{"id":17984839,"url":"https://github.com/nbren12/call_py_fort","last_synced_at":"2025-07-27T10:31:09.476Z","repository":{"id":50469709,"uuid":"145489904","full_name":"nbren12/call_py_fort","owner":"nbren12","description":"Call python from fortran","archived":false,"fork":false,"pushed_at":"2023-07-24T22:50:59.000Z","size":43,"stargazers_count":81,"open_issues_count":8,"forks_count":22,"subscribers_count":11,"default_branch":"master","last_synced_at":"2024-11-21T17:05:32.848Z","etag":null,"topics":["fortran","interoperability","python"],"latest_commit_sha":null,"homepage":"","language":"Fortran","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nbren12.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-2.0.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2018-08-21T01:34:32.000Z","updated_at":"2024-11-01T12:26:49.000Z","dependencies_parsed_at":"2022-09-02T14:32:09.599Z","dependency_job_id":null,"html_url":"https://github.com/nbren12/call_py_fort","commit_stats":{"total_commits":28,"total_committers":1,"mean_commits":28.0,"dds":0.0,"last_synced_commit":"b5f1ac561128c7920cf901c9274407b21ba8e706"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nbren12%2Fcall_py_fort","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nbren12%2Fcall_py_fort/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nbren12%2Fcall_py_fort/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nbren12%2Fcall_py_fort/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nbren12","download_url":"https://codeload.github.com/nbren12/call_py_fort/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227794455,"owners_count":17820991,"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":["fortran","interoperability","python"],"created_at":"2024-10-29T18:23:11.451Z","updated_at":"2024-12-02T19:48:56.313Z","avatar_url":"https://github.com/nbren12.png","language":"Fortran","funding_links":[],"categories":[],"sub_categories":[],"readme":"# call_py_fort\n\n![status](https://github.com/VulcanClimateModeling/call_py_fort/workflows/Check/badge.svg)[![DOI](https://zenodo.org/badge/145489904.svg)](https://zenodo.org/badge/latestdoi/145489904)\n\n\nCall python from Fortran (not the other way around). Inspired by this [blog\npost](https://www.noahbrenowitz.com/post/calling-fortran-from-python/).\n\n## Installation\n\nThis library has the following dependencies\n1. pfUnit (v3.2.9) for the unit tests\n1. python (3+) with numpy and cffi, with libpython built as a shared library.\n1. cmake (\u003e=3.4+)\n\nThis development environment can be setup with the nix package manager. To\nenter a developer environment with all these dependencies installed run:\n\n    nix-shell\n\nOnce the dependencies are installed, you can compile this library using\n\n    mkdir build\n    cd build \n    cmake ..\n    make\n\nRun the tests:\n\n    make test\n\nInstall on your system\n\n    make install\n\nThis will usually install the `libcallpy` library to `/usr/local/lib` and the\nnecessary module files to `/usr/local/include`. The specific way to add this\nlibrary to a Fortran code base will depend on the build system of that code.\nTypically, you will need to add a flag `-I/usr/local/include` to any fortran\ncompiler commands letting the compiler find the `.mod` file for this library,\nand a `-L/usr/local/lib -lcallpy` to link against the dynamic library. On\nsome systems, you may need to set\n`LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH` at runtime to help the\ndynamic linker find the library.\n\n## Usage\n\nOnce installed, this library is very simple to use. For example:\n```\nprogram example\nuse callpy_mod\nimplicit none\n\nreal(8) :: a(10)\na = 1.0\ncall set_state(\"a\", a)\ncall call_function(\"builtins\", \"print\")\n! read any changes from \"a\" back into a.\ncall get_state(\"a\", a)\n\nend program example\n```\n\nIt basically operates by pushing fortran arrays into a global python\ndictionary, calling python functions with this dictionary as input, and then\nreading numpy arrays from this dictionary back into fortran. Let this\ndictionary by called STATE. In terms of python operations, the above lines\nroughly translate to\n\n    # abuse of notation signifyling that the left-hand side is a numpy array\n    STATE[\"a\"] = a[:]\n    # same as `print` but with module name\n    builtins.print(STATE)\n    # transfer from python back to fortran memory\n    a[:] = STATE[\"a\"]\n\nYou should be able to compile the above by running\n\n    gfortran -I/usr/local/include -Wl,-rpath=/usr/local/lib -L/usr/local/lib main.f90 -lcallpy\n    \nHere's what happens when you run the compiled binary:\n```\n$ ./a.out \n{'a': array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])}\n```\n\n\nBy modifying, the arguments of `call_function` you can call any python\nfunction in the pythonpath.\n\nCurrently, `get_state` and `set_state` support 4 byte or 8 byte floating\npoint of one, two, or three dimensions.\n\n## Examples\n\nSee these [examples](/examples). Most examples pair one fortran driver file\n(e.g. `hello_world.f90`) with a python module that it calls (e.g. `hello_world.py`).\n\nThey can be built from the project root like this:\n\n```\ncmake -B build .\nmake -C build\n# need to add the example python modules to the import path\nexport PYTHONPATH=$(pwd)/examples:$PYTHONPATH\n# run the example\n./build/examples/hello_world\n```\n\nSee the [unit tests](/test/test_call_py_fort.pfunit) for more examples.\n\n## Troubleshooting\n\nEmbedded python does not initialize certain variables in the `sys` module the\nsame as running a python script via the `python` command line. This leads to\nsome common errors when using `call_py_fort`.\n\n### Module not found errors\n\nExample of error:\n```\nTraceback (most recent call last):\n  File \"\u003cstdin\u003e\", line 1, in \u003cmodule\u003e\nModuleNotFoundError: No module named 'your_module'\n```\n\nSolution: When run in embedded mode, python does not include the current working\ndirectory in `sys.path`. You can fix this in a few ways\n#. add the current directory to the PYTHONPATH environment variable `export PYTHONPATH=$(pwd)`\n#. If you have packaged it you can install it in editable mode `pip install\n-e`.\n\n### `sys.argv` is None\n\nSome evil libraries like tensorflow actually look at your command line\narguments when they are imported. Unfortunately, `sys.argv` is not initialized\nwhen python is run in embedded mode so this will lead to errors when importing\nsuch packages. Fix this by setting `sys.argv` before importing such packages\ne.g.\n```\nimport sys\nsys.argv = []\nimport tensorflow\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnbren12%2Fcall_py_fort","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnbren12%2Fcall_py_fort","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnbren12%2Fcall_py_fort/lists"}