# content of pyproject.toml [build-system] requires = ["setuptools>=64.0.0", "wheel"] build-backend = "setuptools.build_meta" [project] name = "anta" version = "v0.15.0" readme = "docs/README.md" authors = [{ name = "Khelil Sator", email = "ksator@arista.com" }] maintainers = [ { name = "Khelil Sator", email = "ksator@arista.com" }, { name = "Matthieu Tâche", email = "mtache@arista.com" }, { name = "Thomas Grimonet", email = "tgrimonet@arista.com" }, { name = "Guillaume Mulocher", email = "gmulocher@arista.com" }, ] description = "Arista Network Test Automation (ANTA) Framework" license = { file = "LICENSE" } dependencies = [ "aiocache>=0.12.2", "asyncssh>=2.13.2", "cvprac>=1.3.1", "eval-type-backport>=0.1.3", # Support newer typing features in older Python versions (required until Python 3.9 support is removed) "Jinja2>=3.1.2", "pydantic>=2.7", "pydantic-extra-types>=2.3.0", "PyYAML>=6.0", "requests>=2.31.0", "rich>=13.5.2,<14", "httpx>=0.27.0" ] keywords = ["test", "anta", "Arista", "network", "automation", "networking", "devops", "netdevops"] classifiers = [ "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Development Status :: 4 - Beta", "Intended Audience :: Developers", "Intended Audience :: System Administrators", "Intended Audience :: Information Technology", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3 :: Only", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: Testing", "Topic :: System :: Networking", ] requires-python = ">=3.9" [project.optional-dependencies] cli = [ "click~=8.1.6", "click-help-colors>=0.9", ] dev = [ "bumpver>=2023.1129", "codespell~=2.2.6", "mypy-extensions~=1.0", "mypy~=1.10", "pre-commit>=3.3.3", "pylint-pydantic>=0.2.4", "pylint>=2.17.5", "pytest-asyncio>=0.21.1", "pytest-cov>=4.1.0", "pytest-dependency", "pytest-html>=3.2.0", "pytest-metadata>=3.0.0", "pytest>=7.4.0", "ruff>=0.3.7,<0.5.0", "tox>=4.10.0,<5.0.0", "types-PyYAML", "types-pyOpenSSL", "types-requests", "typing-extensions", "yamllint>=1.32.0", ] doc = [ "fontawesome_markdown", "griffe", "mike==2.1.1", "mkdocs-autorefs>=0.4.1", "mkdocs-bootswatch>=1.1", "mkdocs-git-revision-date-localized-plugin>=1.1.0", "mkdocs-git-revision-date-plugin>=0.3.2", "mkdocs-material-extensions>=1.0.3", "mkdocs-material>=8.3.9", "mkdocs>=1.3.1", "mkdocstrings[python]>=0.20.0", ] [project.urls] Homepage = "https://www.anta.ninja" "Bug Tracker" = "https://github.com/arista-netdevops-community/anta/issues" Contributing = "https://www.anta.ninja/main/contribution/" [project.scripts] anta = "anta.cli:cli" ################################ # Tools ################################ [tool.setuptools.packages.find] include = ["anta*", "asynceapi*"] namespaces = false ################################ # Version ################################ [tool.bumpver] current_version = "0.15.0" version_pattern = "MAJOR.MINOR.PATCH" commit_message = "bump: Version {old_version} -> {new_version}" commit = true # No tag tag = false push = false [tool.bumpver.file_patterns] "pyproject.toml" = ['current_version = "{version}"', 'version = "v{version}"'] "docs/contribution.md" = ["anta {version}"] "docs/requirements-and-installation.md " = ["anta, version v{version}"] ################################ # Typing # mypy as per https://pydantic-docs.helpmanual.io/mypy_plugin/#enabling-the-plugin ################################ [tool.mypy] plugins = [ "pydantic.mypy", ] # Comment below for better type checking #follow_imports = "skip" # Make it false if we implement stubs using stubgen from mypy for aio-eapi, aiocache and cvprac # and configure mypy_path to generated stubs e.g.: mypy_path = "./out" ignore_missing_imports = true warn_redundant_casts = true # Note: tox find some unused type ignore which are required for pre-commit # To investigate warn_unused_ignores = true disallow_any_generics = true check_untyped_defs = true no_implicit_reexport = true strict_optional = true # for strict mypy: (this is the tricky one :-)) disallow_untyped_defs = true [tool.pydantic-mypy] init_forbid_extra = true init_typed = true warn_required_dynamic_aliases = true warn_untyped_fields = true ################################ # Testing ################################ [tool.pytest.ini_options] # When run from anta directory this will read cov-config from pyproject.toml addopts = "-ra -q -vv --cov --cov-report term:skip-covered --color yes" log_level = "WARNING" render_collapsed = true testpaths = ["tests"] filterwarnings = [ "error", # cvprac is raising the next warning "default:pkg_resources is deprecated:DeprecationWarning", # Need to investigate the following - only occuring when running the full pytest suite "ignore:Exception ignored in.*:pytest.PytestUnraisableExceptionWarning", ] [tool.coverage.run] branch = true source = ["anta"] parallel = true [tool.coverage.report] # Regexes for lines to exclude from consideration exclude_lines = [ # Have to re-enable the standard pragma "pragma: no cover", # Don't complain about missing debug-only code: "def __repr__", "if self\\.debug", # Don't complain if tests don't hit defensive assertion code: "raise AssertionError", "raise NotImplementedError", # Don't complain if non-runnable code isn't run: "if 0:", "if __name__ == .__main__.:", # Don't complain about abstract methods, they aren't run: "@(abc\\.)?abstractmethod", # Don't complain about TYPE_CHECKING blocks "if TYPE_CHECKING:", ] ignore_errors = true [tool.coverage.html] directory = "coverage_html_report" [tool.coverage.xml] output = ".coverage.xml" ################################ # Tox ################################ [tool.tox] legacy_tox_ini = """ [tox] min_version = 4.0 envlist = clean, lint, type, py{39,310,311,312}, report [gh-actions] python = 3.9: py39 3.10: py310 3.11: erase, py311, report 3.12: py312 [testenv] description = Run pytest with {basepython} extras = dev cli # posargs allows to run only a specific test using # tox -e -- path/to/my/test::test commands = pytest {posargs} [testenv:lint] description = Check the code style commands = ruff check . ruff format . --check pylint anta pylint tests [testenv:type] description = Check typing commands = mypy --config-file=pyproject.toml anta mypy --config-file=pyproject.toml tests [testenv:clean] description = Erase previous coverage reports deps = coverage[toml] skip_install = true commands = coverage erase [testenv:report] description = Generate coverage report deps = coverage[toml] commands = coverage --version coverage html --rcfile=pyproject.toml coverage xml --rcfile=pyproject.toml # add the following to make the report fail under some percentage # commands = coverage report --fail-under=80 depends = py311 """ ################################ # Ruff ################################ [tool.ruff] # Exclude a variety of commonly ignored directories. exclude = [ ".bzr", ".direnv", ".eggs", ".git", ".git-rewrite", ".hg", ".ipynb_checkpoints", ".mypy_cache", ".nox", ".pants.d", ".pyenv", ".pytest_cache", ".pytype", ".ruff_cache", ".svn", ".tox", ".venv", ".vscode", "__pypackages__", "_build", "buck-out", "build", "dist", "node_modules", "site-packages", "venv", ".github", ] line-length = 165 # Assume Python 3.9 as this is the lowest supported version for ANTA target-version = "py39" [tool.ruff.lint] # select all cause we like being suffering select = ["ALL"] ignore = [ "ANN101", # Missing type annotation for `self` in method - we know what self is.. "D203", # Ignoring conflicting D* warnings - one-blank-line-before-class "D213", # Ignoring conflicting D* warnings - multi-line-summary-second-line "COM812", # Ignoring conflicting rules that may cause conflicts when used with the formatter "ISC001", # Ignoring conflicting rules that may cause conflicts when used with the formatter "TD002", # We don't have require authors in TODO "TD003", # We don't have an issue link for all TODOs today "FIX002", # Line contains TODO - ignoring for ruff for now "F821", # Disable undefined-name until resolution of #10451 ] # Allow autofix for all enabled rules (when `--fix`) is provided. fixable = ["ALL"] unfixable = [] # Allow unused variables when underscore-prefixed. dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" [tool.ruff.lint.pydocstyle] convention = "numpy" [tool.ruff.lint.pylint] # These settings are used to configure pylint rules run in ruff. In order to keep sane and while # we have not removed pylint completely, these settings should be kept in sync with our pylintrc file. # https://github.com/astral-sh/ruff/issues/970 max-branches = 13 [tool.ruff.lint.mccabe] # Unlike Flake8, default to a complexity level of 10. max-complexity = 10 [tool.ruff.lint.pep8-naming] "ignore-names" = [ "RICH_COLOR_PALETTE" ] [tool.ruff.lint.flake8-type-checking] # These classes require that type annotations be available at runtime runtime-evaluated-base-classes = ["pydantic.BaseModel", "anta.models.AntaTest.Input"] [tool.ruff.lint.per-file-ignores] "tests/*" = [ "S101", # Complains about asserts in units and libs. "SLF001", # Lots of private member accessed for test purposes ] "tests/units/*" = [ "BLE001", # Do not catch blind exception: `Exception` - already disabling this in pylint "FBT001", # Boolean-typed positional argument in function definition "PLR0913", # Too many arguments to function call (8 > 5) "PLR2004", # Magic value used in comparison, consider replacing {value} with a constant variable "S105", # Passwords are indeed hardcoded in tests "S106", # Passwords are indeed hardcoded in tests "S108", # Probable insecure usage of temporary file or directory ] "tests/units/anta_tests/test_interfaces.py" = [ "S104", # False positive for 0.0.0.0 bindings in test inputs ] "anta/*" = [ "BLE001", # Do not catch blind exception: `Exception` - caught by other linter "TRY400", # Use `logging.exception` instead of `logging.error` - we know what we are doing ] "anta/cli/exec/utils.py" = [ "SLF001", # TODO: some private members, lets try to fix ] "anta/cli/__init__.py" = [ "T201", # Allow print statements ] "anta/cli/*" = [ "PLR0913", # Allow more than 5 input arguments in CLI functions "ANN401", # TODO: Check if we can update the Any type hints in the CLI ] "anta/tests/field_notices.py" = [ "PLR2004", # Magic value used in comparison, consider replacing 2131 with a constant variable - Field notice IDs are magic values "C901", # TODO: test function is too complex, needs a refactor "PLR0911", # TODO: Too many return statements, same as above needs a refactor ] "anta/decorators.py" = [ "ANN401", # Ok to use Any type hint in our decorators ] "anta/tools.py" = [ "ANN401", # Ok to use Any type hint in our custom get functions "PLR0913", # Ok to have more than 5 arguments in our custom get functions ] "anta/device.py" = [ "PLR0913", # Ok to have more than 5 arguments in the AntaDevice classes ] "anta/inventory/__init__.py" = [ "PLR0913", # Ok to have more than 5 arguments in the AntaInventory class ] "examples/anta_runner.py" = [ # This is an example script and linked in snippets "S108", # Probable insecure usage of temporary file or directory "S105", # Possible hardcoded password "INP001", # Implicit packages ] ################################ # Pylint ################################ [tool.pylint.'MESSAGES CONTROL'] disable = [ "invalid-name", "fixme" ] [tool.pylint.DESIGN] max-statements=61 max-returns=8 max-locals=23 [tool.pylint.FORMAT] max-line-length=165 max-module-lines=1700 [tool.pylint.SIMILARITIES] # making similarity lines limit a bit higher than default 4 min-similarity-lines=10 [tool.pylint.TYPECHECK] # https://stackoverflow.com/questions/49680191/click-and-pylint signature-mutators="click.decorators.option" [tool.pylint.MAIN] load-plugins="pylint_pydantic" extension-pkg-whitelist="pydantic" ignore-paths = [ "^tests/units/anta_tests/.*/data.py$", "^tests/units/anta_tests/routing/.*/data.py$", "^docs/scripts/anta_runner.py", ]