From dcf04af78477e91f3ac438c642bad1b935d7c1c9 Mon Sep 17 00:00:00 2001 From: Robert Kaussow Date: Tue, 31 Jan 2023 20:09:29 +0100 Subject: [PATCH] refactor: rework ci and testing (#3) --- .drone.jsonnet | 93 +- .drone.yml | 132 +- .gitignore | 1 + dev-requirements.txt | 18 - plugins/filter/prefix.py | 6 +- plugins/filter/wrap.py | 6 +- plugins/inventory/proxmox.py | 222 ++-- plugins/modules/iptables_raw.py | 39 +- plugins/modules/openssl_pkcs12.py | 251 ++-- plugins/modules/proxmox_kvm.py | 459 ++++--- plugins/modules/ucr.py | 96 +- poetry.lock | 1143 +++++++++++++++++ pyproject.toml | 149 +++ requirements.txt | 4 - setup.cfg | 42 - test/unit/plugins/inventory/__init__.py | 1 - test/unit/requirements.txt | 11 - tests/config.yml | 2 + tests/unit/plugins/inventory/__init__.py | 0 .../unit/plugins/inventory/test_proxmox.py | 5 +- 20 files changed, 2089 insertions(+), 591 deletions(-) delete mode 100644 dev-requirements.txt create mode 100644 poetry.lock create mode 100644 pyproject.toml delete mode 100644 requirements.txt delete mode 100644 setup.cfg delete mode 100644 test/unit/plugins/inventory/__init__.py delete mode 100644 test/unit/requirements.txt create mode 100644 tests/config.yml create mode 100644 tests/unit/plugins/inventory/__init__.py rename {test => tests}/unit/plugins/inventory/test_proxmox.py (95%) diff --git a/.drone.jsonnet b/.drone.jsonnet index 782cbcd..6826f80 100644 --- a/.drone.jsonnet +++ b/.drone.jsonnet @@ -5,9 +5,30 @@ local PythonVersion(pyversion='3.8') = { PY_COLORS: 1, }, commands: [ - 'pip install -r dev-requirements.txt -qq', - 'pip install -r test/unit/requirements.txt -qq', - 'python -m pytest --cov --cov-append --no-cov-on-fail', + 'pip install poetry -qq', + 'poetry config experimental.new-installer false', + 'poetry install --all-extras', + 'poetry run pytest', + ], + depends_on: [ + 'clone', + ], +}; + +local AnsibleVersion(version='devel') = { + local gitversion = if version == 'devel' then 'devel' else 'stable-' + version, + name: 'ansible-' + std.strReplace(version, '.', ''), + image: 'python:3.9', + environment: { + PY_COLORS: 1, + }, + commands: [ + 'pip install poetry -qq', + 'poetry config experimental.new-installer false', + 'poetry install', + 'poetry run pip install https://github.com/ansible/ansible/archive/' + gitversion + '.tar.gz --disable-pip-version-check', + 'poetry run ansible --version', + 'poetry run ansible-test sanity --exclude .chglog/ --exclude .drone.yml --python 3.9', ], depends_on: [ 'clone', @@ -23,14 +44,31 @@ local PipelineLint = { }, steps: [ { - name: 'flake8', - image: 'python:3.10', + name: 'check-format', + image: 'python:3.11', + environment: { + PY_COLORS: 1, + }, + commands: [ + 'git fetch -tq', + 'pip install poetry -qq', + 'poetry config experimental.new-installer false', + 'poetry install --all-extras', + 'poetry run yapf -dr ./plugins', + ], + }, + { + name: 'check-coding', + image: 'python:3.11', environment: { PY_COLORS: 1, }, commands: [ - 'pip install -r dev-requirements.txt -qq', - 'flake8', + 'git fetch -tq', + 'pip install poetry -qq', + 'poetry config experimental.new-installer false', + 'poetry install --all-extras', + 'poetry run ruff ./plugins', ], }, ], @@ -39,9 +77,9 @@ local PipelineLint = { }, }; -local PipelineTest = { +local PipelineUnitTest = { kind: 'pipeline', - name: 'test', + name: 'unit-test', platform: { os: 'linux', arch: 'amd64', @@ -50,6 +88,7 @@ local PipelineTest = { PythonVersion(pyversion='3.8'), PythonVersion(pyversion='3.9'), PythonVersion(pyversion='3.10'), + PythonVersion(pyversion='3.11'), ], depends_on: [ 'lint', @@ -59,6 +98,29 @@ local PipelineTest = { }, }; +local PipelineSanityTest = { + kind: 'pipeline', + name: 'sanity-test', + platform: { + os: 'linux', + arch: 'amd64', + }, + workspace: { + path: '/drone/src/ansible_collections/${DRONE_REPO_NAME/./\\/}', + }, + steps: [ + AnsibleVersion(version='devel'), + AnsibleVersion(version='2.14'), + AnsibleVersion(version='2.13'), + ], + depends_on: [ + 'unit-test', + ], + trigger: { + ref: ['refs/heads/main', 'refs/tags/**', 'refs/pull/**'], + }, +}; + local PipelineBuild = { kind: 'pipeline', name: 'build', @@ -69,12 +131,14 @@ local PipelineBuild = { steps: [ { name: 'build', - image: 'python:3.9', + image: 'python:3.11', commands: [ 'GALAXY_VERSION=${DRONE_TAG##v}', "sed -i 's/version: 0.0.0/version: '\"$${GALAXY_VERSION:-0.0.0}\"'/g' galaxy.yml", - 'pip install ansible -qq', - 'ansible-galaxy collection build --output-path dist/', + 'pip install poetry -qq', + 'poetry config experimental.new-installer false', + 'poetry install --all-extras', + 'poetry run ansible-galaxy collection build --output-path dist/', ], }, { @@ -117,7 +181,7 @@ local PipelineBuild = { }, ], depends_on: [ - 'test', + 'sanity-test', ], trigger: { ref: ['refs/heads/main', 'refs/tags/**', 'refs/pull/**'], @@ -188,7 +252,8 @@ local PipelineNotifications = { [ PipelineLint, - PipelineTest, + PipelineUnitTest, + PipelineSanityTest, PipelineBuild, PipelineDocumentation, PipelineNotifications, diff --git a/.drone.yml b/.drone.yml index c36777b..027b3b1 100644 --- a/.drone.yml +++ b/.drone.yml @@ -7,11 +7,25 @@ platform: arch: amd64 steps: - - name: flake8 - image: python:3.10 + - name: check-format + image: python:3.11 commands: - - pip install -r dev-requirements.txt -qq - - flake8 + - git fetch -tq + - pip install poetry -qq + - poetry config experimental.new-installer false + - poetry install --all-extras + - poetry run yapf -dr ./plugins + environment: + PY_COLORS: 1 + + - name: check-coding + image: python:3.11 + commands: + - git fetch -tq + - pip install poetry -qq + - poetry config experimental.new-installer false + - poetry install --all-extras + - poetry run ruff ./plugins environment: PY_COLORS: 1 @@ -23,7 +37,7 @@ trigger: --- kind: pipeline -name: test +name: unit-test platform: os: linux @@ -33,9 +47,10 @@ steps: - name: python38-pytest image: python:3.8 commands: - - pip install -r dev-requirements.txt -qq - - pip install -r test/unit/requirements.txt -qq - - python -m pytest --cov --cov-append --no-cov-on-fail + - pip install poetry -qq + - poetry config experimental.new-installer false + - poetry install --all-extras + - poetry run pytest environment: PY_COLORS: 1 depends_on: @@ -44,9 +59,10 @@ steps: - name: python39-pytest image: python:3.9 commands: - - pip install -r dev-requirements.txt -qq - - pip install -r test/unit/requirements.txt -qq - - python -m pytest --cov --cov-append --no-cov-on-fail + - pip install poetry -qq + - poetry config experimental.new-installer false + - poetry install --all-extras + - poetry run pytest environment: PY_COLORS: 1 depends_on: @@ -55,9 +71,22 @@ steps: - name: python310-pytest image: python:3.10 commands: - - pip install -r dev-requirements.txt -qq - - pip install -r test/unit/requirements.txt -qq - - python -m pytest --cov --cov-append --no-cov-on-fail + - pip install poetry -qq + - poetry config experimental.new-installer false + - poetry install --all-extras + - poetry run pytest + environment: + PY_COLORS: 1 + depends_on: + - clone + + - name: python311-pytest + image: python:3.11 + commands: + - pip install poetry -qq + - poetry config experimental.new-installer false + - poetry install --all-extras + - poetry run pytest environment: PY_COLORS: 1 depends_on: @@ -72,6 +101,69 @@ trigger: depends_on: - lint +--- +kind: pipeline +name: sanity-test + +platform: + os: linux + arch: amd64 + +workspace: + path: /drone/src/ansible_collections/${DRONE_REPO_NAME/./\/} + +steps: + - name: ansible-devel + image: python:3.9 + commands: + - pip install poetry -qq + - poetry config experimental.new-installer false + - poetry install + - poetry run pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check + - poetry run ansible --version + - poetry run ansible-test sanity --exclude .chglog/ --exclude .drone.yml --python 3.9 + environment: + PY_COLORS: 1 + depends_on: + - clone + + - name: ansible-214 + image: python:3.9 + commands: + - pip install poetry -qq + - poetry config experimental.new-installer false + - poetry install + - poetry run pip install https://github.com/ansible/ansible/archive/stable-2.14.tar.gz --disable-pip-version-check + - poetry run ansible --version + - poetry run ansible-test sanity --exclude .chglog/ --exclude .drone.yml --python 3.9 + environment: + PY_COLORS: 1 + depends_on: + - clone + + - name: ansible-213 + image: python:3.9 + commands: + - pip install poetry -qq + - poetry config experimental.new-installer false + - poetry install + - poetry run pip install https://github.com/ansible/ansible/archive/stable-2.13.tar.gz --disable-pip-version-check + - poetry run ansible --version + - poetry run ansible-test sanity --exclude .chglog/ --exclude .drone.yml --python 3.9 + environment: + PY_COLORS: 1 + depends_on: + - clone + +trigger: + ref: + - refs/heads/main + - refs/tags/** + - refs/pull/** + +depends_on: + - unit-test + --- kind: pipeline name: build @@ -82,12 +174,14 @@ platform: steps: - name: build - image: python:3.9 + image: python:3.11 commands: - GALAXY_VERSION=${DRONE_TAG##v} - "sed -i 's/version: 0.0.0/version: '\"$${GALAXY_VERSION:-0.0.0}\"'/g' galaxy.yml" - - pip install ansible -qq - - ansible-galaxy collection build --output-path dist/ + - pip install poetry -qq + - poetry config experimental.new-installer false + - poetry install --all-extras + - poetry run ansible-galaxy collection build --output-path dist/ - name: checksum image: alpine @@ -129,7 +223,7 @@ trigger: - refs/pull/** depends_on: - - test + - sanity-test --- kind: pipeline @@ -195,6 +289,6 @@ depends_on: --- kind: signature -hmac: 93f735c3d2fbaf499fd96b79301f6de2455349051dc320c511e6e62c8ba04a4d +hmac: 407d145ab4483651c579eea4e1e9375536caee1aa0579abcdf57b5653e595cb5 ... diff --git a/.gitignore b/.gitignore index 3d8498e..8824083 100644 --- a/.gitignore +++ b/.gitignore @@ -108,3 +108,4 @@ docs/public/ resources/_gen/ CHANGELOG.md +tests/output diff --git a/dev-requirements.txt b/dev-requirements.txt deleted file mode 100644 index fbfddb4..0000000 --- a/dev-requirements.txt +++ /dev/null @@ -1,18 +0,0 @@ -pydocstyle -flake8 -flake8-blind-except -flake8-builtins -flake8-docstrings -flake8-isort -flake8-logging-format -flake8-polyfill -flake8-quotes -flake8-pep3101 -flake8-eradicate -pep8-naming -wheel -pytest -pytest-mock -pytest-cov -bandit -yapf diff --git a/plugins/filter/prefix.py b/plugins/filter/prefix.py index 3db8213..8974ea3 100644 --- a/plugins/filter/prefix.py +++ b/plugins/filter/prefix.py @@ -1,11 +1,15 @@ """Filter to prefix all itams from a list.""" +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + def prefix(value, prefix="--"): return [prefix + x for x in value] -class FilterModule(object): +class FilterModule(object): # noqa def filters(self): return {"prefix": prefix} diff --git a/plugins/filter/wrap.py b/plugins/filter/wrap.py index ffe03e4..a9f0db2 100644 --- a/plugins/filter/wrap.py +++ b/plugins/filter/wrap.py @@ -1,11 +1,15 @@ """Filter to wrap all items from a list.""" +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + def wrap(value, wrapper="'"): return [wrapper + x + wrapper for x in value] -class FilterModule(object): +class FilterModule(object): # noqa def filters(self): return {"wrap": wrap} diff --git a/plugins/inventory/proxmox.py b/plugins/inventory/proxmox.py index 9e4217c..fcd2b71 100644 --- a/plugins/inventory/proxmox.py +++ b/plugins/inventory/proxmox.py @@ -1,95 +1,102 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2014, Mathieu GAUTHIER-LAFAYE # Copyright (c) 2016, Matt Harris # Copyright (c) 2020, Robert Kaussow # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) """Dynamic inventory plugin for Proxmox VE.""" -from __future__ import absolute_import, division, print_function +from __future__ import (absolute_import, division, print_function) __metaclass__ = type DOCUMENTATION = """ - name: proxmox - plugin_type: inventory - short_description: Proxmox VE inventory source - version_added: 1.0.0 +--- +name: proxmox +short_description: Proxmox VE inventory source +version_added: 1.1.0 +description: + - Get inventory hosts from the proxmox service. + - "Uses a configuration file as an inventory source, it must end in C(.proxmox.yml) or C(.proxmox.yaml) and has a C(plugin: xoxys.general.proxmox) entry." +extends_documentation_fragment: + - inventory_cache +options: + plugin: + description: The name of this plugin, it should always be set to C(xoxys.general.proxmox) for this plugin to recognize it as it's own. + required: yes + choices: ["xoxys.general.proxmox"] + api_host: description: - - Get inventory hosts from the proxmox service. - - "Uses a configuration file as an inventory source, it must end in C(.proxmox.yml) or C(.proxmox.yaml) and has a C(plugin: xoxys.general.proxmox) entry." - extends_documentation_fragment: - - inventory_cache - options: - plugin: - description: The name of this plugin, it should always be set to C(xoxys.general.proxmox) for this plugin to recognize it as it's own. - required: yes - choices: ["xoxys.general.proxmox"] - server: - description: Proxmox VE server url. - default: "pve.example.com" - type: string - required: yes - env: - - name: PROXMOX_SERVER - user: - description: Proxmox VE authentication user. - type: string - required: yes - env: - - name: PROXMOX_USER - password: - description: Proxmox VE authentication password. - type: string - required: yes - env: - - name: PROXMOX_PASSWORD - verify_ssl: - description: Skip SSL certificate verification. - type: boolean - default: yes - auth_timeout: - description: Proxmox VE authentication timeout. - type: int - default: 5 - exclude_vmid: - description: VMID's to exclude from inventory. - type: list - default: [] - elements: str - exclude_state: - description: VM states to exclude from inventory. - type: list - default: [] - elements: str - group: - description: Group to place all hosts into. - type: string - default: proxmox - want_facts: - description: Toggle, if C(true) the plugin will retrieve host facts from the server - type: boolean - default: yes -""" # noqa + - Specify the target host of the Proxmox VE cluster. + type: str + required: true + api_user: + description: + - Specify the user to authenticate with. + type: str + required: true + api_password: + description: + - Specify the password to authenticate with. + - You can use C(PROXMOX_PASSWORD) environment variable. + type: str + api_token_id: + description: + - Specify the token ID. + type: str + api_token_secret: + description: + - Specify the token secret. + type: str + verify_ssl: + description: + - If C(false), SSL certificates will not be validated. + - This should only be used on personally controlled sites using self-signed certificates. + type: bool + default: True + auth_timeout: + description: Proxmox VE authentication timeout. + type: int + default: 5 + exclude_vmid: + description: VMID's to exclude from inventory. + type: list + default: [] + elements: str + exclude_state: + description: VM states to exclude from inventory. + type: list + default: [] + elements: str + group: + description: Group to place all hosts into. + type: string + default: proxmox + want_facts: + description: Toggle, if C(true) the plugin will retrieve host facts from the server + type: boolean + default: True +requirements: + - "proxmoxer" +""" # noqa EXAMPLES = """ # proxmox.yml plugin: xoxys.general.proxmox -server: pve.example.com -user: admin@pve -password: secure +api_user: root@pam +api_password: secret +api_host: helldorado """ import json import re import socket +from collections import defaultdict +from distutils.version import LooseVersion from ansible.errors import AnsibleError from ansible.module_utils._text import to_native from ansible.module_utils.parsing.convert_bool import boolean from ansible.module_utils.six import iteritems from ansible.plugins.inventory import BaseInventoryPlugin -from collections import defaultdict -from distutils.version import LooseVersion try: from proxmoxer import ProxmoxAPI @@ -97,17 +104,39 @@ try: except ImportError: HAS_PROXMOXER = False +try: + from requests.packages import urllib3 + HAS_URLLIB3 = True +except ImportError: + try: + import urllib3 + HAS_URLLIB3 = True + except ImportError: + HAS_URLLIB3 = False + class InventoryModule(BaseInventoryPlugin): + """Provide Proxmox VE inventory.""" + NAME = "xoxys.general.proxmox" def _auth(self): + auth_args = {"user": self.get_option("api_user")} + if not (self.get_option("api_token_id") and self.get_option("api_token_secret")): + auth_args["password"] = self.get_option("api_password") + else: + auth_args["token_name"] = self.get_option("api_token_id") + auth_args["token_value"] = self.get_option("api_token_secret") + + verify_ssl = boolean(self.get_option("verify_ssl"), strict=False) + if not verify_ssl and HAS_URLLIB3: + urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + return ProxmoxAPI( - self.get_option("server"), - user=self.get_option("user"), - password=self.get_option("password"), - verify_ssl=boolean(self.get_option("password"), strict=False), - timeout=self.get_option("auth_timeout") + self.get_option("api_host"), + verify_ssl=verify_ssl, + timeout=self.get_option("auth_timeout"), + **auth_args ) def _get_version(self): @@ -117,14 +146,12 @@ class InventoryModule(BaseInventoryPlugin): return LooseVersion(self.client.version.get()["release"]) def _get_names(self, pve_list, pve_type): - names = [] - if pve_type == "node": - names = [node["node"] for node in pve_list] - elif pve_type == "pool": - names = [pool["poolid"] for pool in pve_list] + return [node["node"] for node in pve_list] + if pve_type == "pool": + return [pool["poolid"] for pool in pve_list] - return names + return [] def _get_variables(self, pve_list, pve_type): variables = {} @@ -143,11 +170,9 @@ class InventoryModule(BaseInventoryPlugin): def validate(address): try: # IP address validation - if socket.inet_aton(address): - # Ignore localhost - if address != "127.0.0.1": - return address - except socket.error: + if socket.inet_aton(address) and address != "127.0.0.1": + return address + except OSError: return False address = False @@ -159,19 +184,18 @@ class InventoryModule(BaseInventoryPlugin): networks = self.client.nodes(pve_node).get( "qemu", vmid, "agent", "network-get-interfaces" )["result"] - except Exception: + except Exception: # noqa pass - if networks: - if type(networks) is list: - for network in networks: - for ip_address in network["ip-addresses"]: - address = validate(ip_address["ip-address"]) + if networks and isinstance(networks, list): + for network in networks: + for ip_address in network["ip-addresses"]: + address = validate(ip_address["ip-address"]) else: try: config = self.client.nodes(pve_node).get(pve_type, vmid, "config") address = re.search(r"ip=(\d*\.\d*\.\d*\.\d*)", config["net0"]).group(1) - except Exception: + except Exception: # noqa pass return address @@ -197,8 +221,8 @@ class InventoryModule(BaseInventoryPlugin): try: qemu_list = self._exclude(self.client.nodes(node).qemu.get()) container_list = self._exclude(self.client.nodes(node).lxc.get()) - except Exception as e: - raise AnsibleError("Proxmoxer API error: {0}".format(to_native(e))) + except Exception as e: # noqa + raise AnsibleError(f"Proxmoxer API error: {to_native(e)}") from e # Merge QEMU and Containers lists from this node instances = self._get_variables(qemu_list, "qemu").copy() @@ -217,8 +241,8 @@ class InventoryModule(BaseInventoryPlugin): "config")["description"] except KeyError: description = None - except Exception as e: - raise AnsibleError("Proxmoxer API error: {0}".format(to_native(e))) + except Exception as e: # noqa + raise AnsibleError(f"Proxmoxer API error: {to_native(e)}") from e try: metadata = json.loads(description) @@ -252,8 +276,8 @@ class InventoryModule(BaseInventoryPlugin): for pool in self._get_names(self.client.pools.get(), "pool"): try: pool_list = self._exclude(self.client.pool(pool).get()["members"]) - except Exception as e: - raise AnsibleError("Proxmoxer API error: {0}".format(to_native(e))) + except Exception as e: # noqa + raise AnsibleError(f"Proxmoxer API error: {to_native(e)}") from e members = [ member["name"] @@ -266,13 +290,13 @@ class InventoryModule(BaseInventoryPlugin): def verify_file(self, path): """Verify the Proxmox VE configuration file.""" - if super(InventoryModule, self).verify_file(path): + if super().verify_file(path): endings = ("proxmox.yaml", "proxmox.yml") - if any((path.endswith(ending) for ending in endings)): + if any(path.endswith(ending) for ending in endings): return True return False - def parse(self, inventory, loader, path, cache=True): + def parse(self, inventory, loader, path, cache=True): # noqa """Dynamically parse the Proxmox VE cloud inventory.""" if not HAS_PROXMOXER: raise AnsibleError( @@ -280,7 +304,7 @@ class InventoryModule(BaseInventoryPlugin): "https://pypi.org/project/proxmoxer/" ) - super(InventoryModule, self).parse(inventory, loader, path) + super().parse(inventory, loader, path) self._read_config_data(path) self.client = self._auth() diff --git a/plugins/modules/iptables_raw.py b/plugins/modules/iptables_raw.py index d62238f..5f0b160 100644 --- a/plugins/modules/iptables_raw.py +++ b/plugins/modules/iptables_raw.py @@ -1,3 +1,4 @@ +#!/usr/bin/python # -*- coding: utf-8 -*- """ IPtables raw module. @@ -18,16 +19,20 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with Ansible. If not, see . +along with Ansible. If not, see . """ +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + ANSIBLE_METADATA = {'status': ['preview'], 'supported_by': 'community', 'metadata_version': '1.0'} DOCUMENTATION = r''' --- module: iptables_raw short_description: Manage iptables rules -version_added: "2.4" +version_added: 1.1.0 description: - Add/remove iptables rules while keeping state. options: @@ -35,13 +40,14 @@ options: description: - Create a backup of the iptables state file before overwriting it. required: false - choices: ["yes", "no"] - default: "no" + type: bool + default: False ipversion: description: - Target the IP version this rule is for. required: false default: "4" + type: str choices: ["4", "6"] keep_unmanaged: description: @@ -54,8 +60,8 @@ options: first time, since if you don't specify correct rules, you can block yourself out of the managed host." required: false - choices: ["yes", "no"] - default: "yes" + type: bool + default: True name: description: - Name that will be used as an identifier for these rules. It can contain @@ -64,17 +70,21 @@ options: C(state=absent) to flush all rules in the selected table, or even all tables with C(table=*). required: true + type: str rules: description: - The rules that we want to add. Accepts multiline values. - "Note: You can only use C(-A)/C(--append), C(-N)/C(--new-chain), and C(-P)/C(--policy) to specify rules." required: false + type: str + default: "" state: description: - The state this rules fragment should be in. choices: ["present", "absent"] required: false + type: str default: present table: description: @@ -82,12 +92,13 @@ options: with C(name=*) and C(state=absent) to flush all rules in all tables. choices: ["filter", "nat", "mangle", "raw", "security", "*"] required: false + type: str default: filter weight: description: - Determines the order of the rules. Lower C(weight) means higher priority. Supported range is C(0 - 99) - choices: ["0 - 99"] + type: int required: false default: 40 notes: @@ -116,7 +127,7 @@ EXAMPLES = ''' - iptables_raw: name: default_rules weight: 10 - keep_unmanaged: no + keep_unmanaged: false rules: | -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT -A INPUT -i lo -j ACCEPT @@ -156,12 +167,12 @@ RETURN = ''' state: description: state of the rules returned: success - type: string + type: str sample: present name: description: name of the rules returned: success - type: string + type: str sample: open_tcp_80 weight: description: weight of the rules @@ -176,22 +187,22 @@ ipversion: rules: description: passed rules returned: success - type: string + type: str sample: "-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT" table: description: iptables table used returned: success - type: string + type: str sample: filter backup: description: if the iptables file should backed up returned: success - type: boolean + type: bool sample: False keep_unmanaged: description: if it should keep unmanaged rules returned: success - type: boolean + type: bool sample: True ''' diff --git a/plugins/modules/openssl_pkcs12.py b/plugins/modules/openssl_pkcs12.py index 454182b..7ee2b4e 100644 --- a/plugins/modules/openssl_pkcs12.py +++ b/plugins/modules/openssl_pkcs12.py @@ -1,89 +1,109 @@ +#!/usr/bin/python # -*- coding: utf-8 -*- + +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) """OpenSSL PKCS12 module.""" +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + ANSIBLE_METADATA = {"metadata_version": "1.0", "status": ["preview"], "supported_by": "community"} DOCUMENTATION = """ --- module: openssl_pkcs12 author: "Guillaume Delpierre (@gdelpierre)" -version_added: "2.4" +version_added: 1.1.0 short_description: Generate OpenSSL pkcs12 archive. description: - - "This module allows one to (re-)generate PKCS#12." + - "This module allows one to (re-)generate PKCS#12." requirements: - - "python-pyOpenSSL" + - "python-pyOpenSSL" +extends_documentation_fragment: files options: - ca_certificates: - required: False - description: - - List of CA certificate to include. - cert_path: - required: False - description: - - The path to read certificates and private keys from. - Must be in PEM format. - action: - required: False - default: "export" - choices: ["parse", "export"] - description: - - Create (export) or parse a PKCS#12. - src: - required: False - description: - - PKCS#12 file path to parse. - path: - required: True - default: null - description: - - Filename to write the PKCS#12 file to. - force: - required: False - default: False - description: - - Should the file be regenerated even it it already exists. - friendly_name: - required: False - default: null - aliases: "name" - description: - - Specifies the friendly name for the certificate and private key. - iter_size: - required: False - default: 2048 - description: - - Number of times to repeat the encryption step. - maciter_size: - required: False - default: 1 - description: - - Number of times to repeat the MAC step. - mode: - required: False - default: 0400 - description: - - Default mode for the generated PKCS#12 file. - passphrase: - required: False - default: null - description: - - The PKCS#12 password. - privatekey_path: - required: False - description: - - File to read private key from. - privatekey_passphrase: - required: False - default: null - description: - - Passphrase source to decrypt any input private keys with. - state: - required: False - default: "present" - choices: ["present", "absent"] - description: - - Whether the file should exist or not. + ca_certificates: + required: False + type: list + elements: str + description: + - List of CA certificate to include. + cert_path: + required: False + type: path + description: + - The path to read certificates and private keys from. + Must be in PEM format. + action: + required: False + default: "export" + choices: ["parse", "export"] + type: str + description: + - Create (export) or parse a PKCS#12. + src: + required: False + type: path + description: + - PKCS#12 file path to parse. + path: + required: True + type: path + description: + - Filename to write the PKCS#12 file to. + force: + required: False + default: False + type: bool + description: + - Should the file be regenerated even it it already exists. + friendly_name: + required: False + type: str + aliases: + - "name" + description: + - Specifies the friendly name for the certificate and private key. + iter_size: + required: False + default: 2048 + type: int + description: + - Number of times to repeat the encryption step. + maciter_size: + required: False + default: 1 + type: int + description: + - Number of times to repeat the MAC step. + mode: + required: False + default: "0400" + type: str + description: + - Default mode for the generated PKCS#12 file. + passphrase: + required: False + type: str + description: + - The PKCS#12 password. + privatekey_path: + required: False + type: path + description: + - File to read private key from. + privatekey_passphrase: + required: False + type: str + description: + - Passphrase source to decrypt any input private keys with. + state: + required: False + default: "present" + choices: ["present", "absent"] + type: str + description: + - Whether the file should exist or not. """ EXAMPLES = """ @@ -131,10 +151,10 @@ EXAMPLES = """ RETURN = """ filename: - description: Path to the generate PKCS#12 file. - returned: changed or success - type: string - sample: /opt/certs/ansible.p12 + description: Path to the generate PKCS#12 file. + returned: changed or success + type: str + sample: /opt/certs/ansible.p12 """ import errno @@ -151,11 +171,11 @@ else: pyopenssl_found = True -class PkcsError(Exception): +class PkcsError(Exception): # noqa pass -class Pkcs(object): +class Pkcs(object): # noqa def __init__(self, module): self.path = module.params["path"] @@ -181,36 +201,37 @@ class Pkcs(object): def load_privatekey(self, path, passphrase=None): """Load the specified OpenSSL private key.""" try: - if passphrase: - privatekey = crypto.load_privatekey( - crypto.FILETYPE_PEM, - open(path, "rb").read(), passphrase - ) - else: - privatekey = crypto.load_privatekey(crypto.FILETYPE_PEM, open(path, "rb").read()) + privatekey = crypto.load_privatekey( + crypto.FILETYPE_PEM, + open(path, "rb").read(), # noqa + passphrase + ) if passphrase else crypto.load_privatekey( + crypto.FILETYPE_PEM, + open(path, "rb").read() # noqa + ) return privatekey - except (IOError, OSError) as exc: - raise PkcsError(exc) + except OSError as exc: + raise PkcsError(exc) from exc def load_certificate(self, path): """Load the specified certificate.""" try: - cert_content = open(path, "rb").read() + cert_content = open(path, "rb").read() # noqa cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert_content) return cert - except (IOError, OSError) as exc: - raise PkcsError(exc) + except OSError as exc: + raise PkcsError(exc) from exc def load_pkcs12(self, path, passphrase=None): """Load pkcs12 file.""" try: if passphrase: - return crypto.load_pkcs12(open(path, "rb").read(), passphrase) - else: - return crypto.load_pkcs12(open(path, "rb").read()) - except (IOError, OSError) as exc: - raise PkcsError(exc) + return crypto.load_pkcs12(open(path, "rb").read(), passphrase) # noqa + + return crypto.load_pkcs12(open(path, "rb").read()) # noqa + except OSError as exc: + raise PkcsError(exc) from exc def dump_privatekey(self, path): """Dump the specified OpenSSL private key.""" @@ -219,8 +240,8 @@ class Pkcs(object): crypto.FILETYPE_PEM, self.load_pkcs12(path).get_privatekey() ) - except (IOError, OSError) as exc: - raise PkcsError(exc) + except OSError as exc: + raise PkcsError(exc) from exc def dump_certificate(self, path): """Dump the specified certificate.""" @@ -229,8 +250,8 @@ class Pkcs(object): crypto.FILETYPE_PEM, self.load_pkcs12(path).get_certificate() ) - except (IOError, OSError) as exc: - raise PkcsError(exc) + except OSError as exc: + raise PkcsError(exc) from exc def generate(self, module): """Generate PKCS#12 file archive.""" @@ -264,9 +285,9 @@ class Pkcs(object): ) module.set_mode_if_different(self.path, self.mode, False) self.changed = True - except (IOError, OSError) as exc: + except OSError as exc: self.remove() - raise PkcsError(exc) + raise PkcsError(exc) from exc file_args = module.load_file_common_arguments(module.params) if module.set_fs_attributes_if_different(file_args, False): @@ -281,14 +302,12 @@ class Pkcs(object): with open(self.path, "wb") as content: content.write( - "{0}{1}".format( - self.dump_privatekey(self.src), self.dump_certificate(self.src) - ) + f"{self.dump_privatekey(self.src)}{self.dump_certificate(self.src)}" ) module.set_mode_if_different(self.path, self.mode, False) self.changed = True - except IOError as exc: - raise PkcsError(exc) + except OSError as exc: + raise PkcsError(exc) from exc file_args = module.load_file_common_arguments(module.params) if module.set_fs_attributes_if_different(file_args, False): @@ -302,11 +321,11 @@ class Pkcs(object): self.changed = True except OSError as exc: if exc.errno != errno.ENOENT: - raise PkcsError(exc) - else: - pass + raise PkcsError(exc) from exc + + pass - def check(self, module, perms_required=True): + def check(self, module, perms_required=True): # noqa def _check_pkey_passphrase(): if self.privatekey_passphrase: @@ -337,19 +356,20 @@ class Pkcs(object): def main(): argument_spec = dict( - action=dict(default="export", choices=["parse", "export"], type="str"), - ca_certificates=dict(type="list"), + action=dict(default="export", choices=["parse", "export"], type="str", required=False), + ca_certificates=dict(type="list", elements="str", required=False), cert_path=dict(type="path"), force=dict(default=False, type="bool"), friendly_name=dict(type="str", aliases=["name"]), iter_size=dict(default=2048, type="int"), maciter_size=dict(default=1, type="int"), passphrase=dict(type="str", no_log=True), - path=dict(required=True, type="path"), + path=dict(type="path", required=True), privatekey_path=dict(type="path"), privatekey_passphrase=dict(type="str", no_log=True), state=dict(default="present", choices=["present", "absent"], type="str"), src=dict(type="path"), + mode=dict(default="0400", type="str", required=False) ) required_if = [ @@ -376,8 +396,7 @@ def main(): if not os.path.isdir(base_dir): module.fail_json( name=base_dir, - msg="The directory {0} does not exist or " - "the file is not a directory".format(base_dir) + msg=f"The directory {base_dir} does not exist or the file is not a directory" ) pkcs12 = Pkcs(module) diff --git a/plugins/modules/proxmox_kvm.py b/plugins/modules/proxmox_kvm.py index 767a19c..e7cb082 100644 --- a/plugins/modules/proxmox_kvm.py +++ b/plugins/modules/proxmox_kvm.py @@ -1,20 +1,69 @@ +#!/usr/bin/python # -*- coding: utf-8 -*- + # Copyright: (c) 2016, Abdoul Bah (@helldorado) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -"""Module to control Proxmox KVM machines.""" +"""Control Proxmox KVM machines.""" -from __future__ import absolute_import, division, print_function +from __future__ import (absolute_import, division, print_function) __metaclass__ = type -DOCUMENTATION = """ +DOCUMENTATION = r""" --- module: proxmox_kvm short_description: Management of Qemu(KVM) Virtual Machines in Proxmox VE cluster. description: - Allows you to create/delete/stop Qemu(KVM) Virtual Machines in Proxmox VE cluster. author: "Abdoul Bah (@helldorado) " +version_added: 1.1.0 options: + vmid: + description: + - Specifies the instance ID. + - If not set the next available ID will be fetched from ProxmoxAPI. + type: int + node: + description: + - Proxmox VE node on which to operate. + - Only required for I(state=present). + - For every other states it will be autodiscovered. + type: str + pool: + description: + - Add the new VM to the specified pool. + type: str + api_host: + description: + - Specify the target host of the Proxmox VE cluster. + type: str + required: true + api_user: + description: + - Specify the user to authenticate with. + type: str + required: true + api_password: + description: + - Specify the password to authenticate with. + - You can use C(PROXMOX_PASSWORD) environment variable. + type: str + api_token_id: + description: + - Specify the token ID. + type: str + version_added: 1.3.0 + api_token_secret: + description: + - Specify the token secret. + type: str + version_added: 1.3.0 + verify_ssl: + description: + - If C(false), SSL certificates will not be validated. + - This should only be used on personally controlled sites using self-signed certificates. + type: bool + default: True acpi: description: - Specify if ACPI should be enabled/disabled. @@ -49,7 +98,7 @@ options: description: - Specify the BIOS implementation. type: str - choices: ['seabios', 'ovmf'] + choices: ["seabios", "ovmf"] boot: description: - Specify the boot order -> boot on floppy C(a), hard disk C(c), CD-ROM C(d), or network C(n). @@ -63,27 +112,23 @@ options: type: str cicustom: description: - - 'cloud-init: Specify custom files to replace the automatically generated ones at start.' + - "cloud-init: Specify custom files to replace the automatically generated ones at start." type: str - version_added: 1.3.0 cipassword: description: - - 'cloud-init: password of default user to create.' + - "cloud-init: password of default user to create." type: str - version_added: 1.3.0 citype: description: - - 'cloud-init: Specifies the cloud-init configuration format.' + - "cloud-init: Specifies the cloud-init configuration format." - The default depends on the configured operating system type (C(ostype)). - We use the C(nocloud) format for Linux, and C(configdrive2) for Windows. type: str - choices: ['nocloud', 'configdrive2'] - version_added: 1.3.0 + choices: ["nocloud", "configdrive2"] ciuser: description: - - 'cloud-init: username of default user to create.' + - "cloud-init: username of default user to create." type: str - version_added: 1.3.0 clone: description: - Name of VM to be cloned. If C(vmid) is setted, C(clone) can take arbitrary value but required for initiating the clone. @@ -142,7 +187,8 @@ options: option has a default of C(qcow2). If I(proxmox_default_behavior) is set to C(no_defaults), not specifying this option is equivalent to setting it to C(unspecified). type: str - choices: [ "cloop", "cow", "qcow", "qcow2", "qed", "raw", "vmdk", "unspecified" ] + choices: + ["cloop", "cow", "qcow", "qcow2", "qed", "raw", "vmdk", "unspecified"] freeze: description: - Specify if PVE should freeze CPU at startup (use 'c' monitor command to start execution). @@ -153,7 +199,7 @@ options: - For VM templates, we try to create a linked clone by default. - Used only with clone type: bool - default: 'yes' + default: "yes" hostpci: description: - Specify a hash/dictionary of map host pci devices into guest. C(hostpci='{"key":"value", "key":"value"}'). @@ -175,7 +221,7 @@ options: description: - Enable/disable hugepages memory. type: str - choices: ['any', '2', '1024'] + choices: ["any", "2", "1024"] ide: description: - A hash/dictionary of volume used as IDE hard disk or CD-ROM. C(ide='{"key":"value", "key":"value"}'). @@ -187,17 +233,16 @@ options: type: dict ipconfig: description: - - 'cloud-init: Set the IP configuration.' + - "cloud-init: Set the IP configuration." - A hash/dictionary of network ip configurations. C(ipconfig='{"key":"value", "key":"value"}'). - Keys allowed are - C(ipconfig[n]) where 0 ≤ n ≤ network interfaces. - Values allowed are - C("[gw=] [,gw6=] [,ip=] [,ip6=]"). - - 'cloud-init: Specify IP addresses and gateways for the corresponding interface.' + - "cloud-init: Specify IP addresses and gateways for the corresponding interface." - IP addresses use CIDR notation, gateways are optional but they should be in the same subnet of specified IP address. - The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided. - For IPv6 the special string 'auto' can be used to use stateless autoconfiguration. - If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4. type: dict - version_added: 1.3.0 keyboard: description: - Sets the keyboard layout for VNC server. @@ -217,7 +262,7 @@ options: description: - Lock/unlock the VM. type: str - choices: ['migrate', 'backup', 'snapshot', 'rollback'] + choices: ["migrate", "backup", "snapshot", "rollback"] machine: description: - Specifies the Qemu machine type. @@ -245,11 +290,10 @@ options: type: str nameservers: description: - - 'cloud-init: DNS server IP address(es).' + - "cloud-init: DNS server IP address(es)." - If unset, PVE host settings are used. type: list elements: str - version_added: 1.3.0 net: description: - A hash/dictionary of network interfaces for the VM. C(net='{"key":"value", "key":"value"}'). @@ -293,7 +337,21 @@ options: - If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this option has a default of C(l26). type: str - choices: ['other', 'wxp', 'w2k', 'w2k3', 'w2k8', 'wvista', 'win7', 'win8', 'win10', 'l24', 'l26', 'solaris'] + choices: + [ + "other", + "wxp", + "w2k", + "w2k3", + "w2k8", + "wvista", + "win7", + "win8", + "win10", + "l24", + "l26", + "solaris", + ] parallel: description: - A hash/dictionary of map host parallel devices. C(parallel='{"key":"value", "key":"value"}'). @@ -334,14 +392,21 @@ options: description: - Specifies the SCSI controller model. type: str - choices: ['lsi', 'lsi53c810', 'virtio-scsi-pci', 'virtio-scsi-single', 'megasas', 'pvscsi'] + choices: + [ + "lsi", + "lsi53c810", + "virtio-scsi-pci", + "virtio-scsi-single", + "megasas", + "pvscsi", + ] searchdomains: description: - - 'cloud-init: Sets DNS search domain(s).' + - "cloud-init: Sets DNS search domain(s)." - If unset, PVE host settings are used. type: list elements: str - version_added: 1.3.0 serial: description: - A hash/dictionary of serial device to create inside the VM. C('{"key":"value", "key":"value"}'). @@ -377,9 +442,8 @@ options: type: int sshkeys: description: - - 'cloud-init: SSH key to assign to the default user. NOT TESTED with multiple keys but a multi-line value should work.' + - "cloud-init: SSH key to assign to the default user. NOT TESTED with multiple keys but a multi-line value should work." type: str - version_added: 1.3.0 startdate: description: - Sets the initial date of the real time clock. @@ -396,7 +460,7 @@ options: - Indicates desired state of the instance. - If C(current), the current state of the VM will be fetched. You can access it with C(results.status) type: str - choices: ['present', 'started', 'absent', 'stopped', 'restarted','current'] + choices: ["present", "started", "absent", "stopped", "restarted", "current"] default: present storage: description: @@ -415,7 +479,6 @@ options: - Tags are only available in Proxmox 6+. type: list elements: str - version_added: 2.3.0 target: description: - Target node. Only allowed if the original VM is on shared storage. @@ -441,7 +504,7 @@ options: - If C(yes), the VM will be updated with new value. - Update of C(pool) is disabled. It needs an additional API endpoint not covered by this module. type: bool - default: 'no' + default: "no" vcpus: description: - Sets number of hotplugged vcpus. @@ -452,7 +515,20 @@ options: - If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this option has a default of C(std). type: str - choices: ['std', 'cirrus', 'vmware', 'qxl', 'serial0', 'serial1', 'serial2', 'serial3', 'qxl2', 'qxl3', 'qxl4'] + choices: + [ + "std", + "cirrus", + "vmware", + "qxl", + "serial0", + "serial1", + "serial2", + "serial3", + "qxl2", + "qxl3", + "qxl4", + ] virtio: description: - A hash/dictionary of volume used as VIRTIO hard disk. C(virtio='{"key":"value", "key":"value"}'). @@ -477,10 +553,6 @@ options: choices: - compatibility - no_defaults - version_added: "1.3.0" -extends_documentation_fragment: - - xoxys.general.proxmox.documentation - - xoxys.general.proxmox.selection """ # noqa EXAMPLES = """ @@ -509,8 +581,8 @@ EXAMPLES = """ name: spynal node: sabrewulf net: - net0: 'virtio,bridge=vmbr1,rate=200' - net1: 'e1000,bridge=vmbr2' + net0: "virtio,bridge=vmbr1,rate=200" + net1: "e1000,bridge=vmbr2" - name: Create new VM with one network interface, three virto hard disk, 4 cores, and 2 vcpus xoxys.general.proxmox_kvm: @@ -520,11 +592,11 @@ EXAMPLES = """ name: spynal node: sabrewulf net: - net0: 'virtio,bridge=vmbr1,rate=200' + net0: "virtio,bridge=vmbr1,rate=200" virtio: - virtio0: 'VMs_LVM:10' - virtio1: 'VMs:2,format=qcow2' - virtio2: 'VMs:5,format=raw' + virtio0: "VMs_LVM:10" + virtio1: "VMs:2,format=qcow2" + virtio2: "VMs:5,format=raw" cores: 4 vcpus: 2 @@ -599,15 +671,15 @@ EXAMPLES = """ api_host: helldorado name: spynal ide: - ide2: 'local:cloudinit,format=qcow2' + ide2: "local:cloudinit,format=qcow2" ciuser: mylinuxuser cipassword: supersecret - searchdomains: 'mydomain.internal' + searchdomains: "mydomain.internal" nameservers: 1.1.1.1 net: - net0: 'virtio,bridge=vmbr1,tag=77' + net0: "virtio,bridge=vmbr1,tag=77" ipconfig: - ipconfig0: 'ip=192.168.1.1/24,gw=192.168.1.1' + ipconfig0: "ip=192.168.1.1/24,gw=192.168.1.1" - name: Create new VM using Cloud-Init with an ssh key xoxys.general.proxmox_kvm: @@ -617,16 +689,16 @@ EXAMPLES = """ api_host: helldorado name: spynal ide: - ide2: 'local:cloudinit,format=qcow2' - sshkeys: 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILJkVm98B71lD5XHfihwcYHE9TVpsJmK1vR1JcaU82L+' - searchdomains: 'mydomain.internal' + ide2: "local:cloudinit,format=qcow2" + sshkeys: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILJkVm98B71lD5XHfihwcYHE9TVpsJmK1vR1JcaU82L+" + searchdomains: "mydomain.internal" nameservers: - - '1.1.1.1' - - '8.8.8.8' + - "1.1.1.1" + - "8.8.8.8" net: - net0: 'virtio,bridge=vmbr1,tag=77' + net0: "virtio,bridge=vmbr1,tag=77" ipconfig: - ipconfig0: 'ip=192.168.1.1/24' + ipconfig0: "ip=192.168.1.1/24" - name: Start VM xoxys.general.proxmox_kvm: @@ -701,7 +773,7 @@ EXAMPLES = """ api_host: helldorado name: spynal node: sabrewulf - delete: 'args,template,cpulimit' + delete: "args,template,cpulimit" - name: Revert a pending change xoxys.general.proxmox_kvm: @@ -710,8 +782,9 @@ EXAMPLES = """ api_host: helldorado name: spynal node: sabrewulf - revert: 'template,cpulimit' -""" # noqa + revert: "template,cpulimit" + +""" RETURN = """ vmid: @@ -735,9 +808,10 @@ import re import string import time import traceback +from collections import defaultdict from distutils.version import LooseVersion + from ansible.module_utils.six.moves.urllib.parse import quote -from collections import defaultdict try: from proxmoxer import ProxmoxAPI @@ -745,17 +819,27 @@ try: except ImportError: HAS_PROXMOXER = False -from ansible.module_utils.basic import AnsibleModule, env_fallback +try: + from requests.packages import urllib3 + HAS_URLLIB3 = True +except ImportError: + try: + import urllib3 + HAS_URLLIB3 = True + except ImportError: + HAS_URLLIB3 = False + from ansible.module_utils._text import to_native +from ansible.module_utils.basic import AnsibleModule, env_fallback def get_nextvmid(module, proxmox): try: vmid = proxmox.cluster.nextid.get() return vmid - except Exception as e: + except Exception as e: # noqa module.fail_json( - msg="Unable to get next vmid. Failed with exception: {}".format(to_native(e)), + msg=f"Unable to get next vmid. Failed with exception: {to_native(e)}", exception=traceback.format_exc() ) @@ -775,14 +859,13 @@ def node_check(proxmox, node): def get_vminfo(module, proxmox, node, vmid, **kwargs): - global results # noqa + global results results = {} try: vm = proxmox.nodes(node).qemu(vmid).config.get() - except Exception as e: + except Exception as e: # noqa module.fail_json( - msg="Getting information for VM with vmid = {} failed with exception: {}". - format(vmid, e) + msg=f"Getting information for VM with vmid = {vmid} failed with exception: {e}" ) # Sanitize kwargs. Remove not defined args and ensure True and False converted to int. @@ -800,16 +883,13 @@ def get_vminfo(module, proxmox, node, vmid, **kwargs): results["_raw"] = vm -def settings(module, proxmox, vmid, node, name, **kwargs): +def settings(module, proxmox, vmid, node, name, **kwargs): # noqa proxmox_node = proxmox.nodes(node) # Sanitize kwargs. Remove not defined args and ensure True and False converted to int. kwargs = dict((k, v) for k, v in kwargs.items() if v is not None) - if proxmox_node.qemu(vmid).config.set(**kwargs) is None: - return True - else: - return False + return (proxmox_node.qemu(vmid).config.set(**kwargs) is None) def wait_for_task(module, proxmox, node, taskid): @@ -840,7 +920,7 @@ def create_vm( clone_params = {} # Default args for vm. Note: -args option is for experts only. It allows you # to pass arbitrary arguments to kvm. - vm_args = "-serial unix:/var/run/qemu-server/{0}.serial,server,nowait".format(vmid) + vm_args = f"-serial unix:/var/run/qemu-server/{vmid}.serial,server,nowait" proxmox_node = proxmox.nodes(node) @@ -849,13 +929,13 @@ def create_vm( kwargs.update(dict([k, int(v)] for k, v in kwargs.items() if isinstance(v, bool))) # The features work only on PVE 4+ - if PVE_MAJOR_VERSION < 4: # noqa + if PVE_MAJOR_VERSION < 4: for p in only_v4: if p in kwargs: del kwargs[p] # The features work only on PVE 6 - if PVE_MAJOR_VERSION < 6: # noqa + if PVE_MAJOR_VERSION < 6: for p in only_v6: if p in kwargs: del kwargs[p] @@ -877,17 +957,17 @@ def create_vm( if update: for k, v in disks.items(): if results["disks"].get(k): - kwargs[k.rstrip(string.digits)][k] = "{0}:{1},{2}".format( - results["disks"][k]["storage_id"], results["disks"][k]["storage_opts"], - ",".join(disks[k]["opts"]) - ) + storage_id = results["disks"][k]["storage_id"] + storage_opts = results["disks"][k]["storage_opts"] + opts = ",".join(v["opts"]) + kwargs[k.rstrip(string.digits)][k] = f"{storage_id}:{storage_opts},{opts}" for k, v in nets.items(): if results["nets"].get(k): - kwargs[k.rstrip(string.digits)][k] = "{0}={1},{2}".format( - results["nets"][k]["net_id"], results["nets"][k]["net_opts"], - ",".join(nets[k]["opts"]) - ) + net_id = results["nets"][k]["net_id"] + net_opts = results["nets"][k]["net_opts"] + opts = ",".join(v["opts"]) + kwargs[k.rstrip(string.digits)][k] = f"{net_id}={net_opts},{opts}" # Convert all dict in kwargs to elements. for k in list(kwargs.keys()): @@ -914,13 +994,15 @@ def create_vm( if "tags" in kwargs: for tag in kwargs["tags"]: if not re.match(r"^[a-z0-9_][a-z0-9_\-\+\.]*$", tag): - module.fail_json(msg="{} is not a valid tag".format(tag)) + module.fail_json(msg=f"{tag} is not a valid tag") kwargs["tags"] = ",".join(kwargs["tags"]) # -args and skiplock require root@pam user - but can not use api tokens - if module.params["api_user"] == "root@pam" and module.params["args"] is None: - if not update and module.params["proxmox_default_behavior"] == "compatibility": - kwargs["args"] = vm_args + if ( + module.params["api_user"] == "root@pam" and module.params["args"] is None and not update + and module.params["proxmox_default_behavior"] == "compatibility" + ): + kwargs["args"] = vm_args elif module.params["api_user"] == "root@pam" and module.params["args"] is not None: kwargs["args"] = module.params["args"] elif module.params["api_user"] != "root@pam" and module.params["args"] is not None: @@ -930,13 +1012,12 @@ def create_vm( module.fail_json(msg="skiplock parameter require root@pam user. ") if update: - if proxmox_node.qemu(vmid).config.set( - name=name, memory=memory, cpu=cpu, cores=cores, sockets=sockets, **kwargs - ) is None: - return True - else: - return False - elif module.params["clone"] is not None: + return ( + proxmox_node.qemu(vmid).config. + set(name=name, memory=memory, cpu=cpu, cores=cores, sockets=sockets, **kwargs) is None + ) + + if module.params["clone"] is not None: for param in valid_clone_params: if module.params[param] is not None: clone_params[param] = module.params[param] @@ -952,8 +1033,7 @@ def create_vm( if not wait_for_task(module, proxmox, node, taskid): module.fail_json( msg="Reached timeout while waiting for creating VM." - "Last line in task before timeout: {}". - format(proxmox_node.tasks(taskid).log.get()[:1]) + f"Last line in task before timeout: {proxmox_node.tasks(taskid).log.get()[:1]}" ) return False return True @@ -966,8 +1046,7 @@ def start_vm(module, proxmox, vm): if not wait_for_task(module, proxmox, vm[0]["node"], taskid): module.fail_json( msg="Reached timeout while waiting for starting VM." - "Last line in task before timeout: {}". - format(proxmox_node.tasks(taskid).log.get()[:1]) + f"Last line in task before timeout: {proxmox_node.tasks(taskid).log.get()[:1]}" ) return False return True @@ -980,8 +1059,7 @@ def stop_vm(module, proxmox, vm, force): if not wait_for_task(module, proxmox, vm[0]["node"], taskid): module.fail_json( msg="Reached timeout while waiting for stopping VM." - "Last line in task before timeout: {}". - format(proxmox_node.tasks(taskid).log.get()[:1]) + f"Last line in task before timeout: {proxmox_node.tasks(taskid).log.get()[:1]}" ) return False return True @@ -998,7 +1076,7 @@ def main(): acpi=dict(type="bool"), agent=dict(type="bool"), args=dict(type="str"), - api_host=dict(required=True), + api_host=dict(required=True, type="str"), api_password=dict(no_log=True, fallback=(env_fallback, ["PROXMOX_PASSWORD"])), api_token_id=dict(no_log=True), api_token_secret=dict(no_log=True), @@ -1044,7 +1122,7 @@ def main(): nameservers=dict(type="list", elements="str"), net=dict(type="dict"), newid=dict(type="int"), - node=dict(), + node=dict(type="str"), numa=dict(type="dict"), numa_enabled=dict(type="bool"), onboot=dict(type="bool"), @@ -1076,7 +1154,7 @@ def main(): sockets=dict(type="int"), sshkeys=dict(type="str", no_log=False), startdate=dict(type="str"), - startup=dict(), + startup=dict(type="str"), state=dict( default="present", choices=["present", "absent", "stopped", "started", "restarted", "current"] @@ -1089,7 +1167,7 @@ def main(): template=dict(type="bool"), timeout=dict(type="int", default=30), update=dict(type="bool", default=False), - validate_certs=dict(type="bool", default=False), + verify_ssl=dict(type="bool", default=True), vcpus=dict(type="int"), vga=dict( choices=[ @@ -1099,7 +1177,7 @@ def main(): ), virtio=dict(type="dict"), vmid=dict(type="int"), - watchdog=dict(), + watchdog=dict(type="str"), proxmox_default_behavior=dict(type="str", choices=["compatibility", "no_defaults"]), ), mutually_exclusive=[("delete", "revert"), ("delete", "update"), ("revert", "update"), @@ -1130,7 +1208,7 @@ def main(): state = module.params["state"] update = bool(module.params["update"]) vmid = module.params["vmid"] - validate_certs = module.params["validate_certs"] + verify_ssl = module.params["verify_ssl"] if module.params["proxmox_default_behavior"] is None: module.params["proxmox_default_behavior"] = "compatibility" @@ -1166,15 +1244,16 @@ def main(): auth_args["token_name"] = api_token_id auth_args["token_value"] = api_token_secret + if not verify_ssl and HAS_URLLIB3: + urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + try: - proxmox = ProxmoxAPI(api_host, verify_ssl=validate_certs, **auth_args) - global PVE_MAJOR_VERSION # noqa + proxmox = ProxmoxAPI(api_host, verify_ssl=verify_ssl, **auth_args) + global PVE_MAJOR_VERSION version = proxmox_version(proxmox) PVE_MAJOR_VERSION = 3 if version < LooseVersion("4.0") else version.version[0] - except Exception as e: - module.fail_json( - msg="authorization on proxmox cluster failed with exception: {}".format(e) - ) + except Exception as e: # noqa + module.fail_json(msg=f"authorization on proxmox cluster failed with exception: {e}") # If vmid is not defined then retrieve its value from the vm name, # the cloned vm name or retrieve the next free VM id from ProxmoxAPI. @@ -1182,16 +1261,16 @@ def main(): if state == "present" and not update and not clone and not delete and not revert: try: vmid = get_nextvmid(module, proxmox) - except Exception: + except Exception: # noqa module.fail_json( - msg="Can't get the next vmid for VM {0} automatically." - "Ensure your cluster state is good".format(name) + msg=f"Can't get the next vmid for VM {name} automatically." + "Ensure your cluster state is good" ) else: clone_target = clone or name try: vmid = get_vmid(proxmox, clone_target)[0] - except Exception: + except Exception: # noqa vmid = -1 if clone is not None: @@ -1199,50 +1278,40 @@ def main(): if not newid: try: newid = get_nextvmid(module, proxmox) - except Exception: + except Exception: # noqa module.fail_json( - msg="Can't get the next vmid for VM {0} automatically." - "Ensure your cluster state is good".format(name) + msg=f"Can't get the next vmid for VM {name} automatically." + "Ensure your cluster state is good" ) # Ensure source VM name exists when cloning if -1 == vmid: - module.fail_json(msg="VM with name = {} does not exist in cluster".format(clone)) + module.fail_json(msg=f"VM with name = {clone} does not exist in cluster") # Ensure source VM id exists when cloning if not get_vm(proxmox, vmid): - module.fail_json( - vmid=vmid, msg="VM with vmid = {} does not exist in cluster".format(vmid) - ) + module.fail_json(vmid=vmid, msg=f"VM with vmid = {vmid} does not exist in cluster") # Ensure the choosen VM name doesn't already exist when cloning if get_vmid(proxmox, name): - module.exit_json( - changed=False, vmid=vmid, msg="VM with name <{}> already exists".format(name) - ) + module.exit_json(changed=False, vmid=vmid, msg=f"VM with name <{name}> already exists") # Ensure the choosen VM id doesn't already exist when cloning if get_vm(proxmox, newid): module.exit_json( - changed=False, - vmid=vmid, - msg="vmid {} with VM name {} already exists".format(newid, name) + changed=False, vmid=vmid, msg=f"vmid {newid} with VM name {name} already exists" ) if delete is not None: try: settings(module, proxmox, vmid, node, name, delete=delete) module.exit_json( - changed=True, - vmid=vmid, - msg="Settings has deleted on VM {0} with vmid {1}".format(name, vmid) + changed=True, vmid=vmid, msg=f"Settings has deleted on VM {name} with vmid {vmid}" ) - except Exception as e: + except Exception as e: # noqa module.fail_json( vmid=vmid, - msg="Unable to delete settings on VM {0} with vmid {1}: {2}".format( - name, vmid, str(e) - ) + msg=f"Unable to delete settings on VM {name} with vmid {vmid}: {str(e)}" ) if revert is not None: @@ -1251,29 +1320,29 @@ def main(): module.exit_json( changed=True, vmid=vmid, - msg="Settings has reverted on VM {0} with vmid {1}".format(name, vmid) + msg=f"Settings has reverted on VM {name} with vmid {vmid}" ) - except Exception as e: + except Exception as e: # noqa module.fail_json( vmid=vmid, - msg="Unable to revert settings on VM {0} with vmid {1}:" - "Maybe is not a pending task...".format(name, vmid) + str(e) + msg=f"Unable to revert settings on VM {name} with vmid {vmid}:" + f"Maybe is not a pending task...{str(e)}" ) if state == "present": try: if get_vm(proxmox, vmid) and not (update or clone): module.exit_json( - changed=False, vmid=vmid, msg="VM with vmid <{}> already exists".format(vmid) + changed=False, vmid=vmid, msg=f"VM with vmid <{vmid}> already exists" ) elif get_vmid(proxmox, name) and not (update or clone): module.exit_json( - changed=False, vmid=vmid, msg="VM with name <{}> already exists".format(name) + changed=False, vmid=vmid, msg=f"VM with name <{name}> already exists" ) elif not (node, name): module.fail_json(msg="node, name is mandatory for creating/updating vm") elif not node_check(proxmox, node): - module.fail_json(msg="node '{}' does not exist in cluster".format(node)) + module.fail_json(msg=f"node '{node}' does not exist in cluster") if not clone: get_vminfo( @@ -1362,130 +1431,100 @@ def main(): if update: module.exit_json( - changed=True, vmid=vmid, msg="VM {} with vmid {} updated".format(name, vmid) + changed=True, vmid=vmid, msg=f"VM {name} with vmid {vmid} updated" ) elif clone is not None: module.exit_json( changed=True, vmid=vmid, - msg="VM {} with newid {} cloned from vm with vmid {}".format( - name, newid, vmid - ) + msg=f"VM {name} with newid {newid} cloned from vm with vmid {vmid}" ) else: module.exit_json( - changed=True, - msg="VM {} with vmid {} deployed".format(name, vmid), - **results # noqa + changed=True, msg=f"VM {name} with vmid {vmid} deployed", **results ) - except Exception as e: + except Exception as e: # noqa if update: module.fail_json( - vmid=vmid, - msg="Unable to update vm {0} with vmid {1}=".format(name, vmid) + str(e) + vmid=vmid, msg=f"Unable to update vm {name} with vmid {vmid}=" + str(e) ) elif clone is not None: module.fail_json( - vmid=vmid, - msg="Unable to clone vm {0} from vmid {1}=".format(name, vmid) + str(e) + vmid=vmid, msg=f"Unable to clone vm {name} from vmid {vmid}=" + str(e) ) else: module.fail_json( vmid=vmid, - msg="creation of qemu VM {} with vmid {} failed with exception={}".format( - name, vmid, e - ) + msg=f"creation of qemu VM {name} with vmid {vmid} failed with exception={e}" ) elif state == "started": status = {} try: if -1 == vmid: - module.fail_json(msg="VM with name = {} does not exist in cluster".format(name)) + module.fail_json(msg=f"VM with name = {name} does not exist in cluster") vm = get_vm(proxmox, vmid) if not vm: - module.fail_json( - vmid=vmid, msg="VM with vmid <{}> does not exist in cluster".format(vmid) - ) + module.fail_json(vmid=vmid, msg=f"VM with vmid <{vmid}> does not exist in cluster") status["status"] = vm[0]["status"] if vm[0]["status"] == "running": module.exit_json( - changed=False, - vmid=vmid, - msg="VM {} is already running".format(vmid), - **status + changed=False, vmid=vmid, msg=f"VM {vmid} is already running", **status ) if start_vm(module, proxmox, vm): - module.exit_json( - changed=True, vmid=vmid, msg="VM {} started".format(vmid), **status - ) - except Exception as e: + module.exit_json(changed=True, vmid=vmid, msg=f"VM {vmid} started", **status) + except Exception as e: # noqa module.fail_json( - vmid=vmid, - msg="starting of VM {} failed with exception: {}".format(vmid, e), - **status + vmid=vmid, msg=f"starting of VM {vmid} failed with exception: {e}", **status ) elif state == "stopped": status = {} try: if -1 == vmid: - module.fail_json(msg="VM with name = {} does not exist in cluster".format(name)) + module.fail_json(msg=f"VM with name = {name} does not exist in cluster") vm = get_vm(proxmox, vmid) if not vm: - module.fail_json( - vmid=vmid, msg="VM with vmid = {} does not exist in cluster".format(vmid) - ) + module.fail_json(vmid=vmid, msg=f"VM with vmid = {vmid} does not exist in cluster") status["status"] = vm[0]["status"] if vm[0]["status"] == "stopped": module.exit_json( - changed=False, - vmid=vmid, - msg="VM {} is already stopped".format(vmid), - **status + changed=False, vmid=vmid, msg=f"VM {vmid} is already stopped", **status ) if stop_vm(module, proxmox, vm, force=module.params["force"]): module.exit_json( - changed=True, vmid=vmid, msg="VM {} is shutting down".format(vmid), **status + changed=True, vmid=vmid, msg=f"VM {vmid} is shutting down", **status ) - except Exception as e: + except Exception as e: # noqa module.fail_json( - vmid=vmid, - msg="stopping of VM {} failed with exception: {}".format(vmid, e), - **status + vmid=vmid, msg=f"stopping of VM {vmid} failed with exception: {e}", **status ) elif state == "restarted": status = {} try: if -1 == vmid: - module.fail_json(msg="VM with name = {} does not exist in cluster".format(name)) + module.fail_json(msg=f"VM with name = {name} does not exist in cluster") vm = get_vm(proxmox, vmid) if not vm: - module.fail_json( - vmid=vmid, msg="VM with vmid = {} does not exist in cluster".format(vmid) - ) + module.fail_json(vmid=vmid, msg=f"VM with vmid = {vmid} does not exist in cluster") status["status"] = vm[0]["status"] if vm[0]["status"] == "stopped": module.exit_json( - changed=False, vmid=vmid, msg="VM {} is not running".format(vmid), **status + changed=False, vmid=vmid, msg=f"VM {vmid} is not running", **status ) if stop_vm(module, proxmox, vm, force=module.params["force"]) and start_vm(module, proxmox, vm): - module.exit_json( - changed=True, vmid=vmid, msg="VM {} is restarted".format(vmid), **status - ) - except Exception as e: + module.exit_json(changed=True, vmid=vmid, msg=f"VM {vmid} is restarted", **status) + except Exception as e: # noqa module.fail_json( - vmid=vmid, - msg="restarting of VM {} failed with exception: {}".format(vmid, e), - **status + vmid=vmid, msg=f"restarting of VM {vmid} failed with exception: {e}", **status ) elif state == "absent": @@ -1504,28 +1543,26 @@ def main(): module.exit_json( changed=False, vmid=vmid, - msg="VM {} is running. Stop it before deletion or use force=yes.". - format(vmid) + msg=f"VM {vmid} is running. Stop it before deletion or use force=yes." ) taskid = proxmox_node.qemu.delete(vmid) if not wait_for_task(module, proxmox, vm[0]["node"], taskid): module.fail_json( msg="Reached timeout while waiting for removing VM." - "Last line in task before timeout: {}". - format(proxmox_node.tasks(taskid).log.get()[:1]) + f"Last line in task before timeout: {proxmox_node.tasks(taskid).log.get()[:1]}" ) else: - module.exit_json(changed=True, vmid=vmid, msg="VM {} removed".format(vmid)) - except Exception as e: - module.fail_json(msg="deletion of VM {} failed with exception: {}".format(vmid, e)) + module.exit_json(changed=True, vmid=vmid, msg=f"VM {vmid} removed") + except Exception as e: # noqa + module.fail_json(msg=f"deletion of VM {vmid} failed with exception: {e}") elif state == "current": status = {} if -1 == vmid: - module.fail_json(msg="VM with name = {} does not exist in cluster".format(name)) + module.fail_json(msg=f"VM with name = {name} does not exist in cluster") vm = get_vm(proxmox, vmid) if not vm: - module.fail_json(msg="VM with vmid = {} does not exist in cluster".format(vmid)) + module.fail_json(msg=f"VM with vmid = {vmid} does not exist in cluster") if not name: name = vm[0]["name"] current = proxmox.nodes(vm[0]["node"]).qemu(vmid).status.current.get()["status"] @@ -1534,7 +1571,7 @@ def main(): module.exit_json( changed=False, vmid=vmid, - msg="VM {} with vmid = {} is {}".format(name, vmid, current), + msg=f"VM {name} with vmid = {vmid} is {current}", **status ) @@ -1561,11 +1598,13 @@ def _extract_nets(item): if re.match(r"net[0-9]", k): nets[k]["opts"] = [] for val in v.split(","): - if any(val.startswith(s) for s in ["e1000", "rtl8139", "virtio", "vmxnet3"]): - if len(val.split("=")) == 2: - net = val.split("=") - nets[k]["net_id"] = net[0] - nets[k]["net_opts"] = net[1] + if ( + any(val.startswith(s) for s in ["e1000", "rtl8139", "virtio", "vmxnet3"]) + and len(val.split("=")) == 2 + ): + net = val.split("=") + nets[k]["net_id"] = net[0] + nets[k]["net_opts"] = net[1] else: nets[k]["opts"].append(val) diff --git a/plugins/modules/ucr.py b/plugins/modules/ucr.py index 87229eb..522d255 100644 --- a/plugins/modules/ucr.py +++ b/plugins/modules/ucr.py @@ -1,5 +1,12 @@ +#!/usr/bin/python # -*- coding: utf-8 -*- -"""Module to control Univention Corporate Registry.""" + +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +"""Control Univention Corporate Registry.""" + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported_by": "community"} @@ -7,28 +14,33 @@ DOCUMENTATION = """ --- module: ucr short_description: Manage variables in univention configuration registry. -version_added: "2.6" +version_added: 1.1.0 description: - - "This module allows to manage variables inside the univention configuration registry - on a univention corporate server (UCS)." + - "This module allows to manage variables inside the univention configuration registry + on a univention corporate server (UCS)." options: - path: - description: - - Path for the variable - required: True - default: null - value: - description: - - New value of the variable - required: False - state: - required: False - default: "present" - choices: ["present", "absent"] - description: - - Whether the variable should be exist or not. + path: + description: + - Path for the variable + aliases: + - name + required: True + type: str + value: + description: + - New value of the variable + required: False + type: str + default: "" + state: + required: False + default: "present" + choices: ["present", "absent"] + type: str + description: + - Whether the variable should be exist or not. author: - - Robert Kaussow (@xoxys) + - Robert Kaussow (@xoxys) """ EXAMPLES = """ @@ -47,41 +59,43 @@ EXAMPLES = """ RETURN = """ original_message: - description: The original name param that was passed in - type: str + description: The original name param that was passed in + type: str + returned: success message: - description: The output message that the sample module generates + description: The output message that the sample module generates + type: str + returned: success """ from ansible.module_utils.basic import AnsibleModule -from univention.config_registry import ConfigRegistry # noqa -from univention.config_registry.frontend import ucr_update # noqa + +try: + from univention.config_registry import ConfigRegistry + from univention.config_registry.frontend import ucr_update + HAS_UNIVENTION = True +except ImportError: + HAS_UNIVENTION = False def get_variable(ucr, path): ucr.load() - if path in ucr: - value = ucr.get(path) - else: - value = None - return value + return ucr.get(path) if path in ucr else None -def set_variable(ucr, path, value, result): +def set_variable(ucr, path, value, result): # noqa org_value = get_variable(ucr, path) ucr_update(ucr, {path: value}) new_value = get_variable(ucr, path) - return not org_value == new_value + return org_value != new_value -def dry_variable(ucr, path, value, result): +def dry_variable(ucr, path, value, result): # noqa org_value = get_variable(ucr, path) - return not org_value == value + return org_value != value def main(): - ucr = ConfigRegistry() - module_args = dict( path=dict(type="str", required=True, aliases=["name"]), value=dict(type="str", required=False, default=""), @@ -94,13 +108,17 @@ def main(): argument_spec=module_args, supports_check_mode=True, required_if=required_if ) + if not HAS_UNIVENTION: + module.fail_json(msg="univention required for this module") + + ucr = ConfigRegistry() + result = dict(changed=False, original_message="", message="") path = module.params["path"] value = module.params["value"] - if module.params["state"] == "present": - if value is None or value == "None": - value = "" + if module.params["state"] == "present" and (value is None or value == "None"): + value = "" elif module.params["state"] == "absent": value = None diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..a6a5a83 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,1143 @@ +# This file is automatically @generated by Poetry and should not be changed by hand. + +[[package]] +name = "ansible-core" +version = "2.13.7" +description = "Radically simple IT automation" +category = "main" +optional = true +python-versions = ">=3.8" +files = [ + {file = "ansible-core-2.13.7.tar.gz", hash = "sha256:a9d5f942ff0dcbeec3d7183a898ea4f656d233d6055d4bc8e22e37b013b1881a"}, + {file = "ansible_core-2.13.7-py3-none-any.whl", hash = "sha256:6005c24e45ff59497a7fe24411825fcba862585bc6bde83d6d48242c97042aba"}, +] + +[package.dependencies] +cryptography = "*" +jinja2 = ">=3.0.0" +packaging = "*" +PyYAML = ">=5.1" +resolvelib = ">=0.5.3,<0.9.0" + +[[package]] +name = "astroid" +version = "2.13.4" +description = "An abstract syntax tree for Python with inference support." +category = "dev" +optional = false +python-versions = ">=3.7.2" +files = [ + {file = "astroid-2.13.4-py3-none-any.whl", hash = "sha256:fe430a1dcc6af3abbccd29ba9f2544dcafc0610d37018b5102c232ff917e4bbf"}, + {file = "astroid-2.13.4.tar.gz", hash = "sha256:805d47d685a490f4024e3744064e919998b0eef6619e6ea6d2052deec5333fd5"}, +] + +[package.dependencies] +lazy-object-proxy = ">=1.4.0" +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} +wrapt = [ + {version = ">=1.11,<2", markers = "python_version < \"3.11\""}, + {version = ">=1.14,<2", markers = "python_version >= \"3.11\""}, +] + +[[package]] +name = "attrs" +version = "22.2.0" +description = "Classes Without Boilerplate" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"}, + {file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"}, +] + +[package.extras] +cov = ["attrs[tests]", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"] +dev = ["attrs[docs,tests]"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"] +tests = ["attrs[tests-no-zope]", "zope.interface"] +tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"] + +[[package]] +name = "certifi" +version = "2022.12.7" +description = "Python package for providing Mozilla's CA Bundle." +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, + {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, +] + +[[package]] +name = "cffi" +version = "1.15.1" +description = "Foreign Function Interface for Python calling C code." +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, + {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, + {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, + {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, + {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, + {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, + {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, + {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, + {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, + {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, + {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, + {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, + {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, + {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, + {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, + {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, + {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, + {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, + {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, +] + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "charset-normalizer" +version = "3.0.1" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "charset-normalizer-3.0.1.tar.gz", hash = "sha256:ebea339af930f8ca5d7a699b921106c6e29c617fe9606fa7baa043c1cdae326f"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88600c72ef7587fe1708fd242b385b6ed4b8904976d5da0893e31df8b3480cb6"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c75ffc45f25324e68ab238cb4b5c0a38cd1c3d7f1fb1f72b5541de469e2247db"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:db72b07027db150f468fbada4d85b3b2729a3db39178abf5c543b784c1254539"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62595ab75873d50d57323a91dd03e6966eb79c41fa834b7a1661ed043b2d404d"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ff6f3db31555657f3163b15a6b7c6938d08df7adbfc9dd13d9d19edad678f1e8"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:772b87914ff1152b92a197ef4ea40efe27a378606c39446ded52c8f80f79702e"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70990b9c51340e4044cfc394a81f614f3f90d41397104d226f21e66de668730d"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:292d5e8ba896bbfd6334b096e34bffb56161c81408d6d036a7dfa6929cff8783"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2edb64ee7bf1ed524a1da60cdcd2e1f6e2b4f66ef7c077680739f1641f62f555"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:31a9ddf4718d10ae04d9b18801bd776693487cbb57d74cc3458a7673f6f34639"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:44ba614de5361b3e5278e1241fda3dc1838deed864b50a10d7ce92983797fa76"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:12db3b2c533c23ab812c2b25934f60383361f8a376ae272665f8e48b88e8e1c6"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c512accbd6ff0270939b9ac214b84fb5ada5f0409c44298361b2f5e13f9aed9e"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-win32.whl", hash = "sha256:502218f52498a36d6bf5ea77081844017bf7982cdbe521ad85e64cabee1b608b"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:601f36512f9e28f029d9481bdaf8e89e5148ac5d89cffd3b05cd533eeb423b59"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0298eafff88c99982a4cf66ba2efa1128e4ddaca0b05eec4c456bbc7db691d8d"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a8d0fc946c784ff7f7c3742310cc8a57c5c6dc31631269876a88b809dbeff3d3"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:87701167f2a5c930b403e9756fab1d31d4d4da52856143b609e30a1ce7160f3c"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14e76c0f23218b8f46c4d87018ca2e441535aed3632ca134b10239dfb6dadd6b"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c0a590235ccd933d9892c627dec5bc7511ce6ad6c1011fdf5b11363022746c1"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c7fe7afa480e3e82eed58e0ca89f751cd14d767638e2550c77a92a9e749c317"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79909e27e8e4fcc9db4addea88aa63f6423ebb171db091fb4373e3312cb6d603"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ac7b6a045b814cf0c47f3623d21ebd88b3e8cf216a14790b455ea7ff0135d18"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:72966d1b297c741541ca8cf1223ff262a6febe52481af742036a0b296e35fa5a"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f9d0c5c045a3ca9bedfc35dca8526798eb91a07aa7a2c0fee134c6c6f321cbd7"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5995f0164fa7df59db4746112fec3f49c461dd6b31b841873443bdb077c13cfc"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4a8fcf28c05c1f6d7e177a9a46a1c52798bfe2ad80681d275b10dcf317deaf0b"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:761e8904c07ad053d285670f36dd94e1b6ab7f16ce62b9805c475b7aa1cffde6"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-win32.whl", hash = "sha256:71140351489970dfe5e60fc621ada3e0f41104a5eddaca47a7acb3c1b851d6d3"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:9ab77acb98eba3fd2a85cd160851816bfce6871d944d885febf012713f06659c"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:84c3990934bae40ea69a82034912ffe5a62c60bbf6ec5bc9691419641d7d5c9a"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74292fc76c905c0ef095fe11e188a32ebd03bc38f3f3e9bcb85e4e6db177b7ea"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c95a03c79bbe30eec3ec2b7f076074f4281526724c8685a42872974ef4d36b72"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c39b0e3eac288fedc2b43055cfc2ca7a60362d0e5e87a637beac5d801ef478"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df2c707231459e8a4028eabcd3cfc827befd635b3ef72eada84ab13b52e1574d"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93ad6d87ac18e2a90b0fe89df7c65263b9a99a0eb98f0a3d2e079f12a0735837"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:59e5686dd847347e55dffcc191a96622f016bc0ad89105e24c14e0d6305acbc6"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:cd6056167405314a4dc3c173943f11249fa0f1b204f8b51ed4bde1a9cd1834dc"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:083c8d17153ecb403e5e1eb76a7ef4babfc2c48d58899c98fcaa04833e7a2f9a"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:f5057856d21e7586765171eac8b9fc3f7d44ef39425f85dbcccb13b3ebea806c"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:7eb33a30d75562222b64f569c642ff3dc6689e09adda43a082208397f016c39a"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-win32.whl", hash = "sha256:95dea361dd73757c6f1c0a1480ac499952c16ac83f7f5f4f84f0658a01b8ef41"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:eaa379fcd227ca235d04152ca6704c7cb55564116f8bc52545ff357628e10602"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3e45867f1f2ab0711d60c6c71746ac53537f1684baa699f4f668d4c6f6ce8e14"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cadaeaba78750d58d3cc6ac4d1fd867da6fc73c88156b7a3212a3cd4819d679d"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:911d8a40b2bef5b8bbae2e36a0b103f142ac53557ab421dc16ac4aafee6f53dc"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:503e65837c71b875ecdd733877d852adbc465bd82c768a067badd953bf1bc5a3"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a60332922359f920193b1d4826953c507a877b523b2395ad7bc716ddd386d866"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16a8663d6e281208d78806dbe14ee9903715361cf81f6d4309944e4d1e59ac5b"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a16418ecf1329f71df119e8a65f3aa68004a3f9383821edcb20f0702934d8087"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9d9153257a3f70d5f69edf2325357251ed20f772b12e593f3b3377b5f78e7ef8"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:02a51034802cbf38db3f89c66fb5d2ec57e6fe7ef2f4a44d070a593c3688667b"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:2e396d70bc4ef5325b72b593a72c8979999aa52fb8bcf03f701c1b03e1166918"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:11b53acf2411c3b09e6af37e4b9005cba376c872503c8f28218c7243582df45d"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-win32.whl", hash = "sha256:0bf2dae5291758b6f84cf923bfaa285632816007db0330002fa1de38bfcb7154"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:2c03cc56021a4bd59be889c2b9257dae13bf55041a3372d3295416f86b295fb5"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:024e606be3ed92216e2b6952ed859d86b4cfa52cd5bc5f050e7dc28f9b43ec42"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4b0d02d7102dd0f997580b51edc4cebcf2ab6397a7edf89f1c73b586c614272c"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:358a7c4cb8ba9b46c453b1dd8d9e431452d5249072e4f56cfda3149f6ab1405e"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81d6741ab457d14fdedc215516665050f3822d3e56508921cc7239f8c8e66a58"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8b8af03d2e37866d023ad0ddea594edefc31e827fee64f8de5611a1dbc373174"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9cf4e8ad252f7c38dd1f676b46514f92dc0ebeb0db5552f5f403509705e24753"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e696f0dd336161fca9adbb846875d40752e6eba585843c768935ba5c9960722b"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c22d3fe05ce11d3671297dc8973267daa0f938b93ec716e12e0f6dee81591dc1"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:109487860ef6a328f3eec66f2bf78b0b72400280d8f8ea05f69c51644ba6521a"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:37f8febc8ec50c14f3ec9637505f28e58d4f66752207ea177c1d67df25da5aed"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:f97e83fa6c25693c7a35de154681fcc257c1c41b38beb0304b9c4d2d9e164479"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a152f5f33d64a6be73f1d30c9cc82dfc73cec6477ec268e7c6e4c7d23c2d2291"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:39049da0ffb96c8cbb65cbf5c5f3ca3168990adf3551bd1dee10c48fce8ae820"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-win32.whl", hash = "sha256:4457ea6774b5611f4bed5eaa5df55f70abde42364d498c5134b7ef4c6958e20e"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:e62164b50f84e20601c1ff8eb55620d2ad25fb81b59e3cd776a1902527a788af"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8eade758719add78ec36dc13201483f8e9b5d940329285edcd5f70c0a9edbd7f"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8499ca8f4502af841f68135133d8258f7b32a53a1d594aa98cc52013fff55678"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3fc1c4a2ffd64890aebdb3f97e1278b0cc72579a08ca4de8cd2c04799a3a22be"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00d3ffdaafe92a5dc603cb9bd5111aaa36dfa187c8285c543be562e61b755f6b"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2ac1b08635a8cd4e0cbeaf6f5e922085908d48eb05d44c5ae9eabab148512ca"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6f45710b4459401609ebebdbcfb34515da4fc2aa886f95107f556ac69a9147e"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ae1de54a77dc0d6d5fcf623290af4266412a7c4be0b1ff7444394f03f5c54e3"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b590df687e3c5ee0deef9fc8c547d81986d9a1b56073d82de008744452d6541"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab5de034a886f616a5668aa5d098af2b5385ed70142090e2a31bcbd0af0fdb3d"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9cb3032517f1627cc012dbc80a8ec976ae76d93ea2b5feaa9d2a5b8882597579"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:608862a7bf6957f2333fc54ab4399e405baad0163dc9f8d99cb236816db169d4"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0f438ae3532723fb6ead77e7c604be7c8374094ef4ee2c5e03a3a17f1fca256c"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:356541bf4381fa35856dafa6a965916e54bed415ad8a24ee6de6e37deccf2786"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-win32.whl", hash = "sha256:39cf9ed17fe3b1bc81f33c9ceb6ce67683ee7526e65fde1447c772afc54a1bb8"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:0a11e971ed097d24c534c037d298ad32c6ce81a45736d31e0ff0ad37ab437d59"}, + {file = "charset_normalizer-3.0.1-py3-none-any.whl", hash = "sha256:7e189e2e1d3ed2f4aebabd2d5b0f931e883676e51c7624826e0a4e5fe8a0bf24"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "coverage" +version = "7.1.0" +description = "Code coverage measurement for Python" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "coverage-7.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3b946bbcd5a8231383450b195cfb58cb01cbe7f8949f5758566b881df4b33baf"}, + {file = "coverage-7.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ec8e767f13be637d056f7e07e61d089e555f719b387a7070154ad80a0ff31801"}, + {file = "coverage-7.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4a5a5879a939cb84959d86869132b00176197ca561c664fc21478c1eee60d75"}, + {file = "coverage-7.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b643cb30821e7570c0aaf54feaf0bfb630b79059f85741843e9dc23f33aaca2c"}, + {file = "coverage-7.1.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32df215215f3af2c1617a55dbdfb403b772d463d54d219985ac7cd3bf124cada"}, + {file = "coverage-7.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:33d1ae9d4079e05ac4cc1ef9e20c648f5afabf1a92adfaf2ccf509c50b85717f"}, + {file = "coverage-7.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:29571503c37f2ef2138a306d23e7270687c0efb9cab4bd8038d609b5c2393a3a"}, + {file = "coverage-7.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:63ffd21aa133ff48c4dff7adcc46b7ec8b565491bfc371212122dd999812ea1c"}, + {file = "coverage-7.1.0-cp310-cp310-win32.whl", hash = "sha256:4b14d5e09c656de5038a3f9bfe5228f53439282abcab87317c9f7f1acb280352"}, + {file = "coverage-7.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:8361be1c2c073919500b6601220a6f2f98ea0b6d2fec5014c1d9cfa23dd07038"}, + {file = "coverage-7.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:da9b41d4539eefd408c46725fb76ecba3a50a3367cafb7dea5f250d0653c1040"}, + {file = "coverage-7.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5b15ed7644ae4bee0ecf74fee95808dcc34ba6ace87e8dfbf5cb0dc20eab45a"}, + {file = "coverage-7.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d12d076582507ea460ea2a89a8c85cb558f83406c8a41dd641d7be9a32e1274f"}, + {file = "coverage-7.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2617759031dae1bf183c16cef8fcfb3de7617f394c813fa5e8e46e9b82d4222"}, + {file = "coverage-7.1.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4e4881fa9e9667afcc742f0c244d9364d197490fbc91d12ac3b5de0bf2df146"}, + {file = "coverage-7.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9d58885215094ab4a86a6aef044e42994a2bd76a446dc59b352622655ba6621b"}, + {file = "coverage-7.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ffeeb38ee4a80a30a6877c5c4c359e5498eec095878f1581453202bfacc8fbc2"}, + {file = "coverage-7.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3baf5f126f30781b5e93dbefcc8271cb2491647f8283f20ac54d12161dff080e"}, + {file = "coverage-7.1.0-cp311-cp311-win32.whl", hash = "sha256:ded59300d6330be27bc6cf0b74b89ada58069ced87c48eaf9344e5e84b0072f7"}, + {file = "coverage-7.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:6a43c7823cd7427b4ed763aa7fb63901ca8288591323b58c9cd6ec31ad910f3c"}, + {file = "coverage-7.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7a726d742816cb3a8973c8c9a97539c734b3a309345236cd533c4883dda05b8d"}, + {file = "coverage-7.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc7c85a150501286f8b56bd8ed3aa4093f4b88fb68c0843d21ff9656f0009d6a"}, + {file = "coverage-7.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5b4198d85a3755d27e64c52f8c95d6333119e49fd001ae5798dac872c95e0f8"}, + {file = "coverage-7.1.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddb726cb861c3117a553f940372a495fe1078249ff5f8a5478c0576c7be12050"}, + {file = "coverage-7.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:51b236e764840a6df0661b67e50697aaa0e7d4124ca95e5058fa3d7cbc240b7c"}, + {file = "coverage-7.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7ee5c9bb51695f80878faaa5598040dd6c9e172ddcf490382e8aedb8ec3fec8d"}, + {file = "coverage-7.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c31b75ae466c053a98bf26843563b3b3517b8f37da4d47b1c582fdc703112bc3"}, + {file = "coverage-7.1.0-cp37-cp37m-win32.whl", hash = "sha256:3b155caf3760408d1cb903b21e6a97ad4e2bdad43cbc265e3ce0afb8e0057e73"}, + {file = "coverage-7.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2a60d6513781e87047c3e630b33b4d1e89f39836dac6e069ffee28c4786715f5"}, + {file = "coverage-7.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f2cba5c6db29ce991029b5e4ac51eb36774458f0a3b8d3137241b32d1bb91f06"}, + {file = "coverage-7.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:beeb129cacea34490ffd4d6153af70509aa3cda20fdda2ea1a2be870dfec8d52"}, + {file = "coverage-7.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c45948f613d5d18c9ec5eaa203ce06a653334cf1bd47c783a12d0dd4fd9c851"}, + {file = "coverage-7.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef382417db92ba23dfb5864a3fc9be27ea4894e86620d342a116b243ade5d35d"}, + {file = "coverage-7.1.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c7c0d0827e853315c9bbd43c1162c006dd808dbbe297db7ae66cd17b07830f0"}, + {file = "coverage-7.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e5cdbb5cafcedea04924568d990e20ce7f1945a1dd54b560f879ee2d57226912"}, + {file = "coverage-7.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9817733f0d3ea91bea80de0f79ef971ae94f81ca52f9b66500c6a2fea8e4b4f8"}, + {file = "coverage-7.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:218fe982371ac7387304153ecd51205f14e9d731b34fb0568181abaf7b443ba0"}, + {file = "coverage-7.1.0-cp38-cp38-win32.whl", hash = "sha256:04481245ef966fbd24ae9b9e537ce899ae584d521dfbe78f89cad003c38ca2ab"}, + {file = "coverage-7.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:8ae125d1134bf236acba8b83e74c603d1b30e207266121e76484562bc816344c"}, + {file = "coverage-7.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2bf1d5f2084c3932b56b962a683074a3692bce7cabd3aa023c987a2a8e7612f6"}, + {file = "coverage-7.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:98b85dd86514d889a2e3dd22ab3c18c9d0019e696478391d86708b805f4ea0fa"}, + {file = "coverage-7.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38da2db80cc505a611938d8624801158e409928b136c8916cd2e203970dde4dc"}, + {file = "coverage-7.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3164d31078fa9efe406e198aecd2a02d32a62fecbdef74f76dad6a46c7e48311"}, + {file = "coverage-7.1.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db61a79c07331e88b9a9974815c075fbd812bc9dbc4dc44b366b5368a2936063"}, + {file = "coverage-7.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ccb092c9ede70b2517a57382a601619d20981f56f440eae7e4d7eaafd1d1d09"}, + {file = "coverage-7.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:33ff26d0f6cc3ca8de13d14fde1ff8efe1456b53e3f0273e63cc8b3c84a063d8"}, + {file = "coverage-7.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d47dd659a4ee952e90dc56c97d78132573dc5c7b09d61b416a9deef4ebe01a0c"}, + {file = "coverage-7.1.0-cp39-cp39-win32.whl", hash = "sha256:d248cd4a92065a4d4543b8331660121b31c4148dd00a691bfb7a5cdc7483cfa4"}, + {file = "coverage-7.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:7ed681b0f8e8bcbbffa58ba26fcf5dbc8f79e7997595bf071ed5430d8c08d6f3"}, + {file = "coverage-7.1.0-pp37.pp38.pp39-none-any.whl", hash = "sha256:755e89e32376c850f826c425ece2c35a4fc266c081490eb0a841e7c1cb0d3bda"}, + {file = "coverage-7.1.0.tar.gz", hash = "sha256:10188fe543560ec4874f974b5305cd1a8bdcfa885ee00ea3a03733464c4ca265"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli"] + +[[package]] +name = "cryptography" +version = "39.0.0" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "cryptography-39.0.0-cp36-abi3-macosx_10_12_universal2.whl", hash = "sha256:c52a1a6f81e738d07f43dab57831c29e57d21c81a942f4602fac7ee21b27f288"}, + {file = "cryptography-39.0.0-cp36-abi3-macosx_10_12_x86_64.whl", hash = "sha256:80ee674c08aaef194bc4627b7f2956e5ba7ef29c3cc3ca488cf15854838a8f72"}, + {file = "cryptography-39.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:887cbc1ea60786e534b00ba8b04d1095f4272d380ebd5f7a7eb4cc274710fad9"}, + {file = "cryptography-39.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f97109336df5c178ee7c9c711b264c502b905c2d2a29ace99ed761533a3460f"}, + {file = "cryptography-39.0.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a6915075c6d3a5e1215eab5d99bcec0da26036ff2102a1038401d6ef5bef25b"}, + {file = "cryptography-39.0.0-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:76c24dd4fd196a80f9f2f5405a778a8ca132f16b10af113474005635fe7e066c"}, + {file = "cryptography-39.0.0-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:bae6c7f4a36a25291b619ad064a30a07110a805d08dc89984f4f441f6c1f3f96"}, + {file = "cryptography-39.0.0-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:875aea1039d78557c7c6b4db2fe0e9d2413439f4676310a5f269dd342ca7a717"}, + {file = "cryptography-39.0.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:f6c0db08d81ead9576c4d94bbb27aed8d7a430fa27890f39084c2d0e2ec6b0df"}, + {file = "cryptography-39.0.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f3ed2d864a2fa1666e749fe52fb8e23d8e06b8012e8bd8147c73797c506e86f1"}, + {file = "cryptography-39.0.0-cp36-abi3-win32.whl", hash = "sha256:f671c1bb0d6088e94d61d80c606d65baacc0d374e67bf895148883461cd848de"}, + {file = "cryptography-39.0.0-cp36-abi3-win_amd64.whl", hash = "sha256:e324de6972b151f99dc078defe8fb1b0a82c6498e37bff335f5bc6b1e3ab5a1e"}, + {file = "cryptography-39.0.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:754978da4d0457e7ca176f58c57b1f9de6556591c19b25b8bcce3c77d314f5eb"}, + {file = "cryptography-39.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ee1fd0de9851ff32dbbb9362a4d833b579b4a6cc96883e8e6d2ff2a6bc7104f"}, + {file = "cryptography-39.0.0-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:fec8b932f51ae245121c4671b4bbc030880f363354b2f0e0bd1366017d891458"}, + {file = "cryptography-39.0.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:407cec680e811b4fc829de966f88a7c62a596faa250fc1a4b520a0355b9bc190"}, + {file = "cryptography-39.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:7dacfdeee048814563eaaec7c4743c8aea529fe3dd53127313a792f0dadc1773"}, + {file = "cryptography-39.0.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ad04f413436b0781f20c52a661660f1e23bcd89a0e9bb1d6d20822d048cf2856"}, + {file = "cryptography-39.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50386acb40fbabbceeb2986332f0287f50f29ccf1497bae31cf5c3e7b4f4b34f"}, + {file = "cryptography-39.0.0-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:e5d71c5d5bd5b5c3eebcf7c5c2bb332d62ec68921a8c593bea8c394911a005ce"}, + {file = "cryptography-39.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:844ad4d7c3850081dffba91cdd91950038ee4ac525c575509a42d3fc806b83c8"}, + {file = "cryptography-39.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e0a05aee6a82d944f9b4edd6a001178787d1546ec7c6223ee9a848a7ade92e39"}, + {file = "cryptography-39.0.0.tar.gz", hash = "sha256:f964c7dcf7802d133e8dbd1565914fa0194f9d683d82411989889ecd701e8adf"}, +] + +[package.dependencies] +cffi = ">=1.12" + +[package.extras] +docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1,!=5.2.0,!=5.2.0.post0)", "sphinx-rtd-theme"] +docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] +pep8test = ["black", "ruff"] +sdist = ["setuptools-rust (>=0.11.4)"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-subtests", "pytest-xdist", "pytz"] + +[[package]] +name = "dill" +version = "0.3.6" +description = "serialize all of python" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "dill-0.3.6-py3-none-any.whl", hash = "sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0"}, + {file = "dill-0.3.6.tar.gz", hash = "sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373"}, +] + +[package.extras] +graph = ["objgraph (>=1.7.2)"] + +[[package]] +name = "exceptiongroup" +version = "1.1.0" +description = "Backport of PEP 654 (exception groups)" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.1.0-py3-none-any.whl", hash = "sha256:327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e"}, + {file = "exceptiongroup-1.1.0.tar.gz", hash = "sha256:bcb67d800a4497e1b404c2dd44fca47d3b7a5e5433dbab67f96c1a685cdfdf23"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "hcloud" +version = "1.18.2" +description = "Official Hetzner Cloud python library" +category = "main" +optional = false +python-versions = ">3.5" +files = [ + {file = "hcloud-1.18.2-py2.py3-none-any.whl", hash = "sha256:fcd73c7aab1d6e729333697e5214b26727775eccdbfb50effd1863c3424caa59"}, + {file = "hcloud-1.18.2.tar.gz", hash = "sha256:37bd5ba56387e3c491c5babd3e08ab91d5f0390cd5e880e4dfea19e21681bc9e"}, +] + +[package.dependencies] +python-dateutil = ">=2.7.5" +requests = ">=2.20" + +[package.extras] +docs = ["Sphinx (==1.8.1)", "sphinx-rtd-theme (==0.4.2)"] + +[[package]] +name = "idna" +version = "3.4" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "isort" +version = "5.12.0" +description = "A Python utility / library to sort Python imports." +category = "dev" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, + {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, +] + +[package.extras] +colors = ["colorama (>=0.4.3)"] +pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] +plugins = ["setuptools"] +requirements-deprecated-finder = ["pip-api", "pipreqs"] + +[[package]] +name = "jinja2" +version = "3.1.2" +description = "A very fast and expressive template engine." +category = "main" +optional = true +python-versions = ">=3.7" +files = [ + {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, + {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "lazy-object-proxy" +version = "1.9.0" +description = "A fast and thorough lazy object proxy." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "lazy-object-proxy-1.9.0.tar.gz", hash = "sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-win32.whl", hash = "sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-win32.whl", hash = "sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win32.whl", hash = "sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-win32.whl", hash = "sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-win32.whl", hash = "sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f"}, +] + +[[package]] +name = "markupsafe" +version = "2.1.2" +description = "Safely add untrusted strings to HTML/XML markup." +category = "main" +optional = true +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:665a36ae6f8f20a4676b53224e33d456a6f5a72657d9c83c2aa00765072f31f7"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:340bea174e9761308703ae988e982005aedf427de816d1afe98147668cc03036"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22152d00bf4a9c7c83960521fc558f55a1adbc0631fbb00a9471e097b19d72e1"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28057e985dace2f478e042eaa15606c7efccb700797660629da387eb289b9323"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca244fa73f50a800cf8c3ebf7fd93149ec37f5cb9596aa8873ae2c1d23498601"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d9d971ec1e79906046aa3ca266de79eac42f1dbf3612a05dc9368125952bd1a1"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7e007132af78ea9df29495dbf7b5824cb71648d7133cf7848a2a5dd00d36f9ff"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7313ce6a199651c4ed9d7e4cfb4aa56fe923b1adf9af3b420ee14e6d9a73df65"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-win32.whl", hash = "sha256:c4a549890a45f57f1ebf99c067a4ad0cb423a05544accaf2b065246827ed9603"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:835fb5e38fd89328e9c81067fd642b3593c33e1e17e2fdbf77f5676abb14a156"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2ec4f2d48ae59bbb9d1f9d7efb9236ab81429a764dedca114f5fdabbc3788013"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608e7073dfa9e38a85d38474c082d4281f4ce276ac0010224eaba11e929dd53a"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65608c35bfb8a76763f37036547f7adfd09270fbdbf96608be2bead319728fcd"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2bfb563d0211ce16b63c7cb9395d2c682a23187f54c3d79bfec33e6705473c6"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da25303d91526aac3672ee6d49a2f3db2d9502a4a60b55519feb1a4c7714e07d"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9cad97ab29dfc3f0249b483412c85c8ef4766d96cdf9dcf5a1e3caa3f3661cf1"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:085fd3201e7b12809f9e6e9bc1e5c96a368c8523fad5afb02afe3c051ae4afcc"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1bea30e9bf331f3fef67e0a3877b2288593c98a21ccb2cf29b74c581a4eb3af0"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-win32.whl", hash = "sha256:7df70907e00c970c60b9ef2938d894a9381f38e6b9db73c5be35e59d92e06625"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:e55e40ff0cc8cc5c07996915ad367fa47da6b3fc091fdadca7f5403239c5fec3"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a6e40afa7f45939ca356f348c8e23048e02cb109ced1eb8420961b2f40fb373a"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf877ab4ed6e302ec1d04952ca358b381a882fbd9d1b07cccbfd61783561f98a"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63ba06c9941e46fa389d389644e2d8225e0e3e5ebcc4ff1ea8506dce646f8c8a"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1cd098434e83e656abf198f103a8207a8187c0fc110306691a2e94a78d0abb2"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:55f44b440d491028addb3b88f72207d71eeebfb7b5dbf0643f7c023ae1fba619"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a6f2fcca746e8d5910e18782f976489939d54a91f9411c32051b4aab2bd7c513"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0b462104ba25f1ac006fdab8b6a01ebbfbce9ed37fd37fd4acd70c67c973e460"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-win32.whl", hash = "sha256:7668b52e102d0ed87cb082380a7e2e1e78737ddecdde129acadb0eccc5423859"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6d6607f98fcf17e534162f0709aaad3ab7a96032723d8ac8750ffe17ae5a0666"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a806db027852538d2ad7555b203300173dd1b77ba116de92da9afbc3a3be3eed"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a4abaec6ca3ad8660690236d11bfe28dfd707778e2442b45addd2f086d6ef094"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f03a532d7dee1bed20bc4884194a16160a2de9ffc6354b3878ec9682bb623c54"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cf06cdc1dda95223e9d2d3c58d3b178aa5dacb35ee7e3bbac10e4e1faacb419"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22731d79ed2eb25059ae3df1dfc9cb1546691cc41f4e3130fe6bfbc3ecbbecfa"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f8ffb705ffcf5ddd0e80b65ddf7bed7ee4f5a441ea7d3419e861a12eaf41af58"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8db032bf0ce9022a8e41a22598eefc802314e81b879ae093f36ce9ddf39ab1ba"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2298c859cfc5463f1b64bd55cb3e602528db6fa0f3cfd568d3605c50678f8f03"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-win32.whl", hash = "sha256:50c42830a633fa0cf9e7d27664637532791bfc31c731a87b202d2d8ac40c3ea2"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:bb06feb762bade6bf3c8b844462274db0c76acc95c52abe8dbed28ae3d44a147"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:99625a92da8229df6d44335e6fcc558a5037dd0a760e11d84be2260e6f37002f"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8bca7e26c1dd751236cfb0c6c72d4ad61d986e9a41bbf76cb445f69488b2a2bd"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40627dcf047dadb22cd25ea7ecfe9cbf3bbbad0482ee5920b582f3809c97654f"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40dfd3fefbef579ee058f139733ac336312663c6706d1163b82b3003fb1925c4"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:090376d812fb6ac5f171e5938e82e7f2d7adc2b629101cec0db8b267815c85e2"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2e7821bffe00aa6bd07a23913b7f4e01328c3d5cc0b40b36c0bd81d362faeb65"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c0a33bc9f02c2b17c3ea382f91b4db0e6cde90b63b296422a939886a7a80de1c"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b8526c6d437855442cdd3d87eede9c425c4445ea011ca38d937db299382e6fa3"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-win32.whl", hash = "sha256:137678c63c977754abe9086a3ec011e8fd985ab90631145dfb9294ad09c102a7"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:0576fe974b40a400449768941d5d0858cc624e3249dfd1e0c33674e5c7ca7aed"}, + {file = "MarkupSafe-2.1.2.tar.gz", hash = "sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d"}, +] + +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + +[[package]] +name = "packaging" +version = "23.0" +description = "Core utilities for Python packages" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, + {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, +] + +[[package]] +name = "pathspec" +version = "0.11.0" +description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pathspec-0.11.0-py3-none-any.whl", hash = "sha256:3a66eb970cbac598f9e5ccb5b2cf58930cd8e3ed86d393d541eaf2d8b1705229"}, + {file = "pathspec-0.11.0.tar.gz", hash = "sha256:64d338d4e0914e91c1792321e6907b5a593f1ab1851de7fc269557a21b30ebbc"}, +] + +[[package]] +name = "platformdirs" +version = "2.6.2" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "platformdirs-2.6.2-py3-none-any.whl", hash = "sha256:83c8f6d04389165de7c9b6f0c682439697887bca0aa2f1c87ef1826be3584490"}, + {file = "platformdirs-2.6.2.tar.gz", hash = "sha256:e1fea1fe471b9ff8332e229df3cb7de4f53eeea4998d3b6bfff542115e998bd2"}, +] + +[package.extras] +docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] + +[[package]] +name = "pluggy" +version = "1.0.0" +description = "plugin and hook calling mechanisms for python" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, + {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "proxmoxer" +version = "2.0.1" +description = "Python Wrapper for the Proxmox 2.x API (HTTP and SSH)" +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "proxmoxer-2.0.1-py3-none-any.whl", hash = "sha256:badb3095507e486b76dfda75177545dd85da608a3aef8590d362901253f10576"}, + {file = "proxmoxer-2.0.1.tar.gz", hash = "sha256:088923f1a81ee27631e88314c609bfe22b33d8a41271b5f02e86f996f837fe31"}, +] + +[[package]] +name = "pycodestyle" +version = "2.10.0" +description = "Python style guide checker" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pycodestyle-2.10.0-py2.py3-none-any.whl", hash = "sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610"}, + {file = "pycodestyle-2.10.0.tar.gz", hash = "sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053"}, +] + +[[package]] +name = "pycparser" +version = "2.21" +description = "C parser in Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, +] + +[[package]] +name = "pylint" +version = "2.15.0" +description = "python code static checker" +category = "dev" +optional = false +python-versions = ">=3.7.2" +files = [ + {file = "pylint-2.15.0-py3-none-any.whl", hash = "sha256:4b124affc198b7f7c9b5f9ab690d85db48282a025ef9333f51d2d7281b92a6c3"}, + {file = "pylint-2.15.0.tar.gz", hash = "sha256:4f3f7e869646b0bd63b3dfb79f3c0f28fc3d2d923ea220d52620fd625aed92b0"}, +] + +[package.dependencies] +astroid = ">=2.12.4,<=2.14.0-dev0" +colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} +dill = ">=0.2" +isort = ">=4.2.5,<6" +mccabe = ">=0.6,<0.8" +platformdirs = ">=2.2.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +tomlkit = ">=0.10.1" +typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} + +[package.extras] +spelling = ["pyenchant (>=3.2,<4.0)"] +testutils = ["gitpython (>3)"] + +[[package]] +name = "pyopenssl" +version = "23.0.0" +description = "Python wrapper module around the OpenSSL library" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pyOpenSSL-23.0.0-py3-none-any.whl", hash = "sha256:df5fc28af899e74e19fccb5510df423581047e10ab6f1f4ba1763ff5fde844c0"}, + {file = "pyOpenSSL-23.0.0.tar.gz", hash = "sha256:c1cc5f86bcacefc84dada7d31175cae1b1518d5f60d3d0bb595a67822a868a6f"}, +] + +[package.dependencies] +cryptography = ">=38.0.0,<40" + +[package.extras] +docs = ["sphinx (!=5.2.0,!=5.2.0.post0)", "sphinx-rtd-theme"] +test = ["flaky", "pretend", "pytest (>=3.0.1)"] + +[[package]] +name = "pytest" +version = "7.2.1" +description = "pytest: simple powerful testing with Python" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.2.1-py3-none-any.whl", hash = "sha256:c7c6ca206e93355074ae32f7403e8ea12163b1163c976fee7d4d84027c162be5"}, + {file = "pytest-7.2.1.tar.gz", hash = "sha256:d45e0952f3727241918b8fd0f376f5ff6b301cc0777c6f9a556935c92d8a7d42"}, +] + +[package.dependencies] +attrs = ">=19.2.0" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] + +[[package]] +name = "pytest-cov" +version = "4.0.0" +description = "Pytest plugin for measuring coverage." +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, + {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, +] + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] + +[[package]] +name = "pytest-mock" +version = "3.10.0" +description = "Thin-wrapper around the mock package for easier use with pytest" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-mock-3.10.0.tar.gz", hash = "sha256:fbbdb085ef7c252a326fd8cdcac0aa3b1333d8811f131bdcc701002e1be7ed4f"}, + {file = "pytest_mock-3.10.0-py3-none-any.whl", hash = "sha256:f4c973eeae0282963eb293eb173ce91b091a79c1334455acfac9ddee8a1c784b"}, +] + +[package.dependencies] +pytest = ">=5.0" + +[package.extras] +dev = ["pre-commit", "pytest-asyncio", "tox"] + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pyyaml" +version = "6.0" +description = "YAML parser and emitter for Python" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, + {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, + {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, + {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, + {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, + {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, + {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, + {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, + {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, + {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, + {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, + {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, + {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, + {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, + {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, + {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, + {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, + {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, +] + +[[package]] +name = "requests" +version = "2.28.2" +description = "Python HTTP for Humans." +category = "main" +optional = false +python-versions = ">=3.7, <4" +files = [ + {file = "requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"}, + {file = "requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<1.27" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "resolvelib" +version = "0.8.1" +description = "Resolve abstract dependencies into concrete ones" +category = "main" +optional = true +python-versions = "*" +files = [ + {file = "resolvelib-0.8.1-py2.py3-none-any.whl", hash = "sha256:d9b7907f055c3b3a2cfc56c914ffd940122915826ff5fb5b1de0c99778f4de98"}, + {file = "resolvelib-0.8.1.tar.gz", hash = "sha256:c6ea56732e9fb6fca1b2acc2ccc68a0b6b8c566d8f3e78e0443310ede61dbd37"}, +] + +[package.extras] +examples = ["html5lib", "packaging", "pygraphviz", "requests"] +lint = ["black", "flake8", "isort", "mypy", "types-requests"] +release = ["build", "towncrier", "twine"] +test = ["commentjson", "packaging", "pytest"] + +[[package]] +name = "ruff" +version = "0.0.230" +description = "An extremely fast Python linter, written in Rust." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.0.230-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:fcc31d02cebda0a85e2e13a44642aea7f84362cb4f589e2f6b864e3928e4a7db"}, + {file = "ruff-0.0.230-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:45a7f2c7155d520b8ca255a01235763d5c25fd5e7af055e50a78c6d91ece0ced"}, + {file = "ruff-0.0.230-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4eca8b185ab56cac67acc23287c3c8c62a0c0ffadc0787a3bef3a6e77eaed82f"}, + {file = "ruff-0.0.230-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ec2bcdb5040efd8082a3a98369eec4bdc5fd05f53cc6714cb2b725d557d4abe8"}, + {file = "ruff-0.0.230-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:26571aee2b93b60e47e44478f72a9787b387f752e85b85f176739bd91b27cfd1"}, + {file = "ruff-0.0.230-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4b69c9883c3e264f8bb2d52bdabb88b8d9672750ea05f33e0ff52532824bd5c5"}, + {file = "ruff-0.0.230-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b3dc88b83f200378a9b9c91036989f0285a10759514c42235ce02e5824ac8d0"}, + {file = "ruff-0.0.230-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:767716f008dd3a40ec2318396f648fda437c6968087a4526cde5879e382cf477"}, + {file = "ruff-0.0.230-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac27a0f9b96d9923cef7d911790a21a19b51aec0f08375ccc47ad735b1054d78"}, + {file = "ruff-0.0.230-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:729dfc7b7ad4f7d8761dc60c58f15372d6f5c2dd9b6c5952524f2bc3aec7de6a"}, + {file = "ruff-0.0.230-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ad086cf2e5fef274687121f673f0f9b60c8981ec07c2bb0448c459cbaef81bcb"}, + {file = "ruff-0.0.230-py3-none-musllinux_1_2_i686.whl", hash = "sha256:4feaed0978c24687133cd11c7380de20aa841f893e24430c735cc6c3faba4837"}, + {file = "ruff-0.0.230-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1d1046d0d43a0f24b2e9e61d76bb201b486ad02e9787d3432af43bd7d16f2c2e"}, + {file = "ruff-0.0.230-py3-none-win32.whl", hash = "sha256:4d627911c9ba57bcd2f2776f1c09a10d334db163cb5be8c892e7ec7b59ccf58c"}, + {file = "ruff-0.0.230-py3-none-win_amd64.whl", hash = "sha256:27fd4891a1d0642f5b2038ebf86f8169bc3d466964bdfaa0ce2a65149bc7cced"}, + {file = "ruff-0.0.230.tar.gz", hash = "sha256:a049f93af1057ac450e8c09559d44e371eda1c151b1b863c0013a1066fefddb0"}, +] + +[[package]] +name = "setuptools" +version = "67.0.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "setuptools-67.0.0-py3-none-any.whl", hash = "sha256:9d790961ba6219e9ff7d9557622d2fe136816a264dd01d5997cfc057d804853d"}, + {file = "setuptools-67.0.0.tar.gz", hash = "sha256:883131c5b6efa70b9101c7ef30b2b7b780a4283d5fc1616383cdf22c83cbefe6"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "dev" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "tomlkit" +version = "0.11.6" +description = "Style preserving TOML library" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "tomlkit-0.11.6-py3-none-any.whl", hash = "sha256:07de26b0d8cfc18f871aec595fda24d95b08fef89d147caa861939f37230bf4b"}, + {file = "tomlkit-0.11.6.tar.gz", hash = "sha256:71b952e5721688937fb02cf9d354dbcf0785066149d2855e44531ebdd2b65d73"}, +] + +[[package]] +name = "typing-extensions" +version = "4.4.0" +description = "Backported and Experimental Type Hints for Python 3.7+" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, + {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, +] + +[[package]] +name = "urllib3" +version = "1.26.14" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ + {file = "urllib3-1.26.14-py2.py3-none-any.whl", hash = "sha256:75edcdc2f7d85b137124a6c3c9fc3933cdeaa12ecb9a6a959f22797a0feca7e1"}, + {file = "urllib3-1.26.14.tar.gz", hash = "sha256:076907bf8fd355cde77728471316625a4d2f7e713c125f51953bb5b3eecf4f72"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[[package]] +name = "voluptuous" +version = "0.13.1" +description = "" +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "voluptuous-0.13.1-py3-none-any.whl", hash = "sha256:4b838b185f5951f2d6e8752b68fcf18bd7a9c26ded8f143f92d6d28f3921a3e6"}, + {file = "voluptuous-0.13.1.tar.gz", hash = "sha256:e8d31c20601d6773cb14d4c0f42aee29c6821bbd1018039aac7ac5605b489723"}, +] + +[[package]] +name = "wrapt" +version = "1.14.1" +description = "Module for decorators, wrappers and monkey patching." +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +files = [ + {file = "wrapt-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1"}, + {file = "wrapt-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320"}, + {file = "wrapt-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2"}, + {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4"}, + {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069"}, + {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310"}, + {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f"}, + {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656"}, + {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c"}, + {file = "wrapt-1.14.1-cp310-cp310-win32.whl", hash = "sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8"}, + {file = "wrapt-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d"}, + {file = "wrapt-1.14.1-cp35-cp35m-win32.whl", hash = "sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7"}, + {file = "wrapt-1.14.1-cp35-cp35m-win_amd64.whl", hash = "sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00"}, + {file = "wrapt-1.14.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4"}, + {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1"}, + {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1"}, + {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff"}, + {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d"}, + {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1"}, + {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569"}, + {file = "wrapt-1.14.1-cp36-cp36m-win32.whl", hash = "sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed"}, + {file = "wrapt-1.14.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471"}, + {file = "wrapt-1.14.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248"}, + {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68"}, + {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d"}, + {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77"}, + {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7"}, + {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015"}, + {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a"}, + {file = "wrapt-1.14.1-cp37-cp37m-win32.whl", hash = "sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853"}, + {file = "wrapt-1.14.1-cp37-cp37m-win_amd64.whl", hash = "sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c"}, + {file = "wrapt-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456"}, + {file = "wrapt-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f"}, + {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc"}, + {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1"}, + {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af"}, + {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b"}, + {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0"}, + {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57"}, + {file = "wrapt-1.14.1-cp38-cp38-win32.whl", hash = "sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5"}, + {file = "wrapt-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d"}, + {file = "wrapt-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383"}, + {file = "wrapt-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7"}, + {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86"}, + {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735"}, + {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b"}, + {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3"}, + {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3"}, + {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe"}, + {file = "wrapt-1.14.1-cp39-cp39-win32.whl", hash = "sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5"}, + {file = "wrapt-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb"}, + {file = "wrapt-1.14.1.tar.gz", hash = "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d"}, +] + +[[package]] +name = "yamllint" +version = "1.29.0" +description = "A linter for YAML files." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "yamllint-1.29.0-py3-none-any.whl", hash = "sha256:5153bf9f8205aa9dc6af6217e38bd4f5baf09d9a7c6f4ae1e23f90d9c00c49c5"}, + {file = "yamllint-1.29.0.tar.gz", hash = "sha256:66a755d5fbcbb8831f1a9568676329b5bac82c37995bcc9afd048b6459f9fa48"}, +] + +[package.dependencies] +pathspec = ">=0.5.3" +pyyaml = "*" +setuptools = "*" + +[[package]] +name = "yapf" +version = "0.32.0" +description = "A formatter for Python code." +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "yapf-0.32.0-py2.py3-none-any.whl", hash = "sha256:8fea849025584e486fd06d6ba2bed717f396080fd3cc236ba10cb97c4c51cf32"}, + {file = "yapf-0.32.0.tar.gz", hash = "sha256:a3f5085d37ef7e3e004c4ba9f9b3e40c54ff1901cd111f05145ae313a7c67d1b"}, +] + +[extras] +ansible = ["ansible-core"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.8.0" +content-hash = "98070d85ac9a8d2718daf9130e63de51881f16453a59a5100a799492cc5ecdb4" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..b0f9067 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,149 @@ +[tool.poetry] +authors = ["Robert Kaussow "] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "License :: OSI Approved :: MIT License", + "Intended Audience :: Developers", + "Intended Audience :: Information Technology", + "Intended Audience :: System Administrators", + "Natural Language :: English", + "Operating System :: POSIX", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Topic :: Utilities", + "Topic :: Software Development", + "Topic :: Software Development :: Documentation", +] +description = "Build environment for Ansible Collection." +license = "MIT" +name = "xoxys.general" +readme = "README.md" +repository = "https://gitea.rknet.org/ansible/xoxys.general" +version = "0.0.0" + +[tool.poetry.dependencies] +python = "^3.8.0" +ansible-core = { version = "<=2.14.0", optional = true } +pyopenssl = "23.0.0" +proxmoxer = "2.0.1" +hcloud = "1.18.2" + +[tool.poetry.extras] +ansible = ["ansible-core"] + +[tool.poetry.group.dev.dependencies] +ruff = "0.0.230" +pytest = "7.2.1" +pytest-mock = "3.10.0" +pytest-cov = "4.0.0" +toml = "0.10.2" +yapf = "0.32.0" +pycodestyle = "2.10.0" +yamllint = "1.29.0" +pylint = "2.15.0" +voluptuous = "0.13.1" + +[tool.pytest.ini_options] +addopts = "--cov --cov-report=xml:coverage.xml --cov-report=term --cov-append --no-cov-on-fail" +pythonpath = [ + "." +] +testpaths = [ + "tests", +] +filterwarnings = [ + "ignore::FutureWarning", + "ignore::DeprecationWarning", + "ignore:.*pep8.*:FutureWarning", +] + +[tool.coverage.run] +omit = ["**/tests/*"] + +[build-system] +build-backend = "poetry.core.masonry.api" +requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning"] + +[tool.ruff] +exclude = [ + ".git", + "__pycache__", + "build", + "dist", + "tests", + "*.pyc", + "*.egg-info", + ".cache", + ".eggs", + "env*", + "iptables_raw.py", +] +# Explanation of errors +# +# D102: Missing docstring in public method +# D103: Missing docstring in public function +# D105: Missing docstring in magic method +# D107: Missing docstring in __init__ +# D202: No blank lines allowed after function docstring +# D203: One blank line required before class docstring +# E402: Module level import not at top of file +# SIM105: Use `contextlib.suppress(Exception)` instead of try-except-pass +# C402: Unnecessary generator (rewrite as a `dict` comprehension) +# C408: Unnecessary `dict` call (rewrite as a literal) +# I001: Import block is un-sorted or un-formatted +# UP001: `__metaclass__ = type` is implied +# UP009: UTF-8 encoding declaration is unnecessary +# UP010: Unnecessary `__future__` imports `absolute_import`, `division`, `print_function` for target Python version +ignore = [ + "D102", + "D103", + "D105", + "D107", + "D202", + "D203", + "D212", + "E402", + "SIM105", + "C402", + "C408", + "I001", + "UP001", + "UP009", + "UP010", +] +line-length = 99 +select = [ + "D", + "E", + "F", + "Q", + "W", + "I", + "S", + "BLE", + "N", + "UP", + "B", + "A", + "C4", + "T20", + "SIM", + "RET", + "ARG", + "ERA", + "RUF", +] + +[tool.ruff.flake8-quotes] +inline-quotes = "double" + +[tool.yapf] +based_on_style = "google" +column_limit = 99 +dedent_closing_brackets = true +coalesce_brackets = true +split_before_logical_operator = true diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 2c9ce1c..0000000 --- a/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -ansible-core -pyopenssl -proxmoxer -hcloud diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index f3ceb6e..0000000 --- a/setup.cfg +++ /dev/null @@ -1,42 +0,0 @@ -[isort] -default_section = THIRDPARTY -sections = FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER -force_single_line = true -line_length = 99 -skip_glob = **/.venv*,**/venv/*,**/docs/*,**/inventory/*,**/modules/* - -[yapf] -based_on_style = google -column_limit = 99 -dedent_closing_brackets = true -coalesce_brackets = true -split_before_logical_operator = true - -[tool:pytest] -filterwarnings = - ignore::FutureWarning - ignore:.*collections.*:DeprecationWarning - ignore:.*pep8.*:FutureWarning - -[coverage:run] -omit = - **/test/* - **/.venv/* - -[flake8] -ignore = D101, D102, D103, D105, D107, D202, E402, W503, B902 -max-line-length = 99 -inline-quotes = double -exclude = - .git - .tox - __pycache__ - build - dist - test - *.pyc - *.egg-info - .cache - .eggs - env* - iptables_raw.py diff --git a/test/unit/plugins/inventory/__init__.py b/test/unit/plugins/inventory/__init__.py deleted file mode 100644 index 4ede8e6..0000000 --- a/test/unit/plugins/inventory/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# noqa diff --git a/test/unit/requirements.txt b/test/unit/requirements.txt deleted file mode 100644 index 9afe0a6..0000000 --- a/test/unit/requirements.txt +++ /dev/null @@ -1,11 +0,0 @@ -ansible - -# requirement for the proxmox modules -proxmoxer -requests - -# requirement for the corenetworks modules -corenetworks - -# requirement for the openssl_pkcs12 module -pyOpenSSL diff --git a/tests/config.yml b/tests/config.yml new file mode 100644 index 0000000..49b2a37 --- /dev/null +++ b/tests/config.yml @@ -0,0 +1,2 @@ +modules: + python_requires: ">=3.8" diff --git a/tests/unit/plugins/inventory/__init__.py b/tests/unit/plugins/inventory/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/plugins/inventory/test_proxmox.py b/tests/unit/plugins/inventory/test_proxmox.py similarity index 95% rename from test/unit/plugins/inventory/test_proxmox.py rename to tests/unit/plugins/inventory/test_proxmox.py index cb08524..9696aed 100644 --- a/test/unit/plugins/inventory/test_proxmox.py +++ b/tests/unit/plugins/inventory/test_proxmox.py @@ -1,10 +1,11 @@ """Test inventory plugin proxmox.""" -# -*- coding: utf-8 -*- # Copyright (c) 2020, Robert Kaussow # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + import pytest proxmox = pytest.importorskip("proxmoxer") @@ -58,7 +59,7 @@ def test_get_ip_address(inventory, mocker): inventory.client = mocker.MagicMock() inventory.client.nodes.return_value.get.return_value = networks - assert "10.0.0.1" == inventory._get_ip_address("qemu", None, None) + assert inventory._get_ip_address("qemu", None, None) == "10.0.0.1" def test_exclude(inventory, mocker):