pyproject.toml 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. # See PEP 518 for the spec of this file
  2. # https://www.python.org/dev/peps/pep-0518/
  3. [build-system]
  4. requires = ["hatchling>=1.27", "packaging"]
  5. build-backend = "hatchling.build"
  6. [project]
  7. name = "netbox"
  8. dynamic = ["version", "dependencies"]
  9. requires-python = ">=3.12"
  10. description = "The premier source of truth powering network automation."
  11. readme = "README.md"
  12. license = "Apache-2.0"
  13. license-files = ["LICENSE.txt"]
  14. authors = [{ name = "NetBox Community" }]
  15. classifiers = [
  16. "Development Status :: 5 - Production/Stable",
  17. "Framework :: Django",
  18. "Natural Language :: English",
  19. "Programming Language :: Python",
  20. "Programming Language :: Python :: 3 :: Only",
  21. "Programming Language :: Python :: 3.12",
  22. "Programming Language :: Python :: 3.13",
  23. "Programming Language :: Python :: 3.14",
  24. ]
  25. [project.optional-dependencies]
  26. ldap = ["django-auth-ldap"]
  27. saml2 = ["python3-saml"]
  28. remote-auth = ["django-auth-ldap", "python3-saml"]
  29. sentry = ["sentry-sdk"]
  30. swift = ["django-storage-swift"]
  31. s3 = ["boto3"]
  32. git = ["dulwich"]
  33. # NetBox Labs plugins (proprietary, opt-in). Minor-bounded to the tested series.
  34. branching = ["netboxlabs-netbox-branching>=1.1.0,<1.2.0"]
  35. custom-objects = ["netboxlabs-netbox-custom-objects>=0.5.0,<0.6.0"]
  36. # Convenience aggregate of the recommended NetBox Labs plugins (NOT a catch-all of every extra).
  37. # The component pins are duplicated literally, as remote-auth duplicates ldap and saml2;
  38. # scripts/verify_wheel_metadata.py verifies in CI that this aggregate equals the union of the
  39. # branching and custom-objects extras, guarding the duplication against drift.
  40. recommended-plugins = [
  41. "netboxlabs-netbox-branching>=1.1.0,<1.2.0",
  42. "netboxlabs-netbox-custom-objects>=0.5.0,<0.6.0",
  43. ]
  44. dev = [
  45. "build",
  46. "coverage",
  47. "packaging",
  48. "pre-commit",
  49. "ruff==0.15.10",
  50. "tblib",
  51. "twine",
  52. "uv",
  53. ]
  54. [project.scripts]
  55. netbox = "netbox.cli:main"
  56. [project.urls]
  57. Homepage = "https://netboxlabs.com/products/netbox/"
  58. Documentation = "https://netboxlabs.com/docs/netbox/"
  59. Source = "https://github.com/netbox-community/netbox"
  60. Issues = "https://github.com/netbox-community/netbox/issues"
  61. [tool.coverage.run]
  62. source = ["netbox/"]
  63. concurrency = ["multiprocessing"]
  64. parallel = true
  65. sigterm = true
  66. [tool.coverage.report]
  67. skip_covered = true
  68. fail_under = 91
  69. omit = [
  70. "*/migrations/*",
  71. "*/tests/*",
  72. # Non-application code (no testable logic / not part of the app)
  73. "netbox/scripts/*", # SCRIPTS_ROOT: user/generated scripts
  74. "*/netbox/configuration*.py", # settings/config files (template, testing, local)
  75. "*/netbox/wsgi.py", # WSGI entrypoint
  76. "*/netbox/__main__.py", # `python -m netbox` entry point
  77. "*/generate_secret_key.py", # standalone CLI helper
  78. "*/utilities/debug.py", # debug-toolbar hook, active only when DEBUG=True
  79. "*/extras/management/commands/housekeeping.py", # deprecated; will not be tested
  80. ]
  81. [tool.hatch.metadata.hooks.custom]
  82. # Implemented in scripts/packaging/hatch_metadata.py; computes a PEP 440 version from
  83. # netbox/release.yaml (version + optional designation) and runtime deps from requirements.txt.
  84. path = "scripts/packaging/hatch_metadata.py"
  85. [tool.hatch.build.targets.wheel]
  86. sources = ["netbox"]
  87. packages = [
  88. "netbox/account",
  89. "netbox/circuits",
  90. "netbox/core",
  91. "netbox/dcim",
  92. "netbox/extras",
  93. "netbox/ipam",
  94. "netbox/netbox",
  95. "netbox/tenancy",
  96. "netbox/users",
  97. "netbox/utilities",
  98. "netbox/virtualization",
  99. "netbox/vpn",
  100. "netbox/wireless",
  101. ]
  102. # Never ship a live or local configuration file: configuration.py holds SECRET_KEY
  103. # and database credentials, ldap_config.py holds LDAP bind credentials, and developers
  104. # often keep ad-hoc configuration*.py copies in this directory. Exclude both sets, then
  105. # re-include only the two tracked templates. (verify_wheel_contents.py enforces this in CI.)
  106. exclude = [
  107. "netbox/netbox/configuration*.py",
  108. "netbox/netbox/ldap_config*.py",
  109. ]
  110. # Bundle runtime data inside the installed netbox package at netbox/_data/.
  111. # Destinations carry an extra leading "netbox/" because the wheel `sources`
  112. # setting above strips one "netbox/" prefix from every path (including these
  113. # force-include targets); after stripping they resolve to netbox/_data/...
  114. [tool.hatch.build.targets.wheel.force-include]
  115. "netbox/templates" = "netbox/netbox/_data/templates"
  116. "netbox/translations" = "netbox/netbox/_data/translations"
  117. "netbox/project-static/dist" = "netbox/netbox/_data/project-static/dist"
  118. "netbox/project-static/img" = "netbox/netbox/_data/project-static/img"
  119. "netbox/project-static/js" = "netbox/netbox/_data/project-static/js"
  120. "netbox/release.yaml" = "netbox/netbox/_data/release.yaml"
  121. "contrib/gunicorn.py" = "netbox/netbox/_data/examples/gunicorn.py"
  122. # The canonical contrib files are bundled as-is; `netbox setup` adapts the systemd units for
  123. # a pip install at render time (see _PIP_TRANSFORMS in netbox/netbox/scaffold.py).
  124. "contrib/netbox.service" = "netbox/netbox/_data/examples/netbox.service"
  125. "contrib/netbox-rq.service" = "netbox/netbox/_data/examples/netbox-rq.service"
  126. "contrib/nginx.conf" = "netbox/netbox/_data/examples/nginx.conf"
  127. "contrib/apache.conf" = "netbox/netbox/_data/examples/apache.conf"
  128. "contrib/netbox.env" = "netbox/netbox/_data/examples/netbox.env"
  129. # Force the two tracked config templates in over the configuration*.py exclude above.
  130. "netbox/netbox/configuration_example.py" = "netbox/netbox/configuration_example.py"
  131. "netbox/netbox/configuration_testing.py" = "netbox/netbox/configuration_testing.py"
  132. [tool.hatch.build.targets.sdist]
  133. include = [
  134. "/.github/workflows/release.yml",
  135. "/CHANGELOG.md",
  136. "/LICENSE.txt",
  137. "/README.md",
  138. "/base_requirements.txt",
  139. "/contrib",
  140. "/docs",
  141. "/mkdocs.yml",
  142. "/netbox",
  143. "/pyproject.toml",
  144. "/requirements.txt",
  145. "/scripts",
  146. "/upgrade.sh",
  147. ]
  148. # Keep live/local configuration*.py and ldap_config*.py out of the sdist (same rule as the
  149. # wheel, keeping only the two tracked templates), and drop the local netbox/configuration.py
  150. # symlink that otherwise breaks `python -m build --sdist` with an AbsoluteLinkError.
  151. exclude = [
  152. "netbox/netbox/configuration*.py",
  153. "netbox/netbox/ldap_config*.py",
  154. "netbox/configuration.py",
  155. "netbox/ldap_config.py",
  156. ]
  157. [tool.hatch.build.targets.sdist.force-include]
  158. # Force the two tracked config templates in over the configuration*.py exclude above.
  159. "netbox/netbox/configuration_example.py" = "netbox/netbox/configuration_example.py"
  160. "netbox/netbox/configuration_testing.py" = "netbox/netbox/configuration_testing.py"
  161. [tool.pyright]
  162. include = ["netbox"]
  163. exclude = [
  164. "**/node_modules",
  165. "**/__pycache__",
  166. ]
  167. reportMissingImports = true
  168. reportMissingTypeStubs = false
  169. [tool.ruff]
  170. exclude = [
  171. ".eggs",
  172. ".git",
  173. ".pyenv",
  174. ".pytest_cache",
  175. ".ruff_cache",
  176. ".venv",
  177. ".vscode",
  178. "__pypackages__",
  179. "_build",
  180. "build",
  181. "dist",
  182. "netbox/project-static/**",
  183. "node_modules",
  184. "site-packages",
  185. "venv",
  186. ]
  187. # Enforce line length and indent-width
  188. line-length = 120
  189. indent-width = 4
  190. # Ignores anything in .gitignore
  191. respect-gitignore = true
  192. # Always generate Python 3.12-compatible code
  193. target-version = "py312"
  194. [tool.ruff.lint]
  195. # Pin the effective default rule set used with `preview = true` to match Ruff 0.15.1.
  196. # Ruff 0.15.2 changed the preview defaults, see https://github.com/astral-sh/ruff/releases/tag/0.15.2
  197. # Keeping this explicit makes ruff deterministic.
  198. select = ["E4", "E7", "E9", "F"]
  199. extend-select = [
  200. "E1", # pycodestyle errors: indentation-related (e.g., unexpected/missing indent)
  201. "E2", # pycodestyle errors: whitespace-related (e.g., missing whitespace, extra spaces)
  202. "E3", # pycodestyle errors: blank lines / spacing around definitions
  203. "E501", # pycodestyle: line too long (enforced with `line-length` above)
  204. "W", # pycodestyle warnings (various style warnings, often whitespace/newlines)
  205. "I", # import sorting (isort-equivalent)
  206. "RET", # return semantics (flake8-return family: consistent/explicit returns; remove redundant else/assign before return)
  207. "UP", # pyupgrade: modernize syntax for your target Python (e.g., f-strings, built-in generics, newer stdlib idioms)
  208. "RUF022", # ruff: enforce sorted `__all__` lists
  209. ]
  210. # If you add a rule to `ignore`, please also update the "Linter Exceptions" section in
  211. # docs/development/style-guide.md.
  212. ignore = [
  213. "F403", # pyflakes: `from ... import *` used; unable to detect undefined names
  214. "F405", # pyflakes: name may be undefined or defined from star imports
  215. "RET504", # return: unnecessary assignment before `return` (e.g., `x = expr; return x` -> `return expr`)
  216. "UP032", # pyupgrade: prefer f-strings over `str.format(...)`
  217. ]
  218. preview = true
  219. [tool.ruff.lint.isort]
  220. known-first-party = [
  221. "account",
  222. "circuits",
  223. "core",
  224. "dcim",
  225. "extras",
  226. "ipam",
  227. "netbox",
  228. "tenancy",
  229. "users",
  230. "utilities",
  231. "virtualization",
  232. "vpn",
  233. "wireless",
  234. ]
  235. [tool.ruff.lint.per-file-ignores]
  236. "template_code.py" = ["E501"]
  237. "netbox/netbox/graphql/filter_lookups.py" = ["UP046"] # Strawberry typing: keep `Generic[T]` for now
  238. "netbox/netbox/graphql/scalars.py" = ["UP007"] # Strawberry scalar typing: `Union[...]` required
  239. [tool.ruff.format]
  240. # Use single quotes for strings.
  241. quote-style = "single"
  242. # Indent with spaces, rather than tabs.
  243. indent-style = "space"
  244. # Enforce UNIX line ending
  245. line-ending = "lf"