<!-- SPDX-FileCopyrightText: 2025 Tymoteusz Blazejczyk <tymoteusz.blazejczyk@tymonx.com> -->
<!-- SPDX-License-Identifier: Apache-2.0 -->
# PyTCL
**PyTCL** allows control **EDA** tools directly from **Python** that use **TCL**.
## Features
- It executes Python method with provided positional arguments directly as TCL procedure
For example invocation of Python `<object>.<name>(*args)` method is like calling TCL procedure `<name> {*}${args}`
- Any Python value is converted to TCL value like for example Python `list` to TCL list
- Result from invoked TCL procedure is returned as `pytcl.TCLValue` that can handle any TCL value
(that is represented always as string) to Python `str`, `int`, `bool`, `float`, `list`, `dict`, ...
- TCL error is returned as Python exception `pytcl.TCLError`
- High performance and very low (unnoticeable) overhead by using Unix domain sockets or Windows named pipes
for communication between Python and TCL in streamable way (sockets/pipes are always open and ready)
- It allows to create and access TCL variables from Python side. Please see [tests/test_tclsh.py] for some examples
- It can work with any EDA tool. Please see [tests/test_vivado.py] how to use bare `PyTCL` class for that
- It supports Linux, macOS and Windows
- No external dependencies
## Install
```python
pip install pytcl-eda
```
## Examples
Creating new Vivado project:
```python
#!/usr/bin/env python3
from pathlib import Path
from pytcl import Vivado
def main() -> None:
"""Create new Vivado project."""
hdl_dir: Path = Path.cwd() / "hdl"
project_dir: Path = Path.cwd() / "my-awesome-project"
with Vivado() as vivado:
# See Vivado Design Suite Tcl Command Reference Guide (UG835) for all available Vivado TCL procedures
# https://docs.amd.com/r/en-US/ug835-vivado-tcl-commands
vivado.create_project(project_dir.name, project_dir)
vivado.add_files(hdl_dir / "my_awesome_design.sv")
synthesis_runs = list(vivado.get_runs("synth_*"))
vivado.launch_runs(synthesis_runs)
# wait_on_runs was introduced in Vivado 2021.2. For backward compatibility we will use wait_on_run
# https://docs.amd.com/r/2021.2-English/ug835-vivado-tcl-commands/wait_on_runs
# Vivado >= 2021.2 can just use: vivado.wait_on_runs(synthesis_runs)
for run in synthesis_runs:
vivado.wait_on_run(run)
implementation_runs = list(vivado.get_runs("impl_*"))
vivado.launch_runs(implementation_runs)
for run in implementation_runs:
vivado.wait_on_run(run)
vivado.close_project()
if __name__ == "__main__":
main()
```
To use any EDA tool where `PyTCL` doesn't provide neat helper classes like `pytcl.Vivado`
you can use the `pytcl.PyTCL` class directly:
```python
#!/usr/bin/env python3
from pathlib import Path
from pytcl import PyTCL
def main() -> None:
"""Create new Vivado project."""
project_dir: Path = Path.cwd() / "my-awesome-project"
# PyTCL offers some string placeholders {} that you can use:
# {tcl} -> it will insert <pytcl>/execute.tcl
# {address} -> it will insert Unix socket, Windows named pipe or network address
cmd: list[str] = [
"vivado",
"-nojournal",
"-notrace",
"-nolog",
"-mode",
"batch",
"-source",
"{tcl}",
"-tclargs",
"{address}",
]
with PyTCL(*cmd) as vivado:
vivado.create_project(project_dir.name, project_dir)
# Do the same magic that you would normally do in TCL
vivado.close_project()
if __name__ == "__main__":
main()
```
## Architecture
```mermaid
stateDiagram-v2
direction LR
PyTCL --> connection: send()
connection --> execute.py: string
state tool {
execute.py --> execute.tcl: stdin
execute.tcl --> execute.py: stdout
}
execute.py --> connection: NDJSON
connection --> PyTCL: recv()
```
- `PyTCL` will run tool with `execute.tcl <address>` arguments in separate process
- `execute.tcl` invoked by tool will invoke `execute.py`
- `execute.py` will start new connection listener on provided `<address>`
- `PyTCL` will try connect to `<address>` as client
- `PyTCL` will transform any Python method call `<object>.<name>(*args)` to TCL expression `<name> {*}${args}`
- `PyTCL` will send TCL expression as string to `execute.py` via `<address>`
- `execute.py` will print received TCL expression to standard output `stdout`
- `execute.tcl` will capture received TCL expression from `execute.py` using standard input `stdin`
- `execute.tcl` will evaluate received TCL expression
- `execute.tcl` will print result of evaluated TCL expression back to `execute.py` using standard output `stdout`
in form of [NDJSON] `{"result": "<tcl-result>", "status": <tcl-status>}`
- `execute.py` will capture above result using standard input `stdin` and send it back to `PyTCL`
- `PyTCL` will return received [NDJSON] message as `pytcl.TCLValue`
- `PyTCL` will raise a Python exception `pytcl.TCLError` if received TCL status was non-zero
## Development
Create [Python virtual environment]:
```plaintext
python3 -m venv .venv
```
Activate created [Python virtual environment]:
```plaintext
. .venv/bin/activate
```
Upgrade [pip]:
```plaintext
pip install --upgrade pip
```
Install project in [editable mode] with [pytest]:
```plaintext
pip install --editable .[test]
```
Run tests:
```plaintext
pytest
```
[ndjson]: https://docs.python.org/3/library/venv.html
[python virtual environment]: https://docs.python.org/3/library/venv.html
[editable mode]: https://setuptools.pypa.io/en/latest/userguide/development_mode.html
[pytest]: https://docs.pytest.org/en/stable/
[pip]: https://pip.pypa.io/en/stable/
[tests/test_tclsh.py]: https://gitlab.com/tymonx/pytcl/-/blob/main/tests/test_tclsh.py
[tests/test_vivado.py]: https://gitlab.com/tymonx/pytcl/-/blob/main/tests/test_vivado.py
Raw data
{
"_id": null,
"home_page": null,
"name": "pytcl-eda",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "altera, asic, cadence, eda, flow, fpga, hdl, modelsim, python, quartus, questa, rtl, script, scripting, siemens, synopsys, systemverilog, tcl, vcs, verilog, vhdl, vivado, xcelium, xilinx",
"author": null,
"author_email": "Tymoteusz Blazejczyk <tymoteusz.blazejczyk@tymonx.com>",
"download_url": "https://files.pythonhosted.org/packages/ad/a1/91db9881a4753479288f95117b4d0a19f248c5bbd11a27175d442cc1820d/pytcl_eda-0.3.0.tar.gz",
"platform": null,
"description": "<!-- SPDX-FileCopyrightText: 2025 Tymoteusz Blazejczyk <tymoteusz.blazejczyk@tymonx.com> -->\n<!-- SPDX-License-Identifier: Apache-2.0 -->\n\n# PyTCL\n\n**PyTCL** allows control **EDA** tools directly from **Python** that use **TCL**.\n\n## Features\n\n- It executes Python method with provided positional arguments directly as TCL procedure\n For example invocation of Python `<object>.<name>(*args)` method is like calling TCL procedure `<name> {*}${args}`\n- Any Python value is converted to TCL value like for example Python `list` to TCL list\n- Result from invoked TCL procedure is returned as `pytcl.TCLValue` that can handle any TCL value\n (that is represented always as string) to Python `str`, `int`, `bool`, `float`, `list`, `dict`, ...\n- TCL error is returned as Python exception `pytcl.TCLError`\n- High performance and very low (unnoticeable) overhead by using Unix domain sockets or Windows named pipes\n for communication between Python and TCL in streamable way (sockets/pipes are always open and ready)\n- It allows to create and access TCL variables from Python side. Please see [tests/test_tclsh.py] for some examples\n- It can work with any EDA tool. Please see [tests/test_vivado.py] how to use bare `PyTCL` class for that\n- It supports Linux, macOS and Windows\n- No external dependencies\n\n## Install\n\n```python\npip install pytcl-eda\n```\n\n## Examples\n\nCreating new Vivado project:\n\n```python\n#!/usr/bin/env python3\nfrom pathlib import Path\nfrom pytcl import Vivado\n\ndef main() -> None:\n \"\"\"Create new Vivado project.\"\"\"\n hdl_dir: Path = Path.cwd() / \"hdl\"\n project_dir: Path = Path.cwd() / \"my-awesome-project\"\n\n with Vivado() as vivado:\n # See Vivado Design Suite Tcl Command Reference Guide (UG835) for all available Vivado TCL procedures\n # https://docs.amd.com/r/en-US/ug835-vivado-tcl-commands\n vivado.create_project(project_dir.name, project_dir)\n vivado.add_files(hdl_dir / \"my_awesome_design.sv\")\n\n synthesis_runs = list(vivado.get_runs(\"synth_*\"))\n vivado.launch_runs(synthesis_runs)\n\n # wait_on_runs was introduced in Vivado 2021.2. For backward compatibility we will use wait_on_run\n # https://docs.amd.com/r/2021.2-English/ug835-vivado-tcl-commands/wait_on_runs\n # Vivado >= 2021.2 can just use: vivado.wait_on_runs(synthesis_runs)\n for run in synthesis_runs:\n vivado.wait_on_run(run)\n\n implementation_runs = list(vivado.get_runs(\"impl_*\"))\n vivado.launch_runs(implementation_runs)\n\n for run in implementation_runs:\n vivado.wait_on_run(run)\n\n vivado.close_project()\n\nif __name__ == \"__main__\":\n main()\n```\n\nTo use any EDA tool where `PyTCL` doesn't provide neat helper classes like `pytcl.Vivado`\nyou can use the `pytcl.PyTCL` class directly:\n\n```python\n#!/usr/bin/env python3\nfrom pathlib import Path\nfrom pytcl import PyTCL\n\ndef main() -> None:\n \"\"\"Create new Vivado project.\"\"\"\n project_dir: Path = Path.cwd() / \"my-awesome-project\"\n\n # PyTCL offers some string placeholders {} that you can use:\n # {tcl} -> it will insert <pytcl>/execute.tcl\n # {address} -> it will insert Unix socket, Windows named pipe or network address\n cmd: list[str] = [\n \"vivado\",\n \"-nojournal\",\n \"-notrace\",\n \"-nolog\",\n \"-mode\",\n \"batch\",\n \"-source\",\n \"{tcl}\",\n \"-tclargs\",\n \"{address}\",\n ]\n\n with PyTCL(*cmd) as vivado:\n vivado.create_project(project_dir.name, project_dir)\n\n # Do the same magic that you would normally do in TCL\n\n vivado.close_project()\n\nif __name__ == \"__main__\":\n main()\n```\n\n## Architecture\n\n```mermaid\nstateDiagram-v2\n direction LR\n PyTCL --> connection: send()\n connection --> execute.py: string\n state tool {\n execute.py --> execute.tcl: stdin\n execute.tcl --> execute.py: stdout\n }\n execute.py --> connection: NDJSON\n connection --> PyTCL: recv()\n```\n\n- `PyTCL` will run tool with `execute.tcl <address>` arguments in separate process\n- `execute.tcl` invoked by tool will invoke `execute.py`\n- `execute.py` will start new connection listener on provided `<address>`\n- `PyTCL` will try connect to `<address>` as client\n- `PyTCL` will transform any Python method call `<object>.<name>(*args)` to TCL expression `<name> {*}${args}`\n- `PyTCL` will send TCL expression as string to `execute.py` via `<address>`\n- `execute.py` will print received TCL expression to standard output `stdout`\n- `execute.tcl` will capture received TCL expression from `execute.py` using standard input `stdin`\n- `execute.tcl` will evaluate received TCL expression\n- `execute.tcl` will print result of evaluated TCL expression back to `execute.py` using standard output `stdout`\n in form of [NDJSON] `{\"result\": \"<tcl-result>\", \"status\": <tcl-status>}`\n- `execute.py` will capture above result using standard input `stdin` and send it back to `PyTCL`\n- `PyTCL` will return received [NDJSON] message as `pytcl.TCLValue`\n- `PyTCL` will raise a Python exception `pytcl.TCLError` if received TCL status was non-zero\n\n## Development\n\nCreate [Python virtual environment]:\n\n```plaintext\npython3 -m venv .venv\n```\n\nActivate created [Python virtual environment]:\n\n```plaintext\n. .venv/bin/activate\n```\n\nUpgrade [pip]:\n\n```plaintext\npip install --upgrade pip\n```\n\nInstall project in [editable mode] with [pytest]:\n\n```plaintext\npip install --editable .[test]\n```\n\nRun tests:\n\n```plaintext\npytest\n```\n\n[ndjson]: https://docs.python.org/3/library/venv.html\n[python virtual environment]: https://docs.python.org/3/library/venv.html\n[editable mode]: https://setuptools.pypa.io/en/latest/userguide/development_mode.html\n[pytest]: https://docs.pytest.org/en/stable/\n[pip]: https://pip.pypa.io/en/stable/\n[tests/test_tclsh.py]: https://gitlab.com/tymonx/pytcl/-/blob/main/tests/test_tclsh.py\n[tests/test_vivado.py]: https://gitlab.com/tymonx/pytcl/-/blob/main/tests/test_vivado.py\n",
"bugtrack_url": null,
"license": "Apache-2.0",
"summary": "PyTCL allows control EDA tools directly from Python that use TCL",
"version": "0.3.0",
"project_urls": {
"Documentation": "https://gitlab.com/tymonx/pytcl/-/blob/HEAD/README.md",
"Homepage": "https://gitlab.com/tymonx/pytcl",
"Issues": "https://gitlab.com/tymonx/pytcl/-/issues",
"Source": "https://gitlab.com/tymonx/pytcl.git"
},
"split_keywords": [
"altera",
" asic",
" cadence",
" eda",
" flow",
" fpga",
" hdl",
" modelsim",
" python",
" quartus",
" questa",
" rtl",
" script",
" scripting",
" siemens",
" synopsys",
" systemverilog",
" tcl",
" vcs",
" verilog",
" vhdl",
" vivado",
" xcelium",
" xilinx"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "9c2dfb485e48af513f699ba27b3c6c1ff473a6eb0fefa36f3856add2f54e428d",
"md5": "04702a7d97d6cbaf48fed02e9bebf4e1",
"sha256": "7888521859d85fd951076aff43057b029ba60bd1b52e33df0629a44c447a2af1"
},
"downloads": -1,
"filename": "pytcl_eda-0.3.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "04702a7d97d6cbaf48fed02e9bebf4e1",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 10509,
"upload_time": "2025-08-11T07:27:29",
"upload_time_iso_8601": "2025-08-11T07:27:29.122047Z",
"url": "https://files.pythonhosted.org/packages/9c/2d/fb485e48af513f699ba27b3c6c1ff473a6eb0fefa36f3856add2f54e428d/pytcl_eda-0.3.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "ada191db9881a4753479288f95117b4d0a19f248c5bbd11a27175d442cc1820d",
"md5": "1ec2bb91dac61fc411a7bb7517bcf509",
"sha256": "f39ba3a24b9e6e9608a5b338f62582eb75f8c245caf567dacec63db6387d4fa8"
},
"downloads": -1,
"filename": "pytcl_eda-0.3.0.tar.gz",
"has_sig": false,
"md5_digest": "1ec2bb91dac61fc411a7bb7517bcf509",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 12950,
"upload_time": "2025-08-11T07:27:29",
"upload_time_iso_8601": "2025-08-11T07:27:29.978777Z",
"url": "https://files.pythonhosted.org/packages/ad/a1/91db9881a4753479288f95117b4d0a19f248c5bbd11a27175d442cc1820d/pytcl_eda-0.3.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-11 07:27:29",
"github": false,
"gitlab": true,
"bitbucket": false,
"codeberg": false,
"gitlab_user": "tymonx",
"gitlab_project": "pytcl",
"lcname": "pytcl-eda"
}