Download app/tars_plataforma/__init__.py from OpenTARS/openTARS: direct link, hf CLI and curl.
- Browser
- Download file 11.3 kB
-
https://huggingface.co/OpenTARS/openTARS/resolve/main/app/tars_plataforma/__init__.py
- Command line
-
hf download hf://OpenTARS/openTARS/app/tars_plataforma/__init__.py
-
curl -L -o __init__.py https://huggingface.co/OpenTARS/openTARS/resolve/main/app/tars_plataforma/__init__.py
11.3 kB
| """openTARS 5.2: a única porta de entrada para o que muda de sistema (Linux, Windows, macOS). | |
| Este arquivo traz a interface e o que não depende do sistema (as pastas); o resto vai para o backend de cada sistema | |
| (`linux.py`, `windows.py`, `macos.py`), escolhido na hora da chamada. No Linux é o código que o app já usava; no Windows e no | |
| macOS só existe o que dá para fazer sem testar na máquina, e o que falta levanta `NaoSuportado` dizendo a fase do | |
| `PLANO_5.2.md` em que entra, para nada falhar em silêncio. Só biblioteca padrão, sem Qt. | |
| O que continua preso ao Linux fora daqui, de propósito, até a fase do sistema: a descoberta de programas pelos `.desktop` | |
| (`nucleo/aplicacoes.py`), as janelas do X (`nucleo/janelas.py`), a acessibilidade AT-SPI (`tars_acessibilidade.py`), o | |
| ydotool do Wayland (`tars_wayland.py`), o atalho global do GNOME (`tars_atalho.py`) e o soquete de instância única em | |
| `XDG_RUNTIME_DIR` (`tars_instancia.py`). | |
| Interface (devolvem o resultado ou levantam `NaoSuportado`/`OSError`): | |
| sistema() "linux" | "windows" | "macos" | |
| pastas() {"casa", "config", "dados", "cache"} (Path) | |
| abrir(alvo) abre arquivo, pasta ou endereço no programa padrão | |
| lixeira(caminho) manda para a lixeira (nunca apaga de vez) | |
| notificar(titulo, texto) notificação do sistema (não espera) | |
| ler_area_de_transferencia() texto copiado | |
| escrever_area_de_transferencia(texto) | |
| arquivo_autostart(nome) onde fica o início automático com a sessão | |
| autostart(nome, titulo, comando, ligado) liga ou desliga o início automático; devolve se ficou ligado | |
| tecla_comando() "ctrl", ou "command" no macOS (colar, copiar, salvar) | |
| ler_selecao() o texto marcado agora em qualquer programa ("" se nada) | |
| teclas_de_colar() as teclas de colar na janela ativa (Ctrl+Shift+V num terminal do Linux) | |
| nome_do_sistema() "Windows 11 23H2", "macOS 15.2 Sequoia" (o Linux lê o /etc/os-release no prompt) | |
| janelas(), janela_ativa(), focar_janela(id), fechar_janela(id), mover_janela(id, x, y, largura, altura, maximizar), | |
| area_util() fora do Linux (no Linux o núcleo fala com o X direto: nucleo/janelas.py) | |
| programas() [{nome, outros_nomes, comando, id}] fora do Linux (no Linux: os .desktop) | |
| recursos() {função: existe neste sistema?} (para o diagnóstico) | |
| arquivos_selecionados() os arquivos do gerenciador de arquivos no momento do atalho (ações em arquivos) | |
| permissoes(), pedir_permissao(qual) só no macOS: {"acessibilidade", "tela"} concedidas?; pedir abre os Ajustes | |
| lancador(nome) o comando instalado (opentars, opentars-gui), no PATH ou em ~/.local/bin | |
| comando_instalar(*pacotes) "sudo dnf install ..." com os nomes desta distribuição (só no Linux) | |
| dica_instalar(texto) troca "sudo apt install x" num texto pelo comando desta distribuição | |
| descrever() sistema, versão, arquitetura, núcleos, RAM e Python (para os relatórios) | |
| """ | |
| import os | |
| import platform | |
| import re | |
| import shutil | |
| import sys | |
| from pathlib import Path | |
| NOME = "opentars" | |
| class NaoSuportado(OSError): | |
| """Esta função ainda não existe neste sistema; a mensagem diz em que fase da 5.2 ela entra.""" | |
| def sistema(): | |
| if sys.platform.startswith("win"): | |
| return "windows" | |
| return "macos" if sys.platform == "darwin" else "linux" | |
| def esconder_consoles_dos_filhos(popen=None, tem_console=None): | |
| """Windows sem console (pythonw: a janela e o serviço dos Probes): cada programa de console que o app roda (nvidia-smi, | |
| ollama, powershell) abria uma janela preta por cima, e a janela do app parecia travada. Aqui o padrão vira | |
| CREATE_NO_WINDOW; quem abre um console para a pessoa passa CREATE_NEW_CONSOLE, e aí o Windows ignora o outro.""" | |
| import subprocess | |
| popen = popen or subprocess.Popen | |
| if tem_console is None: | |
| import ctypes | |
| tem_console = bool(ctypes.windll.kernel32.GetConsoleWindow()) | |
| if tem_console or getattr(popen, "_sem_console", False): | |
| return False | |
| original = popen.__init__ | |
| def __init__(self, *a, creationflags=0, **k): | |
| if not creationflags & (0x10 | 0x08): # CREATE_NEW_CONSOLE, DETACHED_PROCESS | |
| creationflags |= 0x08000000 # CREATE_NO_WINDOW | |
| original(self, *a, creationflags=creationflags, **k) | |
| popen.__init__ = __init__ | |
| popen._sem_console = True | |
| return True | |
| def _backend(): | |
| so = sistema() | |
| if so == "windows": | |
| from . import windows as backend | |
| elif so == "macos": | |
| from . import macos as backend | |
| else: | |
| from . import linux as backend | |
| return backend | |
| def pastas(): | |
| casa = Path.home() | |
| so = sistema() | |
| if so == "windows": | |
| roaming = Path(os.environ.get("APPDATA") or casa / "AppData" / "Roaming") | |
| local = Path(os.environ.get("LOCALAPPDATA") or casa / "AppData" / "Local") | |
| return {"casa": casa, "config": roaming / NOME, "dados": local / NOME, "cache": local / NOME / "cache"} | |
| if so == "macos": | |
| base = casa / "Library" | |
| return {"casa": casa, "config": base / "Application Support" / NOME, "dados": base / "Application Support" / NOME, | |
| "cache": base / "Caches" / NOME} | |
| xdg = lambda var, padrao: Path(os.environ.get(var) or casa / padrao) # noqa: E731 | |
| return {"casa": casa, "config": xdg("XDG_CONFIG_HOME", ".config") / NOME, "dados": xdg("XDG_DATA_HOME", ".local/share") / NOME, | |
| "cache": xdg("XDG_CACHE_HOME", ".cache") / NOME} | |
| def abrir(alvo): | |
| return _backend().abrir(alvo) | |
| def arquivos_selecionados(): | |
| """Os arquivos selecionados no gerenciador de arquivos quando o atalho foi apertado (Windows e macOS: da cópia simulada | |
| do ler_selecao; Linux: os que a pessoa copiou com Ctrl+C). [] se não eram arquivos.""" | |
| return _backend().arquivos_selecionados() | |
| def permissoes(): | |
| return _backend().permissoes() if sistema() == "macos" else {} | |
| def pedir_permissao(qual): | |
| return _backend().pedir_permissao(qual) | |
| def lancador(nome): | |
| """O comando instalado (opentars, opentars-gui): no PATH ou em ~/.local/bin, onde os instaladores por usuário o põem | |
| (o Arch e o macOS aberto pelo Finder não têm ~/.local/bin no PATH). None se não houver.""" | |
| local = Path.home() / ".local" / "bin" / nome | |
| return shutil.which(nome) or (str(local) if local.is_file() and os.access(local, os.X_OK) else None) | |
| def comando_instalar(*pacotes): | |
| """Os pacotes vêm com o nome do Debian; volta o comando com os nomes desta distribuição. Fora do Linux, None.""" | |
| return _backend().comando_instalar(*pacotes) if sistema() == "linux" else None | |
| _RE_APT = re.compile(r"sudo apt(?:-get)? install((?: [a-z0-9][\w.+:-]*)+)") | |
| def dica_instalar(texto): | |
| """Troca "sudo apt install x y" num aviso pelo comando desta distribuição (dnf, pacman, zypper), com os nomes de lá.""" | |
| if sistema() != "linux" or (_backend().gerenciador() or "apt") == "apt": | |
| return texto | |
| return _RE_APT.sub(lambda m: comando_instalar(*m.group(1).split()), texto) | |
| def lixeira(caminho): | |
| return _backend().lixeira(caminho) | |
| def notificar(titulo, texto): | |
| return _backend().notificar(titulo, texto) | |
| def ler_area_de_transferencia(): | |
| return _backend().ler_area_de_transferencia() | |
| def escrever_area_de_transferencia(texto): | |
| return _backend().escrever_area_de_transferencia(texto) | |
| def ler_selecao(): | |
| return _backend().ler_selecao() | |
| def teclas_de_colar(): | |
| return _backend().teclas_de_colar() | |
| def arquivo_autostart(nome): | |
| return _backend().arquivo_autostart(nome) | |
| def autostart(nome, titulo, comando, ligado=True): | |
| return _backend().autostart(nome, titulo, comando, ligado) | |
| def nome_do_sistema(): | |
| """O nome que vai no bloco THIS COMPUTER fora do Linux, no formato dos dados da 5.2.""" | |
| so = sistema() | |
| if so == "macos": | |
| versao = platform.mac_ver()[0] | |
| nomes = {"26": "Tahoe", "15": "Sequoia", "14": "Sonoma", "13": "Ventura", "12": "Monterey", "11": "Big Sur"} | |
| return " ".join(x for x in ("macOS", versao, nomes.get(versao.split(".")[0], "")) if x) | |
| if so == "windows": | |
| return " ".join(x for x in ("Windows", platform.release(), _versao_windows()) if x) | |
| return "Linux" | |
| def _versao_windows(): | |
| """23H2, 24H2...: só o registro sabe (o platform dá o número do build).""" | |
| try: | |
| import winreg | |
| with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Windows NT\CurrentVersion") as chave: | |
| return winreg.QueryValueEx(chave, "DisplayVersion")[0] | |
| except (ImportError, OSError): | |
| return "" | |
| def janelas(): | |
| return _backend().janelas() | |
| def janela_ativa(): | |
| return _backend().janela_ativa() | |
| def focar_janela(id_janela): | |
| return _backend().focar_janela(id_janela) | |
| def fechar_janela(id_janela): | |
| return _backend().fechar_janela(id_janela) | |
| def mover_janela(id_janela, x=None, y=None, largura=None, altura=None, maximizar=None): | |
| return _backend().mover_janela(id_janela, x, y, largura, altura, maximizar) | |
| def area_util(): | |
| return _backend().area_util() | |
| def programas(): | |
| return _backend().programas() | |
| def tecla_comando(): | |
| return "command" if sistema() == "macos" else "ctrl" | |
| FUNCOES = ("abrir", "lixeira", "notificar", "ler_area_de_transferencia", "escrever_area_de_transferencia", "autostart", | |
| "ler_selecao", "teclas_de_colar") | |
| FUNCOES_FORA_DO_LINUX = ("janelas", "programas") # no Linux o núcleo usa o X e os .desktop | |
| def recursos(): | |
| backend = _backend() | |
| funcoes = FUNCOES + (FUNCOES_FORA_DO_LINUX if sistema() != "linux" else ()) | |
| return {funcao: funcao in vars(backend) for funcao in funcoes} | |
| def descrever(): | |
| so = sistema() | |
| versao = (platform.mac_ver()[0] if so == "macos" else " ".join(x for x in platform.win32_ver()[:2] if x) if so == "windows" | |
| else platform.release()) | |
| try: | |
| import psutil | |
| ram = round(psutil.virtual_memory().total / 1024 ** 3, 1) | |
| except (ImportError, OSError, AttributeError): # AttributeError: psutil de mentira nos testes | |
| ram = None | |
| return {"sistema": so, "versao": versao, "plataforma": platform.platform(), "arquitetura": platform.machine(), | |
| "processador": platform.processor() or None, "nucleos": os.cpu_count(), "ram_gb": ram, | |
| "python": platform.python_version()} | |
| def janelas_prontas(): | |
| """Dá para listar as janelas agora sem esperar? No macOS o Quartz carrega em segundo plano na abertura (leva segundos); | |
| até lá, o contexto do pedido segue sem a lista de janelas. Nos outros sistemas, sempre.""" | |
| return sistema() != "macos" or _backend().frameworks_prontos() | |
| if sistema() == "windows": | |
| esconder_consoles_dos_filhos() | |
| elif sistema() == "macos": | |
| _backend() # começa a carregar o Quartz em segundo plano (macos.py) | |