Skip to content

Commit

Permalink
Merge pull request siliconcompiler#2375 from siliconcompiler/schema-m…
Browse files Browse the repository at this point in the history
…erge-with-init

add _merge_with_init to schema object to handle inconsistent schemas …
  • Loading branch information
gadfort authored Apr 25, 2024
2 parents fb94664 + 8f383d0 commit 9653dca
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 12 deletions.
68 changes: 56 additions & 12 deletions siliconcompiler/schema/schema_obj.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,17 @@ def __init__(self, cfg=None, manifest=None, logger=None):

self._init_logger(logger)

if cfg is not None:
self.cfg = Schema._dict_to_schema(copy.deepcopy(cfg))
elif manifest is not None:
if manifest is not None:
# Normalize value to string in case we receive a pathlib.Path
manifest = str(manifest)
self.cfg = Schema._read_manifest(manifest)
cfg = Schema.__read_manifest_file(str(manifest))

if cfg is not None:
try:
self.cfg = Schema._dict_to_schema(copy.deepcopy(cfg))
except (TypeError, ValueError) as e:
raise ValueError('Attempting to read manifest with '
f'incompatible schema version: {e}') \
from e
else:
self.cfg = self._init_schema_cfg()

Expand Down Expand Up @@ -110,9 +115,54 @@ def _dict_to_schema(cfg):
Schema._dict_to_schema_set(cfg[category], category)
return cfg

###########################################################################
def _merge_with_init_schema(self):
new_schema = Schema()

for keylist in self.allkeys():
if keylist[0] in ('history', 'library'):
continue

if 'default' in keylist:
continue

# only read in valid keypaths without 'default'
key_valid = new_schema.valid(*keylist, default_valid=True)
if not key_valid:
self.logger.warning(f'Keypath {keylist} is not valid')
if not key_valid:
continue

for val, step, index in self._getvals(*keylist, return_defvalue=False):
new_schema.set(*keylist, val, step=step, index=index)

# update other pernode fields
# TODO: only update these if clobber is successful
step_key = Schema.GLOBAL_KEY if not step else step
idx_key = Schema.GLOBAL_KEY if not index else index
for field in self.getdict(*keylist)['node'][step_key][idx_key].keys():
if field == 'value':
continue
new_schema.set(*keylist,
self.get(*keylist, step=step, index=index, field=field),
step=step, index=index, field=field)

if 'library' in self.cfg:
# Handle libraries seperately
for library in self.cfg['library'].keys():
lib_schema = Schema(cfg=self.getdict('library', library))
lib_schema._merge_with_init_schema()
new_schema.cfg['library'][library] = lib_schema.cfg

if 'history' in self.cfg:
# Copy over history
new_schema.cfg['history'] = self.cfg['history']

self.cfg = new_schema.cfg

###########################################################################
@staticmethod
def _read_manifest(filepath):
def __read_manifest_file(filepath):
if not os.path.isfile(filepath):
raise ValueError(f'Manifest file not found {filepath}')

Expand All @@ -133,12 +183,6 @@ def _read_manifest(filepath):
finally:
fin.close()

try:
Schema._dict_to_schema(localcfg)
except (TypeError, ValueError) as e:
raise ValueError(f'Attempting to read manifest with incompatible schema version: {e}') \
from e

return localcfg

def get(self, *keypath, field='value', job=None, step=None, index=None):
Expand Down
38 changes: 38 additions & 0 deletions tests/schema/test_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from siliconcompiler.schema import Schema
from siliconcompiler.schema.schema_cfg import scparam
from siliconcompiler import Chip


def test_list_of_lists():
Expand Down Expand Up @@ -96,3 +97,40 @@ def test_list_of_tuples():
# for a list type
schema.set(*keypath, ['import', '0'])
assert schema.get(*keypath) == expected


def test_merge_with_init_old_has_values():
old_schema = Schema().cfg

scparam(old_schema, ['test'], sctype='[[str]]', shorthelp='Test')

new_schema = Schema(cfg=old_schema)
assert new_schema.getdict('test')

new_schema._merge_with_init_schema()

with pytest.raises(ValueError):
new_schema.getdict('test')


def test_merge_with_init_new_has_values():
old_schema = Schema().cfg

del old_schema['package']

new_schema = Schema(cfg=old_schema)
with pytest.raises(ValueError):
new_schema.getdict('package')

new_schema._merge_with_init_schema()

assert new_schema.getdict('package')


def test_merge_with_init_with_lib():
chip = Chip('')
chip.load_target('asic_demo')

chip.schema._merge_with_init_schema()

assert 'sky130hd' in chip.getkeys('library')

0 comments on commit 9653dca

Please sign in to comment.