# htagUI
This is a (basic) UI toolkit for [htag](https://github.com/manatlan/htag) apps. Contrario to [htbulma](https://github.com/manatlan/htbulma), this one is a minimal toolkit, providing only useful and solid widgets, and will be maintained (you can use it ;-)).
<img src="https://manatlan.github.io/htag/htag.png" width="100" height="100">
[![Test](https://github.com/manatlan/htagui/actions/workflows/on_commit_do_all_unittests.yml/badge.svg)](https://github.com/manatlan/htagui/actions/workflows/on_commit_do_all_unittests.yml)
<a href="https://pypi.org/project/htagui/">
<img src="https://badge.fury.io/py/htagui.svg?x" alt="Package version">
</a>
**roadmap**
- provide a darker theme css
- test test & test, to be rock solid
- be available in htag4brython too, with the same apis.
- perhaps provide version using "shoelace web components", or "simple bulma styles" (like htbulma) ... but the basics version (current one) will always be available, with its minimal footprint (js/css dependancies in mind)
**INSTALL**
```bash
python3 -m pip install -U htagui
```
**note**: it will install htag and htagui, and provide the `ui` in the htag namespace (`htag.ui`)
A hello world could be :
```python
from htag import Tag, Runner, ui
class MyApp(ui.App):
def init(self):
self <= ui.Button("test", _onclick=lambda ev: self.ui.alert( "hello world" ) )
if __name__ == "__main__":
Runner(MyApp).run()
```
It provides some (ready-to-use) Htag Objects, and some utilities methods.
## Object App
This is a surcharge of Tag.body( ... ) which auto provide an `ui` property on the instance, to interact with `Dialog` features
In place of:
```python
class MyApp(Tag.body):
def init(self):
self.ui = ui.Dialog(self) # <- it will do that, automatically
self <= ui.Button("test", _onclick=lambda ev: self.ui.alert( "hello" ) )
```
you can do :
```python
class MyApp(ui.App):
def init(self):
self <= ui.Button("test", _onclick=lambda ev: self.ui.alert( "hello" ) )
```
## Object Button
A simple surcharge of Tag.button(...), to define a css class
```python
import htagui as ui
self <= ui.Button("my button",_class="myclass", _onclick = myevent )
```
## Object Input
A simple surcharge of Tag.input(...), to define a css class
```python
import htagui as ui
self <= ui.Input(_value="my value", _name="myfield", _class="myclass", _required=True )
```
Availables managed `type`s (setted with `_type`) params:
* `text` : the default one (if omitted): an input text
* `checkbox` : a checkbox
* `radio` : a radio button (non sense : use ui.Radios or uiIRadios !)
* `range` : a slider/range
For `text`: a special field "_label" will set the html "placeholder" attribut.
## Object Textarea
A simple surcharge of Tag.textarea(...), to define a css class
```python
import htagui as ui
self <= ui.Textarea("my value", _name="myfield", _class="myclass", _required=True )
```
A special field "_label" will set the html "placeholder" attribut.
## Object Spinner
A spinner object.
```python
import htagui as ui
self <= ui.Spinner()
```
## Objets "I-fields"
Theses are interactive/reactive fields, which are automatically synced between client and server side, thru a 'value' property
- IText .. an input of type text
- ITextarea ... a textarea
- IBool ... an input of type checkbox
- IRange ... an input of type range
- ISelect ... a multichoice select/option
- IRadios ... a multichoice radio buttons
## Object Select
An htag class to help to create "select/option" html tags, using a dict of {value:title, ...}.
```python
import htagui as ui
self <= ui.Select( dict(a="A",b="B"), _value="a", _name="myfield" )
```
## Object Radios
An htag class to help to create "radio button choices" html tags, using a dict of {value:title, ...}.
```python
import htagui as ui
self <= ui.Radios( dict(a="A",b="B"), _value="a", _name="myfield" )
```
## Object Menu
An htag class to help to create a (first-level) menu and menu items, using a dict of {title:callback,...}
```python
import htagui as ui
ux = ui.Dialog(self)
entries={
"menu1": lambda: ux.notify("menu1"),
"menu2": lambda: ux.notify("menu2"),
"menu3": lambda: ux.notify("menu3"),
}
self <= ui.Menu( entries )
```
## Object Form
A simple surcharge of Tag.form(...) where you can define a callback to call a method wich will receive a python "dict" of all named inputs defined in the form.
```python
import htagui as ui
ux = ui.Dialog( self )
form = ui.Form( onsubmit=lambda dico: ux.notify(str(dico)) )
form <= ui.Input(_name="mystring",_placeholder="input something")
form <= ui.Button("ok")
self <= form
```
## Object FileUpload
A simple surcharge of Tag.input( _type='file'...) which call a method to upload the selected file.
```python
import htagui as ui
def uploaded(name:str, content:bytes):
print(name,content)
self <= ui.FileUpload( uploaded , _multiple=True)
```
## Object Tabs
An htag class to easily create tabs structure. And provides somes attributs/methods to interact with it.
```python
import htagui as ui
tab1 = Tag.div("content1",name="tab1") # tab object needs a `name` property !
tab2 = Tag.div("content2",name="tab2")
t = ui.Tabs( tab1, tab2 )
self += t
```
### method t.add_tab( obj )
A method to add dynamically a tab instance, which is automatically selected.
(note that the tab object needs a `name` property !)
### property t.selected
Dynamic property to retrieve or select the current selected tab.
### event "onchange"
Event which is called when selected index changes.
## Object Dialog
Expose "Dialog boxes" with methods on the instance.
Note that, there can be only one dialog at a time (except toast notification)
```python
import htagui as ui
dialog = ui.Dialog( self )
```
### method dialog.alert(obj, size:float=None)
(like js window.alert(...)) Display a modal dialog box containing the object 'obj' (obj must be str'able)
size is a float to force the percent of width on the dialog box. If None, it will use the default from the ui used.
### method dialog.confirm(obj, cbresponse=lambda bool)
(like js window.confirm(...)) Display a modal dialog box containing the object 'obj' (obj must be str'able), and let the user click on Yes|No buttons, which will call the cbresponse callback with True or False ...
### method dialog.prompt(title, value=None, cbresponse=lambda val)
(like js window.prompt(...)) Display a modal dialog letting the user edit the `value` in an Input box, with a `title` (title must be str'able). When the user click the OK button the value is sent in the callback cbresponse. (clicking the cancel button does nothing, except close the dialog)
### method dialog.notify(obj, time=2000)
Display a toast message (notification), in the right-bottom ... during 2000 ms.
(currently toast messages are not stacked)
### method dialog.pop(obj, xy:tuple)
Display an object, at coords (x,y).
ex "create a popmenu", using "Menu object"
```python
import htagui as ui
dialog = ui.Dialog(self)
entries={
"menu1": lambda: dialog.notify("menu1"),
"menu2": lambda: dialog.notify("menu2"),
"menu3": lambda: dialog.notify("menu3"),
}
self <= ui.Button("pop menu", _onclick=lambda ev: dialog.pop( ui.Menu(entries) ,(ev.clientX,ev.clientY)) )
```
note: it ensures that the object is fully visible in the inner window.
### method dialog.drawer(obj, mode="left")
Display a drawer, in the left-side. mode can be left,right,top,bottom.
### method dialog.page(obj=None)
Display a full page 'obj', or remove page if obj is None. (note that ui.close() does not close the page)
### method dialog.block(obj=None)
Display a modal dialog box containing the object 'obj'. But the dialog is not closable, so be sure to provide a way to close it.
### method dialog.close()
Close programatically, the current ui dialog.
### method dialog.clipboard_copy(txt:str)
Copy the txt in the clipboard
### method dialog.clipboard_paste( lambda content )
Call the callback with the text content from the clipboard. (user may need to authorize the interaction from the navigator)
### method dialog.download( name:str, content:bytes ):
Force the navigator to download a file named 'name', with the content bytes 'content' into the browser.
## Object HSplit & VSplit
A Tag object to use "SplitJS"
```python
import htagui as ui
split = ui.HSplit( Tag.div(1), Tag.div(2), sizes=[60,40], minSize=100, _style="border:2px solid red;height:100px" )
self <= split
```
methods:
split.setSizes( [50,50] )
split.onchange = lambda object: print( object.sizes ) # event
## Object Sortable
A component to let the user reorder items using drag'n'drop.
```python
ll=[Tag.div(f"Item {i} (drag me)",value=i) for i in range(10)]
def onchange(o:ui.Sortable):
print( str([i.value for i in o.values]) )
self <= ui.Sortable(ll,onchange=onchange)
```
## Object VScroll
A component to help you to create an infinite scroller.
```python
def feed():
yield [Tag.div(i) for i in range(20) ]
self <= Tag.div(_style="height:200px; border:1px solid red;" ) <= ui.VScroll( feed )
```
This component should be embbeded in an element which have a constraint on its height. The given callback should yield Tag(s) (or `None` to finnish the endless scroll)
## Object VScrollPager
A component (which inherit from VScroll) to present a finnished list of items in an "on-demand" way (create items on-demand), can contain a big amount of data.
```python
ll=[lambda i=i: MyObject(i) for i in range(1,200_000_000)]
self <= Tag.div(_style="height:200px; border:1px solid red;" ) <= ui.VScrollPager(ll,preload=50,moreload=10,endzone=50)
```
This component should be embbeded in an element which have a constraint on its height. `preload` is the number of items which will be created (it should overflow on height). `moreload` is the number of items which will be loaded when scrolling is in the `endzone` pixels at the end.
Note that the list is a list of lambda (`List[Callable[[], Tag]]`) to create the rendering on-demand.
## Object View
A view component which handle the browser navigation mechanism (go back)
**IMPORTANT**:
- this component is here for tests only (it may disappear if real problems)
- FOR POWER USERS : may be used as first class, and you need to understand how htag works, and how the browser history works ! (if the object is deleted -> nothing work)
TODO: make a better good example !
```python
default_view=Tag.div("Default view")
v = ui.View( default_view, _style="border:1px solid red;width:100%;height:400px" )
self <= ui.Button("p1", _onclick = lambda ev: v.go( Tag.div("p1") ))
self <= ui.Button("p2", _onclick = lambda ev: v.go( Tag.div("p2") ))
self <= v
```
## Object Grid
signature : Grid(format,vformat="auto",gap="1px",**a)
A simple grid container
example:
```python
g = Grid("1fr 1fr 2fr")
g <= Tag.div( "2colums",_style="grid-column:1 / 3")
g <= Tag.div( "1column")
```
## utilities methods
### hflex & vflex
Methods to create an HBox or VBox htag class (flexbox horizontal or vertical, with nowrap mode)
```python
import htagui as ui
HBox = ui.hflex(50, 50) # create a hbox of 2 elements of 50% each
self <= HBox( Tag.div(1), Tag.div(2) )
```
Raw data
{
"_id": null,
"home_page": "https://github.com/manatlan/htagui",
"name": "htagui",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.7",
"maintainer_email": null,
"keywords": "htag, gui, electron, cef, asyncio, guy, desktop, web, mobile, http, websocket, html, pyscript",
"author": "manatlan",
"author_email": "manatlan@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/bb/ca/88791f7111aed52b95fa54e32ecad8c8b8bf8c6164d61238ece72fc07b18/htagui-0.6.5.tar.gz",
"platform": null,
"description": "# htagUI\n\nThis is a (basic) UI toolkit for [htag](https://github.com/manatlan/htag) apps. Contrario to [htbulma](https://github.com/manatlan/htbulma), this one is a minimal toolkit, providing only useful and solid widgets, and will be maintained (you can use it ;-)).\n\n<img src=\"https://manatlan.github.io/htag/htag.png\" width=\"100\" height=\"100\">\n\n[![Test](https://github.com/manatlan/htagui/actions/workflows/on_commit_do_all_unittests.yml/badge.svg)](https://github.com/manatlan/htagui/actions/workflows/on_commit_do_all_unittests.yml)\n\n<a href=\"https://pypi.org/project/htagui/\">\n <img src=\"https://badge.fury.io/py/htagui.svg?x\" alt=\"Package version\">\n</a>\n\n**roadmap**\n\n - provide a darker theme css\n - test test & test, to be rock solid\n - be available in htag4brython too, with the same apis.\n - perhaps provide version using \"shoelace web components\", or \"simple bulma styles\" (like htbulma) ... but the basics version (current one) will always be available, with its minimal footprint (js/css dependancies in mind)\n\n\n**INSTALL**\n```bash\npython3 -m pip install -U htagui\n```\n**note**: it will install htag and htagui, and provide the `ui` in the htag namespace (`htag.ui`)\n\nA hello world could be :\n\n```python\nfrom htag import Tag, Runner, ui\n\nclass MyApp(ui.App):\n def init(self):\n self <= ui.Button(\"test\", _onclick=lambda ev: self.ui.alert( \"hello world\" ) )\n\nif __name__ == \"__main__\":\n Runner(MyApp).run()\n```\n\n\n\nIt provides some (ready-to-use) Htag Objects, and some utilities methods.\n\n\n## Object App\n\nThis is a surcharge of Tag.body( ... ) which auto provide an `ui` property on the instance, to interact with `Dialog` features\n\nIn place of:\n```python\nclass MyApp(Tag.body):\n def init(self):\n self.ui = ui.Dialog(self) # <- it will do that, automatically\n self <= ui.Button(\"test\", _onclick=lambda ev: self.ui.alert( \"hello\" ) )\n```\n\nyou can do :\n```python\nclass MyApp(ui.App):\n def init(self):\n self <= ui.Button(\"test\", _onclick=lambda ev: self.ui.alert( \"hello\" ) )\n```\n\n## Object Button\n\nA simple surcharge of Tag.button(...), to define a css class \n\n```python\nimport htagui as ui\nself <= ui.Button(\"my button\",_class=\"myclass\", _onclick = myevent )\n```\n\n## Object Input\n\nA simple surcharge of Tag.input(...), to define a css class \n\n\n```python\nimport htagui as ui\nself <= ui.Input(_value=\"my value\", _name=\"myfield\", _class=\"myclass\", _required=True )\n```\n\nAvailables managed `type`s (setted with `_type`) params:\n * `text` : the default one (if omitted): an input text\n * `checkbox` : a checkbox\n * `radio` : a radio button (non sense : use ui.Radios or uiIRadios !)\n * `range` : a slider/range\n\nFor `text`: a special field \"_label\" will set the html \"placeholder\" attribut.\n\n## Object Textarea\n\nA simple surcharge of Tag.textarea(...), to define a css class \n\n\n```python\nimport htagui as ui\nself <= ui.Textarea(\"my value\", _name=\"myfield\", _class=\"myclass\", _required=True )\n```\n\nA special field \"_label\" will set the html \"placeholder\" attribut.\n\n## Object Spinner\n\nA spinner object.\n\n```python\nimport htagui as ui\nself <= ui.Spinner()\n```\n\n## Objets \"I-fields\"\n\nTheses are interactive/reactive fields, which are automatically synced between client and server side, thru a 'value' property\n\n- IText .. an input of type text\n- ITextarea ... a textarea \n- IBool ... an input of type checkbox\n- IRange ... an input of type range\n- ISelect ... a multichoice select/option\n- IRadios ... a multichoice radio buttons\n\n## Object Select\n\nAn htag class to help to create \"select/option\" html tags, using a dict of {value:title, ...}.\n\n```python\nimport htagui as ui\nself <= ui.Select( dict(a=\"A\",b=\"B\"), _value=\"a\", _name=\"myfield\" )\n```\n\n## Object Radios\n\nAn htag class to help to create \"radio button choices\" html tags, using a dict of {value:title, ...}.\n\n```python\nimport htagui as ui\nself <= ui.Radios( dict(a=\"A\",b=\"B\"), _value=\"a\", _name=\"myfield\" )\n```\n\n## Object Menu\n\nAn htag class to help to create a (first-level) menu and menu items, using a dict of {title:callback,...}\n\n```python\nimport htagui as ui\nux = ui.Dialog(self)\nentries={\n \"menu1\": lambda: ux.notify(\"menu1\"),\n \"menu2\": lambda: ux.notify(\"menu2\"),\n \"menu3\": lambda: ux.notify(\"menu3\"),\n} \nself <= ui.Menu( entries )\n```\n\n\n## Object Form\n\nA simple surcharge of Tag.form(...) where you can define a callback to call a method wich will receive a python \"dict\" of all named inputs defined in the form.\n\n```python\nimport htagui as ui\nux = ui.Dialog( self )\nform = ui.Form( onsubmit=lambda dico: ux.notify(str(dico)) )\nform <= ui.Input(_name=\"mystring\",_placeholder=\"input something\")\nform <= ui.Button(\"ok\")\nself <= form\n```\n\n## Object FileUpload\n\nA simple surcharge of Tag.input( _type='file'...) which call a method to upload the selected file.\n\n```python\nimport htagui as ui\n\ndef uploaded(name:str, content:bytes):\n print(name,content)\n\nself <= ui.FileUpload( uploaded , _multiple=True)\n```\n\n## Object Tabs\n\nAn htag class to easily create tabs structure. And provides somes attributs/methods to interact with it.\n\n```python\nimport htagui as ui\ntab1 = Tag.div(\"content1\",name=\"tab1\") # tab object needs a `name` property !\ntab2 = Tag.div(\"content2\",name=\"tab2\")\nt = ui.Tabs( tab1, tab2 )\nself += t\n```\n\n### method t.add_tab( obj )\n\nA method to add dynamically a tab instance, which is automatically selected.\n(note that the tab object needs a `name` property !)\n\n### property t.selected\n\nDynamic property to retrieve or select the current selected tab.\n\n### event \"onchange\"\n\nEvent which is called when selected index changes.\n\n## Object Dialog\n\nExpose \"Dialog boxes\" with methods on the instance.\nNote that, there can be only one dialog at a time (except toast notification)\n\n```python\nimport htagui as ui\ndialog = ui.Dialog( self )\n```\n\n### method dialog.alert(obj, size:float=None)\n\n(like js window.alert(...)) Display a modal dialog box containing the object 'obj' (obj must be str'able)\n\nsize is a float to force the percent of width on the dialog box. If None, it will use the default from the ui used.\n\n### method dialog.confirm(obj, cbresponse=lambda bool)\n\n(like js window.confirm(...)) Display a modal dialog box containing the object 'obj' (obj must be str'able), and let the user click on Yes|No buttons, which will call the cbresponse callback with True or False ...\n\n### method dialog.prompt(title, value=None, cbresponse=lambda val)\n\n(like js window.prompt(...)) Display a modal dialog letting the user edit the `value` in an Input box, with a `title` (title must be str'able). When the user click the OK button the value is sent in the callback cbresponse. (clicking the cancel button does nothing, except close the dialog)\n\n\n\n### method dialog.notify(obj, time=2000)\n\nDisplay a toast message (notification), in the right-bottom ... during 2000 ms.\n(currently toast messages are not stacked)\n\n### method dialog.pop(obj, xy:tuple)\n\nDisplay an object, at coords (x,y).\n\nex \"create a popmenu\", using \"Menu object\"\n```python\nimport htagui as ui\ndialog = ui.Dialog(self)\nentries={\n \"menu1\": lambda: dialog.notify(\"menu1\"),\n \"menu2\": lambda: dialog.notify(\"menu2\"),\n \"menu3\": lambda: dialog.notify(\"menu3\"),\n} \nself <= ui.Button(\"pop menu\", _onclick=lambda ev: dialog.pop( ui.Menu(entries) ,(ev.clientX,ev.clientY)) )\n```\nnote: it ensures that the object is fully visible in the inner window.\n\n### method dialog.drawer(obj, mode=\"left\")\n\nDisplay a drawer, in the left-side. mode can be left,right,top,bottom.\n\n### method dialog.page(obj=None)\n\nDisplay a full page 'obj', or remove page if obj is None. (note that ui.close() does not close the page) \n\n### method dialog.block(obj=None)\n\nDisplay a modal dialog box containing the object 'obj'. But the dialog is not closable, so be sure to provide a way to close it.\n\n### method dialog.close()\n\nClose programatically, the current ui dialog.\n\n### method dialog.clipboard_copy(txt:str)\n\nCopy the txt in the clipboard\n\n### method dialog.clipboard_paste( lambda content )\n\nCall the callback with the text content from the clipboard. (user may need to authorize the interaction from the navigator)\n\n### method dialog.download( name:str, content:bytes ):\n\nForce the navigator to download a file named 'name', with the content bytes 'content' into the browser.\n\n## Object HSplit & VSplit\n\nA Tag object to use \"SplitJS\"\n\n```python\nimport htagui as ui\nsplit = ui.HSplit( Tag.div(1), Tag.div(2), sizes=[60,40], minSize=100, _style=\"border:2px solid red;height:100px\" )\nself <= split\n```\n\nmethods:\nsplit.setSizes( [50,50] )\nsplit.onchange = lambda object: print( object.sizes ) # event\n\n\n## Object Sortable\n\nA component to let the user reorder items using drag'n'drop.\n\n```python\nll=[Tag.div(f\"Item {i} (drag me)\",value=i) for i in range(10)]\n \ndef onchange(o:ui.Sortable):\n print( str([i.value for i in o.values]) )\n\nself <= ui.Sortable(ll,onchange=onchange)\n```\n\n## Object VScroll\n\nA component to help you to create an infinite scroller.\n\n```python\ndef feed():\n yield [Tag.div(i) for i in range(20) ]\n\nself <= Tag.div(_style=\"height:200px; border:1px solid red;\" ) <= ui.VScroll( feed )\n```\n\nThis component should be embbeded in an element which have a constraint on its height. The given callback should yield Tag(s) (or `None` to finnish the endless scroll)\n\n## Object VScrollPager\n\nA component (which inherit from VScroll) to present a finnished list of items in an \"on-demand\" way (create items on-demand), can contain a big amount of data.\n\n```python\n\nll=[lambda i=i: MyObject(i) for i in range(1,200_000_000)]\nself <= Tag.div(_style=\"height:200px; border:1px solid red;\" ) <= ui.VScrollPager(ll,preload=50,moreload=10,endzone=50)\n\n```\nThis component should be embbeded in an element which have a constraint on its height. `preload` is the number of items which will be created (it should overflow on height). `moreload` is the number of items which will be loaded when scrolling is in the `endzone` pixels at the end.\n\nNote that the list is a list of lambda (`List[Callable[[], Tag]]`) to create the rendering on-demand.\n\n\n## Object View\n\nA view component which handle the browser navigation mechanism (go back)\n\n**IMPORTANT**:\n\n - this component is here for tests only (it may disappear if real problems)\n - FOR POWER USERS : may be used as first class, and you need to understand how htag works, and how the browser history works ! (if the object is deleted -> nothing work)\n\nTODO: make a better good example !\n\n```python\n\ndefault_view=Tag.div(\"Default view\")\n\nv = ui.View( default_view, _style=\"border:1px solid red;width:100%;height:400px\" )\n\nself <= ui.Button(\"p1\", _onclick = lambda ev: v.go( Tag.div(\"p1\") ))\nself <= ui.Button(\"p2\", _onclick = lambda ev: v.go( Tag.div(\"p2\") ))\nself <= v\n```\n## Object Grid\n\nsignature : Grid(format,vformat=\"auto\",gap=\"1px\",**a)\n\nA simple grid container\n\nexample:\n```python\n\ng = Grid(\"1fr 1fr 2fr\")\ng <= Tag.div( \"2colums\",_style=\"grid-column:1 / 3\") \ng <= Tag.div( \"1column\") \n\n```\n\n\n## utilities methods\n\n### hflex & vflex\n\nMethods to create an HBox or VBox htag class (flexbox horizontal or vertical, with nowrap mode)\n\n```python\nimport htagui as ui\nHBox = ui.hflex(50, 50) # create a hbox of 2 elements of 50% each\nself <= HBox( Tag.div(1), Tag.div(2) )\n```\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "GUI toolkit for creating beautiful applications for mobile, web, and desktop from a single python3 codebase",
"version": "0.6.5",
"project_urls": {
"Documentation": "https://github.com/manatlan/htagui",
"Homepage": "https://github.com/manatlan/htagui",
"Repository": "https://github.com/manatlan/htagui"
},
"split_keywords": [
"htag",
" gui",
" electron",
" cef",
" asyncio",
" guy",
" desktop",
" web",
" mobile",
" http",
" websocket",
" html",
" pyscript"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "25f474c20d9c194da4e48412519a07808a27f5bb36bfa0d76c0681fa32774d95",
"md5": "dac5de2001126c29ca576b490643f50c",
"sha256": "b6116614697619d63ea17f34cbda6081e58e0f3b7f9d1ac967f1e6c665a1cae0"
},
"downloads": -1,
"filename": "htagui-0.6.5-py3-none-any.whl",
"has_sig": false,
"md5_digest": "dac5de2001126c29ca576b490643f50c",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.7",
"size": 120040,
"upload_time": "2024-09-23T10:07:00",
"upload_time_iso_8601": "2024-09-23T10:07:00.645443Z",
"url": "https://files.pythonhosted.org/packages/25/f4/74c20d9c194da4e48412519a07808a27f5bb36bfa0d76c0681fa32774d95/htagui-0.6.5-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "bbca88791f7111aed52b95fa54e32ecad8c8b8bf8c6164d61238ece72fc07b18",
"md5": "139f3b61b33aa8d9eef537a6dfbdbb8f",
"sha256": "85bb390366fdd5058d0d83c5bd915696a7d938cd59af774bf8b11605c9eb4b92"
},
"downloads": -1,
"filename": "htagui-0.6.5.tar.gz",
"has_sig": false,
"md5_digest": "139f3b61b33aa8d9eef537a6dfbdbb8f",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.7",
"size": 113570,
"upload_time": "2024-09-23T10:07:01",
"upload_time_iso_8601": "2024-09-23T10:07:01.672460Z",
"url": "https://files.pythonhosted.org/packages/bb/ca/88791f7111aed52b95fa54e32ecad8c8b8bf8c6164d61238ece72fc07b18/htagui-0.6.5.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-09-23 10:07:01",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "manatlan",
"github_project": "htagui",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "htagui"
}