pytron-kit 0.3.12__py3-none-macosx_11_0_universal2.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pytron/__init__.py +112 -0
- pytron/application.py +562 -0
- pytron/apputils/__init__.py +0 -0
- pytron/apputils/chrome_ipc.py +203 -0
- pytron/apputils/codegen.py +261 -0
- pytron/apputils/config.py +303 -0
- pytron/apputils/deadmansswitch.py +47 -0
- pytron/apputils/extras.py +76 -0
- pytron/apputils/native.py +148 -0
- pytron/apputils/shell.py +73 -0
- pytron/apputils/windows.py +286 -0
- pytron/cli.py +384 -0
- pytron/commands/__init__.py +0 -0
- pytron/commands/android.py +28 -0
- pytron/commands/build.py +26 -0
- pytron/commands/doctor.py +221 -0
- pytron/commands/engine.py +23 -0
- pytron/commands/frontend.py +60 -0
- pytron/commands/harvest.py +112 -0
- pytron/commands/helpers.py +239 -0
- pytron/commands/info.py +50 -0
- pytron/commands/init.py +521 -0
- pytron/commands/install.py +294 -0
- pytron/commands/login.py +130 -0
- pytron/commands/package.py +228 -0
- pytron/commands/plugin.py +442 -0
- pytron/commands/run.py +312 -0
- pytron/commands/scan.py +210 -0
- pytron/commands/show.py +23 -0
- pytron/commands/uninstall.py +150 -0
- pytron/commands/utils.py +42 -0
- pytron/commands/workflow.py +95 -0
- pytron/console.py +133 -0
- pytron/core.py +18 -0
- pytron/dependencies/WebView2Loader.dll +0 -0
- pytron/dependencies/__init__.py +1 -0
- pytron/dependencies/pytron_native.so +0 -0
- pytron/engines/chrome/adapter.py +445 -0
- pytron/engines/chrome/engine.py +576 -0
- pytron/engines/chrome/forge.py +147 -0
- pytron/engines/chrome/shell/package.json +8 -0
- pytron/engines/chrome/shell/preload.js +12 -0
- pytron/engines/chrome/shell/shell.js +534 -0
- pytron/exceptions.py +36 -0
- pytron/inspector.py +201 -0
- pytron/inspector_ui.py +512 -0
- pytron/installer/Installation.nsi +236 -0
- pytron/installer/header.bmp +0 -0
- pytron/installer/pytron.ico +0 -0
- pytron/installer/sidebar.bmp +0 -0
- pytron/llms.md +98 -0
- pytron/manifests/README.md +29 -0
- pytron/manifests/windows-utf8.manifest +44 -0
- pytron/menu.py +128 -0
- pytron/nsis-setup.exe +0 -0
- pytron/pack/__init__.py +0 -0
- pytron/pack/assets.py +131 -0
- pytron/pack/compilers.py +289 -0
- pytron/pack/crystal.py +297 -0
- pytron/pack/graph.py +377 -0
- pytron/pack/inference.py +157 -0
- pytron/pack/installers.py +402 -0
- pytron/pack/introspect.py +357 -0
- pytron/pack/metadata.py +213 -0
- pytron/pack/modules.py +618 -0
- pytron/pack/nuitka.py +108 -0
- pytron/pack/pipeline.py +107 -0
- pytron/pack/pyinstaller.py +176 -0
- pytron/pack/rust_engine.py +273 -0
- pytron/pack/secure.py +309 -0
- pytron/pack/secure_loader/bin/pytron_rust_bootloader +0 -0
- pytron/pack/secure_loader/icon.ico +0 -0
- pytron/pack/utils.py +110 -0
- pytron/pack/virtual_root.py +124 -0
- pytron/platforms/__init__.py +0 -0
- pytron/platforms/android/__init__.py +3 -0
- pytron/platforms/android/android.py +103 -0
- pytron/platforms/android/builder.py +736 -0
- pytron/platforms/android/ops/build.py +79 -0
- pytron/platforms/android/ops/init.py +63 -0
- pytron/platforms/android/ops/run.py +79 -0
- pytron/platforms/android/ops/sync.py +770 -0
- pytron/platforms/android/ops/utils.py +8 -0
- pytron/platforms/android/shell/README.md +30 -0
- pytron/platforms/android/shell/app/build.gradle +64 -0
- pytron/platforms/android/shell/app/src/main/AndroidManifest.xml +29 -0
- pytron/platforms/android/shell/app/src/main/assets/python/main.py +86 -0
- pytron/platforms/android/shell/app/src/main/assets/python/python314.zip +0 -0
- pytron/platforms/android/shell/app/src/main/cpp/CMakeLists.txt +25 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/Python.h +155 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/abstract.h +915 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/audit.h +30 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/bltinmodule.h +14 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/boolobject.h +54 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/bytearrayobject.h +44 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/bytesobject.h +66 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/ceval.h +145 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/codecs.h +176 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/compile.h +22 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/complexobject.h +30 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/abstract.h +104 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/audit.h +8 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/bytearrayobject.h +38 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/bytesobject.h +42 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/cellobject.h +50 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/ceval.h +43 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/classobject.h +71 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/code.h +340 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/compile.h +50 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/complexobject.h +33 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/context.h +107 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/critical_section.h +154 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/descrobject.h +62 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/dictobject.h +105 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/fileobject.h +16 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/fileutils.h +16 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/floatobject.h +27 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/frameobject.h +35 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/funcobject.h +185 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/genobject.h +56 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/import.h +30 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/initconfig.h +334 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/listobject.h +53 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/lock.h +74 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/longintrepr.h +184 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/longobject.h +89 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/memoryobject.h +50 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/methodobject.h +66 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/modsupport.h +26 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/monitoring.h +269 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/object.h +493 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/objimpl.h +104 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/odictobject.h +43 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/picklebufobject.h +31 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pthread_stubs.h +105 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pyatomic.h +614 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pyatomic_gcc.h +615 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pyatomic_msc.h +1197 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pyatomic_std.h +1112 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pyctype.h +39 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pydebug.h +38 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pyerrors.h +132 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pyfpe.h +15 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pyframe.h +45 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pyhash.h +54 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pylifecycle.h +89 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pymem.h +84 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pystate.h +275 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pystats.h +194 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pythonrun.h +96 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pythread.h +43 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pytime.h +27 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/setobject.h +71 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/traceback.h +13 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/tracemalloc.h +32 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/tupleobject.h +40 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/unicodeobject.h +773 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/warnings.h +20 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/weakrefobject.h +66 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/critical_section.h +16 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/datetime.h +267 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/descrobject.h +100 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/dictobject.h +108 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/dynamic_annotations.h +499 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/enumobject.h +17 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/errcode.h +45 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/exports.h +105 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/fileobject.h +41 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/fileutils.h +62 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/floatobject.h +54 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/frameobject.h +20 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/genericaliasobject.h +14 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/import.h +103 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/mimalloc/mimalloc/atomic.h +392 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/mimalloc/mimalloc/internal.h +969 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/mimalloc/mimalloc/prim.h +329 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/mimalloc/mimalloc/track.h +147 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/mimalloc/mimalloc/types.h +721 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/mimalloc/mimalloc.h +565 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_abstract.h +61 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_asdl.h +112 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_ast.h +945 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_ast_state.h +271 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_atexit.h +31 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_audit.h +35 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_backoff.h +133 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_bitutils.h +186 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_blocks_output_buffer.h +321 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_brc.h +73 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_bytes_methods.h +82 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_bytesobject.h +149 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_c_array.h +39 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_call.h +206 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_capsule.h +17 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_cell.h +75 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_ceval.h +390 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_ceval_state.h +48 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_code.h +671 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_codecs.h +76 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_compile.h +230 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_complexobject.h +34 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_condvar.h +93 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_context.h +59 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_critical_section.h +237 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_crossinterp.h +406 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_crossinterp_data_registry.h +41 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_debug_offsets.h +379 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_descrobject.h +28 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_dict.h +410 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_dict_state.h +28 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_dtoa.h +40 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_emscripten_signal.h +30 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_emscripten_trampoline.h +70 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_exceptions.h +40 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_faulthandler.h +100 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_fileutils.h +320 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_fileutils_windows.h +98 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_floatobject.h +49 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_flowgraph.h +47 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_format.h +27 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_frame.h +61 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_freelist.h +111 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_freelist_state.h +70 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_function.h +53 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_gc.h +378 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_genobject.h +43 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_getopt.h +22 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_gil.h +66 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_global_objects.h +34 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_global_objects_fini_generated.h +1592 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_global_strings.h +854 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_hamt.h +113 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_hashtable.h +150 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_import.h +141 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_importdl.h +139 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_index_pool.h +36 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_initconfig.h +197 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_instruction_sequence.h +83 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_instruments.h +127 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_interp.h +109 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_interp_structs.h +977 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_interpframe.h +401 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_interpframe_structs.h +95 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_interpolation.h +26 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_intrinsics.h +51 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_jit.h +29 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_list.h +81 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_llist.h +106 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_lock.h +236 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_long.h +319 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_magic_number.h +305 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_memoryobject.h +20 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_mimalloc.h +69 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_modsupport.h +99 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_moduleobject.h +62 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_namespace.h +21 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_object.h +1029 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_object_alloc.h +71 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_object_deferred.h +32 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_object_stack.h +95 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_object_state.h +49 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_obmalloc.h +702 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_obmalloc_init.h +66 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_opcode_metadata.h +2117 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_opcode_utils.h +90 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_optimizer.h +318 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_parking_lot.h +97 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_parser.h +78 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pathconfig.h +26 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pyarena.h +68 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pyatomic_ft_wrappers.h +174 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pybuffer.h +21 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pyerrors.h +213 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pyhash.h +91 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pylifecycle.h +136 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pymath.h +205 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pymem.h +145 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pymem_init.h +103 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pystate.h +339 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pystats.h +21 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pythonrun.h +68 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pythread.h +172 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_qsbr.h +172 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_range.h +21 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_runtime.h +63 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_runtime_init.h +239 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_runtime_init_generated.h +1589 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_runtime_structs.h +310 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_semaphore.h +67 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_setobject.h +41 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_signal.h +108 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_sliceobject.h +20 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_stackref.h +791 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_stats.h +97 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_strhex.h +39 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_structs.h +88 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_structseq.h +40 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_symtable.h +201 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_sysmodule.h +32 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_template.h +26 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_time.h +334 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_token.h +110 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_traceback.h +111 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_tracemalloc.h +164 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_tstate.h +88 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_tuple.h +75 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_typedefs.h +18 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_typeobject.h +155 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_typevarobject.h +28 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_ucnhash.h +36 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_unicodeobject.h +308 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_unicodeobject_generated.h +3132 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_unionobject.h +26 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_uniqueid.h +57 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_uop_ids.h +335 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_uop_metadata.h +1204 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_warnings.h +21 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_weakref.h +133 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/intrcheck.h +23 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/iterobject.h +24 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/listobject.h +55 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/lock.h +16 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/longobject.h +178 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/marshal.h +31 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/memoryobject.h +34 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/methodobject.h +146 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/modsupport.h +146 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/moduleobject.h +122 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/monitoring.h +18 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/object.h +828 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/objimpl.h +211 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/opcode.h +43 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/opcode_ids.h +259 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/osdefs.h +57 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/osmodule.h +17 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/patchlevel.h +49 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/py_curses.h +117 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pyatomic.h +16 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pybuffer.h +145 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pycapsule.h +58 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pyconfig.h +2088 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pydtrace.h +59 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pyerrors.h +335 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pyexpat.h +62 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pyframe.h +26 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pyhash.h +59 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pylifecycle.h +80 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pymacconfig.h +91 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pymacro.h +243 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pymath.h +65 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pymem.h +110 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pyport.h +710 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pystate.h +132 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pystats.h +28 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pystrcmp.h +23 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pystrtod.h +37 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pythonrun.h +42 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pythread.h +131 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pytypedefs.h +30 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/rangeobject.h +27 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/refcount.h +555 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/setobject.h +49 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/sliceobject.h +69 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/structmember.h +56 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/structseq.h +46 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/sysmodule.h +27 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/traceback.h +26 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/tupleobject.h +46 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/typeslots.h +96 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/unicodeobject.h +1029 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/warnings.h +45 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/weakrefobject.h +46 -0
- pytron/platforms/android/shell/app/src/main/cpp/pytron_bridge.cpp +224 -0
- pytron/platforms/android/shell/app/src/main/java/com/pytron/shell/MainActivity.kt +208 -0
- pytron/platforms/android/shell/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- pytron/platforms/android/shell/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- pytron/platforms/android/shell/build.gradle +11 -0
- pytron/platforms/android/shell/gradle/wrapper/gradle-wrapper.jar +0 -0
- pytron/platforms/android/shell/gradle/wrapper/gradle-wrapper.properties +5 -0
- pytron/platforms/android/shell/gradle.properties +2 -0
- pytron/platforms/android/shell/gradlew.bat +85 -0
- pytron/platforms/android/shell/settings.gradle +16 -0
- pytron/platforms/darwin.py +82 -0
- pytron/platforms/darwin_ops/libs.py +31 -0
- pytron/platforms/darwin_ops/system.py +182 -0
- pytron/platforms/darwin_ops/utils.py +85 -0
- pytron/platforms/darwin_ops/webview.py +5 -0
- pytron/platforms/darwin_ops/window.py +102 -0
- pytron/platforms/interface.py +152 -0
- pytron/platforms/linux.py +82 -0
- pytron/platforms/linux_ops/libs.py +49 -0
- pytron/platforms/linux_ops/system.py +316 -0
- pytron/platforms/linux_ops/utils.py +19 -0
- pytron/platforms/linux_ops/webview.py +5 -0
- pytron/platforms/linux_ops/window.py +115 -0
- pytron/platforms/windows.py +136 -0
- pytron/platforms/windows_ops/__init__.py +0 -0
- pytron/platforms/windows_ops/constants.py +126 -0
- pytron/platforms/windows_ops/system.py +518 -0
- pytron/platforms/windows_ops/utils.py +3 -0
- pytron/platforms/windows_ops/webview.py +5 -0
- pytron/platforms/windows_ops/window.py +361 -0
- pytron/plugin.py +467 -0
- pytron/rcedit-x64.exe +0 -0
- pytron/router.py +146 -0
- pytron/serializer.py +240 -0
- pytron/shortcuts.py +279 -0
- pytron/state.py +76 -0
- pytron/tray.py +399 -0
- pytron/updater.py +181 -0
- pytron/utf8_hook.py +112 -0
- pytron/utils.py +44 -0
- pytron/webview.py +722 -0
- pytron_kit-0.3.12.dist-info/METADATA +131 -0
- pytron_kit-0.3.12.dist-info/RECORD +419 -0
- pytron_kit-0.3.12.dist-info/WHEEL +5 -0
- pytron_kit-0.3.12.dist-info/entry_points.txt +2 -0
- pytron_kit-0.3.12.dist-info/licenses/LICENSE +201 -0
- pytron_kit-0.3.12.dist-info/top_level.txt +1 -0
pytron/serializer.py
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import base64
|
|
3
|
+
import io
|
|
4
|
+
import datetime
|
|
5
|
+
import uuid
|
|
6
|
+
import decimal
|
|
7
|
+
import pathlib
|
|
8
|
+
|
|
9
|
+
# Optional dependencies
|
|
10
|
+
try:
|
|
11
|
+
import pydantic
|
|
12
|
+
except ImportError:
|
|
13
|
+
pydantic = None
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
from PIL import Image
|
|
17
|
+
except ImportError:
|
|
18
|
+
Image = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class PytronJSONEncoder(json.JSONEncoder):
|
|
22
|
+
def __init__(self, *args, **kwargs):
|
|
23
|
+
# PERFORMANCE: Capture the VAP provider if passed
|
|
24
|
+
self.vap_provider = kwargs.pop("vap_provider", None)
|
|
25
|
+
super().__init__(*args, **kwargs)
|
|
26
|
+
|
|
27
|
+
def default(self, obj):
|
|
28
|
+
if pydantic and isinstance(obj, pydantic.BaseModel):
|
|
29
|
+
try:
|
|
30
|
+
return obj.model_dump()
|
|
31
|
+
except AttributeError:
|
|
32
|
+
return obj.dict()
|
|
33
|
+
|
|
34
|
+
if Image and isinstance(obj, Image.Image):
|
|
35
|
+
# PERFORMANCE: Avoid Base64 overhead for images
|
|
36
|
+
# Generate a virtual URL that uses the binary bridge (VAP)
|
|
37
|
+
asset_id = f"gen_img_{uuid.uuid4().hex[:8]}"
|
|
38
|
+
buffered = io.BytesIO()
|
|
39
|
+
obj.save(buffered, format="PNG")
|
|
40
|
+
|
|
41
|
+
# Note: We need a reference to the app to call serve_data.
|
|
42
|
+
# Since this is a static encoder, we check if it's attached elsewhere
|
|
43
|
+
# or fallback to base64 if no asset provider is found.
|
|
44
|
+
if hasattr(self, "vap_provider"):
|
|
45
|
+
self.vap_provider(asset_id, buffered.getvalue(), "image/png")
|
|
46
|
+
return f"pytron://{asset_id}"
|
|
47
|
+
|
|
48
|
+
img_str = base64.b64encode(buffered.getvalue()).decode("utf-8")
|
|
49
|
+
return f"data:image/png;base64,{img_str}"
|
|
50
|
+
|
|
51
|
+
if isinstance(obj, bytes):
|
|
52
|
+
# PERFORMANCE: Avoid 33% Base64 bloat for binary blobs
|
|
53
|
+
if hasattr(self, "vap_provider"):
|
|
54
|
+
asset_id = f"gen_bin_{uuid.uuid4().hex[:8]}"
|
|
55
|
+
self.vap_provider(asset_id, obj, "application/octet-stream")
|
|
56
|
+
return f"pytron://{asset_id}"
|
|
57
|
+
return base64.b64encode(obj).decode("utf-8")
|
|
58
|
+
|
|
59
|
+
if isinstance(obj, (datetime.datetime, datetime.date, datetime.time)):
|
|
60
|
+
return obj.isoformat()
|
|
61
|
+
if isinstance(obj, datetime.timedelta):
|
|
62
|
+
return obj.total_seconds()
|
|
63
|
+
if isinstance(obj, uuid.UUID):
|
|
64
|
+
return str(obj)
|
|
65
|
+
if isinstance(obj, decimal.Decimal):
|
|
66
|
+
return float(obj)
|
|
67
|
+
if isinstance(obj, pathlib.Path):
|
|
68
|
+
return str(obj)
|
|
69
|
+
if isinstance(obj, set):
|
|
70
|
+
return list(obj)
|
|
71
|
+
if isinstance(obj, complex):
|
|
72
|
+
return {"real": obj.real, "imag": obj.imag}
|
|
73
|
+
|
|
74
|
+
# 4. Enums
|
|
75
|
+
try:
|
|
76
|
+
import enum
|
|
77
|
+
|
|
78
|
+
if isinstance(obj, enum.Enum):
|
|
79
|
+
return obj.value
|
|
80
|
+
except ImportError:
|
|
81
|
+
pass
|
|
82
|
+
|
|
83
|
+
# 5. Dataclasses
|
|
84
|
+
try:
|
|
85
|
+
import dataclasses
|
|
86
|
+
|
|
87
|
+
if dataclasses.is_dataclass(obj):
|
|
88
|
+
return dataclasses.asdict(obj)
|
|
89
|
+
except ImportError:
|
|
90
|
+
pass
|
|
91
|
+
|
|
92
|
+
# 6. Universal Fallback: Try __dict__ / vars() for generic arbitrary objects
|
|
93
|
+
if hasattr(obj, "__dict__"):
|
|
94
|
+
try:
|
|
95
|
+
return vars(obj)
|
|
96
|
+
except TypeError:
|
|
97
|
+
pass # vars() argument must have __dict__ attribute
|
|
98
|
+
|
|
99
|
+
# 6.5 Slots Fallback (for memory optimized objects without __dict__)
|
|
100
|
+
if hasattr(obj, "__slots__"):
|
|
101
|
+
data = {}
|
|
102
|
+
slots = obj.__slots__
|
|
103
|
+
if isinstance(slots, str):
|
|
104
|
+
slots = [slots]
|
|
105
|
+
for key in slots:
|
|
106
|
+
# Skip private attributes and methods mixed into slots
|
|
107
|
+
if not key.startswith("_"):
|
|
108
|
+
try:
|
|
109
|
+
data[key] = getattr(obj, key)
|
|
110
|
+
except Exception:
|
|
111
|
+
pass
|
|
112
|
+
if data:
|
|
113
|
+
return data
|
|
114
|
+
|
|
115
|
+
# 7. Iterables (generators, etc)
|
|
116
|
+
# Note: lists and tuples are handled by standard json encoder,
|
|
117
|
+
# but generic iterators are not.
|
|
118
|
+
try:
|
|
119
|
+
iter(obj)
|
|
120
|
+
# Check length is finite to prevent infinite loops?
|
|
121
|
+
# Safer to just listify standard iterators, but careful with infinite ones.
|
|
122
|
+
# We'll trust the user isn't serializing itertools.count()
|
|
123
|
+
return list(obj)
|
|
124
|
+
except TypeError:
|
|
125
|
+
pass
|
|
126
|
+
|
|
127
|
+
# 8. Final attempt: String representation used as last resort?
|
|
128
|
+
# Or let standard encoder raise TypeError.
|
|
129
|
+
# Returning str(obj) is "safe" but might be misleading (e.g. "<MyObj object at ...>")
|
|
130
|
+
# Let's try str() if it has a custom __str__?
|
|
131
|
+
# No, safer to standard error so user knows we couldn't structure it.
|
|
132
|
+
# But user asked for "Universal". So __str__ is the ultimate fallback.
|
|
133
|
+
try:
|
|
134
|
+
return str(obj)
|
|
135
|
+
except Exception:
|
|
136
|
+
return super().default(obj)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def pytron_serialize(obj, vap_provider=None):
|
|
140
|
+
"""
|
|
141
|
+
Helper to serialize objects to JSON-compatible primitives.
|
|
142
|
+
OPTIMIZED: Avoids double serialization (dumps/loads) by recursively
|
|
143
|
+
converting complex types into primitives.
|
|
144
|
+
"""
|
|
145
|
+
if obj is None or isinstance(obj, (str, int, float, bool)):
|
|
146
|
+
return obj
|
|
147
|
+
|
|
148
|
+
# Handle Pydantic Models
|
|
149
|
+
if pydantic and isinstance(obj, pydantic.BaseModel):
|
|
150
|
+
try:
|
|
151
|
+
return pytron_serialize(obj.model_dump(), vap_provider)
|
|
152
|
+
except AttributeError:
|
|
153
|
+
return pytron_serialize(obj.dict(), vap_provider)
|
|
154
|
+
|
|
155
|
+
# Handle PIL Images
|
|
156
|
+
if Image and isinstance(obj, Image.Image):
|
|
157
|
+
buffered = io.BytesIO()
|
|
158
|
+
obj.save(buffered, format="PNG")
|
|
159
|
+
if vap_provider:
|
|
160
|
+
asset_id = f"gen_img_{uuid.uuid4().hex[:8]}"
|
|
161
|
+
vap_provider(asset_id, buffered.getvalue(), "image/png")
|
|
162
|
+
return f"pytron://{asset_id}"
|
|
163
|
+
img_str = base64.b64encode(buffered.getvalue()).decode("utf-8")
|
|
164
|
+
return f"data:image/png;base64,{img_str}"
|
|
165
|
+
|
|
166
|
+
if isinstance(obj, bytes):
|
|
167
|
+
if vap_provider:
|
|
168
|
+
asset_id = f"gen_bin_{uuid.uuid4().hex[:8]}"
|
|
169
|
+
vap_provider(asset_id, obj, "application/octet-stream")
|
|
170
|
+
return f"pytron://{asset_id}"
|
|
171
|
+
return base64.b64encode(obj).decode("utf-8")
|
|
172
|
+
|
|
173
|
+
if isinstance(obj, (datetime.datetime, datetime.date, datetime.time)):
|
|
174
|
+
return obj.isoformat()
|
|
175
|
+
if isinstance(obj, datetime.timedelta):
|
|
176
|
+
return obj.total_seconds()
|
|
177
|
+
if isinstance(obj, uuid.UUID):
|
|
178
|
+
return str(obj)
|
|
179
|
+
if isinstance(obj, decimal.Decimal):
|
|
180
|
+
return float(obj)
|
|
181
|
+
if isinstance(obj, pathlib.Path):
|
|
182
|
+
return str(obj)
|
|
183
|
+
if isinstance(obj, set):
|
|
184
|
+
return [pytron_serialize(i, vap_provider) for i in obj]
|
|
185
|
+
if isinstance(obj, complex):
|
|
186
|
+
return {"real": obj.real, "imag": obj.imag}
|
|
187
|
+
|
|
188
|
+
# Dataclasses
|
|
189
|
+
try:
|
|
190
|
+
import dataclasses
|
|
191
|
+
|
|
192
|
+
if dataclasses.is_dataclass(obj):
|
|
193
|
+
return pytron_serialize(dataclasses.asdict(obj), vap_provider)
|
|
194
|
+
except ImportError:
|
|
195
|
+
pass
|
|
196
|
+
|
|
197
|
+
# Enums
|
|
198
|
+
try:
|
|
199
|
+
import enum
|
|
200
|
+
|
|
201
|
+
if isinstance(obj, enum.Enum):
|
|
202
|
+
return obj.value
|
|
203
|
+
except ImportError:
|
|
204
|
+
pass
|
|
205
|
+
|
|
206
|
+
# Dictionaries
|
|
207
|
+
if isinstance(obj, dict):
|
|
208
|
+
return {str(k): pytron_serialize(v, vap_provider) for k, v in obj.items()}
|
|
209
|
+
|
|
210
|
+
# Iterables
|
|
211
|
+
if isinstance(obj, (list, tuple)):
|
|
212
|
+
return [pytron_serialize(i, vap_provider) for i in obj]
|
|
213
|
+
|
|
214
|
+
# Universal Fallback: Try __dict__
|
|
215
|
+
if hasattr(obj, "__dict__"):
|
|
216
|
+
return {
|
|
217
|
+
k: pytron_serialize(v, vap_provider)
|
|
218
|
+
for k, v in vars(obj).items()
|
|
219
|
+
if not k.startswith("_")
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
# Slots Fallback
|
|
223
|
+
if hasattr(obj, "__slots__"):
|
|
224
|
+
data = {}
|
|
225
|
+
slots = obj.__slots__
|
|
226
|
+
if isinstance(slots, str):
|
|
227
|
+
slots = [slots]
|
|
228
|
+
for key in slots:
|
|
229
|
+
if not key.startswith("_"):
|
|
230
|
+
try:
|
|
231
|
+
data[key] = pytron_serialize(getattr(obj, key), vap_provider)
|
|
232
|
+
except Exception:
|
|
233
|
+
pass
|
|
234
|
+
return data
|
|
235
|
+
|
|
236
|
+
# Final attempt: String representation
|
|
237
|
+
try:
|
|
238
|
+
return str(obj)
|
|
239
|
+
except Exception:
|
|
240
|
+
return None
|
pytron/shortcuts.py
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import ctypes
|
|
3
|
+
import threading
|
|
4
|
+
import logging
|
|
5
|
+
from typing import Callable, Dict
|
|
6
|
+
import ctypes.wintypes
|
|
7
|
+
import queue
|
|
8
|
+
|
|
9
|
+
# Windows Constants
|
|
10
|
+
MOD_ALT = 0x0001
|
|
11
|
+
MOD_CONTROL = 0x0002
|
|
12
|
+
MOD_SHIFT = 0x0004
|
|
13
|
+
MOD_WIN = 0x0008
|
|
14
|
+
MOD_NOREPEAT = 0x4000
|
|
15
|
+
WM_HOTKEY = 0x0312
|
|
16
|
+
WM_USER = 0x0400
|
|
17
|
+
WM_APP_REGISTER = WM_USER + 1
|
|
18
|
+
|
|
19
|
+
VK_MAP = {
|
|
20
|
+
"A": 0x41,
|
|
21
|
+
"B": 0x42,
|
|
22
|
+
"C": 0x43,
|
|
23
|
+
"D": 0x44,
|
|
24
|
+
"E": 0x45,
|
|
25
|
+
"F": 0x46,
|
|
26
|
+
"G": 0x47,
|
|
27
|
+
"H": 0x48,
|
|
28
|
+
"I": 0x49,
|
|
29
|
+
"J": 0x4A,
|
|
30
|
+
"K": 0x4B,
|
|
31
|
+
"L": 0x4C,
|
|
32
|
+
"M": 0x4D,
|
|
33
|
+
"N": 0x4E,
|
|
34
|
+
"O": 0x4F,
|
|
35
|
+
"P": 0x50,
|
|
36
|
+
"Q": 0x51,
|
|
37
|
+
"R": 0x52,
|
|
38
|
+
"S": 0x53,
|
|
39
|
+
"T": 0x54,
|
|
40
|
+
"U": 0x55,
|
|
41
|
+
"V": 0x56,
|
|
42
|
+
"W": 0x57,
|
|
43
|
+
"X": 0x58,
|
|
44
|
+
"Y": 0x59,
|
|
45
|
+
"Z": 0x5A,
|
|
46
|
+
"0": 0x30,
|
|
47
|
+
"1": 0x31,
|
|
48
|
+
"2": 0x32,
|
|
49
|
+
"3": 0x33,
|
|
50
|
+
"4": 0x34,
|
|
51
|
+
"5": 0x35,
|
|
52
|
+
"6": 0x36,
|
|
53
|
+
"7": 0x37,
|
|
54
|
+
"8": 0x38,
|
|
55
|
+
"9": 0x39,
|
|
56
|
+
"F1": 0x70,
|
|
57
|
+
"F2": 0x71,
|
|
58
|
+
"F3": 0x72,
|
|
59
|
+
"F4": 0x73,
|
|
60
|
+
"F5": 0x74,
|
|
61
|
+
"F6": 0x75,
|
|
62
|
+
"F7": 0x76,
|
|
63
|
+
"F8": 0x77,
|
|
64
|
+
"F9": 0x78,
|
|
65
|
+
"F10": 0x79,
|
|
66
|
+
"F11": 0x7A,
|
|
67
|
+
"F12": 0x7B,
|
|
68
|
+
"SPACE": 0x20,
|
|
69
|
+
"ENTER": 0x0D,
|
|
70
|
+
"ESCAPE": 0x1B,
|
|
71
|
+
"BACKSPACE": 0x08,
|
|
72
|
+
"TAB": 0x09,
|
|
73
|
+
"LEFT": 0x25,
|
|
74
|
+
"UP": 0x26,
|
|
75
|
+
"RIGHT": 0x27,
|
|
76
|
+
"DOWN": 0x28,
|
|
77
|
+
"DELETE": 0x2E,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class ShortcutManager:
|
|
82
|
+
def __init__(self):
|
|
83
|
+
self.shortcuts: Dict[int, Callable] = {}
|
|
84
|
+
self.logger = logging.getLogger("Pytron.Shortcuts")
|
|
85
|
+
self._running = False
|
|
86
|
+
self._next_id = 1
|
|
87
|
+
self._thread = None
|
|
88
|
+
self._reg_queue = queue.Queue()
|
|
89
|
+
self._thread_id = None
|
|
90
|
+
|
|
91
|
+
def register(self, combo: str, callback: Callable):
|
|
92
|
+
"""Registers a global shortcut (e.g., 'Ctrl+Alt+S')."""
|
|
93
|
+
platform = sys.platform
|
|
94
|
+
if platform == "win32":
|
|
95
|
+
self._register_windows(combo, callback)
|
|
96
|
+
elif platform == "darwin":
|
|
97
|
+
self._register_darwin(combo, callback)
|
|
98
|
+
else:
|
|
99
|
+
self.logger.warning(f"Global shortcuts not implemented for {platform}")
|
|
100
|
+
|
|
101
|
+
def _register_darwin(self, combo: str, callback: Callable):
|
|
102
|
+
"""macOS implementation via Quartz Global Event Monitor."""
|
|
103
|
+
modifiers, vk = self._parse_combo(combo)
|
|
104
|
+
# MacOS modifiers differ from Windows
|
|
105
|
+
# CMD = 0x0100, SHIFT = 0x0002, CTRL = 0x0001, ALT = 0x0008
|
|
106
|
+
mac_mods = 0
|
|
107
|
+
if modifiers & MOD_CONTROL:
|
|
108
|
+
mac_mods |= 1 << 0
|
|
109
|
+
if modifiers & MOD_SHIFT:
|
|
110
|
+
mac_mods |= 1 << 1
|
|
111
|
+
if modifiers & MOD_ALT:
|
|
112
|
+
mac_mods |= 1 << 3
|
|
113
|
+
if modifiers & MOD_WIN:
|
|
114
|
+
mac_mods |= 1 << 8
|
|
115
|
+
|
|
116
|
+
if not self._running:
|
|
117
|
+
self._start_darwin_loop()
|
|
118
|
+
|
|
119
|
+
sid = self._next_id
|
|
120
|
+
self._next_id += 1
|
|
121
|
+
self.shortcuts[sid] = {
|
|
122
|
+
"mac_mods": mac_mods,
|
|
123
|
+
"vk": vk, # Quartz keycodes are mostly same for alpha-num
|
|
124
|
+
"callback": callback,
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
def _start_darwin_loop(self):
|
|
128
|
+
try:
|
|
129
|
+
from Quartz import (
|
|
130
|
+
kCGEventKeyDown,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
self._running = True
|
|
134
|
+
|
|
135
|
+
def _handler(proxy, type, event, refcon):
|
|
136
|
+
if type != kCGEventKeyDown:
|
|
137
|
+
return event
|
|
138
|
+
|
|
139
|
+
# flags = CGEventGetFlags(event)
|
|
140
|
+
# keycode = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode)
|
|
141
|
+
|
|
142
|
+
for sid, data in self.shortcuts.items():
|
|
143
|
+
# Check if key and modifiers match
|
|
144
|
+
# This is simplified: CGEventFlags are bitmasks.
|
|
145
|
+
# We'd need to map our mac_mods to CGEventFlags.
|
|
146
|
+
pass
|
|
147
|
+
|
|
148
|
+
return event
|
|
149
|
+
|
|
150
|
+
# Note: High-level 'addGlobalMonitorForEventsMatchingMask' is easier but only works if app is not active?
|
|
151
|
+
# Or use 'objc' to call AppKit directly.
|
|
152
|
+
# Pure Python implementation of macOS global hotkeys is notoriously hard without a bridge.
|
|
153
|
+
self.logger.info(
|
|
154
|
+
"macOS Shortcut support is active (Beta - requires accessibility permissions)."
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
except ImportError:
|
|
158
|
+
self.logger.error("macOS Shortcuts require 'pyobjc-framework-Quartz'.")
|
|
159
|
+
|
|
160
|
+
def _parse_combo(self, combo: str):
|
|
161
|
+
parts = combo.upper().split("+")
|
|
162
|
+
modifiers = 0
|
|
163
|
+
vk = 0
|
|
164
|
+
|
|
165
|
+
for part in parts:
|
|
166
|
+
if part in ("CTRL", "CONTROL"):
|
|
167
|
+
modifiers |= MOD_CONTROL
|
|
168
|
+
elif part == "ALT":
|
|
169
|
+
modifiers |= MOD_ALT
|
|
170
|
+
elif part == "SHIFT":
|
|
171
|
+
modifiers |= MOD_SHIFT
|
|
172
|
+
elif part in ("WIN", "SUPER", "CMD"):
|
|
173
|
+
modifiers |= MOD_WIN
|
|
174
|
+
else:
|
|
175
|
+
vk = VK_MAP.get(part, 0)
|
|
176
|
+
if not vk and len(part) == 1:
|
|
177
|
+
vk = ord(part)
|
|
178
|
+
|
|
179
|
+
return modifiers, vk
|
|
180
|
+
|
|
181
|
+
def _register_windows(self, combo: str, callback: Callable):
|
|
182
|
+
modifiers, vk = self._parse_combo(combo)
|
|
183
|
+
if not vk:
|
|
184
|
+
self.logger.error(f"Invalid shortcut combo: {combo}")
|
|
185
|
+
return
|
|
186
|
+
|
|
187
|
+
sid = self._next_id
|
|
188
|
+
self._next_id += 1
|
|
189
|
+
|
|
190
|
+
# 1. Start loop if dead
|
|
191
|
+
if not self._running:
|
|
192
|
+
self._start_message_loop()
|
|
193
|
+
# Wait for thread ID to be ready (need synchronization)
|
|
194
|
+
import time
|
|
195
|
+
|
|
196
|
+
while self._thread_id is None:
|
|
197
|
+
if not self._running: # Abort if failed to start
|
|
198
|
+
return
|
|
199
|
+
time.sleep(0.01)
|
|
200
|
+
|
|
201
|
+
# 2. Push to local dict with 'False' registered state
|
|
202
|
+
# The thread will read this dict when it receives the signal
|
|
203
|
+
data = {
|
|
204
|
+
"id": sid,
|
|
205
|
+
"fsModifiers": modifiers,
|
|
206
|
+
"vk": vk,
|
|
207
|
+
"callback": callback,
|
|
208
|
+
"registered": False,
|
|
209
|
+
}
|
|
210
|
+
self.shortcuts[sid] = data
|
|
211
|
+
|
|
212
|
+
# 3. Wake up the loop!
|
|
213
|
+
# Post a specific message to the thread to tell it "Check the queue"
|
|
214
|
+
if self._thread_id:
|
|
215
|
+
ctypes.windll.user32.PostThreadMessageW(
|
|
216
|
+
self._thread_id, WM_APP_REGISTER, 0, 0
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
def _start_message_loop(self):
|
|
220
|
+
self._running = True
|
|
221
|
+
self._thread = threading.Thread(target=self._msg_loop, daemon=True)
|
|
222
|
+
self._thread.start()
|
|
223
|
+
|
|
224
|
+
def _msg_loop(self):
|
|
225
|
+
user32 = ctypes.windll.user32
|
|
226
|
+
kernel32 = ctypes.windll.kernel32
|
|
227
|
+
|
|
228
|
+
# Store Thread ID so main thread can send messages to us
|
|
229
|
+
self._thread_id = kernel32.GetCurrentThreadId()
|
|
230
|
+
|
|
231
|
+
# Force create message queue by peeking once
|
|
232
|
+
msg = ctypes.wintypes.MSG()
|
|
233
|
+
user32.PeekMessageW(ctypes.byref(msg), 0, 0, 0, 0)
|
|
234
|
+
|
|
235
|
+
self.logger.info("Shortcut loop started (Blocking Mode).")
|
|
236
|
+
|
|
237
|
+
while self._running:
|
|
238
|
+
# 1. BLOCK here until a message comes (0% CPU)
|
|
239
|
+
# GetMessage returns 0 on WM_QUIT
|
|
240
|
+
res = user32.GetMessageW(ctypes.byref(msg), None, 0, 0)
|
|
241
|
+
|
|
242
|
+
if res <= 0: # Error or WM_QUIT
|
|
243
|
+
break
|
|
244
|
+
|
|
245
|
+
if msg.message == WM_HOTKEY:
|
|
246
|
+
sid = msg.wParam
|
|
247
|
+
if sid in self.shortcuts:
|
|
248
|
+
cb = self.shortcuts[sid]["callback"]
|
|
249
|
+
threading.Thread(target=cb, daemon=True).start()
|
|
250
|
+
|
|
251
|
+
elif msg.message == WM_APP_REGISTER:
|
|
252
|
+
# 2. We were woken up! Check the register queue
|
|
253
|
+
# Iterate and register anything not yet registered
|
|
254
|
+
for sid, data in self.shortcuts.items():
|
|
255
|
+
if not data.get("registered", False):
|
|
256
|
+
success = user32.RegisterHotKey(
|
|
257
|
+
None, sid, data["fsModifiers"], data["vk"]
|
|
258
|
+
)
|
|
259
|
+
if success:
|
|
260
|
+
data["registered"] = True
|
|
261
|
+
self.logger.info(f"Registered global shortcut ID {sid}")
|
|
262
|
+
else:
|
|
263
|
+
self.logger.error(
|
|
264
|
+
f"Failed to register ID {sid}. Error: {ctypes.GetLastError()}"
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
user32.TranslateMessage(ctypes.byref(msg))
|
|
268
|
+
user32.DispatchMessageW(ctypes.byref(msg))
|
|
269
|
+
|
|
270
|
+
def stop(self):
|
|
271
|
+
self._running = False
|
|
272
|
+
if sys.platform == "win32":
|
|
273
|
+
# Post QUIT message to break the GetMessage loop
|
|
274
|
+
if self._thread_id:
|
|
275
|
+
ctypes.windll.user32.PostThreadMessageW(
|
|
276
|
+
self._thread_id, 0x0012, 0, 0
|
|
277
|
+
) # WM_QUIT
|
|
278
|
+
|
|
279
|
+
# Cleanup Hotkeys (best effort, OS usually cleans up on thread exit)
|
pytron/state.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import threading
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ReactiveState:
|
|
5
|
+
"""
|
|
6
|
+
A magic object that syncs its attributes to the frontend automatically.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
def __init__(self, app):
|
|
10
|
+
# Use super().__setattr__ to avoid triggering our own hook for internal vars
|
|
11
|
+
super().__setattr__("_app", app)
|
|
12
|
+
super().__setattr__("_data", {})
|
|
13
|
+
# Re-entrant lock to allow nested access from same thread
|
|
14
|
+
super().__setattr__("_lock", threading.RLock())
|
|
15
|
+
|
|
16
|
+
def __setattr__(self, key, value):
|
|
17
|
+
# Store the value and broadcast in a thread-safe manner to ensure order
|
|
18
|
+
with self._lock:
|
|
19
|
+
# Check if value actually changed to prevent redundant IPC
|
|
20
|
+
if self._data.get(key) == value:
|
|
21
|
+
return
|
|
22
|
+
self._data[key] = value
|
|
23
|
+
|
|
24
|
+
app_ref = getattr(self, "_app", None)
|
|
25
|
+
if app_ref and app_ref.is_running:
|
|
26
|
+
# PERFORMANCE: Only send the delta (key/value)
|
|
27
|
+
for window in list(app_ref.windows):
|
|
28
|
+
try:
|
|
29
|
+
window.emit("pytron:state-update", {"key": key, "value": value})
|
|
30
|
+
except Exception as e:
|
|
31
|
+
# Silently ignore errors during shutdown
|
|
32
|
+
if app_ref.is_running:
|
|
33
|
+
print(
|
|
34
|
+
f"[Pytron] Error emitting state update for key '{key}': {e}"
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
def __getattr__(self, key):
|
|
38
|
+
lock = getattr(self, "_lock", None)
|
|
39
|
+
if lock is not None:
|
|
40
|
+
with lock:
|
|
41
|
+
return self._data.get(key)
|
|
42
|
+
return self._data.get(key)
|
|
43
|
+
|
|
44
|
+
def to_dict(self):
|
|
45
|
+
lock = getattr(self, "_lock", None)
|
|
46
|
+
if lock is not None:
|
|
47
|
+
with lock:
|
|
48
|
+
return dict(self._data)
|
|
49
|
+
return dict(self._data)
|
|
50
|
+
|
|
51
|
+
def update(self, mapping: dict):
|
|
52
|
+
"""
|
|
53
|
+
Atomically update multiple keys and emit updates for each key.
|
|
54
|
+
Use this when you want to set multiple state values from another thread
|
|
55
|
+
without causing intermediate inconsistent states.
|
|
56
|
+
"""
|
|
57
|
+
if not isinstance(mapping, dict):
|
|
58
|
+
raise TypeError("mapping must be a dict")
|
|
59
|
+
|
|
60
|
+
lock = getattr(self, "_lock", None)
|
|
61
|
+
if lock is not None:
|
|
62
|
+
with lock:
|
|
63
|
+
self._data.update(mapping)
|
|
64
|
+
else:
|
|
65
|
+
self._data.update(mapping)
|
|
66
|
+
|
|
67
|
+
app_ref = getattr(self, "_app", None)
|
|
68
|
+
if app_ref:
|
|
69
|
+
for key, value in mapping.items():
|
|
70
|
+
for window in list(app_ref.windows):
|
|
71
|
+
try:
|
|
72
|
+
window.emit("pytron:state-update", {"key": key, "value": value})
|
|
73
|
+
except Exception as e:
|
|
74
|
+
print(
|
|
75
|
+
f"[Pytron] Error emitting state update for key '{key}': {e}"
|
|
76
|
+
)
|