pythonhere 0.1.4__py3-none-any.whl → 0.2.0__py3-none-any.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.
pythonhere/server_here.py CHANGED
@@ -1,12 +1,12 @@
1
1
  """SSH server."""
2
+
2
3
  import asyncio
3
4
  from pathlib import Path
4
5
 
6
+ from exception_manager_here import show_exception_popup
7
+ from herethere.here.server import ServerConfig, SSHServerHere, start_server
5
8
  from kivy.app import App
6
9
  from kivy.logger import Logger
7
- from herethere.here.server import SSHServerHere, ServerConfig, start_server
8
-
9
- from exception_manager_here import show_exception_popup
10
10
 
11
11
 
12
12
  class PythonHereServer(SSHServerHere):
@@ -21,28 +21,31 @@ class PythonHereServer(SSHServerHere):
21
21
  async def run_ssh_server(app):
22
22
  """Start and run SSH server."""
23
23
  Logger.debug("PythonHere: wait for %here settings")
24
- try:
25
- await app.ssh_server_config_ready.wait()
26
- except asyncio.CancelledError:
27
- return
28
-
29
- config = ServerConfig(
30
- host="",
31
- chroot=app.upload_dir,
32
- key_path=Path("./key.rsa").resolve(),
33
- **app.get_pythonhere_config(),
34
- )
35
-
36
- try:
37
- server = await start_server(
38
- config, namespace=app.ssh_server_namespace, server_factory=PythonHereServer
39
- )
40
- app.ssh_server_started.set()
41
- except Exception as exc:
42
- Logger.error("PythonHere: SSH server start error")
43
- Logger.exception(exc)
44
- show_exception_popup(exc)
45
- return
24
+ while not app.ssh_server_started.is_set():
25
+ try:
26
+ await app.ssh_server_config_ready.wait()
27
+ except asyncio.CancelledError:
28
+ return
29
+
30
+ try:
31
+ config = ServerConfig(
32
+ host="",
33
+ chroot=app.upload_dir,
34
+ key_path=Path("./key.rsa").resolve(),
35
+ **app.get_pythonhere_config(),
36
+ )
37
+ server = await start_server(
38
+ config,
39
+ namespace=app.ssh_server_namespace,
40
+ server_factory=PythonHereServer,
41
+ )
42
+ except Exception as exc:
43
+ Logger.error("PythonHere: SSH server start error")
44
+ Logger.exception(exc)
45
+ show_exception_popup(exc)
46
+ app.ssh_server_config_ready.clear()
47
+ else:
48
+ app.ssh_server_started.set()
46
49
 
47
50
  try:
48
51
  await server.wait_closed()
@@ -50,7 +53,7 @@ async def run_ssh_server(app):
50
53
  Logger.info("PythonHere: SSH server task canceled")
51
54
  await server.stop()
52
55
  except Exception as exc:
53
- Logger.errror("PythonHere: SSH server stop by exception")
56
+ Logger.error("PythonHere: SSH server stop by exception")
54
57
  Logger.exception(exc)
55
58
  show_exception_popup(exc)
56
59
  Logger.info("PythonHere: SSH server closed")
@@ -0,0 +1,8 @@
1
+ #:kivy 1.0
2
+ #:import App kivy.app.App
3
+
4
+ <ScreenActionButton@ActionToggleButton>:
5
+ group: "screen"
6
+ screen: ""
7
+ allow_no_selection: False
8
+ on_release: App.get_running_app().root.switch_screen(self.screen)
@@ -0,0 +1,14 @@
1
+ #:kivy 1.0
2
+ # Common settings
3
+
4
+ #:import hex kivy.utils.get_color_from_hex
5
+ #:import sp kivy.metrics.sp
6
+
7
+ #:set bg_color "#EEEEEE"
8
+ #:set pallete ["#646464", "#306998", "#4B8BBE", "#FFD43B", "#FFE873"]
9
+ #:set tc lambda text, index: f"[color={pallete[index]}]{text}[/color]"
10
+
11
+
12
+ <Label>:
13
+ font_name: "DejaVuSans"
14
+ markup: True
@@ -0,0 +1,32 @@
1
+ #:kivy 1.0
2
+ #:import ConnectionAddressLabel ui_here.connection_address_here.ConnectionAddressLabel
3
+ #:import ConnectionAddressInfoBox ui_here.connection_address_here.ConnectionAddressInfoBox
4
+
5
+ <ConnectionAddressLabel>:
6
+ text: f"{tc('↳', 3)} {tc(self.address, 2)} ({self.interface})"
7
+ size_hint: 1, None
8
+ text_size: self.size
9
+ height: self.texture_size[1]
10
+ font_size: "20sp"
11
+
12
+ <ConnectionAddressInfoBox>:
13
+ cols: 1
14
+ size_hint: 1, 1
15
+ padding: '20sp', 0, 0, 0
16
+
17
+ Label:
18
+ text: f"Server is running.\nConnect {tc('here', 3)} via"
19
+ size_hint: 1, None
20
+ text_size: self.size
21
+ height: "80sp"
22
+ font_size: "30sp"
23
+
24
+ ScrollView:
25
+ do_scroll_x: False
26
+ size_hint: 1, 1
27
+
28
+ BoxLayout:
29
+ id: address_list
30
+ orientation: "vertical"
31
+ size_hint: 1, None
32
+ height: self.minimum_size[1]
@@ -1,10 +1,10 @@
1
1
  """Connection information widgets."""
2
+
2
3
  from kivy.clock import Clock, mainthread
3
4
  from kivy.logger import Logger
4
5
  from kivy.properties import StringProperty # pylint: disable=no-name-in-module
5
- from kivy.uix.label import Label
6
6
  from kivy.uix.gridlayout import GridLayout
7
-
7
+ from kivy.uix.label import Label
8
8
  from network_here import get_all_available_ipv4_adrresses
9
9
 
10
10
 
@@ -1,4 +1,5 @@
1
1
  """Layouts."""
2
+
2
3
  from kivy.uix.boxlayout import BoxLayout
3
4
  from kivy.uix.togglebutton import ToggleButton
4
5
 
@@ -0,0 +1,57 @@
1
+ #:import FallOutTransition kivy.uix.screenmanager.FallOutTransition
2
+ #:import App kivy.app.App
3
+
4
+ <LoadingImage@Image>:
5
+ source: "data/images/image-loading.zip"
6
+ allow_stretch: True
7
+ pos_hint: {'center_x': 0.5, 'center_y': 0.4}
8
+ size_hint: None, None
9
+ size: sp(100), sp(100)
10
+
11
+ <StackLabel@Label>:
12
+ size_hint: None, None
13
+ font_size: "20sp"
14
+ size: self.texture_size
15
+
16
+ <ServerNotConfigured@Screen>:
17
+ StackLayout:
18
+ orientation: "lr-tb"
19
+ padding: sp(20), sp(20), 0, 0
20
+ StackLabel:
21
+ text: "To start "
22
+ StackLabel:
23
+ text: f"{tc('Python', 1)}{tc('here', 3)}, "
24
+ StackLabel:
25
+ text: "you "
26
+ StackLabel:
27
+ text: "need to "
28
+ StackLabel:
29
+ text: "edit the "
30
+ Button:
31
+ text: "Settings"
32
+ font_size: "20sp"
33
+ size_hint: None, None
34
+ width: self.texture_size[0] + sp(20)
35
+ height: sp(30)
36
+ on_release: App.get_running_app().root.switch_screen(ScreenName.settings)
37
+ StackLabel:
38
+ text: " section."
39
+
40
+ <StartingServerScreen@Screen>:
41
+ Label:
42
+ text: f"Waiting {tc('Python', 1)}{tc('here', 3)} to start"
43
+ font_size: "30sp"
44
+ LoadingImage:
45
+
46
+ <ServerScreenManager>:
47
+ transition: FallOutTransition()
48
+ Screen:
49
+ LoadingImage:
50
+ ServerNotConfigured:
51
+ name: ServerState.not_configured
52
+ Screen:
53
+ StartingServerScreen:
54
+ name: ServerState.starting_server
55
+ Screen:
56
+ name: ServerState.ready
57
+ ConnectionAddressInfoBox:
@@ -1,9 +1,9 @@
1
1
  """%here server screen."""
2
- from kivy.app import App
3
- from kivy.clock import Clock
4
- from kivy.uix.screenmanager import ScreenManager
5
2
 
6
3
  from enum_here import ServerState
4
+ from kivy.app import App
5
+ from kivy.clock import Clock, mainthread
6
+ from kivy.uix.screenmanager import ScreenManager
7
7
 
8
8
 
9
9
  class ServerScreenManager(ScreenManager):
@@ -13,6 +13,7 @@ class ServerScreenManager(ScreenManager):
13
13
  super().__init__(*args, **kwargs)
14
14
  self.update_event = Clock.schedule_interval(self.update, 0.5)
15
15
 
16
+ @mainthread
16
17
  def update(self, _=None):
17
18
  """Determines server state, and switch to appropriate screen."""
18
19
  app = App.get_running_app()
@@ -0,0 +1,31 @@
1
+ #:kivy 1.0
2
+ #:import App kivy.app.App
3
+ #:import SettingPassword ui_here.settings_here.SettingPassword
4
+
5
+ <SettingPassword>:
6
+ PasswordLabel:
7
+ pos: root.pos
8
+ font_size: "15sp"
9
+ text: '*' * len(root.value or '')
10
+
11
+ <SettingButton>:
12
+ size_hint: 1, None
13
+ height: sp(60)
14
+ opacity: 1 if self.active else 0
15
+
16
+ Button:
17
+ size_hint: None, None
18
+ width: self.texture_size[0] + sp(20)
19
+ height: sp(40)
20
+ halign: "center"
21
+ text: root.title
22
+ disabled: not root.active
23
+ on_release: root.on_release()
24
+
25
+
26
+ <StartServersettingButton>:
27
+ title: f"{tc('▶', 3)} Start the server"
28
+
29
+
30
+ <ShowPolicySettingButton>:
31
+ title: "Open privacy\n policy in browser"
@@ -1,6 +1,7 @@
1
1
  """Settings panel widgets."""
2
- from typing import Any, Dict
2
+
3
3
  import webbrowser
4
+ from typing import Any
4
5
 
5
6
  from kivy.app import App
6
7
  from kivy.config import Config
@@ -11,11 +12,9 @@ from kivy.properties import ( # pylint: disable=no-name-in-module
11
12
  )
12
13
  from kivy.uix.anchorlayout import AnchorLayout
13
14
  from kivy.uix.label import Label
15
+ from kivy.uix.popup import Popup
14
16
  from kivy.uix.settings import Settings, SettingString
15
17
 
16
- from enum_here import ScreenName
17
-
18
-
19
18
  SETTINGS_HERE = """
20
19
  [
21
20
  {
@@ -97,8 +96,18 @@ class StartServerSettingButton(SettingButton):
97
96
  def on_release(self):
98
97
  """Start the server."""
99
98
  app = App.get_running_app()
99
+ if app.ssh_server_started.is_set():
100
+ popup = Popup(
101
+ title="Server is already started",
102
+ content=Label(
103
+ text="New settings takes effect\n after application restart."
104
+ ),
105
+ size_hint=(None, None),
106
+ size=("250sp", "250sp"),
107
+ )
108
+ popup.open()
109
+ return
100
110
  app.update_server_config_status()
101
- app.root.switch_screen(ScreenName.here)
102
111
 
103
112
 
104
113
  class ShowPolicySettingButton(SettingButton):
@@ -128,7 +137,7 @@ class SettingsHere(Settings):
128
137
  self.add_kivy_panel()
129
138
  self.add_json_panel("Privacy Policy", Config, data=SETTINGS_PRIVACY)
130
139
 
131
- def get_pythonhere_config(self) -> Dict[str, Any]:
140
+ def get_pythonhere_config(self) -> dict[str, Any]:
132
141
  """Extract server parts of the config."""
133
142
  return {
134
143
  "username": Config.get("pythonhere", "username"),
@@ -1 +1 @@
1
- __version__ = "0.1.4"
1
+ __version__ = "0.2.0"
pythonhere/window_here.py CHANGED
@@ -1,17 +1,20 @@
1
1
  """Utilities for working with Kivy window."""
2
- from base64 import b64encode
2
+
3
3
  import os
4
- from pathlib import Path
5
4
  import time
5
+ from base64 import b64encode
6
+ from pathlib import Path
6
7
 
7
8
  from kivy.app import App
8
- from kivy.core.window import Window
9
9
  from kivy.lang import Builder
10
10
  from kivy.uix.boxlayout import BoxLayout
11
11
 
12
12
 
13
13
  def reset_window_environment() -> BoxLayout:
14
14
  """Remove PythonHere app widgets and styles."""
15
+ # import Window inside function to avoid early loading of the app config
16
+ from kivy.core.window import Window # pylint: disable=import-outside-toplevel
17
+
15
18
  for widget in Window.children:
16
19
  widget.clear_widgets()
17
20
  Window.remove_widget(widget)
@@ -30,6 +33,8 @@ def unload_app_kv_styles():
30
33
 
31
34
  def load_kv_string(code: str, clear_style: bool):
32
35
  """Insert given rules into the Kivy Language Builder."""
36
+ from kivy.core.window import Window # pylint: disable=import-outside-toplevel
37
+
33
38
  app = App.get_running_app()
34
39
 
35
40
  if clear_style:
@@ -50,6 +55,8 @@ def load_kv_string(code: str, clear_style: bool):
50
55
 
51
56
  def encoded_screenshot() -> str:
52
57
  """Return base64 encoded displayed image."""
58
+ from kivy.core.window import Window # pylint: disable=import-outside-toplevel
59
+
53
60
  path = str(Path(f"screenshot_{time.time()}.png").resolve())
54
61
  Window.children[0].export_to_png(path)
55
62
  with open(path, "rb") as png_file:
@@ -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,33 @@
1
+ pythonhere/__init__.py,sha256=gkVrYFkF3klE1fripHpmTuZx8_BaVHWRRvvr6PK6XWE,212
2
+ pythonhere/android_here.py,sha256=imQCNkhAJYgT3gMeX25kd9cQzH5ZbeF5PlgP8e9sbl0,3316
3
+ pythonhere/enum_here.py,sha256=FPj3pBeXfpPwl4-LDdC-wmbaoiv4QdbKHkGoBfTXnTE,449
4
+ pythonhere/exception_manager_here.kv,sha256=FZNhQgVojSLcVxZ0vjAxAF915xCBP-3nldPXVczRzCE,656
5
+ pythonhere/exception_manager_here.py,sha256=-UYqGRbzkoyfF0-pLWbxaFGEAvAdaw6b8hkm_bMIKx8,1943
6
+ pythonhere/launcher_here.py,sha256=I5zBpN0P3hmhsZFOJemxQ9Q2k2am5zkfS6Vg0Svnl98,1274
7
+ pythonhere/main.py,sha256=7vAF6mznCr2JFxeXjm3-a6PN1abPt-loI8ZHncAAPp0,7237
8
+ pythonhere/network_here.py,sha256=e3FDlBcXPaTFlWaqW2_bcWctht-ifpFIvtOj0lO4S9w,1558
9
+ pythonhere/patches_here.py,sha256=zB7Ohbk5PIXt0imnnrV5Mtl-Y7jpD_p5IBPlijQcCCQ,1727
10
+ pythonhere/pythonhere.kv,sha256=x1xwiKvJAevqBhtXGLb_axIf-VRos4V_jM9Q2i44f2U,1453
11
+ pythonhere/server_here.py,sha256=ss4Alg4ySkI0aG58l8D2SQMXiGHJeK-hGUIIBrbQ6nE,1854
12
+ pythonhere/version_here.py,sha256=Zn1KFblwuFHiDRdRAiRnDBRkbPttWh44jKa5zG2ov0E,22
13
+ pythonhere/window_here.py,sha256=na47v7bgomAjb6VC_g35RwhzEtm5RCInQIuQK27zY8U,2023
14
+ pythonhere/data/logo/logo-128.png,sha256=4sitDJcVBHOU5UPxicmrzc6YqFY7_xtYrc_ULyrw9ks,4161
15
+ pythonhere/data/logo/logo-32.png,sha256=qanrIAt6vK_2BsCjCxth2B4vxBa0ONnpDlils7syUWE,1247
16
+ pythonhere/data/logo/logo-splash.png,sha256=-edmwKnkkpGP4RZ0AJYto5_BOy8NoISt5ftOEI8BQOY,4663
17
+ pythonhere/magic_here/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ pythonhere/magic_here/shortcuts.py,sha256=pdB_ET6Snl4DxusbyZPI1_G8jGzA8d35er60qQb_2cY,2499
19
+ pythonhere/ui_here/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
+ pythonhere/ui_here/actionbar_here.kv,sha256=cOjY4ByOyBDUbeS9kbI3JAhi_X3kJ3Pb5h4RL58urwU,214
21
+ pythonhere/ui_here/common_here.kv,sha256=vnNyDwAKKNbRKvh0QKMbTvR0jNDKiY8DdGRnoEEexSc,324
22
+ pythonhere/ui_here/connection_address_here.kv,sha256=T0E8WX6QVvFLB2QL4GP7g9uDwQt5ja7aAODUe8x1NUY,885
23
+ pythonhere/ui_here/connection_address_here.py,sha256=_NM2mJuXM2jgk9eXH8NEV6IxGvJX_fc3wuEq-n7BoLs,1160
24
+ pythonhere/ui_here/layout_here.py,sha256=4sOf4ELSeaJJQkBfgrkM0Cmf6A1bpYTYtZl5GDXGJZE,485
25
+ pythonhere/ui_here/server_screen_here.kv,sha256=x0Se8hmgjS57gFIPa1r2lf6yJchs3lXOrAAtWf6M5Io,1562
26
+ pythonhere/ui_here/server_screen_here.py,sha256=2zQv1YFmiKNxa__7UZDYbAAAwYFLoZPSZPhr7vjCAkU,925
27
+ pythonhere/ui_here/settings_here.kv,sha256=stMcDq8dCYjay4idK30_7EUu5edkMDAQVPv0H0GuAcM,710
28
+ pythonhere/ui_here/settings_here.py,sha256=7NflZBUqY2ANZaSEuubaX9wIKniqbekcNQkUbqhhmto,4093
29
+ pythonhere-0.2.0.dist-info/licenses/LICENSE,sha256=nW9_eVi3dSMOkr6xghsobAovBEJiffjl_5WjujJTa74,1071
30
+ pythonhere-0.2.0.dist-info/METADATA,sha256=s6EVWNzwY9n6PDwLpNX6kVrd55fGxGpba3j26LYz7cQ,4790
31
+ pythonhere-0.2.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
32
+ pythonhere-0.2.0.dist-info/top_level.txt,sha256=dvkfRGF1tFbkjXzD9vwqXTge1Znkv7ga5fRJy5yhJsE,11
33
+ pythonhere-0.2.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.36.2)
2
+ Generator: setuptools (82.0.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,139 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: pythonhere
3
- Version: 0.1.4
4
- Summary: Here is the Kivy based app to run code from the Jupyter magic %there
5
- Home-page: https://github.com/b3b/ipython-pythonhere
6
- Author: b3b
7
- Author-email: ash.b3b@gmail.com
8
- License: MIT
9
- Project-URL: Changelog, https://github.com/b3b/pythonhere/blob/master/CHANGELOG.rst
10
- Keywords: android ipython jupyter magic kivy
11
- Platform: UNKNOWN
12
- Classifier: Development Status :: 3 - Alpha
13
- Classifier: Programming Language :: Python :: 3.7
14
- Classifier: Programming Language :: Python :: 3.8
15
- Description-Content-Type: text/x-rst
16
- Requires-Dist: kivy (>=2.0.0)
17
- Requires-Dist: herethere (<0.2.0,>=0.1.0)
18
- Requires-Dist: ifaddr
19
- Requires-Dist: ipython
20
- Requires-Dist: ipywidgets
21
- Requires-Dist: nest-asyncio
22
- Requires-Dist: Pillow
23
- Provides-Extra: dev
24
- Requires-Dist: black ; extra == 'dev'
25
- Requires-Dist: codecov ; extra == 'dev'
26
- Requires-Dist: docutils ; extra == 'dev'
27
- Requires-Dist: flake8 ; extra == 'dev'
28
- Requires-Dist: jupytext ; extra == 'dev'
29
- Requires-Dist: pylint ; extra == 'dev'
30
- Requires-Dist: pytest ; extra == 'dev'
31
- Requires-Dist: pytest-asyncio ; extra == 'dev'
32
- Requires-Dist: pytest-cov ; extra == 'dev'
33
- Requires-Dist: pytest-mock ; extra == 'dev'
34
- Provides-Extra: docker
35
- Requires-Dist: jupytext (==1.7.1) ; extra == 'docker'
36
-
37
- PythonHere
38
- ==========
39
-
40
- .. start-badges
41
- .. image:: https://img.shields.io/pypi/status/pythonhere
42
- :target: https://pypi.python.org/pypi/pythonhere
43
- :alt: Status
44
- .. image:: https://img.shields.io/pypi/v/pythonhere.svg
45
- :target: https://pypi.python.org/pypi/pythonhere
46
- :alt: Latest version on PyPi
47
- .. image:: https://img.shields.io/docker/v/herethere/pythonhere?color=%23FFD43B&label=Docker%20Image
48
- :target: https://hub.docker.com/r/herethere/pythonhere
49
- :alt: Docker Image Version (latest by date)
50
- .. image:: https://img.shields.io/pypi/pyversions/pythonhere.svg
51
- :target: https://pypi.python.org/pypi/pythonhere
52
- :alt: Supported Python versions
53
- .. image:: https://github.com/b3b/pythonhere/workflows/ci/badge.svg?branch=master
54
- :target: https://github.com/b3b/pythonhere/actions?workflow=CI
55
- :alt: CI Status
56
- .. image:: https://codecov.io/github/b3b/pythonhere/coverage.svg?branch=master
57
- :target: https://codecov.io/github/b3b/pythonhere?branch=master
58
- :alt: Code coverage Status
59
- .. end-badges
60
-
61
- *Here* is the `Kivy <https://kivy.org>`_ based app to run Python code from the `Jupyter <https://jupyter.org/>`_ magic %there.
62
-
63
- - *Here* is a server part with the GUI interface. It could be Android, Raspberry Pi, some other remote device that being debugged.
64
- - And *%there* is a client - Jupyter magic command to run code interactively on remote device.
65
-
66
- This app could serve as a Python Kivy playground, for dynamic code execution from the PC.
67
-
68
- Project documentation: https://herethere.me
69
-
70
- .. image:: https://raw.githubusercontent.com/b3b/pythonhere/master/docs/description.png
71
- :alt: Project description
72
-
73
-
74
- Install on Android
75
- ------------------
76
-
77
- App is available on `Google Play <https://play.google.com/store/apps/details?id=me.herethere.pythonhere>`_.
78
-
79
- Ready-to-use *PythonHere* APKs are available in the `Releases <https://github.com/b3b/pythonhere/releases>`_ section.
80
-
81
- For a list of installed Python packages, see: `buildozer.spec <./buildozer.spec>`_.
82
-
83
-
84
- Quick Start with Docker
85
- -----------------------
86
-
87
- Docker image is based on `Jupyter Docker Stacks <https://jupyter-docker-stacks.readthedocs.io/en/latest/>`_, and includes installed *PythonHere* with usage examples.
88
-
89
- Example command to start the Docker container::
90
-
91
- docker run \
92
- --rm \
93
- -p 8888:8888 \
94
- -v "$(pwd)/work":/home/jovyan/work \
95
- herethere/pythonhere:latest
96
-
97
-
98
- Command will expose the Jupyter Notebook server on host port 8888. Jupyter logs appear in the terminal and include an URL to the notebook server: http://127.0.0.1:8888/?token=... . Visiting this URL in a browser loads the Jupyter Notebook dashboard page.
99
-
100
- Files from the directory **work** inside container, will be available in the host directory with the same name: **work**.
101
-
102
-
103
- Run with Docker Compose
104
- -----------------------
105
-
106
- Commands to run with Docker Compose, in the source directory:::
107
-
108
- cp docker-compose.yml.tmpl docker-compose.yml
109
- docker-compose up
110
-
111
-
112
- Run locally
113
- -----------
114
-
115
- Commands to run locally::
116
-
117
- pip install pythonhere
118
- jupyter notebook start
119
-
120
-
121
- Build Android app
122
- -----------------
123
-
124
- To build with `Buildozer <https://github.com/kivy/buildozer>`_, run in the source directory::
125
-
126
-
127
- buildozer android debug
128
-
129
-
130
-
131
- Related resources
132
- -----------------
133
-
134
- * `Kivy Remote Shell <https://github.com/kivy/kivy-remote-shell>`_ : Remote SSH+Python interactive shell application
135
- * `herethere <https://github.com/b3b/herethere>`_ : Library for interactive code execution, based on AsyncSSH
136
- * `AsyncSSH <https://github.com/ronf/asyncssh>`_ : Asynchronous SSH for Python
137
- * `Buildozer action <https://github.com/ArtemSBulgakov/buildozer-action>`_ : GitHub action that is used to build Android APK with Buildozer
138
-
139
-