AppModern
AppModern é uma biblioteca Python para criar facilmente aplicações de desktop com interfaces web (HTML, CSS, JS), utilizando o poder do pywebview.
Visão Geral
A biblioteca abstrai a complexidade da comunicação entre Python e JavaScript, permitindo que você construa a interface do usuário com componentes Python que são renderizados dinamicamente no frontend.
Instalação
Você pode instalar o AppModern via pip:
pip install appmodern
Como Usar
Toda aplicação possui duas classes principais: App e api.
App Responsável por gerar a interface principal com a janela web.
Api Responsável pela comunicação entre o frontend e o backend Python..
App
O App é o núcleo da aplicação. Ele carrega a janela HTML do PyWebView e gerencia o conteúdo.
from appmodern.app import App
app = App(
title="My Program",
width=800,
height=600,
full_screen=False,
debug=False,
lang='en'
)
# Adiciona filhos extras à tag <head>
app.head.add_children(
# Componentes como folhas de estilo ou scripts externos
)
# Inicializa a aplicação
app.run()
Componentes
A manipulação do DOM é feita através de componentes Python. Os principais são:
Tag (classe genérica para criação de elementos HTML)
ScriptExternal, StyleExternal, Meta, Title, Head, Body
from appmodern.components import Tag
# Classe personalizada baseada em uma <div>
class Div(Tag):
pass
# Estrutura com filhos e atributos
class DivBlock(Tag):
def __init__(self, parent, *children, **kwargs):
"""
parent: seletor CSS para o elemento pai (ex: 'body', '#id', '.class')
children: outros componentes (tags) filhos
kwargs: atributos HTML (id, class_, style, value, etc.)
"""
super().__init__(parent, *children, class_="exemplo", **kwargs)
self.element = 'div' # Corrige o nome da tag HTML
Observação: Por padrão, o nome da tag HTML será o nome da classe. Se necessário, sobrescreva self.element para garantir compatibilidade com o HTML
🧠 API
A Api é a classe responsável pela comunicação entre o backend (Python) e o frontend (JavaScript).
Ela atua com seis funções principais no Python e cinco no JavaScript, sendo elas:
routecallcreatereadupdatedelete
from appmodern import route, call, create, read, update, delete
from appmodern.components import Tag
# Criando componentes personalizados
class P(Tag): pass
class Button(Tag): pass
# Decorador para registrar uma rota que será chamada pelo frontend
# A função 'home' será executada automaticamente ao iniciar a aplicação
@route('home')
def sua_funcao(*args, **kwargs):
# Cria um parágrafo na tag <body>
create(P("body", "Texto"))
# Lê elementos com base em seletores CSS
# Filtros disponíveis: 'text', 'html', 'value', 'style'
read('p', filter=['text', 'html', 'value', 'style'])
# Atualiza o conteúdo de elementos com base em um seletor
update(('p', P('body', "Atualiza aqui")))
# Remove elementos do DOM com base em seletores
delete('p')
# Cria um botão com ação de clique que chama uma função Python
create(Button('body', "Clique", onclick="call('clique')"))
# Rota que será chamada ao clicar no botão
@route('clique')
def uso_do_call(*args, **kwargs):
# call() é uma função de comunicação entre front e back.
# Pode ser usada em ambos os lados para invocar funções.
# Parâmetros:
# call(nome_da_função, lista_de_args, dicionario_de_kwargs)
call('funcao_de_apresentacao', ['arg1', 'arg2'], {"kwarg": 1})
Exemplo pratico
main.py
from appmodern.app import App
import exemples.home
app = App(
title="AppModern Login",
width=800,
height=600,
full_screen=False,
debug=True,
lang='pt-BR'
)
# Roda a aplicação
app.run()
home.py
#Componentes
from appmodern.components import Tag
class Div(Tag): pass
class Button(Tag): pass
class Input(Tag): pass
class Label(Tag): pass
class H1(Tag): pass
class P(Tag): pass
#Tela de login
from appmodern.components import Tag
from appmodern import route, create, read, update, delete, call
from time import sleep
# Componentes personalizados
class Div(Tag):
def __init__(self, parent='body', *children, **kwargs):
style = kwargs.pop("style", "") + """
display: flex;
flex-direction: column;
align-items: center;
background: #ffffff;
padding: 30px;
margin: 10% auto;
width: 300px;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0,0,0,0.2);
font-family: 'Segoe UI', sans-serif;
"""
super().__init__(parent, *children, style=style, **kwargs)
class Label(Tag):
def __init__(self, parent='body', *children, **kwargs):
style = kwargs.pop("style", "") + "margin-top: 12px; width: 100%; color: #444; font-weight: bold;"
super().__init__(parent, *children, style=style, **kwargs)
class Input(Tag):
def __init__(self, parent='body', **kwargs):
style = kwargs.pop("style", "") + """
width: 100%;
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
margin-top: 6px;
"""
super().__init__(parent, style=style, **kwargs)
class Button(Tag):
def __init__(self, parent='body', *children, **kwargs):
style = kwargs.pop("style", "") + """
background-color: #4facfe;
color: white;
border: none;
padding: 12px;
border-radius: 6px;
cursor: pointer;
font-size: 16px;
margin-top: 20px;
width: 100%;
"""
super().__init__(parent, *children, style=style, **kwargs)
class H1(Tag): pass
class H2(Tag): pass
class P(Tag): pass
# Página inicial com formulário de login
@route('home')
def home_page():
create(
Div('body',
H1(None, 'Login'),
Label(None, "Login", Input(None, type="text", id='login')),
Label(None, "Senha", Input(None, type="password", id='password')),
Button(None, "Logar", onclick='call("logar")'),
id='div-login'
)
)
# Função chamada ao clicar em "Logar"
@route('logar')
def logar():
data = read('input', filter=['value'])
login, password = data['data']
if login[0] == 'gustavo' and password[0] == '123':
call('bem-vindo', [login[0], 5])
else:
data = read('p')
if not data['data']:
create(P('#div-login', 'Login ou senha incorretos'))
# Simula tela de carregamento com contagem regressiva
@route('bem-vindo')
def bem_vindo(nome, segs):
if segs == 5:
delete('#div-login')
create(
Div('body',
H1(None, 'Seja Bem-vindo'),
P(None, f'{nome}, o programa ficará pronto em {segs}s'),
id="div-bem-vindo"
)
)
bem_vindo(nome, segs - 1)
elif segs > 0:
sleep(1)
update(('p', P(None, f'{nome}, o programa ficará pronto em {segs}s')))
bem_vindo(nome, segs - 1)
else:
update(('div#div-bem-vindo',
Div(None,
H1(None, "Logado com sucesso"),
P(None, f"{nome}, seja muito bem-vindo ao novo sistema"),
id="div-bem-vindo")
))
create(H2('#div-bem-vindo', "AppModern"))
Licença
Este projeto está licenciado sob a Licença MIT. Veja o arquivo LICENSE para mais detalhes.
Metadata
Release files for appmodern 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| appmodern-0.2.0.tar.gz | 15.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| appmodern-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 30.1 kB
Release files / appmodern-0.2.0.tar.gz
| Download URL | appmodern-0.2.0.tar.gz |
|---|---|
| Size | 15.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3603a1ccf8c026149eed372433f696d262161eebfb33c64c1b5734513a41743f
|
|
BLAKE2b-256 checksum How to use checksums |
d79274ec1ed464d0d675401eb82e04503ef4eee125eed3782ea03445fc43e2f8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.5
|
Release files / appmodern-0.2.0-py3-none-any.whl
| Download URL | appmodern-0.2.0-py3-none-any.whl |
|---|---|
| Size | 14.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5396d063e774c45e03a1e29dfb281b9b50d60b4a765f2e298f814f017f559c74
|
|
BLAKE2b-256 checksum How to use checksums |
f0e323abc980075d702b93af320188dcdbff9784135fac3a0f8c2ee7a11ce9e1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.5
|
Security for appmodern 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.