예제 #1
0
            # Fuzzy category matching
            part_info = {'category': 'Capacitors', 'subcategory': 'Super'}
            categories = tuple(inventree_interface.get_categories(part_info))
            if not (categories[0] and categories[1]):
                method_results = False

            # Digi-Key search with missing part number
            search = inventree_interface.digikey_search('')
            if search:
                method_results = False

            # Load KiCad library paths
            config_interface.load_library_path(settings.CONFIG_KICAD,
                                               silent=True)
            symbol_libraries_paths = config_interface.load_libraries_paths(
                settings.CONFIG_KICAD_CATEGORY_MAP, symbol_libraries_test_path)
            footprint_libraries_paths = config_interface.load_footprint_paths(
                settings.CONFIG_KICAD_CATEGORY_MAP,
                footprint_libraries_test_path)
            if not (symbol_libraries_paths and footprint_libraries_paths):
                method_results = False

            # Add symbol library to user file
            add_symbol_lib = config_interface.add_library_path(
                user_config_path=settings.CONFIG_KICAD_CATEGORY_MAP,
                category='category_test',
                symbol_library='symbol_library_test')
            if not add_symbol_lib:
                method_results = False

            # Add footprint library to user file
예제 #2
0
def user_defined_symbol_template_footprint(categories: list,
										   part_number: str,
										   symbol_lib=None,
										   template=None,
										   footprint_lib=None,
										   symbol_confirm=False,
										   footprint_confirm=False):
	''' Symbol and Footprint user defined window '''
	symbol = None
	footprint = None

	if symbol_confirm and '---' not in symbol_lib:
		if not config_interface.add_library_path(user_config_path=settings.CONFIG_KICAD_CATEGORY_MAP,
												 category=categories[0],
												 symbol_library=symbol_lib):
			cprint(f'[INFO]\tWarning: Failed to add symbol library to {categories[0]} category', silent=settings.SILENT)

	if footprint_confirm and '---' not in footprint_lib:
		if not config_interface.add_footprint_library(user_config_path=settings.CONFIG_KICAD_CATEGORY_MAP,
													  category=categories[0],
													  library_folder=footprint_lib):
			cprint(f'[INFO]\tWarning: Failed to add footprint library to {categories[0]} category', silent=settings.SILENT)
	
	# Load user settings
	settings.load_kicad_settings()

	def fuzzy_default(value:str, choices:list) -> str:
		match = None
		LIMIT = 85

		for item in choices:
			fuzzy_match = fuzz.partial_ratio(value, item)
			display_result = f'"{value}" ?= "{item}"'.ljust(50)
			cprint(f'{display_result} => {fuzzy_match}', silent=settings.HIDE_DEBUG)
			if fuzzy_match >= LIMIT:
				match = item
				break

		return match

	def build_choices(items: dict, category: str, subcategory=None) -> list:
		choices = []

		try:
			for key, value in items[category].items():
				if value:
					choices.append(key)
		except:
			if subcategory:
				error_message = f'Warning: No templates defined for "{category}"'
				cprint(f'[INFO]\t{error_message}', silent=settings.SILENT)
				# sg.popup_ok(error_message, title='No Templates', location=(500, 500))

		if subcategory:
			# Load templates only for given category/subcategory pair
			return sorted(choices)

		# Separate libraries not officially assigned to category
		if choices:
			choices.append('-' * 10)

		more_choices = []
		for cat in items.keys():
			if cat != category and cat != 'uncategorized':
				for key in items[cat].keys():
					more_choices.append(key)

		# Process uncategorized entries
		try:
			for item in items['uncategorized']:
				more_choices.append(item)
		except:
			# error_message = f'Warning: No libraries defined for "{category}"'
			# cprint(f'[INFO]\t{error_message}', silent=settings.SILENT)
			# sg.popup_ok(error_message, title='No Libraries', location=(500, 500))
			pass
		try:
			choices.extend(sorted(more_choices))
		except:
			pass

		return choices

	# Load symbol libraries
	if not settings.KICAD_SYMBOLS_PATH:
		sg.popup_ok(f'Error: KiCad symbol library folder path is not defined ("Settings > KiCad")',
					title='KiCad Symbol Library Folder',
					location=(500, 500))
		return symbol, template, footprint

	symbol_library = config_interface.load_libraries_paths(user_config_path=settings.CONFIG_KICAD_CATEGORY_MAP,
														   library_path=settings.KICAD_SYMBOLS_PATH)
	# cprint(symbol_library)
	if not symbol_library:
		sg.popup_ok(f'Error: Symbol library files were not found in {settings.KICAD_SYMBOLS_PATH}',
					title='KiCad Symbol Library Folder',
					location=(500, 500))
		return symbol, template, footprint
	
	# Build symbol choices
	symbol_lib_choices = build_choices(symbol_library, categories[0])
	if symbol_lib:
		symbol_lib_default = symbol_lib
	else:
		# Try fuzzy matching
		symbol_lib_default = fuzzy_default(categories[0], symbol_lib_choices)
		
		if not symbol_lib_default:
			symbol_lib_default = symbol_lib_choices[0]

	# Load templates
	if not settings.KICAD_TEMPLATES_PATH:
		sg.popup_ok(f'Error: KiCad template folder path is not defined ("Settings > KiCad")',
					title='KiCad Template Folder',
					location=(500, 500))
		return symbol, template, footprint

	templates = config_interface.load_templates_paths(user_config_path=settings.CONFIG_KICAD_CATEGORY_MAP,
													  template_path=settings.KICAD_TEMPLATES_PATH)
	# cprint(templates)
	if not templates:
		sg.popup_ok(f'Error: Template files were not found in {settings.KICAD_TEMPLATES_PATH}',
					title='KiCad Template Folder',
					location=(500, 500))
		return symbol, template, footprint
	
	# Build template choices
	if not categories[0]:
		category = symbol_lib_choices[0]
	else:
		category = categories[0]
	if not categories[1]:
		subcategory = 'None'
	else:
		subcategory = categories[1]
	try:
		template_choices = build_choices(templates, category, subcategory)
		
		if template:
			template_default = template
		else:
			template_default = template_choices[0]
	except:
		pass

	if not template_choices:
		template_choices = ['None']
		template_default = template_choices[0]

	# Load footprint libraries
	if not settings.KICAD_FOOTPRINTS_PATH:
		sg.popup_ok(f'Error: KiCad footprint library folder path is not defined ("Settings > KiCad")',
					title='KiCad Footprint Library Folder',
					location=(500, 500))
		return symbol, template, footprint

	footprint_library = config_interface.load_footprint_paths(user_config_path=settings.CONFIG_KICAD_CATEGORY_MAP,
															  footprint_path=settings.KICAD_FOOTPRINTS_PATH)
	# cprint(f'{footprint_library=}')
	if not footprint_library:
		sg.popup_ok(f'Error: Footprint library files were not found in {settings.KICAD_FOOTPRINTS_PATH}',
					title='KiCad Footprint Library Folder',
					location=(500, 500))
		return symbol, template, footprint
	
	# Build symbol choices
	footprint_lib_choices = build_choices(footprint_library, categories[0])

	# Footprint mod list
	footprint_mod_choices = []
	if footprint_lib:
		footprint_lib_default = footprint_lib
		try:
			footprint_lib_path = footprint_library[categories[0]][footprint_lib]
		except:
			pass

		try:
			footprint_mod_choices = [ item.replace('.kicad_mod','') \
									  for item in sorted(os.listdir(footprint_lib_path)) \
									  if os.path.isfile(os.path.join(footprint_lib_path, item)) ]
		except:
			cprint(f'[INFO]\tWarning: Failed fetching footprint mod files for {footprint_lib}', silent=settings.SILENT)
			# cprint(f'{footprint_lib=}\t{categories[0]}', silent=settings.HIDE_DEBUG)
			cprint(footprint_library, silent=settings.HIDE_DEBUG)
	else:
		# Try fuzzy matching
		footprint_lib_default = fuzzy_default(categories[0], footprint_lib_choices)

		if not footprint_lib_default:
			footprint_lib_default = footprint_lib_choices[0]
		try:
			footprint_lib_path = footprint_library[categories[0]][footprint_lib_default]
			footprint_mod_choices = [ item.replace('.kicad_mod','') \
									  for item in sorted(os.listdir(footprint_lib_path)) \
									  if os.path.isfile(os.path.join(footprint_lib_path, item)) ]
		except:
			cprint(f'[INFO]\tWarning: Failed fetching footprint mod files for {footprint_lib_default}', silent=settings.SILENT)
			# cprint(f'{footprint_lib_default=}\t{categories[0]}', silent=settings.HIDE_DEBUG)
			cprint(footprint_library, silent=settings.HIDE_DEBUG)

	if not footprint_mod_choices:
		footprint_mod_choices = ['None']
		footprint_mod_default = footprint_mod_choices[0]
	else:
		footprint_mod_default = None

	library_layout = [
		[
			sg.Text('Select Symbol Library:'),
			sg.Combo(symbol_lib_choices, default_value=symbol_lib_default, key='symbol_lib'),
			sg.Button('Confirm'),
		],
		[
			sg.Text(f'Select Symbol Template ({categories[0]}):'),
			sg.Combo(template_choices, default_value=template_default, key='template'),
		],
		[
			sg.Text('Select Footprint Library:'),
			sg.Combo(footprint_lib_choices, default_value=footprint_lib_default, key='footprint_lib'),
			sg.Button('Confirm'),
		],
		[
			sg.Text('Select Footprint:'),
			sg.Combo(footprint_mod_choices, default_value=footprint_mod_default, key='footprint_mod_sel'),
			sg.Text('Or Enter Name:'),
			sg.In(size=(20,1),key='footprint_mod_man'),
		],
		[ sg.Text('') ],
	]

	if part_number:
		library_layout.append([ sg.Button('Check SnapEDA'), sg.Button('Submit') ])
	else:
		library_layout.append([ sg.Button('Submit') ])

	library_window = sg.Window('KiCad Libraries', library_layout, location=(500, 500))
	lib_event, lib_values = library_window.read()
	library_window.close()

	if lib_event == sg.WIN_CLOSED:
		return symbol, template, footprint
	elif lib_event == 'Check SnapEDA':
		# SnapEDA window
		snapeda_window(part_number)
		return user_defined_symbol_template_footprint(categories=categories,
													  part_number=part_number,
													  symbol_lib=lib_values['symbol_lib'],
													  template=lib_values['template'],
													  footprint_lib=lib_values['footprint_lib'])
	elif lib_event == 'Confirm':
		return user_defined_symbol_template_footprint(categories=categories,
													  part_number=part_number,
													  symbol_lib=lib_values['symbol_lib'],
													  template=lib_values['template'],
													  footprint_lib=lib_values['footprint_lib'],
													  symbol_confirm=True)
	elif lib_event == 'Confirm0':
		return user_defined_symbol_template_footprint(categories=categories,
													  part_number=part_number,
													  symbol_lib=lib_values['symbol_lib'],
													  template=lib_values['template'],
													  footprint_lib=lib_values['footprint_lib'],
													  footprint_confirm=True)
	else:
		symbol = lib_values['symbol_lib']
		template = lib_values['template']
		if lib_values['footprint_mod_man']:
			footprint = lib_values['footprint_lib'] + ':' + lib_values['footprint_mod_man']
		elif lib_values['footprint_mod_sel'] and lib_values['footprint_mod_sel'] != 'None':
			footprint = lib_values['footprint_lib'] + ':' + lib_values['footprint_mod_sel']
		
		if not footprint:
			footprint = lib_values['footprint_lib'] + ':' + settings.footprint_name_default

		# Save paths
		if not config_interface.add_library_path(user_config_path=settings.CONFIG_KICAD_CATEGORY_MAP,
												 category=categories[0],
												 symbol_library=lib_values['symbol_lib']):
			cprint(f'[INFO]\tWarning: Failed to add symbol library to {categories[0]} category', silent=settings.SILENT)

		if not config_interface.add_footprint_library(user_config_path=settings.CONFIG_KICAD_CATEGORY_MAP,
													  category=categories[0],
													  library_folder=lib_values['footprint_lib']):
			cprint(f'[INFO]\tWarning: Failed to add footprint library to {categories[0]} category', silent=settings.SILENT)

		return symbol, template, footprint
예제 #3
0
def main():
	''' Main GUI window '''

	# Create user configuration files
	if not settings.create_user_config_files():
		cprint('\n[ERROR]\tSome Ki-nTree configuration files seem to be missing')
		return

	CREATE_CUSTOM = False

	# Select PySimpleGUI theme
	# sg.theme_previewer() # Show all
	sg.theme('DarkTeal10')

	# Main Menu
	menu_def = [
		['Settings', 
			[	
				'Digi-Key',
				'KiCad',
				'InvenTree',
			],
		],
		[ 'More', 
			[
				# 'Synchronize',
				'Custom Part',
			],
		],
	]
	# Main Window
	layout = [
		[sg.Menu(menu_def,)],
		[
			sg.Text('Enter Part Number:'),
			sg.InputText(key='part_number'),
		],
		[
			sg.Checkbox('Add to KiCad', enable_events=True, default=settings.ENABLE_KICAD, key='enable_kicad'),
			sg.Checkbox('Add to InvenTree', enable_events=True, default=settings.ENABLE_INVENTREE, key='enable_inventree'),
		],
		[
			sg.Button('CREATE', size=(59,1)),
		],
	]

	# Create the Window
	window = sg.Window(f'Ki-nTree [{settings.version}]', 
						layout, 
						location=(500, 500) )

	# Event Loop to process 'events' and get the 'values' of the inputs
	while True:
		if CREATE_CUSTOM:
			event = 'CREATE_CUSTOM'
		else:
			event, values = window.read()

		if event == sg.WIN_CLOSED:  # if user closes window or clicks cancel
			break

		if event == 'Digi-Key':
			search_api_settings_window()
		elif event == 'InvenTree':
			inventree_settings_window()
		elif event == 'KiCad':
			kicad_settings_window()
		elif 'enable' in event:
			settings.set_inventree_enable_flag(values['enable_inventree'], save=True)
			settings.set_kicad_enable_flag(values['enable_kicad'], save=True)
		elif event == 'Custom Part':
			custom_part_info = add_custom_part(part_data={})
			if custom_part_info:
				CREATE_CUSTOM = True
		else:
			# Adding part information to InvenTree
			categories = [None, None]
			symbol = None
			template = None
			footprint = None
			new_part = False
			part_pk = 0
			part_info = {}
			part_data = {}
			progressbar = False

			if CREATE_CUSTOM:
				if custom_part_info['name'] and custom_part_info['description']:
					part_info = custom_part_info
					cprint('\n[MAIN]\tCustom Part', silent=settings.SILENT)
			else:
				if values['part_number']:
					# New part separation
					new_search = '-' * 20
					cprint(f'\n{new_search}', silent=settings.SILENT)

					# Load KiCad settings
					settings.load_kicad_settings()

					# Load InvenTree settings
					settings.load_inventree_settings()

					# SnapEDA test
					# snapeda_window(values['part_number'])

					# Digi-Key Search
					part_info = inventree_interface.digikey_search(values['part_number'])

			if not part_info:
				# Missing Part Information
				if CREATE_CUSTOM:
					sg.popup_ok(f'Missing "Name" and "Description"',
								title='Incomplete Custom Part Data',
								location=(500, 500))
				else:
					sg.popup_ok(f'Failed to fetch part information\n'
								'Make sure:\n- Digi-Key API settings are correct ("Settings > Digi-Key")'
								'\n- Part number is valid',
								title='Digi-Key API Search',
								location=(500, 500))
			else:
				if settings.ENABLE_INVENTREE:
					cprint('\n[MAIN]\tConnecting to Inventree server', silent=settings.SILENT)
					inventree_connect = inventree_interface.connect_to_server()
					if part_info and not inventree_connect:
						sg.popup_ok(f'Failed to access InvenTree server\nMake sure your username and password are correct',
									title='InvenTree Server Error',
									location=(500, 500))
						# Reset part info
						part_info = {}

			# User Categories
			if part_info and (settings.ENABLE_INVENTREE or settings.ENABLE_KICAD):
				if settings.ENABLE_INVENTREE:
					cprint('\n[MAIN]\tCreating part in Inventree', silent=settings.SILENT)

				categories = inventree_interface.get_categories(part_info=part_info,
																supplier_only=False)
			
				# If categories do not exist: request user to fill in categories
				if not categories[0]:
					categories = user_defined_categories(extend=settings.ENABLE_INVENTREE)
					if categories[0]:
						cprint(f'[INFO]\tCategory: "{categories[0]}"', silent=settings.SILENT)
					if categories[1]:
						cprint(f'[INFO]\tSubcategory: "{categories[1]}"', silent=settings.SILENT)
				elif categories[0] and not categories[1]:
					categories = user_defined_categories(category=categories[0],
														 extend=settings.ENABLE_INVENTREE)
					if categories[1]:
						cprint(f'[INFO]\tUpdated Category: "{categories[0]}"', silent=settings.SILENT)
						cprint(f'[INFO]\tSubcategory: "{categories[1]}"', silent=settings.SILENT)
				else:
					# Ask user to re-confirm categories (pre-filled)
					categories = user_defined_categories(category=categories[0], 
														 subcategory=categories[1],
														 extend=settings.ENABLE_INVENTREE)
					cprint(f'[INFO]\tUser Category: "{categories[0]}"', silent=settings.SILENT)
					cprint(f'[INFO]\tUser Subcategory: "{categories[1]}"', silent=settings.SILENT)

			# User Part Info
			if not (categories[0] and categories[1]):
				part_info = {}
			else:
				if CREATE_CUSTOM:
					# Translate custom part data
					part_info = inventree_interface.translate_form_to_digikey(part_info=part_info,
																			  categories=categories,
																			  custom=True)
				else:
					# Add to supplier categories configuration file
					category_dict = {
						categories[0]:
							{ categories[1]: part_info['subcategory'] }
					}
					if not config_interface.add_supplier_category(category_dict, settings.CONFIG_DIGIKEY_CATEGORIES):
						config_file = settings.CONFIG_DIGIKEY_CATEGORIES.split(os.sep)[-1]
						cprint(f'[INFO]\tWarning: Failed to add new supplier category to {config_file} file', silent=settings.SILENT)
						cprint(f'[DBUG]\tcategory_dict = {category_dict}', silent=settings.SILENT)

					# Confirm part data with user
					form_data = add_custom_part(inventree_interface.translate_digikey_to_inventree(part_info=part_info,
																								   categories=categories,
																								   skip_params=True))
					if form_data:
						# Translate to part info format
						user_part_info = inventree_interface.translate_form_to_digikey(part_info=form_data,
																				  	   categories=categories,
																				  	   custom=False)

						# Merge original part_info with user_part_info
						part_info = {**part_info, **user_part_info}
					else:
						# User did not proceed
						part_info = {}

			# Set KiCad user libraries and symbol/footprint
			if part_info and settings.ENABLE_KICAD:
				# Request user to select symbol and footprint libraries
				symbol, template, footprint = user_defined_symbol_template_footprint(categories, values['part_number'])
				# cprint(f'{symbol=}\t{template=}\t{footprint=}', silent=settings.HIDE_DEBUG)
				if not symbol and not footprint:
					part_info = {}
			
			if part_info:
				# Create progress bar window
				progressbar = progress.create_progress_bar_window()

				# InvenTree
				if (symbol and footprint) or settings.ENABLE_INVENTREE:
					
					# Create part in InvenTree
					if settings.ENABLE_INVENTREE:
						new_part, part_pk, part_data = inventree_interface.inventree_create(part_info=part_info,
																							categories=categories,
																							kicad=settings.ENABLE_KICAD,
																							symbol=symbol,
																							footprint=footprint,
																							show_progress=progressbar)
						if not part_data:
							cprint(f'[INFO]\tError: Could not add part to InvenTree', silent=settings.SILENT)

					else:
						if not categories[0]:
							pseudo_categories = [symbol, None]
							part_data = inventree_interface.translate_digikey_to_inventree(part_info=part_info,
																						   categories=pseudo_categories)
						else:
							part_data = inventree_interface.translate_digikey_to_inventree(part_info=part_info,
																						   categories=categories)
							part_data['parameters']['Symbol'] = symbol
							part_data['parameters']['Footprint'] = footprint
						if not part_data:
							cprint(f'[INFO]\tError: Could not format part data', silent=settings.SILENT)

			if part_data:
				if not settings.ENABLE_INVENTREE:
					# Replace IPN with part name if InvenTree is not used (no part number)
					if CREATE_CUSTOM:
						try:
							manufacturer = part_data['manufacturer'].keys()[0]
							part_data['IPN'] = part_data['manufacturer'][manufacturer][0]
						except:
							part_data['IPN'] = part_data['name']
					else:
						part_data['IPN'] = values['part_number']
					if part_data['datasheet']:
						part_data['inventree_url'] = part_data['datasheet']

				kicad_success = False

				# KiCad
				if settings.ENABLE_KICAD:
					# Reload paths
					settings.load_kicad_settings()
					symbol_libraries_paths = config_interface.load_libraries_paths(settings.CONFIG_KICAD_CATEGORY_MAP, settings.KICAD_SYMBOLS_PATH)
					symbol_templates_paths = config_interface.load_templates_paths(settings.CONFIG_KICAD_CATEGORY_MAP, settings.KICAD_TEMPLATES_PATH)

					# Adding part symbol to KiCAD
					cprint(f'\n[MAIN]\tAdding part to KiCad', silent=settings.SILENT)

					if not symbol:
						kicad_error = 'Incorrect symbol choice'
						cprint(f'[INFO]\tError: {kicad_error}', silent=settings.SILENT)
					elif not template:
						kicad_error = 'Incorrect template choice'
						cprint(f'[INFO]\tError: {kicad_error}', silent=settings.SILENT)
					elif not footprint:
						kicad_error = 'Incorrect footprint choice'
						cprint(f'[INFO]\tError: {kicad_error}', silent=settings.SILENT)
					else:
						try:
							library_path = symbol_libraries_paths[categories[0]][symbol]
						except:
							library_path = symbol_libraries_paths[symbol][symbol]
							
						if template == 'None':
							cprint(f'[INFO]\tWarning: Missing template, using default', silent=settings.SILENT)
							template_path = settings.KICAD_TEMPLATES_PATH + 'default.lib'
						else:
							try:
								template_path = symbol_templates_paths[categories[0]][template]
							except:
								template_path = symbol_templates_paths[symbol][template]

						try:
							library_directory = os.path.dirname(library_path)
						except:
							library_directory = None
							cprint(f'[INFO]\tError: Failed to map library file', silent=settings.SILENT)
						
						if library_directory:
							if settings.AUTO_GENERATE_LIB:
								create_library(library_directory, symbol, settings.symbol_template_lib)

							try:
								kicad_success, kicad_new_part = kicad_interface.inventree_to_kicad(part_data=part_data,
																								   library_path=library_path,
																								   template_path=template_path,
																								   show_progress=progressbar)
							except:
								cprint(f'[INFO]\tError: Failed to add part to KiCad (incomplete InvenTree data)', silent=settings.SILENT)

				# Final result message
				result_message = ''

				# Result pop-up window
				if settings.ENABLE_INVENTREE:
					if not new_part:
						if part_pk:
							result_message = 'Part already in InvenTree database'
						else:
							result_message = 'Error while adding part to InvenTree (check output)'
					else:
						result_message = 'Part added to InvenTree database'
				if settings.ENABLE_KICAD and settings.ENABLE_INVENTREE:
					result_message += '\n'
				if settings.ENABLE_KICAD:
					if not kicad_success:
						result_message += 'Error while adding part in KiCad (check output)'
						try:
							result_message += f'\nINFO: {kicad_error}'
						except:
							pass
					else:
						if kicad_new_part:
							result_message += 'Part added to KiCad library'
						else:
							result_message += 'Part already in KiCad library'

			else:
				if settings.ENABLE_INVENTREE:
					if not categories[0] or categories[1]:
						result_message = 'Part categories were not set properly'
				if settings.ENABLE_INVENTREE or settings.ENABLE_KICAD:
					if not part_data:
						result_message = 'Part data not found - Check part number'
					if not part_pk:
						result_message = 'Unexpected error - Contact developper'

			# Update progress bar to complete and close window
			if progressbar:
				progress.update_progress_bar_window(progress.MAX_PROGRESS)
				progress.close_progress_bar_window()

			if symbol and result_message:
				sg.popup_ok(result_message, title='Results', location=(500, 500))

			if part_data.get('inventree_url', None):
				# Auto-Open Browser Window
				cprint(f'\n[MAIN]\tOpening URL {part_data["inventree_url"]} in browser',
					   silent=settings.SILENT)
				try:
					webbrowser.open(part_data['inventree_url'], new=2)
				except TypeError:
					cprint(f'[INFO]\tError: Failed to open URL', silent=settings.SILENT)

			# Reset create custom flag
			CREATE_CUSTOM = False

	window.close()
예제 #4
0
# Enable flag
def set_kicad_enable_flag(value: bool, save=False):
	global ENABLE_KICAD
	ENABLE_KICAD = value
	if save:
		global CONFIG_KICAD
		kicad_user_settings = config_interface.load_inventree_user_settings(
			CONFIG_KICAD)
		kicad_user_settings['KICAD_ENABLE'] = value
		config_interface.dump_file(kicad_user_settings, CONFIG_KICAD)
	return

# Library Paths
if not ENABLE_TEST:
	symbol_libraries_paths = config_interface.load_libraries_paths(
		CONFIG_KICAD_CATEGORY_MAP, KICAD_SYMBOLS_PATH)
# cprint(symbol_libraries_paths)

# Template Paths
symbol_templates_paths = config_interface.load_templates_paths(
	CONFIG_KICAD_CATEGORY_MAP, KICAD_TEMPLATES_PATH)
# cprint(symbol_templates_paths)

# Footprint Libraries
footprint_libraries_paths = config_interface.load_footprint_paths(
	CONFIG_KICAD_CATEGORY_MAP, KICAD_FOOTPRINTS_PATH)
# cprint(footprint_libraries_paths)
footprint_name_default = 'TBD'

AUTO_GENERATE_LIB = True
symbol_template_lib = os.path.join(