{"id":15442771,"url":"https://github.com/flightaware/tohil","last_synced_at":"2025-07-23T09:05:32.050Z","repository":{"id":44616162,"uuid":"349147332","full_name":"flightaware/tohil","owner":"flightaware","description":"a feathered serpent, delightful integration between python, the serpent, and TCL, the feather...","archived":false,"fork":false,"pushed_at":"2025-05-26T23:50:12.000Z","size":1028,"stargazers_count":26,"open_issues_count":9,"forks_count":11,"subscribers_count":23,"default_branch":"main","last_synced_at":"2025-07-06T10:21:46.813Z","etag":null,"topics":["python","tcl-extension"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/flightaware.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-03-18T16:40:08.000Z","updated_at":"2025-05-26T23:50:16.000Z","dependencies_parsed_at":"2025-04-19T18:44:57.844Z","dependency_job_id":"44b85a62-deb7-4c66-bb4e-5b9a71187f94","html_url":"https://github.com/flightaware/tohil","commit_stats":null,"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/flightaware/tohil","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flightaware%2Ftohil","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flightaware%2Ftohil/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flightaware%2Ftohil/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flightaware%2Ftohil/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/flightaware","download_url":"https://codeload.github.com/flightaware/tohil/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flightaware%2Ftohil/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266649139,"owners_count":23962176,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-23T02:00:09.312Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["python","tcl-extension"],"created_at":"2024-10-01T19:29:58.995Z","updated_at":"2025-07-23T09:05:32.031Z","avatar_url":"https://github.com/flightaware.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Tohil\n\n[![Linux CI](https://github.com/flightaware/tohil/actions/workflows/linux-ci.yml/badge.svg)](https://github.com/flightaware/tohil/actions/workflows/linux-ci.yml)\n\n\u003cimg src=\"https://github.com/flightaware/tohil/blob/main/graphics/237px-Quetzalcoatl_feathered_serpent.png\"\u003e\n\nTohil a feathered serpent, aims to provide a delightful integration between Python, the serpent, and TCL, the feather.\n\nTohil is simultaneously a Python extension and a TCL extension that makes it possible to effortlessly call bidirectionally between Tcl and Python, targeting Tcl 8.6+ and Python 3.6+\n\nTohil is open source software, available for free including for profit and/or for redistribution, under the permissive 3-clause BSD license (see \"LICENSE.txt\").\n\nTohil is pronounced as, your choice, toe-heel, or toe-hill.\n\nTohil has a growing body of documentation, including a tutorial\nand reference, available at https://flightaware.github.io/tohil-docs/.\n\n## Usage\n\nYou can import Tohil into either a Tcl or Python parent interpreter. Doing so will create and initialize an interpreter for the corresponding language and define Tohil's functions in both.\n\nUsing Tohil, Python code can call Tcl code at any time, and vice versa, and they can call \"through\" each other, i.e. Python can call Tcl code that calls Python code that calls Tcl code, and so on.\n\n### Accessing Tcl From Python\n\nTo use Python to do things in Tcl, you invoke functions defined by the Tohil module that gets created when you import Tohil into your Python interpreter.\n\nTohil:\n\n* ...provides several routines to evaluate Tcl code, passing it data using common and familiar Python objects such as strs, bools, ints, floats, lists, dicts, tuples, etc, and producing those types from Tcl results as well.\n* ...defines a new Python data type, [tohil.tclobj](https://flightaware.github.io/tohil-docs/tutorial/tohil_tclobjs.html), that provides direct and efficient manipulation of Tcl, well, strings, of course, but strings containing ints, floats, lists, dicts, etc, passing them around, using them as arguments in calls to Tcl functions, and receiving them from function results as well.\n* ...creates shadow dictionaries, a Python dictionary-type object that accesses and manipulates Tcl arrays as Python dictionaries.\n* ...provides a [TclProc class](https://flightaware.github.io/tohil-docs/tutorial/tohil_tclprocs.html) that creates callable Python object-functions that will call their corresponding Tcl procs and C commands and return the results to Python, optionally with a specified Python type that the returned data should be converted to.\n* ...provides a TclNamespace class that has the ability to import all the Tcl procs and C commands found there as methods of the namespace class, and recursively descend child namespaces, creating new TclNamespaces objects, binding them to their parent objects, and importing all the procs found within them as well.  See also the Tohil 3 [release notes](https://flightaware.github.io/tohil-docs/whatsnew/3.0.html).\n\nHere's a simple example of using Tohil to get Tcl to format a Unix \"epoch\" clock\ninto a standard Posix time and date string, in the French locale:\n\n```python\n\u003e\u003e\u003e import tohil\n\u003e\u003e\u003e clock = 1616182348\n\u003e\u003e\u003e tohil.eval(f\"clock format {clock} -locale es -gmt 1\", to=str)\n'vie mar 19 19:32:28 GMT 2021'\n```\n\nThe optional _to_ named parameter allows you to specify one of a number of data types, or a processing function, that will cause Tohil to convert the return into a native Python data type.\n\nThe types supported are str, int, bool, float, list, set, dict, tuple, tohil.tclobj, and tohil.tcldict.\n\nBy default the results of the Tcl code evaluated (if there wasn't an exception) is returned to the caller, as a tclobj.\n\nUncaught Tcl errors tracing back all the way to the the Tohil membrane are raised as a Python exception.\n\n```python\n\u003e\u003e\u003e tohil.eval('set a [list a 1 b 2 c 3]')\n'a 1 b 2 c 3'\n\u003e\u003e\u003e tohil.eval('return $a', to=list)\n['a', '1', 'b', '2', 'c', '3']\n\u003e\u003e\u003e tohil.eval('return $a',to=dict)\n{'a': '1', 'b': '2', 'c': '3'}\n\n\u003e\u003e\u003e a, b, c = tohil.eval(\"list 1 2 3\", to=tuple)\n\u003e\u003e\u003e c\n'3'\n```\n\nBesides tohil.eval, Tohil provides Python functions to call Tcl functions without argument evaluation (_tohil.call_), to get and set and manipulate Tcl variables and array\nelements (_tohil.getvar_, _tohil.setvar_, _tohil.exists_, _tohil.unset_), and a few others.\n\nFor a complete tutorial on using Tcl from Python, please visit [The Tohil Tutorial](https://flightaware.github.io/tohil-docs/tutorial/tohil_python.html).\n\n#### Tcl objects\n\nTohil 2 introduced a new Python data type called tclobj, aka tohil.tclobj.\n\nIt's a Python-wrapped Tcl object and it's very useful for generating and manipulating, passing to and receiving from, Tcl routines, Tcl lists, .  See [TCLOBJECTS.md](https://flightaware.github.io/tohil-docs/tutorial/tohil_tclobjs.html) for more.\n\n#### Shadow Dictionaries\n\nShadow Dictionaries, aka ShadowDicts, create a Python dict-like object that shadows a Tcl array, meaning that any changes to the dictionary from the Python side are immediately visible to Tcl and vice versa.\n\nFor more info please visit https://flightaware.github.io/tohil-docs/tutorial/shadow_dicts.html\n\n#### Examples using Tohil from Python\n\n```python\n\u003e\u003e\u003e import tohil\n\u003e\u003e\u003e a = tohil.eval('list 1 [list 2 4 5] 3')\n\u003e\u003e\u003e print(a)\n1 {2 4 5} 3\n\n\u003e\u003e\u003e import tohil\n\u003e\u003e\u003e tohil.eval('set a(99) goof')\n'goof'\n\u003e\u003e\u003e tohil.eval('set a(5) foo')\n'foo'\n\u003e\u003e\u003e tohil.getvar('a','99')\n'goof'\n\u003e\u003e\u003e tohil.getvar(array='a',var='5')\n'foo'\n\u003e\u003e\u003e tohil.getvar(array='a',var='16')\n\n\n\u003e\u003e\u003e tohil.eval('set a [list a 1 b 2 c 3]')\n'a 1 b 2 c 3'\n\u003e\u003e\u003e tohil.subst(\"$a\")\n'a 1 b 2 c 3'\n\u003e\u003e\u003e tohil.eval('return $a')\n'a 1 b 2 c 3'\n\u003e\u003e\u003e tohil.eval('return $a',to=list)\n['a', '1', 'b', '2', 'c', '3']\n\u003e\u003e\u003e tohil.eval('return $a',to=dict)\n{'a': '1', 'b': '2', 'c': '3'}\n\n\u003e\u003e\u003e tohil.eval(to=list,tcl_code=\"return [list 1 2 3 4]\")\n['1', '2', '3', '4']\n\n```\n\nCheck this out, converting expected results to Python datatypes:\n\n```python\n\u003e\u003e\u003e import tohil\n\u003e\u003e\u003e tohil.eval(\"clock seconds\")\n'1616053828'\n\u003e\u003e\u003e tohil.eval(\"clock seconds\",to=int)\n1616053834\n\u003e\u003e\u003e tohil.eval(\"clock seconds\",to=float)\n1616053838.0\n\u003e\u003e\u003e tohil.eval(\"clock seconds\",to=bool)\nTrue\n\u003e\u003e\u003e tohil.eval(\"clock seconds\",to=list)\n['1616053849']\n```\n\nNow eval with to=set option to return a set from a list...\n\n```python\n\u003e\u003e\u003e tohil.eval('return [list 1 2 3 4 4 3]',to=set)\n{'3', '4', '2', '1'}\n```\n\n### Accessing Python From Tcl\n\nFrom Tcl, Tohil provides access to Python through several commands and procs.\n\nProbably the most important commands are `tohil::eval`, `tohil::exec` and `tohil::call`.  The first two commands correspond closely to Python's `eval` and `exec`.\n\n```tcl\npackage require tohil\n```\n\nTohil provides commands for interacting with the Python interpreter, via the ::tohil namespace.\n\nCheck out the part of the tutorial about [Using Python From Tcl](https://flightaware.github.io/tohil-docs/tutorial/tohil_tcl.html), and the Tohil reference on [Tohil Tcl Functions](https://flightaware.github.io/tohil-docs/reference/tohil_tcl_functions.html)\n\n### Using Tohil from Rivet\n\nFrom a Rivet page, in some Tcl code body, invoke `package require tohil`.\n\nIf you run _tohil_rivet_ it will plug Tohil's Python interpreter such that everything Python writes to stdout using print, or whatever, will go through Tcl's stdout and thereby into your Rivet page.\n\n```\n\u003c?\n\npackage require tohil; tohil_rivet\n\nputs \"calling out to Python to add 5 + 5: [::tohil::eval \"5 + 5\"]\"\n\ntohil::exec {\nprint('hello, world')\nprint(\"\u003chr\u003e\")\n}\n\n?\u003e\n```\n\n###  Building Tohil on Unix, Linux, FreeBSD and the Mac\n\nTohil builds with the familiar GNU autoconf build system.  You will need to use the older version, autoconf 2.69.  \"autoreconf\" will produce a configure script based on the configure.in.  The tooling used is the standard Tcl Extension Architecture (TEA) approach, which is pretty evolved and fairly clean considering it's autoconf.\n\nIt is assumed that you\n - have got the Tohil repo (either by `git clone` or a tar.gz from the releases page).\n\nThe build process is fairly simple:\n - run the configure script\n - make\n - sudo make install\n\nWe're using setuptools to build the Python module, so the Makefile.in/Makefile is basically doing\n\n```\nPython3 setup.py build\nPython3 setup.py install\n```\n\n...to build and install the Python module.\n\nChceck out the docs on [installing Tohil](https://flightaware.github.io/tohil-docs/installing/index.html).\n\nAlso there are README files for Linux, FreeBSD and macOS.\n\n### Tests\n\nRun the tests with\n\n\t$ make test\n\nThere are currently about 165 tests, but most tests perform many tests, so several hundred.  The Python _hypothesis_ testing framework is used in many cases, and is highly recommended and it helped us identify several tohil bugs that the more typical naive tests would not have found.\n\n### Gotchas\n\n1. Be very careful when putting unicode characters into a inside a `tohil.eval`\nor `tohil.exec` call - they are decoded by the Tcl parser and passed as literal bytes\nto the Python interpreter. So if we directly have the character \"ಠ\", it is\ndecoded to a utf-8 byte sequence and becomes u\"\\xe0\\xb2\\xa0\" (where the \\xXY are\nliteral bytes) as seen by the Python interpreter.\n2. Escape sequences (e.g. `\\x00`) inside py eval may be interpreted by Tcl - use\n{} quoting to avoid this.\n\nYou need to build the library without stubs for Python to be able to use it.\n\n### To Do\n\n* if Python is the parent, register a Tcl panic handler and invoke Py_FatalError if Tcl panics.\n* the reverse of the above if Tcl is the parent if Python has a panic-type function with a registerable callback\n\nWe'd like to have Tohil work on Windows if someone would be willing to take it on.\n\n### Notes\n\nGerald Lester's [pyman](http://chiselapp.com/user/gwlester/repository/pyman/home) is a Tcl package that provides a higher level of abstraction on top of tclpy.  It will need to be updated for Tohil but bears examination.\n\n### Geek Notes\n\nThe same Tohil shared library created by building this software originally\ncould be loaded both by Python and Tcl, which was pretty cool.  Due to\nglobal data kept in the library It used to be necessary so that Tohil could\nwork at all.\n\nHowever since there are different\nbuild pipelines for Tcl extensions (based on autoconf via the Tcl extension\narchitecture) and Python (based on Python setuptools), we\nchanged Tohil's implementation to be able to work ok even with two different\nshared libraries by moving the critical piece of shared data, the Tcl\ninterpreter pointer, formerly held statically by the shared library itself,\ninto the Python interpreter via Python's capsule stuff and the Tcl interpreter\nvia Tcl's associated data stuff, allowing both shared\nlibraries to be able to find what they need without resorting to global data\nat all.\n\nThis was also necessary to support Python subinterpreters.\n\n### What Magic Is This\n\n```\ntohil.call(\"set\", \"mydict\", tohil.call(\"dict\", \"create\", *itertools.chain(*d.items())))\n```\n\nAww that's old stuff, with TclProcs we can do\n\n```\nl = {'a': 1, 'b': 2, 'c': 3, 'd': 4}\nt = tohil.import_tcl()\nt.set(\"mydict\", t.dict(\"create\", *itertools.chain(*l.items())))\nt.dict(\"get\", t.set(\"mydict\"), \"c\", to=int)\n```\n\nthat's a little gross, still.\n\nWith tclobjs we can do\n\n```\no = tohil.tclobj({'a': 1, 'b': 2, 'c': 3, 'd': 4})\nt.set(\"mydict\", o)\no.td_get('c', to=int)\n```\n\n\n### Formatting\n\nthis needs to be built into the makefile or something\n\nclang-format -style=file -i generic/tohil.c\n\n### Debugging Tohil Internals\n\nhttps://Pythonextensionpatterns.readthedocs.io/en/latest/debugging/debug_Python.html#debug-version-of-Python-memory-alloc-label\n\nBuild and install Python with something like\n\nmkdir linux\ncd linux\n../configure --with-pydebug --without-pymalloc --with-valgrind --enable-shared\n\nnot sure about the enable shared\n\nbuild tohil\n\n./configure --prefix=/usr/local --exec-prefix=/usr/local --with-Python-version=3.9d\n\nnote 3.9d instead of just 3.9\n\n### Acknowledgements\n\nTohil is based on, and is completely inspired by and exists because of, libtclpy, by Aidan Hobson Sayers available at https://github.com/aidanhs/libtclpy/.\n\n### Image Attribution\n\nDo you like the Tohil logo?  It's from a creative commons-licensed image of the Mayan deity Quetzalcoatl (also known in some cultures as Tohil), from the Codex Telleriano-Remensis, from the 16th century.\n\nA scan of the image can be found here https://commons.wikimedia.org/wiki/File:Quetzalcoatl_telleriano.jpg.  A wikimedia user, https://commons.wikimedia.org/wiki/User:Di_(they-them), made an SVG file of it, available here https://commons.wikimedia.org/wiki/File:Quetzalcoatl_feathered_serpent.svg\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflightaware%2Ftohil","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fflightaware%2Ftohil","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflightaware%2Ftohil/lists"}