Skip to content

Commit

Permalink
Merge pull request #84 from sparkmicro/lcsc_fix
Browse files Browse the repository at this point in the history
0.5.2 Release
  • Loading branch information
eeintech committed Mar 25, 2022
2 parents 0b7681e + e1750a9 commit 6942431
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 35 deletions.
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,31 @@ Ki-nTree is [available on Arch Linux's AUR](https://aur.archlinux.org/packages/p

### Usage Instructions

#### Before Starting

If you intend to use Ki-nTree with InvenTree, this tool offers to setup the InvenTree category tree with a simple script that you can run as follow:

> Warining: Before running it, make sure you have setup your category tree in your category settings file (`~/.config/kintree/user/categories.yaml`) according to your own preferences, else it will use the [default setup](https://github.com/sparkmicro/Ki-nTree/blob/main/kintree/config/inventree/categories.yaml).
``` bash
$ python3 -m kintree.setup_inventree
```

If the InvenTree category tree is not setup before starting to use Ki-nTree, you will not be able to add parts to InvenTree.

#### InvenTree Permissions

Each InvenTree user has a set of permissions associated to them.
Please refer to the [InvenTree documentation](https://inventree.readthedocs.io/en/latest/settings/permissions/) to understand how to setup user permissions.

The minimum set of user/group permission required to add parts to InvenTree is:
- "Part - Add" to add InvenTree parts
- "Purchase Orders - Add" to add manufacturers, suppliers and their associated parts

If you wish to automatically add subcategories while creating InvenTree parts, you will need to enable the "Part Categories - Add" permission.

Note that each time you enable the "Add" permission to an object, InvenTree automatically enables the "Change" permission to that object too.

#### Settings
1. With Ki-nTree GUI open, click on "Settings > Digi-Key" and fill in both Digi-Key API Client ID and Secret keys (optional: click on "Test" to [get an API token](#get-digi-key-api-token))
2. Click on "Settings > Mouser" and fill in the Mouser part search API key
Expand Down
58 changes: 33 additions & 25 deletions kintree/common/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,41 +65,49 @@ def create_library(library_path: str, symbol: str, template_lib: str):
copyfile(template_dcm, new_dcm_file)


def download_image(image_url: str, image_full_path: str, silent=False) -> str:
''' Standard method to download image URL to local file '''
def download(url, filetype='API data', fileoutput='', timeout=3, enable_headers=False, silent=False):
''' Standard method to download URL content, with option to save to local file (eg. images) '''

import socket
import urllib.request

# Set default timeout for download socket
socket.setdefaulttimeout(timeout)
if enable_headers:
opener = urllib.request.build_opener()
opener.addheaders = [('User-agent', 'Mozilla/5.0')]
urllib.request.install_opener(opener)
try:
if filetype == 'Image':
(image, headers) = urllib.request.urlretrieve(url, filename=fileoutput)
return image
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:
cprint(f'[INFO]\tWarning: {filetype} download socket timed out ({timeout}s)', silent=silent)
except urllib.error.HTTPError:
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)
return None


def download_image(image_url: str, image_full_path: str) -> str:
''' Standard method to download image URL to local file '''

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

def download(url, enable_headers=False):
timeout = 3 # in seconds
# Set default timeout for download socket
socket.setdefaulttimeout(timeout)
if enable_headers:
opener = urllib.request.build_opener()
opener.addheaders = [('User-agent', 'Mozilla/5.0')]
urllib.request.install_opener(opener)
try:
(image_filename, headers) = urllib.request.urlretrieve(url, filename=image_full_path)
return image_filename
except socket.timeout:
cprint(f'[INFO]\tWarning: Image download socket timed out ({timeout}s)', silent=silent)
except urllib.error.HTTPError:
cprint('[INFO]\tWarning: Image download failed (HTTP Error)', silent=silent)
except (urllib.error.URLError, ValueError):
cprint('[INFO]\tWarning: Image download failed (URL Error)', silent=silent)
return None

# Try without headers
image = download(image_url)
image = download(image_url, filetype='Image', fileoutput=image_full_path)

if not image:
# Try with headers
image = download(image_url, enable_headers=True)
image = download(image_url, filetype='Image', fileoutput=image_full_path, enable_headers=True)

# Still nothing
if not image:
Expand Down
1 change: 1 addition & 0 deletions kintree/config/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ def load_user_config():

# GENERAL SETTINGS
CONFIG_GENERAL = config_interface.load_file(os.path.join(CONFIG_USER_FILES, 'general.yaml'))
AUTOMATIC_SUBCATEGORY_CREATE = CONFIG_GENERAL.get('AUTOMATIC_SUBCATEGORY_CREATE', False)
AUTOMATIC_BROWSER_OPEN = CONFIG_GENERAL.get('AUTOMATIC_BROWSER_OPEN', False)

# Supported suppliers APIs
Expand Down
1 change: 1 addition & 0 deletions kintree/config/settings/general.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
AUTOMATIC_SUBCATEGORY_CREATE: false
AUTOMATIC_BROWSER_OPEN: true
INVENTREE_ENV: null
8 changes: 7 additions & 1 deletion kintree/database/inventree_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,13 @@ def create_category(parent: str, name: str):
})
is_new_category = True

return category.pk, is_new_category
try:
category_pk = category.pk
except AttributeError:
# User does not have the permission to create categories
category_pk = 0

return category_pk, is_new_category


def upload_part_image(image_url: str, part_id: int) -> bool:
Expand Down
12 changes: 10 additions & 2 deletions kintree/database/inventree_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,10 +371,18 @@ def inventree_create(part_info: dict, categories: list, kicad=False, symbol=None
# Fetch subcategory id
subcategory_pk = inventree_api.get_inventree_category_id(category_name=subcategory_name,
parent_category_id=category_pk)

if subcategory_pk <= 0:
cprint(f'\n[TREE]\tWarning: Subcategory "{subcategory_name}" does not exist', silent=settings.SILENT)

# Check if user enabled option to automatically create the subcategory in general settings
if settings.AUTOMATIC_SUBCATEGORY_CREATE:
subcategory_pk, is_subcategory_new = inventree_api.create_category(parent=category_name, name=subcategory_name)
if subcategory_pk > 0:
cprint(f'[TREE]\tSuccess: Subcategory "{category_name}/{subcategory_name}" was automatically added to InvenTree')

if subcategory_pk > 0:
category_select = subcategory_pk
else:
cprint(f'\n[TREE]\tWarning: Subcategory "{subcategory_name}" does not exist', silent=settings.SILENT)

# Progress Update
if show_progress and not progress.update_progress_bar_window():
Expand Down
10 changes: 4 additions & 6 deletions kintree/search/lcsc_api.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import requests
from ..common.tools import download

SEARCH_HEADERS = [
'productDescEn',
Expand Down Expand Up @@ -41,15 +41,13 @@ def find_categories(part_details: str):

def fetch_part_info(part_number: str) -> dict:
''' Fetch part data from API '''
from ..wrapt_timeout_decorator import timeout

part_info = {}

@timeout(dec_timeout=20)
def search_timeout():
def search_timeout(timeout=10):
url = 'https://wwwapi.lcsc.com/v1/products/detail?product_code=' + part_number
response = requests.get(url)
return response.json()
response = download(url, timeout=timeout)
return response

# Query part number
try:
Expand Down
2 changes: 1 addition & 1 deletion run_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ def check_result(status: str, new_part: bool) -> bool:

elif method_idx == 9:
# Test download image
if download_image('', '', silent=True) or download_image('http', '', silent=True):
if download_image('', '') or download_image('http', ''):
method_success = False

if method_success:
Expand Down

0 comments on commit 6942431

Please sign in to comment.