Compare commits

...

79 Commits
v3.4.3 ... main

Author SHA1 Message Date
renovate[bot]
5971c9679c
chore(deps): lock file maintenance (#816)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-01 13:42:27 +02:00
renovate[bot]
f87922a662 chore(deps): update dependency ruff to v0.4.5 2024-05-27 02:17:14 +02:00
renovate[bot]
aed6a5f420
fix(deps): update dependency ansible-core to v2.14.17 (#812)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-24 09:44:32 +02:00
renovate[bot]
21d6316dd0 chore(docker): update python:3.12-alpine docker digest to 5365725 2024-05-23 06:02:13 +02:00
renovate[bot]
b0f3dca7c7 chore(deps): update dependency pytest to v8.2.1 2024-05-20 02:27:24 +02:00
renovate[bot]
e6ca4cfdb0
chore(deps): lock file maintenance (#809)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-17 09:37:20 +02:00
renovate[bot]
e1b535af8a
chore(deps): update quay.io/thegeeklab/hugo docker tag to v0.125.7 (#810)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-14 14:08:53 +02:00
renovate[bot]
b7401677dc chore(deps): update dependency ruff to v0.4.4 2024-05-13 02:46:59 +02:00
renovate[bot]
8213c46e05
chore(deps): lock file maintenance (#807)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-07 12:15:03 +02:00
renovate[bot]
e2549dfc77 chore(deps): update dependency ruff to v0.4.3 2024-05-06 03:30:21 +02:00
renovate[bot]
4c3b8f2e82
fix(deps): update dependency jsonschema to v4.22.0 (#805)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-01 12:36:49 +02:00
renovate[bot]
5e64c9d79d
chore(deps): lock file maintenance (#802)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-29 10:29:29 +02:00
renovate[bot]
cfcd804959 chore(deps): update devdeps non-major 2024-04-29 03:04:16 +02:00
renovate[bot]
13ac29da22
fix(deps): update dependency ansible-core to v2.14.16 (#803)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-23 21:18:16 +02:00
renovate[bot]
eeae482b31 chore(deps): update dependency ruff to v0.4.1 2024-04-22 04:20:01 +02:00
renovate[bot]
0a53eee7f3 chore(deps): update dependency ruff to v0.3.7 2024-04-15 03:26:31 +02:00
renovate[bot]
73e960f0b7
chore(deps): lock file maintenance (#794)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-12 09:18:14 +02:00
renovate[bot]
5d40978fa3 chore(docker): update python:3.12-alpine docker digest to ef09762 2024-04-11 02:22:02 +02:00
renovate[bot]
9dcaf5e488 chore(deps): update dependency thegeeklab/hugo-geekdoc to v0.45.0 2024-04-08 02:48:45 +02:00
renovate[bot]
fa65be587b chore(deps): update dependency ruff to v0.3.5 2024-04-08 02:47:25 +02:00
renovate[bot]
dcc2e08d2c chore(deps): update dependency thegeeklab/hugo-geekdoc to v0.44.3 2024-04-01 02:17:59 +02:00
renovate[bot]
ab4f8b209f
chore(deps): update quay.io/thegeeklab/wp-docker-buildx docker tag to v4 (#791)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-27 08:56:19 +01:00
renovate[bot]
82e09a5726 chore(docker): update python:3.12-alpine docker digest to c7eb5c9 2024-03-27 02:34:21 +01:00
renovate[bot]
cef217826e
chore(deps): lock file maintenance (#785)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-26 08:33:14 +01:00
renovate[bot]
64e1b4dadb
fix(deps): update dependency ansible-core to v2.14.15 (#789)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-26 08:33:06 +01:00
renovate[bot]
0f00036d7c
chore(deps): update dependency pytest-cov to v5 (#787)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-25 08:34:14 +01:00
renovate[bot]
2209fabe28 chore(deps): update devdeps non-major 2024-03-25 01:36:01 +01:00
renovate[bot]
c7b9e492d3
chore(deps): update quay.io/thegeeklab/hugo docker tag to v0.124.1 (#786)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-20 22:54:15 +01:00
renovate[bot]
ab9b9c6ae9 chore(deps): update dependency ruff to v0.3.3 2024-03-18 01:32:06 +01:00
renovate[bot]
de4825ff70 chore(docker): update python:3.12-alpine docker digest to 25a82f6 2024-03-17 01:46:53 +01:00
e285bf3351
ci: fix deprecated ruff command 2024-03-12 20:52:53 +01:00
renovate[bot]
58beb822ae chore(deps): update dependency thegeeklab/hugo-geekdoc to v0.44.2 2024-03-11 02:26:27 +01:00
renovate[bot]
afcbd3d356 chore(deps): update devdeps non-major 2024-03-11 02:26:10 +01:00
renovate[bot]
a5832c553a chore(deps): update devdeps non-major 2024-03-04 01:40:41 +01:00
renovate[bot]
fc4a6944d6
chore(deps): lock file maintenance (#778)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-26 10:41:38 +01:00
renovate[bot]
d6ac162764
chore(deps): lock file maintenance (#776)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-26 10:14:12 +01:00
renovate[bot]
a7623f7a5a chore(deps): update dependency pytest to v8.0.2 2024-02-26 02:55:16 +01:00
renovate[bot]
f0baf76e24 chore(deps): update devdeps non-major 2024-02-19 01:13:55 +01:00
renovate[bot]
f754a7f292
fix(deps): update dependency yamllint to v1.35.1 (#774)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-16 13:56:52 +01:00
renovate[bot]
d92da10f13
fix(deps): update dependency yamllint to v1.35.0 (#773)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-15 12:29:39 +01:00
e6027445c8
[skip ci] revert renovate automerge config 2024-02-15 12:23:08 +01:00
renovate[bot]
1d7321e3dc
chore(deps): update quay.io/thegeeklab/hugo docker tag to v0.122.0 (#772)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-11 21:50:13 +01:00
252af19cb3
enable renovate on automerge branches 2024-02-09 23:08:30 +01:00
renovate[bot]
2803c86816 chore(docker): update python:3.12-alpine docker digest to 1a05012 2024-02-09 04:20:27 +01:00
renovate[bot]
359db66db2
fix(deps): update dependency yamllint to v1.34.0 (#770)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-06 11:20:31 +01:00
0e74461b58
chore: bump ruff to v0.2.1 (#769) 2024-02-06 09:34:20 +01:00
renovate[bot]
942420db34 chore(docker): update python:3.12-alpine docker digest to 14cfc61 2024-02-02 14:35:26 +01:00
b90b030054
docs: remove ref to unmaintained github action 2024-02-01 12:37:12 +01:00
8dba488747
docs: add document-end to default config 2024-02-01 12:30:50 +01:00
a89d6d5336
fix: fix handling of blocks (#767) 2024-01-31 22:49:19 +01:00
renovate[bot]
37e701217e
fix(deps): update dependency anyconfig to v0.14.0 (#742)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-31 10:50:12 +01:00
48baa2f338
fix: pkg_resources with importlib.resources (#766) 2024-01-31 10:28:46 +01:00
ce0d895fc4
feat: add new rule CheckKeyOrder (#765) 2024-01-30 22:35:45 +01:00
renovate[bot]
9d6dd16c1c
fix(deps): update dependency ansible-core to v2.14.14 (#763)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-30 08:42:23 +01:00
0e197fd585
fix: ensure yaml document end marker is not set (#762)
BREAKING CHANGE: The default setting for the yamllint rule `docuent-end` has been changed to `false`.
2024-01-29 21:28:23 +01:00
renovate[bot]
9797533a14
chore(deps): update dependency pytest to v8 (#760)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-29 08:34:31 +01:00
674ffe6445
feat: add new rule CheckFQCN (#761) 2024-01-29 08:34:08 +01:00
6fd39b62a4
revert candidate filetype handling 2024-01-28 21:38:56 +01:00
7121b2ce6f
use candiate filetype 2024-01-28 14:54:27 +01:00
74f58c59c9
fix: strip builtin fqc prefix from task action (#759) 2024-01-27 20:56:00 +01:00
da5d3c21c2
feat: add rule CheckYamlOctalValues (#758) 2024-01-27 20:31:15 +01:00
7b44647bec
chore: improve desc and help for CheckFilePermissionOctal 2024-01-27 19:59:45 +01:00
2f4e35d83c
refactor: use lint-like rule identifier (#757) 2024-01-27 19:56:35 +01:00
80ac8ec34d
fix toml formatting 2024-01-27 18:20:15 +01:00
8861dcc705
add back optional dependency group ansible 2024-01-26 10:20:48 +01:00
renovate[bot]
b365b32638
fix(deps): update dependency toolz to v0.12.1 (#751)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-25 22:40:01 +01:00
renovate[bot]
087df4848e
fix(deps): update dependency ansible-core to v2.14.13 (#755)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-25 22:33:50 +01:00
39a5e90e78
chore: cleanup optional ansible dependency (#754) 2024-01-25 22:27:08 +01:00
2df48598ec
refactor: drop default standards version and rename to rules (#752)
BREAKING CHANGE: The option to define a `Standards` version has been removed. Every new rule that is added on upcoming releases is activated by default and will also create errors if triggered. The behavior of rules can be controlled by the existing `rules.exclude_filter` or `rules.warning_filter` options.

BREAKING CHANGE: The option `rules.buildin` has been renamed to `rules.builtin`.

BREAKING CHANGE: The option `rules.standards` has been renamed to `rules.dir`.

BREAKING CHANGE: The option `rules.filter` has been renamed to `rules.include_filter`.
2024-01-25 21:40:15 +01:00
renovate[bot]
d360de2125
chore(deps): update quay.io/thegeeklab/wp-docker-buildx docker tag to v3 (#750)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-22 11:29:41 +01:00
renovate[bot]
0137b863fa chore(deps): update dependency ruff to v0.1.14 2024-01-22 01:34:45 +01:00
renovate[bot]
d4db45ba05
fix(deps): update dependency jsonschema to v4.21.1 (#748)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-20 15:48:13 +01:00
renovate[bot]
e9a082b2fa chore(docker): update python:3.12-alpine docker digest to 801b54e 2024-01-19 23:33:30 +01:00
renovate[bot]
975a7bd661 chore(docker): update python:3.12-alpine docker digest to 4a156f7 2024-01-19 05:57:59 +01:00
renovate[bot]
f907222162
fix(deps): update dependency jsonschema to v4.21.0 (#745)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-18 10:21:58 +01:00
renovate[bot]
7f5c2a51b1 chore(deps): update dependency thegeeklab/hugo-geekdoc to v0.44.1 2024-01-16 02:57:53 +01:00
renovate[bot]
c51a4111ec
chore(deps): lock file maintenance (#735)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-15 21:58:56 +01:00
8c9420b445 fix linting 2024-01-15 15:26:56 +01:00
renovate[bot]
87ef3539cb chore(deps): update dependency ruff to v0.1.13 2024-01-15 15:26:56 +01:00
62 changed files with 1075 additions and 930 deletions

View File

@ -18,8 +18,8 @@ HostVars
Rolesfile Rolesfile
Makefile Makefile
Jinja2 Jinja2
ANSIBLE([0-9]{4}) ANS([0-9]{3})
LINT([0-9]{4}) YML([0-9]{3})
SCM SCM
bools bools
Check[A-Z].+ Check[A-Z].+

View File

@ -13,7 +13,7 @@ steps:
- poetry build - poetry build
- name: dryrun - name: dryrun
image: quay.io/thegeeklab/wp-docker-buildx:2 image: quay.io/thegeeklab/wp-docker-buildx:4
settings: settings:
containerfile: Containerfile.multiarch containerfile: Containerfile.multiarch
dry_run: true dry_run: true
@ -26,7 +26,7 @@ steps:
- event: [pull_request] - event: [pull_request]
- name: publish-dockerhub - name: publish-dockerhub
image: quay.io/thegeeklab/wp-docker-buildx:2 image: quay.io/thegeeklab/wp-docker-buildx:4
group: container group: container
settings: settings:
auto_tag: true auto_tag: true
@ -47,7 +47,7 @@ steps:
- ${CI_REPO_DEFAULT_BRANCH} - ${CI_REPO_DEFAULT_BRANCH}
- name: publish-quay - name: publish-quay
image: quay.io/thegeeklab/wp-docker-buildx:2 image: quay.io/thegeeklab/wp-docker-buildx:4
group: container group: container
settings: settings:
auto_tag: true auto_tag: true

View File

@ -32,7 +32,7 @@ steps:
- lychee --no-progress --format detailed docs/content README.md - lychee --no-progress --format detailed docs/content README.md
- name: build - name: build
image: quay.io/thegeeklab/hugo:0.121.2 image: quay.io/thegeeklab/hugo:0.125.7
commands: commands:
- hugo --panicOnWarning -s docs/ - hugo --panicOnWarning -s docs/

View File

@ -20,6 +20,6 @@ steps:
commands: commands:
- pip install poetry poetry-dynamic-versioning -qq - pip install poetry poetry-dynamic-versioning -qq
- poetry install -E ansible-core - poetry install -E ansible-core
- poetry run ruff ./${CI_REPO_NAME//-/} - poetry run ruff check ./${CI_REPO_NAME//-/}
environment: environment:
PY_COLORS: "1" PY_COLORS: "1"

View File

@ -1,4 +1,4 @@
FROM python:3.12-alpine@sha256:c793b92fd9e0e2a0b611756788a033d569ca864b733461c8fb30cfd14847dbcf FROM python:3.12-alpine@sha256:5365725a6cd59b72a927628fdda9965103e3dc671676c89ef3ed8b8b0e22e812
LABEL maintainer="Robert Kaussow <mail@thegeeklab.de>" LABEL maintainer="Robert Kaussow <mail@thegeeklab.de>"
LABEL org.opencontainers.image.authors="Robert Kaussow <mail@thegeeklab.de>" LABEL org.opencontainers.image.authors="Robert Kaussow <mail@thegeeklab.de>"

View File

@ -1,5 +1,5 @@
# renovate: datasource=github-releases depName=thegeeklab/hugo-geekdoc # renovate: datasource=github-releases depName=thegeeklab/hugo-geekdoc
THEME_VERSION := v0.44.0 THEME_VERSION := v0.45.0
THEME := hugo-geekdoc THEME := hugo-geekdoc
BASEDIR := docs BASEDIR := docs
THEMEDIR := $(BASEDIR)/themes THEMEDIR := $(BASEDIR)/themes

View File

@ -18,16 +18,6 @@ ansible-later does **not** ensure that your role will work as expected. For depl
You can find the full documentation at [https://ansible-later.geekdocs.de](https://ansible-later.geekdocs.de/). You can find the full documentation at [https://ansible-later.geekdocs.de](https://ansible-later.geekdocs.de/).
## Community
<!-- prettier-ignore-start -->
<!-- spellchecker-disable -->
- [GitHub Action](https://github.com/patrickjahns/ansible-later-action) by [@patrickjahns](https://github.com/patrickjahns)
<!-- spellchecker-enable -->
<!-- prettier-ignore-end -->
## Contributors ## Contributors
Special thanks to all [contributors](https://github.com/thegeeklab/ansible-later/graphs/contributors). If you would like to contribute, Special thanks to all [contributors](https://github.com/thegeeklab/ansible-later/graphs/contributors). If you would like to contribute,

View File

@ -7,8 +7,8 @@ import sys
from ansiblelater import LOG, __version__, logger from ansiblelater import LOG, __version__, logger
from ansiblelater.candidate import Candidate from ansiblelater.candidate import Candidate
from ansiblelater.rule import SingleRules
from ansiblelater.settings import Settings from ansiblelater.settings import Settings
from ansiblelater.standard import SingleStandards
def main(): def main():
@ -22,33 +22,33 @@ def main():
parser.add_argument( parser.add_argument(
"-r", "-r",
"--rules-dir", "--rules-dir",
dest="rules.standards", dest="rules.dir",
metavar="RULES", metavar="DIR",
action="append", action="append",
help="directory of standard rules", help="directory of rules",
) )
parser.add_argument( parser.add_argument(
"-B", "-B",
"--no-buildin", "--no-builtin",
dest="rules.buildin", dest="rules.builtin",
action="store_false", action="store_false",
help="disables build-in standard rules", help="disables built-in rules",
) )
parser.add_argument( parser.add_argument(
"-s", "-i",
"--standards", "--include-rules",
dest="rules.filter", dest="rules.include_filter",
metavar="FILTER", metavar="TAGS",
action="append", action="append",
help="limit standards to given ID's", help="limit rules to given id/tags",
) )
parser.add_argument( parser.add_argument(
"-x", "-x",
"--exclude-standards", "--exclude-rules",
dest="rules.exclude_filter", dest="rules.exclude_filter",
metavar="EXCLUDE_FILTER", metavar="TAGS",
action="append", action="append",
help="exclude standards by given ID's", help="exclude rules by given it/tags",
) )
parser.add_argument( parser.add_argument(
"-v", dest="logging.level", action="append_const", const=-1, help="increase log level" "-v", dest="logging.level", action="append_const", const=-1, help="increase log level"
@ -65,7 +65,7 @@ def main():
config = settings.config config = settings.config
logger.update_logger(LOG, config["logging"]["level"], config["logging"]["json"]) logger.update_logger(LOG, config["logging"]["level"], config["logging"]["json"])
SingleStandards(config["rules"]["standards"]) SingleRules(config["rules"]["dir"])
workers = max(multiprocessing.cpu_count() - 2, 2) workers = max(multiprocessing.cpu_count() - 2, 2)
p = multiprocessing.Pool(workers) p = multiprocessing.Pool(workers)

View File

@ -3,14 +3,12 @@
import codecs import codecs
import copy import copy
import os import os
import re
from ansible.plugins.loader import module_loader from ansible.plugins.loader import module_loader
from packaging.version import Version
from ansiblelater import LOG, utils from ansiblelater import LOG
from ansiblelater.logger import flag_extra from ansiblelater.logger import flag_extra
from ansiblelater.standard import SingleStandards, StandardBase from ansiblelater.rule import RuleBase, SingleRules
class Candidate: class Candidate:
@ -21,11 +19,12 @@ class Candidate:
bundled with necessary meta informations for rule processing. bundled with necessary meta informations for rule processing.
""" """
def __init__(self, filename, settings={}, standards=[]): # noqa def __init__(self, filename, settings={}, rules=[]): # noqa
self.path = filename self.path = filename
self.binary = False self.binary = False
self.vault = False self.vault = False
self.filetype = type(self).__name__.lower() self.filemeta = type(self).__name__.lower()
self.kind = type(self).__name__.lower()
self.faulty = False self.faulty = False
self.config = settings.config self.config = settings.config
self.settings = settings self.settings = settings
@ -37,166 +36,117 @@ class Candidate:
except UnicodeDecodeError: except UnicodeDecodeError:
self.binary = True self.binary = True
def _get_version(self): def _filter_rules(self):
name = type(self).__name__ target_rules = []
path = self.path includes = self.config["rules"]["include_filter"]
version = None
config_version = self.config["rules"]["version"].strip()
if config_version:
version_config_re = re.compile(r"([\d.]+)")
match = version_config_re.match(config_version)
if match:
version = match.group(1)
if not self.binary:
if isinstance(self, RoleFile):
parentdir = os.path.dirname(os.path.abspath(self.path))
while parentdir != os.path.dirname(parentdir):
meta_file = os.path.join(parentdir, "meta", "main.yml")
if os.path.exists(meta_file):
path = meta_file
break
parentdir = os.path.dirname(parentdir)
version_file_re = re.compile(r"^# Standards:\s*([\d.]+)")
with codecs.open(path, mode="rb", encoding="utf-8") as f:
for line in f:
match = version_file_re.match(line)
if match:
version = match.group(1)
if version:
LOG.info(f"{name} {path} declares standards version {version}")
return version
def _filter_standards(self):
target_standards = []
includes = self.config["rules"]["filter"]
excludes = self.config["rules"]["exclude_filter"] excludes = self.config["rules"]["exclude_filter"]
if len(includes) == 0: if len(includes) == 0:
includes = [s.sid for s in self.standards] includes = [s.rid for s in self.rules]
for standard in self.standards: for rule in self.rules:
if standard.sid in includes and standard.sid not in excludes: if rule.rid in includes and rule.rid not in excludes:
target_standards.append(standard) target_rules.append(rule)
return target_standards return target_rules
def review(self): def review(self):
errors = 0 errors = 0
self.standards = SingleStandards(self.config["rules"]["standards"]).rules self.rules = SingleRules(self.config["rules"]["dir"]).rules
self.version_config = self._get_version()
self.version = self.version_config or utils.standards_latest(self.standards)
for standard in self._filter_standards(): for rule in self._filter_rules():
if type(self).__name__.lower() not in standard.types: if self.kind not in rule.types:
continue continue
result = standard.check(self, self.config) result = rule.check(self, self.config)
if not result: if not result:
LOG.error( LOG.error(f"rule '{rule.rid}' returns an empty result object. Check failed!")
f"Standard '{standard.sid}' returns an empty result object. Check failed!"
)
continue continue
labels = { labels = {
"tag": "review", "tag": "review",
"standard": standard.description, "rule": rule.description,
"file": self.path, "file": self.path,
"passed": True, "passed": True,
} }
if standard.sid and standard.sid.strip(): if rule.rid and rule.rid.strip():
labels["sid"] = standard.sid labels["rid"] = rule.rid
for err in result.errors: for err in result.errors:
err_labels = copy.copy(labels) err_labels = copy.copy(labels)
err_labels["passed"] = False err_labels["passed"] = False
sid = self._format_id(standard.sid) rid = self._format_id(rule.rid)
path = self.path path = self.path
description = standard.description description = rule.description
if isinstance(err, StandardBase.Error): if isinstance(err, RuleBase.Error):
err_labels.update(err.to_dict()) err_labels.update(err.to_dict())
if not standard.version: msg = f"{rid}rule '{description}' not met:\n{path}:{err}"
LOG.warning(
f"{sid}Best practice '{description}' not met:\n{path}:{err}",
extra=flag_extra(err_labels),
)
elif Version(standard.version) > Version(self.version):
LOG.warning(
f"{sid}Future standard '{description}' not met:\n{path}:{err}",
extra=flag_extra(err_labels),
)
else:
msg = f"{sid}Standard '{description}' not met:\n{path}:{err}"
if standard.sid not in self.config["rules"]["warning_filter"]: if rule.rid not in self.config["rules"]["warning_filter"]:
LOG.error(msg, extra=flag_extra(err_labels)) LOG.error(msg, extra=flag_extra(err_labels))
errors = errors + 1 errors = errors + 1
else: else:
LOG.warning(msg, extra=flag_extra(err_labels)) LOG.warning(msg, extra=flag_extra(err_labels))
return errors return errors
@staticmethod @staticmethod
def classify(filename, settings={}, standards=[]): # noqa def classify(filename, settings={}, rules=[]): # noqa
parentdir = os.path.basename(os.path.dirname(filename)) parentdir = os.path.basename(os.path.dirname(filename))
basename = os.path.basename(filename) basename = os.path.basename(filename)
ext = os.path.splitext(filename)[1][1:] ext = os.path.splitext(filename)[1][1:]
if parentdir in ["tasks"]: if parentdir in ["tasks"]:
return Task(filename, settings, standards) return Task(filename, settings, rules)
if parentdir in ["handlers"]: if parentdir in ["handlers"]:
return Handler(filename, settings, standards) return Handler(filename, settings, rules)
if parentdir in ["vars", "defaults"]: if parentdir in ["vars", "defaults"]:
return RoleVars(filename, settings, standards) return RoleVars(filename, settings, rules)
if "group_vars" in filename.split(os.sep): if "group_vars" in filename.split(os.sep):
return GroupVars(filename, settings, standards) return GroupVars(filename, settings, rules)
if "host_vars" in filename.split(os.sep): if "host_vars" in filename.split(os.sep):
return HostVars(filename, settings, standards) return HostVars(filename, settings, rules)
if parentdir in ["meta"] and "main" in basename: if parentdir in ["meta"] and "main" in basename:
return Meta(filename, settings, standards) return Meta(filename, settings, rules)
if parentdir in ["meta"] and "argument_specs" in basename: if parentdir in ["meta"] and "argument_specs" in basename:
return ArgumentSpecs(filename, settings, standards) return ArgumentSpecs(filename, settings, rules)
if parentdir in [ if parentdir in [
"library", "library",
"lookup_plugins", "lookup_plugins",
"callback_plugins", "callback_plugins",
"filter_plugins", "filter_plugins",
] or filename.endswith(".py"): ] or filename.endswith(".py"):
return Code(filename, settings, standards) return Code(filename, settings, rules)
if basename == "inventory" or basename == "hosts" or parentdir in ["inventories"]: if basename == "inventory" or basename == "hosts" or parentdir in ["inventories"]:
return Inventory(filename, settings, standards) return Inventory(filename, settings, rules)
if "rolesfile" in basename or ("requirements" in basename and ext in ["yaml", "yml"]): if "rolesfile" in basename or ("requirements" in basename and ext in ["yaml", "yml"]):
return Rolesfile(filename, settings, standards) return Rolesfile(filename, settings, rules)
if "Makefile" in basename: if "Makefile" in basename:
return Makefile(filename, settings, standards) return Makefile(filename, settings, rules)
if "templates" in filename.split(os.sep) or basename.endswith(".j2"): if "templates" in filename.split(os.sep) or basename.endswith(".j2"):
return Template(filename, settings, standards) return Template(filename, settings, rules)
if "files" in filename.split(os.sep): if "files" in filename.split(os.sep):
return File(filename, settings, standards) return File(filename, settings, rules)
if basename.endswith(".yml") or basename.endswith(".yaml"): if basename.endswith(".yml") or basename.endswith(".yaml"):
return Playbook(filename, settings, standards) return Playbook(filename, settings, rules)
if "README" in basename: if "README" in basename:
return Doc(filename, settings, standards) return Doc(filename, settings, rules)
return None return None
def _format_id(self, standard_id): def _format_id(self, rule_id):
sid = standard_id.strip() rid = rule_id.strip()
if sid: if rid:
standard_id = f"[{sid}] " rule_id = f"[{rid}] "
return standard_id return rule_id
def __repr__(self): def __repr__(self):
return f"{type(self).__name__} ({self.path})" return f"{self.kind} ({self.path})"
def __getitem__(self, item): def __getitem__(self, item):
return self.__dict__.get(item) return self.__dict__.get(item)
@ -205,8 +155,8 @@ class Candidate:
class RoleFile(Candidate): class RoleFile(Candidate):
"""Object classified as Ansible role file.""" """Object classified as Ansible role file."""
def __init__(self, filename, settings={}, standards=[]): # noqa def __init__(self, filename, settings={}, rules=[]): # noqa
super().__init__(filename, settings, standards) super().__init__(filename, settings, rules)
parentdir = os.path.dirname(os.path.abspath(filename)) parentdir = os.path.dirname(os.path.abspath(filename))
while parentdir != os.path.dirname(parentdir): while parentdir != os.path.dirname(parentdir):
@ -226,17 +176,17 @@ class Playbook(Candidate):
class Task(RoleFile): class Task(RoleFile):
"""Object classified as Ansible task file.""" """Object classified as Ansible task file."""
def __init__(self, filename, settings={}, standards=[]): # noqa def __init__(self, filename, settings={}, rules=[]): # noqa
super().__init__(filename, settings, standards) super().__init__(filename, settings, rules)
self.filetype = "tasks" self.filemeta = "tasks"
class Handler(RoleFile): class Handler(RoleFile):
"""Object classified as Ansible handler file.""" """Object classified as Ansible handler file."""
def __init__(self, filename, settings={}, standards=[]): # noqa def __init__(self, filename, settings={}, rules=[]): # noqa
super().__init__(filename, settings, standards) super().__init__(filename, settings, rules)
self.filetype = "handlers" self.filemeta = "handlers"
class Vars(Candidate): class Vars(Candidate):

View File

@ -82,7 +82,7 @@ class LogFilter:
class MultilineFormatter(logging.Formatter): class MultilineFormatter(logging.Formatter):
"""Logging Formatter to reset color after newline characters.""" """Logging Formatter to reset color after newline characters."""
def format(self, record): # noqa def format(self, record):
record.msg = record.msg.replace("\n", f"\n{colorama.Style.RESET_ALL}... ") record.msg = record.msg.replace("\n", f"\n{colorama.Style.RESET_ALL}... ")
record.msg = record.msg + "\n" record.msg = record.msg + "\n"
return logging.Formatter.format(self, record) return logging.Formatter.format(self, record)
@ -91,7 +91,7 @@ class MultilineFormatter(logging.Formatter):
class MultilineJsonFormatter(jsonlogger.JsonFormatter): class MultilineJsonFormatter(jsonlogger.JsonFormatter):
"""Logging Formatter to remove newline characters.""" """Logging Formatter to remove newline characters."""
def format(self, record): # noqa def format(self, record):
record.msg = record.msg.replace("\n", " ") record.msg = record.msg.replace("\n", " ")
return jsonlogger.JsonFormatter.format(self, record) return jsonlogger.JsonFormatter.format(self, record)

View File

@ -1,4 +1,4 @@
"""Standard definition.""" """Rule definition."""
import copy import copy
import importlib import importlib
@ -27,27 +27,26 @@ from ansiblelater.utils.yamlhelper import (
) )
class StandardMeta(type): class RuleMeta(type):
def __call__(cls, *args): def __call__(cls, *args):
mcls = type.__call__(cls, *args) mcls = type.__call__(cls, *args)
mcls.sid = cls.sid mcls.rid = cls.rid
mcls.description = getattr(cls, "description", "__unknown__") mcls.description = getattr(cls, "description", "__unknown__")
mcls.helptext = getattr(cls, "helptext", "") mcls.helptext = getattr(cls, "helptext", "")
mcls.version = getattr(cls, "version", None)
mcls.types = getattr(cls, "types", []) mcls.types = getattr(cls, "types", [])
return mcls return mcls
class StandardExtendedMeta(StandardMeta, ABCMeta): class RuleExtendedMeta(RuleMeta, ABCMeta):
pass pass
class StandardBase(metaclass=StandardExtendedMeta): class RuleBase(metaclass=RuleExtendedMeta):
SHELL_PIPE_CHARS = "&|<>;$\n*[]{}?" SHELL_PIPE_CHARS = "&|<>;$\n*[]{}?"
@property @property
@abstractmethod @abstractmethod
def sid(self): def rid(self):
pass pass
@abstractmethod @abstractmethod
@ -55,7 +54,7 @@ class StandardBase(metaclass=StandardExtendedMeta):
pass pass
def __repr__(self): def __repr__(self):
return f"Standard: {self.description} (version: {self.version}, types: {self.types})" return f"Rule: {self.description} (types: {self.types})"
@staticmethod @staticmethod
def get_tasks(candidate, settings): # noqa def get_tasks(candidate, settings): # noqa
@ -69,11 +68,11 @@ class StandardBase(metaclass=StandardExtendedMeta):
except LaterError as ex: except LaterError as ex:
e = ex.original e = ex.original
errors.append( errors.append(
StandardBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}") RuleBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}")
) )
candidate.faulty = True candidate.faulty = True
except LaterAnsibleError as e: except LaterAnsibleError as e:
errors.append(StandardBase.Error(e.line, f"syntax error: {e.message}")) errors.append(RuleBase.Error(e.line, f"syntax error: {e.message}"))
candidate.faulty = True candidate.faulty = True
return yamllines, errors return yamllines, errors
@ -93,11 +92,11 @@ class StandardBase(metaclass=StandardExtendedMeta):
except LaterError as ex: except LaterError as ex:
e = ex.original e = ex.original
errors.append( errors.append(
StandardBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}") RuleBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}")
) )
candidate.faulty = True candidate.faulty = True
except LaterAnsibleError as e: except LaterAnsibleError as e:
errors.append(StandardBase.Error(e.line, f"syntax error: {e.message}")) errors.append(RuleBase.Error(e.line, f"syntax error: {e.message}"))
candidate.faulty = True candidate.faulty = True
return tasks, errors return tasks, errors
@ -115,11 +114,11 @@ class StandardBase(metaclass=StandardExtendedMeta):
except LaterError as ex: except LaterError as ex:
e = ex.original e = ex.original
errors.append( errors.append(
StandardBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}") RuleBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}")
) )
candidate.faulty = True candidate.faulty = True
except LaterAnsibleError as e: except LaterAnsibleError as e:
errors.append(StandardBase.Error(e.line, f"syntax error: {e.message}")) errors.append(RuleBase.Error(e.line, f"syntax error: {e.message}"))
candidate.faulty = True candidate.faulty = True
return normalized, errors return normalized, errors
@ -150,20 +149,21 @@ class StandardBase(metaclass=StandardExtendedMeta):
# No need to normalize_task if we are skipping it. # No need to normalize_task if we are skipping it.
continue continue
normalized.append( normalized_task = normalize_task(
normalize_task( task, candidate.path, settings["ansible"]["custom_modules"]
task, candidate.path, settings["ansible"]["custom_modules"]
)
) )
normalized_task["__raw_task__"] = task
normalized.append(normalized_task)
except LaterError as ex: except LaterError as ex:
e = ex.original e = ex.original
errors.append( errors.append(
StandardBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}") RuleBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}")
) )
candidate.faulty = True candidate.faulty = True
except LaterAnsibleError as e: except LaterAnsibleError as e:
errors.append(StandardBase.Error(e.line, f"syntax error: {e.message}")) errors.append(RuleBase.Error(e.line, f"syntax error: {e.message}"))
candidate.faulty = True candidate.faulty = True
return normalized, errors return normalized, errors
@ -184,11 +184,11 @@ class StandardBase(metaclass=StandardExtendedMeta):
except LaterError as ex: except LaterError as ex:
e = ex.original e = ex.original
errors.append( errors.append(
StandardBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}") RuleBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}")
) )
candidate.faulty = True candidate.faulty = True
except LaterAnsibleError as e: except LaterAnsibleError as e:
errors.append(StandardBase.Error(e.line, f"syntax error: {e.message}")) errors.append(RuleBase.Error(e.line, f"syntax error: {e.message}"))
candidate.faulty = True candidate.faulty = True
return yamllines, errors return yamllines, errors
@ -210,7 +210,7 @@ class StandardBase(metaclass=StandardExtendedMeta):
content = yaml.safe_load(f) content = yaml.safe_load(f)
except yaml.YAMLError as e: except yaml.YAMLError as e:
errors.append( errors.append(
StandardBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}") RuleBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}")
) )
candidate.faulty = True candidate.faulty = True
@ -224,14 +224,14 @@ class StandardBase(metaclass=StandardExtendedMeta):
try: try:
with open(candidate.path, encoding="utf-8") as f: with open(candidate.path, encoding="utf-8") as f:
for problem in linter.run(f, YamlLintConfig(options)): for problem in linter.run(f, YamlLintConfig(options)):
errors.append(StandardBase.Error(problem.line, problem.desc)) errors.append(RuleBase.Error(problem.line, problem.desc))
except yaml.YAMLError as e: except yaml.YAMLError as e:
errors.append( errors.append(
StandardBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}") RuleBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}")
) )
candidate.faulty = True candidate.faulty = True
except (TypeError, ValueError) as e: except (TypeError, ValueError) as e:
errors.append(StandardBase.Error(None, f"yamllint error: {e}")) errors.append(RuleBase.Error(None, f"yamllint error: {e}"))
candidate.faulty = True candidate.faulty = True
return errors return errors
@ -302,7 +302,7 @@ class StandardBase(metaclass=StandardExtendedMeta):
return "\n".join([f"{self.candidate}:{error}" for error in self.errors]) return "\n".join([f"{self.candidate}:{error}" for error in self.errors])
class StandardLoader: class RulesLoader:
def __init__(self, source): def __init__(self, source):
self.rules = [] self.rules = []
@ -331,23 +331,20 @@ class StandardLoader:
def _is_plugin(self, obj): def _is_plugin(self, obj):
return ( return (
inspect.isclass(obj) inspect.isclass(obj) and issubclass(obj, RuleBase) and obj is not RuleBase and not None
and issubclass(obj, StandardBase)
and obj is not StandardBase
and not None
) )
def validate(self): def validate(self):
normalized_std = list(toolz.remove(lambda x: x.sid == "", self.rules)) normalize_rule = list(toolz.remove(lambda x: x.rid == "", self.rules))
unique_std = len(list(toolz.unique(normalized_std, key=lambda x: x.sid))) unique_rule = len(list(toolz.unique(normalize_rule, key=lambda x: x.rid)))
all_std = len(normalized_std) all_rules = len(normalize_rule)
if all_std != unique_std: if all_rules != unique_rule:
sysexit_with_message( sysexit_with_message(
"Detect duplicate ID's in standards definition. Please use unique ID's only." "Found duplicate tags in rules definition. Please use unique tags only."
) )
class SingleStandards(StandardLoader, metaclass=Singleton): class SingleRules(RulesLoader, metaclass=Singleton):
"""Singleton config class.""" """Singleton config class."""
pass pass

View File

@ -1,11 +1,10 @@
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckBecomeUser(StandardBase): class CheckBecomeUser(RuleBase):
sid = "ANSIBLE0015" rid = "ANS115"
description = "Become should be combined with become_user" description = "Become should be combined with become_user"
helptext = "the task has `become` enabled but `become_user` is missing" helptext = "the task has `become` enabled but `become_user` is missing"
version = "0.1"
types = ["playbook", "task", "handler"] types = ["playbook", "task", "handler"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,14 +1,13 @@
import re import re
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
from ansiblelater.utils import count_spaces from ansiblelater.utils import count_spaces
class CheckBracesSpaces(StandardBase): class CheckBracesSpaces(RuleBase):
sid = "ANSIBLE0004" rid = "ANS104"
description = "YAML should use consistent number of spaces around variables" description = "YAML should use consistent number of spaces around variables"
helptext = "no suitable numbers of spaces (min: {min} max: {max})" helptext = "no suitable numbers of spaces (min: {min} max: {max})"
version = "0.1"
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"] types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -18,14 +18,13 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE. # THE SOFTWARE.
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckChangedInWhen(StandardBase): class CheckChangedInWhen(RuleBase):
sid = "ANSIBLE0026" rid = "ANS126"
description = "Use handlers instead of `when: changed`" description = "Use handlers instead of `when: changed`"
helptext = "tasks using `when: result.changed` setting are effectively acting as a handler" helptext = "tasks using `when: result.changed` setting are effectively acting as a handler"
version = "0.2"
types = ["playbook", "task", "handler"] types = ["playbook", "task", "handler"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,14 +1,13 @@
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckCommandHasChanges(StandardBase): class CheckCommandHasChanges(RuleBase):
sid = "ANSIBLE0011" rid = "ANS111"
description = "Commands should be idempotent" description = "Commands should be idempotent"
helptext = ( helptext = (
"commands should only read while using `changed_when` or try to be " "commands should only read while using `changed_when` or try to be "
"idempotent while using controls like `creates`, `removes` or `when`" "idempotent while using controls like `creates`, `removes` or `when`"
) )
version = "0.1"
types = ["playbook", "task"] types = ["playbook", "task"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -20,14 +20,13 @@
import os import os
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckCommandInsteadOfArgument(StandardBase): class CheckCommandInsteadOfArgument(RuleBase):
sid = "ANSIBLE0017" rid = "ANS117"
description = "Commands should not be used in place of module arguments" description = "Commands should not be used in place of module arguments"
helptext = "{exec} used in place of file modules argument {arg}" helptext = "{exec} used in place of file modules argument {arg}"
version = "0.2"
types = ["playbook", "task", "handler"] types = ["playbook", "task", "handler"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,13 +1,12 @@
import os import os
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckCommandInsteadOfModule(StandardBase): class CheckCommandInsteadOfModule(RuleBase):
sid = "ANSIBLE0008" rid = "ANS108"
description = "Commands should not be used in place of modules" description = "Commands should not be used in place of modules"
helptext = "{exec} command used in place of {module} module" helptext = "{exec} command used in place of {module} module"
version = "0.1"
types = ["playbook", "task", "handler"] types = ["playbook", "task", "handler"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,14 +1,13 @@
import re import re
from ansiblelater.candidate import Template from ansiblelater.candidate import Template
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckCompareToEmptyString(StandardBase): class CheckCompareToEmptyString(RuleBase):
sid = "ANSIBLE0012" rid = "ANS112"
description = 'Don\'t compare to empty string ""' description = 'Don\'t compare to empty string ""'
helptext = "use `when: var` rather than `when: var !=` (or conversely `when: not var`)" helptext = "use `when: var` rather than `when: var !=` (or conversely `when: not var`)"
version = "0.1"
types = ["playbook", "task", "handler", "template"] types = ["playbook", "task", "handler", "template"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,14 +1,13 @@
import re import re
from ansiblelater.candidate import Template from ansiblelater.candidate import Template
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckCompareToLiteralBool(StandardBase): class CheckCompareToLiteralBool(RuleBase):
sid = "ANSIBLE0013" rid = "ANS113"
description = "Don't compare to True or False" description = "Don't compare to True or False"
helptext = "use `when: var` rather than `when: var == True` (or conversely `when: not var`)" helptext = "use `when: var` rather than `when: var == True` (or conversely `when: not var`)"
version = "0.1"
types = ["playbook", "task", "handler"] types = ["playbook", "task", "handler"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,11 +1,10 @@
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckDeprecated(StandardBase): class CheckDeprecated(RuleBase):
sid = "ANSIBLE9999" rid = "ANS999"
description = "Deprecated features should not be used" description = "Deprecated features should not be used"
helptext = "'{old}' is deprecated and should not be used anymore. Use '{new}' instead." helptext = "`{old}` is deprecated and should not be used anymore. Use `{new}` instead."
version = "0.1"
types = ["playbook", "task", "handler"] types = ["playbook", "task", "handler"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -20,18 +20,17 @@
import os import os
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
from ansiblelater.utils import has_glob, has_jinja from ansiblelater.utils import has_glob, has_jinja
class CheckDeprecatedBareVars(StandardBase): class CheckDeprecatedBareVars(RuleBase):
sid = "ANSIBLE0027" rid = "ANS127"
description = "Deprecated bare variables in loops must not be used" description = "Deprecated bare variables in loops must not be used"
helptext = ( helptext = (
"bare var '{barevar}' in '{loop_type}' must use full var syntax '{{{{ {barevar} }}}}' " "bare var '{barevar}' in '{loop_type}' must use full var syntax '{{{{ {barevar} }}}}' "
"or be converted to a list" "or be converted to a list"
) )
version = "0.3"
types = ["playbook", "task", "handler"] types = ["playbook", "task", "handler"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -0,0 +1,132 @@
# Original code written by the authors of ansible-lint
from ansiblelater.rule import RuleBase
from ansiblelater.utils import load_plugin
class CheckFQCNBuiltin(RuleBase):
rid = "ANS128"
helptext = "use FQCN `{module_alias}` for module action `{module}`"
description = "Module actions should use full qualified collection names"
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars"]
module_aliases = {"block/always/rescue": "block/always/rescue"}
def check(self, candidate, settings):
tasks, errors = self.get_normalized_tasks(candidate, settings)
_builtins = [
"add_host",
"apt",
"apt_key",
"apt_repository",
"assemble",
"assert",
"async_status",
"blockinfile",
"command",
"copy",
"cron",
"debconf",
"debug",
"dnf",
"dpkg_selections",
"expect",
"fail",
"fetch",
"file",
"find",
"gather_facts",
"get_url",
"getent",
"git",
"group",
"group_by",
"hostname",
"import_playbook",
"import_role",
"import_tasks",
"include",
"include_role",
"include_tasks",
"include_vars",
"iptables",
"known_hosts",
"lineinfile",
"meta",
"package",
"package_facts",
"pause",
"ping",
"pip",
"raw",
"reboot",
"replace",
"rpm_key",
"script",
"service",
"service_facts",
"set_fact",
"set_stats",
"setup",
"shell",
"slurp",
"stat",
"subversion",
"systemd",
"sysvinit",
"tempfile",
"template",
"unarchive",
"uri",
"user",
"wait_for",
"wait_for_connection",
"yum",
"yum_repository",
]
if errors:
return self.Result(candidate.path, errors)
for task in tasks:
module = task["action"]["__ansible_module_original__"]
if module not in self.module_aliases:
loaded_module = load_plugin(module)
target = loaded_module.resolved_fqcn
self.module_aliases[module] = target
if target is None:
self.module_aliases[module] = module
continue
if target not in self.module_aliases:
self.module_aliases[target] = target
if module != self.module_aliases[module]:
module_alias = self.module_aliases[module]
if module_alias.startswith("ansible.builtin"):
legacy_module = module_alias.replace(
"ansible.builtin.",
"ansible.legacy.",
1,
)
if module != legacy_module:
helptext = self.helptext.format(module_alias=module_alias, module=module)
if module == "ansible.builtin.include":
helptext = (
"`ansible.builtin.include_task` or `ansible.builtin.import_tasks` "
f"should be used instead of deprecated `{module}`",
)
errors.append(self.Error(task["__line__"], helptext))
else:
if module.count(".") < 2:
errors.append(
self.Error(
task["__line__"],
self.helptext.format(module_alias=module_alias, module=module),
)
)
return self.Result(candidate.path, errors)

View File

@ -19,17 +19,16 @@
# THE SOFTWARE. # THE SOFTWARE.
import re import re
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckFilePermissionMissing(StandardBase): class CheckFilePermissionMissing(RuleBase):
sid = "ANSIBLE0018" rid = "ANS118"
description = "File permissions unset or incorrect" description = "File permissions unset or incorrect"
helptext = ( helptext = (
"`mode` parameter should set permissions explicitly (e.g. `mode: 0644`) " "`mode` parameter should set permissions explicitly (e.g. `mode: 0644`) "
"to avoid unexpected file permissions" "to avoid unexpected file permissions"
) )
version = "0.2"
types = ["playbook", "task", "handler"] types = ["playbook", "task", "handler"]
_modules = { _modules = {

View File

@ -18,14 +18,13 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE. # THE SOFTWARE.
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckFilePermissionOctal(StandardBase): class CheckFilePermissionOctal(RuleBase):
sid = "ANSIBLE0019" rid = "ANS119"
description = "Octal file permissions must contain leading zero or be a string" description = "Numeric file permissions without a leading zero can behave unexpectedly"
helptext = "numeric file permissions without leading zero can behave in unexpected ways" helptext = '`mode: {mode}` should be strings with a leading zero `mode: "0{mode}"`'
version = "0.2"
types = ["playbook", "task", "handler"] types = ["playbook", "task", "handler"]
def check(self, candidate, settings): def check(self, candidate, settings):
@ -48,7 +47,9 @@ class CheckFilePermissionOctal(StandardBase):
mode = task["action"].get("mode", None) mode = task["action"].get("mode", None)
if isinstance(mode, int) and self._is_invalid_permission(mode): if isinstance(mode, int) and self._is_invalid_permission(mode):
errors.append(self.Error(task["__line__"], self.helptext)) errors.append(
self.Error(task["__line__"], self.helptext.format(mode=mode))
)
return self.Result(candidate.path, errors) return self.Result(candidate.path, errors)

View File

@ -1,13 +1,12 @@
import re import re
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckFilterSeparation(StandardBase): class CheckFilterSeparation(RuleBase):
sid = "ANSIBLE0016" rid = "ANS116"
description = "Jinja2 filters should be separated with spaces" description = "Jinja2 filters should be separated with spaces"
helptext = "no suitable numbers of spaces (required: 1)" helptext = "no suitable numbers of spaces (required: 1)"
version = "0.1"
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars"] types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -18,14 +18,13 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE. # THE SOFTWARE.
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckGitHasVersion(StandardBase): class CheckGitHasVersion(RuleBase):
sid = "ANSIBLE0020" rid = "ANS120"
description = "Git checkouts should use explicit version" description = "Git checkouts should use explicit version"
helptext = "git checkouts should point to an explicit commit or tag, not `latest`" helptext = "git checkouts should point to an explicit commit or tag, not `latest`"
version = "0.2"
types = ["playbook", "task", "handler"] types = ["playbook", "task", "handler"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,11 +1,10 @@
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckInstallUseLatest(StandardBase): class CheckInstallUseLatest(RuleBase):
sid = "ANSIBLE0009" rid = "ANS109"
description = "Package installs should use present, not latest" description = "Package installs should use present, not latest"
helptext = "package installs should use `state=present` with or without a version" helptext = "package installs should use `state=present` with or without a version"
version = "0.1"
types = ["playbook", "task", "handler"] types = ["playbook", "task", "handler"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -0,0 +1,89 @@
# Original code written by the authors of ansible-lint
import functools
from ansiblelater.rule import RuleBase
SORTER_TASKS = (
"name",
# "__module__",
# "action",
# "args",
None, # <-- None include all modules that not using action and *
# "when",
# "notify",
# "tags",
"block",
"rescue",
"always",
)
class CheckKeyOrder(RuleBase):
rid = "ANS129"
description = "Check for recommended key order"
helptext = "{type} key order can be improved to `{sorted_keys}`"
types = ["playbook", "task", "handler"]
def check(self, candidate, settings):
errors = []
tasks, err = self.get_normalized_tasks(candidate, settings)
if err:
return self.Result(candidate.path, err)
for task in tasks:
is_sorted, keys = self._sort_keys(task.get("__raw_task__"))
if not is_sorted:
errors.append(
self.Error(
task["__line__"],
self.helptext.format(type="task", sorted_keys=", ".join(keys)),
)
)
if candidate.kind == "playbook":
tasks, err = self.get_tasks(candidate, settings)
if err:
return self.Result(candidate.path, err)
for task in tasks:
is_sorted, keys = self._sort_keys(task)
if not is_sorted:
errors.append(
self.Error(
task["__line__"],
self.helptext.format(type="play", sorted_keys=", ".join(keys)),
)
)
return self.Result(candidate.path, errors)
@staticmethod
def _sort_keys(task):
if not task:
return True, []
keys = [str(key) for key in task if not key.startswith("_")]
sorted_keys = sorted(keys, key=functools.cmp_to_key(_task_property_sorter))
return (keys == sorted_keys), sorted_keys
def _task_property_sorter(property1, property2):
"""Sort task properties based on SORTER."""
v_1 = _get_property_sort_index(property1)
v_2 = _get_property_sort_index(property2)
return (v_1 > v_2) - (v_1 < v_2)
def _get_property_sort_index(name):
"""Return the index of the property in the sorter."""
a_index = -1
for i, v in enumerate(SORTER_TASKS):
if v == name:
return i
if v is None:
a_index = i
return a_index

View File

@ -1,13 +1,12 @@
import re import re
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckLiteralBoolFormat(StandardBase): class CheckLiteralBoolFormat(RuleBase):
sid = "ANSIBLE0014" rid = "ANS114"
description = "Literal bools should be consistent" description = "Literal bools should be consistent"
helptext = "literal bools should be written as `{bools}`" helptext = "literal bools should be written as `{bools}`"
version = "0.1"
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars"] types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,13 +1,12 @@
# Copyright (c) 2016, Tsukinowa Inc. <info@tsukinowa.jp> # Copyright (c) 2016, Tsukinowa Inc. <info@tsukinowa.jp>
# Copyright (c) 2018, Ansible Project # Copyright (c) 2018, Ansible Project
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckLocalAction(StandardBase): class CheckLocalAction(RuleBase):
sid = "ANSIBLE0024" rid = "ANS124"
description = "Don't use local_action" description = "Don't use local_action"
helptext = "`delegate_to: localhost` should be used instead of `local_action`" helptext = "`delegate_to: localhost` should be used instead of `local_action`"
version = "0.2"
types = ["playbook", "task", "handler"] types = ["playbook", "task", "handler"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,14 +1,13 @@
# Copyright (c) 2018, Ansible Project # Copyright (c) 2018, Ansible Project
from nested_lookup import nested_lookup from nested_lookup import nested_lookup
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckMetaChangeFromDefault(StandardBase): class CheckMetaChangeFromDefault(RuleBase):
sid = "ANSIBLE0021" rid = "ANS121"
description = "Roles meta/main.yml default values should be changed" description = "Roles meta/main.yml default values should be changed"
helptext = "meta/main.yml default values should be changed for: `{field}`" helptext = "meta/main.yml default values should be changed for: `{field}`"
version = "0.2"
types = ["meta"] types = ["meta"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,13 +1,12 @@
from nested_lookup import nested_lookup from nested_lookup import nested_lookup
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckMetaMain(StandardBase): class CheckMetaMain(RuleBase):
sid = "ANSIBLE0002" rid = "ANS102"
description = "Roles must contain suitable meta/main.yml" description = "Roles must contain suitable meta/main.yml"
helptext = "file should contain `{key}` key" helptext = "file should contain `{key}` key"
version = "0.1"
types = ["meta"] types = ["meta"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,13 +1,12 @@
from collections import defaultdict from collections import defaultdict
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckNameFormat(StandardBase): class CheckNameFormat(RuleBase):
sid = "ANSIBLE0007" rid = "ANS107"
description = "Name of tasks and handlers must be formatted" description = "Name of tasks and handlers must be formatted"
helptext = "name '{name}' should start with uppercase" helptext = "name `{name}` should start with uppercase"
version = "0.1"
types = ["playbook", "task", "handler"] types = ["playbook", "task", "handler"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,11 +1,10 @@
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckNamedTask(StandardBase): class CheckNamedTask(RuleBase):
sid = "ANSIBLE0006" rid = "ANS106"
description = "Tasks and handlers must be named" description = "Tasks and handlers must be named"
helptext = "module '{module}' used without or empty `name` attribute" helptext = "module `{module}` used without or empty `name` attribute"
version = "0.1"
types = ["playbook", "task", "handler"] types = ["playbook", "task", "handler"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,11 +1,10 @@
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckNativeYaml(StandardBase): class CheckNativeYaml(RuleBase):
sid = "LINT0008" rid = "YML108"
description = "Use YAML format for tasks and handlers rather than key=value" description = "Use YAML format for tasks and handlers rather than key=value"
helptext = "task arguments appear to be in key value rather than YAML format" helptext = "task arguments appear to be in key value rather than YAML format"
version = "0.1"
types = ["playbook", "task", "handler"] types = ["playbook", "task", "handler"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -21,17 +21,16 @@
# THE SOFTWARE. # THE SOFTWARE.
import re import re
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckNestedJinja(StandardBase): class CheckNestedJinja(RuleBase):
sid = "ANSIBLE0023" rid = "ANS123"
description = "Don't use nested Jinja2 pattern" description = "Don't use nested Jinja2 pattern"
helptext = ( helptext = (
"there should not be any nested jinja pattern " "there should not be any nested jinja pattern "
"like `{{ list_one + {{ list_two | max }} }}`" "like `{{ list_one + {{ list_two | max }} }}`"
) )
version = "0.2"
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars"] types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,13 +1,12 @@
# Copyright (c) 2016, Tsukinowa Inc. <info@tsukinowa.jp> # Copyright (c) 2016, Tsukinowa Inc. <info@tsukinowa.jp>
# Copyright (c) 2018, Ansible Project # Copyright (c) 2018, Ansible Project
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckRelativeRolePaths(StandardBase): class CheckRelativeRolePaths(RuleBase):
sid = "ANSIBLE0025" rid = "ANS125"
description = "Don't use a relative path in a role" description = "Don't use a relative path in a role"
helptext = "`copy` and `template` modules don't need relative path for `src`" helptext = "`copy` and `template` modules don't need relative path for `src`"
version = "0.2"
types = ["playbook", "task", "handler"] types = ["playbook", "task", "handler"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,13 +1,12 @@
from ansible.parsing.yaml.objects import AnsibleMapping from ansible.parsing.yaml.objects import AnsibleMapping
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckScmInSrc(StandardBase): class CheckScmInSrc(RuleBase):
sid = "ANSIBLE0005" rid = "ANS105"
description = "Use `scm:` key rather than `src: scm+url`" description = "Use `scm:` key rather than `src: scm+url`"
helptext = "usage of `src: scm+url` not recommended" helptext = "usage of `src: scm+url` not recommended"
version = "0.1"
types = ["rolesfile"] types = ["rolesfile"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,11 +1,10 @@
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckShellInsteadCommand(StandardBase): class CheckShellInsteadCommand(RuleBase):
sid = "ANSIBLE0010" rid = "ANS110"
description = "Shell should only be used when essential" description = "Shell should only be used when essential"
helptext = "shell should only be used when piping, redirecting or chaining commands" helptext = "shell should only be used when piping, redirecting or chaining commands"
version = "0.1"
types = ["playbook", "task", "handler"] types = ["playbook", "task", "handler"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,14 +1,13 @@
import re import re
from collections import defaultdict from collections import defaultdict
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckTaskSeparation(StandardBase): class CheckTaskSeparation(RuleBase):
sid = "ANSIBLE0001" rid = "ANS101"
description = "Single tasks should be separated by empty line" description = "Single tasks should be separated by empty line"
helptext = "missing task separation (required: 1 empty line)" helptext = "missing task separation (required: 1 empty line)"
version = "0.1"
types = ["playbook", "task", "handler"] types = ["playbook", "task", "handler"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,13 +1,12 @@
from collections import defaultdict from collections import defaultdict
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckUniqueNamedTask(StandardBase): class CheckUniqueNamedTask(RuleBase):
sid = "ANSIBLE0003" rid = "ANS103"
description = "Tasks and handlers must be uniquely named within a single file" description = "Tasks and handlers must be uniquely named within a single file"
helptext = "name '{name}' appears multiple times" helptext = "name `{name}` appears multiple times"
version = "0.1"
types = ["playbook", "task", "handler"] types = ["playbook", "task", "handler"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,16 +0,0 @@
from ansiblelater.standard import StandardBase
class CheckVersion(StandardBase):
sid = "ANSIBLE9998"
description = "Standards version should be pinned"
helptext = "Standards version not set. Using latest standards version {version}"
types = ["task", "handler", "rolevars", "meta", "template", "file", "playbook"]
def check(self, candidate, settings): # noqa
errors = []
if not candidate.version_config:
errors.append(self.Error(None, self.helptext.format(version=candidate.version)))
return self.Result(candidate.path, errors)

View File

@ -1,13 +1,13 @@
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckWhenFormat(StandardBase): class CheckWhenFormat(RuleBase):
sid = "ANSIBLE0022" rid = "ANS122"
description = "Don't use Jinja2 in when" description = "Don't use Jinja2 in when"
helptext = ( helptext = (
"`when` is a raw Jinja2 expression, redundant {{ }} " "should be removed from variable(s)" "`when` is a raw Jinja2 expression, redundant `{{ }}` should be removed from variable(s)"
) )
version = "0.2"
types = ["playbook", "task", "handler"] types = ["playbook", "task", "handler"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,10 +1,9 @@
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckYamlColons(StandardBase): class CheckYamlColons(RuleBase):
sid = "LINT0005" rid = "YML105"
description = "YAML should use consistent number of spaces around colons" description = "YAML should use consistent number of spaces around colons"
version = "0.1"
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"] types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,10 +1,9 @@
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckYamlDocumentEnd(StandardBase): class CheckYamlDocumentEnd(RuleBase):
sid = "LINT0009" rid = "YML109"
description = "YAML should contain document end marker" description = "YAML document end marker should match configuration"
version = "0.1"
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"] types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,10 +1,9 @@
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckYamlDocumentStart(StandardBase): class CheckYamlDocumentStart(RuleBase):
sid = "LINT0004" rid = "YML104"
description = "YAML should contain document start marker" description = "YAML document start marker should match configuration"
version = "0.1"
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"] types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,10 +1,9 @@
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckYamlEmptyLines(StandardBase): class CheckYamlEmptyLines(RuleBase):
sid = "LINT0001" rid = "YML101"
description = "YAML should not contain unnecessarily empty lines" description = "YAML should not contain unnecessarily empty lines"
version = "0.1"
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"] types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,13 +1,12 @@
import os import os
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckYamlFile(StandardBase): class CheckYamlFile(RuleBase):
sid = "LINT0006" rid = "YML106"
description = "Roles file should be in yaml format" description = "Roles file should be in yaml format"
helptext = "file does not have a .yml extension" helptext = "file does not have a .yml extension"
version = "0.1"
types = ["playbook", "task", "handler"] types = ["playbook", "task", "handler"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,11 +1,10 @@
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckYamlHasContent(StandardBase): class CheckYamlHasContent(RuleBase):
sid = "LINT0007" rid = "YML107"
description = "Files should contain useful content" description = "Files should contain useful content"
helptext = "the file appears to have no useful content" helptext = "the file appears to have no useful content"
version = "0.1"
types = ["playbook", "task", "handler", "rolevars", "defaults", "meta"] types = ["playbook", "task", "handler", "rolevars", "defaults", "meta"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,10 +1,9 @@
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckYamlHyphens(StandardBase): class CheckYamlHyphens(RuleBase):
sid = "LINT0003" rid = "YML103"
description = "YAML should use consistent number of spaces after hyphens" description = "YAML should use consistent number of spaces after hyphens"
version = "0.1"
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"] types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -1,10 +1,9 @@
from ansiblelater.standard import StandardBase from ansiblelater.rule import RuleBase
class CheckYamlIndent(StandardBase): class CheckYamlIndent(RuleBase):
sid = "LINT0002" rid = "YML102"
description = "YAML should not contain unnecessarily empty lines" description = "YAML should not contain unnecessarily empty lines"
version = "0.1"
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"] types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -0,0 +1,13 @@
from ansiblelater.rule import RuleBase
class CheckYamlOctalValues(RuleBase):
rid = "YML110"
description = "YAML implicit/explicit octal value should match configuration"
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"]
def check(self, candidate, settings):
options = f"rules: {{octal-values: {settings['yamllint']['octal-values']}}}"
errors = self.run_yamllint(candidate, options)
return self.Result(candidate.path, errors)

View File

@ -1,5 +1,6 @@
"""Global settings object definition.""" """Global settings object definition."""
import importlib.resources
import os import os
import anyconfig import anyconfig
@ -7,7 +8,6 @@ import jsonschema.exceptions
import pathspec import pathspec
from appdirs import AppDirs from appdirs import AppDirs
from jsonschema._utils import format_as_index from jsonschema._utils import format_as_index
from pkg_resources import resource_filename
from ansiblelater import utils from ansiblelater import utils
@ -104,13 +104,13 @@ class Settings:
if f not in defaults["ansible"]["custom_modules"]: if f not in defaults["ansible"]["custom_modules"]:
defaults["ansible"]["custom_modules"].append(f) defaults["ansible"]["custom_modules"].append(f)
if defaults["rules"]["buildin"]: if defaults["rules"]["builtin"]:
defaults["rules"]["standards"].append( ref = importlib.resources.files("ansiblelater") / "rules"
os.path.join(resource_filename("ansiblelater", "rules")) with importlib.resources.as_file(ref) as path:
) defaults["rules"]["dir"].append(path)
defaults["rules"]["standards"] = [ defaults["rules"]["dir"] = [
os.path.relpath(os.path.normpath(p)) for p in defaults["rules"]["standards"] os.path.relpath(os.path.normpath(p)) for p in defaults["rules"]["dir"]
] ]
return defaults return defaults
@ -118,17 +118,16 @@ class Settings:
def _get_defaults(self): def _get_defaults(self):
defaults = { defaults = {
"rules": { "rules": {
"buildin": True, "builtin": True,
"standards": [], "dir": [],
"filter": [], "include_filter": [],
"exclude_filter": [], "exclude_filter": [],
"warning_filter": [ "warning_filter": [
"ANSIBLE9999", "ANS128",
"ANSIBLE9998", "ANS999",
], ],
"ignore_dotfiles": True, "ignore_dotfiles": True,
"exclude_files": [], "exclude_files": [],
"version": "",
}, },
"logging": { "logging": {
"level": "WARNING", "level": "WARNING",
@ -145,7 +144,7 @@ class Settings:
"exclude": [ "exclude": [
"meta", "meta",
"debug", "debug",
"block", "block/always/rescue",
"include_role", "include_role",
"import_role", "import_role",
"include_tasks", "include_tasks",
@ -175,12 +174,16 @@ class Settings:
"present": True, "present": True,
}, },
"document-end": { "document-end": {
"present": True, "present": False,
}, },
"colons": { "colons": {
"max-spaces-before": 0, "max-spaces-before": 0,
"max-spaces-after": 1, "max-spaces-after": 1,
}, },
"octal-values": {
"forbid-implicit-octal": True,
"forbid-explicit-octal": True,
},
}, },
} }

View File

@ -4,9 +4,10 @@ import contextlib
import re import re
import sys import sys
from contextlib import suppress from contextlib import suppress
from functools import lru_cache
import yaml import yaml
from packaging.version import Version from ansible.plugins.loader import module_loader
from ansiblelater import logger from ansiblelater import logger
@ -35,12 +36,6 @@ def count_spaces(c_string):
return (leading_spaces, trailing_spaces) return (leading_spaces, trailing_spaces)
def standards_latest(standards):
return max(
[standard.version for standard in standards if standard.version] or ["0.1"], key=Version
)
def lines_ranges(lines_spec): def lines_ranges(lines_spec):
if not lines_spec: if not lines_spec:
return None return None
@ -84,9 +79,7 @@ def open_file(filename, mode="r"):
def add_dict_branch(tree, vector, value): def add_dict_branch(tree, vector, value):
key = vector[0] key = vector[0]
tree[key] = ( tree[key] = (
value value if len(vector) == 1 else add_dict_branch(tree.get(key, {}), vector[1:], value)
if len(vector) == 1
else add_dict_branch(tree[key] if key in tree else {}, vector[1:], value)
) )
return tree return tree
@ -121,3 +114,21 @@ class Singleton(type):
if cls not in cls._instances: if cls not in cls._instances:
cls._instances[cls] = super().__call__(*args, **kwargs) cls._instances[cls] = super().__call__(*args, **kwargs)
return cls._instances[cls] return cls._instances[cls]
@lru_cache
def load_plugin(name):
"""Return loaded ansible plugin/module."""
loaded_module = module_loader.find_plugin_with_context(
name,
ignore_deprecated=True,
check_aliases=True,
)
if not loaded_module.resolved and name.startswith("ansible.builtin."):
# fallback to core behavior of using legacy
loaded_module = module_loader.find_plugin_with_context(
name.replace("ansible.builtin.", "ansible.legacy."),
ignore_deprecated=True,
check_aliases=True,
)
return loaded_module

View File

@ -65,11 +65,11 @@ def ansible_template(basedir, varname, templatevars, **kwargs):
try: try:
from ansible.plugins import module_loader
except ImportError:
from ansible.plugins.loader import init_plugin_loader, module_loader from ansible.plugins.loader import init_plugin_loader, module_loader
init_plugin_loader() init_plugin_loader()
except ImportError:
from ansible.plugins.loader import module_loader
LINE_NUMBER_KEY = "__line__" LINE_NUMBER_KEY = "__line__"
FILENAME_KEY = "__file__" FILENAME_KEY = "__file__"
@ -369,12 +369,63 @@ def _kv_to_dict(v):
def normalize_task(task, filename, custom_modules=None): def normalize_task(task, filename, custom_modules=None):
"""Ensure tasks have an action key and strings are converted to python objects.""" """Ensure tasks have an action key and strings are converted to python objects."""
if custom_modules is None: def _normalize(task, custom_modules):
custom_modules = [] if custom_modules is None:
custom_modules = []
ansible_action_type = task.get("__ansible_action_type__", "task") normalized = {}
if "__ansible_action_type__" in task: ansible_parsed_keys = ("action", "local_action", "args", "delegate_to")
del task["__ansible_action_type__"]
if is_nested_task(task):
_extract_ansible_parsed_keys_from_task(normalized, task, ansible_parsed_keys)
# Add dummy action for block/always/rescue statements
normalized["action"] = {
"__ansible_module__": "block/always/rescue",
"__ansible_module_original__": "block/always/rescue",
"__ansible_arguments__": "block/always/rescue",
}
return normalized
builtin = list(ansible.parsing.mod_args.BUILTIN_TASKS)
builtin = list(set(builtin + custom_modules))
ansible.parsing.mod_args.BUILTIN_TASKS = frozenset(builtin)
mod_arg_parser = ModuleArgsParser(task)
try:
action, arguments, normalized["delegate_to"] = mod_arg_parser.parse()
except AnsibleParserError as e:
raise LaterAnsibleError(e) from e
# denormalize shell -> command conversion
if "_uses_shell" in arguments:
action = "shell"
del arguments["_uses_shell"]
for k, v in list(task.items()):
if k in ansible_parsed_keys or k == action:
# we don"t want to re-assign these values, which were
# determined by the ModuleArgsParser() above
continue
normalized[k] = v
# convert builtin fqn calls to short forms because most rules know only
# about short calls
normalized["action"] = {
"__ansible_module__": action.removeprefix("ansible.builtin."),
"__ansible_module_original__": action,
}
if "_raw_params" in arguments:
normalized["action"]["__ansible_arguments__"] = (
arguments["_raw_params"].strip().split()
)
del arguments["_raw_params"]
else:
normalized["action"]["__ansible_arguments__"] = []
normalized["action"].update(arguments)
return normalized
# temp. extract metadata # temp. extract metadata
ansible_meta = {} ansible_meta = {}
@ -386,39 +437,11 @@ def normalize_task(task, filename, custom_modules=None):
ansible_meta[key] = task.pop(key, default) ansible_meta[key] = task.pop(key, default)
normalized = {} ansible_action_type = task.get("__ansible_action_type__", "task")
if "__ansible_action_type__" in task:
del task["__ansible_action_type__"]
builtin = list(ansible.parsing.mod_args.BUILTIN_TASKS) normalized = _normalize(task, custom_modules)
builtin = list(set(builtin + custom_modules))
ansible.parsing.mod_args.BUILTIN_TASKS = frozenset(builtin)
mod_arg_parser = ModuleArgsParser(task)
try:
action, arguments, normalized["delegate_to"] = mod_arg_parser.parse()
except AnsibleParserError as e:
raise LaterAnsibleError(e) from e
# denormalize shell -> command conversion
if "_uses_shell" in arguments:
action = "shell"
del arguments["_uses_shell"]
for k, v in list(task.items()):
if k in ("action", "local_action", "args", "delegate_to") or k == action:
# we don"t want to re-assign these values, which were
# determined by the ModuleArgsParser() above
continue
normalized[k] = v
normalized["action"] = {"__ansible_module__": action}
if "_raw_params" in arguments:
normalized["action"]["__ansible_arguments__"] = arguments["_raw_params"].strip().split()
del arguments["_raw_params"]
else:
normalized["action"]["__ansible_arguments__"] = []
normalized["action"].update(arguments)
normalized[FILENAME_KEY] = filename normalized[FILENAME_KEY] = filename
normalized["__ansible_action_type__"] = ansible_action_type normalized["__ansible_action_type__"] = ansible_action_type
@ -431,22 +454,17 @@ def normalize_task(task, filename, custom_modules=None):
return normalized return normalized
def action_tasks(yaml, file): def action_tasks(yaml, candidate):
tasks = [] tasks = []
if file["filetype"] in ["tasks", "handlers"]: if candidate.filemeta in ["tasks", "handlers"]:
tasks = add_action_type(yaml, file["filetype"]) tasks = add_action_type(yaml, candidate.filemeta)
else: else:
tasks.extend(extract_from_list(yaml, ["tasks", "handlers", "pre_tasks", "post_tasks"])) tasks.extend(extract_from_list(yaml, ["tasks", "handlers", "pre_tasks", "post_tasks"]))
# Add sub-elements of block/rescue/always to tasks list # Add sub-elements of block/rescue/always to tasks list
tasks.extend(extract_from_list(tasks, ["block", "rescue", "always"])) tasks.extend(extract_from_list(tasks, ["block", "rescue", "always"]))
# Remove block/rescue/always elements from tasks list
block_rescue_always = ("block", "rescue", "always")
tasks[:] = [task for task in tasks if all(k not in task for k in block_rescue_always)]
allowed = ["include", "include_tasks", "import_playbook", "import_tasks"] return tasks
return [task for task in tasks if set(allowed).isdisjoint(task.keys())]
def task_to_str(task): def task_to_str(task):
@ -475,7 +493,10 @@ def extract_from_list(blocks, candidates):
meta_data = dict(block) meta_data = dict(block)
for key in delete_meta_keys: for key in delete_meta_keys:
meta_data.pop(key, None) meta_data.pop(key, None)
results.extend(add_action_type(block[candidate], candidate, meta_data))
actions = add_action_type(block[candidate], candidate, meta_data)
results.extend(actions)
elif block[candidate] is not None: elif block[candidate] is not None:
raise RuntimeError( raise RuntimeError(
f"Key '{candidate}' defined, but bad value: '{block[candidate]!s}'" f"Key '{candidate}' defined, but bad value: '{block[candidate]!s}'"
@ -564,6 +585,26 @@ def normalized_yaml(file, options):
return lines return lines
def is_nested_task(task):
"""Check if task includes block/always/rescue."""
# Cannot really trust the input
if isinstance(task, str):
return False
return any(task.get(key) for key in ["block", "rescue", "always"])
def _extract_ansible_parsed_keys_from_task(result, task, keys):
"""Return a dict with existing key in task."""
for k, v in list(task.items()):
if k in keys:
# we don't want to re-assign these values, which were
# determined by the ModuleArgsParser() above
continue
result[k] = v
return result
class UnsafeTag: class UnsafeTag:
"""Handle custom yaml unsafe tag.""" """Handle custom yaml unsafe tag."""

View File

@ -1,18 +1,17 @@
--- ---
title: Minimal standard checks title: Write a rule
--- ---
A typical standards check will look like: A typical rule check will look like:
<!-- prettier-ignore-start --> <!-- prettier-ignore-start -->
<!-- spellchecker-disable --> <!-- spellchecker-disable -->
{{< highlight Python "linenos=table" >}} {{< highlight Python "linenos=table" >}}
class CheckBecomeUser(StandardBase): class CheckBecomeUser(RuleBase):
sid = "ANSIBLE0015" rid = "ANS115"
description = "Become should be combined with become_user" description = "Become should be combined with become_user"
helptext = "the task has `become` enabled but `become_user` is missing" helptext = "the task has `become` enabled but `become_user` is missing"
version = "0.1"
types = ["playbook", "task", "handler"] types = ["playbook", "task", "handler"]
def check(self, candidate, settings): def check(self, candidate, settings):

View File

@ -8,28 +8,27 @@ You can get all available CLI options by running `ansible-later --help`:
<!-- spellchecker-disable --> <!-- spellchecker-disable -->
{{< highlight Shell "linenos=table" >}} {{< highlight Shell "linenos=table" >}}
$ ansible-later --help $ ansible-later --help
usage: ansible-later [-h] [-c CONFIG_FILE] [-r RULES.STANDARDS] usage: ansible-later [-h] [-c CONFIG] [-r DIR] [-B] [-i TAGS] [-x TAGS] [-v] [-q] [-V] [rules.files ...]
[-s RULES.FILTER] [-v] [-q] [--version]
[rules.files [rules.files ...]]
Validate Ansible files against best practice guideline Validate Ansible files against best practice guideline
positional arguments: positional arguments:
rules.files rules.files
optional arguments: options:
-h, --help show this help message and exit -h, --help show this help message and exit
-c CONFIG_FILE, --config CONFIG_FILE -c CONFIG, --config CONFIG
location of configuration file path to configuration file
-r RULES.STANDARDS, --rules RULES.STANDARDS -r DIR, --rules-dir DIR
location of standards rules directory of rules
-s RULES.FILTER, --standards RULES.FILTER -B, --no-builtin disables built-in rules
limit standards to given ID's -i TAGS, --include-rules TAGS
-x RULES.EXCLUDE_FILTER, --exclude-standards RULES.EXCLUDE_FILTER limit rules to given id/tags
exclude standards by given ID's -x TAGS, --exclude-rules TAGS
exclude rules by given it/tags
-v increase log level -v increase log level
-q decrease log level -q decrease log level
--version show program's version number and exit -V, --version show program's version number and exit
{{< /highlight >}} {{< /highlight >}}
<!-- spellchecker-enable --> <!-- spellchecker-enable -->
<!-- prettier-ignore-end --> <!-- prettier-ignore-end -->

View File

@ -16,32 +16,32 @@ ansible:
# directory will be auto-detected and don't need to be added to this list. # directory will be auto-detected and don't need to be added to this list.
custom_modules: [] custom_modules: []
# Settings for variable formatting rule (ANSIBLE0004) # Settings for variable formatting rule (ANS104)
double-braces: double-braces:
max-spaces-inside: 1 max-spaces-inside: 1
min-spaces-inside: 1 min-spaces-inside: 1
# List of allowed literal bools (ANSIBLE0014) # List of allowed literal bools (ANS114)
literal-bools: literal-bools:
- "True" - "True"
- "False" - "False"
- "yes" - "yes"
- "no" - "no"
# List of modules that don't need to be named (ANSIBLE0006). # List of modules that don't need to be named (ANS106).
# You must specify each individual module name, globs or wildcards do not work! # You must specify each individual module name, globs or wildcards do not work!
named-task: named-task:
exclude: exclude:
- "meta" - "meta"
- "debug" - "debug"
- "block" - "block/always/rescue"
- "include_role" - "include_role"
- "include_tasks" - "include_tasks"
- "include_vars" - "include_vars"
- "import_role" - "import_role"
- "import_tasks" - "import_tasks"
# List of modules that are allowed to use the key=value format instead of the native YAML format (LINT0008). # List of modules that are allowed to use the key=value format instead of the native YAML format (YML108).
# You must specify each individual module name, globs or wildcards do not work! # You must specify each individual module name, globs or wildcards do not work!
native-yaml: native-yaml:
exclude: [] exclude: []
@ -58,8 +58,8 @@ logging:
# Global settings for all defined rules # Global settings for all defined rules
rules: rules:
# Disable build-in rules if required # Disable built-in rules if required
buildin: True builtin: True
# List of files to exclude # List of files to exclude
exclude_files: [] exclude_files: []
@ -75,22 +75,17 @@ rules:
exclude_filter: [] exclude_filter: []
# List of rule ID's that should be displayed as a warning instead of an error. By default, # List of rule ID's that should be displayed as a warning instead of an error. By default,
# only rules whose version is higher than the current default version are marked as warnings. # no rules are marked as warnings. This list allows to degrade errors to warnings for each rule.
# This list allows to degrade errors to warnings for each rule.
warning_filter: warning_filter:
- "ANSIBLE9999" - "ANS128"
- "ANSIBLE9998" - "ANS999"
# All dotfiles (including hidden folders) are excluded by default. # All dotfiles (including hidden folders) are excluded by default.
# You can disable this setting and handle dotfiles by yourself with `exclude_files`. # You can disable this setting and handle dotfiles by yourself with `exclude_files`.
ignore_dotfiles: True ignore_dotfiles: True
# List of directories to load standard rules from (defaults to build-in) # List of directories to load rules from (defaults to built-in)
standards: [] dir: []
# Standard version to use. Standard version set in a roles meta file
# or playbook will takes precedence.
version:
# Block to control included yamllint rules. # Block to control included yamllint rules.
# See https://yamllint.readthedocs.io/en/stable/rules.html # See https://yamllint.readthedocs.io/en/stable/rules.html
@ -100,6 +95,8 @@ yamllint:
max-spaces-before: 0 max-spaces-before: 0
document-start: document-start:
present: True present: True
document-end:
present: True
empty-lines: empty-lines:
max: 1 max: 1
max-end: 1 max-end: 1

View File

@ -2,45 +2,47 @@
title: Included rules title: Included rules
--- ---
Reviews are useless without some rules or standards to check against. ansible-later comes with a set of built-in checks, which are explained in the following table. Reviews are useless without some rules to check against. `ansible-later` comes with a set of built-in checks, which are explained in the following table.
| Rule | ID | Description | Parameter | | Rule | ID | Description | Parameter |
| ----------------------------- | ----------- | ----------------------------------------------------------------- | ---------------------------------------------------------------------- | | ----------------------------- | ------ | ----------------------------------------------------------------- | -------------------------------------------------------------------------- |
| CheckYamlEmptyLines | LINT0001 | YAML should not contain unnecessarily empty lines. | {max: 1, max-start: 0, max-end: 1} | | CheckYamlEmptyLines | YML101 | YAML should not contain unnecessarily empty lines. | {max: 1, max-start: 0, max-end: 1} |
| CheckYamlIndent | LINT0002 | YAML should be correctly indented. | {spaces: 2, check-multi-line-strings: false, indent-sequences: true} | | CheckYamlIndent | YML102 | YAML should be correctly indented. | {spaces: 2, check-multi-line-strings: false, indent-sequences: true} |
| CheckYamlHyphens | LINT0003 | YAML should use consistent number of spaces after hyphens (-). | {max-spaces-after: 1} | | CheckYamlHyphens | YML103 | YAML should use consistent number of spaces after hyphens (-). | {max-spaces-after: 1} |
| CheckYamlDocumentStart | LINT0004 | YAML should contain document start marker. | {document-start: {present: true}} | | CheckYamlDocumentStart | YML104 | YAML should contain document start marker. | {document-start: {present: true}} |
| CheckYamlColons | LINT0005 | YAML should use consistent number of spaces around colons. | {colons: {max-spaces-before: 0, max-spaces-after: 1}} | | CheckYamlColons | YML105 | YAML should use consistent number of spaces around colons. | {colons: {max-spaces-before: 0, max-spaces-after: 1}} |
| CheckYamlFile | LINT0006 | Roles file should be in YAML format. | | | CheckYamlFile | YML106 | Roles file should be in YAML format. | |
| CheckYamlHasContent | LINT0007 | Files should contain useful content. | | | CheckYamlHasContent | YML107 | Files should contain useful content. | |
| CheckNativeYaml | LINT0008 | Use YAML format for tasks and handlers rather than key=value. | {native-yaml: {exclude: []}} | | CheckNativeYaml | YML108 | Use YAML format for tasks and handlers rather than key=value. | {native-yaml: {exclude: []}} |
| CheckYamlDocumentEnd | LINT0009 | YAML should contain document end marker. | {document-end: {present: true}} | | CheckYamlDocumentEnd | YML109 | YAML should contain document end marker. | {document-end: {present: true}} |
| CheckTaskSeparation | ANSIBLE0001 | Single tasks should be separated by an empty line. | | | CheckYamlOctalValues | YML110 | YAML should not use forbidden implicit or explicit octal value. | {octal-values: {forbid-implicit-octal: true, forbid-explicit-octal: true}} |
| CheckMetaMain | ANSIBLE0002 | Meta file should contain a basic subset of parameters. | author, description, min_ansible_version, platforms, dependencies | | CheckTaskSeparation | ANS101 | Single tasks should be separated by an empty line. | |
| CheckUniqueNamedTask | ANSIBLE0003 | Tasks and handlers must be uniquely named within a file. | | | CheckMetaMain | ANS102 | Meta file should contain a basic subset of parameters. | author, description, min_ansible_version, platforms, dependencies |
| CheckBraces | ANSIBLE0004 | YAML should use consistent number of spaces around variables. | {double-braces: max-spaces-inside: 1, min-spaces-inside: 1} | | CheckUniqueNamedTask | ANS103 | Tasks and handlers must be uniquely named within a file. | |
| CheckScmInSrc | ANSIBLE0005 | Use SCM key rather than `src: scm+url` in requirements file. | | | CheckBraces | ANS104 | YAML should use consistent number of spaces around variables. | {double-braces: max-spaces-inside: 1, min-spaces-inside: 1} |
| CheckNamedTask | ANSIBLE0006 | Tasks and handlers must be named. | {named-task: {exclude: [meta, debug, block, include\_\*, import\_\*]}} | | CheckScmInSrc | ANS105 | Use SCM key rather than `src: scm+url` in requirements file. | |
| CheckNameFormat | ANSIBLE0007 | Name of tasks and handlers must be formatted. | formats: first letter capital | | CheckNamedTask | ANS106 | Tasks and handlers must be named. | {named-task: {exclude: [meta, debug, block, include\_\*, import\_\*]}} |
| CheckCommandInsteadofModule | ANSIBLE0008 | Commands should not be used in place of modules. | | | CheckNameFormat | ANS107 | Name of tasks and handlers must be formatted. | formats: first letter capital |
| CheckInstallUseLatest | ANSIBLE0009 | Package managers should not install with state=latest. | | | CheckCommandInsteadofModule | ANS108 | Commands should not be used in place of modules. | |
| CheckShellInsteadCommand | ANSIBLE0010 | Use Shell only when piping, redirecting or chaining commands. | | | CheckInstallUseLatest | ANS109 | Package managers should not install with state=latest. | |
| CheckCommandHasChanges | ANSIBLE0011 | Commands should be idempotent and only used with some checks. | | | CheckShellInsteadCommand | ANS110 | Use Shell only when piping, redirecting or chaining commands. | |
| CheckCompareToEmptyString | ANSIBLE0012 | Don't compare to "" - use `when: var` or `when: not var`. | | | CheckCommandHasChanges | ANS111 | Commands should be idempotent and only used with some checks. | |
| CheckCompareToLiteralBool | ANSIBLE0013 | Don't compare to True/False - use `when: var` or `when: not var`. | | | CheckCompareToEmptyString | ANS112 | Don't compare to "" - use `when: var` or `when: not var`. | |
| CheckLiteralBoolFormat | ANSIBLE0014 | Literal bools should be consistent. | {literal-bools: [True, False, yes, no]} | | CheckCompareToLiteralBool | ANS113 | Don't compare to True/False - use `when: var` or `when: not var`. | |
| CheckBecomeUser | ANSIBLE0015 | Become should be combined with become_user. | | | CheckLiteralBoolFormat | ANS114 | Literal bools should be consistent. | {literal-bools: [True, False, yes, no]} |
| CheckFilterSeparation | ANSIBLE0016 | Jinja2 filters should be separated with spaces. | | | CheckBecomeUser | ANS115 | Become should be combined with become_user. | |
| CheckCommandInsteadOfArgument | ANSIBLE0017 | Commands should not be used in place of module arguments. | | | CheckFilterSeparation | ANS116 | Jinja2 filters should be separated with spaces. | |
| CheckFilePermissionMissing | ANSIBLE0018 | File permissions unset or incorrect. | | | CheckCommandInsteadOfArgument | ANS117 | Commands should not be used in place of module arguments. | |
| CheckFilePermissionOctal | ANSIBLE0019 | Octal file permissions must contain leading zero or be a string. | | | CheckFilePermissionMissing | ANS118 | File permissions unset or incorrect. | |
| CheckGitHasVersion | ANSIBLE0020 | Git checkouts should use explicit version. | | | CheckFilePermissionOctal | ANS119 | Octal file permissions must contain leading zero or be a string. | |
| CheckMetaChangeFromDefault | ANSIBLE0021 | Roles meta/main.yml default values should be changed. | | | CheckGitHasVersion | ANS120 | Git checkouts should use explicit version. | |
| CheckWhenFormat | ANSIBLE0022 | Don't use Jinja2 in `when`. | | | CheckMetaChangeFromDefault | ANS121 | Roles meta/main.yml default values should be changed. | |
| CheckNestedJinja | ANSIBLE0023 | Don't use nested Jinja2 pattern. | | | CheckWhenFormat | ANS122 | Don't use Jinja2 in `when`. | |
| CheckLocalAction | ANSIBLE0024 | Don't use local_action. | | | CheckNestedJinja | ANS123 | Don't use nested Jinja2 pattern. | |
| CheckRelativeRolePaths | ANSIBLE0025 | Don't use a relative path in a role. | | | CheckLocalAction | ANS124 | Don't use local_action. | |
| CheckChangedInWhen | ANSIBLE0026 | Use handlers instead of `when: changed`. | | | CheckRelativeRolePaths | ANS125 | Don't use a relative path in a role. | |
| CheckChangedInWhen | ANSIBLE0027 | Deprecated bare variables in loops must not be used. | | | CheckChangedInWhen | ANS126 | Use handlers instead of `when: changed`. | |
| CheckVersion | ANSIBLE9998 | Standards version should be pinned. | | | CheckChangedInWhen | ANS127 | Deprecated bare variables in loops must not be used. | |
| CheckDeprecated | ANSIBLE9999 | Deprecated features of `ansible-later` should not be used. | | | CheckFQCNBuiltin | ANS128 | Module actions should use full qualified collection names. | |
| CheckFQCNBuiltin | ANS129 | Check optimized playbook/tasks key order. | |
| CheckDeprecated | ANS999 | Deprecated features of `ansible-later` should not be used. | |

View File

@ -23,5 +23,5 @@ main:
sub: sub:
- name: Candidates - name: Candidates
ref: "/build_rules/candidates" ref: "/build_rules/candidates"
- name: Standards checks - name: Rules
ref: "/build_rules/standards_check" ref: "/build_rules/rule"

703
poetry.lock generated
View File

@ -2,56 +2,51 @@
[[package]] [[package]]
name = "ansible" name = "ansible"
version = "8.7.0" version = "7.7.0"
description = "Radically simple IT automation" description = "Radically simple IT automation"
optional = true optional = true
python-versions = ">=3.9" python-versions = ">=3.9"
files = [ files = [
{file = "ansible-8.7.0-py3-none-any.whl", hash = "sha256:fa7d3bc2dfdb0ab031df645814ff86b15cb5ec041bfbee4041f795abfa5646ca"}, {file = "ansible-7.7.0-py3-none-any.whl", hash = "sha256:4f8d346db1b6cec0f30b77935b3dce5633d76881186da839b58b34b48a089b92"},
{file = "ansible-8.7.0.tar.gz", hash = "sha256:3a5ca5152e4547d590e40b542d76b18dbbe2b36da4edd00a13a7c51a374ff737"}, {file = "ansible-7.7.0.tar.gz", hash = "sha256:9c206ba515f13a0cc9c919d496218ba26df581755bdc39be85b074066c699a02"},
] ]
[package.dependencies] [package.dependencies]
ansible-core = ">=2.15.7,<2.16.0" ansible-core = ">=2.14.7,<2.15.0"
[[package]] [[package]]
name = "ansible-core" name = "ansible-core"
version = "2.15.8" version = "2.14.17"
description = "Radically simple IT automation" description = "Radically simple IT automation"
optional = true optional = true
python-versions = ">=3.9" python-versions = ">=3.9"
files = [ files = [
{file = "ansible-core-2.15.8.tar.gz", hash = "sha256:8aa49cb1ddbf33d88c2bb4bf09ecd4b0dd8b788e174adca8b88dda6e6bdbf59b"}, {file = "ansible_core-2.14.17-py3-none-any.whl", hash = "sha256:fefd600780a9fa40f7cdc432264d861731682db43255eb0ebb6e6b6ab6165b1e"},
{file = "ansible_core-2.15.8-py3-none-any.whl", hash = "sha256:55e6f4350fb98ac5441620ba981b1d9f7b90aa5f320885965af996e149bd3caa"}, {file = "ansible_core-2.14.17.tar.gz", hash = "sha256:9afec5ffd3bd762c258f4661e831e0930a4d99ae9d84844ddd7abf7da2c63114"},
] ]
[package.dependencies] [package.dependencies]
cryptography = "*" cryptography = "*"
importlib-resources = {version = ">=5.0,<5.1", markers = "python_version < \"3.10\""}
jinja2 = ">=3.0.0" jinja2 = ">=3.0.0"
packaging = "*" packaging = "*"
PyYAML = ">=5.1" PyYAML = ">=5.1"
resolvelib = ">=0.5.3,<1.1.0" resolvelib = ">=0.5.3,<0.9.0"
[[package]] [[package]]
name = "anyconfig" name = "anyconfig"
version = "0.13.0" version = "0.14.0"
description = "Library provides common APIs to load and dump configuration files in various formats" description = "Library provides common APIs to load and dump configuration files in various formats"
optional = false optional = false
python-versions = "*" python-versions = "*"
files = [ files = [
{file = "anyconfig-0.13.0-py2.py3-none-any.whl", hash = "sha256:17cb189938d6cda4d21a2dabcd63db86658d2556e767dfd4835b1011544a1f8e"}, {file = "anyconfig-0.14.0.tar.gz", hash = "sha256:2cdf54af5dae8e91743ded82c54ed9d8aaefa3a9722f5d45e9b5f74b603e014d"},
{file = "anyconfig-0.13.0.tar.gz", hash = "sha256:03ff2e1762af388fbbbed1c1ab7f9f1ec006a91da7db3a68b963da6e7795d2ac"},
] ]
[package.dependencies]
setuptools = "*"
[package.extras] [package.extras]
query = ["jmespath"] query = ["jmespath"]
schema = ["jsonschema"] schema = ["jsonschema"]
template = ["Jinja2"] template = ["Jinja2"]
toml = ["toml"] toml = ["tomli", "tomli-w"]
yaml = ["pyyaml"] yaml = ["pyyaml"]
[[package]] [[package]]
@ -67,21 +62,22 @@ files = [
[[package]] [[package]]
name = "attrs" name = "attrs"
version = "23.1.0" version = "23.2.0"
description = "Classes Without Boilerplate" description = "Classes Without Boilerplate"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"},
{file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"},
] ]
[package.extras] [package.extras]
cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] cov = ["attrs[tests]", "coverage[toml] (>=5.3)"]
dev = ["attrs[docs,tests]", "pre-commit"] dev = ["attrs[tests]", "pre-commit"]
docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"]
tests = ["attrs[tests-no-zope]", "zope-interface"] tests = ["attrs[tests-no-zope]", "zope-interface"]
tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"]
tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"]
[[package]] [[package]]
name = "cffi" name = "cffi"
@ -160,63 +156,63 @@ files = [
[[package]] [[package]]
name = "coverage" name = "coverage"
version = "7.3.2" version = "7.5.3"
description = "Code coverage measurement for Python" description = "Code coverage measurement for Python"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "coverage-7.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d872145f3a3231a5f20fd48500274d7df222e291d90baa2026cc5152b7ce86bf"}, {file = "coverage-7.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45"},
{file = "coverage-7.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:310b3bb9c91ea66d59c53fa4989f57d2436e08f18fb2f421a1b0b6b8cc7fffda"}, {file = "coverage-7.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec"},
{file = "coverage-7.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f47d39359e2c3779c5331fc740cf4bce6d9d680a7b4b4ead97056a0ae07cb49a"}, {file = "coverage-7.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286"},
{file = "coverage-7.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa72dbaf2c2068404b9870d93436e6d23addd8bbe9295f49cbca83f6e278179c"}, {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc"},
{file = "coverage-7.3.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:beaa5c1b4777f03fc63dfd2a6bd820f73f036bfb10e925fce067b00a340d0f3f"}, {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d"},
{file = "coverage-7.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:dbc1b46b92186cc8074fee9d9fbb97a9dd06c6cbbef391c2f59d80eabdf0faa6"}, {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83"},
{file = "coverage-7.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:315a989e861031334d7bee1f9113c8770472db2ac484e5b8c3173428360a9148"}, {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d"},
{file = "coverage-7.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d1bc430677773397f64a5c88cb522ea43175ff16f8bfcc89d467d974cb2274f9"}, {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c"},
{file = "coverage-7.3.2-cp310-cp310-win32.whl", hash = "sha256:a889ae02f43aa45032afe364c8ae84ad3c54828c2faa44f3bfcafecb5c96b02f"}, {file = "coverage-7.5.3-cp310-cp310-win32.whl", hash = "sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84"},
{file = "coverage-7.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c0ba320de3fb8c6ec16e0be17ee1d3d69adcda99406c43c0409cb5c41788a611"}, {file = "coverage-7.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac"},
{file = "coverage-7.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ac8c802fa29843a72d32ec56d0ca792ad15a302b28ca6203389afe21f8fa062c"}, {file = "coverage-7.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974"},
{file = "coverage-7.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:89a937174104339e3a3ffcf9f446c00e3a806c28b1841c63edb2b369310fd074"}, {file = "coverage-7.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232"},
{file = "coverage-7.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e267e9e2b574a176ddb983399dec325a80dbe161f1a32715c780b5d14b5f583a"}, {file = "coverage-7.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd"},
{file = "coverage-7.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2443cbda35df0d35dcfb9bf8f3c02c57c1d6111169e3c85fc1fcc05e0c9f39a3"}, {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807"},
{file = "coverage-7.3.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4175e10cc8dda0265653e8714b3174430b07c1dca8957f4966cbd6c2b1b8065a"}, {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb"},
{file = "coverage-7.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0cbf38419fb1a347aaf63481c00f0bdc86889d9fbf3f25109cf96c26b403fda1"}, {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc"},
{file = "coverage-7.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5c913b556a116b8d5f6ef834038ba983834d887d82187c8f73dec21049abd65c"}, {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8"},
{file = "coverage-7.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1981f785239e4e39e6444c63a98da3a1db8e971cb9ceb50a945ba6296b43f312"}, {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614"},
{file = "coverage-7.3.2-cp311-cp311-win32.whl", hash = "sha256:43668cabd5ca8258f5954f27a3aaf78757e6acf13c17604d89648ecc0cc66640"}, {file = "coverage-7.5.3-cp311-cp311-win32.whl", hash = "sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9"},
{file = "coverage-7.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10c39c0452bf6e694511c901426d6b5ac005acc0f78ff265dbe36bf81f808a2"}, {file = "coverage-7.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a"},
{file = "coverage-7.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4cbae1051ab791debecc4a5dcc4a1ff45fc27b91b9aee165c8a27514dd160836"}, {file = "coverage-7.5.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8"},
{file = "coverage-7.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12d15ab5833a997716d76f2ac1e4b4d536814fc213c85ca72756c19e5a6b3d63"}, {file = "coverage-7.5.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3"},
{file = "coverage-7.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c7bba973ebee5e56fe9251300c00f1579652587a9f4a5ed8404b15a0471f216"}, {file = "coverage-7.5.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1"},
{file = "coverage-7.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe494faa90ce6381770746077243231e0b83ff3f17069d748f645617cefe19d4"}, {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db"},
{file = "coverage-7.3.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6e9589bd04d0461a417562649522575d8752904d35c12907d8c9dfeba588faf"}, {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd"},
{file = "coverage-7.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d51ac2a26f71da1b57f2dc81d0e108b6ab177e7d30e774db90675467c847bbdf"}, {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523"},
{file = "coverage-7.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:99b89d9f76070237975b315b3d5f4d6956ae354a4c92ac2388a5695516e47c84"}, {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35"},
{file = "coverage-7.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fa28e909776dc69efb6ed975a63691bc8172b64ff357e663a1bb06ff3c9b589a"}, {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84"},
{file = "coverage-7.3.2-cp312-cp312-win32.whl", hash = "sha256:289fe43bf45a575e3ab10b26d7b6f2ddb9ee2dba447499f5401cfb5ecb8196bb"}, {file = "coverage-7.5.3-cp312-cp312-win32.whl", hash = "sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08"},
{file = "coverage-7.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7dbc3ed60e8659bc59b6b304b43ff9c3ed858da2839c78b804973f613d3e92ed"}, {file = "coverage-7.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb"},
{file = "coverage-7.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f94b734214ea6a36fe16e96a70d941af80ff3bfd716c141300d95ebc85339738"}, {file = "coverage-7.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f78300789a708ac1f17e134593f577407d52d0417305435b134805c4fb135adb"},
{file = "coverage-7.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:af3d828d2c1cbae52d34bdbb22fcd94d1ce715d95f1a012354a75e5913f1bda2"}, {file = "coverage-7.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b368e1aee1b9b75757942d44d7598dcd22a9dbb126affcbba82d15917f0cc155"},
{file = "coverage-7.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:630b13e3036e13c7adc480ca42fa7afc2a5d938081d28e20903cf7fd687872e2"}, {file = "coverage-7.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f836c174c3a7f639bded48ec913f348c4761cbf49de4a20a956d3431a7c9cb24"},
{file = "coverage-7.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9eacf273e885b02a0273bb3a2170f30e2d53a6d53b72dbe02d6701b5296101c"}, {file = "coverage-7.5.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:244f509f126dc71369393ce5fea17c0592c40ee44e607b6d855e9c4ac57aac98"},
{file = "coverage-7.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8f17966e861ff97305e0801134e69db33b143bbfb36436efb9cfff6ec7b2fd9"}, {file = "coverage-7.5.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4c2872b3c91f9baa836147ca33650dc5c172e9273c808c3c3199c75490e709d"},
{file = "coverage-7.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b4275802d16882cf9c8b3d057a0839acb07ee9379fa2749eca54efbce1535b82"}, {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dd4b3355b01273a56b20c219e74e7549e14370b31a4ffe42706a8cda91f19f6d"},
{file = "coverage-7.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:72c0cfa5250f483181e677ebc97133ea1ab3eb68645e494775deb6a7f6f83901"}, {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f542287b1489c7a860d43a7d8883e27ca62ab84ca53c965d11dac1d3a1fab7ce"},
{file = "coverage-7.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cb536f0dcd14149425996821a168f6e269d7dcd2c273a8bff8201e79f5104e76"}, {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:75e3f4e86804023e991096b29e147e635f5e2568f77883a1e6eed74512659ab0"},
{file = "coverage-7.3.2-cp38-cp38-win32.whl", hash = "sha256:307adb8bd3abe389a471e649038a71b4eb13bfd6b7dd9a129fa856f5c695cf92"}, {file = "coverage-7.5.3-cp38-cp38-win32.whl", hash = "sha256:c59d2ad092dc0551d9f79d9d44d005c945ba95832a6798f98f9216ede3d5f485"},
{file = "coverage-7.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:88ed2c30a49ea81ea3b7f172e0269c182a44c236eb394718f976239892c0a27a"}, {file = "coverage-7.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:fa21a04112c59ad54f69d80e376f7f9d0f5f9123ab87ecd18fbb9ec3a2beed56"},
{file = "coverage-7.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b631c92dfe601adf8f5ebc7fc13ced6bb6e9609b19d9a8cd59fa47c4186ad1ce"}, {file = "coverage-7.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5102a92855d518b0996eb197772f5ac2a527c0ec617124ad5242a3af5e25f85"},
{file = "coverage-7.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d3d9df4051c4a7d13036524b66ecf7a7537d14c18a384043f30a303b146164e9"}, {file = "coverage-7.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d1da0a2e3b37b745a2b2a678a4c796462cf753aebf94edcc87dcc6b8641eae31"},
{file = "coverage-7.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f7363d3b6a1119ef05015959ca24a9afc0ea8a02c687fe7e2d557705375c01f"}, {file = "coverage-7.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8383a6c8cefba1b7cecc0149415046b6fc38836295bc4c84e820872eb5478b3d"},
{file = "coverage-7.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f11cc3c967a09d3695d2a6f03fb3e6236622b93be7a4b5dc09166a861be6d25"}, {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9aad68c3f2566dfae84bf46295a79e79d904e1c21ccfc66de88cd446f8686341"},
{file = "coverage-7.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:149de1d2401ae4655c436a3dced6dd153f4c3309f599c3d4bd97ab172eaf02d9"}, {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e079c9ec772fedbade9d7ebc36202a1d9ef7291bc9b3a024ca395c4d52853d7"},
{file = "coverage-7.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3a4006916aa6fee7cd38db3bfc95aa9c54ebb4ffbfc47c677c8bba949ceba0a6"}, {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bde997cac85fcac227b27d4fb2c7608a2c5f6558469b0eb704c5726ae49e1c52"},
{file = "coverage-7.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9028a3871280110d6e1aa2df1afd5ef003bab5fb1ef421d6dc748ae1c8ef2ebc"}, {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:990fb20b32990b2ce2c5f974c3e738c9358b2735bc05075d50a6f36721b8f303"},
{file = "coverage-7.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9f805d62aec8eb92bab5b61c0f07329275b6f41c97d80e847b03eb894f38d083"}, {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3d5a67f0da401e105753d474369ab034c7bae51a4c31c77d94030d59e41df5bd"},
{file = "coverage-7.3.2-cp39-cp39-win32.whl", hash = "sha256:d1c88ec1a7ff4ebca0219f5b1ef863451d828cccf889c173e1253aa84b1e07ce"}, {file = "coverage-7.5.3-cp39-cp39-win32.whl", hash = "sha256:e08c470c2eb01977d221fd87495b44867a56d4d594f43739a8028f8646a51e0d"},
{file = "coverage-7.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b4767da59464bb593c07afceaddea61b154136300881844768037fd5e859353f"}, {file = "coverage-7.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:1d2a830ade66d3563bb61d1e3c77c8def97b30ed91e166c67d0632c018f380f0"},
{file = "coverage-7.3.2-pp38.pp39.pp310-none-any.whl", hash = "sha256:ae97af89f0fbf373400970c0a21eef5aa941ffeed90aee43650b81f7d7f47637"}, {file = "coverage-7.5.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884"},
{file = "coverage-7.3.2.tar.gz", hash = "sha256:be32ad29341b0170e795ca590e1c07e81fc061cb5b10c74ce7203491484404ef"}, {file = "coverage-7.5.3.tar.gz", hash = "sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f"},
] ]
[package.dependencies] [package.dependencies]
@ -227,78 +223,72 @@ toml = ["tomli"]
[[package]] [[package]]
name = "cryptography" name = "cryptography"
version = "41.0.7" version = "42.0.7"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
optional = true optional = true
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:3c78451b78313fa81607fa1b3f1ae0a5ddd8014c38a02d9db0616133987b9cdf"}, {file = "cryptography-42.0.7-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:a987f840718078212fdf4504d0fd4c6effe34a7e4740378e59d47696e8dfb477"},
{file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:928258ba5d6f8ae644e764d0f996d61a8777559f72dfeb2eea7e2fe0ad6e782d"}, {file = "cryptography-42.0.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:bd13b5e9b543532453de08bcdc3cc7cebec6f9883e886fd20a92f26940fd3e7a"},
{file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a1b41bc97f1ad230a41657d9155113c7521953869ae57ac39ac7f1bb471469a"}, {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a79165431551042cc9d1d90e6145d5d0d3ab0f2d66326c201d9b0e7f5bf43604"},
{file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:841df4caa01008bad253bce2a6f7b47f86dc9f08df4b433c404def869f590a15"}, {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a47787a5e3649008a1102d3df55424e86606c9bae6fb77ac59afe06d234605f8"},
{file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5429ec739a29df2e29e15d082f1d9ad683701f0ec7709ca479b3ff2708dae65a"}, {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:02c0eee2d7133bdbbc5e24441258d5d2244beb31da5ed19fbb80315f4bbbff55"},
{file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:43f2552a2378b44869fe8827aa19e69512e3245a219104438692385b0ee119d1"}, {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:5e44507bf8d14b36b8389b226665d597bc0f18ea035d75b4e53c7b1ea84583cc"},
{file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:af03b32695b24d85a75d40e1ba39ffe7db7ffcb099fe507b39fd41a565f1b157"}, {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7f8b25fa616d8b846aef64b15c606bb0828dbc35faf90566eb139aa9cff67af2"},
{file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:49f0805fc0b2ac8d4882dd52f4a3b935b210935d500b6b805f321addc8177406"}, {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:93a3209f6bb2b33e725ed08ee0991b92976dfdcf4e8b38646540674fc7508e13"},
{file = "cryptography-41.0.7-cp37-abi3-win32.whl", hash = "sha256:f983596065a18a2183e7f79ab3fd4c475205b839e02cbc0efbbf9666c4b3083d"}, {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e6b8f1881dac458c34778d0a424ae5769de30544fc678eac51c1c8bb2183e9da"},
{file = "cryptography-41.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:90452ba79b8788fa380dfb587cca692976ef4e757b194b093d845e8d99f612f2"}, {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3de9a45d3b2b7d8088c3fbf1ed4395dfeff79d07842217b38df14ef09ce1d8d7"},
{file = "cryptography-41.0.7-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:079b85658ea2f59c4f43b70f8119a52414cdb7be34da5d019a77bf96d473b960"}, {file = "cryptography-42.0.7-cp37-abi3-win32.whl", hash = "sha256:789caea816c6704f63f6241a519bfa347f72fbd67ba28d04636b7c6b7da94b0b"},
{file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:b640981bf64a3e978a56167594a0e97db71c89a479da8e175d8bb5be5178c003"}, {file = "cryptography-42.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:8cb8ce7c3347fcf9446f201dc30e2d5a3c898d009126010cbd1f443f28b52678"},
{file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e3114da6d7f95d2dee7d3f4eec16dacff819740bbab931aff8648cb13c5ff5e7"}, {file = "cryptography-42.0.7-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:a3a5ac8b56fe37f3125e5b72b61dcde43283e5370827f5233893d461b7360cd4"},
{file = "cryptography-41.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d5ec85080cce7b0513cfd233914eb8b7bbd0633f1d1703aa28d1dd5a72f678ec"}, {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:779245e13b9a6638df14641d029add5dc17edbef6ec915688f3acb9e720a5858"},
{file = "cryptography-41.0.7-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7a698cb1dac82c35fcf8fe3417a3aaba97de16a01ac914b89a0889d364d2f6be"}, {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d563795db98b4cd57742a78a288cdbdc9daedac29f2239793071fe114f13785"},
{file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:37a138589b12069efb424220bf78eac59ca68b95696fc622b6ccc1c0a197204a"}, {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:31adb7d06fe4383226c3e963471f6837742889b3c4caa55aac20ad951bc8ffda"},
{file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:68a2dec79deebc5d26d617bfdf6e8aab065a4f34934b22d3b5010df3ba36612c"}, {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:efd0bf5205240182e0f13bcaea41be4fdf5c22c5129fc7ced4a0282ac86998c9"},
{file = "cryptography-41.0.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:09616eeaef406f99046553b8a40fbf8b1e70795a91885ba4c96a70793de5504a"}, {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a9bc127cdc4ecf87a5ea22a2556cab6c7eda2923f84e4f3cc588e8470ce4e42e"},
{file = "cryptography-41.0.7-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48a0476626da912a44cc078f9893f292f0b3e4c739caf289268168d8f4702a39"}, {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:3577d029bc3f4827dd5bf8bf7710cac13527b470bbf1820a3f394adb38ed7d5f"},
{file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c7f3201ec47d5207841402594f1d7950879ef890c0c495052fa62f58283fde1a"}, {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2e47577f9b18723fa294b0ea9a17d5e53a227867a0a4904a1a076d1646d45ca1"},
{file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c5ca78485a255e03c32b513f8c2bc39fedb7f5c5f8535545bdc223a03b24f248"}, {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1a58839984d9cb34c855197043eaae2c187d930ca6d644612843b4fe8513c886"},
{file = "cryptography-41.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d6c391c021ab1f7a82da5d8d0b3cee2f4b2c455ec86c8aebbc84837a631ff309"}, {file = "cryptography-42.0.7-cp39-abi3-win32.whl", hash = "sha256:e6b79d0adb01aae87e8a44c2b64bc3f3fe59515280e00fb6d57a7267a2583cda"},
{file = "cryptography-41.0.7.tar.gz", hash = "sha256:13f93ce9bea8016c253b34afc6bd6a75993e5c40672ed5405a9c832f0d4a00bc"}, {file = "cryptography-42.0.7-cp39-abi3-win_amd64.whl", hash = "sha256:16268d46086bb8ad5bf0a2b5544d8a9ed87a0e33f5e77dd3c3301e63d941a83b"},
{file = "cryptography-42.0.7-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2954fccea107026512b15afb4aa664a5640cd0af630e2ee3962f2602693f0c82"},
{file = "cryptography-42.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:362e7197754c231797ec45ee081f3088a27a47c6c01eff2ac83f60f85a50fe60"},
{file = "cryptography-42.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4f698edacf9c9e0371112792558d2f705b5645076cc0aaae02f816a0171770fd"},
{file = "cryptography-42.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5482e789294854c28237bba77c4c83be698be740e31a3ae5e879ee5444166582"},
{file = "cryptography-42.0.7-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e9b2a6309f14c0497f348d08a065d52f3020656f675819fc405fb63bbcd26562"},
{file = "cryptography-42.0.7-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d8e3098721b84392ee45af2dd554c947c32cc52f862b6a3ae982dbb90f577f14"},
{file = "cryptography-42.0.7-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c65f96dad14f8528a447414125e1fc8feb2ad5a272b8f68477abbcc1ea7d94b9"},
{file = "cryptography-42.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36017400817987670037fbb0324d71489b6ead6231c9604f8fc1f7d008087c68"},
{file = "cryptography-42.0.7.tar.gz", hash = "sha256:ecbfbc00bf55888edda9868a4cf927205de8499e7fabe6c050322298382953f2"},
] ]
[package.dependencies] [package.dependencies]
cffi = ">=1.12" cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""}
[package.extras] [package.extras]
docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"]
docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"]
nox = ["nox"] nox = ["nox"]
pep8test = ["black", "check-sdist", "mypy", "ruff"] pep8test = ["check-sdist", "click", "mypy", "ruff"]
sdist = ["build"] sdist = ["build"]
ssh = ["bcrypt (>=3.1.5)"] ssh = ["bcrypt (>=3.1.5)"]
test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test = ["certifi", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"]
test-randomorder = ["pytest-randomly"] test-randomorder = ["pytest-randomly"]
[[package]] [[package]]
name = "exceptiongroup" name = "exceptiongroup"
version = "1.2.0" version = "1.2.1"
description = "Backport of PEP 654 (exception groups)" description = "Backport of PEP 654 (exception groups)"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"},
{file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"},
] ]
[package.extras] [package.extras]
test = ["pytest (>=6)"] test = ["pytest (>=6)"]
[[package]]
name = "importlib-resources"
version = "5.0.7"
description = "Read resources from Python packages"
optional = true
python-versions = ">=3.6"
files = [
{file = "importlib_resources-5.0.7-py3-none-any.whl", hash = "sha256:2238159eb743bd85304a16e0536048b3e991c531d1cd51c4a834d1ccf2829057"},
{file = "importlib_resources-5.0.7.tar.gz", hash = "sha256:4df460394562b4581bb4e4087ad9447bd433148fba44241754ec3152499f1d1b"},
]
[package.extras]
docs = ["jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "sphinx"]
testing = ["pytest (>=3.5,!=3.7.3)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=1.2.3)", "pytest-cov", "pytest-enabler", "pytest-flake8", "pytest-mypy"]
[[package]] [[package]]
name = "iniconfig" name = "iniconfig"
version = "2.0.0" version = "2.0.0"
@ -312,13 +302,13 @@ files = [
[[package]] [[package]]
name = "jinja2" name = "jinja2"
version = "3.1.2" version = "3.1.4"
description = "A very fast and expressive template engine." description = "A very fast and expressive template engine."
optional = true optional = true
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"},
{file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"},
] ]
[package.dependencies] [package.dependencies]
@ -329,13 +319,13 @@ i18n = ["Babel (>=2.7)"]
[[package]] [[package]]
name = "jsonschema" name = "jsonschema"
version = "4.20.0" version = "4.22.0"
description = "An implementation of JSON Schema validation for Python" description = "An implementation of JSON Schema validation for Python"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "jsonschema-4.20.0-py3-none-any.whl", hash = "sha256:ed6231f0429ecf966f5bc8dfef245998220549cbbcf140f913b7464c52c3b6b3"}, {file = "jsonschema-4.22.0-py3-none-any.whl", hash = "sha256:ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802"},
{file = "jsonschema-4.20.0.tar.gz", hash = "sha256:4f614fd46d8d61258610998997743ec5492a648b33cf478c1ddc23ed4598a5fa"}, {file = "jsonschema-4.22.0.tar.gz", hash = "sha256:5b22d434a45935119af990552c862e5d6d564e8f6601206b305a61fdf661a2b7"},
] ]
[package.dependencies] [package.dependencies]
@ -350,13 +340,13 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-
[[package]] [[package]]
name = "jsonschema-specifications" name = "jsonschema-specifications"
version = "2023.11.2" version = "2023.12.1"
description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "jsonschema_specifications-2023.11.2-py3-none-any.whl", hash = "sha256:e74ba7c0a65e8cb49dc26837d6cfe576557084a8b423ed16a420984228104f93"}, {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"},
{file = "jsonschema_specifications-2023.11.2.tar.gz", hash = "sha256:9472fc4fea474cd74bea4a2b190daeccb5a9e4db2ea80efcf7a1b582fc9a81b8"}, {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"},
] ]
[package.dependencies] [package.dependencies]
@ -364,71 +354,71 @@ referencing = ">=0.31.0"
[[package]] [[package]]
name = "markupsafe" name = "markupsafe"
version = "2.1.3" version = "2.1.5"
description = "Safely add untrusted strings to HTML/XML markup." description = "Safely add untrusted strings to HTML/XML markup."
optional = true optional = true
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"},
{file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"},
{file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"},
{file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"},
{file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"},
{file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"},
{file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"},
{file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"},
{file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"},
{file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"},
{file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"},
{file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"},
{file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"},
{file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"},
{file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"},
{file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"},
{file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"},
{file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"},
{file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"},
{file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"},
{file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"},
{file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"},
{file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"},
{file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"},
{file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"},
{file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"},
{file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"},
{file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"},
{file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"},
{file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"},
{file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"},
{file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"},
{file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"},
{file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"},
{file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"},
{file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"},
{file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"},
{file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"},
{file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"},
{file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"},
{file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"},
{file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"},
{file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"},
{file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"},
{file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"},
{file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"},
{file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"},
{file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"},
{file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"},
{file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"},
{file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"},
] ]
[[package]] [[package]]
@ -446,13 +436,13 @@ six = "*"
[[package]] [[package]]
name = "packaging" name = "packaging"
version = "23.2" version = "24.0"
description = "Core utilities for Python packages" description = "Core utilities for Python packages"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"},
{file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"},
] ]
[[package]] [[package]]
@ -468,13 +458,13 @@ files = [
[[package]] [[package]]
name = "pluggy" name = "pluggy"
version = "1.3.0" version = "1.5.0"
description = "plugin and hook calling mechanisms for python" description = "plugin and hook calling mechanisms for python"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"},
{file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"},
] ]
[package.extras] [package.extras]
@ -483,24 +473,24 @@ testing = ["pytest", "pytest-benchmark"]
[[package]] [[package]]
name = "pycparser" name = "pycparser"
version = "2.21" version = "2.22"
description = "C parser in Python" description = "C parser in Python"
optional = true optional = true
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" python-versions = ">=3.8"
files = [ files = [
{file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
{file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
] ]
[[package]] [[package]]
name = "pytest" name = "pytest"
version = "7.4.4" version = "8.2.1"
description = "pytest: simple powerful testing with Python" description = "pytest: simple powerful testing with Python"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.8"
files = [ files = [
{file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, {file = "pytest-8.2.1-py3-none-any.whl", hash = "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1"},
{file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, {file = "pytest-8.2.1.tar.gz", hash = "sha256:5046e5b46d8e4cac199c373041f26be56fdb81eb4e67dc11d4e10811fc3408fd"},
] ]
[package.dependencies] [package.dependencies]
@ -508,21 +498,21 @@ colorama = {version = "*", markers = "sys_platform == \"win32\""}
exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
iniconfig = "*" iniconfig = "*"
packaging = "*" packaging = "*"
pluggy = ">=0.12,<2.0" pluggy = ">=1.5,<2.0"
tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} tomli = {version = ">=1", markers = "python_version < \"3.11\""}
[package.extras] [package.extras]
testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
[[package]] [[package]]
name = "pytest-cov" name = "pytest-cov"
version = "4.1.0" version = "5.0.0"
description = "Pytest plugin for measuring coverage." description = "Pytest plugin for measuring coverage."
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.8"
files = [ files = [
{file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"},
{file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"},
] ]
[package.dependencies] [package.dependencies]
@ -530,21 +520,21 @@ coverage = {version = ">=5.2.1", extras = ["toml"]}
pytest = ">=4.6" pytest = ">=4.6"
[package.extras] [package.extras]
testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"]
[[package]] [[package]]
name = "pytest-mock" name = "pytest-mock"
version = "3.12.0" version = "3.14.0"
description = "Thin-wrapper around the mock package for easier use with pytest" description = "Thin-wrapper around the mock package for easier use with pytest"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "pytest-mock-3.12.0.tar.gz", hash = "sha256:31a40f038c22cad32287bb43932054451ff5583ff094bca6f675df2f8bc1a6e9"}, {file = "pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0"},
{file = "pytest_mock-3.12.0-py3-none-any.whl", hash = "sha256:0972719a7263072da3a21c7f4773069bcc7486027d7e8e1f81d98a47e701bc4f"}, {file = "pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f"},
] ]
[package.dependencies] [package.dependencies]
pytest = ">=5.0" pytest = ">=6.2.5"
[package.extras] [package.extras]
dev = ["pre-commit", "pytest-asyncio", "tox"] dev = ["pre-commit", "pytest-asyncio", "tox"]
@ -585,6 +575,7 @@ files = [
{file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
{file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
{file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"},
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
{file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
{file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
@ -621,13 +612,13 @@ files = [
[[package]] [[package]]
name = "referencing" name = "referencing"
version = "0.32.0" version = "0.35.1"
description = "JSON Referencing + Python" description = "JSON Referencing + Python"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "referencing-0.32.0-py3-none-any.whl", hash = "sha256:bdcd3efb936f82ff86f993093f6da7435c7de69a3b3a5a06678a6050184bee99"}, {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"},
{file = "referencing-0.32.0.tar.gz", hash = "sha256:689e64fe121843dcfd57b71933318ef1f91188ffb45367332700a86ac8fd6161"}, {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"},
] ]
[package.dependencies] [package.dependencies]
@ -636,13 +627,13 @@ rpds-py = ">=0.7.0"
[[package]] [[package]]
name = "resolvelib" name = "resolvelib"
version = "1.0.1" version = "0.8.1"
description = "Resolve abstract dependencies into concrete ones" description = "Resolve abstract dependencies into concrete ones"
optional = true optional = true
python-versions = "*" python-versions = "*"
files = [ files = [
{file = "resolvelib-1.0.1-py2.py3-none-any.whl", hash = "sha256:d2da45d1a8dfee81bdd591647783e340ef3bcb104b54c383f70d422ef5cc7dbf"}, {file = "resolvelib-0.8.1-py2.py3-none-any.whl", hash = "sha256:d9b7907f055c3b3a2cfc56c914ffd940122915826ff5fb5b1de0c99778f4de98"},
{file = "resolvelib-1.0.1.tar.gz", hash = "sha256:04ce76cbd63fded2078ce224785da6ecd42b9564b1390793f64ddecbe997b309"}, {file = "resolvelib-0.8.1.tar.gz", hash = "sha256:c6ea56732e9fb6fca1b2acc2ccc68a0b6b8c566d8f3e78e0443310ede61dbd37"},
] ]
[package.extras] [package.extras]
@ -653,154 +644,138 @@ test = ["commentjson", "packaging", "pytest"]
[[package]] [[package]]
name = "rpds-py" name = "rpds-py"
version = "0.13.2" version = "0.18.1"
description = "Python bindings to Rust's persistent data structures (rpds)" description = "Python bindings to Rust's persistent data structures (rpds)"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "rpds_py-0.13.2-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:1ceebd0ae4f3e9b2b6b553b51971921853ae4eebf3f54086be0565d59291e53d"}, {file = "rpds_py-0.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d31dea506d718693b6b2cffc0648a8929bdc51c70a311b2770f09611caa10d53"},
{file = "rpds_py-0.13.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:46e1ed994a0920f350a4547a38471217eb86f57377e9314fbaaa329b71b7dfe3"}, {file = "rpds_py-0.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:732672fbc449bab754e0b15356c077cc31566df874964d4801ab14f71951ea80"},
{file = "rpds_py-0.13.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee353bb51f648924926ed05e0122b6a0b1ae709396a80eb583449d5d477fcdf7"}, {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a98a1f0552b5f227a3d6422dbd61bc6f30db170939bd87ed14f3c339aa6c7c9"},
{file = "rpds_py-0.13.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:530190eb0cd778363bbb7596612ded0bb9fef662daa98e9d92a0419ab27ae914"}, {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f1944ce16401aad1e3f7d312247b3d5de7981f634dc9dfe90da72b87d37887d"},
{file = "rpds_py-0.13.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29d311e44dd16d2434d5506d57ef4d7036544fc3c25c14b6992ef41f541b10fb"}, {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38e14fb4e370885c4ecd734f093a2225ee52dc384b86fa55fe3f74638b2cfb09"},
{file = "rpds_py-0.13.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2e72f750048b32d39e87fc85c225c50b2a6715034848dbb196bf3348aa761fa1"}, {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08d74b184f9ab6289b87b19fe6a6d1a97fbfea84b8a3e745e87a5de3029bf944"},
{file = "rpds_py-0.13.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db09b98c7540df69d4b47218da3fbd7cb466db0fb932e971c321f1c76f155266"}, {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d70129cef4a8d979caa37e7fe957202e7eee8ea02c5e16455bc9808a59c6b2f0"},
{file = "rpds_py-0.13.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2ac26f50736324beb0282c819668328d53fc38543fa61eeea2c32ea8ea6eab8d"}, {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ce0bb20e3a11bd04461324a6a798af34d503f8d6f1aa3d2aa8901ceaf039176d"},
{file = "rpds_py-0.13.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:12ecf89bd54734c3c2c79898ae2021dca42750c7bcfb67f8fb3315453738ac8f"}, {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81c5196a790032e0fc2464c0b4ab95f8610f96f1f2fa3d4deacce6a79852da60"},
{file = "rpds_py-0.13.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a44c8440183b43167fd1a0819e8356692bf5db1ad14ce140dbd40a1485f2dea"}, {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f3027be483868c99b4985fda802a57a67fdf30c5d9a50338d9db646d590198da"},
{file = "rpds_py-0.13.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bcef4f2d3dc603150421de85c916da19471f24d838c3c62a4f04c1eb511642c1"}, {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d44607f98caa2961bab4fa3c4309724b185b464cdc3ba6f3d7340bac3ec97cc1"},
{file = "rpds_py-0.13.2-cp310-none-win32.whl", hash = "sha256:ee6faebb265e28920a6f23a7d4c362414b3f4bb30607141d718b991669e49ddc"}, {file = "rpds_py-0.18.1-cp310-none-win32.whl", hash = "sha256:c273e795e7a0f1fddd46e1e3cb8be15634c29ae8ff31c196debb620e1edb9333"},
{file = "rpds_py-0.13.2-cp310-none-win_amd64.whl", hash = "sha256:ac96d67b37f28e4b6ecf507c3405f52a40658c0a806dffde624a8fcb0314d5fd"}, {file = "rpds_py-0.18.1-cp310-none-win_amd64.whl", hash = "sha256:8352f48d511de5f973e4f2f9412736d7dea76c69faa6d36bcf885b50c758ab9a"},
{file = "rpds_py-0.13.2-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:b5f6328e8e2ae8238fc767703ab7b95785521c42bb2b8790984e3477d7fa71ad"}, {file = "rpds_py-0.18.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6b5ff7e1d63a8281654b5e2896d7f08799378e594f09cf3674e832ecaf396ce8"},
{file = "rpds_py-0.13.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:729408136ef8d45a28ee9a7411917c9e3459cf266c7e23c2f7d4bb8ef9e0da42"}, {file = "rpds_py-0.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8927638a4d4137a289e41d0fd631551e89fa346d6dbcfc31ad627557d03ceb6d"},
{file = "rpds_py-0.13.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65cfed9c807c27dee76407e8bb29e6f4e391e436774bcc769a037ff25ad8646e"}, {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:154bf5c93d79558b44e5b50cc354aa0459e518e83677791e6adb0b039b7aa6a7"},
{file = "rpds_py-0.13.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aefbdc934115d2f9278f153952003ac52cd2650e7313750390b334518c589568"}, {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07f2139741e5deb2c5154a7b9629bc5aa48c766b643c1a6750d16f865a82c5fc"},
{file = "rpds_py-0.13.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d48db29bd47814671afdd76c7652aefacc25cf96aad6daefa82d738ee87461e2"}, {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c7672e9fba7425f79019db9945b16e308ed8bc89348c23d955c8c0540da0a07"},
{file = "rpds_py-0.13.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3c55d7f2d817183d43220738270efd3ce4e7a7b7cbdaefa6d551ed3d6ed89190"}, {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:489bdfe1abd0406eba6b3bb4fdc87c7fa40f1031de073d0cfb744634cc8fa261"},
{file = "rpds_py-0.13.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6aadae3042f8e6db3376d9e91f194c606c9a45273c170621d46128f35aef7cd0"}, {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c20f05e8e3d4fc76875fc9cb8cf24b90a63f5a1b4c5b9273f0e8225e169b100"},
{file = "rpds_py-0.13.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5feae2f9aa7270e2c071f488fab256d768e88e01b958f123a690f1cc3061a09c"}, {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:967342e045564cef76dfcf1edb700b1e20838d83b1aa02ab313e6a497cf923b8"},
{file = "rpds_py-0.13.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:51967a67ea0d7b9b5cd86036878e2d82c0b6183616961c26d825b8c994d4f2c8"}, {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2cc7c1a47f3a63282ab0f422d90ddac4aa3034e39fc66a559ab93041e6505da7"},
{file = "rpds_py-0.13.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d0c10d803549427f427085ed7aebc39832f6e818a011dcd8785e9c6a1ba9b3e"}, {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f7afbfee1157e0f9376c00bb232e80a60e59ed716e3211a80cb8506550671e6e"},
{file = "rpds_py-0.13.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:603d5868f7419081d616dab7ac3cfa285296735e7350f7b1e4f548f6f953ee7d"}, {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9e6934d70dc50f9f8ea47081ceafdec09245fd9f6032669c3b45705dea096b88"},
{file = "rpds_py-0.13.2-cp311-none-win32.whl", hash = "sha256:b8996ffb60c69f677245f5abdbcc623e9442bcc91ed81b6cd6187129ad1fa3e7"}, {file = "rpds_py-0.18.1-cp311-none-win32.whl", hash = "sha256:c69882964516dc143083d3795cb508e806b09fc3800fd0d4cddc1df6c36e76bb"},
{file = "rpds_py-0.13.2-cp311-none-win_amd64.whl", hash = "sha256:5379e49d7e80dca9811b36894493d1c1ecb4c57de05c36f5d0dd09982af20211"}, {file = "rpds_py-0.18.1-cp311-none-win_amd64.whl", hash = "sha256:70a838f7754483bcdc830444952fd89645569e7452e3226de4a613a4c1793fb2"},
{file = "rpds_py-0.13.2-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:8a776a29b77fe0cc28fedfd87277b0d0f7aa930174b7e504d764e0b43a05f381"}, {file = "rpds_py-0.18.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3dd3cd86e1db5aadd334e011eba4e29d37a104b403e8ca24dcd6703c68ca55b3"},
{file = "rpds_py-0.13.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2a1472956c5bcc49fb0252b965239bffe801acc9394f8b7c1014ae9258e4572b"}, {file = "rpds_py-0.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:05f3d615099bd9b13ecf2fc9cf2d839ad3f20239c678f461c753e93755d629ee"},
{file = "rpds_py-0.13.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f252dfb4852a527987a9156cbcae3022a30f86c9d26f4f17b8c967d7580d65d2"}, {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35b2b771b13eee8729a5049c976197ff58a27a3829c018a04341bcf1ae409b2b"},
{file = "rpds_py-0.13.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f0d320e70b6b2300ff6029e234e79fe44e9dbbfc7b98597ba28e054bd6606a57"}, {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ee17cd26b97d537af8f33635ef38be873073d516fd425e80559f4585a7b90c43"},
{file = "rpds_py-0.13.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ade2ccb937060c299ab0dfb2dea3d2ddf7e098ed63ee3d651ebfc2c8d1e8632a"}, {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b646bf655b135ccf4522ed43d6902af37d3f5dbcf0da66c769a2b3938b9d8184"},
{file = "rpds_py-0.13.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9d121be0217787a7d59a5c6195b0842d3f701007333426e5154bf72346aa658"}, {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19ba472b9606c36716062c023afa2484d1e4220548751bda14f725a7de17b4f6"},
{file = "rpds_py-0.13.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fa6bd071ec6d90f6e7baa66ae25820d57a8ab1b0a3c6d3edf1834d4b26fafa2"}, {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e30ac5e329098903262dc5bdd7e2086e0256aa762cc8b744f9e7bf2a427d3f8"},
{file = "rpds_py-0.13.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c918621ee0a3d1fe61c313f2489464f2ae3d13633e60f520a8002a5e910982ee"}, {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d58ad6317d188c43750cb76e9deacf6051d0f884d87dc6518e0280438648a9ac"},
{file = "rpds_py-0.13.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:25b28b3d33ec0a78e944aaaed7e5e2a94ac811bcd68b557ca48a0c30f87497d2"}, {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e1735502458621921cee039c47318cb90b51d532c2766593be6207eec53e5c4c"},
{file = "rpds_py-0.13.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:31e220a040b89a01505128c2f8a59ee74732f666439a03e65ccbf3824cdddae7"}, {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f5bab211605d91db0e2995a17b5c6ee5edec1270e46223e513eaa20da20076ac"},
{file = "rpds_py-0.13.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:15253fff410873ebf3cfba1cc686a37711efcd9b8cb30ea21bb14a973e393f60"}, {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2fc24a329a717f9e2448f8cd1f960f9dac4e45b6224d60734edeb67499bab03a"},
{file = "rpds_py-0.13.2-cp312-none-win32.whl", hash = "sha256:b981a370f8f41c4024c170b42fbe9e691ae2dbc19d1d99151a69e2c84a0d194d"}, {file = "rpds_py-0.18.1-cp312-none-win32.whl", hash = "sha256:1805d5901779662d599d0e2e4159d8a82c0b05faa86ef9222bf974572286b2b6"},
{file = "rpds_py-0.13.2-cp312-none-win_amd64.whl", hash = "sha256:4c4e314d36d4f31236a545696a480aa04ea170a0b021e9a59ab1ed94d4c3ef27"}, {file = "rpds_py-0.18.1-cp312-none-win_amd64.whl", hash = "sha256:720edcb916df872d80f80a1cc5ea9058300b97721efda8651efcd938a9c70a72"},
{file = "rpds_py-0.13.2-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:80e5acb81cb49fd9f2d5c08f8b74ffff14ee73b10ca88297ab4619e946bcb1e1"}, {file = "rpds_py-0.18.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:c827576e2fa017a081346dce87d532a5310241648eb3700af9a571a6e9fc7e74"},
{file = "rpds_py-0.13.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:efe093acc43e869348f6f2224df7f452eab63a2c60a6c6cd6b50fd35c4e075ba"}, {file = "rpds_py-0.18.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aa3679e751408d75a0b4d8d26d6647b6d9326f5e35c00a7ccd82b78ef64f65f8"},
{file = "rpds_py-0.13.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c2a61c0e4811012b0ba9f6cdcb4437865df5d29eab5d6018ba13cee1c3064a0"}, {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0abeee75434e2ee2d142d650d1e54ac1f8b01e6e6abdde8ffd6eeac6e9c38e20"},
{file = "rpds_py-0.13.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:751758d9dd04d548ec679224cc00e3591f5ebf1ff159ed0d4aba6a0746352452"}, {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed402d6153c5d519a0faf1bb69898e97fb31613b49da27a84a13935ea9164dfc"},
{file = "rpds_py-0.13.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6ba8858933f0c1a979781272a5f65646fca8c18c93c99c6ddb5513ad96fa54b1"}, {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:338dee44b0cef8b70fd2ef54b4e09bb1b97fc6c3a58fea5db6cc083fd9fc2724"},
{file = "rpds_py-0.13.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bfdfbe6a36bc3059fff845d64c42f2644cf875c65f5005db54f90cdfdf1df815"}, {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7750569d9526199c5b97e5a9f8d96a13300950d910cf04a861d96f4273d5b104"},
{file = "rpds_py-0.13.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa0379c1935c44053c98826bc99ac95f3a5355675a297ac9ce0dfad0ce2d50ca"}, {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:607345bd5912aacc0c5a63d45a1f73fef29e697884f7e861094e443187c02be5"},
{file = "rpds_py-0.13.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5593855b5b2b73dd8413c3fdfa5d95b99d657658f947ba2c4318591e745d083"}, {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:207c82978115baa1fd8d706d720b4a4d2b0913df1c78c85ba73fe6c5804505f0"},
{file = "rpds_py-0.13.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2a7bef6977043673750a88da064fd513f89505111014b4e00fbdd13329cd4e9a"}, {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6d1e42d2735d437e7e80bab4d78eb2e459af48c0a46e686ea35f690b93db792d"},
{file = "rpds_py-0.13.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:3ab96754d23372009638a402a1ed12a27711598dd49d8316a22597141962fe66"}, {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:5463c47c08630007dc0fe99fb480ea4f34a89712410592380425a9b4e1611d8e"},
{file = "rpds_py-0.13.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:e06cfea0ece444571d24c18ed465bc93afb8c8d8d74422eb7026662f3d3f779b"}, {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:06d218939e1bf2ca50e6b0ec700ffe755e5216a8230ab3e87c059ebb4ea06afc"},
{file = "rpds_py-0.13.2-cp38-none-win32.whl", hash = "sha256:5493569f861fb7b05af6d048d00d773c6162415ae521b7010197c98810a14cab"}, {file = "rpds_py-0.18.1-cp38-none-win32.whl", hash = "sha256:312fe69b4fe1ffbe76520a7676b1e5ac06ddf7826d764cc10265c3b53f96dbe9"},
{file = "rpds_py-0.13.2-cp38-none-win_amd64.whl", hash = "sha256:b07501b720cf060c5856f7b5626e75b8e353b5f98b9b354a21eb4bfa47e421b1"}, {file = "rpds_py-0.18.1-cp38-none-win_amd64.whl", hash = "sha256:9437ca26784120a279f3137ee080b0e717012c42921eb07861b412340f85bae2"},
{file = "rpds_py-0.13.2-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:881df98f0a8404d32b6de0fd33e91c1b90ed1516a80d4d6dc69d414b8850474c"}, {file = "rpds_py-0.18.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:19e515b78c3fc1039dd7da0a33c28c3154458f947f4dc198d3c72db2b6b5dc93"},
{file = "rpds_py-0.13.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d79c159adea0f1f4617f54aa156568ac69968f9ef4d1e5fefffc0a180830308e"}, {file = "rpds_py-0.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7b28c5b066bca9a4eb4e2f2663012debe680f097979d880657f00e1c30875a0"},
{file = "rpds_py-0.13.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38d4f822ee2f338febcc85aaa2547eb5ba31ba6ff68d10b8ec988929d23bb6b4"}, {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:673fdbbf668dd958eff750e500495ef3f611e2ecc209464f661bc82e9838991e"},
{file = "rpds_py-0.13.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5d75d6d220d55cdced2f32cc22f599475dbe881229aeddba6c79c2e9df35a2b3"}, {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d960de62227635d2e61068f42a6cb6aae91a7fe00fca0e3aeed17667c8a34611"},
{file = "rpds_py-0.13.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d97e9ae94fb96df1ee3cb09ca376c34e8a122f36927230f4c8a97f469994bff"}, {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:352a88dc7892f1da66b6027af06a2e7e5d53fe05924cc2cfc56495b586a10b72"},
{file = "rpds_py-0.13.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67a429520e97621a763cf9b3ba27574779c4e96e49a27ff8a1aa99ee70beb28a"}, {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e0ee01ad8260184db21468a6e1c37afa0529acc12c3a697ee498d3c2c4dcaf3"},
{file = "rpds_py-0.13.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:188435794405c7f0573311747c85a96b63c954a5f2111b1df8018979eca0f2f0"}, {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4c39ad2f512b4041343ea3c7894339e4ca7839ac38ca83d68a832fc8b3748ab"},
{file = "rpds_py-0.13.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:38f9bf2ad754b4a45b8210a6c732fe876b8a14e14d5992a8c4b7c1ef78740f53"}, {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aaa71ee43a703c321906813bb252f69524f02aa05bf4eec85f0c41d5d62d0f4c"},
{file = "rpds_py-0.13.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a6ba2cb7d676e9415b9e9ac7e2aae401dc1b1e666943d1f7bc66223d3d73467b"}, {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6cd8098517c64a85e790657e7b1e509b9fe07487fd358e19431cb120f7d96338"},
{file = "rpds_py-0.13.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:eaffbd8814bb1b5dc3ea156a4c5928081ba50419f9175f4fc95269e040eff8f0"}, {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:4adec039b8e2928983f885c53b7cc4cda8965b62b6596501a0308d2703f8af1b"},
{file = "rpds_py-0.13.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5a4c1058cdae6237d97af272b326e5f78ee7ee3bbffa6b24b09db4d828810468"}, {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:32b7daaa3e9389db3695964ce8e566e3413b0c43e3394c05e4b243a4cd7bef26"},
{file = "rpds_py-0.13.2-cp39-none-win32.whl", hash = "sha256:b5267feb19070bef34b8dea27e2b504ebd9d31748e3ecacb3a4101da6fcb255c"}, {file = "rpds_py-0.18.1-cp39-none-win32.whl", hash = "sha256:2625f03b105328729f9450c8badda34d5243231eef6535f80064d57035738360"},
{file = "rpds_py-0.13.2-cp39-none-win_amd64.whl", hash = "sha256:ddf23960cb42b69bce13045d5bc66f18c7d53774c66c13f24cf1b9c144ba3141"}, {file = "rpds_py-0.18.1-cp39-none-win_amd64.whl", hash = "sha256:bf18932d0003c8c4d51a39f244231986ab23ee057d235a12b2684ea26a353590"},
{file = "rpds_py-0.13.2-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:97163a1ab265a1073a6372eca9f4eeb9f8c6327457a0b22ddfc4a17dcd613e74"}, {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cbfbea39ba64f5e53ae2915de36f130588bba71245b418060ec3330ebf85678e"},
{file = "rpds_py-0.13.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:25ea41635d22b2eb6326f58e608550e55d01df51b8a580ea7e75396bafbb28e9"}, {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a3d456ff2a6a4d2adcdf3c1c960a36f4fd2fec6e3b4902a42a384d17cf4e7a65"},
{file = "rpds_py-0.13.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d59d4d451ba77f08cb4cd9268dec07be5bc65f73666302dbb5061989b17198"}, {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7700936ef9d006b7ef605dc53aa364da2de5a3aa65516a1f3ce73bf82ecfc7ae"},
{file = "rpds_py-0.13.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7c564c58cf8f248fe859a4f0fe501b050663f3d7fbc342172f259124fb59933"}, {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:51584acc5916212e1bf45edd17f3a6b05fe0cbb40482d25e619f824dccb679de"},
{file = "rpds_py-0.13.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:61dbc1e01dc0c5875da2f7ae36d6e918dc1b8d2ce04e871793976594aad8a57a"}, {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:942695a206a58d2575033ff1e42b12b2aece98d6003c6bc739fbf33d1773b12f"},
{file = "rpds_py-0.13.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fdb82eb60d31b0c033a8e8ee9f3fc7dfbaa042211131c29da29aea8531b4f18f"}, {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b906b5f58892813e5ba5c6056d6a5ad08f358ba49f046d910ad992196ea61397"},
{file = "rpds_py-0.13.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d204957169f0b3511fb95395a9da7d4490fb361763a9f8b32b345a7fe119cb45"}, {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6f8e3fecca256fefc91bb6765a693d96692459d7d4c644660a9fff32e517843"},
{file = "rpds_py-0.13.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c45008ca79bad237cbc03c72bc5205e8c6f66403773929b1b50f7d84ef9e4d07"}, {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7732770412bab81c5a9f6d20aeb60ae943a9b36dcd990d876a773526468e7163"},
{file = "rpds_py-0.13.2-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:79bf58c08f0756adba691d480b5a20e4ad23f33e1ae121584cf3a21717c36dfa"}, {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:bd1105b50ede37461c1d51b9698c4f4be6e13e69a908ab7751e3807985fc0346"},
{file = "rpds_py-0.13.2-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:e86593bf8637659e6a6ed58854b6c87ec4e9e45ee8a4adfd936831cef55c2d21"}, {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:618916f5535784960f3ecf8111581f4ad31d347c3de66d02e728de460a46303c"},
{file = "rpds_py-0.13.2-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:d329896c40d9e1e5c7715c98529e4a188a1f2df51212fd65102b32465612b5dc"}, {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:17c6d2155e2423f7e79e3bb18151c686d40db42d8645e7977442170c360194d4"},
{file = "rpds_py-0.13.2-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:4a5375c5fff13f209527cd886dc75394f040c7d1ecad0a2cb0627f13ebe78a12"}, {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6c4c4c3f878df21faf5fac86eda32671c27889e13570645a9eea0a1abdd50922"},
{file = "rpds_py-0.13.2-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:06d218e4464d31301e943b65b2c6919318ea6f69703a351961e1baaf60347276"}, {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:fab6ce90574645a0d6c58890e9bcaac8d94dff54fb51c69e5522a7358b80ab64"},
{file = "rpds_py-0.13.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1f41d32a2ddc5a94df4b829b395916a4b7f103350fa76ba6de625fcb9e773ac"}, {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:531796fb842b53f2695e94dc338929e9f9dbf473b64710c28af5a160b2a8927d"},
{file = "rpds_py-0.13.2-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6bc568b05e02cd612be53900c88aaa55012e744930ba2eeb56279db4c6676eb3"}, {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:740884bc62a5e2bbb31e584f5d23b32320fd75d79f916f15a788d527a5e83644"},
{file = "rpds_py-0.13.2-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d94d78418203904730585efa71002286ac4c8ac0689d0eb61e3c465f9e608ff"}, {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:998125738de0158f088aef3cb264a34251908dd2e5d9966774fdab7402edfab7"},
{file = "rpds_py-0.13.2-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bed0252c85e21cf73d2d033643c945b460d6a02fc4a7d644e3b2d6f5f2956c64"}, {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e2be6e9dd4111d5b31ba3b74d17da54a8319d8168890fbaea4b9e5c3de630ae5"},
{file = "rpds_py-0.13.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:244e173bb6d8f3b2f0c4d7370a1aa341f35da3e57ffd1798e5b2917b91731fd3"}, {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0cee71bc618cd93716f3c1bf56653740d2d13ddbd47673efa8bf41435a60daa"},
{file = "rpds_py-0.13.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7f55cd9cf1564b7b03f238e4c017ca4794c05b01a783e9291065cb2858d86ce4"}, {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2c3caec4ec5cd1d18e5dd6ae5194d24ed12785212a90b37f5f7f06b8bedd7139"},
{file = "rpds_py-0.13.2-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:f03a1b3a4c03e3e0161642ac5367f08479ab29972ea0ffcd4fa18f729cd2be0a"}, {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:27bba383e8c5231cd559affe169ca0b96ec78d39909ffd817f28b166d7ddd4d8"},
{file = "rpds_py-0.13.2-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:f5f4424cb87a20b016bfdc157ff48757b89d2cc426256961643d443c6c277007"}, {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:a888e8bdb45916234b99da2d859566f1e8a1d2275a801bb8e4a9644e3c7e7909"},
{file = "rpds_py-0.13.2-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:c82bbf7e03748417c3a88c1b0b291288ce3e4887a795a3addaa7a1cfd9e7153e"}, {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6031b25fb1b06327b43d841f33842b383beba399884f8228a6bb3df3088485ff"},
{file = "rpds_py-0.13.2-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:c0095b8aa3e432e32d372e9a7737e65b58d5ed23b9620fea7cb81f17672f1fa1"}, {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48c2faaa8adfacefcbfdb5f2e2e7bdad081e5ace8d182e5f4ade971f128e6bb3"},
{file = "rpds_py-0.13.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:4c2d26aa03d877c9730bf005621c92da263523a1e99247590abbbe252ccb7824"}, {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:d85164315bd68c0806768dc6bb0429c6f95c354f87485ee3593c4f6b14def2bd"},
{file = "rpds_py-0.13.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96f2975fb14f39c5fe75203f33dd3010fe37d1c4e33177feef1107b5ced750e3"}, {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6afd80f6c79893cfc0574956f78a0add8c76e3696f2d6a15bca2c66c415cf2d4"},
{file = "rpds_py-0.13.2-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4dcc5ee1d0275cb78d443fdebd0241e58772a354a6d518b1d7af1580bbd2c4e8"}, {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa242ac1ff583e4ec7771141606aafc92b361cd90a05c30d93e343a0c2d82a89"},
{file = "rpds_py-0.13.2-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:61d42d2b08430854485135504f672c14d4fc644dd243a9c17e7c4e0faf5ed07e"}, {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21be4770ff4e08698e1e8e0bce06edb6ea0626e7c8f560bc08222880aca6a6f"},
{file = "rpds_py-0.13.2-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d3a61e928feddc458a55110f42f626a2a20bea942ccedb6fb4cee70b4830ed41"}, {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c45a639e93a0c5d4b788b2613bd637468edd62f8f95ebc6fcc303d58ab3f0a8"},
{file = "rpds_py-0.13.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7de12b69d95072394998c622cfd7e8cea8f560db5fca6a62a148f902a1029f8b"}, {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910e71711d1055b2768181efa0a17537b2622afeb0424116619817007f8a2b10"},
{file = "rpds_py-0.13.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:87a90f5545fd61f6964e65eebde4dc3fa8660bb7d87adb01d4cf17e0a2b484ad"}, {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b9bb1f182a97880f6078283b3505a707057c42bf55d8fca604f70dedfdc0772a"},
{file = "rpds_py-0.13.2-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:9c95a1a290f9acf7a8f2ebbdd183e99215d491beea52d61aa2a7a7d2c618ddc6"}, {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1d54f74f40b1f7aaa595a02ff42ef38ca654b1469bef7d52867da474243cc633"},
{file = "rpds_py-0.13.2-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:35f53c76a712e323c779ca39b9a81b13f219a8e3bc15f106ed1e1462d56fcfe9"}, {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:8d2e182c9ee01135e11e9676e9a62dfad791a7a467738f06726872374a83db49"},
{file = "rpds_py-0.13.2-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:96fb0899bb2ab353f42e5374c8f0789f54e0a94ef2f02b9ac7149c56622eaf31"}, {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:636a15acc588f70fda1661234761f9ed9ad79ebed3f2125d44be0862708b666e"},
{file = "rpds_py-0.13.2.tar.gz", hash = "sha256:f8eae66a1304de7368932b42d801c67969fd090ddb1a7a24f27b435ed4bed68f"}, {file = "rpds_py-0.18.1.tar.gz", hash = "sha256:dc48b479d540770c811fbd1eb9ba2bb66951863e448efec2e2c102625328e92f"},
] ]
[[package]] [[package]]
name = "ruff" name = "ruff"
version = "0.1.11" version = "0.4.5"
description = "An extremely fast Python linter and code formatter, written in Rust." description = "An extremely fast Python linter and code formatter, written in Rust."
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "ruff-0.1.11-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:a7f772696b4cdc0a3b2e527fc3c7ccc41cdcb98f5c80fdd4f2b8c50eb1458196"}, {file = "ruff-0.4.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:8f58e615dec58b1a6b291769b559e12fdffb53cc4187160a2fc83250eaf54e96"},
{file = "ruff-0.1.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:934832f6ed9b34a7d5feea58972635c2039c7a3b434fe5ba2ce015064cb6e955"}, {file = "ruff-0.4.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:84dd157474e16e3a82745d2afa1016c17d27cb5d52b12e3d45d418bcc6d49264"},
{file = "ruff-0.1.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea0d3e950e394c4b332bcdd112aa566010a9f9c95814844a7468325290aabfd9"}, {file = "ruff-0.4.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25f483ad9d50b00e7fd577f6d0305aa18494c6af139bce7319c68a17180087f4"},
{file = "ruff-0.1.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9bd4025b9c5b429a48280785a2b71d479798a69f5c2919e7d274c5f4b32c3607"}, {file = "ruff-0.4.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:63fde3bf6f3ad4e990357af1d30e8ba2730860a954ea9282c95fc0846f5f64af"},
{file = "ruff-0.1.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1ad00662305dcb1e987f5ec214d31f7d6a062cae3e74c1cbccef15afd96611d"}, {file = "ruff-0.4.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78e3ba4620dee27f76bbcad97067766026c918ba0f2d035c2fc25cbdd04d9c97"},
{file = "ruff-0.1.11-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4b077ce83f47dd6bea1991af08b140e8b8339f0ba8cb9b7a484c30ebab18a23f"}, {file = "ruff-0.4.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:441dab55c568e38d02bbda68a926a3d0b54f5510095c9de7f95e47a39e0168aa"},
{file = "ruff-0.1.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4a88efecec23c37b11076fe676e15c6cdb1271a38f2b415e381e87fe4517f18"}, {file = "ruff-0.4.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1169e47e9c4136c997f08f9857ae889d614c5035d87d38fda9b44b4338909cdf"},
{file = "ruff-0.1.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b25093dad3b055667730a9b491129c42d45e11cdb7043b702e97125bcec48a1"}, {file = "ruff-0.4.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:755ac9ac2598a941512fc36a9070a13c88d72ff874a9781493eb237ab02d75df"},
{file = "ruff-0.1.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:231d8fb11b2cc7c0366a326a66dafc6ad449d7fcdbc268497ee47e1334f66f77"}, {file = "ruff-0.4.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4b02a65985be2b34b170025a8b92449088ce61e33e69956ce4d316c0fe7cce0"},
{file = "ruff-0.1.11-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:09c415716884950080921dd6237767e52e227e397e2008e2bed410117679975b"}, {file = "ruff-0.4.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:75a426506a183d9201e7e5664de3f6b414ad3850d7625764106f7b6d0486f0a1"},
{file = "ruff-0.1.11-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0f58948c6d212a6b8d41cd59e349751018797ce1727f961c2fa755ad6208ba45"}, {file = "ruff-0.4.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:6e1b139b45e2911419044237d90b60e472f57285950e1492c757dfc88259bb06"},
{file = "ruff-0.1.11-py3-none-musllinux_1_2_i686.whl", hash = "sha256:190a566c8f766c37074d99640cd9ca3da11d8deae2deae7c9505e68a4a30f740"}, {file = "ruff-0.4.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a6f29a8221d2e3d85ff0c7b4371c0e37b39c87732c969b4d90f3dad2e721c5b1"},
{file = "ruff-0.1.11-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:6464289bd67b2344d2a5d9158d5eb81025258f169e69a46b741b396ffb0cda95"}, {file = "ruff-0.4.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:d6ef817124d72b54cc923f3444828ba24fa45c3164bc9e8f1813db2f3d3a8a11"},
{file = "ruff-0.1.11-py3-none-win32.whl", hash = "sha256:9b8f397902f92bc2e70fb6bebfa2139008dc72ae5177e66c383fa5426cb0bf2c"}, {file = "ruff-0.4.5-py3-none-win32.whl", hash = "sha256:aed8166c18b1a169a5d3ec28a49b43340949e400665555b51ee06f22813ef062"},
{file = "ruff-0.1.11-py3-none-win_amd64.whl", hash = "sha256:eb85ee287b11f901037a6683b2374bb0ec82928c5cbc984f575d0437979c521a"}, {file = "ruff-0.4.5-py3-none-win_amd64.whl", hash = "sha256:b0b03c619d2b4350b4a27e34fd2ac64d0dabe1afbf43de57d0f9d8a05ecffa45"},
{file = "ruff-0.1.11-py3-none-win_arm64.whl", hash = "sha256:97ce4d752f964ba559c7023a86e5f8e97f026d511e48013987623915431c7ea9"}, {file = "ruff-0.4.5-py3-none-win_arm64.whl", hash = "sha256:9d15de3425f53161b3f5a5658d4522e4eee5ea002bf2ac7aa380743dd9ad5fba"},
{file = "ruff-0.1.11.tar.gz", hash = "sha256:f9d4d88cb6eeb4dfe20f9f0519bd2eaba8119bde87c3d5065c541dbae2b5a2cb"}, {file = "ruff-0.4.5.tar.gz", hash = "sha256:286eabd47e7d4d521d199cab84deca135557e6d1e0f0d01c29e757c3cb151b54"},
] ]
[[package]]
name = "setuptools"
version = "69.0.2"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
optional = false
python-versions = ">=3.8"
files = [
{file = "setuptools-69.0.2-py3-none-any.whl", hash = "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"},
{file = "setuptools-69.0.2.tar.gz", hash = "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6"},
]
[package.extras]
docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
[[package]] [[package]]
name = "six" name = "six"
version = "1.16.0" version = "1.16.0"
@ -836,13 +811,13 @@ files = [
[[package]] [[package]]
name = "toolz" name = "toolz"
version = "0.12.0" version = "0.12.1"
description = "List processing tools and functional utilities" description = "List processing tools and functional utilities"
optional = false optional = false
python-versions = ">=3.5" python-versions = ">=3.7"
files = [ files = [
{file = "toolz-0.12.0-py3-none-any.whl", hash = "sha256:2059bd4148deb1884bb0eb770a3cde70e7f954cfbbdc2285f1f2de01fd21eb6f"}, {file = "toolz-0.12.1-py3-none-any.whl", hash = "sha256:d22731364c07d72eea0a0ad45bafb2c2937ab6fd38a3507bf55eae8744aa7d85"},
{file = "toolz-0.12.0.tar.gz", hash = "sha256:88c570861c440ee3f2f6037c4654613228ff40c93a6c25e0eba70d17282c6194"}, {file = "toolz-0.12.1.tar.gz", hash = "sha256:ecca342664893f177a13dac0e6b41cbd8ac25a358e5f215316d43e2100224f4d"},
] ]
[[package]] [[package]]
@ -858,13 +833,13 @@ files = [
[[package]] [[package]]
name = "yamllint" name = "yamllint"
version = "1.33.0" version = "1.35.1"
description = "A linter for YAML files." description = "A linter for YAML files."
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "yamllint-1.33.0-py3-none-any.whl", hash = "sha256:28a19f5d68d28d8fec538a1db21bb2d84c7dc2e2ea36266da8d4d1c5a683814d"}, {file = "yamllint-1.35.1-py3-none-any.whl", hash = "sha256:2e16e504bb129ff515b37823b472750b36b6de07963bd74b307341ef5ad8bdc3"},
{file = "yamllint-1.33.0.tar.gz", hash = "sha256:2dceab9ef2d99518a2fcf4ffc964d44250ac4459be1ba3ca315118e4a1a81f7d"}, {file = "yamllint-1.35.1.tar.gz", hash = "sha256:7a003809f88324fd2c877734f2d575ee7881dd9043360657cc8049c809eba6cd"},
] ]
[package.dependencies] [package.dependencies]
@ -881,4 +856,4 @@ ansible-core = ["ansible-core"]
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.9.0" python-versions = "^3.9.0"
content-hash = "06f1f0e7c07d7c65ec8e16fc5e9ad5f155a56e7af064ae9729f473666f2d84f6" content-hash = "b31c0bc892767d8bc020eb18b5002f857475601d5fff6b253728b26c42626134"

View File

@ -20,34 +20,30 @@ classifiers = [
description = "Reviews ansible playbooks, roles and inventories and suggests improvements." description = "Reviews ansible playbooks, roles and inventories and suggests improvements."
documentation = "https://ansible-later.geekdocs.de/" documentation = "https://ansible-later.geekdocs.de/"
homepage = "https://ansible-later.geekdocs.de/" homepage = "https://ansible-later.geekdocs.de/"
include = [ include = ["LICENSE"]
"LICENSE",
]
keywords = ["ansible", "code", "review"] keywords = ["ansible", "code", "review"]
license = "MIT" license = "MIT"
name = "ansible-later" name = "ansible-later"
packages = [ packages = [{ include = "ansiblelater" }]
{include = "ansiblelater"},
]
readme = "README.md" readme = "README.md"
repository = "https://github.com/thegeeklab/ansible-later/" repository = "https://github.com/thegeeklab/ansible-later/"
version = "0.0.0" version = "0.0.0"
[tool.poetry.dependencies] [tool.poetry.dependencies]
PyYAML = "6.0.1" PyYAML = "6.0.1"
ansible = {version = "8.7.0", optional = true} ansible-core = { version = "2.14.17", optional = true }
ansible-core = {version = "2.15.8", optional = true} ansible = { version = "7.7.0", optional = true }
anyconfig = "0.13.0" anyconfig = "0.14.0"
appdirs = "1.4.4" appdirs = "1.4.4"
colorama = "0.4.6" colorama = "0.4.6"
jsonschema = "4.20.0" jsonschema = "4.22.0"
nested-lookup = "0.2.25" nested-lookup = "0.2.25"
pathspec = "0.12.1" pathspec = "0.12.1"
python = "^3.9.0" python = "^3.9.0"
python-json-logger = "2.0.7" python-json-logger = "2.0.7"
toolz = "0.12.0" toolz = "0.12.1"
unidiff = "0.7.5" unidiff = "0.7.5"
yamllint = "1.33.0" yamllint = "1.35.1"
[tool.poetry.extras] [tool.poetry.extras]
ansible = ["ansible"] ansible = ["ansible"]
@ -57,10 +53,10 @@ ansible-core = ["ansible-core"]
ansible-later = "ansiblelater.__main__:main" ansible-later = "ansiblelater.__main__:main"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
ruff = "0.1.11" ruff = "0.4.5"
pytest = "7.4.4" pytest = "8.2.1"
pytest-mock = "3.12.0" pytest-mock = "3.14.0"
pytest-cov = "4.1.0" pytest-cov = "5.0.0"
toml = "0.10.2" toml = "0.10.2"
[tool.poetry-dynamic-versioning] [tool.poetry-dynamic-versioning]
@ -85,21 +81,22 @@ requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning"]
[tool.ruff] [tool.ruff]
exclude = [ exclude = [
".git", ".git",
"__pycache__", "__pycache__",
"build", "build",
"dist", "dist",
"test", "test",
"*.pyc", "*.pyc",
"*.egg-info", "*.egg-info",
".cache", ".cache",
".eggs", ".eggs",
"env*", "env*",
] ]
line-length = 99 line-length = 99
indent-width = 4 indent-width = 4
[tool.ruff.lint]
# Explanation of errors # Explanation of errors
# #
# D100: Missing docstring in public module # D100: Missing docstring in public module
@ -112,38 +109,38 @@ indent-width = 4
# D203: One blank line required before class docstring # D203: One blank line required before class docstring
# D212: Multi-line docstring summary should start at the first line # D212: Multi-line docstring summary should start at the first line
ignore = [ ignore = [
"D100", "D100",
"D101", "D101",
"D102", "D102",
"D103", "D103",
"D105", "D105",
"D107", "D107",
"D202", "D202",
"D203", "D203",
"D212", "D212",
"UP038", "UP038",
"RUF012", "RUF012",
] ]
select = [ select = [
"D", "D",
"E", "E",
"F", "F",
"Q", "Q",
"W", "W",
"I", "I",
"S", "S",
"BLE", "BLE",
"N", "N",
"UP", "UP",
"B", "B",
"A", "A",
"C4", "C4",
"T20", "T20",
"SIM", "SIM",
"RET", "RET",
"ARG", "ARG",
"ERA", "ERA",
"RUF", "RUF",
] ]
[tool.ruff.format] [tool.ruff.format]