brutalpywebui


Namebrutalpywebui JSON
Version 0.1.0 PyPI version JSON
download
home_pagehttps://github.com/zenoverflow/brutalpywebui
SummaryBrutalist realtime web-based UI for hassle-free desktop apps.
upload_time2024-02-06 21:35:59
maintainer
docs_urlNone
authorZen
requires_python>=3.11,<4.0
licenseMIT
keywords web ui frontend backend asyncio websocket html5 css javascript
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            
## Intro
BrutalPyWebUI is a brutalist async Python framework for building
utilitarian desktop applications that require a tried-and-true
web-based cross-platform interface with realtime capabilities and no hassle.

## Simple and focused
BrutalPyWebUI exposes a basic web interface bound to a host and port of
your choice, and provides you a selection of very basic utility
functions to update the DOM on the frontend from your Python backend,
as well as a few global javascript functions for quickly
grabbing data from the interface on the frontend and sending
it to the backend.

## Light on dependencies
BrutalPyWebUI depends only on:
- [hypercorn (the ASGI server)](https://github.com/pgjones/hypercorn),
- [Quart (a Flask replacement for asyncio)](https://github.com/pallets/quart)

## Light on assets
BrutalPyWebUI bundles only:
- [a default favicon (the Pyton logo)](https://www.favicon.cc/?action=icon&file_id=831343)
- [a default font (JetBrains Mono Regular)](https://github.com/JetBrains/JetBrainsMono)
- [a default css reset (Normalize.css)](https://github.com/necolas/normalize.css)

Note that you can disable all three separately.

## Flexible UI design
There are three main approaches in regards to actually
building the user interface:

### Utilitarian
Write most of your logic in Python and use the UI
as a barebones interface that sends events by calling
the special global `_wuiEvent()` function from a script
or an onclick attribute, etc., and gets updated
on-demand, from your Python code, by calling any
of the `wui.el_*()` or `wui.pg_*()` utility functions.

### Embrace Modernity
Use Python-land as more of a complementary backend and
inject heavier javascript and css that can contain
anything from logic and styling for basic web components
to the bundled code of a full-fledged React app. Note that
any js you inject using `base_js` in the constructor
is injected after the definitions for the global `_wui*()` functions
so they will not be overriden and you can call them normally
from within your app. You could also just use `asset_handler`
to serve your scripts along with other files.

### Anything in the middle / anything you can think of
Self-explanatory.

The idea is to give the developer a sturdy platform to
build upon, expanding freely as needed, without
highly specific enforced patterns.


## Installation
```bash
pip install brutalpywebui
```

## Basic usage
```python
import typing as t
from brutalpywebui import BrutalPyWebUI


example_html = '''
<input id="inp_regular_txt" value="Updated value" />
<button onclick="_wuiEvent('btn_press', _wuiVal('#inp_regular_txt'))">{{ button_text }}</button>
<div>Result: <span id="txt_result">Old value</span></div>
<div>Ticker: <span id="txt_ticker">{{ ticker_text }}</span></div>
'''

example_css = '''
body {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 30px 20px;
}

body > * {
    width: 100%;
    height: 24px;
    max-width: 300px;
    margin-bottom: 10px;
    padding: 0;
    border: none;
    outline: none;
    box-sizing: border-box;
}

body > input {
    border: 1px solid black;
    padding: 0 3px;
}
'''

wui: BrutalPyWebUI | None = None

ticker = 0


async def on_background():
    global ticker

    ticker += 1
    await wui.el_set_text(["#txt_ticker"], str(ticker))


async def on_event(event: str, data: t.Any):
    match event:
        case "btn_press":
            await wui.el_set_text(["#txt_result"], data)

        case _:
            pass


async def on_init():
    # this uses Jinja2 templates
    await wui.el_set_html_templ(
        ["body"],
        example_html,
        button_text="Press me!",
        ticker_text=str(ticker),
    )


wui = BrutalPyWebUI(
    page_title="MyApp",
    init_handler=on_init,
    event_handler=on_event,
    background_handler=on_background,
    background_interval=5.2,  # seconds
    base_css=example_css,
)

# these are the default host and port
# specified here for the sake of the example
wui.run(host="localhost", port=7865)

```

## Technical note
The run() method uses asyncio.run() and is meant
to be run on the main thread. The app will not be
served until run() is called.

## Python reference


### `__init__`


```python
async def on_init():
    pass

async def on_event(name: str, data: t.Any):
    pass

async def on_asset(asset_name: str):
    # served at yourhost:port/assets/<asset_name>
    asset_bytes, content_type = mock_read_asset(asset_name)
    return asset_bytes, content_type

wui = BrutalPyWebUI(
    page_title="MyApp",
    init_handler=on_init,
    event_handler=on_event,
    asset_handler=on_asset,
    background_handler=on_background,
    background_interval=5.2,  # seconds
    base_css=lambda: mock_read_asset("bundle.css")  # or pass str directly,
    base_js=lambda: mock_read_asset("bundle.js")  # or pass str directly,
    inject_python_favicon=True,
    inject_jetbrains_font=True,
    inject_normalize_css=True,
    page_websocket_use_tls=False,
    page_lang=lambda: "en",  # or pass str directly,
    page_encoding=lambda: "UTF-8",  # or pass str directly,
    page_viewport=lambda: "width=device-width, initial-scale=1.0", # or pass str directly,
    debug=False,  # print debug logs where applicable
)
```

- `page_title(str|()->str)` -- title of the page.
- `init_handler(async()->None)` -- coroutine to run on init.
- `event_handler(async(str,Any)->None)` -- coroutine to handle your custom events
from the frontend.
- `asset_handler(async(str)->(asset_content(Any), content_type(str)))` -- coroutine
to handle serving your custom assets for the frontend.
- `background_handler(async()->None)` -- coroutine called periodically in the background
controlled by the background_interval arg.
- `background_interval(float)` -- how often (in seconds with subsecond precision)
to call the background_handler.
- `base_css(str|()->str)` -- css string to inject in the main css file
for the frontend.
- `base_js(str|()->str)` -- js string to inject into the main js file
for the frontend.
- `inject_python_favicon(bool)` -- whether to use a default favicon.
- `inject_jetbrains_font(bool)` -- whether to use the JetBrains Mono Regular font.
- `inject_normalize_css(bool)` -- whether to inject NormalizeCSS into the main css file
for the frontend.
- `page_websocket_use_tls(bool)` -- whether to use wss instead of ws for the websocket
connection on the frontend.
- `page_lang(str)` -- the lang attribute for the html tag.
- `page_encoding(str)` -- the encoding of the page, normally you should not change this.
- `page_viewport(str)` -- the value for the viewport meta tag, normally you should not
change this unless having responsive issues with CSS.
- `debug(bool)` -- whether to print debug logs where applicable.


### `el_append_text`


Append text to the current el.innerText of one or more targets.
Affects all connected instances.

```python
await wui.el_set_text(['#my_element'], 'Hello')
await wui.el_append_text(['#my_element'], ' there')
```

- `selectors(list[str])` -- querySelectorAll selectors for targeting.
- `content(str)` -- a string containing any text.


### `el_append_value`


Append text to the current el.value of one or more targets.
Affects all connected instances.

```python
await wui.el_set_value(['#my_input'], 'Hello')
await wui.el_append_value(['#my_input'], ' there')
```

- `selectors(list[str])` -- querySelectorAll selectors for targeting.
- `content(str)` -- a string containing any text.


### `el_class_add`


Add a class to el.classList on one or more targets.
Affects all connected instances.

```python
await wui.el_class_add(['#my_element'], 'my_custom_class')
```

- `selectors(list[str])` -- querySelectorAll selectors for targeting.
- `name(str)` -- name of the class.


### `el_class_remove`


Remove a class from el.classList on one or more targets.
Affects all connected instances.

```python
await wui.el_class_remove(['#my_element'], 'my_custom_class')
```

- `selectors(list[str])` -- querySelectorAll selectors for targeting.
- `name(str)` -- name of the class.


### `el_disable`


Disable an element using el.disabled.
Affects all connected instances.

```python
await wui.el_disable(['#some_input', '#some_button'])
```

- `selectors(list[str])` -- querySelectorAll selectors for targeting.


### `el_enable`


Enable an element disabled using el.disabled.
Affects all connected instances.

```python
await wui.el_enable(['#some_input', '#some_button'])
```

- `selectors(list[str])` -- querySelectorAll selectors for targeting.


### `el_set_attribute`


Use el.setAttribute on one or more targets.
Affects all connected instances.

```python
await wui.el_set_attribute(['#my_element'], 'data-something', 'the value')
```

- `selectors(list[str])` -- querySelectorAll selectors for targeting.
- `name(str)` -- name of the attribute.
- `content(str)` -- value of the attribute.


### `el_set_html_templ`


Evaluate a Jinja2 template string and set the el.innerHTML of one or more targets.
Affects all connected instances.

```python
await wui.el_set_html_templ(
    ['#my_element'],
    '<div>{{ content }}</div>',
    content='Stuff',
)
```

- `selectors(list[str])` -- querySelectorAll selectors for targeting.
- `content(str)` -- a string containing a Jinja2 template.


### `el_set_html_unsafe`


Directly set the el.innerHTML of one or more targets.
Affects all connected instances.

```python
await wui.el_set_html_unsafe(['#my_element'], '<div>Stuff</div>')
```

- `selectors(list[str])` -- querySelectorAll selectors for targeting.
- `content(str)` -- a string containing html.


### `el_set_style`


Set a property on el.style on one or more targets.
Affects all connected instances.

```python
await wui.el_set_style(['#my_element'], 'backgroundColor', 'lightgray')
```

- `selectors(list[str])` -- querySelectorAll selectors for targeting.
- `name(str)` -- name of the style attribute (camelCase).
- `content(str)` -- value of the attribute.


### `el_set_text`


Directly set the el.innerText of one or more targets.
Affects all connected instances.

```python
await wui.el_set_text(['#my_element'], 'Hello there')
```

- `selectors(list[str])` -- querySelectorAll selectors for targeting.
- `content(str)` -- a string containing raw text.


### `el_set_value`


Set the el.value of one or more targets.
Affects all connected instances.

```python
await wui.el_set_value(['#my_input'], 'Hello')
```

- `selectors(list[str])` -- querySelectorAll selectors for targeting.
- `content(str)` -- a string containing any text.


### `pg_eval`


Eval a js string on the frontend.
Affects all connected instances.

```python
await wui.pg_eval('call_some_javascript()')
```

- `content(str)` -- the js string


### `pg_set_title`


Set the title of the page dynamically.
Affects all connected instances.

```python
await wui.pg_set_title('A New Title')
```

- `content(str)` -- the page title


### `run`


Run the BrutalPyWebUI app at host on port.

```python
await wui.run(host="localhost", port=7865)
```

- `host(str)` -- hostname.
- `port(int)` -- port number.


## JavaScript reference

### `_wuiEvent`

Send an event to your `event_handler` on the backend.

```javascript
_wuiEvent('my_event', ['some', 'data'])
```

- `name(string)` -- name of your event
- `data(any)` -- json-compatible object to send with your event

### `_wuiVal`

Returns `el.value` of an element.

```javascript
_wuiVal('#my_input')
```

- `selector(string)` -- querySelector selector

### `_wuiChecked`

Returns `el.checked` of an element.

```javascript
_wuiChecked('#my_input')
```

- `selector(string)` -- querySelector selector

### `_wuiSelected`

Returns `el.selected` of an element.

```javascript
_wuiSelected('#my_input')
```

- `selector(string)` -- querySelector selector

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/zenoverflow/brutalpywebui",
    "name": "brutalpywebui",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.11,<4.0",
    "maintainer_email": "",
    "keywords": "web,ui,frontend,backend,asyncio,websocket,html5,css,javascript",
    "author": "Zen",
    "author_email": "zen@zenoverflow.com",
    "download_url": "https://files.pythonhosted.org/packages/46/5e/4a54a7d0add6da00a0e2501ccd20eb849c1c386bff41147d1ee5c45e2fa7/brutalpywebui-0.1.0.tar.gz",
    "platform": null,
    "description": "\n## Intro\nBrutalPyWebUI is a brutalist async Python framework for building\nutilitarian desktop applications that require a tried-and-true\nweb-based cross-platform interface with realtime capabilities and no hassle.\n\n## Simple and focused\nBrutalPyWebUI exposes a basic web interface bound to a host and port of\nyour choice, and provides you a selection of very basic utility\nfunctions to update the DOM on the frontend from your Python backend,\nas well as a few global javascript functions for quickly\ngrabbing data from the interface on the frontend and sending\nit to the backend.\n\n## Light on dependencies\nBrutalPyWebUI depends only on:\n- [hypercorn (the ASGI server)](https://github.com/pgjones/hypercorn),\n- [Quart (a Flask replacement for asyncio)](https://github.com/pallets/quart)\n\n## Light on assets\nBrutalPyWebUI bundles only:\n- [a default favicon (the Pyton logo)](https://www.favicon.cc/?action=icon&file_id=831343)\n- [a default font (JetBrains Mono Regular)](https://github.com/JetBrains/JetBrainsMono)\n- [a default css reset (Normalize.css)](https://github.com/necolas/normalize.css)\n\nNote that you can disable all three separately.\n\n## Flexible UI design\nThere are three main approaches in regards to actually\nbuilding the user interface:\n\n### Utilitarian\nWrite most of your logic in Python and use the UI\nas a barebones interface that sends events by calling\nthe special global `_wuiEvent()` function from a script\nor an onclick attribute, etc., and gets updated\non-demand, from your Python code, by calling any\nof the `wui.el_*()` or `wui.pg_*()` utility functions.\n\n### Embrace Modernity\nUse Python-land as more of a complementary backend and\ninject heavier javascript and css that can contain\nanything from logic and styling for basic web components\nto the bundled code of a full-fledged React app. Note that\nany js you inject using `base_js` in the constructor\nis injected after the definitions for the global `_wui*()` functions\nso they will not be overriden and you can call them normally\nfrom within your app. You could also just use `asset_handler`\nto serve your scripts along with other files.\n\n### Anything in the middle / anything you can think of\nSelf-explanatory.\n\nThe idea is to give the developer a sturdy platform to\nbuild upon, expanding freely as needed, without\nhighly specific enforced patterns.\n\n\n## Installation\n```bash\npip install brutalpywebui\n```\n\n## Basic usage\n```python\nimport typing as t\nfrom brutalpywebui import BrutalPyWebUI\n\n\nexample_html = '''\n<input id=\"inp_regular_txt\" value=\"Updated value\" />\n<button onclick=\"_wuiEvent('btn_press', _wuiVal('#inp_regular_txt'))\">{{ button_text }}</button>\n<div>Result: <span id=\"txt_result\">Old value</span></div>\n<div>Ticker: <span id=\"txt_ticker\">{{ ticker_text }}</span></div>\n'''\n\nexample_css = '''\nbody {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    padding: 30px 20px;\n}\n\nbody > * {\n    width: 100%;\n    height: 24px;\n    max-width: 300px;\n    margin-bottom: 10px;\n    padding: 0;\n    border: none;\n    outline: none;\n    box-sizing: border-box;\n}\n\nbody > input {\n    border: 1px solid black;\n    padding: 0 3px;\n}\n'''\n\nwui: BrutalPyWebUI | None = None\n\nticker = 0\n\n\nasync def on_background():\n    global ticker\n\n    ticker += 1\n    await wui.el_set_text([\"#txt_ticker\"], str(ticker))\n\n\nasync def on_event(event: str, data: t.Any):\n    match event:\n        case \"btn_press\":\n            await wui.el_set_text([\"#txt_result\"], data)\n\n        case _:\n            pass\n\n\nasync def on_init():\n    # this uses Jinja2 templates\n    await wui.el_set_html_templ(\n        [\"body\"],\n        example_html,\n        button_text=\"Press me!\",\n        ticker_text=str(ticker),\n    )\n\n\nwui = BrutalPyWebUI(\n    page_title=\"MyApp\",\n    init_handler=on_init,\n    event_handler=on_event,\n    background_handler=on_background,\n    background_interval=5.2,  # seconds\n    base_css=example_css,\n)\n\n# these are the default host and port\n# specified here for the sake of the example\nwui.run(host=\"localhost\", port=7865)\n\n```\n\n## Technical note\nThe run() method uses asyncio.run() and is meant\nto be run on the main thread. The app will not be\nserved until run() is called.\n\n## Python reference\n\n\n### `__init__`\n\n\n```python\nasync def on_init():\n    pass\n\nasync def on_event(name: str, data: t.Any):\n    pass\n\nasync def on_asset(asset_name: str):\n    # served at yourhost:port/assets/<asset_name>\n    asset_bytes, content_type = mock_read_asset(asset_name)\n    return asset_bytes, content_type\n\nwui = BrutalPyWebUI(\n    page_title=\"MyApp\",\n    init_handler=on_init,\n    event_handler=on_event,\n    asset_handler=on_asset,\n    background_handler=on_background,\n    background_interval=5.2,  # seconds\n    base_css=lambda: mock_read_asset(\"bundle.css\")  # or pass str directly,\n    base_js=lambda: mock_read_asset(\"bundle.js\")  # or pass str directly,\n    inject_python_favicon=True,\n    inject_jetbrains_font=True,\n    inject_normalize_css=True,\n    page_websocket_use_tls=False,\n    page_lang=lambda: \"en\",  # or pass str directly,\n    page_encoding=lambda: \"UTF-8\",  # or pass str directly,\n    page_viewport=lambda: \"width=device-width, initial-scale=1.0\", # or pass str directly,\n    debug=False,  # print debug logs where applicable\n)\n```\n\n- `page_title(str|()->str)` -- title of the page.\n- `init_handler(async()->None)` -- coroutine to run on init.\n- `event_handler(async(str,Any)->None)` -- coroutine to handle your custom events\nfrom the frontend.\n- `asset_handler(async(str)->(asset_content(Any), content_type(str)))` -- coroutine\nto handle serving your custom assets for the frontend.\n- `background_handler(async()->None)` -- coroutine called periodically in the background\ncontrolled by the background_interval arg.\n- `background_interval(float)` -- how often (in seconds with subsecond precision)\nto call the background_handler.\n- `base_css(str|()->str)` -- css string to inject in the main css file\nfor the frontend.\n- `base_js(str|()->str)` -- js string to inject into the main js file\nfor the frontend.\n- `inject_python_favicon(bool)` -- whether to use a default favicon.\n- `inject_jetbrains_font(bool)` -- whether to use the JetBrains Mono Regular font.\n- `inject_normalize_css(bool)` -- whether to inject NormalizeCSS into the main css file\nfor the frontend.\n- `page_websocket_use_tls(bool)` -- whether to use wss instead of ws for the websocket\nconnection on the frontend.\n- `page_lang(str)` -- the lang attribute for the html tag.\n- `page_encoding(str)` -- the encoding of the page, normally you should not change this.\n- `page_viewport(str)` -- the value for the viewport meta tag, normally you should not\nchange this unless having responsive issues with CSS.\n- `debug(bool)` -- whether to print debug logs where applicable.\n\n\n### `el_append_text`\n\n\nAppend text to the current el.innerText of one or more targets.\nAffects all connected instances.\n\n```python\nawait wui.el_set_text(['#my_element'], 'Hello')\nawait wui.el_append_text(['#my_element'], ' there')\n```\n\n- `selectors(list[str])` -- querySelectorAll selectors for targeting.\n- `content(str)` -- a string containing any text.\n\n\n### `el_append_value`\n\n\nAppend text to the current el.value of one or more targets.\nAffects all connected instances.\n\n```python\nawait wui.el_set_value(['#my_input'], 'Hello')\nawait wui.el_append_value(['#my_input'], ' there')\n```\n\n- `selectors(list[str])` -- querySelectorAll selectors for targeting.\n- `content(str)` -- a string containing any text.\n\n\n### `el_class_add`\n\n\nAdd a class to el.classList on one or more targets.\nAffects all connected instances.\n\n```python\nawait wui.el_class_add(['#my_element'], 'my_custom_class')\n```\n\n- `selectors(list[str])` -- querySelectorAll selectors for targeting.\n- `name(str)` -- name of the class.\n\n\n### `el_class_remove`\n\n\nRemove a class from el.classList on one or more targets.\nAffects all connected instances.\n\n```python\nawait wui.el_class_remove(['#my_element'], 'my_custom_class')\n```\n\n- `selectors(list[str])` -- querySelectorAll selectors for targeting.\n- `name(str)` -- name of the class.\n\n\n### `el_disable`\n\n\nDisable an element using el.disabled.\nAffects all connected instances.\n\n```python\nawait wui.el_disable(['#some_input', '#some_button'])\n```\n\n- `selectors(list[str])` -- querySelectorAll selectors for targeting.\n\n\n### `el_enable`\n\n\nEnable an element disabled using el.disabled.\nAffects all connected instances.\n\n```python\nawait wui.el_enable(['#some_input', '#some_button'])\n```\n\n- `selectors(list[str])` -- querySelectorAll selectors for targeting.\n\n\n### `el_set_attribute`\n\n\nUse el.setAttribute on one or more targets.\nAffects all connected instances.\n\n```python\nawait wui.el_set_attribute(['#my_element'], 'data-something', 'the value')\n```\n\n- `selectors(list[str])` -- querySelectorAll selectors for targeting.\n- `name(str)` -- name of the attribute.\n- `content(str)` -- value of the attribute.\n\n\n### `el_set_html_templ`\n\n\nEvaluate a Jinja2 template string and set the el.innerHTML of one or more targets.\nAffects all connected instances.\n\n```python\nawait wui.el_set_html_templ(\n    ['#my_element'],\n    '<div>{{ content }}</div>',\n    content='Stuff',\n)\n```\n\n- `selectors(list[str])` -- querySelectorAll selectors for targeting.\n- `content(str)` -- a string containing a Jinja2 template.\n\n\n### `el_set_html_unsafe`\n\n\nDirectly set the el.innerHTML of one or more targets.\nAffects all connected instances.\n\n```python\nawait wui.el_set_html_unsafe(['#my_element'], '<div>Stuff</div>')\n```\n\n- `selectors(list[str])` -- querySelectorAll selectors for targeting.\n- `content(str)` -- a string containing html.\n\n\n### `el_set_style`\n\n\nSet a property on el.style on one or more targets.\nAffects all connected instances.\n\n```python\nawait wui.el_set_style(['#my_element'], 'backgroundColor', 'lightgray')\n```\n\n- `selectors(list[str])` -- querySelectorAll selectors for targeting.\n- `name(str)` -- name of the style attribute (camelCase).\n- `content(str)` -- value of the attribute.\n\n\n### `el_set_text`\n\n\nDirectly set the el.innerText of one or more targets.\nAffects all connected instances.\n\n```python\nawait wui.el_set_text(['#my_element'], 'Hello there')\n```\n\n- `selectors(list[str])` -- querySelectorAll selectors for targeting.\n- `content(str)` -- a string containing raw text.\n\n\n### `el_set_value`\n\n\nSet the el.value of one or more targets.\nAffects all connected instances.\n\n```python\nawait wui.el_set_value(['#my_input'], 'Hello')\n```\n\n- `selectors(list[str])` -- querySelectorAll selectors for targeting.\n- `content(str)` -- a string containing any text.\n\n\n### `pg_eval`\n\n\nEval a js string on the frontend.\nAffects all connected instances.\n\n```python\nawait wui.pg_eval('call_some_javascript()')\n```\n\n- `content(str)` -- the js string\n\n\n### `pg_set_title`\n\n\nSet the title of the page dynamically.\nAffects all connected instances.\n\n```python\nawait wui.pg_set_title('A New Title')\n```\n\n- `content(str)` -- the page title\n\n\n### `run`\n\n\nRun the BrutalPyWebUI app at host on port.\n\n```python\nawait wui.run(host=\"localhost\", port=7865)\n```\n\n- `host(str)` -- hostname.\n- `port(int)` -- port number.\n\n\n## JavaScript reference\n\n### `_wuiEvent`\n\nSend an event to your `event_handler` on the backend.\n\n```javascript\n_wuiEvent('my_event', ['some', 'data'])\n```\n\n- `name(string)` -- name of your event\n- `data(any)` -- json-compatible object to send with your event\n\n### `_wuiVal`\n\nReturns `el.value` of an element.\n\n```javascript\n_wuiVal('#my_input')\n```\n\n- `selector(string)` -- querySelector selector\n\n### `_wuiChecked`\n\nReturns `el.checked` of an element.\n\n```javascript\n_wuiChecked('#my_input')\n```\n\n- `selector(string)` -- querySelector selector\n\n### `_wuiSelected`\n\nReturns `el.selected` of an element.\n\n```javascript\n_wuiSelected('#my_input')\n```\n\n- `selector(string)` -- querySelector selector\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Brutalist realtime web-based UI for hassle-free desktop apps.",
    "version": "0.1.0",
    "project_urls": {
        "Homepage": "https://github.com/zenoverflow/brutalpywebui",
        "Repository": "https://github.com/zenoverflow/brutalpywebui"
    },
    "split_keywords": [
        "web",
        "ui",
        "frontend",
        "backend",
        "asyncio",
        "websocket",
        "html5",
        "css",
        "javascript"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "fcccc36f9d88f02831751ce4af99d3bb15254ce70a347be39f832b15e996b084",
                "md5": "c6b9ddde7e657f6ed42889a3fa038917",
                "sha256": "74039aad9c2403486cc281cd2bebe207ae13fb9c6d88a0d6a3b95576c203c42c"
            },
            "downloads": -1,
            "filename": "brutalpywebui-0.1.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "c6b9ddde7e657f6ed42889a3fa038917",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.11,<4.0",
            "size": 185512,
            "upload_time": "2024-02-06T21:35:56",
            "upload_time_iso_8601": "2024-02-06T21:35:56.440690Z",
            "url": "https://files.pythonhosted.org/packages/fc/cc/c36f9d88f02831751ce4af99d3bb15254ce70a347be39f832b15e996b084/brutalpywebui-0.1.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "465e4a54a7d0add6da00a0e2501ccd20eb849c1c386bff41147d1ee5c45e2fa7",
                "md5": "e414e544dd16ad0a926d9582e360dd31",
                "sha256": "5ddec54e3246ea4b0ceea5c4764c6f7e5d2140c69422f8db9cc94d6951dde00d"
            },
            "downloads": -1,
            "filename": "brutalpywebui-0.1.0.tar.gz",
            "has_sig": false,
            "md5_digest": "e414e544dd16ad0a926d9582e360dd31",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.11,<4.0",
            "size": 185329,
            "upload_time": "2024-02-06T21:35:59",
            "upload_time_iso_8601": "2024-02-06T21:35:59.157546Z",
            "url": "https://files.pythonhosted.org/packages/46/5e/4a54a7d0add6da00a0e2501ccd20eb849c1c386bff41147d1ee5c45e2fa7/brutalpywebui-0.1.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-02-06 21:35:59",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "zenoverflow",
    "github_project": "brutalpywebui",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "brutalpywebui"
}
        
Zen
Elapsed time: 0.18821s