Skip to content

Commit

Permalink
Merge pull request #15 from EUdds/staging
Browse files Browse the repository at this point in the history
Release v0.1.0
  • Loading branch information
EUdds authored Dec 13, 2023
2 parents f1abeec + 5ff7e6c commit 9d22131
Show file tree
Hide file tree
Showing 19 changed files with 1,322 additions and 230 deletions.
29 changes: 29 additions & 0 deletions .github/workflows/python-publish.yaml
Original file line number Diff line number Diff line change
@@ -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
31 changes: 24 additions & 7 deletions .github/workflows/python-test.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Pytest
name: Testing and Linting

on: [pull_request]

Expand All @@ -11,19 +11,36 @@ 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 }}
uses: actions/setup-python@v4
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"
20 changes: 20 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -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
42 changes: 39 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <path>` flag

```
[DIGIKEY_API]
Expand All @@ -17,3 +28,28 @@ CLIENT_SECRET=
URL=<URL to the inventree instance>
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`
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from pathlib import Path
from inventree.api import InvenTreeAPI


class ConfigReader:
"""
Manage global configuration settings and Inventree instance
Expand All @@ -29,65 +30,81 @@ 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

@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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand All @@ -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:
Expand All @@ -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:
Expand All @@ -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:
Expand Down
Loading

0 comments on commit 9d22131

Please sign in to comment.