{"id":13712546,"url":"https://github.com/hschneider/neutralino-ext-python","last_synced_at":"2025-04-10T04:32:56.282Z","repository":{"id":208452129,"uuid":"721572113","full_name":"hschneider/neutralino-ext-python","owner":"hschneider","description":"A low-code Python-Extension for NeutralinoJS. This turns Neutralino into a reactive Python GUI.","archived":false,"fork":false,"pushed_at":"2024-10-10T12:16:33.000Z","size":267,"stargazers_count":13,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-24T16:24:06.924Z","etag":null,"topics":["cross-platform","crossplatform","neutralino","neutralinojs","python"],"latest_commit_sha":null,"homepage":"https://marketmix.com","language":"Python","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/hschneider.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":"2023-11-21T10:40:49.000Z","updated_at":"2025-03-20T06:24:01.000Z","dependencies_parsed_at":"2023-11-30T08:24:17.258Z","dependency_job_id":"41fd2e2c-72b3-4393-8958-33825ba57420","html_url":"https://github.com/hschneider/neutralino-ext-python","commit_stats":null,"previous_names":["hschneider/neutralino-ext-python"],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hschneider%2Fneutralino-ext-python","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hschneider%2Fneutralino-ext-python/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hschneider%2Fneutralino-ext-python/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hschneider%2Fneutralino-ext-python/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hschneider","download_url":"https://codeload.github.com/hschneider/neutralino-ext-python/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248157672,"owners_count":21057050,"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":["cross-platform","crossplatform","neutralino","neutralinojs","python"],"created_at":"2024-08-02T23:01:19.710Z","updated_at":"2025-04-10T04:32:55.846Z","avatar_url":"https://github.com/hschneider.png","language":"Python","funding_links":[],"categories":["Extensions"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://marketmix.com/git-assets/neutralino-ext-python/neutralino-python-header.svg\" style=\"margin-left:auto;margin-right:auto\"\u003e\n\u003c/p\u003e\n\n# neutralino-ext-python\n**A Python Extension for Neutralino**\n\nThis extension adds a Python3 backend to Neutralino with the following features:\n- Requires only a few lines of code on both ends.\n- Read all events from the Neutralino app in your Python code.\n- Run Python functions from Neutralino.\n- Run Neutralino functions from Python.\n- All communication between Neutralino and Python runs asynchronously.\n- All events are queued, so none will be missed during processing.\n- Track the data flow between Neutralino and Python in realtime.\n- Works in Window- and headless Cloud-Mode.\n- Terminates the Python interpreter when the Neutralino app quits.\n\n![Neutralino Python Extension](https://marketmix.com/git-assets/neutralino-ext-python/neutralino-python-extension.gif)\n\n## Run the demo\nThe demo opens a Neutralino app. Clicking on the blue link sends a Ping to Python, which replies with Pong.\nThis illustrates the data-flow in both directions. \n\nBefore running the demo, adapt the path to your Python interpreter in the **neutralino.config.json** file:\n\nReplace this:\n```json\n \"extensions\": [\n    {\n      \"id\": \"extPython\",\n      \"commandDarwin\": \"${NL_PATH}/extensions/python/_interpreter/python3.framework/Versions/Current/bin/python3 ${NL_PATH}/extensions/python/main.py\",\n      \"commandWindows\": \"${NL_PATH}/extensions/python/_interpreter/pypy3/pypy.exe ${NL_PATH}/extensions/python/main.py\"\n    }\n  ]\n```\nwith e.g. \n```json\n \"extensions\": [\n    {\n      \"id\": \"extPython\",\n      \"commandDarwin\": \"python3 ${NL_PATH}/extensions/python/main.py\",\n      \"commandWindows\": \"python3 ${NL_PATH}/extensions/python/main.py\"\n    }\n  ]\n```\n\nWhen including the extension in your own project, make sure that your config contains this whitelist:\n```json\n  \"nativeAllowList\": [\n    \"app.*\",\n    \"os.*\",\n    \"window.*\",\n    \"events.*\",\n    \"extensions.*\",\n    \"debug.log\"\n  ],\n```\n\nNext, prepare your Python environment with:\n```commandline\n# python3 -m pip install --no-binary :all: websocket-client\n```\n\nAfter this, run these commands in the ext-python folder:\n```commandline\nneu update\nneu run\n```\n\n## Integrate into your own project\nJust follow these steps:\n- Modify **neutralino.config.json**, like mentioned in **\"Run the demo\"**.\n- Copy the **extensions** folder to your project.\n- Adapt the Python code in **extensions/python/main.py** to your needs.\n- Copy **resources/js/python-extension.js** to **resources/js**.\n- Add `\u003cscript src=\"js/python-extension.js\"\u003e\u003c/script\u003e` to your **index.html**\n- Add `const PYTHON = new PythonExtension(true)` to your **main.js**\n- Add **PYTHON.run(function_name, data) to main.js** to run Python functions from Neutralino.\n- Add **event listeners to main.js**, to fetch result data from Python.\n\n## ./extensions/python/main.py explained\n\n```Python\nfrom NeutralinoExtension import *\n\nDEBUG = True    # Print incoming event messages to the console\n\ndef ping(d):\n    #\n    # Send some data to the Neutralino app\n\n    ext.sendMessage('pingResult', f'Python says PONG, in reply to \"{d}\"')\n\ndef processAppEvent(d):\n    \"\"\"\n    Handle Neutralino app events.\n    :param d: data package as JSON dict.\n    :return: ---\n    \"\"\"\n\n    if ext.isEvent(d, 'runPython'):\n        (f, d) = ext.parseFunctionCall(d)\n\n        # Process incoming function calls:\n        # f: function name, d: data as JSON or string\n        #\n        if f == 'ping':\n            ping(d)\n\n\n# Activate extension\n#\next = NeutralinoExtension(DEBUG)\next.run(processAppEvent)\n```\n\nThe extension is activated with the last 2 lines. \n**processAppEvent** is a callback function, which is triggered with each event coming from the Neutralino app.\n\nIn the callback function, you can process the incoming events by their name. In this case we react to the **\"runPython\"** event.\n**parseFunctionCall(data)** extracts the **function name (f)** and its **parameters (p)** from the event's data package. Variable p can be a string or JSON dictionary.\n\nif the requested function is named ping, we call the ping-function which sends a message back to Neutralino. \n\n**sendMessage()** requires the following parameters:\n- An event name, here \"pingResult\"\n- The data package to send, which can be of type string or JSON.\n\nThe **DEBUG** variable tells the NeutralinoExtension to report each event to the console. Incoming events, incoming function calls and outgoing messages are printed in different colors.\nThis makes debugging easier, since you can track the data flow between Neutralino and Python:\n\n![Debug Python](https://marketmix.com/git-assets/neutralino-ext-python/debug-python.jpg)\n\n## ./resources/js/main.js explained\n```Javascript\n\nasync function onPingResult(e) {\n ...\n}\n\n// Init Neutralino\n//\nNeutralino.init();\n...\nNeutralino.events.on(\"pingResult\", onPingResult);\n...\n// Init Python Extension\nconst PYTHON = new PythonExtension(true)\n```\n\nThe last line initializes the JavaScript part of the Python extension. It's important to place this after Neutralino.init() and after all event handlers have been installed. Put it in the last line of your code and you are good to go. The const **PYTHON** is accessible globally and **must not be renamed.**\n\nThe **PythonExtension class** takes only 1 argument which instructs it to run in debug mode (here true). In this mode, all data from the Python extension is printed to the dev-console:\n\n![Debug Meutralino](https://marketmix.com/git-assets/neutralino-ext-python/debug-neutralino.jpg)\n\nThe **pingResult event handler** listens to messages with the same name, sent by sendMessage() on Python's side. \n\nIn **index.html**, you can see how to send data from Neutralino to Python, which is dead simple:\n```html\n\u003ca href=\"#\" onclick=\"PYTHON.run('ping', 'Neutralino says PING!');\"\u003eSend PING to Python\u003c/a\u003e\u003cbr\u003e\n```\n\n**PYTHON.run()** takes 2 arguments:\n- The Python function to call, here \"ping\"\n- The data package to submit, either as string or JSON.\n\nBelow this link, you see\n```html\n\u003ca id=\"link-quit\" href=\"#\" onclick=\"PYTHON.stop();\" style=\"display:none\"\u003eQuit\u003c/a\u003e\n```\n**PYTHON.stop()** is only required, when running Neutralino in cloud-mode. This will unload the Python extension gracefully.\n\n## Classes overview\n\n### NeutralinoExtension.py\n\nNeutralinoExtension Class:\n\n| Method                           | Description                                                  |\n| -------------------------------- | ------------------------------------------------------------ |\n| NeutralinoExtension(debug=false) | Extension class. debug: Print data flow to the terminal.     |\n| debugLog(msg, tag=\"info\")        | Write a message to the terminal.\u003cbr /\u003emsg: Message\u003cbr /\u003etag: The message type, \"in\" for incoming, \"out\" for outgoing, \"info\" for others. |\n| isEvent(d, e)                    | Checks if the incoming event data package contains a particular event.\u003cbr /\u003ed: Data-package\u003cbr /\u003ee: Event-name |\n| parseFunctionCall(d)             | Extracts function-name (f) and parameter-data (p) from a message data package. Returns (f, p).\u003cbr /\u003ed: Data-package. |\n| run(onReceiveMessage)            | Starts the sockethandler main loop. \u003cbr /\u003eonReceiveMessage: Callback function for incoming messages. |\n| runThread(f, t, d):              | Starts a background task. \u003cbr /\u003ef: Task-function\u003cbr /\u003et: Task-name\u003cbr /\u003ed: Data-package |\n| sendMessage(e, d=None)           | Send a message to Neutralino. \u003cbr /\u003ee: Event-name,\u003cbr /\u003ed: Data-package as string or JSON dict. |\n\n| Property | Description                                    |\n| -------- | ---------------------------------------------- |\n| debug    | If true,  data flow is printed to the terminal |\n\n### python-extension.js\n\nPythonExtension Class:\n\n| Method               | Description                                                  |\n| -------------------- | ------------------------------------------------------------ |\n| async run(f, p=null) | Call a Python function. f: Function-name, p: Parameter data package as string or JSON. |\n| async stop()         | Stop and quit the Python extension and its parent app. Use this if Neutralino runs in Cloud-Mode. This is called automatically, when the browser tab is closed. |\n\n| Property | Description                                        |\n| -------- | -------------------------------------------------- |\n| debug    | If true,  data flow is printed to the dev-console. |\n\nEvents, sent from the frontend to the extension:\n\n| Event    | Description                                                  |\n| -------- | ------------------------------------------------------------ |\n| appClose | Notifies the extension, that the app will close. This quits the extension. |\n\n## More about Neutralino\n\n- \u003cu\u003e[NeutralinoJS Home](https://neutralino.js.org)\u003c/u\u003e \n- \u003cu\u003e[Neutralino Build Automation for macOS, Windows, Linux](https://github.com/hschneider/neutralino-build-scripts)\u003c/u\u003e\n\n- \u003cu\u003e[Neutralino related blog posts at marketmix.com](https://marketmix.com/de/tag/neutralinojs/)\u003c/u\u003e\n\n\n\n\u003cimg src=\"https://marketmix.com/git-assets/star-me-2.svg\"\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhschneider%2Fneutralino-ext-python","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhschneider%2Fneutralino-ext-python","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhschneider%2Fneutralino-ext-python/lists"}