Name | import-zig JSON |
Version |
0.13.0
JSON |
| download |
home_page | None |
Summary | Compile and import Zig functions at runtime without building a package |
upload_time | 2024-09-21 19:40:15 |
maintainer | None |
docs_url | None |
author | Felix Graßl |
requires_python | >=3.10 |
license | MIT |
keywords |
zig
ziglang
import
compile
|
VCS |
|
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# import-zig
pip install import-zig
This module provides a way to import Zig code directly into Python using a single function call to `import_zig`. Here is an example:
```py
from import_zig import import_zig
mod = import_zig(source_code = """
pub fn Q_rsqrt(number: f32) f32 {
const threehalfs: f32 = 1.5;
const x2 = number * 0.5;
var y = number;
var i: i32 = @bitCast(y);
i = 0x5f3759df - (i >> 1);
y = @bitCast(i);
y = y * (threehalfs - (x2 * y * y));
return y;
}
""")
print(f"1 / sqrt(1.234) = {mod.Q_rsqrt(1.234)}")
```
The main goal of this module is to make it easy to prototype Zig extensions for Python without having to engage with the Python build system. When building larger Zig extensions it is likely preferable to write your own build process with setuptools or to use a ziggy-pydust template, which provides a comptime abstraction over many aspects of the Python C API. Zig and Zig extensions are still very new though, so things will likely change. Technically you could also use this module as part of a packaging step by calling the `compile_to` function to build the binary and moving it into the packages build folder.
One approach that I expect to stay the same is the comptime wrapping for conversion between Zig and Python types as well as exception handling. This is conveniently packed into the file `py_utils.zig` and could be copy pasted into a new setuptools based project and maybe adjusted.
See the docs of the import_zig function for more details or check out the examples directory.
# File structure
The file structure that will be generated to compile the Zig code looks as follows.
```bash
project_folder
├── build.zig
├── generated.zig
├── inner
│ └── import_fns.zig
├── py_utils.zig
└── zig_ext.zig
```
The `inner` directory is where your code lives. When you pass a source code string or file path, it will be written / linked as the `import_fns.zig` file. When you pass a directory path, the directory will be linked as the `inner` directory above, enabling references to other files in the directory path.
The above file structure can be generated with:
```py
import_zig.prepare("/path/to/project_folder", "module_name")
```
This enables ZLS support for the Python C API when importing `py_utils` from `import_fns.zig`.
# Type mapping
The conversion is defined in `py_utils.zig` and applied based on the parameter / return types of the exported function. Errors are also forwarded. The solution to passing variable length data back to Python is a bit of a hack: When an exported function specifies `std.mem.Allocator` as a parameter type, then an arena allocator - which gets deallocated after the function call - will be passed into the function. The allocator can then be used to allocate and return new slices for example.
For nested types, the conversion is applied recursively.
| Conversion from Python | Zig datatype | Conversion to Python |
| --------------------------------------- | --------------------------------- | --------------------------------------------- |
| int | integer (any size / sign) | int |
| float | float (any size) | float |
| - | void | None |
| evaluated like bool() | bool | bool |
| sequence | array | list |
| sequence | non u8 const slice | list |
| str | u8 const slice | str |
| dict or sequence | struct | tuple if struct is a tuple or named tuple |
| comparison with None | optional | null -> None |
Raw data
{
"_id": null,
"home_page": null,
"name": "import-zig",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": "zig, ziglang, import, compile",
"author": "Felix Gra\u00dfl",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/87/2a/8f5028d556e1926062a70395e165ca90f6d8bcbfb2d7e6debfb4379e9aba/import_zig-0.13.0.tar.gz",
"platform": null,
"description": "# import-zig\n\n pip install import-zig\n\nThis module provides a way to import Zig code directly into Python using a single function call to `import_zig`. Here is an example:\n\n```py\nfrom import_zig import import_zig\n\nmod = import_zig(source_code = \"\"\"\n pub fn Q_rsqrt(number: f32) f32 {\n const threehalfs: f32 = 1.5;\n const x2 = number * 0.5;\n var y = number;\n var i: i32 = @bitCast(y);\n i = 0x5f3759df - (i >> 1);\n y = @bitCast(i);\n y = y * (threehalfs - (x2 * y * y));\n\n return y;\n }\n\"\"\")\n\nprint(f\"1 / sqrt(1.234) = {mod.Q_rsqrt(1.234)}\")\n```\n\nThe main goal of this module is to make it easy to prototype Zig extensions for Python without having to engage with the Python build system. When building larger Zig extensions it is likely preferable to write your own build process with setuptools or to use a ziggy-pydust template, which provides a comptime abstraction over many aspects of the Python C API. Zig and Zig extensions are still very new though, so things will likely change. Technically you could also use this module as part of a packaging step by calling the `compile_to` function to build the binary and moving it into the packages build folder.\n\nOne approach that I expect to stay the same is the comptime wrapping for conversion between Zig and Python types as well as exception handling. This is conveniently packed into the file `py_utils.zig` and could be copy pasted into a new setuptools based project and maybe adjusted.\n\nSee the docs of the import_zig function for more details or check out the examples directory.\n\n# File structure\n\nThe file structure that will be generated to compile the Zig code looks as follows.\n\n```bash\nproject_folder\n\u251c\u2500\u2500 build.zig\n\u251c\u2500\u2500 generated.zig\n\u251c\u2500\u2500 inner\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 import_fns.zig\n\u251c\u2500\u2500 py_utils.zig\n\u2514\u2500\u2500 zig_ext.zig\n```\n\nThe `inner` directory is where your code lives. When you pass a source code string or file path, it will be written / linked as the `import_fns.zig` file. When you pass a directory path, the directory will be linked as the `inner` directory above, enabling references to other files in the directory path.\n\nThe above file structure can be generated with:\n\n```py\nimport_zig.prepare(\"/path/to/project_folder\", \"module_name\")\n```\n\nThis enables ZLS support for the Python C API when importing `py_utils` from `import_fns.zig`.\n\n# Type mapping\n\nThe conversion is defined in `py_utils.zig` and applied based on the parameter / return types of the exported function. Errors are also forwarded. The solution to passing variable length data back to Python is a bit of a hack: When an exported function specifies `std.mem.Allocator` as a parameter type, then an arena allocator - which gets deallocated after the function call - will be passed into the function. The allocator can then be used to allocate and return new slices for example.\n\nFor nested types, the conversion is applied recursively.\n\n| Conversion from Python | Zig datatype | Conversion to Python |\n| --------------------------------------- | --------------------------------- | --------------------------------------------- |\n| int | integer (any size / sign) | int |\n| float | float (any size) | float |\n| - | void | None |\n| evaluated like bool() | bool | bool |\n| sequence | array | list |\n| sequence | non u8 const slice | list |\n| str | u8 const slice | str |\n| dict or sequence | struct | tuple if struct is a tuple or named tuple |\n| comparison with None | optional | null -> None |\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Compile and import Zig functions at runtime without building a package",
"version": "0.13.0",
"project_urls": {
"Homepage": "https://github.com/ffelixg/import_zig",
"Issues": "https://github.com/ffelixg/import_zig/issues"
},
"split_keywords": [
"zig",
" ziglang",
" import",
" compile"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "a026e5713725644d7fe6e030a42a5b13b1a91916c916b03bba2376ab70411e7e",
"md5": "74df0f26654d0042899a261b42e75829",
"sha256": "4dd74ab3cae161d5f34f375b8a898c474c3b6d218204b8bf93b68f9e33abc6ff"
},
"downloads": -1,
"filename": "import_zig-0.13.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "74df0f26654d0042899a261b42e75829",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 11171,
"upload_time": "2024-09-21T19:40:14",
"upload_time_iso_8601": "2024-09-21T19:40:14.603196Z",
"url": "https://files.pythonhosted.org/packages/a0/26/e5713725644d7fe6e030a42a5b13b1a91916c916b03bba2376ab70411e7e/import_zig-0.13.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "872a8f5028d556e1926062a70395e165ca90f6d8bcbfb2d7e6debfb4379e9aba",
"md5": "c12d355d66e8ad20d93496d9f41a1867",
"sha256": "457a66e46df6917e18dd53f2e35309fd89872e5ccd00bf95b54ea23d9d4bd491"
},
"downloads": -1,
"filename": "import_zig-0.13.0.tar.gz",
"has_sig": false,
"md5_digest": "c12d355d66e8ad20d93496d9f41a1867",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 11714,
"upload_time": "2024-09-21T19:40:15",
"upload_time_iso_8601": "2024-09-21T19:40:15.892384Z",
"url": "https://files.pythonhosted.org/packages/87/2a/8f5028d556e1926062a70395e165ca90f6d8bcbfb2d7e6debfb4379e9aba/import_zig-0.13.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-09-21 19:40:15",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "ffelixg",
"github_project": "import_zig",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "import-zig"
}