diff --git a/.github/workflows/python-publish.yaml b/.github/workflows/python-publish.yaml new file mode 100644 index 0000000..e920962 --- /dev/null +++ b/.github/workflows/python-publish.yaml @@ -0,0 +1,29 @@ +# This workflow will upload a Python Package using Twine when a release is created +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Upload Python Package + +on: + release: + types: [published] + +permissions: + contents: read + +jobs: + deploy: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Build and publish to PyPI + uses: JRubics/poetry-publish@v1.17 + with: + pypi_token: ${{ secrets.PYPI_KEY }} # optional + repository_name: inventree_digikey_integration diff --git a/.github/workflows/python-test.yaml b/.github/workflows/python-test.yaml index 30ade77..a460523 100644 --- a/.github/workflows/python-test.yaml +++ b/.github/workflows/python-test.yaml @@ -1,4 +1,4 @@ -name: Pytest +name: Testing and Linting on: [pull_request] @@ -11,7 +11,7 @@ jobs: strategy: matrix: python-version: ["3.8", "3.9", "3.10", "3.11"] - + steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} @@ -19,11 +19,28 @@ jobs: with: python-version: ${{ matrix.python-version }} cache: 'pip' + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + virtualenvs-create: True + virtualenvs-in-project: True + installer-parallel: true + - name: Setup Cache + uses: actions/cache@v3 + with: + path: .venv + key: venv-${{ runner.os }}-${{ steps.full-python-version.outputs.version }}-${{ hashFiles('**/poetry.lock') }} - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt + run: poetry install + if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' - name: Pytest run: | - pip install pytest pytest-cov - python -m pytest --cov=src --cov-report=xml --cov-report=html --junitxml=junit/test-results.xml + poetry run pytest --junitxml=junit/test-results.xml + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: psf/black@stable + with: + options: "--check --verbose" + src: "inventree_digikey tests" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..a962eb5 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,20 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v3.2.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files +- repo: https://github.com/psf/black + rev: 22.10.0 + hooks: + - id: black +- repo: https://github.com/python-poetry/poetry + rev: '1.7.0' + hooks: + - id: poetry-check + - id: poetry-lock + - id: poetry-install diff --git a/README.md b/README.md index 530c436..496913e 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,22 @@ ## Setup -`pip install -r requirements.txt` +### Installation -Put a config.ini file in `inventree_digikey/` +#### Install from Pypi -config.ini has the following template +`pip install inventree_digikey_integration` + +#### Install from source + +1. Install [poetry](https://python-poetry.org/docs/#installation) +2. Clone the repo `git clone git@github.com:EUdds/digikey-inventree-integration.git` +3. `cd digikey-inventree-integration` +4. `poetry install` + +### Configuration + +Create a config.ini file according to the template and specify it's location with the `-c ` flag ``` [DIGIKEY_API] @@ -17,3 +28,28 @@ CLIENT_SECRET= URL= USER= PASSWORD= +``` + + +## Usage + +Invoke the cli by running `import_digikey_parts` + +```bash +usage: import_digikey_parts [-h] [-y] [-c CONFIG] query_numbers [query_numbers ...] + +Import Digikey part numbers into InvenTree + +positional arguments: + query_numbers Part number(s) to import + +optional arguments: + -h, --help show this help message and exit + -y, --yes Bypass user prompts and assume "yes" + -c CONFIG, --config CONFIG + Path to config file +``` + +## Testing + +Run the test suite by running `poetry run pytest` \ No newline at end of file diff --git a/inventree_digikey/ConfigReader.py b/inventree_digikey_integration/ConfigReader.py similarity index 57% rename from inventree_digikey/ConfigReader.py rename to inventree_digikey_integration/ConfigReader.py index 9a040d3..973d407 100644 --- a/inventree_digikey/ConfigReader.py +++ b/inventree_digikey_integration/ConfigReader.py @@ -3,6 +3,7 @@ from pathlib import Path from inventree.api import InvenTreeAPI + class ConfigReader: """ Manage global configuration settings and Inventree instance @@ -29,43 +30,59 @@ def __init__(self, config_file=None): if config_file: self.read_config(config_file) - + def read_config(self, config_file: Path) -> None: """ Read configuration from a file """ self.config.read(config_file) - self.digikey_client_id = self.config['DIGIKEY_API']['CLIENT_ID'] - self.digikey_client_secret = self.config['DIGIKEY_API']['CLIENT_SECRET'] - if 'SANDBOX' in self.config['DIGIKEY_API']: - self.digikey_client_sandbox = self.config['DIGIKEY_API'].getboolean('SANDBOX') - if 'STORAGE_PATH' in self.config['DIGIKEY_API']: - self.digikey_storage_path = self.config['DIGIKEY_API']['STORAGE_PATH'] - self._inventree_url = self.config['INVENTREE_API']['URL'] - self._inventree_username = self.config['INVENTREE_API']['USER'] - self._inventree_password = self.config['INVENTREE_API']['PASSWORD'] - + self.digikey_client_id = self.config["DIGIKEY_API"]["CLIENT_ID"] + self.digikey_client_secret = self.config["DIGIKEY_API"]["CLIENT_SECRET"] + if "SANDBOX" in self.config["DIGIKEY_API"]: + self.digikey_client_sandbox = self.config["DIGIKEY_API"].getboolean( + "SANDBOX" + ) + if "STORAGE_PATH" in self.config["DIGIKEY_API"]: + self.digikey_storage_path = self.config["DIGIKEY_API"]["STORAGE_PATH"] + self._inventree_url = self.config["INVENTREE_API"]["URL"] + self._inventree_username = self.config["INVENTREE_API"]["USER"] + self._inventree_password = self.config["INVENTREE_API"]["PASSWORD"] + @property def inventree_api(self): - if self._inventree_api is None or self._reinit_api: # Allows us to reinit the api if the config changes - if self.inventree_url and self.inventree_username and self.inventree_password: - try: - api = InvenTreeAPI(self.inventree_url, username=self.inventree_username, password=self.inventree_password) + if ( + self._inventree_api is None or self._reinit_api + ): # Allows us to reinit the api if the config changes + if ( + self.inventree_url + and self.inventree_username + and self.inventree_password + ): + try: + api = InvenTreeAPI( + self.inventree_url, + username=self.inventree_username, + password=self.inventree_password, + ) except: - print("Error: Could not connect to Inventree API") #FIXME - + print("Error: Could not connect to Inventree API") # FIXME + self._reinit_api = False self._inventree_api = api return api else: - raise AttributeError("Cannot init inventree_api without inventree_[url|username|password] set") + raise AttributeError( + "Cannot init inventree_api without inventree_[url|username|password] set" + ) else: return self._inventree_api - + @inventree_api.setter def inventree_api(self, value): - raise AttributeError("Cannot set inventree_api directly. Use inventree_[url|username|password] instead") - + raise AttributeError( + "Cannot set inventree_api directly. Use inventree_[url|username|password] instead" + ) + @property def inventree_url(self): return self._inventree_url @@ -73,21 +90,21 @@ def inventree_url(self): @property def inventree_username(self): return self._inventree_username - + @property def inventree_password(self): return self._inventree_password - + @inventree_url.setter def inventree_url(self, value): self._reinit_api = True self._inventree_url = value - + @inventree_username.setter def inventree_username(self, value): self._reinit_api = True self._inventree_username = value - + @inventree_password.setter def inventree_password(self, value): self._reinit_api = True diff --git a/inventree_digikey/Digikey.py b/inventree_digikey_integration/Digikey.py similarity index 79% rename from inventree_digikey/Digikey.py rename to inventree_digikey_integration/Digikey.py index 43ba127..c5482d8 100644 --- a/inventree_digikey/Digikey.py +++ b/inventree_digikey_integration/Digikey.py @@ -1,10 +1,11 @@ from digikey import status_salesorder_id -import digikey # have to use digikey.product_details for monkeypatch testing +import digikey # have to use digikey.product_details for monkeypatch testing import os from pathlib import Path from .ConfigReader import ConfigReader + class DigiPart: def __init__(self, api_value): self.name = None @@ -20,7 +21,6 @@ def __init__(self, api_value): self.picture = None self.thumbnail = None - def injest_api(self, prompt=True): self.manufacturer = self.raw_value.manufacturer.value self.mfg_part_num = self.raw_value.manufacturer_part_number @@ -31,7 +31,7 @@ def injest_api(self, prompt=True): for raw_param in self.raw_value.parameters: cleaned_param = (raw_param.parameter, raw_param.value) self.parameters.append(cleaned_param) - + if prompt: self.prompt_part_name() else: @@ -48,20 +48,24 @@ def prompt_part_name(self): name = input("> ") self.name = name - def _extract_picture(self): for media in self.raw_value.media_links: print(media.media_type) if "Product Photos" in media.media_type: self.picture = "%s" % media.url - + @staticmethod def _set_environment(config): - if config.digikey_client_id and config.digikey_client_secret and config.digikey_client_sandbox and config.digikey_storage_path: - os.environ['DIGIKEY_CLIENT_ID'] = config.digikey_client_id - os.environ['DIGIKEY_CLIENT_SECRET'] = config.digikey_client_secret - os.environ['DIGIKEY_CLIENT_SANDBOX'] = config.digikey_client_sandbox - os.environ['DIGIKEY_STORAGE_PATH'] = config.digikey_storage_path + if ( + config.digikey_client_id + and config.digikey_client_secret + and config.digikey_client_sandbox + and config.digikey_storage_path + ): + os.environ["DIGIKEY_CLIENT_ID"] = config.digikey_client_id + os.environ["DIGIKEY_CLIENT_SECRET"] = config.digikey_client_secret + os.environ["DIGIKEY_CLIENT_SANDBOX"] = config.digikey_client_sandbox + os.environ["DIGIKEY_STORAGE_PATH"] = config.digikey_storage_path else: errmsg = "Cannot set environment variables for digikey module. Please set " if not config.digikey_client_id: @@ -72,11 +76,17 @@ def _set_environment(config): errmsg += "DIGIKEY_CLIENT_SANDBOX " if not config.digikey_storage_path: errmsg += "DIGIKEY_STORAGE_PATH " - + raise AttributeError(errmsg) - + @classmethod - def from_digikey_part_number(cls, partnum: str, config: ConfigReader, injest_api_automatically=True, prompt=False) -> 'DigiPart': + def from_digikey_part_number( + cls, + partnum: str, + config: ConfigReader, + injest_api_automatically=True, + prompt=False, + ) -> "DigiPart": cls._set_environment(config) raw = digikey.product_details(partnum) if injest_api_automatically: diff --git a/inventree_digikey/ImageManager.py b/inventree_digikey_integration/ImageManager.py similarity index 81% rename from inventree_digikey/ImageManager.py rename to inventree_digikey_integration/ImageManager.py index 183eb4e..9301c3a 100644 --- a/inventree_digikey/ImageManager.py +++ b/inventree_digikey_integration/ImageManager.py @@ -6,12 +6,12 @@ from pathlib import Path -class ImageManager: +class ImageManager: cache_path: Path = Path(__file__).resolve().parent / "cache" @classmethod - def get_image(cls, url:str) -> str: + def get_image(cls, url: str) -> str: """ Gets an image given an url returns a filepath @@ -43,13 +43,19 @@ def clean_cache(cls): f.unlink() def _filename_generator(size=6) -> str: - return "".join(random.choice(string.ascii_lowercase + string.digits) for _ in range(size)) + ".jpg" + return ( + "".join( + random.choice(string.ascii_lowercase + string.digits) + for _ in range(size) + ) + + ".jpg" + ) @classmethod - def _download_image(cls, url:str) -> str: + def _download_image(cls, url: str) -> str: print(f"Trying URL {url}") - escaped_url = quote(url, safe=':/') + escaped_url = quote(url, safe=":/") parsed_url = urlparse(escaped_url) @@ -59,20 +65,20 @@ def _download_image(cls, url:str) -> str: path = parsed_url.path # Create an HTTP connection to the server based on the protocol - if protocol == 'http': + if protocol == "http": conn = http.client.HTTPConnection(server_host) - elif protocol == 'https': + elif protocol == "https": conn = http.client.HTTPSConnection(server_host) else: print("Unsupported protocol:", protocol) exit(1) # Send an HTTP GET request with custom headers - conn.request('GET', path) + conn.request("GET", path) # Get the response response = conn.getresponse() - + if not response.status == 200: print(f"ERROR: Request code is {response.status}") return -1 @@ -80,7 +86,7 @@ def _download_image(cls, url:str) -> str: filename = cls._filename_generator() filepath = cls.cache_path / filename - with open(filepath, 'wb') as handler: + with open(filepath, "wb") as handler: while True: chunk = response.read(1024) if not chunk: @@ -88,4 +94,3 @@ def _download_image(cls, url:str) -> str: handler.write(chunk) return str(filepath) - diff --git a/inventree_digikey/Inventree.py b/inventree_digikey_integration/Inventree.py similarity index 53% rename from inventree_digikey/Inventree.py rename to inventree_digikey_integration/Inventree.py index a2f4218..3bcd090 100644 --- a/inventree_digikey/Inventree.py +++ b/inventree_digikey_integration/Inventree.py @@ -5,10 +5,14 @@ from .ImageManager import ImageManager from .ConfigReader import ConfigReader + def import_digikey_part(partnum: str, prompt=False): - dkpart = DigiPart.from_digikey_part_number(partnum, injest_api_automatically=True, prompt=prompt) + dkpart = DigiPart.from_digikey_part_number( + partnum, injest_api_automatically=True, prompt=prompt + ) return add_digikey_part(dkpart) + def add_digikey_part(dkpart: DigiPart, config: ConfigReader): dk = get_digikey_supplier(config) inv_part = create_inventree_part(dkpart, config) @@ -17,32 +21,40 @@ def add_digikey_part(dkpart: DigiPart, config: ConfigReader): base_pk = int(inv_part.pk) mfg = find_manufacturer(dkpart, config) - ManufacturerPart.create(config.inventree_api, { - 'part': base_pk, - 'supplier': dk.pk, - 'MPN': dkpart.mfg_part_num, - 'manufacturer': mfg.pk - }) + ManufacturerPart.create( + config.inventree_api, + { + "part": base_pk, + "supplier": dk.pk, + "MPN": dkpart.mfg_part_num, + "manufacturer": mfg.pk, + }, + ) - return SupplierPart.create(config.inventree_api, { - "part":base_pk, + return SupplierPart.create( + config.inventree_api, + { + "part": base_pk, "supplier": dk.pk, "SKU": dkpart.digi_part_num, "manufacturer": mfg.pk, "description": dkpart.description, - "link": dkpart.link - }) - + "link": dkpart.link, + }, + ) def get_digikey_supplier(config: ConfigReader): dk = Company.list(config.inventree_api, name="Digikey") if len(dk) == 0: - dk = Company.create(config.inventree_api, { - 'name': 'Digikey', - 'is_supplier': True, - 'description': 'Electronics Supply Store' - }) + dk = Company.create( + config.inventree_api, + { + "name": "Digikey", + "is_supplier": True, + "description": "Electronics Supply Store", + }, + ) return dk else: return dk[0] @@ -50,61 +62,79 @@ def get_digikey_supplier(config: ConfigReader): def create_inventree_part(dkpart: DigiPart, config: ConfigReader): category = find_category(config) - possible_parts = Part.list(config.inventree_api, name=dkpart.name, description=dkpart.description) + possible_parts = Part.list( + config.inventree_api, name=dkpart.name, description=dkpart.description + ) if len(possible_parts) > 0: part_names = [p.name.lower() for p in possible_parts] if dkpart.name.lower() in part_names: print("Part already exists") return -1 - part = Part.create(config.inventree_api, { - 'name': dkpart.name, - 'description': dkpart.description, - 'category': category, - 'active': True, - 'virtual': False, - 'component': True, - 'purchaseable': 1 - }) + part = Part.create( + config.inventree_api, + { + "name": dkpart.name, + "description": dkpart.description, + "category": category, + "active": True, + "virtual": False, + "component": True, + "purchaseable": 1, + }, + ) upload_picture(dkpart, part) return part def find_category(config): categories = PartCategory.list(config.inventree_api) - print("="*20) + print("=" * 20) print(f"Choose a category") for idx, category in enumerate(categories): - print("\t%d %s" %(idx, category.name)) - print("="*20) + print("\t%d %s" % (idx, category.name)) + print("=" * 20) idx = int(input("> ")) return categories[idx].pk def find_manufacturer(dkpart: DigiPart, config: ConfigReader): - possible_manufacturers = Company.list(config.inventree_api, name=dkpart.manufacturer) + possible_manufacturers = Company.list( + config.inventree_api, name=dkpart.manufacturer + ) if len(possible_manufacturers) == 0: mfg = create_manufacturer(dkpart.manufacturer, config) return mfg else: - print("="*20) + print("=" * 20) print("Choose a manufacturer") for idx, mfg in enumerate(possible_manufacturers): - print("\t%d %s" %(idx, mfg.name, )) - print("="*20) + print( + "\t%d %s" + % ( + idx, + mfg.name, + ) + ) + print("=" * 20) idx = int(input("> ")) return possible_manufacturers[idx] -def create_manufacturer(name: str, config: ConfigReader, is_supplier: bool=False): - mfg = Company.create(config.inventree_api, { - 'name': name, - 'is_manufacturer': True, - 'is_supplier': is_supplier, - 'description': name - }) + +def create_manufacturer(name: str, config: ConfigReader, is_supplier: bool = False): + mfg = Company.create( + config.inventree_api, + { + "name": name, + "is_manufacturer": True, + "is_supplier": is_supplier, + "description": name, + }, + ) return mfg + def upload_picture(dkpart: DigiPart, invPart): if dkpart.picture is not None: img_file = ImageManager.get_image(dkpart.picture) invPart.uploadImage(img_file) - ImageManager.clean_cache() \ No newline at end of file + ImageManager.clean_cache() diff --git a/inventree_digikey/__init__.py b/inventree_digikey_integration/__init__.py similarity index 100% rename from inventree_digikey/__init__.py rename to inventree_digikey_integration/__init__.py diff --git a/inventree_digikey/__main__.py b/inventree_digikey_integration/__main__.py similarity index 59% rename from inventree_digikey/__main__.py rename to inventree_digikey_integration/__main__.py index 9baf5b2..abc74f4 100644 --- a/inventree_digikey/__main__.py +++ b/inventree_digikey_integration/__main__.py @@ -8,17 +8,34 @@ def parse_args(args): - parser = argparse.ArgumentParser(description='Import Digikey part numbers into InvenTree') + parser = argparse.ArgumentParser( + description="Import Digikey part numbers into InvenTree" + ) # Add an optional '-y' flag to bypass prompting - parser.add_argument('-y', "--yes", action='store_true', help='Bypass user prompts and assume "yes"', default=False) - parser.add_argument("-c", "--config", type=Path, help="Path to config file", default=DEFAULT_CONFIG_PATH) + parser.add_argument( + "-y", + "--yes", + action="store_true", + help='Bypass user prompts and assume "yes"', + default=False, + ) + parser.add_argument( + "-c", + "--config", + type=Path, + help="Path to config file", + default=DEFAULT_CONFIG_PATH, + ) # Add the 'part_number' argument as the last item on the command line - parser.add_argument('query_numbers', type=str, help='Part number(s) to import', nargs='*') + parser.add_argument( + "query_numbers", type=str, help="Part number(s) to import", nargs="+" + ) return parser.parse_args(args) + def main(): args = parse_args(sys.argv[1:]) if len(args.query_numbers) == 0: @@ -31,5 +48,6 @@ def main(): for num in args.query_number: import_digikey_part(num, not args.yes) + if __name__ == "__main__": main() diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..4b0afc9 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,802 @@ +# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. + +[[package]] +name = "black" +version = "23.12.0" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.8" +files = [ + {file = "black-23.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:67f19562d367468ab59bd6c36a72b2c84bc2f16b59788690e02bbcb140a77175"}, + {file = "black-23.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bbd75d9f28a7283b7426160ca21c5bd640ca7cd8ef6630b4754b6df9e2da8462"}, + {file = "black-23.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:593596f699ca2dcbbbdfa59fcda7d8ad6604370c10228223cd6cf6ce1ce7ed7e"}, + {file = "black-23.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:12d5f10cce8dc27202e9a252acd1c9a426c83f95496c959406c96b785a92bb7d"}, + {file = "black-23.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e73c5e3d37e5a3513d16b33305713237a234396ae56769b839d7c40759b8a41c"}, + {file = "black-23.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ba09cae1657c4f8a8c9ff6cfd4a6baaf915bb4ef7d03acffe6a2f6585fa1bd01"}, + {file = "black-23.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ace64c1a349c162d6da3cef91e3b0e78c4fc596ffde9413efa0525456148873d"}, + {file = "black-23.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:72db37a2266b16d256b3ea88b9affcdd5c41a74db551ec3dd4609a59c17d25bf"}, + {file = "black-23.12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fdf6f23c83078a6c8da2442f4d4eeb19c28ac2a6416da7671b72f0295c4a697b"}, + {file = "black-23.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39dda060b9b395a6b7bf9c5db28ac87b3c3f48d4fdff470fa8a94ab8271da47e"}, + {file = "black-23.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7231670266ca5191a76cb838185d9be59cfa4f5dd401b7c1c70b993c58f6b1b5"}, + {file = "black-23.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:193946e634e80bfb3aec41830f5d7431f8dd5b20d11d89be14b84a97c6b8bc75"}, + {file = "black-23.12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bcf91b01ddd91a2fed9a8006d7baa94ccefe7e518556470cf40213bd3d44bbbc"}, + {file = "black-23.12.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:996650a89fe5892714ea4ea87bc45e41a59a1e01675c42c433a35b490e5aa3f0"}, + {file = "black-23.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdbff34c487239a63d86db0c9385b27cdd68b1bfa4e706aa74bb94a435403672"}, + {file = "black-23.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:97af22278043a6a1272daca10a6f4d36c04dfa77e61cbaaf4482e08f3640e9f0"}, + {file = "black-23.12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ead25c273adfad1095a8ad32afdb8304933efba56e3c1d31b0fee4143a1e424a"}, + {file = "black-23.12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c71048345bdbced456cddf1622832276d98a710196b842407840ae8055ade6ee"}, + {file = "black-23.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a832b6e00eef2c13b3239d514ea3b7d5cc3eaa03d0474eedcbbda59441ba5d"}, + {file = "black-23.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:6a82a711d13e61840fb11a6dfecc7287f2424f1ca34765e70c909a35ffa7fb95"}, + {file = "black-23.12.0-py3-none-any.whl", hash = "sha256:a7c07db8200b5315dc07e331dda4d889a56f6bf4db6a9c2a526fa3166a81614f"}, + {file = "black-23.12.0.tar.gz", hash = "sha256:330a327b422aca0634ecd115985c1c7fd7bdb5b5a2ef8aa9888a82e2ebe9437a"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "certauth" +version = "1.3.0" +description = "Simple Certificate Authority for MITM proxies" +optional = false +python-versions = "*" +files = [ + {file = "certauth-1.3.0-py2.py3-none-any.whl", hash = "sha256:f84b8c7075d0e445614d5ec4662056511453f19228cf4fcf8278cccae17b316b"}, + {file = "certauth-1.3.0.tar.gz", hash = "sha256:7862d5deff0b33d2fb28d36861ba63d91c82d700bfdfc4bd848a8711ca72b8fb"}, +] + +[package.dependencies] +pyopenssl = "*" +tldextract = "*" + +[[package]] +name = "certifi" +version = "2023.11.17" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, + {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, +] + +[[package]] +name = "cffi" +version = "1.16.0" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, + {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, + {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, + {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, + {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, + {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, + {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, + {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, + {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, + {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, + {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, + {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, + {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, + {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, +] + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "cfgv" +version = "3.4.0" +description = "Validate configuration and produce human readable error messages." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, + {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +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 = "cryptography" +version = "41.0.7" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +optional = false +python-versions = ">=3.7" +files = [ + {file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:3c78451b78313fa81607fa1b3f1ae0a5ddd8014c38a02d9db0616133987b9cdf"}, + {file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:928258ba5d6f8ae644e764d0f996d61a8777559f72dfeb2eea7e2fe0ad6e782d"}, + {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a1b41bc97f1ad230a41657d9155113c7521953869ae57ac39ac7f1bb471469a"}, + {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:841df4caa01008bad253bce2a6f7b47f86dc9f08df4b433c404def869f590a15"}, + {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5429ec739a29df2e29e15d082f1d9ad683701f0ec7709ca479b3ff2708dae65a"}, + {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:43f2552a2378b44869fe8827aa19e69512e3245a219104438692385b0ee119d1"}, + {file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:af03b32695b24d85a75d40e1ba39ffe7db7ffcb099fe507b39fd41a565f1b157"}, + {file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:49f0805fc0b2ac8d4882dd52f4a3b935b210935d500b6b805f321addc8177406"}, + {file = "cryptography-41.0.7-cp37-abi3-win32.whl", hash = "sha256:f983596065a18a2183e7f79ab3fd4c475205b839e02cbc0efbbf9666c4b3083d"}, + {file = "cryptography-41.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:90452ba79b8788fa380dfb587cca692976ef4e757b194b093d845e8d99f612f2"}, + {file = "cryptography-41.0.7-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:079b85658ea2f59c4f43b70f8119a52414cdb7be34da5d019a77bf96d473b960"}, + {file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:b640981bf64a3e978a56167594a0e97db71c89a479da8e175d8bb5be5178c003"}, + {file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e3114da6d7f95d2dee7d3f4eec16dacff819740bbab931aff8648cb13c5ff5e7"}, + {file = "cryptography-41.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d5ec85080cce7b0513cfd233914eb8b7bbd0633f1d1703aa28d1dd5a72f678ec"}, + {file = "cryptography-41.0.7-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7a698cb1dac82c35fcf8fe3417a3aaba97de16a01ac914b89a0889d364d2f6be"}, + {file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:37a138589b12069efb424220bf78eac59ca68b95696fc622b6ccc1c0a197204a"}, + {file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:68a2dec79deebc5d26d617bfdf6e8aab065a4f34934b22d3b5010df3ba36612c"}, + {file = "cryptography-41.0.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:09616eeaef406f99046553b8a40fbf8b1e70795a91885ba4c96a70793de5504a"}, + {file = "cryptography-41.0.7-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48a0476626da912a44cc078f9893f292f0b3e4c739caf289268168d8f4702a39"}, + {file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c7f3201ec47d5207841402594f1d7950879ef890c0c495052fa62f58283fde1a"}, + {file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c5ca78485a255e03c32b513f8c2bc39fedb7f5c5f8535545bdc223a03b24f248"}, + {file = "cryptography-41.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d6c391c021ab1f7a82da5d8d0b3cee2f4b2c455ec86c8aebbc84837a631ff309"}, + {file = "cryptography-41.0.7.tar.gz", hash = "sha256:13f93ce9bea8016c253b34afc6bd6a75993e5c40672ed5405a9c832f0d4a00bc"}, +] + +[package.dependencies] +cffi = ">=1.12" + +[package.extras] +docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] +docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] +nox = ["nox"] +pep8test = ["black", "check-sdist", "mypy", "ruff"] +sdist = ["build"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test-randomorder = ["pytest-randomly"] + +[[package]] +name = "digikey-api" +version = "1.0.0" +description = "Python client for Digikey API" +optional = false +python-versions = "*" +files = [ + {file = "digikey-api-1.0.0.tar.gz", hash = "sha256:18bf4b7f5c69f83d1f717d3b70df68579353c40225c99ed5b9554af6f148e41b"}, + {file = "digikey_api-1.0.0-py3-none-any.whl", hash = "sha256:3e5c825aa17a61b1c79df0d3ec7162bbd298f0b655f478cd4b0534bf0a68138a"}, +] + +[package.dependencies] +certauth = ">=1.3.0" +inflection = ">=0.3.1" +requests = ">=2.22.0" +retrying = ">=1.3.3" +urllib3 = ">=1.25.3" + +[[package]] +name = "distlib" +version = "0.3.8" +description = "Distribution utilities" +optional = false +python-versions = "*" +files = [ + {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, + {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.2.0" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "filelock" +version = "3.13.1" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.8" +files = [ + {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, + {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] +typing = ["typing-extensions (>=4.8)"] + +[[package]] +name = "identify" +version = "2.5.33" +description = "File identification library for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "identify-2.5.33-py2.py3-none-any.whl", hash = "sha256:d40ce5fcd762817627670da8a7d8d8e65f24342d14539c59488dc603bf662e34"}, + {file = "identify-2.5.33.tar.gz", hash = "sha256:161558f9fe4559e1557e1bff323e8631f6a0e4837f7497767c1782832f16b62d"}, +] + +[package.extras] +license = ["ukkonen"] + +[[package]] +name = "idna" +version = "3.6" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, +] + +[[package]] +name = "inflection" +version = "0.5.1" +description = "A port of Ruby on Rails inflector to Python" +optional = false +python-versions = ">=3.5" +files = [ + {file = "inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"}, + {file = "inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417"}, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +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 = "inventree" +version = "0.13.2" +description = "Python interface for InvenTree inventory management system" +optional = false +python-versions = ">=3.8" +files = [ + {file = "inventree-0.13.2-py2.py3-none-any.whl", hash = "sha256:7d104d68ee96323bdf737ca25bcdb78bc24e8a0d3393bade35b6c4097edda5f2"}, + {file = "inventree-0.13.2.tar.gz", hash = "sha256:e1f45b9e84522221b4ecbfacd4cf81a36195ba9d4cf489a94c775b24c8fae6ce"}, +] + +[package.dependencies] +requests = ">=2.27.0" + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "nodeenv" +version = "1.8.0" +description = "Node.js virtual environment builder" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +files = [ + {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, + {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, +] + +[package.dependencies] +setuptools = "*" + +[[package]] +name = "packaging" +version = "23.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "platformdirs" +version = "4.1.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, + {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, +] + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] + +[[package]] +name = "pluggy" +version = "1.3.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, + {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pre-commit" +version = "3.5.0" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pre_commit-3.5.0-py2.py3-none-any.whl", hash = "sha256:841dc9aef25daba9a0238cd27984041fa0467b4199fc4852e27950664919f660"}, + {file = "pre_commit-3.5.0.tar.gz", hash = "sha256:5804465c675b659b0862f07907f96295d490822a450c4c40e747d0b1c6ebcb32"}, +] + +[package.dependencies] +cfgv = ">=2.0.0" +identify = ">=1.0.0" +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +virtualenv = ">=20.10.0" + +[[package]] +name = "pycparser" +version = "2.21" +description = "C parser in Python" +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 = "pyopenssl" +version = "23.3.0" +description = "Python wrapper module around the OpenSSL library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pyOpenSSL-23.3.0-py3-none-any.whl", hash = "sha256:6756834481d9ed5470f4a9393455154bc92fe7a64b7bc6ee2c804e78c52099b2"}, + {file = "pyOpenSSL-23.3.0.tar.gz", hash = "sha256:6b2cba5cc46e822750ec3e5a81ee12819850b11303630d575e98108a079c2b12"}, +] + +[package.dependencies] +cryptography = ">=41.0.5,<42" + +[package.extras] +docs = ["sphinx (!=5.2.0,!=5.2.0.post0,!=7.2.5)", "sphinx-rtd-theme"] +test = ["flaky", "pretend", "pytest (>=3.0.1)"] + +[[package]] +name = "pytest" +version = "7.4.3" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, + {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, +] + +[package.dependencies] +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", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "requests-file" +version = "1.5.1" +description = "File transport adapter for Requests" +optional = false +python-versions = "*" +files = [ + {file = "requests-file-1.5.1.tar.gz", hash = "sha256:07d74208d3389d01c38ab89ef403af0cfec63957d53a0081d8eca738d0247d8e"}, + {file = "requests_file-1.5.1-py2.py3-none-any.whl", hash = "sha256:dfe5dae75c12481f68ba353183c53a65e6044c923e64c24b2209f6c7570ca953"}, +] + +[package.dependencies] +requests = ">=1.0.0" +six = "*" + +[[package]] +name = "retrying" +version = "1.3.4" +description = "Retrying" +optional = false +python-versions = "*" +files = [ + {file = "retrying-1.3.4-py3-none-any.whl", hash = "sha256:8cc4d43cb8e1125e0ff3344e9de678fefd85db3b750b81b2240dc0183af37b35"}, + {file = "retrying-1.3.4.tar.gz", hash = "sha256:345da8c5765bd982b1d1915deb9102fd3d1f7ad16bd84a9700b85f64d24e8f3e"}, +] + +[package.dependencies] +six = ">=1.7.0" + +[[package]] +name = "setuptools" +version = "69.0.2" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "setuptools-69.0.2-py3-none-any.whl", hash = "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"}, + {file = "setuptools-69.0.2.tar.gz", hash = "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +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 = "tldextract" +version = "5.1.1" +description = "Accurately separates a URL's subdomain, domain, and public suffix, using the Public Suffix List (PSL). By default, this includes the public ICANN TLDs and their exceptions. You can optionally support the Public Suffix List's private domains as well." +optional = false +python-versions = ">=3.8" +files = [ + {file = "tldextract-5.1.1-py3-none-any.whl", hash = "sha256:b9c4510a8766d377033b6bace7e9f1f17a891383ced3c5d50c150f181e9e1cc2"}, + {file = "tldextract-5.1.1.tar.gz", hash = "sha256:9b6dbf803cb5636397f0203d48541c0da8ba53babaf0e8a6feda2d88746813d4"}, +] + +[package.dependencies] +filelock = ">=3.0.8" +idna = "*" +requests = ">=2.1.0" +requests-file = ">=1.4" + +[package.extras] +testing = ["black", "mypy", "pytest", "pytest-gitignore", "pytest-mock", "responses", "ruff", "tox", "types-filelock", "types-requests"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +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 = "typing-extensions" +version = "4.9.0" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, + {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, +] + +[[package]] +name = "urllib3" +version = "2.1.0" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.8" +files = [ + {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, + {file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "virtualenv" +version = "20.25.0" +description = "Virtual Python Environment builder" +optional = false +python-versions = ">=3.7" +files = [ + {file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3"}, + {file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b"}, +] + +[package.dependencies] +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +platformdirs = ">=3.9.1,<5" + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.8" +content-hash = "73ddc9d1024a94b2b4942f540908956997283a355c416ec6abd288207782e36d" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..5232d18 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,25 @@ +[tool.poetry] +name = "inventree_digikey_integration" +version = "1.0.0" +description = "A CLI to import Digikey parts into an Inventree instance" +authors = ["Eric Udlis "] +license = "MIT" +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.8" +inventree = "^0.13.1" +digikey-api = "^1.0.0" + + +[tool.poetry.group.dev.dependencies] +pytest = "^7.4.3" +black = "^23.11.0" +pre-commit = "^3.5.0" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" + +[tool.poetry.scripts] +import_digikey_parts = "inventree_digikey_integration.__main__:main" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index f2e2dc5..0000000 --- a/requirements.txt +++ /dev/null @@ -1,50 +0,0 @@ -appdirs==1.4.3 -CacheControl==0.12.6 -certauth==1.3.0 -certifi==2019.11.28 -cffi==1.14.5 -chardet==3.0.4 -charset-normalizer==3.3.2 -colorama==0.4.3 -contextlib2==0.6.0 -coreapi==2.3.3 -coreschema==0.0.4 -cryptography==3.4.7 -digikey-api==1.0.0 -distlib==0.3.0 -distro==1.4.0 -exceptiongroup==1.2.0 -fake-useragent==0.1.11 -filelock==3.0.12 -html5lib==1.0.1 -idna==2.8 -inflection==0.5.1 -iniconfig==2.0.0 -inventree==0.13.1 -ipaddr==2.2.0 -itypes==1.2.0 -Jinja2==2.11.3 -lockfile==0.12.2 -MarkupSafe==1.1.1 -msgpack==0.6.2 -packaging==20.3 -pathlib==1.0.1 -pep517==0.8.2 -pluggy==1.3.0 -progress==1.5 -pycparser==2.20 -pyOpenSSL==20.0.1 -pyparsing==2.4.6 -pytest==7.4.3 -pytoml==0.1.21 -requests==2.31.0 -requests-file==1.5.1 -retrying==1.3.3 -schematics==2.1.0 -six==1.14.0 -tldextract==3.1.0 -toml==0.10.2 -tomli==2.0.1 -uritemplate==3.0.1 -urllib3==1.25.8 -webencodings==0.5.1 diff --git a/tests/conftest.py b/tests/conftest.py index 12e049e..82da3b9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -4,10 +4,11 @@ import pickle import os -from inventree_digikey.ConfigReader import ConfigReader +from inventree_digikey_integration.ConfigReader import ConfigReader TEST_DATA_PATH = Path(__file__).resolve().parent / "test_data" + @pytest.fixture(scope="session") def test_data(): data_dict = {} @@ -18,24 +19,23 @@ def test_data(): config = ConfigParser() config.read(file) data_dict[file.stem] = config - + data_dict["config_reader"] = ConfigReader(TEST_DATA_PATH / "test_config.ini") - - - - data_dict["test_image"] = { - "url":"https://postimg.cc/WF5g5BGP", + + data_dict["test_image"] = { + "url": "https://postimg.cc/WF5g5BGP", "size": 11688, - "size_error": 0.2, # Add some error margin for different download sizes + "size_error": 0.2, # Add some error margin for different download sizes } return data_dict + @pytest.fixture def test_supplier_data(): return { "name": "Digikey", "is_supplier": True, "description": "Electronics Supply Store", - "pk": 1 - } \ No newline at end of file + "pk": 1, + } diff --git a/tests/test_cli.py b/tests/test_cli.py index 36ab33d..6d65234 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,9 +1,10 @@ -import inventree_digikey.__main__ as test_module +import inventree_digikey_integration.__main__ as test_module from pathlib import Path SOURCE_ROOT = Path(__file__).resolve().parent.parent / "inventree_digikey" + def test_argparse(): args = test_module.parse_args(["-y", "1234", "5678"]) assert args.yes == True diff --git a/tests/test_data/generate_test_data.py b/tests/test_data/generate_test_data.py index e3e0b2c..e9a9f19 100644 --- a/tests/test_data/generate_test_data.py +++ b/tests/test_data/generate_test_data.py @@ -5,12 +5,12 @@ os.sys.path.append(str(Path(__file__).resolve().parent.parent.parent)) -from inventree_digikey.Digikey import DigiPart +from inventree_digikey_integration.Digikey import DigiPart TEST_DATA_PATH = Path(__file__).resolve().parent -DIGIKEY_PART_NUMBER_UNDER_TEST ="296-21752-2-ND" +DIGIKEY_PART_NUMBER_UNDER_TEST = "296-21752-2-ND" print("Fetching test data from Digikey API") resp = product_details(DIGIKEY_PART_NUMBER_UNDER_TEST) @@ -25,4 +25,4 @@ dkpart.injest_api(prompt=False) pickle.dump(dkpart, f) -print("Test data saved") \ No newline at end of file +print("Test data saved") diff --git a/tests/test_digikey.py b/tests/test_digikey.py index 5152752..0b4b772 100644 --- a/tests/test_digikey.py +++ b/tests/test_digikey.py @@ -1,32 +1,68 @@ -from inventree_digikey.Digikey import DigiPart +from inventree_digikey_integration.Digikey import DigiPart from digikey.v3.api import DigikeyApiWrapper import digikey + def test_part_creation(test_data): test_resp = test_data["test_resp"] dkpart = DigiPart(test_resp) dkpart.injest_api(prompt=False) - assert dkpart.manufacturer == "Texas Instruments", "Manufacturer not set correctly: Got %s expected %s" %(dkpart.manufacturer, "Texas Instruments") + assert ( + dkpart.manufacturer == "Texas Instruments" + ), "Manufacturer not set correctly: Got %s expected %s" % ( + dkpart.manufacturer, + "Texas Instruments", + ) assert dkpart.mfg_part_num == "NA555DR", "MFG Part Number not set correctly" assert dkpart.name == "NA555DR", "Name not set correctly" - assert dkpart.description == "IC OSC SGL TIMER 100KHZ 8-SOIC", "Description not set correctly" - assert dkpart.link == "https://www.digikey.com/en/products/detail/texas-instruments/NA555DR/1571933" + assert ( + dkpart.description == "IC OSC SGL TIMER 100KHZ 8-SOIC" + ), "Description not set correctly" + assert ( + dkpart.link + == "https://www.digikey.com/en/products/detail/texas-instruments/NA555DR/1571933" + ) assert dkpart.digi_part_num == "296-21752-2-ND" - assert dkpart.picture == "https://mm.digikey.com/Volume0/opasdata/d220001/medias/images/4849/296_8-SOIC.jpg" + assert ( + dkpart.picture + == "https://mm.digikey.com/Volume0/opasdata/d220001/medias/images/4849/296_8-SOIC.jpg" + ) for param in test_resp.parameters: - assert (param.parameter, param.value) in dkpart.parameters, "Parameter not set correctly" + assert ( + param.parameter, + param.value, + ) in dkpart.parameters, "Parameter not set correctly" + def test_part_creation_from_partnumber(test_data, monkeypatch): - monkeypatch.setattr('digikey.product_details', lambda x: test_data["test_resp"]) - dkpart = DigiPart.from_digikey_part_number("296-21752-2-ND", test_data['config_reader']) + monkeypatch.setattr("digikey.product_details", lambda x: test_data["test_resp"]) + dkpart = DigiPart.from_digikey_part_number( + "296-21752-2-ND", test_data["config_reader"] + ) dkpart.injest_api(prompt=False) - - assert dkpart.manufacturer == "Texas Instruments", "Manufacturer not set correctly: Got %s expected %s" %(dkpart.manufacturer, "Texas Instruments") + + assert ( + dkpart.manufacturer == "Texas Instruments" + ), "Manufacturer not set correctly: Got %s expected %s" % ( + dkpart.manufacturer, + "Texas Instruments", + ) assert dkpart.mfg_part_num == "NA555DR", "MFG Part Number not set correctly" assert dkpart.name == "NA555DR", "Name not set correctly" - assert dkpart.description == "IC OSC SGL TIMER 100KHZ 8-SOIC", "Description not set correctly" - assert dkpart.link == "https://www.digikey.com/en/products/detail/texas-instruments/NA555DR/1571933" + assert ( + dkpart.description == "IC OSC SGL TIMER 100KHZ 8-SOIC" + ), "Description not set correctly" + assert ( + dkpart.link + == "https://www.digikey.com/en/products/detail/texas-instruments/NA555DR/1571933" + ) assert dkpart.digi_part_num == "296-21752-2-ND" - assert dkpart.picture == "https://mm.digikey.com/Volume0/opasdata/d220001/medias/images/4849/296_8-SOIC.jpg" - for param in test_data['test_resp'].parameters: - assert (param.parameter, param.value) in dkpart.parameters, "Parameter not set correctly" + assert ( + dkpart.picture + == "https://mm.digikey.com/Volume0/opasdata/d220001/medias/images/4849/296_8-SOIC.jpg" + ) + for param in test_data["test_resp"].parameters: + assert ( + param.parameter, + param.value, + ) in dkpart.parameters, "Parameter not set correctly" diff --git a/tests/test_image_manager.py b/tests/test_image_manager.py index c204209..812f4ce 100644 --- a/tests/test_image_manager.py +++ b/tests/test_image_manager.py @@ -1,9 +1,10 @@ -from inventree_digikey.ImageManager import ImageManager +from inventree_digikey_integration.ImageManager import ImageManager import random import pytest from pathlib import Path + @pytest.fixture() def tempdir(tmpdir_factory): return Path(tmpdir_factory.mktemp("cache")) @@ -16,9 +17,13 @@ def test_image_manager_cache_path(tempdir): def test_image_manager_get_image(tempdir, test_data): - ImageManager.cache_path = tempdir + ImageManager.cache_path = tempdir path = ImageManager.get_image(test_data["test_image"]["url"]) assert Path(path).exists() - assert Path(path).stat().st_size <= test_data["test_image"]["size"] * (1 + test_data["test_image"]["size_error"]) - assert Path(path).stat().st_size >= test_data["test_image"]["size"] * (1 - test_data["test_image"]["size_error"]) + assert Path(path).stat().st_size <= test_data["test_image"]["size"] * ( + 1 + test_data["test_image"]["size_error"] + ) + assert Path(path).stat().st_size >= test_data["test_image"]["size"] * ( + 1 - test_data["test_image"]["size_error"] + ) assert Path(path).suffix == ".jpg" diff --git a/tests/test_inventree.py b/tests/test_inventree.py index c44609e..6584c23 100644 --- a/tests/test_inventree.py +++ b/tests/test_inventree.py @@ -1,5 +1,5 @@ import pytest -import inventree_digikey.Inventree as test_module +import inventree_digikey_integration.Inventree as test_module from configparser import ConfigParser import inventree.company import inventree.api @@ -10,21 +10,30 @@ def mock_create_company(*args, **kwargs): data["pk"] = 1 return inventree.company.Company(args[0], data=args[1]) + def mock_create_part(*args, **kwargs): data = args[1] data["pk"] = 1 return inventree.part.Part(args[0], data=args[1]) + @pytest.fixture() def test_api(test_data, monkeypatch): - monkeypatch.setattr(inventree.api.InvenTreeAPI, 'connect', lambda *args, **kwargs: None) - api = inventree.api.InvenTreeAPI(test_data['test_config']['INVENTREE_API']['URL'], username=test_data['test_config']['INVENTREE_API']['USER'], password=test_data['test_config']['INVENTREE_API']['PASSWORD']) + monkeypatch.setattr( + inventree.api.InvenTreeAPI, "connect", lambda *args, **kwargs: None + ) + api = inventree.api.InvenTreeAPI( + test_data["test_config"]["INVENTREE_API"]["URL"], + username=test_data["test_config"]["INVENTREE_API"]["USER"], + password=test_data["test_config"]["INVENTREE_API"]["PASSWORD"], + ) return api # Cleanup here as necessary + def test_get_digikey_supplier_new_company(test_api, monkeypatch, test_data): - monkeypatch.setattr(inventree.company.Company, 'list', lambda *args, **kwargs: []) - monkeypatch.setattr(inventree.company.Company, 'create', mock_create_company) + monkeypatch.setattr(inventree.company.Company, "list", lambda *args, **kwargs: []) + monkeypatch.setattr(inventree.company.Company, "create", mock_create_company) dk = test_module.get_digikey_supplier(test_data["config_reader"]) assert dk.pk == 1 assert dk.name == "Digikey" @@ -32,65 +41,147 @@ def test_get_digikey_supplier_new_company(test_api, monkeypatch, test_data): assert dk.description == "Electronics Supply Store" -def test_get_digikey_supplier_existing_company(test_api, test_supplier_data, monkeypatch, test_data): - monkeypatch.setattr(inventree.company.Company, 'list', lambda *args, **kwargs: [inventree.company.Company(test_api, data=test_supplier_data)]) - dk = test_module.get_digikey_supplier(test_data['config_reader']) +def test_get_digikey_supplier_existing_company( + test_api, test_supplier_data, monkeypatch, test_data +): + monkeypatch.setattr( + inventree.company.Company, + "list", + lambda *args, **kwargs: [ + inventree.company.Company(test_api, data=test_supplier_data) + ], + ) + dk = test_module.get_digikey_supplier(test_data["config_reader"]) assert dk.pk == 1 - def test_create_inventree_part(monkeypatch, test_data, test_api): - monkeypatch.setattr(test_module, 'find_category', lambda *args, **kwargs: inventree.part.PartCategory(test_api, data={"pk": 1})) - monkeypatch.setattr(inventree.part.Part, 'uploadImage', lambda *args, **kwargs: None) - monkeypatch.setattr(inventree.part.Part, 'create', mock_create_part) - monkeypatch.setattr(inventree.part.Part, 'list', lambda *args, **kwargs: []) - - inventree_part = test_module.create_inventree_part(test_data["test_dkpart"], test_data['config_reader']) + monkeypatch.setattr( + test_module, + "find_category", + lambda *args, **kwargs: inventree.part.PartCategory(test_api, data={"pk": 1}), + ) + monkeypatch.setattr( + inventree.part.Part, "uploadImage", lambda *args, **kwargs: None + ) + monkeypatch.setattr(inventree.part.Part, "create", mock_create_part) + monkeypatch.setattr(inventree.part.Part, "list", lambda *args, **kwargs: []) + + inventree_part = test_module.create_inventree_part( + test_data["test_dkpart"], test_data["config_reader"] + ) assert inventree_part.pk == 1 assert inventree_part.name == test_data["test_dkpart"].name assert inventree_part.description == test_data["test_dkpart"].description - -def test_create_inventree_part_part_exists(test_data, monkeypatch, test_api): - monkeypatch.setattr(test_module, 'find_category', lambda *args, **kwargs: inventree.part.PartCategory(test_api, data={"pk": 1})) - monkeypatch.setattr(inventree.part.Part, 'uploadImage', lambda *args, **kwargs: None) - monkeypatch.setattr(inventree.part.Part, 'create', mock_create_part) - monkeypatch.setattr(inventree.part.Part, 'list', lambda *args, **kwargs: [inventree.part.Part(test_api, data={"pk": 1, "name": test_data["test_dkpart"].name, "description": test_data["test_dkpart"].description})]) - inventree_part = test_module.create_inventree_part(test_data["test_dkpart"], test_data['config_reader']) +def test_create_inventree_part_part_exists(test_data, monkeypatch, test_api): + monkeypatch.setattr( + test_module, + "find_category", + lambda *args, **kwargs: inventree.part.PartCategory(test_api, data={"pk": 1}), + ) + monkeypatch.setattr( + inventree.part.Part, "uploadImage", lambda *args, **kwargs: None + ) + monkeypatch.setattr(inventree.part.Part, "create", mock_create_part) + monkeypatch.setattr( + inventree.part.Part, + "list", + lambda *args, **kwargs: [ + inventree.part.Part( + test_api, + data={ + "pk": 1, + "name": test_data["test_dkpart"].name, + "description": test_data["test_dkpart"].description, + }, + ) + ], + ) + + inventree_part = test_module.create_inventree_part( + test_data["test_dkpart"], test_data["config_reader"] + ) assert inventree_part == -1 def test_find_manufacturer(test_data, monkeypatch, test_api): - monkeypatch.setattr(inventree.company.Company, 'list', lambda *args, **kwargs: []) - monkeypatch.setattr(inventree.company.Company, 'create', mock_create_company) - test_manufacturer = test_module.find_manufacturer(test_data["test_dkpart"], test_data['config_reader']) + monkeypatch.setattr(inventree.company.Company, "list", lambda *args, **kwargs: []) + monkeypatch.setattr(inventree.company.Company, "create", mock_create_company) + test_manufacturer = test_module.find_manufacturer( + test_data["test_dkpart"], test_data["config_reader"] + ) assert test_manufacturer.pk == 1 assert test_manufacturer.name == test_data["test_dkpart"].manufacturer assert test_manufacturer.is_supplier == False assert test_manufacturer.description == test_data["test_dkpart"].manufacturer + def test_find_manufacturer_manufactuer_exists(test_data, monkeypatch, test_api): - monkeypatch.setattr(inventree.company.Company, 'list', lambda *args, **kwargs: [inventree.company.Company(test_api, data={"pk": 1, "name": test_data["test_dkpart"].manufacturer, "description": test_data["test_dkpart"].manufacturer, "is_supplier": False})]) - monkeypatch.setattr('builtins.input', lambda *args, **kwargs: "0") - test_manufacturer = test_module.find_manufacturer(test_data["test_dkpart"], test_data['config_reader']) + monkeypatch.setattr( + inventree.company.Company, + "list", + lambda *args, **kwargs: [ + inventree.company.Company( + test_api, + data={ + "pk": 1, + "name": test_data["test_dkpart"].manufacturer, + "description": test_data["test_dkpart"].manufacturer, + "is_supplier": False, + }, + ) + ], + ) + monkeypatch.setattr("builtins.input", lambda *args, **kwargs: "0") + test_manufacturer = test_module.find_manufacturer( + test_data["test_dkpart"], test_data["config_reader"] + ) assert test_manufacturer.pk == 1 assert test_manufacturer.name == "Texas Instruments" assert test_manufacturer.is_supplier == False assert test_manufacturer.description == "Texas Instruments" -def test_add_digikey_part(test_data, monkeypatch, test_api): - monkeypatch.setattr(inventree.company.Company, 'list', lambda *args, **kwargs: [inventree.company.Company(test_api, data={"pk": 1, "name": "Digikey", "description": "Electronics Supply Store", "is_supplier": True})]) - monkeypatch.setattr(inventree.part.Part, 'create', mock_create_part) - monkeypatch.setattr(inventree.part.Part, 'list', lambda *args, **kwargs: []) - monkeypatch.setattr(inventree.part.Part, 'uploadImage', lambda *args, **kwargs: None) - monkeypatch.setattr(inventree.part.PartCategory, 'list', lambda *args, **kwargs: [inventree.part.PartCategory(test_api, data={"pk": 1, "name": "Resistors", "parent": None})]) - monkeypatch.setattr('builtins.input', lambda *args, **kwargs: "0") - monkeypatch.setattr(inventree.company.ManufacturerPart, 'create', lambda *args, **kwargs: None) - monkeypatch.setattr(inventree.company.SupplierPart, 'create', lambda *args, **kwargs: None) - - test_module.add_digikey_part(test_data["test_dkpart"], test_data['config_reader']) # Yeah, I should add some return value error checking type stuff here - - - +def test_add_digikey_part(test_data, monkeypatch, test_api): + monkeypatch.setattr( + inventree.company.Company, + "list", + lambda *args, **kwargs: [ + inventree.company.Company( + test_api, + data={ + "pk": 1, + "name": "Digikey", + "description": "Electronics Supply Store", + "is_supplier": True, + }, + ) + ], + ) + monkeypatch.setattr(inventree.part.Part, "create", mock_create_part) + monkeypatch.setattr(inventree.part.Part, "list", lambda *args, **kwargs: []) + monkeypatch.setattr( + inventree.part.Part, "uploadImage", lambda *args, **kwargs: None + ) + monkeypatch.setattr( + inventree.part.PartCategory, + "list", + lambda *args, **kwargs: [ + inventree.part.PartCategory( + test_api, data={"pk": 1, "name": "Resistors", "parent": None} + ) + ], + ) + monkeypatch.setattr("builtins.input", lambda *args, **kwargs: "0") + monkeypatch.setattr( + inventree.company.ManufacturerPart, "create", lambda *args, **kwargs: None + ) + monkeypatch.setattr( + inventree.company.SupplierPart, "create", lambda *args, **kwargs: None + ) + + test_module.add_digikey_part( + test_data["test_dkpart"], test_data["config_reader"] + ) # Yeah, I should add some return value error checking type stuff here