diff --git a/.github/workflows/test_deploy.yaml b/.github/workflows/test_deploy.yaml index 7a21c198..a6ddd27a 100644 --- a/.github/workflows/test_deploy.yaml +++ b/.github/workflows/test_deploy.yaml @@ -3,7 +3,7 @@ name: tests | linting | publishing on: push: branches: - - master + - main tags: - "*.*.*" paths-ignore: @@ -11,7 +11,7 @@ on: - images/** pull_request: branches: - - master + - main jobs: style: @@ -86,6 +86,7 @@ jobs: env: DIGIKEY_CLIENT_ID: ${{ secrets.DIGIKEY_CLIENT_ID }} DIGIKEY_CLIENT_SECRET: ${{ secrets.DIGIKEY_CLIENT_SECRET }} + MOUSER_PART_API_KEY: ${{ secrets.MOUSER_PART_API_KEY }} - name: Coveralls run: | coveralls --version diff --git a/kintree/config/config_interface.py b/kintree/config/config_interface.py index 0f0ec0bc..2a535c24 100644 --- a/kintree/config/config_interface.py +++ b/kintree/config/config_interface.py @@ -91,6 +91,13 @@ def load_config(path): except: cprint('[INFO]\tWarning: Failed to load Digi-Key configuration', silent=silent) result = False + # Load Mouser configuration files + try: + config_files = os.path.join(path_to_root, 'mouser', '') + load_config(config_files) + except: + cprint('[INFO]\tWarning: Failed to load Mouser configuration', silent=silent) + result = False # Load LCSC configuration files try: config_files = os.path.join(path_to_root, 'lcsc', '') diff --git a/kintree/config/digikey/digikey_config.yaml b/kintree/config/digikey/digikey_config.yaml index c2103a8e..6d9c9b62 100644 --- a/kintree/config/digikey/digikey_config.yaml +++ b/kintree/config/digikey/digikey_config.yaml @@ -1,3 +1,4 @@ +SUPPLIER_INVENTREE_NAME: Digi-Key SEARCH_NAME: null SEARCH_DESCRIPTION: null SEARCH_REVISION: null diff --git a/kintree/config/lcsc/lcsc_config.yaml b/kintree/config/lcsc/lcsc_config.yaml index c2103a8e..4ac32512 100644 --- a/kintree/config/lcsc/lcsc_config.yaml +++ b/kintree/config/lcsc/lcsc_config.yaml @@ -1,3 +1,4 @@ +SUPPLIER_INVENTREE_NAME: LCSC Electronics SEARCH_NAME: null SEARCH_DESCRIPTION: null SEARCH_REVISION: null diff --git a/kintree/config/mouser/mouser_api.yaml b/kintree/config/mouser/mouser_api.yaml new file mode 100644 index 00000000..47fe91e9 --- /dev/null +++ b/kintree/config/mouser/mouser_api.yaml @@ -0,0 +1 @@ +MOUSER_PART_API_KEY: null \ No newline at end of file diff --git a/kintree/config/mouser/mouser_config.yaml b/kintree/config/mouser/mouser_config.yaml new file mode 100644 index 00000000..9d16e79c --- /dev/null +++ b/kintree/config/mouser/mouser_config.yaml @@ -0,0 +1,10 @@ +SUPPLIER_INVENTREE_NAME: Mouser Electronics +SEARCH_NAME: null +SEARCH_DESCRIPTION: null +SEARCH_REVISION: null +SEARCH_KEYWORDS: null +SEARCH_SKU: null +SEARCH_MANUFACTURER: null +SEARCH_MPN: null +SEARCH_SUPPLIER_URL: null +SEARCH_DATASHEET: null \ No newline at end of file diff --git a/kintree/config/settings.py b/kintree/config/settings.py index 8f72fc1b..847117f4 100644 --- a/kintree/config/settings.py +++ b/kintree/config/settings.py @@ -10,7 +10,7 @@ version_info = { 'MAJOR_REVISION': 0, 'MINOR_REVISION': 4, - 'RELEASE_STATUS': 3, # Digit means stable version + 'RELEASE_STATUS': 4, # Digit means stable version } try: version = '.'.join([str(v) for v in version_info.values()]) @@ -95,6 +95,9 @@ def load_user_config(): CONFIG_DIGIKEY_CATEGORIES = os.path.join(CONFIG_USER_FILES, 'digikey_categories.yaml') # CONFIG_DIGIKEY_PARAMETERS = os.path.join(CONFIG_USER_FILES, 'digikey_parameters.yaml') +# Mouser +CONFIG_MOUSER_API = os.path.join(CONFIG_USER_FILES, 'mouser_api.yaml') + # KiCad CONFIG_KICAD = os.path.join(CONFIG_USER_FILES, 'kicad.yaml') CONFIG_KICAD_CATEGORY_MAP = os.path.join(CONFIG_USER_FILES, 'kicad_map.yaml') @@ -120,7 +123,7 @@ def load_user_config(): AUTOMATIC_BROWSER_OPEN = CONFIG_GENERAL.get('AUTOMATIC_BROWSER_OPEN', False) # Supported suppliers APIs -SUPPORTED_SUPPLIERS_API = ['Digi-Key', 'LCSC'] +SUPPORTED_SUPPLIERS_API = ['Digi-Key', 'Mouser', 'LCSC'] # Digi-Key user configuration CONFIG_DIGIKEY = config_interface.load_file(os.path.join(CONFIG_USER_FILES, 'digikey_config.yaml')) @@ -128,6 +131,9 @@ def load_user_config(): # LCSC user configuration CONFIG_LCSC = config_interface.load_file(os.path.join(CONFIG_USER_FILES, 'lcsc_config.yaml')) +# Mouser user configuration +CONFIG_MOUSER = config_interface.load_file(os.path.join(CONFIG_USER_FILES, 'mouser_config.yaml')) + # Generic API user configuration CONFIG_SEARCH_API = config_interface.load_file(os.path.join(CONFIG_USER_FILES, 'search_api.yaml')) diff --git a/kintree/database/inventree_interface.py b/kintree/database/inventree_interface.py index 29ea8c4c..08cf6f9f 100644 --- a/kintree/database/inventree_interface.py +++ b/kintree/database/inventree_interface.py @@ -7,7 +7,7 @@ from ..config import config_interface from ..database import inventree_api from fuzzywuzzy import fuzz -from ..search import search_api, digikey_api, lcsc_api +from ..search import search_api, digikey_api, mouser_api, lcsc_api def connect_to_server(timeout=5) -> bool: @@ -250,6 +250,8 @@ def get_value_from_user_key(user_key: str, default_key: str, default_value=None) user_search_key = None if supplier == 'Digi-Key': user_search_key = settings.CONFIG_DIGIKEY.get(user_key, None) + elif supplier == 'Mouser': + user_search_key = settings.CONFIG_MOUSER.get(user_key, None) elif supplier == 'LCSC': user_search_key = settings.CONFIG_LCSC.get(user_key, None) else: @@ -262,12 +264,31 @@ def get_value_from_user_key(user_key: str, default_key: str, default_value=None) # Get value for user key, return value from default key if not found return part_info.get(user_search_key, part_info.get(default_key, default_value)) + def get_supplier_name(supplier: str) -> str: + ''' Get InvenTree supplier name ''' + # Check that supplier is supported + if supplier not in settings.SUPPORTED_SUPPLIERS_API: + return '' + + if supplier == 'Digi-Key': + supplier_name = settings.CONFIG_DIGIKEY.get('SUPPLIER_INVENTREE_NAME', None) + elif supplier == 'Mouser': + supplier_name = settings.CONFIG_MOUSER.get('SUPPLIER_INVENTREE_NAME', None) + elif supplier == 'LCSC': + supplier_name = settings.CONFIG_LCSC.get('SUPPLIER_INVENTREE_NAME', None) + else: + supplier_name = supplier + + return supplier_name + # Check that supplier argument is valid if not supplier or (supplier != 'custom' and supplier not in settings.SUPPORTED_SUPPLIERS_API): return part_form # Get default keys if supplier == 'Digi-Key': default_search_keys = digikey_api.get_default_search_keys() + elif supplier == 'Mouser': + default_search_keys = mouser_api.get_default_search_keys() elif supplier == 'LCSC': default_search_keys = lcsc_api.get_default_search_keys() else: @@ -279,7 +300,7 @@ def get_value_from_user_key(user_key: str, default_key: str, default_value=None) part_form['description'] = get_value_from_user_key('SEARCH_DESCRIPTION', default_search_keys[1], default_value='') part_form['revision'] = get_value_from_user_key('SEARCH_REVISION', default_search_keys[2], default_value=settings.INVENTREE_DEFAULT_REV) part_form['keywords'] = get_value_from_user_key('SEARCH_KEYWORDS', default_search_keys[1], default_value='') - part_form['supplier_name'] = supplier if supplier in settings.SUPPORTED_SUPPLIERS_API else '' + part_form['supplier_name'] = get_supplier_name(supplier) part_form['supplier_part_number'] = get_value_from_user_key('SEARCH_SKU', default_search_keys[4], default_value='') part_form['supplier_link'] = get_value_from_user_key('SEARCH_SUPPLIER_URL', default_search_keys[7], default_value='') part_form['manufacturer_name'] = get_value_from_user_key('SEARCH_MANUFACTURER', default_search_keys[5], default_value='') @@ -309,10 +330,12 @@ def supplier_search(supplier: str, part_number: str, test_mode=False) -> dict: cprint(f'\n[MAIN]\t{supplier} search for {part_number}', silent=settings.SILENT) if supplier == 'Digi-Key': part_info = digikey_api.fetch_part_info(part_number) + elif supplier == 'Mouser': + part_info = mouser_api.fetch_part_info(part_number) elif supplier == 'LCSC': part_info = lcsc_api.fetch_part_info(part_number) - # Check Digi-Key data exist + # Check supplier data exist if not part_info: cprint(f'[INFO]\tError: Failed to fetch data for "{part_number}"', silent=settings.SILENT) @@ -325,7 +348,7 @@ def supplier_search(supplier: str, part_number: str, test_mode=False) -> dict: def inventree_create(part_info: dict, categories: list, kicad=False, symbol=None, footprint=None, show_progress=True, is_custom=False): ''' Create InvenTree part from supplier part data and categories ''' - # TODO: Make 'supplier' a variable for use with other APIs (eg. LCSC, Mouser, etc) + part_pk = 0 new_part = False diff --git a/kintree/kintree_gui.py b/kintree/kintree_gui.py index 09cd9433..598bafd7 100644 --- a/kintree/kintree_gui.py +++ b/kintree/kintree_gui.py @@ -11,6 +11,8 @@ import PySimpleGUI as sg # Digi-Key API from .search import digikey_api as digikey_api +# Mouser API +from .search import mouser_api as mouser_api # SnapEDA API from .search import snapeda_api as snapeda_api # Progress @@ -77,8 +79,8 @@ def user_settings_window(): return -def search_api_settings_window(): - ''' Part search API settings window ''' +def digikey_api_settings_window(): + ''' Digi-Key API settings window ''' user_settings = config_interface.load_file(settings.CONFIG_DIGIKEY_API) @@ -131,6 +133,55 @@ def save_settings(user_settings: dict): return +def mouser_api_settings_window(): + ''' Mouser API settings window ''' + + user_settings = config_interface.load_file(settings.CONFIG_MOUSER_API) + + search_api_layout = [ + [ + sg.Text('Mouser Part API Key '), + sg.InputText(user_settings['MOUSER_PART_API_KEY'], key='api_key'), + ], + [ + sg.Button('Test', size=(15, 1)), + sg.Button('Save', size=(15, 1)), + ], + ] + search_api_window = sg.Window( + 'Mouser API (v1) Settings', search_api_layout, location=(500, 500) + ) + + while True: + api_event, api_values = search_api_window.read() + + def save_settings(user_settings: dict): + new_settings = { + 'MOUSER_PART_API_KEY': api_values['api_key'], + } + user_settings = {**user_settings, **new_settings} + config_interface.dump_file(user_settings, settings.CONFIG_MOUSER_API) + mouser_api.setup_environment() + + if api_event == sg.WIN_CLOSED: + search_api_window.close() + return + elif api_event == 'Test': + # Automatically save settings + save_settings(user_settings) + if mouser_api.test_api(): + result_message = 'Successfully connected to Mouser API' + else: + result_message = 'Failed to connect to Mouser API' + sg.popup_ok(result_message, + title='Mouser API Connect Test', + location=(500, 500)) + else: + save_settings(user_settings) + search_api_window.close() + return + + def inventree_settings_window(): ''' InvenTree settings window ''' @@ -778,12 +829,23 @@ def build_choices(items: dict, category: str, subcategory=None) -> list: return symbol, template, footprint -# Main + +# Init +def init(): + # Disable Digi-Key API logger + digikey_api.disable_api_logger() + # Fix for Windows EXE + import multiprocessing + multiprocessing.freeze_support() +# Main def main(): ''' Main GUI window ''' + # Disable Digi-Key logger + init() + CREATE_CUSTOM = False # Select PySimpleGUI theme @@ -796,6 +858,7 @@ def main(): [ 'User', 'Digi-Key', + 'Mouser', 'KiCad', 'InvenTree', ], @@ -842,7 +905,9 @@ def main(): if event == 'User': user_settings_window() elif event == 'Digi-Key': - search_api_settings_window() + digikey_api_settings_window() + elif event == 'Mouser': + mouser_api_settings_window() elif event == 'InvenTree': inventree_settings_window() elif event == 'KiCad': @@ -924,6 +989,8 @@ def main(): '\n- Part number is valid and not blank' if values['supplier'] == 'Digi-Key': error_message += '\n- Digi-Key API settings are correct ("Settings > Digi-Key")' + elif values['supplier'] == 'Mouser': + error_message += '\n- Mouser API settings are correct ("Settings > Mouser")' elif values['supplier'] == 'LCSC': error_message += '\n- Part number starts with "C" (LCSC code)' # Missing Part Information @@ -1176,13 +1243,3 @@ def main(): CREATE_CUSTOM = False window.close() - - -if __name__ == '__main__': - # Disable Digi-Key API logger - digikey_api.disable_api_logger() - # Fix for Windows EXE - import multiprocessing - multiprocessing.freeze_support() - # Run main window - main() diff --git a/kintree/search/lcsc_api.py b/kintree/search/lcsc_api.py index 09a989c9..2f63b89e 100644 --- a/kintree/search/lcsc_api.py +++ b/kintree/search/lcsc_api.py @@ -34,7 +34,6 @@ def get_default_search_keys(): def find_categories(part_details: str): ''' Find categories ''' try: - part_details['parentCatalogName'] return part_details['parentCatalogName'], part_details['catalogName'] except: return None, None diff --git a/kintree/search/mouser/api.py b/kintree/search/mouser/api.py new file mode 100644 index 00000000..c53d7502 --- /dev/null +++ b/kintree/search/mouser/api.py @@ -0,0 +1,168 @@ +import json + +from .base import MouserBaseRequest + + +class MouserCartRequest(MouserBaseRequest): + """ Mouser Cart Request """ + + name = 'Cart' + operations = { + 'get': ('', ''), + 'update': ('', ''), + 'insertitem': ('', ''), + 'updateitem': ('', ''), + 'removeitem': ('', ''), + } + + +class MouserOrderHistoryRequest(MouserBaseRequest): + """ Mouser Order History Request """ + + name = 'Order History' + operations = { + 'ByDateFilter': ('', ''), + 'ByDateRange': ('', ''), + } + + +class MouserOrderRequest(MouserBaseRequest): + """ Mouser Order Request """ + + name = 'Order' + operations = { + 'get': ('GET', '/order'), + 'create': ('', ''), + 'submit': ('', ''), + 'options': ('', ''), + 'currencies': ('', ''), + 'countries': ('', ''), + } + + def export_order_lines_to_csv(self, order_number='', clean=False): + ''' Export Order Lines to CSV ''' + + def convert_order_lines_to_list(clean=False): + + if clean: + # Exclude following columns + exclude_col = [ + 'Errors', + 'MouserATS', + 'PartsPerReel', + 'ScheduledReleases', + 'InfoMessages', + 'CartItemCustPartNumber', + 'LifeCycle', + 'SalesMultipleQty', + 'SalesMinimumOrderQty', + 'SalesMaximumOrderQty', + ] + else: + exclude_col = [] + + response_data = self.get_response() + data_list = [] + if 'OrderLines' in response_data: + order_lines = response_data['OrderLines'] + + headers = [key for key in order_lines[0] if key not in exclude_col] + data_list.append(headers) + + for order_line in order_lines: + line = [value for key, value in order_line.items() if key not in exclude_col] + data_list.append(line) + + return data_list + + data_to_export = convert_order_lines_to_list(clean) + filename = '_'.join([self.name, order_number]) + '.csv' + # Export to CSV file + self.export_csv(filename, data_to_export) + + return filename + + +class MouserPartSearchRequest(MouserBaseRequest): + """ Mouser Part Search Request """ + + name = 'Part Search' + operations = { + 'keyword': ('', ''), + 'keywordandmanufacturer': ('', ''), + 'partnumber': ('POST', '/search/partnumber'), + 'partnumberandmanufacturer': ('', ''), + 'manufacturerlist': ('', ''), + } + + def get_clean_response(self): + cleaned_data = { + 'Availability': '', + 'Category': '', + 'DataSheetUrl': '', + 'Description': '', + 'ImagePath': '', + 'Manufacturer': '', + 'ManufacturerPartNumber': '', + 'MouserPartNumber': '', + 'ProductDetailUrl': '', + 'ProductAttributes': [], + 'PriceBreaks': [], + } + + response = self.get_response() + if self.get_response(): + try: + parts = response['SearchResults'].get('Parts', []) + except AttributeError: + parts = None + + if parts: + if len(parts) > 1: + # TODO + pass + else: + # Process part + part_data = parts[0] + # Merge + for key in cleaned_data: + cleaned_data[key] = part_data[key] + + return cleaned_data + + def print_clean_response(self): + response_data = self.get_clean_response() + print(json.dumps(response_data, indent=4, sort_keys=True)) + + def get_body(self, **kwargs): + + body = {} + + if self.operation == 'partnumber': + part_number = kwargs.get('part_number', None) + option = kwargs.get('option', 'None') + + if part_number: + body = { + 'SearchByPartRequest': { + 'mouserPartNumber': part_number, + 'partSearchOptions': option, + } + } + + return body + + def part_search(self, part_number, option='None'): + '''Mouser Part Number Search ''' + + kwargs = { + 'part_number': part_number, + 'option': option, + } + + self.body = self.get_body(**kwargs) + + if self.api_key: + return self.run(self.body) + else: + return False diff --git a/kintree/search/mouser/base.py b/kintree/search/mouser/base.py new file mode 100644 index 00000000..ce62f2d2 --- /dev/null +++ b/kintree/search/mouser/base.py @@ -0,0 +1,140 @@ +import os +import csv +import json +import requests + + +# Mouser Base URL +BASE_URL = 'https://api.mouser.com/api/v1.0' +# API Keys File (Default) +API_KEYS_FILE = 'mouser_api_keys.yaml' + + +def get_api_keys(filename=None): + """ Mouser API Keys """ + + # Look for API keys in environmental variables + api_keys = [ + os.environ.get('MOUSER_ORDER_API_KEY', ''), + os.environ.get('MOUSER_PART_API_KEY', ''), + ] + + # Else look into configuration file + if not(api_keys[0] or api_keys[1]) and filename: + try: + with open(filename, 'r') as keys_in_file: + api_keys = [] + + for key in keys_in_file: + api_keys.append(key.replace('\n', '')) + + if len(api_keys) == 2: + return api_keys + else: + pass + except FileNotFoundError: + print(f'[ERROR]\tAPI Keys File "{filename}" Not Found') + + return api_keys + + +class MouserAPIRequest: + """ Mouser API Request """ + + url = None + api_url = None + method = None + body = {} + response = None + api_key = None + + def __init__(self, url, method, file_keys=None, *args): + if not url or not method: + return None + self.api_url = BASE_URL + url + self.method = method + + # Append argument + if len(args) == 1: + self.api_url += '/' + str(args[0]) + + # Append API Key + if self.name == 'Part Search': + self.api_key = get_api_keys(file_keys)[1] + else: + self.api_key = get_api_keys(file_keys)[0] + + if self.api_key: + self.url = self.api_url + '?apiKey=' + self.api_key + + def get(self, url): + response = requests.get(url=url) + return response + + def post(self, url, body): + headers = { + 'Content-Type': 'application/json', + } + response = requests.post(url=url, data=json.dumps(body), headers=headers) + return response + + def run(self, body={}): + if self.method == 'GET': + self.response = self.get(self.url) + elif self.method == 'POST': + self.response = self.post(self.url, body) + + return True if self.response else False + + def get_response(self): + if self.response is not None: + try: + return json.loads(self.response.text) + except json.decoder.JSONDecodeError: + return self.response.text + + return {} + + def print_response(self): + print(json.dumps(self.get_response(), indent=4, sort_keys=True)) + + +class MouserBaseRequest(MouserAPIRequest): + """ Mouser Base Request """ + + name = '' + allowed_methods = ['GET', 'POST'] + operation = None + operations = {} + + def __init__(self, operation, file_keys=None, *args): + ''' Init ''' + + if operation not in self.operations: + print(f'[{self.name}]\tInvalid Operation') + print('-' * 10) + + valid_operations = [operation for operation, values in self.operations.items() if values[0] and values[1]] + if valid_operations: + print('Valid operations:') + for operation in valid_operations: + print(f'- {operation}') + return + + self.operation = operation + (method, url) = self.operations.get(self.operation, ('', '')) + + if not url or not method or method not in self.allowed_methods: + print(f'[{self.name}]\tOperation "{operation}" Not Yet Supported') + return + + super().__init__(url, method, file_keys, *args) + + def export_csv(self, file_path: str, data: dict): + ''' Export dictionary data to CSV ''' + + with open(file_path, 'w') as csvfile: + csvwriter = csv.writer(csvfile) + + for row in data: + csvwriter.writerow(row) diff --git a/kintree/search/mouser_api.py b/kintree/search/mouser_api.py new file mode 100644 index 00000000..6982c71b --- /dev/null +++ b/kintree/search/mouser_api.py @@ -0,0 +1,129 @@ +import os + +from ..config import settings, config_interface +from .mouser.api import MouserPartSearchRequest + +SEARCH_HEADERS = [ + 'Description', + 'productCode', + 'MouserPartNumber', + 'Manufacturer', + 'ManufacturerPartNumber', + 'DataSheetUrl', + 'ProductDetailUrl', + 'ImagePath', +] +PARAMETERS_MAP = [ + 'ProductAttributes', + 'AttributeName', + 'AttributeValue', +] + + +def get_default_search_keys(): + return [ + 'Description', + 'Description', + 'revision', + 'keywords', + 'MouserPartNumber', + 'Manufacturer', + 'ManufacturerPartNumber', + 'ProductDetailUrl', + 'DataSheetUrl', + 'ImagePath', + ] + + +def setup_environment(): + ''' Setup environmental variables ''' + + MOUSER_PART_API_KEY = os.environ.get('MOUSER_PART_API_KEY', None) + if not MOUSER_PART_API_KEY: + mouser_api_settings = config_interface.load_file(settings.CONFIG_MOUSER_API) + os.environ['MOUSER_PART_API_KEY'] = mouser_api_settings['MOUSER_PART_API_KEY'] + + +def find_categories(part_details: str): + ''' Find categories ''' + + try: + return part_details['Category'], None + except: + return None, None + + +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(): + request = MouserPartSearchRequest('partnumber') + request.part_search(part_number) + return request.get_clean_response() + + # Query part number + try: + print('SEARCH MOUSER') + part = search_timeout() + except: + part = None + + if not part: + return part_info + + category, subcategory = find_categories(part) + try: + part_info['category'] = category + part_info['subcategory'] = subcategory + except: + part_info['category'] = '' + part_info['subcategory'] = '' + + headers = SEARCH_HEADERS + + for key in part: + if key in headers: + part_info[key] = part[key] + + # Parameters + part_info['parameters'] = {} + [parameter_key, name_key, value_key] = PARAMETERS_MAP + + for parameter in range(len(part[parameter_key])): + parameter_name = part[parameter_key][parameter][name_key] + parameter_value = part[parameter_key][parameter][value_key] + # Append to parameters dictionary + part_info['parameters'][parameter_name] = parameter_value + + return part_info + + +def test_api() -> bool: + ''' Test method for API ''' + + setup_environment() + + test_success = True + expected = { + 'Description': 'MOSFET P-channel 1.25W', + 'MouserPartNumber': '621-DMP2066LSN-7', + 'Manufacturer': 'Diodes Incorporated', + 'ManufacturerPartNumber': 'DMP2066LSN-7', + } + + test_part = fetch_part_info('DMP2066LSN-7') + + # Check content of response + if test_success: + for key, value in expected.items(): + if test_part[key] != value: + print(f'"{test_part[key]}" <> "{value}"') + test_success = False + break + + return test_success diff --git a/run_tests.py b/run_tests.py index 7b954e64..3fa76d77 100644 --- a/run_tests.py +++ b/run_tests.py @@ -6,7 +6,7 @@ from kintree.config import config_interface from kintree.database import inventree_api, inventree_interface from kintree.kicad import kicad_interface -from kintree.search import digikey_api, lcsc_api +from kintree.search import digikey_api, mouser_api, lcsc_api from kintree.search.snapeda_api import test_snapeda_api from kintree.setup_inventree import setup_inventree @@ -85,6 +85,14 @@ def check_result(status: str, new_part: bool) -> bool: else: cprint('[ PASS ]') +# Test Mouser API +pretty_test_print('[MAIN]\tMouser API Test') +if not mouser_api.test_api(): + cprint('[ FAIL ]') + sys.exit(-1) +else: + cprint('[ PASS ]') + # Test LCSC API pretty_test_print('[MAIN]\tLCSC API Test') if not lcsc_api.test_api():