python-uime


Namepython-uime JSON
Version 1.0.8 PyPI version JSON
download
home_pagehttps://github.com/livetheoogway/python-uime
SummaryA python library to help you build simple UI forms for your python functions
upload_time2024-02-23 20:26:25
maintainer
docs_urlNone
authorTushar Naik
requires_python
licenseLicense 2.0
keywords ui generate-ui ui-generate ui-enable function to ui flask style decorator tushar
VCS
bugtrack_url
requirements flask
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <p align="center">
  <h1 align="center">Python UI-Me</h1>
  <p align="center">A simple python decorator, to build UI forms out of your everyday python functions<p>
  <p align="center">
    <a href="https://pypi.org/project/python-uime">
    	<img src="https://img.shields.io/pypi/v/python-uime"/>
    </a>
    <a href="https://github.com/livetheoogway/python-uime/blob/master/LICENSE">
    	<img src="https://img.shields.io/github/license/livetheoogway/python-uime" alt="license" />
    </a></p>
</p>

## UI-Me

Python UI-Me (as in: Python methods saying "make elegant UI forms out of me") is a Python package that enables
developers to quickly create web-based user interfaces for Python functions. It uses decorators to mark functions for UI
exposure and a built-in Flask server to render the UI.

## TL;DR

**The promise:** With-in 3 lines of code, you will be able to get a working UI form out of your python functions<br>
**Another promise:** You won't regret the time spent in reading the [Motivation](#Motivation) section, it is not too
long<br>
But for the ones seeking instant gratification: watch this fancy gif (which I totally struggled to create):<br>
![demo.gif](resources/demo.gif)

## Motivation

I'm pretty sure I'm not the only lazy developer that over-engineers every small daily task as scripts. <br>
Honestly, this is yet another attempt of the aforementioned over-engineering, towards making it as easy as possible to
whip up a quick UI to run those scripts.<br>
Yes, there are good alternatives, `argparse` being a popular one for running your scripts through cli. But I've always
struggled with it the moment the script has multiple functionalities or modules.
The day you start forgetting your engineering principles and start overloading your one script to do many things (
because duh! that was the whole point of writing it as a script), these cli tools start to fall apart.  
Not the mention the amount of code you'd have to write, like stitching parsers and subparsers and subsubparsers
and.. <br>

Having said that, for proper production scripts, UI-me is not the way to go. But for those quick and dirty daily /
personal scripts, you would find UI-me useful <br>
Think of this like [Swagger UI](https://swagger.io/tools/swagger-ui/), but for python functions. <br>

## Features

1. **Easy Function Exposure** <br>
   Decorate Python functions with `@ui_enabled` to expose them as web forms.
2. **Automatic UI Generation** <br>
   Generates web UIs for decorated functions, with form fields corresponding to function parameters.
3. **Grouping of Functions** <br>
   Organize functions into <br>
   groups (nav-tabs) in the UI for better organization.
4. **Customizable Function Metadata** <br>
   Specify titles, descriptions, and other metadata for functions.
5. **Built-in Web Server** <br>
   Comes with an integrated Flask web server to host the UI.
6. **Clipboard Support** <br>
   Easy copy-to-clipboard feature for function outputs.
7. **Quick navigation Sidebar** <br>
   If you have too many functions, the sidebar can be used to quickly navigate to your function
8. **Global Variables** <br>
   Set global variables for your script, from within the UI.
9. **Type Inferring (This is Cool !!)** <br>
   Functions that contain arguments with types, are inferred and rendered accordingly in the INPUT form

## Installation

Install Python UI-me using pip:

```bash
python3 -m pip install python-uime
```

## Usage

Basically 3 lines of code

```python
from uime import start_server, ui_enabled  ## <--- This is line 1


##  Below is line 2
@ui_enabled(group="Greeting", description="This function will greet you (with positivity!)")
def hello_world(name):
    return f"Hello {name}"


@ui_enabled(group="Greeting", title="My Test Function with Nice Title",
            description="This function will return a json (So that you can see it is nicely printed)")
def make_api_call(url, data):
    return json.dumps({"url": url, "data": hello_world(data)})


@ui_enabled(group="Maths", description="This will return a + b")
def sum_math_function(a, b):
    return a + b


@ui_enabled(group="Maths")
def difference_math_function(a, b):
    return a - b


if __name__ == '__main__':
    start_server()  ## <--- This is line 3 (As promised, within 3 lines of code)
```

![img.png](resources/ui-example.png)

## Advanced Usage

### 1. Setting Global Variables

You might run into situations where you want to set global variables of your script. <br>
This is going to be a little more involved - you need to expose a setter to the global variable, while using a new
decorator `@ui_global` <br>
Here is an example:

```python
from uime import start_server, ui_enabled, ui_global  ## <--- ui_global is the new import

DEFAULT = "There are no accidents."
DEFAULT_2 = "Only coincidences."


@ui_global(name="DEFAULT", description="Global DEFAULT value", default_value=DEFAULT)
def set_default(value):
    global DEFAULT
    DEFAULT = value


@ui_global(name="DEFAULT_2", description="Global DEFAULT_2 value", default_value=DEFAULT_2)
def set_default2(value):
    global DEFAULT_2
    DEFAULT_2 = value


@ui_enabled(group="group1")
def hello_world(name):
    return f"Hello {name}. {DEFAULT} {DEFAULT_2}"  # <-- using the global variables
```

The left navigation bar contains a section for Global Variables, which will allow you to set them. <br>

### 2. Function Parameter Type Inferring

| type          | form input   | type inferred          |
|---------------|--------------|------------------------|
| nothing       | text input   | str                    |
| str           | text input   | str                    |
| bool          | switch       | bool                   |
| int           | number input | int                    |
| float         | number input | float                  |
| complex       | number input | complex                |
| list          | text area    | list of string         |
| set           | text area    | set of string          |
| type          | text area    | list of string         |
| List[str]     | text area    | list of string         |
| List[int]     | text area    | list of int            |
| List[float]   | text area    | list of float          |
| List[complex] | text area    | list of complex        |
| List[list]    | text area    | list of list of string |
| dict          | text area    | json to dict           |

Sample code below shows a list of parameters that have different types:

```python
from typing import List
import json
from uime import start_server, ui_enabled


@ui_enabled(group="group1")
def test_list_string(regular_list: list, strings: List[str], ints: List[int], dicts: dict, list_of_list: List[list]):
    return f"""
    list = {regular_list}
    strings= {strings}
    ints= {ints}
    dicts: {json.dumps(dicts)}
    list_of_list: {list_of_list}
    """

```

The UI would look something like this
![global.png](resources/type-infer-demo.png)

> [!NOTE]
> As you observe the above table, a text-area is used to collect inputs for complex datatypes. This is being done on
> purpose to keep things simple, but that simplicity comes at a cost.
> When inferring a list of anything from the text-area - extraction of the list from the large string, is done by using
> delimiters.
> By default, the priority of delimiters are NEWLINE, COMMA, SPACE
> ie: NEWLINE is checked first, if available, the string will be split by newline and returned as a list. Then there is a
> check for COMMA, if available, the string will be split by comma and returned as a list. Finally SPACE.
> In case of <list of list>, it is always a check on NEWLINE for the outer list, and COMMA/SPACE for the inner lists

## Dependencies

The following is not the exhaustive list of dependencies, but UI-me was made possible because of these:

- [Flask](https://flask.palletsprojects.com/en/3.0.x/): quickest way to spin up a web server
- [Jinja2](https://jinja.palletsprojects.com/en/2.11.x/templates/): for templating
- [Tailwind CSS](https://tailwindcss.com/): it is a pretty neat, utility-first CSS framework for rapid UI development

## Features Pending

- [ ] Handle overloading of functions (identify functions with ids rather than names)
- [x] Add support for setting `global` variables in the UI ([Setting Global Variables](#1-setting-global-variables))
- [x] Add support for complex data-structures as inputs (like list of strings, or json strings)
- [x] Make default values for parameters as non-mandatory in the form
- [x] Capture parameter data types and change the form field type accordingly

## Contributions

Please raise Issues, Bugs or any feature requests
at [Github Issues](https://github.com/livetheoogway/python-uime/issues). <br>
If you plan on contributing to the code, fork the repository and raise a Pull Request back here.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/livetheoogway/python-uime",
    "name": "python-uime",
    "maintainer": "",
    "docs_url": null,
    "requires_python": "",
    "maintainer_email": "",
    "keywords": "ui,generate-ui,ui-generate,ui-enable,function to ui,flask style,decorator,tushar",
    "author": "Tushar Naik",
    "author_email": "tushar.knaik@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/0a/fb/51692ce2ce9188e7bb3d1220cc523b6f06c11f5303965cfd785203021bd0/python-uime-1.0.8.tar.gz",
    "platform": null,
    "description": "<p align=\"center\">\n  <h1 align=\"center\">Python UI-Me</h1>\n  <p align=\"center\">A simple python decorator, to build UI forms out of your everyday python functions<p>\n  <p align=\"center\">\n    <a href=\"https://pypi.org/project/python-uime\">\n    \t<img src=\"https://img.shields.io/pypi/v/python-uime\"/>\n    </a>\n    <a href=\"https://github.com/livetheoogway/python-uime/blob/master/LICENSE\">\n    \t<img src=\"https://img.shields.io/github/license/livetheoogway/python-uime\" alt=\"license\" />\n    </a></p>\n</p>\n\n## UI-Me\n\nPython UI-Me (as in: Python methods saying \"make elegant UI forms out of me\") is a Python package that enables\ndevelopers to quickly create web-based user interfaces for Python functions. It uses decorators to mark functions for UI\nexposure and a built-in Flask server to render the UI.\n\n## TL;DR\n\n**The promise:** With-in 3 lines of code, you will be able to get a working UI form out of your python functions<br>\n**Another promise:** You won't regret the time spent in reading the [Motivation](#Motivation) section, it is not too\nlong<br>\nBut for the ones seeking instant gratification: watch this fancy gif (which I totally struggled to create):<br>\n![demo.gif](resources/demo.gif)\n\n## Motivation\n\nI'm pretty sure I'm not the only lazy developer that over-engineers every small daily task as scripts. <br>\nHonestly, this is yet another attempt of the aforementioned over-engineering, towards making it as easy as possible to\nwhip up a quick UI to run those scripts.<br>\nYes, there are good alternatives, `argparse` being a popular one for running your scripts through cli. But I've always\nstruggled with it the moment the script has multiple functionalities or modules.\nThe day you start forgetting your engineering principles and start overloading your one script to do many things (\nbecause duh! that was the whole point of writing it as a script), these cli tools start to fall apart.  \nNot the mention the amount of code you'd have to write, like stitching parsers and subparsers and subsubparsers\nand.. <br>\n\nHaving said that, for proper production scripts, UI-me is not the way to go. But for those quick and dirty daily /\npersonal scripts, you would find UI-me useful <br>\nThink of this like [Swagger UI](https://swagger.io/tools/swagger-ui/), but for python functions. <br>\n\n## Features\n\n1. **Easy Function Exposure** <br>\n   Decorate Python functions with `@ui_enabled` to expose them as web forms.\n2. **Automatic UI Generation** <br>\n   Generates web UIs for decorated functions, with form fields corresponding to function parameters.\n3. **Grouping of Functions** <br>\n   Organize functions into <br>\n   groups (nav-tabs) in the UI for better organization.\n4. **Customizable Function Metadata** <br>\n   Specify titles, descriptions, and other metadata for functions.\n5. **Built-in Web Server** <br>\n   Comes with an integrated Flask web server to host the UI.\n6. **Clipboard Support** <br>\n   Easy copy-to-clipboard feature for function outputs.\n7. **Quick navigation Sidebar** <br>\n   If you have too many functions, the sidebar can be used to quickly navigate to your function\n8. **Global Variables** <br>\n   Set global variables for your script, from within the UI.\n9. **Type Inferring (This is Cool !!)** <br>\n   Functions that contain arguments with types, are inferred and rendered accordingly in the INPUT form\n\n## Installation\n\nInstall Python UI-me using pip:\n\n```bash\npython3 -m pip install python-uime\n```\n\n## Usage\n\nBasically 3 lines of code\n\n```python\nfrom uime import start_server, ui_enabled  ## <--- This is line 1\n\n\n##  Below is line 2\n@ui_enabled(group=\"Greeting\", description=\"This function will greet you (with positivity!)\")\ndef hello_world(name):\n    return f\"Hello {name}\"\n\n\n@ui_enabled(group=\"Greeting\", title=\"My Test Function with Nice Title\",\n            description=\"This function will return a json (So that you can see it is nicely printed)\")\ndef make_api_call(url, data):\n    return json.dumps({\"url\": url, \"data\": hello_world(data)})\n\n\n@ui_enabled(group=\"Maths\", description=\"This will return a + b\")\ndef sum_math_function(a, b):\n    return a + b\n\n\n@ui_enabled(group=\"Maths\")\ndef difference_math_function(a, b):\n    return a - b\n\n\nif __name__ == '__main__':\n    start_server()  ## <--- This is line 3 (As promised, within 3 lines of code)\n```\n\n![img.png](resources/ui-example.png)\n\n## Advanced Usage\n\n### 1. Setting Global Variables\n\nYou might run into situations where you want to set global variables of your script. <br>\nThis is going to be a little more involved - you need to expose a setter to the global variable, while using a new\ndecorator `@ui_global` <br>\nHere is an example:\n\n```python\nfrom uime import start_server, ui_enabled, ui_global  ## <--- ui_global is the new import\n\nDEFAULT = \"There are no accidents.\"\nDEFAULT_2 = \"Only coincidences.\"\n\n\n@ui_global(name=\"DEFAULT\", description=\"Global DEFAULT value\", default_value=DEFAULT)\ndef set_default(value):\n    global DEFAULT\n    DEFAULT = value\n\n\n@ui_global(name=\"DEFAULT_2\", description=\"Global DEFAULT_2 value\", default_value=DEFAULT_2)\ndef set_default2(value):\n    global DEFAULT_2\n    DEFAULT_2 = value\n\n\n@ui_enabled(group=\"group1\")\ndef hello_world(name):\n    return f\"Hello {name}. {DEFAULT} {DEFAULT_2}\"  # <-- using the global variables\n```\n\nThe left navigation bar contains a section for Global Variables, which will allow you to set them. <br>\n\n### 2. Function Parameter Type Inferring\n\n| type          | form input   | type inferred          |\n|---------------|--------------|------------------------|\n| nothing       | text input   | str                    |\n| str           | text input   | str                    |\n| bool          | switch       | bool                   |\n| int           | number input | int                    |\n| float         | number input | float                  |\n| complex       | number input | complex                |\n| list          | text area    | list of string         |\n| set           | text area    | set of string          |\n| type          | text area    | list of string         |\n| List[str]     | text area    | list of string         |\n| List[int]     | text area    | list of int            |\n| List[float]   | text area    | list of float          |\n| List[complex] | text area    | list of complex        |\n| List[list]    | text area    | list of list of string |\n| dict          | text area    | json to dict           |\n\nSample code below shows a list of parameters that have different types:\n\n```python\nfrom typing import List\nimport json\nfrom uime import start_server, ui_enabled\n\n\n@ui_enabled(group=\"group1\")\ndef test_list_string(regular_list: list, strings: List[str], ints: List[int], dicts: dict, list_of_list: List[list]):\n    return f\"\"\"\n    list = {regular_list}\n    strings= {strings}\n    ints= {ints}\n    dicts: {json.dumps(dicts)}\n    list_of_list: {list_of_list}\n    \"\"\"\n\n```\n\nThe UI would look something like this\n![global.png](resources/type-infer-demo.png)\n\n> [!NOTE]\n> As you observe the above table, a text-area is used to collect inputs for complex datatypes. This is being done on\n> purpose to keep things simple, but that simplicity comes at a cost.\n> When inferring a list of anything from the text-area - extraction of the list from the large string, is done by using\n> delimiters.\n> By default, the priority of delimiters are NEWLINE, COMMA, SPACE\n> ie: NEWLINE is checked first, if available, the string will be split by newline and returned as a list. Then there is a\n> check for COMMA, if available, the string will be split by comma and returned as a list. Finally SPACE.\n> In case of <list of list>, it is always a check on NEWLINE for the outer list, and COMMA/SPACE for the inner lists\n\n## Dependencies\n\nThe following is not the exhaustive list of dependencies, but UI-me was made possible because of these:\n\n- [Flask](https://flask.palletsprojects.com/en/3.0.x/): quickest way to spin up a web server\n- [Jinja2](https://jinja.palletsprojects.com/en/2.11.x/templates/): for templating\n- [Tailwind CSS](https://tailwindcss.com/): it is a pretty neat, utility-first CSS framework for rapid UI development\n\n## Features Pending\n\n- [ ] Handle overloading of functions (identify functions with ids rather than names)\n- [x] Add support for setting `global` variables in the UI ([Setting Global Variables](#1-setting-global-variables))\n- [x] Add support for complex data-structures as inputs (like list of strings, or json strings)\n- [x] Make default values for parameters as non-mandatory in the form\n- [x] Capture parameter data types and change the form field type accordingly\n\n## Contributions\n\nPlease raise Issues, Bugs or any feature requests\nat [Github Issues](https://github.com/livetheoogway/python-uime/issues). <br>\nIf you plan on contributing to the code, fork the repository and raise a Pull Request back here.\n",
    "bugtrack_url": null,
    "license": "License 2.0",
    "summary": "A python library to help you build simple UI forms for your python functions",
    "version": "1.0.8",
    "project_urls": {
        "Homepage": "https://github.com/livetheoogway/python-uime"
    },
    "split_keywords": [
        "ui",
        "generate-ui",
        "ui-generate",
        "ui-enable",
        "function to ui",
        "flask style",
        "decorator",
        "tushar"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "0afb51692ce2ce9188e7bb3d1220cc523b6f06c11f5303965cfd785203021bd0",
                "md5": "342eeebaccb9e92e9b78c736c289fbba",
                "sha256": "e91044a92e61fdb99a09d66b53174b21732eece77581de0e8e356174de4926b3"
            },
            "downloads": -1,
            "filename": "python-uime-1.0.8.tar.gz",
            "has_sig": false,
            "md5_digest": "342eeebaccb9e92e9b78c736c289fbba",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 17936,
            "upload_time": "2024-02-23T20:26:25",
            "upload_time_iso_8601": "2024-02-23T20:26:25.043571Z",
            "url": "https://files.pythonhosted.org/packages/0a/fb/51692ce2ce9188e7bb3d1220cc523b6f06c11f5303965cfd785203021bd0/python-uime-1.0.8.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-02-23 20:26:25",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "livetheoogway",
    "github_project": "python-uime",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [
        {
            "name": "flask",
            "specs": []
        }
    ],
    "lcname": "python-uime"
}
        
Elapsed time: 0.21184s