Skip to content

Commit

Permalink
improve spice library
Browse files Browse the repository at this point in the history
  • Loading branch information
FabriceSalvaire committed Jan 26, 2024
1 parent fd89227 commit a05f0f5
Show file tree
Hide file tree
Showing 7 changed files with 220 additions and 74 deletions.
24 changes: 17 additions & 7 deletions PySpice/Scripts/Library.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

####################################################################################################

from PySpice.Spice.Library import SpiceLibrary
from PySpice.Spice.Library import SpiceLibrary, Model, Subcircuit

####################################################################################################

Expand Down Expand Up @@ -87,9 +87,7 @@ def main() -> None:
library_path = Path(args.library_path).resolve()
print(f"Library is {library_path}")

# scan = args.search is not None or args.scan
scan = False
spice_library = SpiceLibrary(library_path, scan=scan)
spice_library = SpiceLibrary(library_path, scan=args.scan)

if args.delete_yaml:
rc = input('Confirm deletion (y/n): ')
Expand All @@ -110,6 +108,18 @@ def main() -> None:
if args.search:
print()
print(f'Results for "{args.search}":')
for name, path in spice_library.search(args.search).items():
path = path.relative_to(library_path)
print(f" {name} {path}")
# list() to don't mix logging and print
for name, include in list(spice_library.search(args.search)):
path = include.path.relative_to(library_path)
print(' '*2 + f"{name} {path}")
indent = ' '*4
if include.description:
print(f"{indent}Library: {include.description}")
_ = include[name]
is_model = isinstance(_, Model)
if is_model:
print(f"{indent}Model: {_.name}{_.description}")
else:
print(f"{indent}Subcircuit: {_.name}{_.description}")
pins = ' '.join(_.pin_names)
print(f"{indent}Pins: {pins}")
57 changes: 34 additions & 23 deletions PySpice/Spice/Library/Library.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@
####################################################################################################

from pathlib import Path
from typing import Iterator
from typing import Iterable, Iterator

import logging
import os
import pickle
import re

from .SpiceInclude import SpiceInclude
from PySpice.Spice.Parser import Subcircuit, Model
from PySpice.Tools import PathTools
from .SpiceInclude import SpiceInclude, is_yaml

####################################################################################################

Expand Down Expand Up @@ -70,25 +70,38 @@ class SpiceLibrary:

##############################################

def __init__(self, root_path: str | Path, scan: bool = True) -> None:
def __init__(self, root_path: str | Path, scan: bool = False) -> None:
self._path = PathTools.expand_path(root_path)
if not self._path.exists():
self._path.mkdir(parents=True)
self._logger.info(f"Created {self._path}")
self._subcircuits = {}
self._models = {}
if not scan:
if self.has_db_path:
self.load()
else:
self._logger.info("Initialize library...")
scan = True
if scan:
self.scan()
self.save()
else:
self.load()

##############################################

@property
def db_path(self) -> Path:
return self._path.joinpath('db.pickle')

@property
def has_db_path(self) -> bool:
return self.db_path.exists()

##############################################

def __bool__(self) -> bool:
return bool(self._subcircuits or self._models)

##############################################

def __getstate__(self):
Expand All @@ -114,13 +127,10 @@ def save(self) -> None:
pickle.dump(_, fh)

def load(self) -> None:
if self.db_path.exists():
self._logger.info(f"Load {self.db_path}")
with open(self.db_path, 'rb') as fh:
_ = pickle.load(fh)
self.__setstate__(_)
else:
self._logger.warning("uninitialised library")
self._logger.info(f"Load {self.db_path}")
with open(self.db_path, 'rb') as fh:
_ = pickle.load(fh)
self.__setstate__(_)

##############################################

Expand Down Expand Up @@ -155,40 +165,43 @@ def list_categories(self) -> str:
##############################################

def scan(self) -> None:
self._logger.info(f"Scan {self._path}...")
for path in PathTools.walk(self._path):
extension = path.suffix.lower()
if extension in self.EXTENSIONS:
_ = path.suffix.lower()
if _ in self.EXTENSIONS:
self._handle_library(path)

##############################################

def _handle_library(self, path: Path) -> None:
spice_include = SpiceInclude(path)
# Fixme: check overwrite
self._models.update({_.name: path for _ in spice_include.models})
self._subcircuits.update({_.name: path for _ in spice_include.subcircuits})

##############################################

def delete_yaml(self) -> None:
for path in PathTools.walk(self._path):
extension = path.suffix.lower()
if extension == '.yaml':
if is_yaml(path):
self._logger.info(f"{NEWLINE}Delete {path}")
path.unlink()

##############################################

def __getitem__(self, name: str) -> Subcircuit | Model:
if not (self._subcircuits or self._models):
if not self:
self._logger.warning("Empty library")
if name in self._subcircuits:
return self._subcircuits[name]
path = self._subcircuits[name]
elif name in self._models:
return self._models[name]
path = self._models[name]
else:
# print('Library {} not found in {}'.format(name, self._path))
# self._logger.warn('Library {} not found in {}'.format(name, self._path))
raise KeyError(name)
# Fixme: lazy ???
return SpiceInclude(path)[name]

##############################################

Expand All @@ -214,14 +227,12 @@ def models(self) -> Iterator[Model]:

# ##############################################

def search(self, regexp: str) -> dict[str, Subcircuit | Model]:
def search(self, regexp: str) -> Iterable[tuple[str, SpiceInclude]]:
""" Return dict of all models/subcircuits with names matching regex. """
regexp = re.compile(regexp)
matches = {}
models_subcircuits = {**self._models, **self._subcircuits}
if not models_subcircuits:
self._logger.warning("Empty library")
for name, _ in models_subcircuits.items():
if regexp.search(name):
matches[name] = _
return matches
yield name, SpiceInclude(_)
Loading

0 comments on commit a05f0f5

Please sign in to comment.