[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Tests](https://github.com/AlexeyBond/turbosnake/workflows/Tests/badge.svg)](https://github.com/AlexeyBond/turbosnake/actions?query=workflow%3ATests)
[![Coverage Status](https://coveralls.io/repos/github/AlexeyBond/turbosnake/badge.svg?branch=master)](https://coveralls.io/github/AlexeyBond/turbosnake?branch=master)
# turbosnake - a react.js-like framework for ui in python
## Motivation
There are lots of nice graphical applications written in python. But code that creates UI (at least in simple examples I
could find and in few projects I tried to contribute to) looks like some sort of imperative mess. And it gets even
uglier when UI should be changed dynamically. So, I decided to try to reproduce the declarative approach which I am used
to as a professional web-developer.
## Installing
```shell
$ pip install turbosnake
```
## Syntax
Unlike JavaScript frameworks with JSX, we cannot just modify Python's syntax for our purposes. Instead, turbosnake uses
unmodified Python's syntax to represent its concepts.
### Instantiating components
Instead of JSX's `<Component ... />` turbosnake uses a plain function call:
```python
component(...)
```
In most cases, return value of such calls is useless. The main effect of such call is a component being appended to a
list in specific runtime context. Calls of components outside of proper runtime context are prohibited and will cause
error.
### Nesting components
Children are added to a component using `with` operator:
```python
with component1(...):
component11(...)
component12(...)
```
this fragment of code is kinda equivalent to the following JSX:
```jsx
<Component1 ...>
<Component11 .../>
<Component12 .../>
</Component1>
```
but unlike it, any loops and conditions are allowed within body of `with` operator. Components that support nesting
implement context provider interface. When used in `with` operator they substitute previously mentioned runtime context
with the one that adds all created components to list of their children.
### Functional components
The easiest way to compose few components is to create a functional component. In some simple cases (component doesn't
use hooks or is always rendered constant number of times within it's parent) a plain function can serve as a functional
component:
```python
def foo(**props):
with component1():
component2(**props)
...
foo(...)
```
But a function can be converted into a full-fledged component with its own state using `functional_component` decorator:
```python
from turbosnake import functional_component
...
@functional_component
def foo(**props):
with component1():
component2(**props)
...
foo(...)
```
Depending on function signature and settings passed to the decorator, it may add (or don't add) support for nesting and
hooks.
### Hooks
Hooks are supported in functional components (if not disabled explicitly) and in components
inheriting `ComponentWithHooks`. Some of implemented hooks are: `use_toggle`, `use_state`, `use_memo`, `use_effect`
, `use_callback`, `use_previous`, `use_ref`, `use_callback_proxy`, `use_self`.
Hooks that accept a function can be used as decorators on a local function:
```python
from turbosnake import functional_component, use_callback
...
@functional_component
def foo():
...
@use_callback([...])
def callback():
...
...
```
## UI
Core of turbosnake isn't bound to any UI library or framework. With some effort applied, it can be used with any UI
library or even for purposes different from user interface rendering.
Package `turbosnake.ttk` provides adapters for tkinter (mostly ttk) UI components. For examples
see [TODO-list application example](https://github.com/AlexeyBond/turbosnake/blob/master/examples/todo.py).
### Live preview
Composite turbosnake UI components are not meant to be edited using any sort of visual editor. But, in order to make it
easier to create, modify and debug complex layouts turbosnake provides live preview tool. It is inspired by React's
Storybook. The tool tracks changes in component file and renders the most recent version in a window.
Current version of preview tool tracks changes only in the preview file itself. Tracking of changes in dependencies may
be added later.
See [preview_example.py](https://github.com/AlexeyBond/turbosnake/blob/master/examples/preview_example.py) for example
of preview tool use.
Raw data
{
"_id": null,
"home_page": "https://github.com/AlexeyBond/turbosnake",
"name": "turbosnake",
"maintainer": "",
"docs_url": null,
"requires_python": "",
"maintainer_email": "",
"keywords": "ui,reactive,tkinter",
"author": "Alexey Bondarenko",
"author_email": "alexey.bond.94.55+turbosnake@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/0f/3c/a1aad1433f264c7e25eb3d881ade120344aa9daadf8b70d78e1e93b6419e/turbosnake-1.24.434.tar.gz",
"platform": null,
"description": "[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\r\n[![Tests](https://github.com/AlexeyBond/turbosnake/workflows/Tests/badge.svg)](https://github.com/AlexeyBond/turbosnake/actions?query=workflow%3ATests)\r\n[![Coverage Status](https://coveralls.io/repos/github/AlexeyBond/turbosnake/badge.svg?branch=master)](https://coveralls.io/github/AlexeyBond/turbosnake?branch=master)\r\n\r\n# turbosnake - a react.js-like framework for ui in python\r\n\r\n## Motivation\r\n\r\nThere are lots of nice graphical applications written in python. But code that creates UI (at least in simple examples I\r\ncould find and in few projects I tried to contribute to) looks like some sort of imperative mess. And it gets even\r\nuglier when UI should be changed dynamically. So, I decided to try to reproduce the declarative approach which I am used\r\nto as a professional web-developer.\r\n\r\n## Installing\r\n\r\n```shell\r\n$ pip install turbosnake\r\n```\r\n\r\n## Syntax\r\n\r\nUnlike JavaScript frameworks with JSX, we cannot just modify Python's syntax for our purposes. Instead, turbosnake uses\r\nunmodified Python's syntax to represent its concepts.\r\n\r\n### Instantiating components\r\n\r\nInstead of JSX's `<Component ... />` turbosnake uses a plain function call:\r\n\r\n```python\r\ncomponent(...)\r\n```\r\n\r\nIn most cases, return value of such calls is useless. The main effect of such call is a component being appended to a\r\nlist in specific runtime context. Calls of components outside of proper runtime context are prohibited and will cause\r\nerror.\r\n\r\n### Nesting components\r\n\r\nChildren are added to a component using `with` operator:\r\n\r\n```python\r\nwith component1(...):\r\n component11(...)\r\n component12(...)\r\n```\r\n\r\nthis fragment of code is kinda equivalent to the following JSX:\r\n\r\n```jsx\r\n<Component1 ...>\r\n <Component11 .../>\r\n <Component12 .../>\r\n</Component1>\r\n```\r\n\r\nbut unlike it, any loops and conditions are allowed within body of `with` operator. Components that support nesting\r\nimplement context provider interface. When used in `with` operator they substitute previously mentioned runtime context\r\nwith the one that adds all created components to list of their children.\r\n\r\n### Functional components\r\n\r\nThe easiest way to compose few components is to create a functional component. In some simple cases (component doesn't\r\nuse hooks or is always rendered constant number of times within it's parent) a plain function can serve as a functional\r\ncomponent:\r\n\r\n```python\r\ndef foo(**props):\r\n with component1():\r\n component2(**props)\r\n\r\n\r\n...\r\n\r\nfoo(...)\r\n```\r\n\r\nBut a function can be converted into a full-fledged component with its own state using `functional_component` decorator:\r\n\r\n```python\r\nfrom turbosnake import functional_component\r\n\r\n...\r\n\r\n\r\n@functional_component\r\ndef foo(**props):\r\n with component1():\r\n component2(**props)\r\n\r\n\r\n...\r\n\r\nfoo(...)\r\n```\r\n\r\nDepending on function signature and settings passed to the decorator, it may add (or don't add) support for nesting and\r\nhooks.\r\n\r\n### Hooks\r\n\r\nHooks are supported in functional components (if not disabled explicitly) and in components\r\ninheriting `ComponentWithHooks`. Some of implemented hooks are: `use_toggle`, `use_state`, `use_memo`, `use_effect`\r\n, `use_callback`, `use_previous`, `use_ref`, `use_callback_proxy`, `use_self`.\r\n\r\nHooks that accept a function can be used as decorators on a local function:\r\n\r\n```python\r\nfrom turbosnake import functional_component, use_callback\r\n\r\n...\r\n\r\n\r\n@functional_component\r\ndef foo():\r\n ...\r\n\r\n @use_callback([...])\r\n def callback():\r\n ...\r\n\r\n ...\r\n```\r\n\r\n## UI\r\n\r\nCore of turbosnake isn't bound to any UI library or framework. With some effort applied, it can be used with any UI\r\nlibrary or even for purposes different from user interface rendering.\r\n\r\nPackage `turbosnake.ttk` provides adapters for tkinter (mostly ttk) UI components. For examples\r\nsee [TODO-list application example](https://github.com/AlexeyBond/turbosnake/blob/master/examples/todo.py).\r\n\r\n### Live preview\r\n\r\nComposite turbosnake UI components are not meant to be edited using any sort of visual editor. But, in order to make it\r\neasier to create, modify and debug complex layouts turbosnake provides live preview tool. It is inspired by React's\r\nStorybook. The tool tracks changes in component file and renders the most recent version in a window.\r\n\r\nCurrent version of preview tool tracks changes only in the preview file itself. Tracking of changes in dependencies may\r\nbe added later.\r\n\r\nSee [preview_example.py](https://github.com/AlexeyBond/turbosnake/blob/master/examples/preview_example.py) for example\r\nof preview tool use.\r\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "React.js-like framework with components for native user interfaces",
"version": "1.24.434",
"project_urls": {
"Homepage": "https://github.com/AlexeyBond/turbosnake"
},
"split_keywords": [
"ui",
"reactive",
"tkinter"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "48188dcf9f1e24810cc5840074ca103aa1aeeca7e4ec17a8441559646e621176",
"md5": "7d4aaaaf8b2f6ae3f72d89c90258be68",
"sha256": "a1711d919aa67c0485f698273125fc84660923a522f761d11b3604aebba2a2b2"
},
"downloads": -1,
"filename": "turbosnake-1.24.434-py3-none-any.whl",
"has_sig": false,
"md5_digest": "7d4aaaaf8b2f6ae3f72d89c90258be68",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 35585,
"upload_time": "2023-08-01T08:16:35",
"upload_time_iso_8601": "2023-08-01T08:16:35.447945Z",
"url": "https://files.pythonhosted.org/packages/48/18/8dcf9f1e24810cc5840074ca103aa1aeeca7e4ec17a8441559646e621176/turbosnake-1.24.434-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "0f3ca1aad1433f264c7e25eb3d881ade120344aa9daadf8b70d78e1e93b6419e",
"md5": "a70141d016bd6b317729c14573177467",
"sha256": "83dd81fe7b67d80573a7d73f60f99b86e0ac586f70f21558d92618f58d2f7e89"
},
"downloads": -1,
"filename": "turbosnake-1.24.434.tar.gz",
"has_sig": false,
"md5_digest": "a70141d016bd6b317729c14573177467",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 30548,
"upload_time": "2023-08-01T08:16:38",
"upload_time_iso_8601": "2023-08-01T08:16:38.252549Z",
"url": "https://files.pythonhosted.org/packages/0f/3c/a1aad1433f264c7e25eb3d881ade120344aa9daadf8b70d78e1e93b6419e/turbosnake-1.24.434.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-08-01 08:16:38",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "AlexeyBond",
"github_project": "turbosnake",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [],
"lcname": "turbosnake"
}