0321 from macmini

This commit is contained in:
2025-03-21 13:28:36 +08:00
commit cd1fd4bdfa
11397 changed files with 4528845 additions and 0 deletions

View File

@ -0,0 +1,59 @@
import os
import pcbnew
from .xmlparser import XmlParser
from .netlistparser import NetlistParser
PARSERS = {
'.xml': XmlParser,
'.net': NetlistParser,
}
if hasattr(pcbnew, 'FOOTPRINT'):
PARSERS['.kicad_pcb'] = None
def parse_schematic_data(file_name):
if not os.path.isfile(file_name):
return None
extension = os.path.splitext(file_name)[1]
if extension not in PARSERS:
return None
else:
parser_cls = PARSERS[extension]
if parser_cls is None:
return None
parser = parser_cls(file_name)
return parser.get_extra_field_data()
def find_latest_schematic_data(base_name, directories):
"""
:param base_name: base name of pcb file
:param directories: list of directories to search
:return: last modified parsable file path or None if not found
"""
files = []
for d in directories:
files.extend(_find_in_dir(d))
# sort by decreasing modification time
files = sorted(files, reverse=True)
if files:
# try to find first (last modified) file that has name matching pcb file
for _, f in files:
if os.path.splitext(os.path.basename(f))[0] == base_name:
return f
# if no such file is found just return last modified
return files[0][1]
else:
return None
def _find_in_dir(dir):
_, _, files = next(os.walk(dir), (None, None, []))
# filter out files that we can not parse
files = [f for f in files if os.path.splitext(f)[1] in PARSERS.keys()]
files = [os.path.join(dir, f) for f in files]
# get their modification time and sort in descending order
return [(os.path.getmtime(f), f) for f in files]

View File

@ -0,0 +1,59 @@
import io
from .parser_base import ParserBase
from .sexpressions import parse_sexpression
class NetlistParser(ParserBase):
def get_extra_field_data(self):
with io.open(self.file_name, 'r', encoding='utf-8') as f:
sexpression = parse_sexpression(f.read())
components = None
for s in sexpression:
if s[0] == 'components':
components = s[1:]
if components is None:
return None
field_set = set()
comp_dict = {}
for c in components:
ref = None
fields = None
datasheet = None
libsource = None
dnp = False
for f in c[1:]:
if f[0] == 'ref':
ref = f[1]
if f[0] == 'fields':
fields = f[1:]
if f[0] == 'datasheet':
datasheet = f[1]
if f[0] == 'libsource':
libsource = f[1:]
if f[0] == 'property' and isinstance(f[1], list) and \
f[1][0] == 'name' and f[1][1] == 'dnp':
dnp = True
if ref is None:
return None
ref_fields = comp_dict.setdefault(ref, {})
if datasheet and datasheet != '~':
field_set.add('Datasheet')
ref_fields['Datasheet'] = datasheet
if libsource is not None:
for lib_field in libsource:
if lib_field[0] == 'description':
field_set.add('Description')
ref_fields['Description'] = lib_field[1]
if dnp:
field_set.add('kicad_dnp')
ref_fields['kicad_dnp'] = "DNP"
if fields is None:
continue
for f in fields:
if len(f) > 1:
field_set.add(f[1][1])
if len(f) > 2:
ref_fields[f[1][1]] = f[2]
return list(field_set), comp_dict

View File

@ -0,0 +1,26 @@
class ParserBase:
def __init__(self, file_name):
"""
:param file_name: path to file that should be parsed.
"""
self.file_name = file_name
def get_extra_field_data(self):
# type: () -> tuple
"""
Parses the file and returns extra field data.
:return: tuple of the format
(
[field_name1, field_name2,... ],
{
ref1: {
field_name1: field_value1,
field_name2: field_value2,
...
],
ref2: ...
}
)
"""
pass

View File

@ -0,0 +1,32 @@
import re
term_regex = r'''(?mx)
\s*(?:
(?P<open>\()|
(?P<close>\))|
(?P<sq>"(?:\\\\|\\"|[^"])*")|
(?P<s>[^(^)\s]+)
)'''
pattern = re.compile(term_regex)
def parse_sexpression(sexpression):
stack = []
out = []
for terms in pattern.finditer(sexpression):
term, value = [(t, v) for t, v in terms.groupdict().items() if v][0]
if term == 'open':
stack.append(out)
out = []
elif term == 'close':
assert stack, "Trouble with nesting of brackets"
tmp, out = out, stack.pop(-1)
out.append(tmp)
elif term == 'sq':
out.append(value[1:-1].replace('\\\\', '\\').replace('\\"', '"'))
elif term == 's':
out.append(value)
else:
raise NotImplementedError("Error: %s, %s" % (term, value))
assert not stack, "Trouble with nesting of brackets"
return out[0]

View File

@ -0,0 +1,42 @@
from xml.dom import minidom
from .parser_base import ParserBase
class XmlParser(ParserBase):
@staticmethod
def get_text(nodelist):
rc = []
for node in nodelist:
if node.nodeType == node.TEXT_NODE:
rc.append(node.data)
return ''.join(rc)
def get_extra_field_data(self):
xml = minidom.parse(self.file_name)
components = xml.getElementsByTagName('comp')
field_set = set()
comp_dict = {}
for c in components:
ref_fields = comp_dict.setdefault(c.attributes['ref'].value, {})
datasheet = c.getElementsByTagName('datasheet')
if datasheet:
datasheet = self.get_text(datasheet[0].childNodes)
if datasheet != '~':
field_set.add('Datasheet')
ref_fields['Datasheet'] = datasheet
libsource = c.getElementsByTagName('libsource')
if libsource and libsource[0].hasAttribute('description'):
field_set.add('Description')
attr = libsource[0].attributes['description']
ref_fields['Description'] = attr.value
for f in c.getElementsByTagName('field'):
name = f.attributes['name'].value
field_set.add(name)
ref_fields[name] = self.get_text(f.childNodes)
for f in c.getElementsByTagName('property'):
if f.attributes['name'].value == 'dnp':
field_set.add('kicad_dnp')
ref_fields['kicad_dnp'] = "DNP"
return list(field_set), comp_dict