Skip to content

Commit 1713e9c

Browse files
committed
use Kivy settings for %here server
1 parent f366bff commit 1713e9c

12 files changed

Lines changed: 191 additions & 37 deletions

pythonhere/enum_here.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"""Enums."""
2+
from enum import Enum
3+
4+
5+
class StrEnum(str, Enum):
6+
"""Base class for str enums."""
7+
8+
def __str__(self):
9+
return str(self.value)
10+
11+
12+
class ScreenName(StrEnum):
13+
"""Enum for root screen names."""
14+
15+
here = "here"
16+
settings = "settings"
17+
18+
19+
class ServerState(StrEnum):
20+
"""Enum for %here server state (screen name)."""
21+
22+
not_configured = "not_configured"
23+
starting_server = "starting_server"
24+
ready = "ready"

pythonhere/main.py

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
from kivy.app import App
55
from kivy.logger import Logger
6-
from kivy.uix.settings import Settings
76

7+
from enum_here import ScreenName
88
from herethere.here import ServerConfig, start_server
99
from patches_here import monkeypatch_kivy
1010

@@ -13,13 +13,17 @@
1313

1414
async def run_ssh_server(app):
1515
"""Start and run SSH server."""
16+
Logger.debug("Python Here: wait for %here settings")
17+
try:
18+
await app.ssh_server_config_ready.wait()
19+
except asyncio.CancelledError:
20+
return
21+
1622
config = ServerConfig(
1723
host="",
18-
port=8022,
19-
username="here",
20-
password="there",
2124
chroot=app.user_data_dir or "",
2225
key_path="./key.rsa",
26+
**app.get_pythonhere_config(),
2327
)
2428

2529
try:
@@ -48,15 +52,16 @@ class PythonHereApp(App):
4852
def __init__(self):
4953
super().__init__()
5054
self.server_task = None
55+
self.settings = None
56+
self.ssh_server_config_ready = asyncio.Event()
5157
self.ssh_server_started = asyncio.Event()
5258
self.ssh_server_namespace = {}
5359

5460
def build(self):
5561
"""Initialize application UI."""
56-
self.settings_cls = Settings
57-
5862
super().build()
59-
self.root.switch_screen("here")
63+
64+
self.settings = self.root.ids.settings
6065

6166
self.ssh_server_namespace.update(
6267
{
@@ -65,6 +70,10 @@ def build(self):
6570
}
6671
)
6772

73+
self.settings.bind(on_config_change=self.handle_config_change)
74+
self.update_server_config_status()
75+
self.root.switch_screen(ScreenName.here)
76+
6877
def run_app(self):
6978
"""Run application and SSH server tasks."""
7079
self.ssh_server_started = asyncio.Event()
@@ -84,6 +93,22 @@ async def async_run_app(self):
8493
if self.server_task:
8594
self.server_task.cancel()
8695

96+
def update_server_config_status(self):
97+
"""Check and update value of the `ssh_server_config_ready`."""
98+
if all(self.get_pythonhere_config().values()):
99+
self.ssh_server_config_ready.set()
100+
101+
def get_pythonhere_config(self):
102+
"""Return user settings for SSH server."""
103+
return self.settings.get_pythonhere_config()
104+
105+
def handle_config_change(
106+
self, settings, config, section, key, value
107+
): # pylint: disable=too-many-arguments, unused-argument
108+
"""Config change handler."""
109+
if section == "pythonhere":
110+
self.update_server_config_status()
111+
87112
def on_start(self):
88113
"""App start handler."""
89114
Logger.info("Python Here: app started")

pythonhere/pythonhere.kv

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
#:kivy 1.0
22
#:import RootLayout ui_here.layout_here.RootLayout
3+
#:import ScreenName enum_here.ScreenName
4+
#:import ServerState enum_here.ServerState
5+
#:import ServerScreenManager ui_here.server_screen_here.ServerScreenManager
36
#:include ui_here/common_here.kv
47
#:include ui_here/connection_address_here.kv
8+
#:include ui_here/server_screen_here.kv
59
#:include ui_here/settings_here.kv
610

711
RootLayout:
@@ -18,11 +22,11 @@ RootLayout:
1822
ScreenActionButton:
1923
id: open_here_action
2024
text: f"%{tc('H', 3)}ere"
21-
screen: "here"
25+
screen: ScreenName.here
2226
ScreenActionButton:
2327
id: open_settings_action
2428
text: f"{tc('S', 3)}ettings"
25-
screen: "settings"
29+
screen: ScreenName.settings
2630

2731
ActionButton:
2832
text: f"{tc('Q', 3)}uit"
@@ -33,10 +37,11 @@ RootLayout:
3337
Screen:
3438
Screen:
3539
id: here_screen
36-
name: "here"
37-
ConnectionAddressInfoBox:
38-
id: address_info
40+
name: ScreenName.here
41+
ServerScreenManager:
42+
id: here_screen_manager
3943
Screen:
4044
id: settings_screen
41-
name: "settings"
45+
name: ScreenName.settings
4246
SettingsHere:
47+
id: settings

pythonhere/ui_here/connection_address_here.kv

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@
1717
padding: '20sp', 0, 0, 0
1818

1919
Label:
20-
text: f"Connect {tc('here', 3)} via"
20+
text: f"Server is running.\nConnect {tc('here', 3)} via"
2121
size_hint: 1, None
2222
text_size: self.size
23-
height: self.texture_size[1]
23+
height: "80sp"
2424
font_size: "30sp"
2525

2626
ScrollView:
@@ -32,4 +32,3 @@
3232
orientation: "vertical"
3333
size_hint: 1, None
3434
height: self.minimum_size[1]
35-
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
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+
name: "not_configured"
18+
StackLayout:
19+
orientation: "lr-tb"
20+
padding: sp(20), 0, 0, 0
21+
StackLabel:
22+
text: "To start the "
23+
StackLabel:
24+
text: f"{tc('Python', 1)}{tc('here', 3)}, "
25+
StackLabel:
26+
text: "you "
27+
StackLabel:
28+
text: "need to "
29+
StackLabel:
30+
text: "edit the "
31+
Button:
32+
text: "Settings"
33+
font_size: "20sp"
34+
size_hint: None, None
35+
width: self.texture_size[0] + sp(20)
36+
height: sp(30)
37+
on_release: App.get_running_app().root.switch_screen(ScreenName.settings)
38+
StackLabel:
39+
text: " section."
40+
41+
<StartingServerScreen@Screen>:
42+
Label:
43+
text: f"Waiting {tc('Python', 1)}{tc('here', 3)} to start"
44+
font_size: "30sp"
45+
LoadingImage:
46+
47+
<ServerScreenManager>:
48+
app: app
49+
transition: FallOutTransition()
50+
Screen:
51+
LoadingImage:
52+
ServerNotConfigured:
53+
Screen:
54+
name: ServerState.not_configured
55+
StartingServerScreen:
56+
name: ServerState.starting_server
57+
Screen:
58+
name: ServerState.ready
59+
ConnectionAddressInfoBox:
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"""%here server screen."""
2+
from kivy.clock import Clock
3+
from kivy.uix.screenmanager import ScreenManager
4+
5+
from enum_here import ServerState
6+
7+
8+
class ServerScreenManager(ScreenManager):
9+
"""Screen manager for server %here section."""
10+
11+
def __init__(self, *args, **kwargs):
12+
super().__init__(*args, **kwargs)
13+
self.update_event = Clock.schedule_interval(self.update, 0.5)
14+
15+
def update(self, _=None):
16+
"""Determines server state, and switch to appropriate screen."""
17+
if self.app.ssh_server_config_ready.is_set():
18+
if self.app.ssh_server_started.is_set():
19+
self.current = ServerState.ready
20+
Clock.unschedule(self.update_event)
21+
else:
22+
self.current = ServerState.starting_server
23+
else:
24+
self.current = ServerState.not_configured

pythonhere/ui_here/settings_here.kv

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
#:kivy 1.0
22

33
#:import SettingPassword ui_here.settings_here.SettingPassword
4+
#:import App kivy.app.App
45

56
<ScreenActionButton@ActionToggleButton>:
67
group: "screen"
78
screen: ""
89
allow_no_selection: False
9-
on_release: app.root.switch_screen(self.screen)
10+
on_release: App.get_running_app().root.switch_screen(self.screen)
1011

1112

1213
<SettingPassword>:

pythonhere/ui_here/settings_here.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
"""Settings panel widgets."""
2+
from typing import Any, Dict
3+
24
from kivy.config import Config
35
from kivy.properties import ObjectProperty # pylint: disable=no-name-in-module
46
from kivy.uix.label import Label
@@ -9,26 +11,26 @@
911
[
1012
{
1113
"type": "title",
12-
"title": "SSH server"
14+
"title": "%here server"
1315
},
1416
{
1517
"type": "string",
16-
"title": "Login",
17-
"desc": "SSH login",
18+
"title": "Username",
19+
"desc": "Username to ask (THERE_USERNAME)",
1820
"section": "pythonhere",
19-
"key": "login"
21+
"key": "username"
2022
},
2123
{
2224
"type": "password",
2325
"title": "Password",
24-
"desc": "SSH password",
26+
"desc": "Password to ask (THERE_PASSWORD)",
2527
"section": "pythonhere",
2628
"key": "password"
2729
},
2830
{
2931
"type": "numeric",
3032
"title": "Port",
31-
"desc": "SSH server port number",
33+
"desc": "Server port number, to start on this device (THERE_PORT)",
3234
"section": "pythonhere",
3335
"key": "port"
3436
}
@@ -74,7 +76,15 @@ def __init__(self, *args, **kargs):
7476
self.register_type("password", SettingPassword)
7577

7678
Config.setdefaults(
77-
"pythonhere", {"login": "here", "password": "", "port": 8022}
79+
"pythonhere", {"username": "here", "password": "", "port": 8022}
7880
)
7981
self.add_json_panel("Python Here", Config, data=SETTINGS_HERE)
8082
self.add_kivy_panel()
83+
84+
def get_pythonhere_config(self) -> Dict[str, Any]:
85+
"""Extract server parts of the config."""
86+
return {
87+
"username": Config.get("pythonhere", "username"),
88+
"password": Config.get("pythonhere", "password"),
89+
"port": Config.getint("pythonhere", "port"),
90+
}

tests/config.ini

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[pythonhere]
2+
username = here
3+
password = there
4+
port = 8022

tests/conftest.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import nest_asyncio
44
import pytest
5+
from kivy.config import Config
6+
from kivy.core.window import Window
57

68
from herethere.everywhere import ConnectionConfig
79
from herethere.there.client import Client
@@ -10,7 +12,6 @@
1012
from main import PythonHereApp, run_ssh_server
1113

1214

13-
1415
@pytest.fixture
1516
def connection_config():
1617
return ConnectionConfig(
@@ -22,7 +23,12 @@ def connection_config():
2223

2324

2425
@pytest.fixture
25-
async def app_instance():
26+
def app_config():
27+
Config.read("../tests/config.ini")
28+
29+
30+
@pytest.fixture
31+
async def app_instance(capfd, app_config):
2632
app = PythonHereApp()
2733
app_task = asyncio.ensure_future(app.async_run_app())
2834
server_task = asyncio.ensure_future(run_ssh_server(app))
@@ -31,6 +37,8 @@ async def app_instance():
3137
server_task.cancel()
3238
app_task.cancel()
3339
await asyncio.gather(app_task, server_task)
40+
app.root.clear_widgets()
41+
Window.children.clear()
3442

3543

3644
@pytest.fixture

0 commit comments

Comments
 (0)