Skip to content

Commit

Permalink
Merge pull request #167 from T0jan/main
Browse files Browse the repository at this point in the history
datasheet upload, update functionality, pricing
  • Loading branch information
eeintech committed Aug 3, 2023
2 parents ae792ed + 2d670f4 commit e7ad3a6
Show file tree
Hide file tree
Showing 18 changed files with 418 additions and 109 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test_deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ jobs:
git clone https://github.com/inventree/InvenTree/
mkdir InvenTree/static
cp tests/files/inventree_default_db.sqlite3 InvenTree/
cd InvenTree/ && git switch stable && invoke install && invoke migrate && cd -
cd InvenTree/ && git switch 0.11.x && invoke install && invoke migrate && cd -
- name: Ki-nTree setup
run: |
invoke install
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,16 @@ Note that each time you enable the "Add" permission to an object, InvenTree auto
5. If you intend to use InvenTree with this tool, click on "Settings > InvenTree" and fill in your InvenTree server address and credentials then click "Save" (optional: click on "Test" to check communication with server)
a. It is possible to define a Proxy Server over which all interactions with InvenTree will be routed. To set a proxy server use the "Enable Proxy Support" switch in "Settings > InvenTree" and define the proxy address in the new input field.
b. Instead of user credential authentication token authentication is also supported. To use a token add it it to the "Password or Token" field and leave the "Username" empty. You can retrieve your personal access token from your InvenTree server by sending an get-request to its api url `api/user/token/`.
c. If needed this tool can try to download the parts datasheet from the suppliers and upload it it to the attachment section of each part. For this just activate "Upload Datasheets to InvenTree" in the InvenTree settings
d. It is also possible to sync the prices in InvenTree with the latest supplier prices. For this enable "Upload Pricing Data to InvenTree"


#### Get Digi-Key API token
<details>
<summary>Show steps (click to expand)</summary>
<p>

Enter your Digi-Key developper account credentials then login. The following page will appear (`user@email.com` will show your email address):
Enter your Digi-Key developer account credentials then login. The following page will appear (`user@email.com` will show your email address):

<img src="https://raw.githubusercontent.com/sparkmicro/Ki-nTree/main/images/doc/digikey_api_approval_request.png" width="600" height="auto">

Expand Down
49 changes: 27 additions & 22 deletions kintree/common/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ def download(url, filetype='API data', fileoutput='', timeout=3, enable_headers=

import socket
import urllib.request
import requests

# Set default timeout for download socket
socket.setdefaulttimeout(timeout)
Expand All @@ -73,56 +74,60 @@ def download(url, filetype='API data', fileoutput='', timeout=3, enable_headers=
opener.addheaders = [('User-agent', 'Mozilla/5.0')]
urllib.request.install_opener(opener)
try:
if filetype == 'Image':
# Enable use of requests library for downloading images (Element14 URLs do NOT work with urllib)
if filetype == 'Image' or filetype == 'PDF':
# Enable use of requests library for downloading files (some URLs do NOT work with urllib)
if requests_lib:
import requests
headers = {'User-agent': 'Mozilla/5.0'}
response = requests.get(url, headers=headers, timeout=timeout)
with open(fileoutput, 'wb') as image:
image.write(response.content)
response = requests.get(url, headers=headers, timeout=timeout, allow_redirects=True)
if filetype.lower() not in response.headers['Content-Type'].lower():
cprint(f'[INFO]\tWarning: {filetype} download returned the wrong file type', silent=silent)
return None
with open(fileoutput, 'wb') as file:
file.write(response.content)
else:
(image, headers) = urllib.request.urlretrieve(url, filename=fileoutput)
return image
elif filetype == 'PDF':
(pdf, headers) = urllib.request.urlretrieve(url, filename=fileoutput)
return pdf
(file, headers) = urllib.request.urlretrieve(url, filename=fileoutput)
if filetype.lower() not in headers['Content-Type'].lower():
cprint(f'[INFO]\tWarning: {filetype} download returned the wrong file type', silent=silent)
return None
return file
else:
url_data = urllib.request.urlopen(url)
data = url_data.read()
data_json = json.loads(data.decode('utf-8'))
return data_json
except socket.timeout:
except (socket.timeout, requests.exceptions.ConnectTimeout, requests.exceptions.ReadTimeout):
cprint(f'[INFO]\tWarning: {filetype} download socket timed out ({timeout}s)', silent=silent)
except urllib.error.HTTPError:
except (urllib.error.HTTPError, requests.exceptions.ConnectionError):
cprint(f'[INFO]\tWarning: {filetype} download failed (HTTP Error)', silent=silent)
except (urllib.error.URLError, ValueError):
cprint(f'[INFO]\tWarning: {filetype} download failed (URL Error)', silent=silent)
except requests.exceptions.SSLError:
cprint(f'[INFO]\tWarning: {filetype} download failed (SSL Error)', silent=silent)
except FileNotFoundError:
cprint(f'[INFO]\tWarning: {os.path.dirname(fileoutput)} folder does not exist', silent=silent)
return None


def download_image(image_url: str, image_full_path: str, silent=False) -> str:
def download_with_retry(url: str, full_path: str, silent=False, **kwargs) -> str:
''' Standard method to download image URL to local file '''

if not image_url:
if not url:
cprint('[INFO]\tError: Missing image URL', silent=silent)
return False

# Try without headers
image = download(image_url, filetype='Image', fileoutput=image_full_path, silent=silent)
file = download(url, fileoutput=full_path, silent=silent, **kwargs)

if not image:
if not file:
# Try with headers
image = download(image_url, filetype='Image', fileoutput=image_full_path, enable_headers=True, silent=silent)
file = download(url, fileoutput=full_path, enable_headers=True, silent=silent, **kwargs)

if not image:
if not file:
# Try with requests library
image = download(image_url, filetype='Image', fileoutput=image_full_path, enable_headers=True, requests_lib=True, silent=silent)
file = download(url, fileoutput=full_path, enable_headers=True, requests_lib=True, silent=silent, **kwargs)

# Still nothing
if not image:
if not file:
return False

return True
8 changes: 8 additions & 0 deletions kintree/config/config_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ def load_inventree_user_settings(user_config_path: str) -> dict:
# loading the proxy independent if it is http or https
user_settings['PROXY'] = list(proxies.values())[0]

if 'DATASHEET_UPLOAD' not in user_settings:
user_settings['DATASHEET_UPLOAD'] = False
if 'PRICING_UPLOAD' not in user_settings:
user_settings['PRICING_UPLOAD'] = False
return user_settings


Expand All @@ -116,6 +120,8 @@ def save_inventree_user_settings(enable: bool,
password: str,
enable_proxy: bool,
proxies: dict,
datasheet_upload: bool,
pricing_upload: bool,
user_config_path: str):
''' Save InvenTree user settings to file '''
user_settings = {}
Expand All @@ -127,6 +133,8 @@ def save_inventree_user_settings(enable: bool,
user_settings['PASSWORD'] = base64.b64encode(password.encode())
user_settings['ENABLE_PROXY'] = enable_proxy
user_settings['PROXIES'] = proxies
user_settings['DATASHEET_UPLOAD'] = datasheet_upload
user_settings['PRICING_UPLOAD'] = pricing_upload

return dump_file(user_settings, user_config_path)

Expand Down
6 changes: 3 additions & 3 deletions kintree/config/inventree/parameters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ Breakdown Voltage: V
Capacitance: nF
Clamping Voltage: V
Collector Gate Voltage: V
DC Resistance: mOhm
ESR: mOhm
DC Resistance:
ESR:
Footprint: null
Forward Voltage: V
Frequency: Hz
Expand Down Expand Up @@ -39,7 +39,7 @@ Package Type: null
Pitch: mm
Polarity: null
Quiescent Current: A
RDS On Resistance: Ohm
RDS On Resistance: Ω
RDS On Voltage: V
Rated Current: A
Rated Power: W
Expand Down
20 changes: 18 additions & 2 deletions kintree/config/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,13 @@ def reload_enable_flags():
global ENABLE_KICAD
global ENABLE_INVENTREE
global ENABLE_ALTERNATE
global UPDATE_INVENTREE

try:
ENABLE_KICAD = CONFIG_GENERAL.get('ENABLE_KICAD', False)
ENABLE_INVENTREE = CONFIG_GENERAL.get('ENABLE_INVENTREE', False)
ENABLE_ALTERNATE = CONFIG_GENERAL.get('ENABLE_ALTERNATE', False)
UPDATE_INVENTREE = CONFIG_GENERAL.get('UPDATE_INVENTREE', False)
return True
except TypeError:
pass
Expand Down Expand Up @@ -185,9 +187,10 @@ def load_suppliers():
def load_cache_settings():
global search_results
global search_images
global search_datasheets
global CACHE_ENABLED
global DIGIKEY_STORAGE_PATH

USER_SETTINGS = config_interface.load_user_paths(home_dir=HOME_DIR)

search_results = {
Expand All @@ -204,6 +207,13 @@ def load_cache_settings():
if not os.path.exists(search_images):
os.makedirs(search_images)

# Part images
search_datasheets = os.path.join(
USER_SETTINGS['USER_CACHE'], 'datasheets', '')
# Create folder if it does not exists
if not os.path.exists(search_datasheets):
os.makedirs(search_datasheets)

# API token storage path
DIGIKEY_STORAGE_PATH = os.path.join(USER_SETTINGS['USER_CACHE'], '')

Expand Down Expand Up @@ -310,6 +320,8 @@ def load_inventree_settings():
global ENABLE_PROXY
global PROXIES
global PART_URL_ROOT
global DATASHEET_UPLOAD
global PRICING_UPLOAD

inventree_settings = config_interface.load_inventree_user_settings(INVENTREE_CONFIG)

Expand All @@ -318,6 +330,8 @@ def load_inventree_settings():
PASSWORD = inventree_settings.get('PASSWORD', None)
ENABLE_PROXY = inventree_settings.get('ENABLE_PROXY', False)
PROXIES = inventree_settings.get('PROXIES', None)
DATASHEET_UPLOAD = inventree_settings.get('DATASHEET_UPLOAD', False)
PRICING_UPLOAD = inventree_settings.get('PRICING_UPLOAD', False)
# Part URL
if SERVER_ADDRESS:
# If missing, append slash to root URL
Expand Down Expand Up @@ -352,13 +366,15 @@ def set_enable_flag(key: str, value: bool):
global CONFIG_GENERAL

user_settings = CONFIG_GENERAL
if key in ['kicad', 'inventree', 'alternate']:
if key in ['kicad', 'inventree', 'alternate', 'update']:
if key == 'kicad':
user_settings['ENABLE_KICAD'] = value
elif key == 'inventree':
user_settings['ENABLE_INVENTREE'] = value
elif key == 'alternate':
user_settings['ENABLE_ALTERNATE'] = value
elif key == 'update':
user_settings['UPDATE_INVENTREE'] = value

# Save
config_interface.dump_file(
Expand Down

0 comments on commit e7ad3a6

Please sign in to comment.