A pure-Python parser for Liberty (.lib) files — reads, edits, and writes standard-cell and pad library data for EDA automation workflows
Project description
liberty-parser
A pure-Python parser for Liberty (.lib) cell-library files — the
industry-standard format used by EDA tools to describe the timing, power,
and interface of standard cells.
Features
- Full Liberty grammar — comments, simple attributes, complex attributes, and arbitrarily deep group blocks
- Round-trip write —
write_liberty()reconstructs the file with the exact original whitespace and formatting - In-place editing —
set_val(),set_vals(),set_LU_matrix(),add_simple(),add_complex(),add_block(),remove_block(),merge_blocks() - Hierarchical navigation —
navigate()with exact-match or{RE}regexfilters,navigate_to_base()to walk up the tree - Convenience helpers —
get_cell_list(),get_pin_list(),map_LU_indexes() - Parse from string — no file required; pass a Liberty text block directly
- Zero required dependencies — only the Python standard library
- Optional colored output via
termcolor - CLI included:
liberty-parser cells.lib --cell INV_X1 --pins
Installation
pip install eda-liberty-parser # no extra dependencies
pip install "eda-liberty-parser[color]" # adds termcolor for colored output
Or for development:
git clone https://github.com/rohaansch/liberty-parser
cd liberty-parser
pip install -e ".[dev]"
Quick start
from liberty_parser import LP
lib = LP("cells.lib")
print(lib.get_cell_list())
# ['INV_X1', 'AND2_X1', 'DFFS_X2']
print(lib.get_pin_list(cell="INV_X1"))
# ['A', 'ZN']
# Read a library attribute
time_unit = lib.navigate_single('library', 'time_unit').get_val()
print(time_unit)
# 1ns
Navigation
navigate() accepts a chain of filter strings, one per hierarchy level:
# All cells in the library
cells = lib.navigate('library', 'cell')
# Specific cell by name
inv = lib.navigate_single('library', 'cell:INV_X1')
# Pin direction of a specific pin
direction = lib.navigate_single('library', 'cell:INV_X1', 'pin:ZN', 'direction')
print(direction.get_val())
# output
# Regex filter — find all *_template blocks
for tmpl in lib.navigate('library', '{RE}_template$'):
print(tmpl.get_val())
navigate_single() returns the first match (or None).
navigate_singles() is the fastest variant — stops at the first match at
every level.
In-place editing
All edits modify the in-memory dict and are written back with write_liberty():
# Change a simple attribute value
lib.navigate_single('library', 'time_unit').set_val('2ns')
# Or use the two-argument shorthand (nav_to, new_value)
lib.navigate_single('library').set_val('voltage_unit', '1.8V')
# Edit a lookup-table 2-D matrix
cell_rise = lib.navigate_single(
'library', 'cell:INV_X1', 'pin:ZN', 'timing', 'cell_rise'
)
matrix = cell_rise.get_LU_matrix()
matrix[0][0] = '0.15'
cell_rise.set_LU_matrix(matrix)
# Write back to disk
lib.write_liberty("cells_modified.lib")
Structural edits
library = lib.navigate_single('library')
# Add a new simple attribute
library.add_simple('nom_voltage', '1.8')
# Add a new complex attribute
library.add_complex('operating_conditions', 'typical')
# Remove a cell
cell = lib.navigate_single('library', 'cell:INV_X1')
cell.remove_block()
# Merge another Liberty block into an existing one
lib.navigate_single('library').merge_blocks('extra_cells.lib')
Parsing from a string
No file needed — pass Liberty text directly:
snippet = 'library (mini) { voltage_unit : "1V"; nom_voltage : 1.8; }'
mini = LP(snippet)
print(mini.navigate_single('library', 'nom_voltage').get_val())
# 1.8
Element type predicates
from liberty_parser import is_comment, is_simple_attribute, is_complex_attribute, is_block
for element in lib.navigate('library'):
if is_block(element):
print(f"Block: {element.get_val()}")
elif is_simple_attribute(element):
print(f"Attr: {element.get_val()}")
API reference
LP(arg=None)
| Argument | Behavior |
|---|---|
None |
Create empty LP object |
filepath (.lib file) |
Parse the file |
text (Liberty string) |
Parse the string as a Liberty block |
dict |
Wrap an existing internal dict |
LP |
Share the internal dict of another LP object |
Navigation
| Method | Description |
|---|---|
navigate(*filters) |
Return all matching LP objects |
navigate_single(*filters) |
Return first match at last filter |
navigate_singles(*filters) |
Return first match at every filter (fastest) |
navigate_to_base() |
Walk up to the file root |
Getters
| Method | Description |
|---|---|
get_val(nav_to=None) |
Return value or name string |
get_vals(nav_to=None) |
Return comma-separated value as a list |
get_LU_matrix(nav_to=None) |
Return LU table as a 2-D list |
get_type() |
Return the element type string |
get_cell_list() |
Return all cell names |
get_pin_list(cell=None) |
Return pin names for one or all cells |
map_LU_indexes() |
Return transition/load index map |
Setters
| Method | Description |
|---|---|
set_val(nav_or_val, val=None) |
Set a simple or complex attribute value |
set_vals(nav_or_vals, vals=None) |
Replace comma-separated value list |
set_LU_matrix(nav_or_matrix, matrix=None) |
Replace LU table 2-D matrix |
Structural edits
| Method | Description |
|---|---|
add_simple(name, value, insert_ndx=0) |
Insert a simple attribute |
add_complex(type, name, insert_ndx=0) |
Insert a complex attribute |
add_block(lp_block, insert_ndx=0) |
Insert an LP element |
add_blocks(input, insert_ndx=0) |
Parse and insert multiple elements |
remove_block(ndx=None) |
Remove element at index, or remove self |
move_block(from_index, to_index) |
Reorder elements |
merge_blocks(blocks_input) |
Deep merge another Liberty block |
Write & debug
| Method | Description |
|---|---|
write_liberty(out_path) |
Write parsed dict back to a .lib file |
print(indent=0) |
Pretty-print the internal dict |
Command-line usage
liberty-parser cells.lib
liberty-parser cells.lib --cells
liberty-parser cells.lib --cell INV_X1
liberty-parser cells.lib --cell INV_X1 --pins
liberty-parser cells.lib --attr voltage_unit
liberty-parser --version
Or without installing:
python -m liberty_parser cells.lib --cell INV_X1 --pins
Running the tests
pip install -e ".[dev]"
pytest -v
Companion projects
- sdf-parser — Standard Delay Format
- verilog-parser — Verilog cell-library interfaces
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file eda_liberty_parser-0.1.0.tar.gz.
File metadata
- Download URL: eda_liberty_parser-0.1.0.tar.gz
- Upload date:
- Size: 18.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f66546e9f421f1fb2337cb6fa01458196becf9a99483a034a16bfa61e083501e
|
|
| MD5 |
eaba5a59c01b41ce7b4c1b1cf712a5ad
|
|
| BLAKE2b-256 |
20aa45b56b291f1ac4b8c573f0ceeee24c7ede165753481f1fbcc0361c1736d4
|
File details
Details for the file eda_liberty_parser-0.1.0-py3-none-any.whl.
File metadata
- Download URL: eda_liberty_parser-0.1.0-py3-none-any.whl
- Upload date:
- Size: 17.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
42e25aa34f6ea6f901fb79d5ecfb5526be4705bb7ff89a1f584e251913cf9abe
|
|
| MD5 |
6c91bd04c49aec4973bc692cb734a931
|
|
| BLAKE2b-256 |
7d2c20a5f7cc6782a7a220b408dc216707cbeeb4a395b0a12c14a8d11612ef2a
|