2025-02-05 11:32:35 +01:00
# content of pyproject.toml
[ build-system ]
requires = [ "setuptools>=64.0.0" , "wheel" ]
build-backend = "setuptools.build_meta"
[ project ]
name = "anta"
2025-02-05 11:55:09 +01:00
version = "v1.2.0"
2025-02-05 11:32:35 +01:00
readme = "docs/README.md"
2025-02-05 11:53:44 +01:00
authors = [ { name = "Arista Networks ANTA maintainers" , email = "anta-dev@arista.com" } ]
2025-02-05 11:32:35 +01:00
maintainers = [
2025-02-05 11:53:44 +01:00
{ name = "Arista Networks ANTA maintainers" , email = "anta-dev@arista.com" } ,
2025-02-05 11:32:35 +01:00
{ 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" } ,
2025-02-05 11:53:44 +01:00
{ name = "Carl Baillargeon" , email = "carl.baillargeon@arista.com" } ,
2025-02-05 11:32:35 +01:00
]
description = "Arista Network Test Automation (ANTA) Framework"
license = { file = "LICENSE" }
dependencies = [
2025-02-05 11:39:42 +01:00
"aiocache>=0.12.2" ,
2025-02-05 11:54:23 +01:00
"asyncssh>=2.16" ,
2025-02-05 11:39:42 +01:00
"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)
2025-02-05 11:55:09 +01:00
"httpx>=0.27.0" ,
2025-02-05 11:39:42 +01:00
"Jinja2>=3.1.2" ,
"pydantic>=2.7" ,
"pydantic-extra-types>=2.3.0" ,
"PyYAML>=6.0" ,
"requests>=2.31.0" ,
2025-02-05 11:55:09 +01:00
"rich>=13.5.2,<14"
2025-02-05 11:32:35 +01:00
]
keywords = [ "test" , "anta" , "Arista" , "network" , "automation" , "networking" , "devops" , "netdevops" ]
classifiers = [
"License :: OSI Approved :: Apache Software License" ,
"Operating System :: OS Independent" ,
2025-02-05 11:53:44 +01:00
"Development Status :: 5 - Production/Stable" ,
2025-02-05 11:32:35 +01:00
"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" ,
2025-02-05 11:55:09 +01:00
"Programming Language :: Python :: 3.13" ,
2025-02-05 11:32:35 +01:00
"Programming Language :: Python :: 3 :: Only" ,
"Topic :: Software Development :: Libraries :: Python Modules" ,
"Topic :: Software Development :: Testing" ,
"Topic :: System :: Networking" ,
]
2025-02-05 11:38:32 +01:00
requires-python = ">=3.9"
2025-02-05 11:32:35 +01:00
[ project . optional-dependencies ]
2025-02-05 11:39:42 +01:00
cli = [
"click~=8.1.6" ,
"click-help-colors>=0.9" ,
]
2025-02-05 11:32:35 +01:00
dev = [
2025-02-05 11:39:42 +01:00
"bumpver>=2023.1129" ,
2025-02-05 11:53:44 +01:00
"codespell>=2.2.6,<2.4.0" ,
2025-02-05 11:32:35 +01:00
"mypy-extensions~=1.0" ,
2025-02-05 11:39:42 +01:00
"mypy~=1.10" ,
2025-02-05 11:32:35 +01:00
"pre-commit>=3.3.3" ,
2025-02-05 11:39:42 +01:00
"pylint-pydantic>=0.2.4" ,
2025-02-05 11:32:35 +01:00
"pylint>=2.17.5" ,
"pytest-asyncio>=0.21.1" ,
"pytest-cov>=4.1.0" ,
"pytest-dependency" ,
2025-02-05 11:54:23 +01:00
"pytest-codspeed>=2.2.0" ,
2025-02-05 11:32:35 +01:00
"pytest-html>=3.2.0" ,
2025-02-05 11:54:23 +01:00
"pytest-httpx>=0.30.0" ,
2025-02-05 11:32:35 +01:00
"pytest-metadata>=3.0.0" ,
2025-02-05 11:39:42 +01:00
"pytest>=7.4.0" ,
2025-02-05 11:55:09 +01:00
"respx>=0.22.0" ,
"ruff>=0.5.4,<0.9.0" ,
2025-02-05 11:32:35 +01:00
"tox>=4.10.0,<5.0.0" ,
"types-PyYAML" ,
2025-02-05 11:39:42 +01:00
"types-pyOpenSSL" ,
2025-02-05 11:32:35 +01:00
"types-requests" ,
"typing-extensions" ,
"yamllint>=1.32.0" ,
]
doc = [
2025-02-05 11:54:23 +01:00
"fontawesome_markdown>=0.2.6" ,
"griffe >=1.2.0" ,
"mike==2.1.3" ,
"mkdocs>=1.6.1" ,
"mkdocs-autorefs>=1.2.0" ,
2025-02-05 11:32:35 +01:00
"mkdocs-bootswatch>=1.1" ,
2025-02-05 11:54:23 +01:00
"mkdocs-git-revision-date-localized-plugin>=1.2.8" ,
2025-02-05 11:32:35 +01:00
"mkdocs-git-revision-date-plugin>=0.3.2" ,
2025-02-05 11:54:23 +01:00
"mkdocs-glightbox>=0.4.0" ,
"mkdocs-material-extensions>=1.3.1" ,
"mkdocs-material>=9.5.34" ,
"mkdocstrings[python]>=0.26.0" ,
"mkdocstrings-python>=1.11.0" ,
2025-02-05 11:55:09 +01:00
"black>=24.10.0" ,
"mkdocs-github-admonitions-plugin>=0.0.3"
2025-02-05 11:32:35 +01:00
]
[ project . urls ]
2025-02-05 11:53:44 +01:00
Homepage = "https://anta.arista.com"
"Bug Tracker" = "https://github.com/aristanetworks/anta/issues"
Contributing = "https://anta.arista.com/main/contribution/"
2025-02-05 11:32:35 +01:00
[ project . scripts ]
anta = "anta.cli:cli"
[ tool . setuptools . packages . find ]
2025-02-05 11:39:42 +01:00
include = [ "anta*" , "asynceapi*" ]
2025-02-05 11:32:35 +01:00
namespaces = false
2025-02-05 11:55:09 +01:00
[ tool . setuptools . package-data ]
"anta" = [ "py.typed" ]
2025-02-05 11:32:35 +01:00
################################
# Version
################################
[ tool . bumpver ]
2025-02-05 11:55:09 +01:00
current_version = "1.2.0"
2025-02-05 11:32:35 +01:00
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"
2025-02-05 11:39:42 +01:00
# 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"
2025-02-05 11:32:35 +01:00
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
2025-02-05 11:38:32 +01:00
addopts = "-ra -q -vv --cov --cov-report term:skip-covered --color yes"
2025-02-05 11:32:35 +01:00
log_level = "WARNING"
render_collapsed = true
testpaths = [ "tests" ]
2025-02-05 11:54:23 +01:00
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"
norecursedirs = [ "tests/benchmark" ] # Do not run performance testing outside of Codspeed
2025-02-05 11:39:42 +01:00
filterwarnings = [
# 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" ,
2025-02-05 11:54:23 +01:00
# Ignore cryptography >=43.0.0 warnings until asyncssh issue is fixed
"ignore:ARC4:cryptography.utils.CryptographyDeprecationWarning" ,
"ignore:TripleDES:cryptography.utils.CryptographyDeprecationWarning" ,
2025-02-05 11:39:42 +01:00
]
2025-02-05 11:32:35 +01:00
[ tool . coverage . run ]
branch = true
2025-02-05 11:54:23 +01:00
# https://community.sonarsource.com/t/python-coverage-analysis-warning/62629/7
include = [ "anta/*" , "asynceapi/*" ]
2025-02-05 11:32:35 +01:00
parallel = true
2025-02-05 11:54:23 +01:00
relative_files = true
2025-02-05 11:32:35 +01:00
[ 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 ,
2025-02-05 11:55:09 +01:00
py { 39 , 310 , 311 , 312 , 313 } ,
2025-02-05 11:32:35 +01:00
report
[ gh-actions ]
python =
3.9 : py39
3.10 : py310
3.11 : erase , py311 , report
3.12 : py312
2025-02-05 11:55:09 +01:00
3.13 : py313
2025-02-05 11:32:35 +01:00
[ testenv ]
description = Run pytest with { basepython }
2025-02-05 11:39:42 +01:00
extras =
dev
cli
2025-02-05 11:32:35 +01:00
# posargs allows to run only a specific test using
# tox -e <env> -- path/to/my/test::test
commands =
pytest { posargs }
2025-02-05 11:55:09 +01:00
# To test on non-POSIX system
# https://github.com/tox-dev/tox/issues/1455
passenv = USERNAME
2025-02-05 11:32:35 +01:00
[ testenv : lint ]
description = Check the code style
commands =
2025-02-05 11:38:32 +01:00
ruff check .
ruff format . --check
2025-02-05 11:32:35 +01:00
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
"" "
2025-02-05 11:38:32 +01:00
################################
# Ruff
################################
2025-02-05 11:32:35 +01:00
[ tool . ruff ]
# Exclude a variety of commonly ignored directories.
exclude = [
".bzr" ,
".direnv" ,
".eggs" ,
".git" ,
".git-rewrite" ,
".hg" ,
2025-02-05 11:38:32 +01:00
".ipynb_checkpoints" ,
2025-02-05 11:32:35 +01:00
".mypy_cache" ,
".nox" ,
".pants.d" ,
2025-02-05 11:38:32 +01:00
".pyenv" ,
".pytest_cache" ,
2025-02-05 11:32:35 +01:00
".pytype" ,
".ruff_cache" ,
".svn" ,
".tox" ,
".venv" ,
2025-02-05 11:38:32 +01:00
".vscode" ,
2025-02-05 11:32:35 +01:00
"__pypackages__" ,
"_build" ,
"buck-out" ,
"build" ,
"dist" ,
"node_modules" ,
2025-02-05 11:38:32 +01:00
"site-packages" ,
2025-02-05 11:32:35 +01:00
"venv" ,
2025-02-05 11:38:32 +01:00
".github" ,
2025-02-05 11:32:35 +01:00
]
line-length = 165
2025-02-05 11:38:32 +01:00
# 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
2025-02-05 11:54:23 +01:00
select = [ "ALL" ,
# By enabling a convention for docstrings, ruff automatically ignore some rules that need to be
# added back if we want them.
# https://docs.astral.sh/ruff/faq/#does-ruff-support-numpy-or-google-style-docstrings
2025-02-05 11:55:09 +01:00
"D212" ,
2025-02-05 11:54:23 +01:00
"D415" ,
"D417" ,
]
2025-02-05 11:38:32 +01:00
ignore = [
"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 = [ ]
2025-02-05 11:32:35 +01:00
# Allow unused variables when underscore-prefixed.
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
2025-02-05 11:38:32 +01:00
[ 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
2025-02-05 11:55:09 +01:00
max-args = 10
2025-02-05 11:32:35 +01:00
2025-02-05 11:38:32 +01:00
[ tool . ruff . lint . mccabe ]
2025-02-05 11:32:35 +01:00
# Unlike Flake8, default to a complexity level of 10.
max-complexity = 10
2025-02-05 11:38:32 +01:00
[ tool . ruff . lint . pep8-naming ]
"ignore-names" = [
"RICH_COLOR_PALETTE"
]
2025-02-05 11:55:09 +01:00
2025-02-05 11:38:32 +01:00
[ 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/*" = [
2025-02-05 11:54:23 +01:00
"ARG002" , # Sometimes we need to declare unused arguments when a parameter is not used but declared in @pytest.mark.parametrize
2025-02-05 11:38:32 +01:00
"FBT001" , # Boolean-typed positional argument in function definition
"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
]
2025-02-05 11:54:23 +01:00
"tests/units/anta_tests/*" = [
"F401" , # In this module, we import tests.units.anta_tests.test without using it to auto-generate tests
]
2025-02-05 11:38:32 +01:00
"anta/*" = [
"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
]
2025-02-05 11:39:42 +01:00
"anta/cli/__init__.py" = [
"T201" , # Allow print statements
]
2025-02-05 11:38:32 +01:00
"anta/cli/*" = [
2025-02-05 11:55:09 +01:00
"PLR0913" , # CLI has many arguments defined in functions
2025-02-05 11:38:32 +01:00
"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
]
2025-02-05 11:53:44 +01:00
"anta/tests/routing/isis.py" = [
"C901" , # TODO: test function is too complex, needs a refactor
"PLR0912" # Too many branches (15/12) (too-many-branches), needs a refactor
]
2025-02-05 11:38:32 +01:00
"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
]
2025-02-05 11:54:23 +01:00
"examples/*.py" = [ # These are example scripts and linked in snippets
2025-02-05 11:39:42 +01:00
"S105" , # Possible hardcoded password
2025-02-05 11:54:23 +01:00
"S106" , # Possible hardcoded password assigned to argument
"S108" , # Probable insecure usage of temporary file or directory
2025-02-05 11:39:42 +01:00
"INP001" , # Implicit packages
2025-02-05 11:54:23 +01:00
"T201" , # `print` found
"T203" , # `pprint` found
2025-02-05 11:39:42 +01:00
]
2025-02-05 11:38:32 +01:00
################################
# Pylint
################################
2025-02-05 11:54:23 +01:00
[ tool . pylint ]
disable = [ # Any rule listed here can be disabled: https://github.com/astral-sh/ruff/issues/970
2025-02-05 11:38:32 +01:00
"invalid-name" ,
2025-02-05 11:54:23 +01:00
"fixme" ,
"unused-import" ,
"unused-argument" ,
"keyword-arg-before-vararg" ,
"protected-access" ,
"too-many-arguments" ,
"too-many-positional-arguments" ,
"wrong-import-position" ,
"pointless-statement" ,
"broad-exception-caught" ,
"line-too-long" ,
"unused-variable" ,
"redefined-builtin" ,
"global-statement" ,
"reimported" ,
"wrong-import-order" ,
"wrong-import-position" ,
2025-02-05 11:55:09 +01:00
"unnecessary-lambda" ,
2025-02-05 11:54:23 +01:00
"abstract-class-instantiated" , # Overlap with https://mypy.readthedocs.io/en/stable/error_code_list.html#check-instantiation-of-abstract-classes-abstract
"unexpected-keyword-arg" , # Overlap with https://mypy.readthedocs.io/en/stable/error_code_list.html#check-arguments-in-calls-call-arg and other rules
2025-02-05 11:55:09 +01:00
"no-value-for-parameter" , # Overlap with https://mypy.readthedocs.io/en/stable/error_code_list.html#check-arguments-in-calls-call-arg
"import-outside-toplevel"
2025-02-05 11:38:32 +01:00
]
max-statements = 61
max-returns = 8
max-locals = 23
max-line-length = 165
max-module-lines = 1700
# making similarity lines limit a bit higher than default 4
min-similarity-lines = 10
# https://stackoverflow.com/questions/49680191/click-and-pylint
signature-mutators = "click.decorators.option"
load-plugins = "pylint_pydantic"
extension-pkg-whitelist = "pydantic"