{"id":25369861,"url":"https://github.com/das-dias/pythonclibrarytutorial","last_synced_at":"2025-04-09T07:17:54.023Z","repository":{"id":220805609,"uuid":"752635323","full_name":"das-dias/PythonCLibraryTutorial","owner":"das-dias","description":"A simple Python C library tutorial / template project.","archived":false,"fork":false,"pushed_at":"2024-02-05T13:36:21.000Z","size":6485,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-15T01:35:04.736Z","etag":null,"topics":["c-python-extensions"],"latest_commit_sha":null,"homepage":"","language":"Python","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/das-dias.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2024-02-04T12:06:53.000Z","updated_at":"2024-02-05T13:37:47.000Z","dependencies_parsed_at":"2024-02-04T13:38:09.524Z","dependency_job_id":null,"html_url":"https://github.com/das-dias/PythonCLibraryTutorial","commit_stats":null,"previous_names":["das-dias/pythonclibrarytutorial"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/das-dias%2FPythonCLibraryTutorial","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/das-dias%2FPythonCLibraryTutorial/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/das-dias%2FPythonCLibraryTutorial/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/das-dias%2FPythonCLibraryTutorial/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/das-dias","download_url":"https://codeload.github.com/das-dias/PythonCLibraryTutorial/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247994134,"owners_count":21030050,"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":["c-python-extensions"],"created_at":"2025-02-15T01:35:12.770Z","updated_at":"2025-04-09T07:17:53.992Z","avatar_url":"https://github.com/das-dias.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PythonCLibraryTutorial\n\nA tutorial on how to create a Python C library using the Python C API, \nand how to use it in a Python program.\n\n## TOC:\n- [PythonCLibraryTutorial](#pythonclibrarytutorial)\n  - [TOC:](#toc)\n  - [Introduction](#introduction)\n  - [Repository Structure](#repository-structure)\n  - [API Flow](#api-flow)\n  - [Makefile](#makefile)\n  - [Building the C Library](#building-the-c-library)\n  - [Running the Python Program](#running-the-python-program)\n\n## Introduction\nThis tutorial is based on the [RealPython.com](https://realpython.com/build-python-c-extension-module/) tutorial for packaging a C Library in a Python module. \nFurther extensions to the code were performed by following the stuff written at [the official Python docs](https://docs.python.org/3/extending/extending.html#building-arbitrary-values).\nThis tutorial extends the previous by: \n1. using a Python virtual environment together with a \n[```Makefile```](./lib/Makefile) to tell the ```clang``` compiler where the Python header files are located.\n\n2. defining a C structure to be wrapped by a Python class object.\n\n## Repository Structure\n\nThe repository is structured as follows:\n  \n```\nPythonCLibraryTutorial/\n│\n├── lib/\n│   ├── init.c # defines the cpyfputs C Python Library extension module\n│   ├── Makefile\n│   ├── src/\n│   │   └── pyfputs.c\n│   └── include/\n│       └── pyfputs.h\n│\n├── pyfputs/\n│   ├── __init__.py\n│   ├── __main__.py\n│   └── example_class.py\n│\n├── setup.py\n└── README.md\n```\n\n## API Flow\n\nA call to the ```fputs``` C library is made through the ```lib/init.c::PyInit_cpyfputs``` function. This function is called by the Python interpreter when the Python module is imported, creating the C library module linkage to the Python interpreter. The ```PyInit_cpyfputs``` function is declared in the [```lib/init.c```](./lib/init.c) file.\n\nAfter the ```PyInit_cpyfputs``` function creates the link to the module's symbols, the declared C methods and datastructures within the ```lib/init.c::PyFputs_methods``` and  ```lib/init.c::ExampleClass_methods``` structs are made available to the Python interpreter. The [```ExampleClass```](./lib/include/pyfputs.h) is also instantiated as a Python Object of the module in the initialization function. The methods and datastructures are declared source of the C library and are now ready to be used within the Python module.\n\n## Makefile\n\nThe [```Makefile```](./lib/Makefile) is used to build the C library. In this example, its sole purpose is to tell the ```clang``` compiler where the Python header files are located. The ```Makefile``` is located in the [```lib```](./lib) directory.\n\n```make\n# Makefile\nCFLAGS = -I venv/include/python3.11/\n```\n\nBecause I am using a Python virtual environment, the Python header files are located in the ```venv/include/python3.11/``` directory. The ```-I``` flag tells the compiler (```clang``` in my case, but it also works for ```gcc```) where to find the header files.\n\n## Building the C Library\n\nBuilding the library is quite straightfoward. This tutorial takes use of a (deprecated!) ```setup.py``` file to build the Python C library. The ```setup.py``` file is located in the root directory of the repository.\n\n```python\nfrom distutils.core import setup, Extension\n\ndef main():\n    setup(\n      name=\"PyFputs\",\n      version=\"1.0.0\",\n      description=\"Python interface for the fputs C library function\",\n      author=\"Diogo Andre\",\n      author_email=\"your_email@gmail.com\",\n      ext_modules=[Extension(\n        \"cpyfputs\", \n        [ \"lib/init.c\", \"lib/src/pyfputs.c\"],\n        swig_opts=[\"-modern\", \"-I./venv/include/python3.11\"],\n      )],\n      packages=[\"pyfputs\"],\n    )\n\nif __name__ == \"__main__\":\n    main()\n```\n\nA different approach is being researched to build the library using Python-native (non-deprecated) tools. If you have any suggestions, please let me know by creating an issue or a pull request.\n\n## Running the Python Program\n\nTo run the Python program, simply run the following command in the root directory of the repository:\n\n```bash\n$ python pyfputs\n```\n\nThe [```__main__.py```](./pyfputs/__main__.py) file in the [```pyfputs```](./pyfputs) directory will be executed, creating three new files in the root directory of the repository: ```hello.txt```, ```hello_from_exampleclass.txt``` and ```hello_from_exampleclass2.txt```. There will be stuff written in each of these files.\n\n```python\nfrom pyfputs import fputs, ExampleClassWrapper\n\nif __name__ == \"__main__\":\n  fputs(\"Hello, World!\", \"hello.txt\")\n  print(\"Wrote to hello.txt\")\n  obj = ExampleClassWrapper(\"hello_from_exampleclass.txt\")\n  obj.fputs(\"Hello, World! From the ExampleClass!\")\n  print(\"Wrote to hello_from_exampleclass.txt\")\n  obj2 = ExampleClassWrapper()\n  print(\"Current filename: \", obj2.filename)\n  obj2.filename = \"hello_from_exampleclass2.txt\"\n  obj2.fputs(\"Hello, World! From the ExampleClass! Again!\")\n  print(\"Wrote to hello_from_exampleclass2.txt\")\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdas-dias%2Fpythonclibrarytutorial","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdas-dias%2Fpythonclibrarytutorial","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdas-dias%2Fpythonclibrarytutorial/lists"}