pythonhere 0.1.5.2__tar.gz → 0.2.0__tar.gz
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.
- pythonhere-0.2.0/LICENSE +22 -0
- pythonhere-0.2.0/PKG-INFO +125 -0
- pythonhere-0.2.0/README.rst +101 -0
- pythonhere-0.2.0/pyproject.toml +151 -0
- {pythonhere-0.1.5.2 → pythonhere-0.2.0}/pythonhere/android_here.py +4 -5
- pythonhere-0.2.0/pythonhere/data/logo/logo-128.png +0 -0
- pythonhere-0.2.0/pythonhere/data/logo/logo-32.png +0 -0
- pythonhere-0.2.0/pythonhere/data/logo/logo-splash.png +0 -0
- {pythonhere-0.1.5.2 → pythonhere-0.2.0}/pythonhere/enum_here.py +1 -0
- pythonhere-0.2.0/pythonhere/exception_manager_here.kv +22 -0
- {pythonhere-0.1.5.2 → pythonhere-0.2.0}/pythonhere/exception_manager_here.py +14 -30
- {pythonhere-0.1.5.2 → pythonhere-0.2.0}/pythonhere/magic_here/shortcuts.py +6 -5
- {pythonhere-0.1.5.2 → pythonhere-0.2.0}/pythonhere/main.py +90 -36
- {pythonhere-0.1.5.2 → pythonhere-0.2.0}/pythonhere/network_here.py +4 -3
- {pythonhere-0.1.5.2 → pythonhere-0.2.0}/pythonhere/patches_here.py +1 -2
- pythonhere-0.2.0/pythonhere/pythonhere.kv +49 -0
- {pythonhere-0.1.5.2 → pythonhere-0.2.0}/pythonhere/server_here.py +4 -4
- pythonhere-0.2.0/pythonhere/ui_here/actionbar_here.kv +8 -0
- pythonhere-0.2.0/pythonhere/ui_here/common_here.kv +14 -0
- pythonhere-0.2.0/pythonhere/ui_here/connection_address_here.kv +32 -0
- {pythonhere-0.1.5.2 → pythonhere-0.2.0}/pythonhere/ui_here/layout_here.py +1 -0
- pythonhere-0.2.0/pythonhere/ui_here/server_screen_here.kv +57 -0
- pythonhere-0.2.0/pythonhere/ui_here/settings_here.kv +31 -0
- {pythonhere-0.1.5.2 → pythonhere-0.2.0}/pythonhere/ui_here/settings_here.py +3 -3
- pythonhere-0.2.0/pythonhere/version_here.py +1 -0
- {pythonhere-0.1.5.2 → pythonhere-0.2.0}/pythonhere/window_here.py +3 -2
- pythonhere-0.2.0/pythonhere.egg-info/PKG-INFO +125 -0
- {pythonhere-0.1.5.2 → pythonhere-0.2.0}/pythonhere.egg-info/SOURCES.txt +23 -2
- pythonhere-0.2.0/pythonhere.egg-info/requires.txt +4 -0
- {pythonhere-0.1.5.2 → pythonhere-0.2.0}/setup.cfg +0 -3
- pythonhere-0.2.0/setup.py +3 -0
- pythonhere-0.2.0/tests/test_android_here.py +32 -0
- pythonhere-0.2.0/tests/test_exception_manager_here.py +20 -0
- pythonhere-0.2.0/tests/test_launcher_here.py +50 -0
- pythonhere-0.2.0/tests/test_magic.py +73 -0
- pythonhere-0.2.0/tests/test_main.py +271 -0
- pythonhere-0.2.0/tests/test_network.py +8 -0
- pythonhere-0.2.0/tests/test_patches.py +37 -0
- pythonhere-0.2.0/tests/test_server_here.py +86 -0
- pythonhere-0.2.0/tests/test_settings.py +33 -0
- pythonhere-0.2.0/tests/test_window_here.py +14 -0
- pythonhere-0.1.5.2/PKG-INFO +0 -119
- pythonhere-0.1.5.2/README.rst +0 -101
- pythonhere-0.1.5.2/pythonhere/version_here.py +0 -1
- pythonhere-0.1.5.2/pythonhere.egg-info/PKG-INFO +0 -119
- pythonhere-0.1.5.2/pythonhere.egg-info/requires.txt +0 -22
- pythonhere-0.1.5.2/setup.py +0 -63
- {pythonhere-0.1.5.2 → pythonhere-0.2.0}/pythonhere/__init__.py +1 -1
- {pythonhere-0.1.5.2 → pythonhere-0.2.0}/pythonhere/launcher_here.py +3 -3
- {pythonhere-0.1.5.2 → pythonhere-0.2.0}/pythonhere/magic_here/__init__.py +0 -0
- {pythonhere-0.1.5.2 → pythonhere-0.2.0}/pythonhere/ui_here/__init__.py +0 -0
- {pythonhere-0.1.5.2 → pythonhere-0.2.0}/pythonhere/ui_here/connection_address_here.py +2 -2
- {pythonhere-0.1.5.2 → pythonhere-0.2.0}/pythonhere/ui_here/server_screen_here.py +2 -2
- {pythonhere-0.1.5.2 → pythonhere-0.2.0}/pythonhere.egg-info/dependency_links.txt +0 -0
- {pythonhere-0.1.5.2 → pythonhere-0.2.0}/pythonhere.egg-info/top_level.txt +0 -0
pythonhere-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020 b3b
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pythonhere
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Here is the Kivy based app to run code from the Jupyter magic %there
|
|
5
|
+
Author-email: b3b <ash.b3b@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/b3b/ipython-pythonhere
|
|
8
|
+
Project-URL: Changelog, https://github.com/b3b/pythonhere/blob/master/CHANGELOG.rst
|
|
9
|
+
Keywords: android,ipython,jupyter,magic,kivy
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Description-Content-Type: text/x-rst
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: herethere[magic]>=0.1.0
|
|
20
|
+
Requires-Dist: ipython
|
|
21
|
+
Requires-Dist: ipywidgets
|
|
22
|
+
Requires-Dist: Pillow
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
|
|
25
|
+
PythonHere
|
|
26
|
+
==========
|
|
27
|
+
|
|
28
|
+
.. start-badges
|
|
29
|
+
.. image:: https://img.shields.io/pypi/status/pythonhere
|
|
30
|
+
:target: https://pypi.python.org/pypi/pythonhere
|
|
31
|
+
:alt: Status
|
|
32
|
+
.. image:: https://img.shields.io/pypi/v/pythonhere.svg
|
|
33
|
+
:target: https://pypi.python.org/pypi/pythonhere
|
|
34
|
+
:alt: Latest version on PyPi
|
|
35
|
+
.. image:: https://img.shields.io/docker/v/herethere/pythonhere?color=%23FFD43B&label=Docker%20Image
|
|
36
|
+
:target: https://hub.docker.com/r/herethere/pythonhere
|
|
37
|
+
:alt: Docker Image Version (latest by date)
|
|
38
|
+
.. image:: https://img.shields.io/pypi/pyversions/pythonhere.svg
|
|
39
|
+
:target: https://pypi.python.org/pypi/pythonhere
|
|
40
|
+
:alt: Supported Python versions
|
|
41
|
+
.. image:: https://github.com/b3b/pythonhere/actions/workflows/tests.yml/badge.svg?branch=master
|
|
42
|
+
:target: https://github.com/b3b/pythonhere/actions/workflows/tests.yml?query=branch%3Amaster
|
|
43
|
+
:alt: CI Status
|
|
44
|
+
.. image:: https://codecov.io/github/b3b/pythonhere/coverage.svg?branch=master
|
|
45
|
+
:target: https://codecov.io/github/b3b/pythonhere?branch=master
|
|
46
|
+
:alt: Code coverage Status
|
|
47
|
+
.. end-badges
|
|
48
|
+
|
|
49
|
+
*PythonHere* lets you run Python code from a local `Jupyter <https://jupyter.org/>`_
|
|
50
|
+
notebook inside a remote `Kivy <https://kivy.org>`_ app.
|
|
51
|
+
|
|
52
|
+
PythonHere has two parts:
|
|
53
|
+
|
|
54
|
+
* *Here* is the remote/server side. It runs a Python environment with a Kivy GUI,
|
|
55
|
+
for example on Android, Raspberry Pi, or another machine.
|
|
56
|
+
* *%there* is the local/client side. It is a Jupyter magic command for running
|
|
57
|
+
code interactively in the remote PythonHere environment.
|
|
58
|
+
|
|
59
|
+
This makes PythonHere useful as a live Python/Kivy playground, and as a way to
|
|
60
|
+
inspect or control a Python app running remotely.
|
|
61
|
+
|
|
62
|
+
Project documentation: https://herethere.me/pythonhere
|
|
63
|
+
|
|
64
|
+
.. image:: https://raw.githubusercontent.com/b3b/pythonhere/master/docs/description.png
|
|
65
|
+
:alt: Project description
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
Install the Android app
|
|
69
|
+
-----------------------
|
|
70
|
+
|
|
71
|
+
Ready-to-use *PythonHere* APKs are available from the `GitHub Releases <https://github.com/b3b/pythonhere/releases>`_ page.
|
|
72
|
+
|
|
73
|
+
For APK provenance and signing checks, see `Android APK verification <https://github.com/b3b/pythonhere/blob/master/docs/android-apk-verification.rst>`_.
|
|
74
|
+
For a list of Python packages included in the Android build, see `buildozer.spec <https://github.com/b3b/pythonhere/blob/master/buildozer.spec>`_.
|
|
75
|
+
|
|
76
|
+
Start a local Jupyter environment with Docker
|
|
77
|
+
---------------------------------------------
|
|
78
|
+
|
|
79
|
+
The Docker image is based on `Jupyter Docker Stacks <https://jupyter-docker-stacks.readthedocs.io/en/latest/>`_
|
|
80
|
+
and includes *PythonHere* with usage examples.
|
|
81
|
+
|
|
82
|
+
Example command to start the Docker container::
|
|
83
|
+
|
|
84
|
+
docker run \
|
|
85
|
+
--rm \
|
|
86
|
+
-p 8888:8888 \
|
|
87
|
+
--user root \
|
|
88
|
+
-e CHOWN_EXTRA=/home/jovyan/work \
|
|
89
|
+
-e CHOWN_EXTRA_OPTS='-R' \
|
|
90
|
+
-v "$(pwd)/work":/home/jovyan/work \
|
|
91
|
+
herethere/pythonhere:latest
|
|
92
|
+
|
|
93
|
+
The command exposes the Jupyter server on host port ``8888``. Jupyter logs are
|
|
94
|
+
printed in the terminal and include a URL such as
|
|
95
|
+
``http://127.0.0.1:8888/?token=...``. Open this URL in a browser to use the
|
|
96
|
+
local Jupyter environment.
|
|
97
|
+
|
|
98
|
+
Files in ``/home/jovyan/work`` inside the container are stored in the local
|
|
99
|
+
``work`` directory.
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
Run a local Jupyter environment without Docker
|
|
103
|
+
----------------------------------------------
|
|
104
|
+
|
|
105
|
+
Commands to run locally::
|
|
106
|
+
|
|
107
|
+
pip install pythonhere jupyter
|
|
108
|
+
jupyter notebook
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
Build Android app
|
|
112
|
+
-----------------
|
|
113
|
+
|
|
114
|
+
To build with `Buildozer <https://github.com/kivy/buildozer>`_, run in the source directory::
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
buildozer android debug
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
Related resources
|
|
121
|
+
-----------------
|
|
122
|
+
|
|
123
|
+
* `Kivy Remote Shell <https://github.com/kivy/kivy-remote-shell>`_ : Remote SSH+Python interactive shell application
|
|
124
|
+
* `herethere <https://github.com/b3b/herethere>`_ : Library for interactive code execution, based on AsyncSSH
|
|
125
|
+
* `AsyncSSH <https://github.com/ronf/asyncssh>`_ : Asynchronous SSH for Python
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
PythonHere
|
|
2
|
+
==========
|
|
3
|
+
|
|
4
|
+
.. start-badges
|
|
5
|
+
.. image:: https://img.shields.io/pypi/status/pythonhere
|
|
6
|
+
:target: https://pypi.python.org/pypi/pythonhere
|
|
7
|
+
:alt: Status
|
|
8
|
+
.. image:: https://img.shields.io/pypi/v/pythonhere.svg
|
|
9
|
+
:target: https://pypi.python.org/pypi/pythonhere
|
|
10
|
+
:alt: Latest version on PyPi
|
|
11
|
+
.. image:: https://img.shields.io/docker/v/herethere/pythonhere?color=%23FFD43B&label=Docker%20Image
|
|
12
|
+
:target: https://hub.docker.com/r/herethere/pythonhere
|
|
13
|
+
:alt: Docker Image Version (latest by date)
|
|
14
|
+
.. image:: https://img.shields.io/pypi/pyversions/pythonhere.svg
|
|
15
|
+
:target: https://pypi.python.org/pypi/pythonhere
|
|
16
|
+
:alt: Supported Python versions
|
|
17
|
+
.. image:: https://github.com/b3b/pythonhere/actions/workflows/tests.yml/badge.svg?branch=master
|
|
18
|
+
:target: https://github.com/b3b/pythonhere/actions/workflows/tests.yml?query=branch%3Amaster
|
|
19
|
+
:alt: CI Status
|
|
20
|
+
.. image:: https://codecov.io/github/b3b/pythonhere/coverage.svg?branch=master
|
|
21
|
+
:target: https://codecov.io/github/b3b/pythonhere?branch=master
|
|
22
|
+
:alt: Code coverage Status
|
|
23
|
+
.. end-badges
|
|
24
|
+
|
|
25
|
+
*PythonHere* lets you run Python code from a local `Jupyter <https://jupyter.org/>`_
|
|
26
|
+
notebook inside a remote `Kivy <https://kivy.org>`_ app.
|
|
27
|
+
|
|
28
|
+
PythonHere has two parts:
|
|
29
|
+
|
|
30
|
+
* *Here* is the remote/server side. It runs a Python environment with a Kivy GUI,
|
|
31
|
+
for example on Android, Raspberry Pi, or another machine.
|
|
32
|
+
* *%there* is the local/client side. It is a Jupyter magic command for running
|
|
33
|
+
code interactively in the remote PythonHere environment.
|
|
34
|
+
|
|
35
|
+
This makes PythonHere useful as a live Python/Kivy playground, and as a way to
|
|
36
|
+
inspect or control a Python app running remotely.
|
|
37
|
+
|
|
38
|
+
Project documentation: https://herethere.me/pythonhere
|
|
39
|
+
|
|
40
|
+
.. image:: https://raw.githubusercontent.com/b3b/pythonhere/master/docs/description.png
|
|
41
|
+
:alt: Project description
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
Install the Android app
|
|
45
|
+
-----------------------
|
|
46
|
+
|
|
47
|
+
Ready-to-use *PythonHere* APKs are available from the `GitHub Releases <https://github.com/b3b/pythonhere/releases>`_ page.
|
|
48
|
+
|
|
49
|
+
For APK provenance and signing checks, see `Android APK verification <https://github.com/b3b/pythonhere/blob/master/docs/android-apk-verification.rst>`_.
|
|
50
|
+
For a list of Python packages included in the Android build, see `buildozer.spec <https://github.com/b3b/pythonhere/blob/master/buildozer.spec>`_.
|
|
51
|
+
|
|
52
|
+
Start a local Jupyter environment with Docker
|
|
53
|
+
---------------------------------------------
|
|
54
|
+
|
|
55
|
+
The Docker image is based on `Jupyter Docker Stacks <https://jupyter-docker-stacks.readthedocs.io/en/latest/>`_
|
|
56
|
+
and includes *PythonHere* with usage examples.
|
|
57
|
+
|
|
58
|
+
Example command to start the Docker container::
|
|
59
|
+
|
|
60
|
+
docker run \
|
|
61
|
+
--rm \
|
|
62
|
+
-p 8888:8888 \
|
|
63
|
+
--user root \
|
|
64
|
+
-e CHOWN_EXTRA=/home/jovyan/work \
|
|
65
|
+
-e CHOWN_EXTRA_OPTS='-R' \
|
|
66
|
+
-v "$(pwd)/work":/home/jovyan/work \
|
|
67
|
+
herethere/pythonhere:latest
|
|
68
|
+
|
|
69
|
+
The command exposes the Jupyter server on host port ``8888``. Jupyter logs are
|
|
70
|
+
printed in the terminal and include a URL such as
|
|
71
|
+
``http://127.0.0.1:8888/?token=...``. Open this URL in a browser to use the
|
|
72
|
+
local Jupyter environment.
|
|
73
|
+
|
|
74
|
+
Files in ``/home/jovyan/work`` inside the container are stored in the local
|
|
75
|
+
``work`` directory.
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
Run a local Jupyter environment without Docker
|
|
79
|
+
----------------------------------------------
|
|
80
|
+
|
|
81
|
+
Commands to run locally::
|
|
82
|
+
|
|
83
|
+
pip install pythonhere jupyter
|
|
84
|
+
jupyter notebook
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
Build Android app
|
|
88
|
+
-----------------
|
|
89
|
+
|
|
90
|
+
To build with `Buildozer <https://github.com/kivy/buildozer>`_, run in the source directory::
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
buildozer android debug
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
Related resources
|
|
97
|
+
-----------------
|
|
98
|
+
|
|
99
|
+
* `Kivy Remote Shell <https://github.com/kivy/kivy-remote-shell>`_ : Remote SSH+Python interactive shell application
|
|
100
|
+
* `herethere <https://github.com/b3b/herethere>`_ : Library for interactive code execution, based on AsyncSSH
|
|
101
|
+
* `AsyncSSH <https://github.com/ronf/asyncssh>`_ : Asynchronous SSH for Python
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=70", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pythonhere"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Here is the Kivy based app to run code from the Jupyter magic %there"
|
|
9
|
+
readme = { file = "README.rst", content-type = "text/x-rst" }
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "b3b", email = "ash.b3b@gmail.com" },
|
|
14
|
+
]
|
|
15
|
+
keywords = ["android", "ipython", "jupyter", "magic", "kivy"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Programming Language :: Python :: 3.10",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
22
|
+
"Programming Language :: Python :: 3.14",
|
|
23
|
+
]
|
|
24
|
+
dependencies = [
|
|
25
|
+
"herethere[magic]>=0.1.0",
|
|
26
|
+
"ipython",
|
|
27
|
+
"ipywidgets",
|
|
28
|
+
"Pillow",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[dependency-groups]
|
|
32
|
+
dev = [
|
|
33
|
+
{ include-group = "docker" },
|
|
34
|
+
"build",
|
|
35
|
+
"codecov",
|
|
36
|
+
"docutils",
|
|
37
|
+
"ifaddr",
|
|
38
|
+
"kivy==2.3.1",
|
|
39
|
+
"nest-asyncio2==1.7.2",
|
|
40
|
+
"pylint",
|
|
41
|
+
"pytest",
|
|
42
|
+
"pytest-asyncio",
|
|
43
|
+
"pytest-cov",
|
|
44
|
+
"pytest-mock",
|
|
45
|
+
"ruff",
|
|
46
|
+
"twine",
|
|
47
|
+
]
|
|
48
|
+
docker = [
|
|
49
|
+
"jupytext==1.19.3",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
[project.urls]
|
|
53
|
+
Homepage = "https://github.com/b3b/ipython-pythonhere"
|
|
54
|
+
Changelog = "https://github.com/b3b/pythonhere/blob/master/CHANGELOG.rst"
|
|
55
|
+
|
|
56
|
+
[tool.uv]
|
|
57
|
+
environments = [
|
|
58
|
+
"sys_platform == 'linux'",
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
[tool.pytest.ini_options]
|
|
62
|
+
asyncio_mode = "auto"
|
|
63
|
+
|
|
64
|
+
[tool.setuptools]
|
|
65
|
+
packages = [
|
|
66
|
+
"pythonhere",
|
|
67
|
+
"pythonhere.magic_here",
|
|
68
|
+
"pythonhere.ui_here",
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
[tool.setuptools.dynamic]
|
|
72
|
+
version = { attr = "pythonhere.version_here.__version__" }
|
|
73
|
+
|
|
74
|
+
[tool.setuptools.package-data]
|
|
75
|
+
pythonhere = [
|
|
76
|
+
"*.kv",
|
|
77
|
+
"data/logo/*.png",
|
|
78
|
+
"ui_here/*.kv",
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
[tool.ruff]
|
|
82
|
+
line-length = 88
|
|
83
|
+
target-version = "py310"
|
|
84
|
+
|
|
85
|
+
[tool.ruff.lint]
|
|
86
|
+
select = [
|
|
87
|
+
"E", # pycodestyle errors
|
|
88
|
+
"F", # pyflakes
|
|
89
|
+
"W", # pycodestyle warnings
|
|
90
|
+
"I", # import sorting
|
|
91
|
+
"UP", # pyupgrade
|
|
92
|
+
"B", # flake8-bugbear
|
|
93
|
+
"TRY", # exception handling checks
|
|
94
|
+
"PL", # pylint-style checks supported by Ruff
|
|
95
|
+
]
|
|
96
|
+
ignore = [
|
|
97
|
+
"PLC0207", # keep simple last-part string splits when they are clearer
|
|
98
|
+
"PLC0415", # allow delayed Kivy/Android imports that control side effects
|
|
99
|
+
"TRY002", # keep existing broad app-facing exceptions for now
|
|
100
|
+
"TRY003", # allow direct exception messages in this small app
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
[tool.ruff.lint.per-file-ignores]
|
|
104
|
+
"tests/**/*.py" = [
|
|
105
|
+
"PLR0913", # parametrized tests naturally pass several fixtures/values
|
|
106
|
+
"PLR2004", # literal expected values are readable in tests
|
|
107
|
+
"PLW0603", # tests may intentionally exercise global namespace behavior
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
[tool.ruff.format]
|
|
111
|
+
quote-style = "double"
|
|
112
|
+
indent-style = "space"
|
|
113
|
+
|
|
114
|
+
[tool.pylint.main]
|
|
115
|
+
fail-under = 10.0
|
|
116
|
+
ignore = ["migrations"]
|
|
117
|
+
py-version = "3.10"
|
|
118
|
+
|
|
119
|
+
[tool.pylint."messages control"]
|
|
120
|
+
disable = [
|
|
121
|
+
"attribute-defined-outside-init",
|
|
122
|
+
"bad-inline-option",
|
|
123
|
+
"broad-exception-caught",
|
|
124
|
+
"broad-exception-raised",
|
|
125
|
+
"deprecated-pragma",
|
|
126
|
+
"duplicate-code",
|
|
127
|
+
"file-ignored",
|
|
128
|
+
"import-outside-toplevel",
|
|
129
|
+
"import-error",
|
|
130
|
+
"inconsistent-return-statements",
|
|
131
|
+
"invalid-name",
|
|
132
|
+
"locally-disabled",
|
|
133
|
+
"logging-too-few-args",
|
|
134
|
+
"missing-function-docstring",
|
|
135
|
+
"missing-module-docstring",
|
|
136
|
+
"no-member",
|
|
137
|
+
"possibly-used-before-assignment",
|
|
138
|
+
"protected-access",
|
|
139
|
+
"raw-checker-failed",
|
|
140
|
+
"suppressed-message",
|
|
141
|
+
"too-few-public-methods",
|
|
142
|
+
"too-many-instance-attributes",
|
|
143
|
+
"unnecessary-ellipsis",
|
|
144
|
+
"unused-argument",
|
|
145
|
+
"unused-wildcard-import",
|
|
146
|
+
"use-symbolic-message-instead",
|
|
147
|
+
"useless-suppression",
|
|
148
|
+
"wildcard-import",
|
|
149
|
+
"wrong-import-order",
|
|
150
|
+
]
|
|
151
|
+
enable = ["c-extension-no-member"]
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
"""Android specific functions."""
|
|
2
|
+
|
|
2
3
|
# pylint: disable=invalid-name,import-error,import-outside-toplevel
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
from typing import Optional
|
|
5
4
|
import uuid
|
|
5
|
+
from pathlib import Path
|
|
6
6
|
|
|
7
7
|
from android import activity as android_activity
|
|
8
8
|
from jnius import autoclass, cast
|
|
9
9
|
from kivy.logger import Logger
|
|
10
10
|
|
|
11
|
-
|
|
12
11
|
Context = autoclass("android.content.Context")
|
|
13
12
|
Icon = autoclass("android.graphics.drawable.Icon")
|
|
14
13
|
Intent = autoclass("android.content.Intent")
|
|
@@ -23,7 +22,7 @@ def get_current_intent() -> Intent:
|
|
|
23
22
|
return PythonActivity.mActivity.getIntent()
|
|
24
23
|
|
|
25
24
|
|
|
26
|
-
def get_startup_script(intent: None = None) ->
|
|
25
|
+
def get_startup_script(intent: None = None) -> str | None:
|
|
27
26
|
"""Return script entrypoint that was passed to a given, or current, intent."""
|
|
28
27
|
if not intent:
|
|
29
28
|
intent = get_current_intent()
|
|
@@ -62,7 +61,7 @@ def bind_run_script_on_new_intent():
|
|
|
62
61
|
def create_shortcut_icon() -> Icon:
|
|
63
62
|
"""Create icon to use for a shurtcut."""
|
|
64
63
|
activity = PythonActivity.mActivity
|
|
65
|
-
Drawable = autoclass("{}.R$drawable"
|
|
64
|
+
Drawable = autoclass(f"{activity.getPackageName()}.R$drawable")
|
|
66
65
|
context = cast("android.content.Context", activity.getApplicationContext())
|
|
67
66
|
return Icon.createWithResource(context, Drawable.icon)
|
|
68
67
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<-UnhandledExceptionPopupHere>:
|
|
2
|
+
title: "Unhandled Exception catched"
|
|
3
|
+
BoxLayout:
|
|
4
|
+
orientation: 'vertical'
|
|
5
|
+
padding: 10
|
|
6
|
+
spacing: 20
|
|
7
|
+
Label:
|
|
8
|
+
size_hint_y: None
|
|
9
|
+
font_size: '18sp'
|
|
10
|
+
height: '24sp'
|
|
11
|
+
text: 'Exception details: '
|
|
12
|
+
ScrollView:
|
|
13
|
+
CodeInput:
|
|
14
|
+
id: catched_exception_code_input_here
|
|
15
|
+
text: root.message
|
|
16
|
+
size_hint: 1, None
|
|
17
|
+
height: self.minimum_height
|
|
18
|
+
Button:
|
|
19
|
+
size_hint_y: None
|
|
20
|
+
height: '40sp'
|
|
21
|
+
text: 'OK, continue'
|
|
22
|
+
on_press: root.dismiss()
|
|
@@ -1,46 +1,26 @@
|
|
|
1
1
|
"""App exceptions manager."""
|
|
2
|
+
|
|
2
3
|
import asyncio
|
|
3
4
|
import traceback
|
|
4
|
-
from
|
|
5
|
+
from pathlib import Path
|
|
5
6
|
|
|
6
7
|
from kivy.base import (
|
|
7
8
|
ExceptionHandler,
|
|
8
9
|
ExceptionManager,
|
|
9
10
|
)
|
|
10
11
|
from kivy.clock import Clock
|
|
11
|
-
from kivy.properties import StringProperty # pylint: disable=no-name-in-module
|
|
12
12
|
from kivy.lang import Builder
|
|
13
13
|
from kivy.logger import Logger
|
|
14
|
+
from kivy.properties import StringProperty # pylint: disable=no-name-in-module
|
|
14
15
|
from kivy.uix.popup import Popup
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
def load_exception_popup_style():
|
|
18
19
|
"""Load KV rules for `UnhandledExceptionPopupHere`."""
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
orientation: 'vertical'
|
|
24
|
-
padding: 10
|
|
25
|
-
spacing: 20
|
|
26
|
-
Label:
|
|
27
|
-
size_hint_y: None
|
|
28
|
-
font_size: '18sp'
|
|
29
|
-
height: '24sp'
|
|
30
|
-
text: 'Exception details: '
|
|
31
|
-
ScrollView:
|
|
32
|
-
CodeInput:
|
|
33
|
-
id: catched_exception_code_input_here
|
|
34
|
-
text: root.message
|
|
35
|
-
size_hint: 1, None
|
|
36
|
-
height: self.minimum_height
|
|
37
|
-
Button:
|
|
38
|
-
size_hint_y: None
|
|
39
|
-
height: '40sp'
|
|
40
|
-
text: 'OK, continue'
|
|
41
|
-
on_press: root.dismiss()
|
|
42
|
-
"""
|
|
43
|
-
)
|
|
20
|
+
kv_path = str(Path(__file__).with_suffix(".kv"))
|
|
21
|
+
|
|
22
|
+
if kv_path not in Builder.files:
|
|
23
|
+
Builder.load_file(kv_path)
|
|
44
24
|
|
|
45
25
|
|
|
46
26
|
class ErrorMessageOnException(ExceptionHandler):
|
|
@@ -48,9 +28,9 @@ class ErrorMessageOnException(ExceptionHandler):
|
|
|
48
28
|
|
|
49
29
|
def handle_exception(self, exception) -> int:
|
|
50
30
|
"""Handle a exception."""
|
|
51
|
-
Logger.exception("Unhandled Exception catched")
|
|
52
31
|
if isinstance(exception, (asyncio.CancelledError, KeyboardInterrupt)):
|
|
53
32
|
return ExceptionManager.RAISE
|
|
33
|
+
Logger.exception("Unhandled Exception catched")
|
|
54
34
|
show_exception_popup()
|
|
55
35
|
return ExceptionManager.PASS
|
|
56
36
|
|
|
@@ -63,10 +43,14 @@ class UnhandledExceptionPopupHere(Popup):
|
|
|
63
43
|
|
|
64
44
|
def install_exception_handler():
|
|
65
45
|
"""Install `ErrorMessageOnException` exception handler."""
|
|
66
|
-
|
|
46
|
+
if not any(
|
|
47
|
+
isinstance(handler, ErrorMessageOnException)
|
|
48
|
+
for handler in ExceptionManager.handlers
|
|
49
|
+
):
|
|
50
|
+
ExceptionManager.add_handler(ErrorMessageOnException())
|
|
67
51
|
|
|
68
52
|
|
|
69
|
-
def show_exception_popup(exc:
|
|
53
|
+
def show_exception_popup(exc: Exception | None = None):
|
|
70
54
|
"""Show exception popup."""
|
|
71
55
|
load_exception_popup_style()
|
|
72
56
|
if exc:
|
|
@@ -4,11 +4,10 @@
|
|
|
4
4
|
from base64 import b64decode
|
|
5
5
|
from io import BytesIO, StringIO
|
|
6
6
|
|
|
7
|
-
from PIL import Image as PILImage
|
|
8
|
-
from IPython.display import display
|
|
9
7
|
import click
|
|
10
|
-
from herethere.there.commands import
|
|
11
|
-
|
|
8
|
+
from herethere.there.commands import there_code_shortcut, there_group
|
|
9
|
+
from IPython.display import display
|
|
10
|
+
from PIL import Image as PILImage
|
|
12
11
|
|
|
13
12
|
KV_COMMAND_TEMPLATE = r"""
|
|
14
13
|
from window_here import load_kv_string
|
|
@@ -67,7 +66,9 @@ def screenshot(ctx, width, output):
|
|
|
67
66
|
img = PILImage.open(BytesIO(data)).convert("RGB")
|
|
68
67
|
if width:
|
|
69
68
|
height = int(width * img.size[1] // img.size[0])
|
|
70
|
-
|
|
69
|
+
resampling = getattr(PILImage, "Resampling", PILImage)
|
|
70
|
+
resample_filter = getattr(resampling, "LANCZOS", PILImage.LANCZOS)
|
|
71
|
+
img = img.resize((width, height), resample_filter)
|
|
71
72
|
|
|
72
73
|
if output:
|
|
73
74
|
img.save(output)
|