def extractCsvComponents(self): if globals.CsvSeparator not in self.contents[1]: return 'error: no delimiter found in CSV. ' + '"' + globals.CsvSeparator + '" expected. See config.ini' # Find the order of the parameters saved in the csv header = self.contents[0] header = header.strip('\n') header = header.strip('\r') columnNames = header.split(globals.CsvSeparator) if len(columnNames) < 7: return 'error: missing delimiter(s) in CSV. ' + 'At least 7 occurrences of "' + globals.CsvSeparator + '" expected. See config.ini' for c in columnNames: new_csv_field = KicadField() new_csv_field.name = c self.fieldList.append(new_csv_field) #parse date belonging to component for i in range(1, len(self.contents)): newCsvComponent = CsvComponent() dataLine = self.contents[i] newCsvComponent.Contents = self.contents[i] dataLine = dataLine.strip('\n') dataLine = dataLine.strip('\r') values = dataLine.split(globals.CsvSeparator) column = 0 for value in values: # TODO 3: replace these constants with a common definition in globals if columnNames[column] == 'Part': newCsvComponent.name = value elif columnNames[column] == 'Reference': newCsvComponent.reference = value elif columnNames[column] == 'Unit': newCsvComponent.unit = value elif columnNames[column] == 'Value': newCsvComponent.value = value elif columnNames[column] == 'Footprint': newCsvComponent.footprint = value elif columnNames[column] == 'Datasheet': newCsvComponent.datasheet = value elif columnNames[column] == 'File': newCsvComponent.schematic = value else: newCsvComponent.propertyList.append( [self.fieldList[column], value]) column += 1 # end for all values in dataLine self.components.append(newCsvComponent) DT.info("finished component extractions")
def extractCsvComponents(self, filename: str): self.deleteContents() try: with open(filename, newline='\n') as csvfile: reader = csv.DictReader(csvfile, delimiter=globals.CsvSeparator, quotechar='"') if len(reader.fieldnames) < 7: return 'error: missing delimiter(s) in CSV. ' + 'At least 7 occurrences of "' + globals.CsvSeparator + '" expected. See config.ini' for c in reader.fieldnames: new_csv_field = KicadField() new_csv_field.name = c self.fieldList.append(new_csv_field) # get property field names: propertyFieldNames = copy.deepcopy(reader.fieldnames) for mand in self.MandatoryFields: propertyFieldNames.remove(mand) if 'Index' in propertyFieldNames: propertyFieldNames.remove('Index') DT.info('Property field names in CSV: ' + str(propertyFieldNames)) for row in reader: # parse data belonging to component newCsvComponent = CsvComponent() # TODO 3: replace these constants with a common definition in globals newCsvComponent.name = row['Part'] newCsvComponent.reference = row['Reference'] newCsvComponent.unit = row['Unit'] newCsvComponent.value = row['Value'] newCsvComponent.footprint = row['Footprint'] newCsvComponent.datasheet = row['Datasheet'] newCsvComponent.schematic = row['File'] for key in propertyFieldNames: newCsvComponent.propertyDict[key] = row[key] self.components.append(newCsvComponent) csvfile.close() except EnvironmentError as e: return str(e) DT.info("finished component extractions")
def load_csv(): DT.clear() config = ConfigParser() config.read('config.ini') initialDirectory = config.get('main', 'lastDirectory', fallback="") #mainSchematicFile.printprops() if initialDirectory == "": root.filename = filedialog.askopenfilename( filetypes=(("KiCAD Partslist-editor files", ".csv"), ("All Files", ".*"))) else: root.filename = filedialog.askopenfilename(initialdir=initialDirectory, filetypes=( ("KiCAD Partslist-editor files", ".csv"), ("All Files", ".*"))) filename = root.filename config.read('config.ini') if config.has_section('main') == FALSE: config.add_section('main') config.set('main', 'lastDirectory', os.path.dirname(filename)) with open('config.ini', 'w') as f: config.write(f) if filename[-4:] == ".csv" or filename[-4:] == ".CSV": error = csvFile.extractCsvComponents(filename) if error: messagebox.showerror("Incorrect Fileformat", error) else: statusLabel['text'] = "Import: " + str(root.filename) + " complete" + "\n" + str(len(csvFile.components)) + " components were imported" f.close() else: if filename: messagebox.showerror("FileParseError", "This is not a valid CSV document (*.csv or *.CSV)") print("Summary for importing from CSV: ") DT.summary() DT.info(str(len(csvFile.components)) + ' components were imported from CSV')
def extractProperties(self): # temporary dictionay, if we have all fields found fieldFound = {} for anyField in self.fieldList: fieldFound[anyField] = False fieldTemplate = "" # used for new extra fields maxFieldNr = 3 # used for new extra fields; 0 to 3 are default fields lastExistingFieldLine = 0 # used for adding new extra fields; relative to $COMP (which is zero) for line_nr in range(len(self.contents)): line = self.contents[line_nr] # Example for a resistor with component=R and ref=R609 # L R R609 # the reference here is a common reference, if it is used in multiple instances of a subsheet if line[0] == "L": searchResult = re.search('L +(.*) +(.*)', line) if searchResult: componentName = searchResult.group(1) componentRef = searchResult.group(2) self.reference = componentRef self.name = componentName DT.debug("Found Component: " + componentName + " " + componentRef) # Special case for power-components: don't parse them if componentRef[0] == "#": self.unlisted = True return # no further parsing for unlisted components continue else: DT.error("Regex Missmatch for L-record in line: " + line + " in file " + self.schematicName) # endelse # endif L # Unit: Example # U 1 1 5873950B if line[0:2] == "U ": searchResult = re.search('U +(\d*) +(\d+) +([0-9A-Fa-f]+) *', line) if searchResult: componentUnit = searchResult.group(1) componentMm = searchResult.group( 2 ) # could not find a proper meaning of this value other than 'mm' componentTimestamp = searchResult.group(3) # unused here self.unit = componentUnit continue else: DT.error("Regex Missmatch for 'U '-record in line: " + line + " in file " + self.schematicName) # end else # endif U # Example: # AR Path="/56647084/5664BC85" Ref="U501" Part="2" # the number for Part= varies e.g. from 1 to 4 for a component with 4 Units (e.g. LM324) # NOTE; it is not clear, for what reason we get this record only for some components... # we print just a message # for now, we don't use the data any further if "AR Path=" in line: # extract the path, Ref and Part into regex groups: searchResult = re.search( 'AR +Path="(.*)" +Ref="(.*)" +Part="(.*)".*', line) if searchResult: componentPath = searchResult.group(1) componentRef = searchResult.group(2) componentUnit = searchResult.group(3) # Print some messages DT.debug('AR Record: ' + componentPath + ' ' + componentRef + ' ' + componentUnit) # Example # F 0 "R51" H 5820 2046 50 0000 L CNN if line[0:4] == "F 0 ": if line_nr > lastExistingFieldLine: lastExistingFieldLine = line_nr searchResult = re.search('F 0 +"(.*)" +.*', line) if searchResult: componentRef = searchResult.group(1) # TODO 1: handle proper reference name for multiple instances # we get the unique references only from the AR-records!!! #self.referenceUnique = componentRef if not (componentRef == self.reference): DT.info("L record value doesn't match 'F 0 ' record: "\ + self.reference + " vs. " + componentRef + " in '" +\ line + "' in file " + self.schematicName + ". Using 'F 0' records value: " + componentRef) self.reference = componentRef continue else: DT.error("Regex Missmatch for 'F 0 '-record in line: " +\ line + " in file " + self.schematicName) # endelse # endif F 0 # Value, Example: # F 1 "LTC2052IS#PBF" H 9750 5550 50 0000 C CNN if "F 1 " in line: # find f1 indicating value field in EEschema file format if line_nr > lastExistingFieldLine: lastExistingFieldLine = line_nr searchResult = re.search('F 1 +"(.*)".*', line) if searchResult: componentValue = searchResult.group(1) self.value = componentValue continue else: DT.error( "Regex Mismatch, cannot find value in 'F 1 '-record in '" + line + "' in file " + self.schematicName) # end if # endif F 1 # Footprint, Example: # F 2 "standardSMD:R0603" V 5680 2000 50 0001 C CNN if "F 2 " in line: # find f2 indicating Footprint field in EEschema file format if line_nr > lastExistingFieldLine: lastExistingFieldLine = line_nr searchResult = re.search('F 2 +"(.*)".*', line) if searchResult: componentFootprint = searchResult.group(1) self.footprint = componentFootprint continue else: DT.error( "Regex Mismatch, cannot find value in 'F 2 '-record (footprint) in '" + line + "' in file " + self.schematicName) # end if # endif F 2 # # Datasheet; Example: # F 3 "" H 5750 2000 50 0000 C CNN if "F 3 " in line: # find f3 indicating Datasheet field in EEschema file format if line_nr > lastExistingFieldLine: lastExistingFieldLine = line_nr fieldTemplate = line # use the Datasheet field as a template for new extra fields searchResult = re.search('F 3 +"(.*)".*', line) if searchResult: componentDatasheet = searchResult.group(1) self.datasheet = componentDatasheet continue else: DT.error( "Regex Mismatch, cannot find value in 'F 3 '-record (datasheet) in '" + line + "' in file " + self.schematicName) # end if # endif F 3 else: # Custom Fields, Example: # F 4 "C3216-100n-50V" H 8450 6050 60 0001 C CNN "InternalName" searchResult = re.search('F +([0-9]+) +"(.*)" +.*"(.*)".*', line) if searchResult: if line_nr > lastExistingFieldLine: lastExistingFieldLine = line_nr fieldNr = int(searchResult.group(1)) if fieldNr > maxFieldNr: maxFieldNr = fieldNr fieldValue = searchResult.group(2) fieldName = searchResult.group(3) print(fieldValue) print(fieldName) tempFound = False for anyField in self.fieldList: for Alias in anyField.Aliases: if Alias == fieldName: if fieldFound[anyField] is True: DT.warning( "duplicate definition of Field " + fieldName + " with Alias " + Alias + " for Component " + self.getReference() + " in file " + self.schematicName) fieldFound[anyField] = True tempFound = True cf = ComponentField() cf.setContent(line) cf.relativeLine = line_nr self.propertyList.append(cf) print(fieldName + "added to propertylist ") break if tempFound == True: break if tempFound == True: continue
def ModifyNewSCHFile(self, oldSCHFile, csvFile, savepath): # TODO 1: don't call this multiple times, if it is referred multiple times in parent sheets! # --> more efficient, avoid possible errors # TODO 2: improve this messages: SCH and CSV parts should match DT.info("Number of Parts in CSV: " + str(len(csvFile.components))) DT.info("Number of Parts in this SCH: " + str(len(self.components))) if len(csvFile.components) and len(self.components): for i in range(len(csvFile.components)): #Loop over csv_components for p in range(len( self.components)): #loop over .sch components if csvFile.components[i].reference == self.components[p].getReference() and \ self.schematicName == csvFile.components[i].getSchematic() and \ csvFile.components[i].unit == self.components[p].unit: #if annotation and schematic name match comp = self.components[p] # assign KiCad's default fields: comp.name = csvFile.components[i].name comp.value = csvFile.components[i].value comp.footprint = csvFile.components[i].footprint comp.datasheet = csvFile.components[i].datasheet lineTemplate = "" for ii in range(comp.startPosition, comp.endPosition): line = self.contents[ii] helper = ComponentField( ) # helper for creating 'F x ' records if line[0:2] == 'L ': self.contents[ ii] = 'L ' + comp.name + ' ' + comp.reference + '\n' elif line[0:4] == 'F 1 ': # component value helper.setContent(line) helper.value = comp.value self.contents[ii] = helper.getContent() lineTemplate = line # save a template line for newly to be created fields elif line[0:4] == 'F 2 ': # component footprint helper.setContent(line) helper.value = comp.footprint self.contents[ii] = helper.getContent() elif line[0:4] == 'F 3 ': # component datasheet helper.setContent(line) helper.value = comp.datasheet self.contents[ii] = helper.getContent() comp.updateAllMatchingFieldValues( csvFile.components[i].propertyList) for property in range(len(comp.propertyList)): if comp.propertyList[property].exists: self.contents[comp.startPosition+comp.propertyList[property].relativeLine] = \ comp.propertyList[property].getContent() else: # otherwise we have to append it self.contents[comp.startPosition+comp.propertyList[property].relativeLine] += \ comp.propertyList[property].getContent() # end for(all properties) # end if components match # end for all schematic components #end for all csv components try: f = open(savepath, 'w') f.writelines(self.contents) except Exception as e: print('Error: ' + e) return str(e) for i in range(len(self.subcircuits)): newSavePath = os.path.join(os.path.dirname(savepath), self.namesOfSubcircuits[i]) DT.info(newSavePath) self.subcircuits[i].ModifyNewSCHFile(0, csvFile, newSavePath) #mainFile.ModifyNewSCHFile(0, openCSVFile,savePath): else: DT.error("No components loaded")