From 69c025e4b598a5af226ab401fb1c98b3e691c593 Mon Sep 17 00:00:00 2001 From: Grzegorz Latosinski Date: Wed, 2 Dec 2020 12:04:26 +0100 Subject: [PATCH 1/3] base: added methods for iterating over libraries, versions and cells Signed-off-by: Grzegorz Latosinski --- .../python-skywater-pdk/skywater_pdk/base.py | 68 ++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/scripts/python-skywater-pdk/skywater_pdk/base.py b/scripts/python-skywater-pdk/skywater_pdk/base.py index bcfc7e845..39b5d8287 100644 --- a/scripts/python-skywater-pdk/skywater_pdk/base.py +++ b/scripts/python-skywater-pdk/skywater_pdk/base.py @@ -22,7 +22,8 @@ from dataclasses import dataclass from dataclasses_json import dataclass_json from enum import Enum -from typing import Optional, Union, Tuple +from typing import Optional, Union, Tuple, Iterator +from pathlib import Path from .utils import comparable_to_none from .utils import dataclass_json_passthru_config as dj_pass_cfg @@ -504,6 +505,71 @@ def parse(cls, s): kw['name'] = bits.pop(0) return cls(**kw) + @classmethod + def get_libraries(cls, libroot : str) -> Iterator['Library']: + """ + Lists libraries present in the libroot directory. + + Parameters + ---------- + libroot : str + Path to the Skywater PDK libraries + + Yields + ------ + Library : next library object + """ + libroot = Path(libroot) + for libdir in libroot.iterdir(): + if libdir.is_dir(): + yield cls.parse(libdir.name) + + def get_versions(self, libroot : str) -> Iterator['LibraryVersion']: + """ + Lists versions of the library. + + Parameters + ---------- + libroot : str + Path to the Skywater PDK libraries. + + Yields + ------ + LibraryVersion : next version of the library + """ + libdir = Path(libroot) / self.fullname + for version in libdir.iterdir(): + if version.is_dir() and version.name != 'latest': + yield LibraryVersion.parse(version.name) + + def get_cells(self, libroot) -> Iterator['Cell']: + """ + Lists cells for the library. + + If the version of the library is not specified, the cells for the + 'latest' version are listed. + + Parameters + ---------- + libroot : str + Path to the Skywater PDK libraries. + + Yields + ------ + Cell : next cell in the library + """ + libdir = Path(libroot) / self.fullname + version = 'latest' + if self.version: + version = f'v{self.version.fullname}' + libdir = libdir / version / 'cells' + assert libdir.is_dir() + for cell in libdir.iterdir(): + if cell.is_dir(): + cell = Cell.parse(cell.name) + cell.library = self + yield cell + @dataclass_json @dataclass From dbba89f5494c3411905e11b966d61521a93ce36a Mon Sep 17 00:00:00 2001 From: Grzegorz Latosinski Date: Wed, 2 Dec 2020 15:43:16 +0100 Subject: [PATCH 2/3] base: added method for converting Library/Cell to corresponding path Signed-off-by: Grzegorz Latosinski --- .../python-skywater-pdk/skywater_pdk/base.py | 46 ++++++++++++++++++- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/scripts/python-skywater-pdk/skywater_pdk/base.py b/scripts/python-skywater-pdk/skywater_pdk/base.py index 39b5d8287..05ae949c7 100644 --- a/scripts/python-skywater-pdk/skywater_pdk/base.py +++ b/scripts/python-skywater-pdk/skywater_pdk/base.py @@ -157,7 +157,6 @@ def parse_pathname(pathname): return lib, filename - def parse_filename(pathname) -> Tuple[LibraryOrCell, Optional[str], Optional[str]]: """Extract library and module name from filename. @@ -258,6 +257,50 @@ def parse_filename(pathname) -> Tuple[LibraryOrCell, Optional[str], Optional[str return (library, extra, extension) +def convert_to_path(libraryorcell: LibraryOrCell, libdir : str): + """Create path to the library or cell from the objects + + Parameters + ---------- + libraryorcell : Library or Cell + Library or Cell information + libdir : str + Path to the root directory of the Skywater PDK libraries + + Returns + ------- + str : Path to the library (or cell) directory + + See Also + -------- + skywater_pdk.base.parse_pathname + skywater_pdk.base.Cell + skywater_pdk.base.Library + + Examples + -------- + + >>> lib = parse_pathname('libraries/sky130_fd_pr/v0.0.1')[0] + >>> convert_to_path(lib, 'libraries') + 'libraries/sky130_fd_pr/v0.0.1' + >>> cell = parse_pathname('libraries/sky130_fd_pr/v0.20.1/cells/cap_mim_m3/sky130_fd_pr__cap_mim_m3_1.model.spice')[0] + >>> convert_to_path(cell, 'libraries') + 'libraries/sky130_fd_pr/v0.20.1/cells/cap_mim_m3' + """ + assert type(libraryorcell) is Library or type(libraryorcell) is Cell + libdir = Path(libdir) + if type(libraryorcell) is Library: + version = (f'v{libraryorcell.version.fullname}' + if libraryorcell.version else 'latest') + return str(libdir / libraryorcell.fullname / version) + if type(libraryorcell) is Cell: + library = libraryorcell.library + version = (f'v{library.version.fullname}' + if library.version else 'latest') + libname = library.fullname + return str(libdir / libname / version / 'cells' / libraryorcell.name) + + SEPERATOR = "__" @comparable_to_none @@ -621,7 +664,6 @@ def parse(cls, s): return cls(**kw) - if __name__ == "__main__": import doctest doctest.testmod() From 2770251073a0efcdb28547beddc61de432f009d2 Mon Sep 17 00:00:00 2001 From: Grzegorz Latosinski Date: Wed, 2 Dec 2020 16:18:11 +0100 Subject: [PATCH 3/3] base: moved libdir parameter as field in the Library Signed-off-by: Grzegorz Latosinski --- .../python-skywater-pdk/skywater_pdk/base.py | 56 +++++++++++-------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/scripts/python-skywater-pdk/skywater_pdk/base.py b/scripts/python-skywater-pdk/skywater_pdk/base.py index 05ae949c7..7eda136a8 100644 --- a/scripts/python-skywater-pdk/skywater_pdk/base.py +++ b/scripts/python-skywater-pdk/skywater_pdk/base.py @@ -518,6 +518,7 @@ class Library: type: LibraryType = dj_pass_cfg() name: str = '' version: Optional[LibraryVersion] = None + rootdir: str = '' @property def fullname(self): @@ -530,7 +531,7 @@ def fullname(self): return "_".join(output) @classmethod - def parse(cls, s): + def parse(cls, s, libroot=''): if SEPERATOR in s: raise ValueError( "Found separator '__' in library name: {!r}".format(s)) @@ -546,10 +547,11 @@ def parse(cls, s): kw['type'] = LibraryType.parse(bits.pop(0)) if bits: kw['name'] = bits.pop(0) + kw['rootdir'] = libroot return cls(**kw) @classmethod - def get_libraries(cls, libroot : str) -> Iterator['Library']: + def get_libraries(cls, libroot : str = '') -> Iterator['Library']: """ Lists libraries present in the libroot directory. @@ -563,55 +565,46 @@ def get_libraries(cls, libroot : str) -> Iterator['Library']: Library : next library object """ libroot = Path(libroot) + assert libroot.is_dir() for libdir in libroot.iterdir(): if libdir.is_dir(): - yield cls.parse(libdir.name) + yield cls.parse(libdir.name, libroot) - def get_versions(self, libroot : str) -> Iterator['LibraryVersion']: + def get_versions(self) -> Iterator['LibraryVersion']: """ Lists versions of the library. - Parameters - ---------- - libroot : str - Path to the Skywater PDK libraries. - Yields ------ LibraryVersion : next version of the library """ - libdir = Path(libroot) / self.fullname + libdir = Path(self.rootdir) / self.fullname for version in libdir.iterdir(): if version.is_dir() and version.name != 'latest': yield LibraryVersion.parse(version.name) - def get_cells(self, libroot) -> Iterator['Cell']: + def get_cells(self) -> Iterator['Cell']: """ Lists cells for the library. If the version of the library is not specified, the cells for the 'latest' version are listed. - Parameters - ---------- - libroot : str - Path to the Skywater PDK libraries. - Yields ------ Cell : next cell in the library """ - libdir = Path(libroot) / self.fullname + libdir = Path(self.rootdir) / self.fullname version = 'latest' if self.version: version = f'v{self.version.fullname}' libdir = libdir / version / 'cells' - assert libdir.is_dir() - for cell in libdir.iterdir(): - if cell.is_dir(): - cell = Cell.parse(cell.name) - cell.library = self - yield cell + if libdir.is_dir(): + for cell in libdir.iterdir(): + if cell.is_dir(): + cell = Cell.parse(cell.name) + cell.library = self + yield cell @dataclass_json @@ -663,6 +656,23 @@ def parse(cls, s): kw['name'] = s return cls(**kw) + def get_matching_files(self, pattern) -> Iterator[str]: + """ + Yields files for a matching pattern for a given cell if present. + + Parameters + ---------- + pattern : str + The file pattern to look for + + Yields + ------ + str : path to files for a given cell + """ + celldir = Path(convert_to_path(self, self.library.rootdir)) + for filename in celldir.glob(pattern): + yield str(filename) + if __name__ == "__main__": import doctest