{"id":14967288,"url":"https://github.com/stinos/micropython-wrap","last_synced_at":"2025-08-23T15:06:24.650Z","repository":{"id":17015541,"uuid":"19779471","full_name":"stinos/micropython-wrap","owner":"stinos","description":"API for interop between C/C++ and MicroPython","archived":false,"fork":false,"pushed_at":"2024-12-10T09:13:34.000Z","size":291,"stargazers_count":129,"open_issues_count":8,"forks_count":24,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-03-29T08:07:20.125Z","etag":null,"topics":["micropython"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stinos.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2014-05-14T12:58:53.000Z","updated_at":"2025-03-05T06:44:45.000Z","dependencies_parsed_at":"2024-03-27T11:28:35.315Z","dependency_job_id":"aa741f61-2ab8-4d66-b58f-e82cf6bfb327","html_url":"https://github.com/stinos/micropython-wrap","commit_stats":{"total_commits":230,"total_committers":3,"mean_commits":76.66666666666667,"dds":"0.31304347826086953","last_synced_commit":"2feb22252223e45c5fb3c5d7d81df1a0556d15d3"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stinos%2Fmicropython-wrap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stinos%2Fmicropython-wrap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stinos%2Fmicropython-wrap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stinos%2Fmicropython-wrap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stinos","download_url":"https://codeload.github.com/stinos/micropython-wrap/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247312078,"owners_count":20918344,"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","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":["micropython"],"created_at":"2024-09-24T13:37:47.632Z","updated_at":"2025-04-05T09:07:10.493Z","avatar_url":"https://github.com/stinos.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build status](https://ci.appveyor.com/api/projects/status/3a7gmffr0mpfv9va?svg=true)](https://ci.appveyor.com/project/stinos/micropython-wrap)\n\nMicroPython-Wrap\n================\n\nThis header-only C++ library provides some interoperability between C/C++ and the [MicroPython](https://github.com/micropython/micropython) programming language.\n\nThe standard way of extending MicroPython with your own C or C++ modules involves a lot of boilerplate,\nboth for converting function arguments and return values between native types and the MicroPython object model and for\nregsitering the function and type names so they can be discovered by MicroPython.\nUsing MicroPython-Wrap most of that boilerplate is avoided and instead one can focus on writing the actual C and/or C++ code\nwhile the process of integration with MicroPython comes down to adding two lines of code for every function/method or type which needs to be\navailable in your scripts.\n\nWARNING: while fully tested and daily in use without problems, this project should still be considered to be in beta stage and is subject to changes of the\ncode base, including project-wide name changes and API changes.\nFurthermore the actual integration at the build level is not too straightforward, see below.\n\nPlatforms\n---------\nIn principle any MicroPython port which has a working C++ compiler should work since the code is just standard C++.\nHas been tested for the unix port with gcc, the esp32 port with ESP-IDF sdk v4, and the windows port with gcc (from MSYS2) and msvc.\n\nExample\n-------\nComplete usage examples covering all aspects can be found in the the [tests](tests) directory which also serves as documentation:\n in [module.cpp](tests/module.cpp) a micropython module is created and a bunch of C++ classes and functions are added to the module.\nConsequently when running the [python test code](tests/py) using the standard MicroPython test runner the module is imported and all registered functions are called.\n\nJust to get an idea here is a short sample of C++ code registration; code achieving the same using just the MicroPython API is not shown here but would likely be around 50 lines:\n\n```c++\n#include \u003cmicropython-wrap/functionwrapper.h\u003e\n\n//function we want to call from within a MicroPython script\nstd::vector\u003c std::string \u003e SomeFunction( std::vector\u003c std::string \u003e vec )\n{\n  for( auto\u0026 v : vec )\n    v += \"TRANSFORM\";\n  return vec;\n}\n\n//function names are declared in structs\nstruct FunctionNames\n{\n  func_name_def( TransformList )\n};\n\nextern \"C\"\n{\n  void RegisterMyModule(void)\n  {\n    //register a module named 'foo'\n    auto mod = upywrap::CreateModule( \"foo\" );\n\n    //register our function with the name 'TransformList'\n    //conversion of a MicroPython list of strings is done automatically\n    upywrap::FunctionWrapper wrapfunc( mod );\n    wrapfunc.Def\u003c FunctionNames::TransformList \u003e( SomeFunction );\n  }\n}\n\n//now call RegisterMyModule() in MicroPython's main() for example\n```\n\nAnd the MicroPython code making use of this looks like:\n\n```python\nimport foo\n\nprint(foo.TransformList(['a', 'b']))  # Prints ['aTRANSFORM', 'bTRANSFORM']\n```\n\nType Conversion\n---------------\nConversion between standard native types and `mp_obj_t`, the MicroPython opaque object type\nis declared in two template classes aptly named [ToPyObj](detail/topyobj.h) and [FromPyObj](detail/frompyobj.h).\n\nCurrently these conversions are supported (depending on C++ standard used):\n\n    uPy double \u003c-\u003e double/float\n    uPy int \u003c-\u003e std::int16_t/std::int32_t/std::int64_t/std::uint16_t/std::uint32_t/std::uint64_t with overflow checks\n    uPy bool \u003c-\u003e bool\n    uPy str \u003c-\u003e std::string/std::string_view\n    uPy str \u003c-\u003e const char* (optional)\n    uPy tuple \u003c-\u003e std::tuple/std::pair\n    uPy list \u003c-\u003e std::vector (each element must be of the same type)\n    uPy dict \u003c-\u003e std::map (each key/value must be of the same type)\n    uPy callable \u003c-\u003e std::function (None maps to empty std::function)\n    uPy None \u003c-\u003e std::optional (i.e. std::nullopt \u003c-\u003e None, otherwise value gets converted)\n    uPy None \u003c- empty std::shared_ptr\n    uPy None \u003c- std::error_code (if empty, otherwise throws runtime_error)\n\nFunction and class wrapping\n---------------------------\nWrapping code is provided for:\n\n    uPy functions \u003c-\u003e free functions via upywrap::FunctionWrapper\n    uPy class \u003c-\u003e C++ class via upywrap::ClasssWrapper\n    uPy __init__ \u003c-\u003e C++ class constructor or factory function of choice\n    uPy __del__ \u003c-\u003e C++ class destructor (called only when instance is grabage collected!)\n    uPy __exit__ \u003c-\u003e C++ class method with void() signature\n    uPy __call__ \u003c-\u003e any C++ class method\n    uPy class methods \u003c-\u003e C++ class methods\n    uPy class attributes \u003c-\u003e C++ class methods\n\nFor builtin types listed under 'type conversion', the native function must take the argument by value, const value or const reference,\nand only values can be returned.\nClassWrapper types can be passed by pointer, value, reference or std::shared_ptr and returned as pointer,\nreference or std::shared_ptr. See tests for ownership rules.\n\nFurthermore there is optional support for wrapping each native call in a try/catch for std::exception,\nand re-raise it as a uPy RuntimeError\n\nOptional and keyword argument support\n-------------------------------------\nThis is supported by naming the arguments and eventually supplying defaults when registering the function in the C++ code, example:\n\n```c++\nvoid Foo( int, std::string, const std::vector\u003c int \u003e\u0026 );\n\nstruct FunctionNames\n{\n  func_name_def( Foo )\n};\n\nextern \"C\"\n{\n  void RegisterMyModule(void)\n  {\n    upywrap::FunctionWrapper wrapfunc( upywrap::CreateModule( \"foo\" ) );\n    //Make the first argument required and the rest optional.\n    wrapfunc.Def\u003c FunctionNames::Foo \u003e( Foo, upywrap::Kwargs( \"a\" )( \"b\", \"default\" )( \"c\", {0, 1} ) );\n  }\n}\n\n```\n\nCalling code:\n\n```python\nimport foo\n\nfoo.Foo(0)  # Calls Foo( 0, \"default\", std::vector\u003c int \u003e{ 0, 1 } ) in C++.\nfoo.Foo(a=1, c=[2])  # Calls Foo( 1, \"default\", std::vector\u003c int \u003e{ 2 } ) in C++.\n```\n\n\nIntegrating and Building\n------------------------\nFirst clone this repository alongside the MicroPython repository, then refer to the way the tests module\nis built and create your own modules in the same way. Also see the [Makefile](Makefile) for Unix and\n[Project file](micropython-wrap.vcxproj) for Windows, and the [Appveyor config](.appveyor.yml) for how builds are done.\n\n- the [Unix Makefile](Makefile) shows three ways way of integration (also explained in [the module code](module.h)):\n    - combination of a static library and 'user C module': the C++ test code is compiled into a static library\n      and tests/cmodule.c is built with MicroPython as a 'user C module', linking to the static library.\n    - as a 'user C module': same as above but MicroPython builds both .c and .cpp files.\n    - with a shared library: using [this MicroPython fork](https://github.com/stinos/micropython/tree/windows-pyd) adds CPython-like\n      support for loading dynamic modules.\n- the Makefile is also a starting point for other gcc-based ports, e.g.\n  ```\n  make usercmodule MICROPYTHON_PORT_DIR=../micropython/ports/esp32\n  ```\n  will build the tests into a user C module. Note this might require changing ports/esp32/partitions.csv to make room for the C++ code like\n  ```\n  factory,  app,  factory, 0x10000, 0x200000,\n  vfs,      data, fat,     0x210000, 0x1F0000,\n  ```\n- for Windows with Visual Studio (2013 or up) some extra work has already been done in [this MicroPython fork](https://github.com/stinos/micropython/tree/windows-pyd).\n  Create an empty C++ dll project, import [extmodule.props](https://github.com/stinos/micropython/blob/windows-pyd/ports/windows/msvc/extmodule.props)\n  and all code is built into a dll with a .pyd extension which is discovered automatically by the fork's micropython.exe when using\n  an import statement.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstinos%2Fmicropython-wrap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstinos%2Fmicropython-wrap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstinos%2Fmicropython-wrap/lists"}