From 43df3695637fd0e7c6b656c7aa3a2e0e2225a4b4 Mon Sep 17 00:00:00 2001 From: Giovanni Torres Date: Sun, 15 Mar 2026 09:32:23 -0400 Subject: [PATCH 1/5] feat: cleanups - Move all metadata from setup.py into [project] in pyproject.toml - Move dev deps from Pipfile into [project.optional-dependencies] in pyproject.toml - Drop setup.cfg - Delete Pipfile and Pipfile.lock - Keep setup.py but slim it down to just the Cython/Slurm build logic --- Pipfile | 18 --- Pipfile.lock | 296 ------------------------------------------------- pyproject.toml | 80 +++++++++++-- setup.cfg | 9 -- setup.py | 104 +++-------------- 5 files changed, 89 insertions(+), 418 deletions(-) delete mode 100644 Pipfile delete mode 100644 Pipfile.lock delete mode 100644 setup.cfg diff --git a/Pipfile b/Pipfile deleted file mode 100644 index b9d48d32..00000000 --- a/Pipfile +++ /dev/null @@ -1,18 +0,0 @@ -[[source]] -url = "https://pypi.org/simple" -verify_ssl = true -name = "pypi" - -[packages] -cython = "*" - -[dev-packages] -black = "*" -pytest = "*" -pytest-sugar = "*" -pytest-testinfra = "*" -isort = "*" -flake8 = "*" - -[pipenv] -allow_prereleases = true diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index 472a86ab..00000000 --- a/Pipfile.lock +++ /dev/null @@ -1,296 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "99ea627667369c5677db9137f222ec8e899705e788963d0f3806af942bb2cfd5" - }, - "pipfile-spec": 6, - "requires": {}, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "cython": { - "hashes": [ - "sha256:09ac3087ac7a3d489ebcb3fb8402e00c13d1a3a1c6bc73fd3b0d756a3e341e79", - "sha256:0a142c6b862e6ed6b02209d543062c038c110585b5e32d1ad7c9717af4f07e41", - "sha256:0d414458cb22f8a90d64260da6dace5d5fcebde43f31be52ca51f818c46db8cb", - "sha256:10cb3def9774fa99e4583617a5616874aed3255dc241fd1f4a3c2978c78e1c53", - "sha256:112efa54a58293a4fb0acf0dd8e5b3736e95b595eee24dd88615648e445abe41", - "sha256:166f9f29cd0058ce1a14a7b3a2458b849ed34b1ec5fd4108af3fdd2c24afcbb0", - "sha256:2d9e61ed1056a3b6a4b9156b62297ad18b357a7948e57a2f49b061217696567e", - "sha256:2f41ef7edd76dd23315925e003f0c58c8585f3ab24be6885c4b3f60e77c82746", - "sha256:37bcfa5df2a3009f49624695d917c3804fccbdfcdc5eda6378754a879711a4d5", - "sha256:416046a98255eff97ec02077d20ebeaae52682dfca1c35aadf31260442b92514", - "sha256:4cf4452f0e4d50e11701bca38f3857fe6fa16593e7fd6a4d5f7be66f611b7da2", - "sha256:55b0ee28c2c8118bfb3ad9b25cf7a6cbd724e442ea96956e32ccd908d5e3e043", - "sha256:5dd56d0be50073f0e54825a8bc3393852de0eed126339ecbca0ae149dba55cfc", - "sha256:5fa12ebafc2f688ea6d26ab6d1d2e634a9872509ba7135b902bb0d8b368fb04b", - "sha256:5fb977945a2111f6b64501fdf7ed0ec162cc502b84457fd648d6a558ea8de0d6", - "sha256:60c958bcab0ff315b4036a949bed1c65334e1f6a69e17e9966d742febb59043a", - "sha256:661dbdea519d9cfb288867252b75fef73ffa8e8bb674cec27acf70646afb369b", - "sha256:6a2cf2ccccc25413864928dfd730c29db6f63eaf98206c1e600003a445ca7f58", - "sha256:6ade74eece909fd3a437d9a5084829180751d7ade118e281e9824dd75eafaff2", - "sha256:73ac33a4379056a02031baa4def255717fadb9181b5ac2b244792d53eae1c925", - "sha256:76cbca0188d278e93d12ebdaf5990678e6e436485fdfad49dbe9b07717d41a3c", - "sha256:774cb8fd931ee1ba52c472bc1c19077cd6895c1b24014ae07bb27df59aed5ebe", - "sha256:821c2d416ad7d006b069657ee1034c0e0cb45bdbe9ab6ab631e8c495dfcfa4ac", - "sha256:84826ec1c11cda56261a252ddecac0c7d6b02e47e81b94f40b27b4c23c29c17c", - "sha256:854fe2193d3ad4c8b61932ff54d6dbe10c5fa8749eb8958d72cc0ab28243f833", - "sha256:88dc3c250dec280b0489a83950b15809762e27232f4799b1b8d0bad503f5ab84", - "sha256:8cb87777e82d1996aef6c146560a19270684271c9c669ba62ac6803b3cd2ff82", - "sha256:91339ee4b465924a3ea4b2a9cec7f7227bc4cadf673ce859d24c2b9ef60b1214", - "sha256:9164aeef1af6f837e4fc20402a31d256188ba4d535e262c6cb78caf57ad744f8", - "sha256:a102cfa795c6b3b81a29bdb9dbec545367cd7f353c03e6f30a056fdfefd92854", - "sha256:ad43e684ade673565f6f9d6638015112f6c7f11aa2a632167b79014f613f0f5f", - "sha256:afb521523cb46ddaa8d269b421f88ea2731fee05e65b952b96d4db760f5a2a1c", - "sha256:b28f92e617f540d3f21f8fd479a9c6491be920ffff672a4c61b7fc4d7f749f39", - "sha256:bc05de569f811be1fcfde6756c9048ae518f0c4b6d9f8f024752c5365d934cac", - "sha256:cdf04d07c3600860e8c2ebaad4e8f52ac3feb212453c1764a49ac08c827e8443", - "sha256:d8d1a087f35e39384303f5e6b75d465d6f29d746d7138eae9d3b6e8e6f769eae", - "sha256:eb2843f8cc01c645725e6fc690a84e99cdb266ce8ebe427cf3a680ff09f876aa", - "sha256:f2e9381497b12e8f622af620bde0d1d094035d79b899abb2ddd3a7891f535083", - "sha256:f96411f0120b5cae483923aaacd2872af8709be4b46522daedc32f051d778385" - ], - "index": "pypi", - "version": "==0.29.24" - } - }, - "develop": { - "attrs": { - "hashes": [ - "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1", - "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==21.2.0" - }, - "black": { - "hashes": [ - "sha256:6eb7448da9143ee65b856a5f3676b7dda98ad9abe0f87fce8c59291f15e82a5b", - "sha256:a9952229092e325fe5f3dae56d81f639b23f7131eb840781947e4b2886030f33" - ], - "index": "pypi", - "version": "==21.10b0" - }, - "click": { - "hashes": [ - "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3", - "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b" - ], - "markers": "python_version >= '3.6'", - "version": "==8.0.3" - }, - "flake8": { - "hashes": [ - "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d", - "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d" - ], - "index": "pypi", - "version": "==4.0.1" - }, - "iniconfig": { - "hashes": [ - "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", - "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32" - ], - "version": "==1.1.1" - }, - "isort": { - "hashes": [ - "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7", - "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951" - ], - "index": "pypi", - "version": "==5.10.1" - }, - "mccabe": { - "hashes": [ - "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", - "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" - ], - "version": "==0.6.1" - }, - "mypy-extensions": { - "hashes": [ - "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", - "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8" - ], - "version": "==0.4.3" - }, - "packaging": { - "hashes": [ - "sha256:096d689d78ca690e4cd8a89568ba06d07ca097e3306a4381635073ca91479966", - "sha256:14317396d1e8cdb122989b916fa2c7e9ca8e2be9e8060a6eff75b6b7b4d8a7e0" - ], - "markers": "python_version >= '3.6'", - "version": "==21.2" - }, - "pathspec": { - "hashes": [ - "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a", - "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1" - ], - "version": "==0.9.0" - }, - "platformdirs": { - "hashes": [ - "sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2", - "sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d" - ], - "markers": "python_version >= '3.6'", - "version": "==2.4.0" - }, - "pluggy": { - "hashes": [ - "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159", - "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3" - ], - "markers": "python_version >= '3.6'", - "version": "==1.0.0" - }, - "py": { - "hashes": [ - "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719", - "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==1.11.0" - }, - "pycodestyle": { - "hashes": [ - "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20", - "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==2.8.0" - }, - "pyflakes": { - "hashes": [ - "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c", - "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.4.0" - }, - "pyparsing": { - "hashes": [ - "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", - "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" - ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.4.7" - }, - "pytest": { - "hashes": [ - "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89", - "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134" - ], - "index": "pypi", - "version": "==6.2.5" - }, - "pytest-sugar": { - "hashes": [ - "sha256:b1b2186b0a72aada6859bea2a5764145e3aaa2c1cfbb23c3a19b5f7b697563d3" - ], - "index": "pypi", - "version": "==0.9.4" - }, - "pytest-testinfra": { - "hashes": [ - "sha256:5c3d1f61852a4e2c08bf40dbdf9ff004b10ee8308985883986e53d1610c0b2c3", - "sha256:b3f147cf18608298381b976ba5e161bc625e9f58ca6d8d61eb769fbd99716de6" - ], - "index": "pypi", - "version": "==6.4.0" - }, - "regex": { - "hashes": [ - "sha256:05b7d6d7e64efe309972adab77fc2af8907bb93217ec60aa9fe12a0dad35874f", - "sha256:0617383e2fe465732af4509e61648b77cbe3aee68b6ac8c0b6fe934db90be5cc", - "sha256:07856afef5ffcc052e7eccf3213317fbb94e4a5cd8177a2caa69c980657b3cb4", - "sha256:162abfd74e88001d20cb73ceaffbfe601469923e875caf9118333b1a4aaafdc4", - "sha256:2207ae4f64ad3af399e2d30dde66f0b36ae5c3129b52885f1bffc2f05ec505c8", - "sha256:30ab804ea73972049b7a2a5c62d97687d69b5a60a67adca07eb73a0ddbc9e29f", - "sha256:3b5df18db1fccd66de15aa59c41e4f853b5df7550723d26aa6cb7f40e5d9da5a", - "sha256:3c5fb32cc6077abad3bbf0323067636d93307c9fa93e072771cf9a64d1c0f3ef", - "sha256:416c5f1a188c91e3eb41e9c8787288e707f7d2ebe66e0a6563af280d9b68478f", - "sha256:432bd15d40ed835a51617521d60d0125867f7b88acf653e4ed994a1f8e4995dc", - "sha256:4aaa4e0705ef2b73dd8e36eeb4c868f80f8393f5f4d855e94025ce7ad8525f50", - "sha256:537ca6a3586931b16a85ac38c08cc48f10fc870a5b25e51794c74df843e9966d", - "sha256:53db2c6be8a2710b359bfd3d3aa17ba38f8aa72a82309a12ae99d3c0c3dcd74d", - "sha256:5537f71b6d646f7f5f340562ec4c77b6e1c915f8baae822ea0b7e46c1f09b733", - "sha256:6650f16365f1924d6014d2ea770bde8555b4a39dc9576abb95e3cd1ff0263b36", - "sha256:666abff54e474d28ff42756d94544cdfd42e2ee97065857413b72e8a2d6a6345", - "sha256:68a067c11463de2a37157930d8b153005085e42bcb7ad9ca562d77ba7d1404e0", - "sha256:780b48456a0f0ba4d390e8b5f7c661fdd218934388cde1a974010a965e200e12", - "sha256:788aef3549f1924d5c38263104dae7395bf020a42776d5ec5ea2b0d3d85d6646", - "sha256:7ee1227cf08b6716c85504aebc49ac827eb88fcc6e51564f010f11a406c0a667", - "sha256:7f301b11b9d214f83ddaf689181051e7f48905568b0c7017c04c06dfd065e244", - "sha256:83ee89483672b11f8952b158640d0c0ff02dc43d9cb1b70c1564b49abe92ce29", - "sha256:85bfa6a5413be0ee6c5c4a663668a2cad2cbecdee367630d097d7823041bdeec", - "sha256:9345b6f7ee578bad8e475129ed40123d265464c4cfead6c261fd60fc9de00bcf", - "sha256:93a5051fcf5fad72de73b96f07d30bc29665697fb8ecdfbc474f3452c78adcf4", - "sha256:962b9a917dd7ceacbe5cd424556914cb0d636001e393b43dc886ba31d2a1e449", - "sha256:98ba568e8ae26beb726aeea2273053c717641933836568c2a0278a84987b2a1a", - "sha256:a3feefd5e95871872673b08636f96b61ebef62971eab044f5124fb4dea39919d", - "sha256:b43c2b8a330a490daaef5a47ab114935002b13b3f9dc5da56d5322ff218eeadb", - "sha256:b483c9d00a565633c87abd0aaf27eb5016de23fed952e054ecc19ce32f6a9e7e", - "sha256:ba05430e819e58544e840a68b03b28b6d328aff2e41579037e8bab7653b37d83", - "sha256:ca5f18a75e1256ce07494e245cdb146f5a9267d3c702ebf9b65c7f8bd843431e", - "sha256:d5ca078bb666c4a9d1287a379fe617a6dccd18c3e8a7e6c7e1eb8974330c626a", - "sha256:da1a90c1ddb7531b1d5ff1e171b4ee61f6345119be7351104b67ff413843fe94", - "sha256:dba70f30fd81f8ce6d32ddeef37d91c8948e5d5a4c63242d16a2b2df8143aafc", - "sha256:dd33eb9bdcfbabab3459c9ee651d94c842bc8a05fabc95edf4ee0c15a072495e", - "sha256:e0538c43565ee6e703d3a7c3bdfe4037a5209250e8502c98f20fea6f5fdf2965", - "sha256:e1f54b9b4b6c53369f40028d2dd07a8c374583417ee6ec0ea304e710a20f80a0", - "sha256:e32d2a2b02ccbef10145df9135751abea1f9f076e67a4e261b05f24b94219e36", - "sha256:e71255ba42567d34a13c03968736c5d39bb4a97ce98188fafb27ce981115beec", - "sha256:ed2e07c6a26ed4bea91b897ee2b0835c21716d9a469a96c3e878dc5f8c55bb23", - "sha256:eef2afb0fd1747f33f1ee3e209bce1ed582d1896b240ccc5e2697e3275f037c7", - "sha256:f23222527b307970e383433daec128d769ff778d9b29343fb3496472dc20dabe", - "sha256:f341ee2df0999bfdf7a95e448075effe0db212a59387de1a70690e4acb03d4c6", - "sha256:f7f325be2804246a75a4f45c72d4ce80d2443ab815063cdf70ee8fb2ca59ee1b", - "sha256:f8af619e3be812a2059b212064ea7a640aff0568d972cd1b9e920837469eb3cb", - "sha256:fa8c626d6441e2d04b6ee703ef2d1e17608ad44c7cb75258c09dd42bacdfc64b", - "sha256:fbb9dc00e39f3e6c0ef48edee202f9520dafb233e8b51b06b8428cfcb92abd30", - "sha256:fff55f3ce50a3ff63ec8e2a8d3dd924f1941b250b0aac3d3d42b687eeff07a8e" - ], - "version": "==2021.11.10" - }, - "termcolor": { - "hashes": [ - "sha256:1d6d69ce66211143803fbc56652b41d73b4a400a2891d7bf7a1cdf4c02de613b" - ], - "version": "==1.1.0" - }, - "toml": { - "hashes": [ - "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", - "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" - ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.10.2" - }, - "tomli": { - "hashes": [ - "sha256:c6ce0015eb38820eaf32b5db832dbc26deb3dd427bd5f6556cf0acac2c214fee", - "sha256:f04066f68f5554911363063a30b108d2b5a5b1a010aa8b6132af78489fe3aade" - ], - "markers": "python_version >= '3.6'", - "version": "==1.2.2" - }, - "typing-extensions": { - "hashes": [ - "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e", - "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7", - "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34" - ], - "version": "==3.10.0.2" - } - } -} diff --git a/pyproject.toml b/pyproject.toml index d23f40c4..18fdb181 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,20 +7,84 @@ requires = [ "packaging>=21.3" ] -[tool.flake8] -filename = ["*.py", "*.pyx", "*.pxd"] -max-line-length = 80 -exclude = [ - ".git", - "__pycache__", +[project] +name = "pyslurm" +dynamic = ["version"] +license = "GPL-2.0-only" +description = "Python Interface for Slurm" +readme = "README.md" +requires-python = ">=3.6" +authors = [ + { name = "Mark Roberts" }, + { name = "Giovanni Torres" }, + { name = "Toni Harzendorf" }, +] +maintainers = [ + { name = "Toni Harzendorf", email = "toni.harzendorf@gmail.com" }, +] +keywords = [ + "HPC", + "Batch Scheduler", + "Resource Manager", + "Slurm", + "Cython", +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Intended Audience :: Developers", + "Intended Audience :: System Administrators", + "Natural Language :: English", + "Operating System :: POSIX :: Linux", + "Programming Language :: Cython", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Software Development :: Libraries", + "Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: System :: Distributed Computing", +] + +[project.urls] +Homepage = "https://github.com/PySlurm/pyslurm" +Repository = "https://github.com/PySlurm/pyslurm" +Issues = "https://github.com/PySlurm/pyslurm/issues" +Discussions = "https://github.com/PySlurm/pyslurm/discussions" + +[project.optional-dependencies] +dev = [ + "ruff", + "cython-lint", + "pytest", + "pytest-sugar", +] + +[tool.setuptools.dynamic] +version = { attr = "pyslurm.version.__version__" } + +[tool.setuptools.packages.find] +include = ["pyslurm*"] + +[tool.ruff] +line-length = 80 +extend-exclude = [ ".eggs", - "*.egg", "build", "tests", "examples", "scripts", ] -extend-ignore = ["E203", "E901", "E225", "E226", "E227", "E999"] + +[tool.ruff.lint] +extend-ignore = ["E203", "E225", "E226", "E227"] + +[tool.ruff.lint.isort] [tool.cython-lint] max-line-length = 80 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index b75cbb33..00000000 --- a/setup.cfg +++ /dev/null @@ -1,9 +0,0 @@ -[bdist_rpm] -release = 1 -packager = Giovanni Torres -doc_files = README.md - examples/ -build_requires = python3-devel >= 3.6 - slurm-devel >= 25.11.0 -requires = slurm -use_bzip2 = 1 diff --git a/setup.py b/setup.py index b6e7d23b..c380ab0f 100644 --- a/setup.py +++ b/setup.py @@ -1,10 +1,10 @@ #!/usr/bin/env python3 -"""The Pyslurm Setup - build options""" +"""PySlurm Setup - Cython build logic for Slurm extensions.""" import os import sys from pathlib import Path -from setuptools import setup, Extension, find_packages +from setuptools import setup, Extension try: from packaging.version import Version @@ -12,98 +12,27 @@ from setuptools._vendor.packaging.version import Version TOPDIR = Path(__file__).parent +CYTHON_VERSION_MIN = "0.29.37" # Keep in sync with pyproject.toml +SLURM_LIB = "libslurmfull" -def get_version(): +def get_slurm_version(): with (TOPDIR / "pyslurm/version.py").open() as f: for line in f.read().splitlines(): - if not line.startswith("__version__"): - continue - - V = Version(line.split('"')[1]) - if not hasattr(V, "major") or not hasattr(V, "minor"): - (V.major, V.minor) = V._version.release[0:2] - - return V + if line.startswith("__version__"): + V = Version(line.split('"')[1]) + if not hasattr(V, "major") or not hasattr(V, "minor"): + (V.major, V.minor) = V._version.release[0:2] + return f"{V.major}.{V.minor}" raise RuntimeError("Cannot get version string.") -CYTHON_VERSION_MIN = "0.29.37" # Keep in sync with pyproject.toml -SLURM_LIB = "libslurmfull" -VERSION = get_version() -SLURM_VERSION = f"{VERSION.major}.{VERSION.minor}" -DOCUMENTATION_URL = f"https://pyslurm.github.io/{SLURM_VERSION}" -GITHUB_URL = "https://github.com/PySlurm/pyslurm" - - -def homepage(*args): - return "/".join([DOCUMENTATION_URL] + list(args)) - - -def github(*args): - return "/".join([GITHUB_URL] + list(args)) - - -metadata = dict( - name="pyslurm", - version=str(VERSION), - license="GPLv2", - description="Python Interface for Slurm", - long_description=(TOPDIR / "README.md").read_text(encoding="utf-8"), - long_description_content_type="text/markdown", - author="Mark Roberts, Giovanni Torres, Toni Harzendorf, et al.", - maintainer="Toni Harzendorf", - maintainer_email="toni.harzendorf@gmail.com", - platforms=["Linux"], - url=homepage(), - keywords=[ - "HPC", - "Batch Scheduler", - "Resource Manager", - "Slurm", - "Cython", - ], - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Environment :: Console", - "Intended Audience :: Developers", - "Intended Audience :: System Administrators", - "License :: OSI Approved :: GNU General Public License v2 (GPLv2)", - "Natural Language :: English", - "Operating System :: POSIX :: Linux", - "Programming Language :: Cython", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Topic :: Software Development :: Libraries", - "Topic :: Software Development :: Libraries :: Python Modules", - "Topic :: System :: Distributed Computing", - ], - project_urls={ - "Homepage" : github(), - "Repository" : github(), - "Issues" : github("issues"), - "Discussions" : github("discussions"), - "Documentation" : homepage("reference"), - "Changelog" : homepage("changelog") - }, - python_requires=">=3.6", - packages=find_packages( - include=['pyslurm*'], - ), - include_package_data=True, -) +SLURM_VERSION = get_slurm_version() + class SlurmConfig(): def __init__(self): - # Assume some defaults here self._lib_dir = Path("/usr/lib64") self._lib = None self._lib_dir_search_paths = [] @@ -236,7 +165,7 @@ def cythongen(): cleanup_build() nthreads = os.getenv("PYSLURM_BUILD_JOBS", 1) - metadata["ext_modules"] = cythonize(get_extensions(), nthreads=int(nthreads)) + return cythonize(get_extensions(), nthreads=int(nthreads)) def parse_setuppy_commands(): @@ -261,18 +190,19 @@ def parse_setuppy_commands(): def setup_package(): build_it = parse_setuppy_commands() + ext_modules = None if build_it: parse_slurm_args() slurm.check_version() - cythongen() + ext_modules = cythongen() if "install" in sys.argv: parse_slurm_args() slurm.check_version() - metadata["ext_modules"] = get_extensions() + ext_modules = get_extensions() - setup(**metadata) + setup(ext_modules=ext_modules) if __name__ == "__main__": From 6bcf46e0f169393a0cd09290ed8d0cbe9dc31b60 Mon Sep 17 00:00:00 2001 From: Giovanni Torres Date: Sun, 15 Mar 2026 09:45:57 -0400 Subject: [PATCH 2/5] style: run Ruff on unit tests --- tests/unit/test_collection.py | 4 ++-- tests/unit/test_common.py | 36 +++++++++++++------------------- tests/unit/test_db_slurm_list.py | 2 -- tests/unit/test_job.py | 8 ++++--- tests/unit/test_job_steps.py | 5 ----- tests/unit/test_job_submit.py | 14 +++---------- tests/unit/test_node.py | 4 +--- tests/unit/test_partition.py | 4 +--- tests/unit/test_reservation.py | 4 ++-- tests/unit/test_slurmctld.py | 2 -- tests/unit/test_task_dist.py | 1 - tests/unit/test_tres.py | 4 +--- tests/unit/util.py | 2 -- 13 files changed, 30 insertions(+), 60 deletions(-) diff --git a/tests/unit/test_collection.py b/tests/unit/test_collection.py index ec46410f..b7360a7e 100644 --- a/tests/unit/test_collection.py +++ b/tests/unit/test_collection.py @@ -145,10 +145,10 @@ def test_getitem(self): assert item1 != item3 with pytest.raises(KeyError): - item = col[30] + col[30] with pytest.raises(KeyError): - item = col[OTHER_CLUSTER][30] + col[OTHER_CLUSTER][30] def test_setitem(self): col = self._create_collection() diff --git a/tests/unit/test_common.py b/tests/unit/test_common.py index dc6aa8de..a6f3a744 100644 --- a/tests/unit/test_common.py +++ b/tests/unit/test_common.py @@ -23,7 +23,7 @@ import pyslurm import pytest from datetime import datetime -from pyslurm import Job, JobSubmitDescription, Node, Partition +from pyslurm import Node from pyslurm.utils.ctime import ( timestr_to_mins, timestr_to_secs, @@ -51,16 +51,11 @@ humanize, dehumanize, signal_to_num, - cpubind_to_num, nodelist_from_range_str, nodelist_to_range_str, - instance_to_dict, gres_from_tres_dict, ) from pyslurm.utils import cstr -from pyslurm.xcollections import ( - sum_property, -) class TestStrings: @@ -148,8 +143,8 @@ def test_dict_to_str(self): expected_str = "key1=value1,key2=value2" assert cstr.dict_to_str(expected_str) == expected_str - assert cstr.dict_to_str({}) == None - assert cstr.dict_to_str("") == None + assert cstr.dict_to_str({}) is None + assert cstr.dict_to_str("") is None def test_dict_to_gres_str(self): input_dict = {"gpu:tesla": 3} @@ -214,19 +209,19 @@ class TestUint: def _uint_impl(self, func_set, func_get, typ): val = func_set(2**typ-2) - assert func_get(val) == None + assert func_get(val) is None val = func_set(None) - assert func_get(val) == None + assert func_get(val) is None val = func_set(str(2**typ-2)) - assert func_get(val) == None + assert func_get(val) is None val = func_set("UNLIMITED", inf=True) assert func_get(val) == "UNLIMITED" val = func_set(0) - assert func_get(val) == None + assert func_get(val) is None val = func_set(0, zero_is_noval=False) assert func_get(val, zero_is_noval=False) == 0 @@ -290,8 +285,8 @@ def test_parse_minutes(self): assert mins_to_timestr(mins) == mins_str assert mins_to_timestr(2**32-1) == "UNLIMITED" - assert mins_to_timestr(2**32-2) == None - assert mins_to_timestr(0) == None + assert mins_to_timestr(2**32-2) is None + assert mins_to_timestr(0) is None with pytest.raises(ValueError, match="Invalid Time Specification: invalid_val."): @@ -307,8 +302,8 @@ def test_parse_seconds(self): assert secs_to_timestr(secs) == secs_str assert secs_to_timestr(2**32-1) == "UNLIMITED" - assert secs_to_timestr(2**32-2) == None - assert secs_to_timestr(0) == None + assert secs_to_timestr(2**32-2) is None + assert secs_to_timestr(0) is None with pytest.raises(ValueError, match="Invalid Time Specification: invalid_val."): @@ -324,9 +319,9 @@ def test_parse_date(self): assert date_to_timestamp(datetime_date) == timestamp assert timestamp_to_date(timestamp) == date - assert timestamp_to_date(0) == None - assert timestamp_to_date(2**32-1) == None - assert timestamp_to_date(2**32-2) == None + assert timestamp_to_date(0) is None + assert timestamp_to_date(2**32-1) is None + assert timestamp_to_date(2**32-2) is None with pytest.raises(ValueError, match="Invalid Time Specification: 2022-11-08T21"): @@ -391,7 +386,7 @@ def test_humanize(self): assert val == "UNLIMITED" val = humanize(None) - assert val == None + assert val is None with pytest.raises(ValueError): val = humanize("invalid_val") @@ -436,7 +431,6 @@ def test_signal_to_num(self): def test_nodelist_from_range_str(self): nodelist = ["node001", "node007", "node008", "node009"] - nodelist_str = ",".join(nodelist) assert nodelist == nodelist_from_range_str("node[001,007-009]") assert nodelist_from_range_str("node[001,007:009]") == [] diff --git a/tests/unit/test_db_slurm_list.py b/tests/unit/test_db_slurm_list.py index 6d770bcf..a00eef9a 100644 --- a/tests/unit/test_db_slurm_list.py +++ b/tests/unit/test_db_slurm_list.py @@ -20,8 +20,6 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """test_db_slurm_List.py - Unit test basic Slurm list functionalities.""" -import pytest -import pyslurm from pyslurm.db.util import SlurmList diff --git a/tests/unit/test_job.py b/tests/unit/test_job.py index 5bb58b6e..81b72fe9 100644 --- a/tests/unit/test_job.py +++ b/tests/unit/test_job.py @@ -20,10 +20,12 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """test_job.py - Unit test basic job functionalities.""" -import pytest -import pyslurm from pyslurm import Job -from pyslurm.core.job.util import * +from pyslurm.core.job.util import ( + acctg_profile_int_to_list, + dependency_str_to_dict, + mail_type_int_to_list, + ) from pyslurm.utils.helpers import cpu_freq_int_to_str def test_create_instance(): diff --git a/tests/unit/test_job_steps.py b/tests/unit/test_job_steps.py index c8c52352..1cec4072 100644 --- a/tests/unit/test_job_steps.py +++ b/tests/unit/test_job_steps.py @@ -20,12 +20,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """test_job_steps.py - Unit test basic job step functionality.""" -import pytest from pyslurm import JobStep, Job -from pyslurm.utils.helpers import ( - humanize_step_id, - dehumanize_step_id, -) def test_create_instance(): step = JobStep(9999, 1) diff --git a/tests/unit/test_job_submit.py b/tests/unit/test_job_submit.py index 37f5efef..4225c92a 100644 --- a/tests/unit/test_job_submit.py +++ b/tests/unit/test_job_submit.py @@ -20,20 +20,13 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """test_job_submit.py - Test the job submit api functions.""" -import sys -import time import pytest -import pyslurm import tempfile import os from os import environ as pyenviron -from util import create_simple_job_desc, create_job_script -from pyslurm.utils.uint import u32 +from util import create_job_script from pyslurm import ( - Job, - Jobs, JobSubmitDescription, - RPCError, ) from pyslurm.core.job.submission import ( _parse_cpu_freq_str_to_dict, @@ -48,7 +41,6 @@ acctg_profile_list_to_int, cpu_freq_str_to_int, cpu_gov_str_to_int, - shared_type_str_to_int, ) @@ -319,7 +311,7 @@ def test_setting_attrs_with_env_vars(): assert job.wckey == "wckey" assert job.clusters == "cluster1,cluster2" assert job.comment == "A simple job comment" - assert job.requires_contiguous_nodes == True + assert job.requires_contiguous_nodes is True assert job.working_directory == "/work/user2" job = job_desc(working_directory="/work/user2", account="account2") @@ -330,7 +322,7 @@ def test_setting_attrs_with_env_vars(): assert job.wckey == "wckey" assert job.clusters == "cluster1,cluster2" assert job.comment == "A simple job comment" - assert job.requires_contiguous_nodes == True + assert job.requires_contiguous_nodes is True assert job.working_directory == "/work/user1" diff --git a/tests/unit/test_node.py b/tests/unit/test_node.py index c4dba73e..60803d9e 100644 --- a/tests/unit/test_node.py +++ b/tests/unit/test_node.py @@ -20,9 +20,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """test_node.py - Unit Test basic functionality of the Node class.""" -import pytest -import pyslurm -from pyslurm import Node, Nodes +from pyslurm import Node from pyslurm.core.node import _node_state_from_str diff --git a/tests/unit/test_partition.py b/tests/unit/test_partition.py index 490fba1b..d7c6848e 100644 --- a/tests/unit/test_partition.py +++ b/tests/unit/test_partition.py @@ -21,9 +21,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """test_partition.py - Unit Test basic functionality of the Partition class.""" -import pytest -import pyslurm -from pyslurm import Partition, Partitions +from pyslurm import Partition def test_create_instance(): diff --git a/tests/unit/test_reservation.py b/tests/unit/test_reservation.py index 7d7f43ca..861136dc 100644 --- a/tests/unit/test_reservation.py +++ b/tests/unit/test_reservation.py @@ -29,8 +29,8 @@ def test_create_instance(): resv = pyslurm.Reservation("test") assert resv.name == "test" assert resv.accounts == [] - assert resv.start_time == None - assert resv.end_time == None + assert resv.start_time is None + assert resv.end_time is None assert resv.duration == 0 assert resv.is_active is False assert resv.cpu_ids_by_node == {} diff --git a/tests/unit/test_slurmctld.py b/tests/unit/test_slurmctld.py index 71d36d34..f13c20fa 100644 --- a/tests/unit/test_slurmctld.py +++ b/tests/unit/test_slurmctld.py @@ -20,8 +20,6 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """test_slurmctld.py - Unit test basic slurmctld functionalities.""" -import pyslurm -from pyslurm import slurmctld from pyslurm.core.slurmctld.stats import _parse_test_data diff --git a/tests/unit/test_task_dist.py b/tests/unit/test_task_dist.py index 52a3e07c..8c197fda 100644 --- a/tests/unit/test_task_dist.py +++ b/tests/unit/test_task_dist.py @@ -20,7 +20,6 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """test_task_dist.py - Test task distribution functions.""" -import pyslurm from pyslurm.core.job.task_dist import TaskDistribution diff --git a/tests/unit/test_tres.py b/tests/unit/test_tres.py index cb27c79d..31598a34 100644 --- a/tests/unit/test_tres.py +++ b/tests/unit/test_tres.py @@ -20,7 +20,6 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """test_tres.py - Test TRES parsing functionality""" -import pyslurm import pytest from pyslurm.db import ( TrackableResource, @@ -28,7 +27,6 @@ GenericResourceLayout, GPU, ) -from pyslurm.utils import cstr def test_parse_tres_str(): @@ -47,7 +45,7 @@ def test_parse_tres_str(): gres = tres.gres["gpu"] assert isinstance(gres, GPU) assert gres.count == 5 - assert gres.type == None + assert gres.type is None # Simulating the global TRES-data that is required when translating # such strings that only come with IDs, but without names. diff --git a/tests/unit/util.py b/tests/unit/util.py index d142a3a4..6f6617da 100644 --- a/tests/unit/util.py +++ b/tests/unit/util.py @@ -19,9 +19,7 @@ # with PySlurm; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -import pytest from pyslurm import ( - Job, JobSubmitDescription, ) From d67ced362f14a2ee4e7ea4d00edfb349cde436d9 Mon Sep 17 00:00:00 2001 From: Giovanni Torres Date: Sun, 15 Mar 2026 09:47:24 -0400 Subject: [PATCH 3/5] style: run Ruff formatter on unit tests --- tests/unit/test_collection.py | 41 +++++------ tests/unit/test_common.py | 123 +++++++++++++++++-------------- tests/unit/test_db_slurm_list.py | 6 +- tests/unit/test_job.py | 3 +- tests/unit/test_job_steps.py | 1 + tests/unit/test_job_submit.py | 64 ++++++++-------- tests/unit/test_reservation.py | 8 +- tests/unit/test_task_dist.py | 2 + tests/unit/test_tres.py | 23 +++--- tests/unit/util.py | 1 + 10 files changed, 148 insertions(+), 124 deletions(-) diff --git a/tests/unit/test_collection.py b/tests/unit/test_collection.py index b7360a7e..5801a8b4 100644 --- a/tests/unit/test_collection.py +++ b/tests/unit/test_collection.py @@ -29,7 +29,6 @@ class TestMultiClusterMap: - def _create_collection(self): data = { LOCAL_CLUSTER: { @@ -39,7 +38,7 @@ def _create_collection(self): OTHER_CLUSTER: { 1: pyslurm.db.Job(1, cluster=OTHER_CLUSTER), 10: pyslurm.db.Job(10, cluster=OTHER_CLUSTER), - } + }, } col = pyslurm.db.Jobs() col.update(data) @@ -81,13 +80,13 @@ def test_add(self): col.add(item) assert len(col[LOCAL_CLUSTER]) == 3 - assert len(col) == col_len+1 + assert len(col) == col_len + 1 item = pyslurm.db.Job(20, cluster=OTHER_CLUSTER) col.add(item) assert len(col[LOCAL_CLUSTER]) == 3 - assert len(col) == col_len+2 + assert len(col) == col_len + 2 def test_get(self): col = self._create_collection() @@ -157,22 +156,22 @@ def test_setitem(self): item = pyslurm.db.Job(30) col[item.id] = item assert len(col[LOCAL_CLUSTER]) == 3 - assert len(col) == col_len+1 + assert len(col) == col_len + 1 item = pyslurm.db.Job(50, cluster=OTHER_CLUSTER) col[OTHER_CLUSTER][item.id] = item assert len(col[OTHER_CLUSTER]) == 3 - assert len(col) == col_len+2 + assert len(col) == col_len + 2 item = pyslurm.db.Job(100, cluster=OTHER_CLUSTER) col[item] = item assert len(col[OTHER_CLUSTER]) == 4 - assert len(col) == col_len+3 + assert len(col) == col_len + 3 item = pyslurm.db.Job(101, cluster=OTHER_CLUSTER) col[(item.cluster, item.id)] = item assert len(col[OTHER_CLUSTER]) == 5 - assert len(col) == col_len+4 + assert len(col) == col_len + 4 new_other_data = { 1: pyslurm.db.Job(1), @@ -190,11 +189,11 @@ def test_delitem(self): del col[1] assert len(col[LOCAL_CLUSTER]) == 1 - assert len(col) == col_len-1 + assert len(col) == col_len - 1 del col[OTHER_CLUSTER][1] assert len(col[OTHER_CLUSTER]) == 1 - assert len(col) == col_len-2 + assert len(col) == col_len - 2 del col[OTHER_CLUSTER] assert len(col) == 1 @@ -231,7 +230,7 @@ def test_popitem(self): assert item assert key assert isinstance(item, pyslurm.db.Job) - assert len(col) == col_len-1 + assert len(col) == col_len - 1 def test_update(self): col = self._create_collection() @@ -242,7 +241,7 @@ def test_update(self): 50: pyslurm.db.Job(50), } col.update(col_update) - assert len(col) == col_len+2 + assert len(col) == col_len + 2 assert len(col[LOCAL_CLUSTER]) == 4 assert 30 in col assert 50 in col @@ -254,7 +253,7 @@ def test_update(self): } } col.update(col_update) - assert len(col) == col_len+4 + assert len(col) == col_len + 4 assert len(col[LOCAL_CLUSTER]) == 4 assert len(col["new_cluster"]) == 2 assert 80 in col @@ -265,7 +264,7 @@ def test_update(self): 300: pyslurm.db.Job(300, cluster=OTHER_CLUSTER), } col.update({OTHER_CLUSTER: col_update}) - assert len(col) == col_len+6 + assert len(col) == col_len + 6 assert len(col[OTHER_CLUSTER]) == 4 assert 200 in col assert 300 in col @@ -281,7 +280,7 @@ def test_pop(self): item = col.pop(1) assert item assert item.id == 1 - assert len(col) == col_len-1 + assert len(col) == col_len - 1 item = col.pop(999, default="def") assert item == "def" @@ -338,7 +337,7 @@ def test_ior(self): "test_cluster": { 1000: pyslurm.db.Job(1000, cluster="test_cluster"), 1001: pyslurm.db.Job(1001, cluster="test_cluster"), - } + }, } other_col = pyslurm.db.Jobs() other_col.update(other_data) @@ -347,7 +346,7 @@ def test_ior(self): assert isinstance(col, pyslurm.xcollections.MultiClusterMap) assert isinstance(col, pyslurm.db.Jobs) assert len(col.clusters()) == 3 - assert len(col) == col_len+3 + assert len(col) == col_len + 3 dict_data = { 10: pyslurm.db.Job(10), @@ -359,7 +358,7 @@ def test_ior(self): assert isinstance(col, pyslurm.db.Jobs) assert len(col.clusters()) == 3 assert len(col[LOCAL_CLUSTER]) == 5 - assert len(col) == col_len+5 + assert len(col) == col_len + 5 def test_or(self): col = self._create_collection() @@ -373,7 +372,7 @@ def test_or(self): "test_cluster": { 1000: pyslurm.db.Job(1000, cluster="test_cluster"), 1001: pyslurm.db.Job(1001, cluster="test_cluster"), - } + }, } other_col = pyslurm.db.Jobs() other_col.update(other_data) @@ -382,7 +381,7 @@ def test_or(self): assert isinstance(_col, pyslurm.xcollections.MultiClusterMap) assert isinstance(_col, pyslurm.db.Jobs) assert len(_col.clusters()) == 3 - assert len(_col) == col_len+3 + assert len(_col) == col_len + 3 dict_data = { 10: pyslurm.db.Job(10), @@ -394,4 +393,4 @@ def test_or(self): assert isinstance(_col, pyslurm.db.Jobs) assert len(_col.clusters()) == 3 assert len(_col[LOCAL_CLUSTER]) == 5 - assert len(_col) == col_len+5 + assert len(_col) == col_len + 5 diff --git a/tests/unit/test_common.py b/tests/unit/test_common.py index a6f3a744..8e9bdf7a 100644 --- a/tests/unit/test_common.py +++ b/tests/unit/test_common.py @@ -59,7 +59,6 @@ class TestStrings: - def test_fmalloc(self): n = Node() @@ -97,8 +96,12 @@ def test_lists(self): assert n.available_features == [] def test_str_to_dict(self): - expected_dict = {"cpu": 2, "mem": "11G", - "gres/gpu": 1, "gres/gpu:nvidia-a100": 1} + expected_dict = { + "cpu": 2, + "mem": "11G", + "gres/gpu": 1, + "gres/gpu:nvidia-a100": 1, + } input_str = "cpu=2,mem=11G,gres/gpu=1,gres/gpu:nvidia-a100=1" assert cstr.to_dict(input_str) == expected_dict assert cstr.to_dict("") == {} @@ -132,12 +135,15 @@ def test_dict_to_str(self): assert cstr.dict_to_str(input_dict) == expected_str expected_str = "key1-value1:key2-value2" - assert cstr.dict_to_str(input_dict, delim1=":", delim2="-") == expected_str + assert ( + cstr.dict_to_str(input_dict, delim1=":", delim2="-") == expected_str + ) input_dict = {"key1=": "value1", "key2": "value2"} expected_str = "key1=value1,key2=value2" - with pytest.raises(ValueError, - match=r"Key or Value cannot contain either*"): + with pytest.raises( + ValueError, match=r"Key or Value cannot contain either*" + ): assert cstr.dict_to_str(input_dict) == expected_str expected_str = "key1=value1,key2=value2" @@ -199,22 +205,25 @@ def test_str_to_gres_dict(self): assert cstr.to_gres_dict(input_str) == expected def test_gres_from_tres_dict(self): - input_dict = {"cpu": 10, "mem": "5G", - "gres/gpu": 5, "gres/gpu:nvidia": 100} + input_dict = { + "cpu": 10, + "mem": "5G", + "gres/gpu": 5, + "gres/gpu:nvidia": 100, + } expected = {"gpu": 5, "gpu:nvidia": 100} assert gres_from_tres_dict(input_dict) == expected class TestUint: - def _uint_impl(self, func_set, func_get, typ): - val = func_set(2**typ-2) + val = func_set(2**typ - 2) assert func_get(val) is None val = func_set(None) assert func_get(val) is None - val = func_set(str(2**typ-2)) + val = func_set(str(2**typ - 2)) assert func_get(val) is None val = func_set("UNLIMITED", inf=True) @@ -226,17 +235,19 @@ def _uint_impl(self, func_set, func_get, typ): val = func_set(0, zero_is_noval=False) assert func_get(val, zero_is_noval=False) == 0 - with pytest.raises(TypeError, - match="an integer is required"): + with pytest.raises(TypeError, match="an integer is required"): val = func_set("UNLIMITED") - with pytest.raises(OverflowError, - match=r"can't convert negative value to*"): + with pytest.raises( + OverflowError, match=r"can't convert negative value to*" + ): val = func_set(-1) - with pytest.raises(OverflowError, - match=r"value too large to convert to*|" - "Python int too large*"): + with pytest.raises( + OverflowError, + match=r"value too large to convert to*|" + "Python int too large*", + ): val = func_set(2**typ) def test_u8(self): @@ -274,22 +285,22 @@ def test_set_parse_bool_flag(self): class TestTime: - def test_parse_minutes(self): mins = 60 mins_str = "01:00:00" assert timestr_to_mins(mins_str) == mins - assert timestr_to_mins("UNLIMITED") == 2**32-1 - assert timestr_to_mins(None) == 2**32-2 + assert timestr_to_mins("UNLIMITED") == 2**32 - 1 + assert timestr_to_mins(None) == 2**32 - 2 assert mins_to_timestr(mins) == mins_str - assert mins_to_timestr(2**32-1) == "UNLIMITED" - assert mins_to_timestr(2**32-2) is None + assert mins_to_timestr(2**32 - 1) == "UNLIMITED" + assert mins_to_timestr(2**32 - 2) is None assert mins_to_timestr(0) is None - with pytest.raises(ValueError, - match="Invalid Time Specification: invalid_val."): + with pytest.raises( + ValueError, match="Invalid Time Specification: invalid_val." + ): timestr_to_mins("invalid_val") def test_parse_seconds(self): @@ -297,16 +308,17 @@ def test_parse_seconds(self): secs_str = "01:00:00" assert timestr_to_secs(secs_str) == secs - assert timestr_to_secs("UNLIMITED") == 2**32-1 - assert timestr_to_secs(None) == 2**32-2 + assert timestr_to_secs("UNLIMITED") == 2**32 - 1 + assert timestr_to_secs(None) == 2**32 - 2 assert secs_to_timestr(secs) == secs_str - assert secs_to_timestr(2**32-1) == "UNLIMITED" - assert secs_to_timestr(2**32-2) is None + assert secs_to_timestr(2**32 - 1) == "UNLIMITED" + assert secs_to_timestr(2**32 - 2) is None assert secs_to_timestr(0) is None - with pytest.raises(ValueError, - match="Invalid Time Specification: invalid_val."): + with pytest.raises( + ValueError, match="Invalid Time Specification: invalid_val." + ): timestr_to_secs("invalid_val") def test_parse_date(self): @@ -320,16 +332,16 @@ def test_parse_date(self): assert timestamp_to_date(timestamp) == date assert timestamp_to_date(0) is None - assert timestamp_to_date(2**32-1) is None - assert timestamp_to_date(2**32-2) is None + assert timestamp_to_date(2**32 - 1) is None + assert timestamp_to_date(2**32 - 2) is None - with pytest.raises(ValueError, - match="Invalid Time Specification: 2022-11-08T21"): + with pytest.raises( + ValueError, match="Invalid Time Specification: 2022-11-08T21" + ): date_to_timestamp("2022-11-08T21") class TestMiscUtil: - def test_parse_uid(self): name = uid_to_name(0) assert name == "root" @@ -341,10 +353,10 @@ def test_parse_uid(self): assert user_to_uid("root") == 0 assert user_to_uid(0) == 0 assert user_to_uid("0") == 0 - assert uid_to_name(2**32-5) == str(2**32-5) + assert uid_to_name(2**32 - 5) == str(2**32 - 5) with pytest.raises(KeyError): - name = uid_to_name(2**32-5, err_on_invalid=True) + name = uid_to_name(2**32 - 5, err_on_invalid=True) with pytest.raises(KeyError): name = user_to_uid("invalid_user") @@ -360,10 +372,10 @@ def test_parse_gid(self): assert group_to_gid("root") == 0 assert group_to_gid(0) == 0 assert group_to_gid("0") == 0 - assert gid_to_name(2**32-5) == str(2**32-5) + assert gid_to_name(2**32 - 5) == str(2**32 - 5) with pytest.raises(KeyError): - name = gid_to_name(2**32-5, err_on_invalid=True) + name = gid_to_name(2**32 - 5, err_on_invalid=True) with pytest.raises(KeyError): name = group_to_gid("invalid_group") @@ -403,31 +415,31 @@ def test_dehumanize(self): assert val == 10240 val = dehumanize("9.6G") - assert val == round(1024*9.6) + assert val == round(1024 * 9.6) val = dehumanize("10T") - assert val == 10*(2**20) + assert val == 10 * (2**20) val = dehumanize("10T", target="G") - assert val == 10*(2**10) + assert val == 10 * (2**10) - with pytest.raises(ValueError, - match="Invalid value specified: 10L"): - val = dehumanize("10L") + with pytest.raises(ValueError, match="Invalid value specified: 10L"): + val = dehumanize("10L") - with pytest.raises(ValueError, - match="could not convert string to float: 'invalid_val'"): - val = dehumanize("invalid_valM") + with pytest.raises( + ValueError, match="could not convert string to float: 'invalid_val'" + ): + val = dehumanize("invalid_valM") def test_signal_to_num(self): - sig = signal_to_num("SIGKILL") - assert sig == 9 + sig = signal_to_num("SIGKILL") + assert sig == 9 - sig = signal_to_num(7) - assert sig == 7 + sig = signal_to_num(7) + assert sig == 7 - with pytest.raises(ValueError): - sig = signal_to_num("invalid_sig") + with pytest.raises(ValueError): + sig = signal_to_num("invalid_sig") def test_nodelist_from_range_str(self): nodelist = ["node001", "node007", "node008", "node009"] @@ -439,4 +451,3 @@ def test_nodelist_to_range_str(self): nodelist_str = ",".join(nodelist) assert "node[001,007-009]" == nodelist_to_range_str(nodelist) assert "node[001,007-009]" == nodelist_to_range_str(nodelist_str) - diff --git a/tests/unit/test_db_slurm_list.py b/tests/unit/test_db_slurm_list.py index a00eef9a..63db13c8 100644 --- a/tests/unit/test_db_slurm_list.py +++ b/tests/unit/test_db_slurm_list.py @@ -30,7 +30,7 @@ def test_create_and_destroy_list(): slist2 = SlurmList(["user1", "user2"]) assert not slist.is_null assert slist2.cnt == 2 - assert slist2.itr_cnt == 0 + assert slist2.itr_cnt == 0 assert slist2.is_itr_null slist2._dealloc_itr() @@ -75,7 +75,7 @@ def test_iter(): for idx, slurm_item in enumerate(slist): assert not slist.is_itr_null assert slurm_item.has_data - assert slist.itr_cnt == idx+1 + assert slist.itr_cnt == idx + 1 assert slist.itr_cnt == 0 assert slist.is_itr_null @@ -95,7 +95,7 @@ def test_iter_and_pop(): assert slist.itr_cnt == 0 assert slist.is_itr_null assert slist.cnt == 3 - + for idx, slurm_item in enumerate(SlurmList.iter_and_pop(slist)): assert slist.is_itr_null assert slurm_item.has_data diff --git a/tests/unit/test_job.py b/tests/unit/test_job.py index 81b72fe9..91b901c6 100644 --- a/tests/unit/test_job.py +++ b/tests/unit/test_job.py @@ -25,9 +25,10 @@ acctg_profile_int_to_list, dependency_str_to_dict, mail_type_int_to_list, - ) +) from pyslurm.utils.helpers import cpu_freq_int_to_str + def test_create_instance(): job = Job(9999) assert job.id == 9999 diff --git a/tests/unit/test_job_steps.py b/tests/unit/test_job_steps.py index 1cec4072..f41e34bc 100644 --- a/tests/unit/test_job_steps.py +++ b/tests/unit/test_job_steps.py @@ -22,6 +22,7 @@ from pyslurm import JobStep, Job + def test_create_instance(): step = JobStep(9999, 1) assert step.id == 1 diff --git a/tests/unit/test_job_submit.py b/tests/unit/test_job_submit.py index 4225c92a..7909584f 100644 --- a/tests/unit/test_job_submit.py +++ b/tests/unit/test_job_submit.py @@ -61,6 +61,8 @@ def test_parse_environment(): # TODO: more test cases # Test explicitly set vars as dict + + # job.environment = { # "PYSLURM_TEST_VAR_1": 2, # "PYSLURM_TEST_VAR_2": "test-value", @@ -94,29 +96,25 @@ def test_parse_cpu_frequency(): assert freq_dict["governor"] == "Performance" _validate_cpu_freq(freq_dict) - with pytest.raises(ValueError, - match=r"Invalid cpu_frequency format*"): + with pytest.raises(ValueError, match=r"Invalid cpu_frequency format*"): freq = "Performance:3700000" freq_dict = _parse_cpu_freq_str_to_dict(freq) - with pytest.raises(ValueError, - match=r"min cpu-freq*"): + with pytest.raises(ValueError, match=r"min cpu-freq*"): freq = "4000000-3700000" freq_dict = _parse_cpu_freq_str_to_dict(freq) _validate_cpu_freq(freq_dict) -# with pytest.raises(ValueError, -# match=r"Invalid cpu freq value*"): -# freq = "3700000:Performance" -# job._create_job_submit_desc() + # with pytest.raises(ValueError, + # match=r"Invalid cpu freq value*"): + # freq = "3700000:Performance" + # job._create_job_submit_desc() - with pytest.raises(ValueError, - match=r"Setting Governor when specifying*"): + with pytest.raises(ValueError, match=r"Setting Governor when specifying*"): freq = {"max": 3700000, "governor": "Performance"} _validate_cpu_freq(freq) - with pytest.raises(ValueError, - match=r"Setting Governor when specifying*"): + with pytest.raises(ValueError, match=r"Setting Governor when specifying*"): freq = {"min": 3700000, "governor": "Performance"} _validate_cpu_freq(freq) @@ -137,8 +135,7 @@ def test_parse_nodes(): assert nmin == 5 assert nmax == 10 - with pytest.raises(ValueError, - match=r"Max Nodecount cannot be less than*"): + with pytest.raises(ValueError, match=r"Max Nodecount cannot be less than*"): nodes = {"min": 10, "max": 5} nmin, nmax = _parse_nodes(nodes) @@ -149,33 +146,35 @@ def test_parse_script(): # Try passing in a path to a script. fd, path = tempfile.mkstemp() try: - with os.fdopen(fd, 'w') as tmp: + with os.fdopen(fd, "w") as tmp: tmp.write(script) _validate_batch_script(path, "-t 10 input.csv") finally: - os.remove(path) + os.remove(path) - with pytest.raises(ValueError, - match=r"Passing arguments to a script*"): + with pytest.raises(ValueError, match=r"Passing arguments to a script*"): script = "#!/bin/bash\nsleep 10" script_args = "-t 10" _validate_batch_script(script, script_args) - with pytest.raises(ValueError, - match=r"The Slurm Controller does not allow*"): + with pytest.raises( + ValueError, match=r"The Slurm Controller does not allow*" + ): script = "#!/bin/bash\nsleep 10" + "\0" script_args = None _validate_batch_script(script, script_args) - with pytest.raises(ValueError, - match="Batch script is empty or none was provided."): + with pytest.raises( + ValueError, match="Batch script is empty or none was provided." + ): script = "" script_args = None _validate_batch_script(script, script_args) - with pytest.raises(ValueError, - match=r"Batch script contains DOS line breaks*"): + with pytest.raises( + ValueError, match=r"Batch script contains DOS line breaks*" + ): script = "#!/bin/bash\nsleep 10" + "\r\n" script_args = None _validate_batch_script(script, script_args) @@ -211,8 +210,10 @@ def test_validate_cpus(): job.cpus_per_task = 5 job._validate_options() - with pytest.raises(ValueError, - match="cpus_per_task and cpus_per_gpu are mutually exclusive."): + with pytest.raises( + ValueError, + match="cpus_per_task and cpus_per_gpu are mutually exclusive.", + ): job.cpus_per_gpu = 5 job._validate_options() @@ -220,8 +221,10 @@ def test_validate_cpus(): job.cpus_per_gpu = 5 job._validate_options() - with pytest.raises(ValueError, - match="cpus_per_task and cpus_per_gpu are mutually exclusive."): + with pytest.raises( + ValueError, + match="cpus_per_task and cpus_per_gpu are mutually exclusive.", + ): job.cpus_per_task = 5 job._validate_options() @@ -329,7 +332,7 @@ def test_setting_attrs_with_env_vars(): def test_parsing_sbatch_options_from_script(): fd, path = tempfile.mkstemp() try: - with os.fdopen(fd, 'w') as tmp: + with os.fdopen(fd, "w") as tmp: tmp.write( """#!/bin/bash @@ -369,5 +372,4 @@ def test_parsing_sbatch_options_from_script(): assert job.gres_tasks_per_sharing == "one-task-per-sharing" assert job.gres_binding == "enforce-binding" finally: - os.remove(path) - + os.remove(path) diff --git a/tests/unit/test_reservation.py b/tests/unit/test_reservation.py index 861136dc..c96674f4 100644 --- a/tests/unit/test_reservation.py +++ b/tests/unit/test_reservation.py @@ -72,7 +72,12 @@ def test_create_instance(): resv.flags = ReservationFlags.MAINTENANCE | ReservationFlags.FLEX assert resv.flags == ReservationFlags.MAINTENANCE | ReservationFlags.FLEX resv.flags |= ReservationFlags.MAGNETIC - assert resv.flags == ReservationFlags.MAINTENANCE | ReservationFlags.FLEX | ReservationFlags.MAGNETIC + assert ( + resv.flags + == ReservationFlags.MAINTENANCE + | ReservationFlags.FLEX + | ReservationFlags.MAGNETIC + ) resv.flags = ["FLEX", "PURGE"] assert resv.flags == ReservationFlags.FLEX | ReservationFlags.PURGE @@ -87,4 +92,3 @@ def test_flags_sched_failed(): decoded = ReservationFlags(combo.value) assert ReservationFlags.SCHED_FAILED in decoded - diff --git a/tests/unit/test_task_dist.py b/tests/unit/test_task_dist.py index 8c197fda..3ba63cc5 100644 --- a/tests/unit/test_task_dist.py +++ b/tests/unit/test_task_dist.py @@ -48,4 +48,6 @@ def test_from_str(): assert parsed == expected assert parsed.to_str() == "plane" assert parsed.plane == 10 + + # assert parsed.as_int() == pyslurm.SLURM_DIST_PLANE diff --git a/tests/unit/test_tres.py b/tests/unit/test_tres.py index 31598a34..ce05f011 100644 --- a/tests/unit/test_tres.py +++ b/tests/unit/test_tres.py @@ -124,21 +124,24 @@ def test_set_tres_limits(): 1: TrackableResource("cpu", tres_id=1, name=None, count=0), 2: TrackableResource("mem", tres_id=2, name=None, count=0), 6: TrackableResource("fs", tres_id=6, name="disk", count=0), - 10: TrackableResource("gres", tres_id=10, name="gpu:nvidia-a100", count=0), - 11: TrackableResource("gres", tres_id=11, name="gpu:nvidia-h100", count=0), + 10: TrackableResource( + "gres", tres_id=10, name="gpu:nvidia-a100", count=0 + ), + 11: TrackableResource( + "gres", tres_id=11, name="gpu:nvidia-h100", count=0 + ), 12: TrackableResource("gres", tres_id=12, name="gpu", count=0), } tres = TrackableResources( - cpu = 10, - mem = 10 * 2**10, - fs = { "disk": 20 * 2**10 }, - gres = { "gpu:nvidia-a100": 15, "gpu:nvidia-h100": 20, "gpu": 35}, + cpu=10, + mem=10 * 2**10, + fs={"disk": 20 * 2**10}, + gres={"gpu:nvidia-a100": 15, "gpu:nvidia-h100": 20, "gpu": 35}, ) - expected_tres = { 1: 10, 2: 10240, 10: 15, 11: 20, 12: 35, 6: 20480 } + expected_tres = {1: 10, 2: 10240, 10: 15, 11: 20, 12: 35, 6: 20480} validated_tres = tres._validate(global_tres_data) assert expected_tres == validated_tres - with pytest.raises(ValueError, - match=r"Invalid TRES specified*"): - tres = TrackableResources(invalid_tres = 10) + with pytest.raises(ValueError, match=r"Invalid TRES specified*"): + tres = TrackableResources(invalid_tres=10) tres._validate(global_tres_data) diff --git a/tests/unit/util.py b/tests/unit/util.py index 6f6617da..041fd9b6 100644 --- a/tests/unit/util.py +++ b/tests/unit/util.py @@ -26,6 +26,7 @@ # TODO: Figure out how to share this properly between the unit and integration # folders + def create_job_script(): job_script = """\ #!/bin/bash From 37e4417aa99857274501e5f57236960005f0f4b8 Mon Sep 17 00:00:00 2001 From: Giovanni Torres Date: Sun, 15 Mar 2026 09:47:56 -0400 Subject: [PATCH 4/5] style: run Ruff formatter on integration tests --- tests/integration/test_db_job.py | 4 +++- tests/integration/test_job_steps.py | 8 ++------ tests/integration/test_job_submit.py | 1 + tests/integration/test_node.py | 4 +--- tests/integration/test_partition.py | 7 +++---- tests/integration/test_reservation.py | 2 +- tests/integration/test_slurmctld.py | 9 +++------ tests/integration/util.py | 4 ++-- 8 files changed, 16 insertions(+), 23 deletions(-) diff --git a/tests/integration/test_db_job.py b/tests/integration/test_db_job.py index 396eebff..0ff75956 100644 --- a/tests/integration/test_db_job.py +++ b/tests/integration/test_db_job.py @@ -142,7 +142,9 @@ def test_load_with_filter_qos(submit_job): # PySlurm validates QoS names before querying — a bogus name raises ValueError with pytest.raises(ValueError, match="does not exist"): - jfilter_bad = pyslurm.db.JobFilter(ids=[job.id], qos=["nonexistent_qos"]) + jfilter_bad = pyslurm.db.JobFilter( + ids=[job.id], qos=["nonexistent_qos"] + ) pyslurm.db.Jobs.load(jfilter_bad) diff --git a/tests/integration/test_job_steps.py b/tests/integration/test_job_steps.py index 6aded75f..150de5da 100644 --- a/tests/integration/test_job_steps.py +++ b/tests/integration/test_job_steps.py @@ -104,9 +104,7 @@ def test_collection(submit_job): assert steps # We have 3 Steps: batch, 0 and 1 assert len(steps) == 3 - assert ("batch" in steps and - 0 in steps and - 1 in steps) + assert "batch" in steps and 0 in steps and 1 in steps def test_cancel(submit_job): @@ -114,9 +112,7 @@ def test_cancel(submit_job): steps = util.wait_for_steps(job.id, 3) assert len(steps) == 3 - assert ("batch" in steps and - 0 in steps and - 1 in steps) + assert "batch" in steps and 0 in steps and 1 in steps steps[0].cancel() util.wait_for_step_gone(job.id, 0, timeout=30) diff --git a/tests/integration/test_job_submit.py b/tests/integration/test_job_submit.py index c2ffb972..798ddfc9 100644 --- a/tests/integration/test_job_submit.py +++ b/tests/integration/test_job_submit.py @@ -25,6 +25,7 @@ JobSubmitDescription, ) + def job_desc(**kwargs): return JobSubmitDescription(script=create_job_script(), **kwargs) diff --git a/tests/integration/test_node.py b/tests/integration/test_node.py index 6da38625..07eaba10 100644 --- a/tests/integration/test_node.py +++ b/tests/integration/test_node.py @@ -34,12 +34,10 @@ def test_load(): assert node.weight is not None assert node.slurm_version is not None - with pytest.raises(RPCError, - match="Node 'nonexistent' does not exist"): + with pytest.raises(RPCError, match="Node 'nonexistent' does not exist"): Node.load("nonexistent") - def test_modify(): _, node = Nodes.load().popitem() diff --git a/tests/integration/test_partition.py b/tests/integration/test_partition.py index b64dc082..4664b890 100644 --- a/tests/integration/test_partition.py +++ b/tests/integration/test_partition.py @@ -33,8 +33,7 @@ def test_load(): assert part.name assert part.state - with pytest.raises(RPCError, - match="Partition 'nonexistent' doesn't exist"): + with pytest.raises(RPCError, match="Partition 'nonexistent' doesn't exist"): Partition.load("nonexistent") @@ -55,7 +54,7 @@ def test_modify(): assert Partition.load(part.name).default_time == 120 part.modify(Partition(default_time="1-00:00:00")) - assert Partition.load(part.name).default_time == 24*60 + assert Partition.load(part.name).default_time == 24 * 60 part.modify(Partition(max_time="UNLIMITED")) assert Partition.load(part.name).max_time == "UNLIMITED" @@ -95,6 +94,6 @@ def test_reload(): assert len(my_parts) == 2 for part in my_parts.values(): assert part.state != "UNKNOWN" - + for part in _tmp_parts.values(): part.delete() diff --git a/tests/integration/test_reservation.py b/tests/integration/test_reservation.py index e1ee3482..610cd7cd 100644 --- a/tests/integration/test_reservation.py +++ b/tests/integration/test_reservation.py @@ -34,7 +34,7 @@ def test_api_calls(): duration=duration, users=["root"], node_count=1, - reoccurrence="DAILY" + reoccurrence="DAILY", ) resv.create() diff --git a/tests/integration/test_slurmctld.py b/tests/integration/test_slurmctld.py index 5ad1551c..c494c089 100644 --- a/tests/integration/test_slurmctld.py +++ b/tests/integration/test_slurmctld.py @@ -84,8 +84,7 @@ def test_log_level(): slurmctld.set_log_level("debug2") assert slurmctld.get_log_level() == "debug2" - with pytest.raises(pyslurm.RPCError, - match=r"Invalid Log*"): + with pytest.raises(pyslurm.RPCError, match=r"Invalid Log*"): slurmctld.set_log_level("invalid") @@ -100,12 +99,10 @@ def test_fair_share_dampening_factor(): slurmctld.set_fair_share_dampening_factor(1) assert slurmctld.get_fair_share_dampening_factor() == 1 - with pytest.raises(pyslurm.RPCError, - match=r"Invalid Dampening*"): + with pytest.raises(pyslurm.RPCError, match=r"Invalid Dampening*"): slurmctld.set_fair_share_dampening_factor(0) - with pytest.raises(pyslurm.RPCError, - match=r"Invalid Dampening*"): + with pytest.raises(pyslurm.RPCError, match=r"Invalid Dampening*"): slurmctld.set_fair_share_dampening_factor(99999999) diff --git a/tests/integration/util.py b/tests/integration/util.py index f20fd59e..baf392da 100644 --- a/tests/integration/util.py +++ b/tests/integration/util.py @@ -149,8 +149,8 @@ def wait_for_job_done(job_id, timeout=POLL_TIMEOUT): def randstr(strlen=10): - chars = string.ascii_lowercase - return ''.join(random.choice(chars) for n in range(strlen)) + chars = string.ascii_lowercase + return "".join(random.choice(chars) for n in range(strlen)) def create_job_script(): From 0652a318efb8fe0c54fde8b08582b771659529e5 Mon Sep 17 00:00:00 2001 From: Giovanni Torres Date: Sun, 15 Mar 2026 09:50:39 -0400 Subject: [PATCH 5/5] style: run Ruff checker and formatter on scripts --- scripts/griffe_exts.py | 35 +++++++++++++++++++++-------------- scripts/pyslurm_bindgen.py | 29 +++++++++++++++++++---------- 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/scripts/griffe_exts.py b/scripts/griffe_exts.py index c55b9150..06d87164 100644 --- a/scripts/griffe_exts.py +++ b/scripts/griffe_exts.py @@ -30,27 +30,30 @@ SLURM_DOCS_URL_BASE = "https://slurm.schedmd.com/archive" SLURM_DOCS_URL_VERSIONED = f"{SLURM_DOCS_URL_BASE}/slurm-{SLURM_VERSION}-latest" -config_files = ["acct_gather.conf", - "slurm.conf", - "cgroup.conf", - "mpi.conf", - "scontrol"] +config_files = [ + "acct_gather.conf", + "slurm.conf", + "cgroup.conf", + "mpi.conf", + "scontrol", +] def replace_with_slurm_docs_url(match): first_part = match.group(1) second_part = match.group(2) ref = f"[{first_part}{second_part}]" - return f'{ref}({SLURM_DOCS_URL_VERSIONED}/{first_part}.html{second_part})' + return f"{ref}({SLURM_DOCS_URL_VERSIONED}/{first_part}.html{second_part})" pattern = re.compile( - r'\{(' - + '|'.join([re.escape(config) for config in config_files]) - + r')' # Match the first word before "#" - + r'([#][^}]+)\}' # Match "#" and everything after it until } + r"\{(" + + "|".join([re.escape(config) for config in config_files]) + + r")" # Match the first word before "#" + + r"([#][^}]+)\}" # Match "#" and everything after it until } ) + # This class is inspired from here, with a few adaptions: # https://github.com/mkdocstrings/griffe/blob/97f3613c5f0ae5653e8b91479c716b9ec44baacc/docs/guide/users/extending.md#full-example # @@ -70,8 +73,11 @@ def replace_with_slurm_docs_url(match): # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. class DynamicDocstrings(griffe.Extension): - def __init__(self, include_paths: list[str] | None = None, - ignore_paths: list[str] | None = None) -> None: + def __init__( + self, + include_paths: list[str] | None = None, + ignore_paths: list[str] | None = None, + ) -> None: self.include_paths = include_paths self.ignore_paths = ignore_paths @@ -84,8 +90,9 @@ def on_instance( **kwargs, ) -> None: - if ((self.include_paths and obj.path not in self.include_paths) - or (self.ignore_paths and obj.path in self.ignore_paths)): + if (self.include_paths and obj.path not in self.include_paths) or ( + self.ignore_paths and obj.path in self.ignore_paths + ): return try: diff --git a/scripts/pyslurm_bindgen.py b/scripts/pyslurm_bindgen.py index 82eb157c..2372bfc4 100755 --- a/scripts/pyslurm_bindgen.py +++ b/scripts/pyslurm_bindgen.py @@ -24,7 +24,6 @@ import click from datetime import datetime import os -import re import pathlib from collections import OrderedDict @@ -32,11 +31,12 @@ UINT16_RANGE = range((2**16)) UINT32_RANGE = range((2**32)) UINT64_RANGE = range((2**64)) -INT8_RANGE = range(-128, 127+1) +INT8_RANGE = range(-128, 127 + 1) # TODO: also translate slurm enums automatically as variables like: # = slurm. + def get_data_type(val): if val in UINT8_RANGE: return "uint8_t" @@ -67,14 +67,14 @@ def capture_copyright(hdr_file): def try_get_macro_value(s): if s.startswith("SLURM_BIT"): - val = int(s[s.find("(")+1:s.find(")")]) + val = int(s[s.find("(") + 1 : s.find(")")]) return 1 << val if s.startswith("0x"): return int(s, 16) if s.startswith("(0x"): - _s = s[s.find("(")+1:s.find(")")] + _s = s[s.find("(") + 1 : s.find(")")] return int(_s, 16) try: @@ -103,7 +103,10 @@ def translate_slurm_header(hdr_dir, hdr): macros = "".join(translate_hdr_macros(lines, hdr)) c = click.get_current_context() - if c.params["show_unparsed_macros"] or c.params["generate_python_const"]: + if ( + c.params["show_unparsed_macros"] + or c.params["generate_python_const"] + ): return codegen = autopxd.AutoPxd("slurm/" + hdr) @@ -204,7 +207,7 @@ def translate_hdr_macros(s, hdr): unknown = [] for line in s: if line.startswith("#define"): - name, ty = parse_macro(line.rstrip('\n'), hdr) + name, ty = parse_macro(line.rstrip("\n"), hdr) if ty: vals.update({name: ty}) elif name and not ty: @@ -226,13 +229,14 @@ def translate_hdr_macros(s, hdr): print("{} = slurm.{}".format(name, name)) else: hdr_file = "slurm/" + hdr - out.append(f"cdef extern from \"{hdr_file}\":\n") + out.append(f'cdef extern from "{hdr_file}":\n') out.append("\n") for name, ty in vals.items(): out.append(f" {ty} {name}\n") return out + def setup_include_path(hdr_dir): include_dir = pathlib.Path(hdr_dir).parent.as_posix() if not os.environ.get("C_INCLUDE_PATH", None): @@ -277,13 +281,18 @@ def setup_include_path(hdr_dir): is_flag=True, help="Instead of writing everything to files, just print to stdout.", ) -def main(slurm_header_dir, show_unparsed_macros, - generate_python_const, output_dir, stdout): +def main( + slurm_header_dir, + show_unparsed_macros, + generate_python_const, + output_dir, + stdout, +): setup_include_path(slurm_header_dir) translate_slurm_header(slurm_header_dir, "slurm_errno.h") translate_slurm_header(slurm_header_dir, "slurm.h") translate_slurm_header(slurm_header_dir, "slurmdb.h") -if __name__ == '__main__': +if __name__ == "__main__": main()