[tool.poetry]
name = "nautobot"
# Primary package version gets set here. This is used for publishing, and once
# installed, `nautobot.__version__` will have this version number.
version = "2.4.30"
description = "Source of truth and network automation platform."
authors = ["Network to Code <opensource@networktocode.com>"]
license = "Apache-2.0"
homepage = "https://nautobot.com"
repository = "https://github.com/nautobot/nautobot"
documentation = "https://docs.nautobot.com"
readme = "README.md"
keywords = ["Nautobot"]
classifiers = [
    "Intended Audience :: Developers",
    "Development Status :: 5 - Production/Stable",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
]
packages = [
    {include = "nautobot"}
]
include = [
    # Rendered documentation - Poetry by default would exclude these files as they are in .gitignore
    {path = "nautobot/project-static/docs/**/*", format = ["sdist", "wheel"]},
]
exclude = [
    # Source code of the documentation doesn't need to be included since we package the rendered docs
    "nautobot/docs/**/*",
]

[tool.poetry.dependencies]
python = ">=3.10,<3.13"
# Background task processing
celery = "~5.6.2"
# Cryptographic recipes and primitives.
# Not directly used by Nautobot itself, but key to many of Nautobot's dependencies.
# Added as an explicit dependency to protect against various CVEs in older versions.
cryptography = "~46.0.6"
# Fundamental web framework for Nautobot
Django = "~4.2.29"
# Adds AJAX capabilities to django-tables2
django-ajax-tables = "~1.1.1"
# LDAP Support
django-auth-ldap = {version = "~5.2.0", optional = true}
# Base functionality for task scheduling with Celery
# Not yet upgrading to v2.8.x due to numerous reported issues, including:
# https://github.com/celery/django-celery-beat/issues/894
# https://github.com/celery/django-celery-beat/issues/922
# https://github.com/celery/django-celery-beat/issues/927
django-celery-beat = "~2.7.0"
# Provides a database backend & models for Celery task results
django-celery-results = "~2.6.0"
# Management of app configuration via the Django admin UI
django-constance = "~4.3.3"
# Permit cross-domain API requests
django-cors-headers = "~4.9.0"
# Store files in the database for background tasks
django-db-file-storage = "~0.5.6.1"
# AutoSlugField and shell_plus
django-extensions = "~4.1"
# Advanced query filters
django-filter = "~25.1"
# Health check endpoint
django-health-check = "~3.20.0"
# Django Jinja - jinja2 backend for django, used to easily register custom jinja filters and render jinja.
django-jinja = "~2.11.0"
# Prometheus metrics for Django
django-prometheus = "~2.4.1"
# Redis cache for Django used for distributed locking
django-redis = "~6.0.0"
# Django silk for request profiling
django-silk = "~5.4.3"
# External Storage support (i.e. S3)
django-storages = {version = "~1.14.6", optional = true}
# Structured logging for Django
django-structlog = {version = "~10.0.0", extras = ["celery"]}
# Advanced HTML tables
django-tables2 = "~2.8.0"
# Tags
django-taggit = "~6.1.0"
# Represent time zones in Django
django-timezone-field = "~7.2.1"
# Tree database structures based on Common Table Expressions
django-tree-queries = "~0.23.0"
# Run production webservers such as uWSGI/gunicorn as a Django management command.
django-webserver = "~1.2.0"
# REST API framework
djangorestframework = "~3.16.1"
# OpenAPI 3.0 schema generation for the REST API
# Avoiding 0.29.0 for now due to https://github.com/tfranzel/drf-spectacular/issues/1475
drf-spectacular = {version = "~0.28.0", extras = ["sidecar"]}
# Emoji terminal output for Python.
emoji = "~2.15.0"
# Git integrations for Python
GitPython = "~3.1.45"
# GraphQL support
# NOTE: graphene-django 3.x is available but includes breaking changes. Will address in a future release.
graphene-django = "~2.16.0"
# Graphene Optimizer
# NOTE: graphene-django-optimizer 0.9 and later require Graphene v3
graphene-django-optimizer = "~0.8.0"
# Template rendering engine
Jinja2 = "~3.1.6"
# Optional data validation of config contexts - loose dependency since our usage is light but apps may be more specific
jsonschema = "^4.7.0"
# Library to access Kubernetes API used to develop K8s integration
kubernetes = "^33.1.0"
# Rendering of markdown files to HTML
Markdown = "~3.8.2"
# MySQL database adapter
mysqlclient = {version = "~2.2.8", optional = true}
# NAPALM automation library
napalm = {version = ">=4.1.0,<6.0.0", optional = true}
# IP prefix and address handling
netaddr = "~1.3.0"
# Library of network related utilities including network driver mappings and Jinja Filters
# Note: netutils is limited in scope, dependencies, and observes semver, as such
#       we permit a looser (^) version constraint here.
netutils = "^1.14.0"
# HTML sanitization
nh3 = "~0.3.2"
# Handling of version numbers
packaging = ">=23.1"
# Image processing library
Pillow = "^12.1.1"
# Custom prometheus metrics
prometheus-client = "~0.23.1"
# PostgreSQL database adapter
# NOTE: psycopg3 is available now and nominally replaces psycopg2
psycopg2-binary = "~2.9.11"
# A Python slugify application that handles unicode.
python-slugify = "~8.0.4"
# The uWSGI WSGI HTTP server as a Python module
pyuwsgi = "~2.0.30"
# YAML parsing and rendering
PyYAML = "~6.0.3"
# Social authentication core
# Note that social-auth-app-django (below) is *not* an optional dependency, and it requires social-auth-core in turn.
# The only part of this dependency that is actually optional is in fact social-auth-core's "saml" extra.
social-auth-core = {version = "~4.8.5", optional = true, extras = ["saml"]}
# Social authentication/registration with support for many auth providers
# NOTE: When upgrading to 5.6.0 or later, remove the patch in nautobot/core/apps/__init__.py
#       that addresses a security vulnerability in social-auth-app-django 5.4.3
social-auth-app-django = "~5.4.3"
# Rendering of SVG images (for rack elevations, etc.)
svgwrite = "~1.4.3"

[tool.poetry.extras]
all = ["django-auth-ldap", "django-storages", "mysqlclient", "napalm", "social-auth-core"]
ldap = ["django-auth-ldap"]
mysql = ["mysqlclient"]
napalm = ["napalm"]
# This is not currently possible, there is a feature request with Poetry https://github.com/python-poetry/poetry/issues/3913
# openid = ["social-auth-core[openidconnect]"]
remote_storage = ["django-storages"]
# This is not currently possible, there is a feature request with Poetry https://github.com/python-poetry/poetry/issues/3913
# saml = ["social-auth-core[saml]"]
sso = ["social-auth-core"]

[tool.poetry.group.dev.dependencies]
# Tool for debugging Django
# Currently pinned to 5.2.0 due to https://github.com/django-commons/django-debug-toolbar/issues/2168
django-debug-toolbar = "~5.2.0"
# Nautobot example App used for testing
example-app = {path = "examples/example_app", develop = true}
# Nautobot test App used for testing core view overrides
example-app-with-view-override = {path = "examples/example_app_with_view_override", develop = true}
# Random data generation
factory-boy = "~3.3.3"
# Factory Boy dependency.
faker = "^37.11.0"
# Alternative to Make, CLI based on `tasks.py`
invoke = "~2.2.1"
# Colorization and autoformatting of CLI output, used for Invoke tasks
rich = "~14.2.0"
# Change log management and generation
towncrier = "~25.8.0"
# Watch files for celery and mkdocs reload
watchdog = "~6.0.0"

[tool.poetry.group.docs.dependencies]
# Rendering docs to HTML
mkdocs = "~1.6.1"
# Embedding YAML files into Markdown documents as tables
markdown-data-tables = "~1.0.0"
# Render custom markdown for version added/changed/remove notes
markdown-version-annotations = "~1.0.1"
# Automatically generate some files as part of mkdocs build
mkdocs-gen-files = "~0.6.0"
# Image lightboxing in mkdocs
mkdocs-glightbox = "~0.5.2"
# Use Jinja2 templating in docs - see settings.md
mkdocs-macros-plugin = "~1.5.0"
# Material for mkdocs theme
mkdocs-material = "~9.7.0"
# Handle docs redirections
mkdocs-redirects = "~1.2.2"
# Automatically handle index pages for docs sections
mkdocs-section-index = "~0.3.10"
# Automatic documentation from sources, for MkDocs
mkdocstrings = "~0.30.1"
# Python-specific extension to mkdocstrings
mkdocstrings-python = "~1.19.0"

[tool.poetry.group.linting.dependencies]
# Django template files indenter
djhtml = "~3.0.10"
# Django template files linter and formatter
djlint = "~1.36.4"
# Code static analysis
pylint = "~3.3.9"
# Pylint extensions for Django
pylint-django = "~2.6.1"
# Python implementation of markdownlint
pymarkdownlnt = "~0.9.33"
# Combination linter and code formatter
ruff = "~0.14.8"
# YAML linting
yamllint = "~1.37.1"

[tool.poetry.group.testing.dependencies]
# Test code coverage measurement
coverage = "~7.13.4"
# Testing of data migrations
django-test-migrations = "~1.5.0"
# OpenAPI validator to test that our generated schema is valid
openapi-spec-validator = "~0.7.2"
# Integration Tests
requests = "~2.33.0"
# Selenium web drivers for live integration testing
selenium = "~4.36.0"
# Abstraction layer for working with Selenium
splinter = "~0.21.0"
# Serialization of tracebacks - used when running unittest with --parallel flag
tblib = "~3.2.2"
# Time travel for testing, used in ScheduledJob tests etc.
time-machine = "~2.19.0"

[tool.poetry.scripts]
nautobot-server = "nautobot.core.cli:main"
nautobot-migrate-deprecated-templates = "nautobot.core.cli.migrate_deprecated_templates:main"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

[tool.coverage.run]
concurrency = ["multiprocessing", "thread"]
disable_warnings = ["already-imported"]
include = [
    "nautobot/*",
]
omit = [
    # Don't measure coverage of test code
    "nautobot/**/tests/**/*.py",
    "nautobot/core/testing/*.py",
    "nautobot/extras/test_jobs/*.py",
]
relative_files = true

[tool.djlint]
ignore = "H005,H006,H008,H011,H012,H013,H014,H015,H016,H019,H020,H021,H022,H023,H025,H026,H030,H031,H037,T001,T002,T003"
profile="django"
extend_exclude = "docs/,example_app/static,nautobot/project-static/"

[tool.pylint.master]
load-plugins = "pylint_django"
py-version = "3.10"
ignore-paths = [
    ".*third_party.*",
    "nautobot/extras/tests/git_data/02-invalid-files/",
]
jobs = 0

[tool.pylint.basic]
# No docstrings required yet for private functions, or for test_* functions, or for inner Meta classes.
no-docstring-rgx="^(_|test_|Meta$)"
# Don't complain about "pk" as a variable name
good-names = """_,i,j,k,pk"""

[tool.pylint.message_control]
# TODO: re-enable and fix these as time permits
disable = [
    # Warnings
    "abstract-method",
    "attribute-defined-outside-init",
    "broad-except",
    "fixme",
    "global-statement",
    "global-variable-not-assigned",
    "logging-format-interpolation",
    "logging-fstring-interpolation",
    "pointless-statement",
    "pointless-string-statement",
    "protected-access",
    "raise-missing-from",
    "self-assigning-variable",
    "signature-differs",
    "unspecified-encoding",
    "unused-argument",
    "unused-import",  # covered by ruff?
    "unused-wildcard-import",
    "wildcard-import",
    # Conventions
    "consider-iterating-dictionary",
    "empty-docstring",
    "import-outside-toplevel",
    "invalid-name",
    "keyword-arg-before-vararg",  # https://github.com/pylint-dev/pylint/issues/7396
    "line-too-long",
    "missing-class-docstring",
    "missing-function-docstring",
    "missing-module-docstring",
    "superfluous-parens",
    "too-many-lines",
    "ungrouped-imports",
    "unnecessary-dunder-call",
    "use-maxsplit-arg",
    "wrong-import-order",
    "wrong-import-position",
    # Refactoring
    "consider-using-from-import",
    "consider-using-in",
    "consider-using-generator",
    "cyclic-import",
    "duplicate-code",
    "no-else-break",
    "no-else-raise",
    "no-else-return",
    "super-with-arguments",
    "too-few-public-methods",
    "too-many-ancestors",
    "too-many-arguments",
    "too-many-boolean-expressions",
    "too-many-branches",
    "too-many-instance-attributes",
    "too-many-locals",
    "too-many-nested-blocks",
    "too-many-positional-arguments",
    "too-many-public-methods",
    "too-many-return-statements",
    "too-many-statements",
    # Pylint-Django
    "modelform-uses-exclude",
]

[tool.pylint.miscellaneous]
# We don't want to fail on "TODO" comments as there are plenty of those in our code for good reason
notes = ["FIXME", "XXX"]

[tool.pylint.typecheck]
# Regex patterns describing dynamically defined attributes that cause false reports for "no-member" checker
generated-members = [
    ".*Factory\\..*",
    ".*FactoryOptions\\..*",
    ".*FilterSet\\._meta",
    ".*FilterSet\\.base_filters",
    ".*FilterSet\\.declared_filters",
    ".*Job\\.request",
    ".*LazyAttribute\\..*",  # factory attributes
    ".*Maybe\\..*",  # factory attributes
    ".*Serializer\\.Meta",
    ".*Table\\._meta",
    ".*Table\\.base_columns",
    ".*Table\\.context",
]
extension-pkg-allow-list = [
    "nh3",
]
# @patch changes the signature of a function it's applied to; don't raise "no-value-for-parameter" here
signature-mutators = ["unittest.mock.patch"]

[tool.pymarkdown]
extensions.front-matter.enabled = true  # needed for mkdocs-macros compatibility
plugins.additional_paths = "scripts/file_relative_links.py"
plugins.code-block-style.enabled = false  # inconsistency between "code" blocks and "admonition" blocks is expected
plugins.line-length.enabled = false  # we don't wrap markdown to 80 characters.
plugins.list-anchored-indent.enabled = true  # in place of ul-indent, see below
plugins.proper-names.names = "Celery,Django,Nautobot,Pylint,PyMarkdown,Python,REST API"
plugins.proper-names.code_blocks = false  # don't check proper nouns inside ```code blocks```
plugins.proper-names.code_spans = false  # don't check proper nouns inside `code spans`
plugins.ul-indent.enabled = false  # doesn't work well with MkDocs expectations, use list-anchored-indent instead

[tool.ruff]
line-length = 120
target-version = "py310"
extend-exclude = [
    # Intentionally malformed files
    "nautobot/extras/tests/git_data/02-invalid-files/jobs",
]

[tool.ruff.lint]
select = [
    "DJ",  # flake8-django
    "E",  # pycodestyle
    "F",  # pyflakes
    "I",  # isort
    "PIE",  # flake8-pie
    "PLE",  # pylint errors
    "RUF",  # ruff itself
    "S",  # flake8-bandit
    "W",  # pycodestyle
]
ignore = [
    "E501",  # pycodestyle: line-too-long
    "PIE808",  # unnecessary-range-start
    "RUF012",  # mutable-class-default - see https://github.com/astral-sh/ruff/issues/5243
]

[tool.ruff.lint.isort]
combine-as-imports = true
force-sort-within-sections = true
known-local-folder = ["example_app"]
order-by-type = false

[tool.towncrier]
package = "nautobot"
directory = "changes"
filename = "nautobot/docs/release-notes/version-2.4.md"
template = "development/towncrier_template.j2"
start_string = "<!-- towncrier release notes start -->"
issue_format = "[#{issue}](https://github.com/nautobot/nautobot/issues/{issue})"

[[tool.towncrier.type]]
directory = "breaking"
name = "Breaking Changes"
showcontent = true

[[tool.towncrier.type]]
directory = "security"
name = "Security"
showcontent = true

[[tool.towncrier.type]]
directory = "added"
name = "Added"
showcontent = true

[[tool.towncrier.type]]
directory = "changed"
name = "Changed"
showcontent = true

[[tool.towncrier.type]]
directory = "deprecated"
name = "Deprecated"
showcontent = true

[[tool.towncrier.type]]
directory = "removed"
name = "Removed"
showcontent = true

[[tool.towncrier.type]]
directory = "fixed"
name = "Fixed"
showcontent = true

[[tool.towncrier.type]]
directory = "dependencies"
name = "Dependencies"
showcontent = true

[[tool.towncrier.type]]
directory = "documentation"
name = "Documentation"
showcontent = true

[[tool.towncrier.type]]
directory = "housekeeping"
name = "Housekeeping"
showcontent = true
