shuttlecheck 0.4.1__tar.gz → 0.4.2__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.
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/PKG-INFO +1 -1
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/pyproject.toml +1 -1
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/cli.py +9 -2
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/ui.py +36 -1
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/ui_assets/app.js +12 -1
- shuttlecheck-0.4.2/shuttlecheck/version.py +1 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck.egg-info/PKG-INFO +1 -1
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_window.py +41 -0
- shuttlecheck-0.4.1/shuttlecheck/version.py +0 -1
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/LICENSE +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/PYPI.md +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/README.md +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/setup.cfg +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/__init__.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/admission.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/ale.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/aliases.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/arrivals.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/attribution.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/auth.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/certificate.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/checks.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/completeness.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/conventions.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/delivery.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/demo.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/demo_convention.yaml +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/endpoints.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/extensions.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/infer.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/jobs.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/journal.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/layoutlog.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/listener.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/marks.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/mhl.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/originals.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/patterns.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/prefolder.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/probe.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/provenance.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/receive.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/report.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/say.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/schedule.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/schema.json +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/seal.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/seal_api.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/sidecar.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/sizing.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/spec.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/store.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/support.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/telemetry-v1.schema.json +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/telemetry.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/templates.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/today.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/transport.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/ui_assets/app.css +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/ui_assets/app.html +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/ui_assets/classic.css +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/ui_assets/classic.html +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/ui_assets/classic.js +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/ui_assets/fonts/display-LICENSE.txt +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/ui_assets/fonts/display.woff2 +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/ui_assets/fonts/inter-LICENSE.txt +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/ui_assets/fonts/inter.woff2 +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/ui_assets/fonts/mono-LICENSE.txt +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/ui_assets/fonts/mono.woff2 +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/updates.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/validate.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/walkthrough.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck/window.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck.egg-info/SOURCES.txt +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck.egg-info/dependency_links.txt +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck.egg-info/entry_points.txt +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck.egg-info/requires.txt +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/shuttlecheck.egg-info/top_level.txt +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_admission.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_ale.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_aliases.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_allocate.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_arrivals.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_auth.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_auth_packaged.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_check_against.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_classify.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_cli.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_completeness.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_consoles.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_conventions.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_conventions_routes.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_counting_files.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_dailies.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_dailiesdrop.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_delivery.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_device_flow.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_due.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_endpoints.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_enrolment.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_fleet_units.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_folders.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_fonts.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_groups.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_infer.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_infer_keys.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_jobs.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_keepable.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_lamps.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_listener.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_marks_api.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_message_style.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_meters_measure.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_mhl.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_min_version.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_monitor.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_no_convention.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_one_file_is_not_a_pattern.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_originals.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_path_length.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_pick.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_pointed_at_the_job.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_prefolder.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_problems.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_provenance.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_rack.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_receive.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_rename_token.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_report.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_reveal.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_rollcall_schedule.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_signal_path.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_sizing.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_sizing_history.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_source_attach.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_store.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_support.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_sweeping.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_telemetry.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_templates.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_the_04_window.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_the_analyser.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_the_pipeline.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_today.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_today_screen.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_trademark.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_transport.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_ui.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_ui_routes.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_unread_sources.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_updates.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_validate.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_verify.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_walk.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_web_seal.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_what_the_far_end_reads.py +0 -0
- {shuttlecheck-0.4.1 → shuttlecheck-0.4.2}/tests/test_where_it_belongs.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shuttlecheck
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: Check media filenames, folder structure and deliverables against a written convention. Read-only.
|
|
5
5
|
Author-email: MVRK Systems <hello@mvrk.systems>
|
|
6
6
|
License: Proprietary — free to use, no redistribution
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "shuttlecheck"
|
|
3
|
-
version = "0.4.
|
|
3
|
+
version = "0.4.2"
|
|
4
4
|
description = "Check media filenames, folder structure and deliverables against a written convention. Read-only."
|
|
5
5
|
readme = { file = "PYPI.md", content-type = "text/markdown" }
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -69,11 +69,17 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
69
69
|
b.add_argument("--yes", action="store_true",
|
|
70
70
|
help="write it without printing the contents first")
|
|
71
71
|
|
|
72
|
-
u = sub.add_parser("ui", help="open the local app in a browser")
|
|
72
|
+
u = sub.add_parser("ui", help="open the local app in a browser, or in its own window")
|
|
73
73
|
u.add_argument("root", nargs="?", help="folder to open on (optional)")
|
|
74
74
|
u.add_argument("--port", type=int, default=8765)
|
|
75
75
|
u.add_argument("--no-browser", action="store_true",
|
|
76
76
|
help="print the URL instead of opening it")
|
|
77
|
+
# What the packaged app does, available from a checkout. Without it a
|
|
78
|
+
# checkout can only ever show the tool as a tab, and the window is the one
|
|
79
|
+
# part of the product nobody sees until a build ships.
|
|
80
|
+
u.add_argument("--window", action="store_true",
|
|
81
|
+
help="open in its own window (needs the [app] extra); "
|
|
82
|
+
"falls back to a browser where there is no webview")
|
|
77
83
|
|
|
78
84
|
i = sub.add_parser("init", help="read a tree and write the spec it already follows")
|
|
79
85
|
i.add_argument("root")
|
|
@@ -187,7 +193,8 @@ def _ui(args) -> int:
|
|
|
187
193
|
if root and not root.is_dir():
|
|
188
194
|
print(f"error: not a folder: {root}", file=sys.stderr)
|
|
189
195
|
return 2
|
|
190
|
-
serve(root, port=args.port, open_browser=not args.no_browser
|
|
196
|
+
serve(root, port=args.port, open_browser=not args.no_browser,
|
|
197
|
+
shell=args.window and not args.no_browser)
|
|
191
198
|
return 0
|
|
192
199
|
|
|
193
200
|
|
|
@@ -35,6 +35,7 @@ import secrets
|
|
|
35
35
|
import subprocess
|
|
36
36
|
import sys
|
|
37
37
|
import threading
|
|
38
|
+
import time
|
|
38
39
|
import webbrowser
|
|
39
40
|
from dataclasses import asdict
|
|
40
41
|
from datetime import datetime, timezone
|
|
@@ -2382,10 +2383,17 @@ ROUTES = build_routes()
|
|
|
2382
2383
|
class Handler(BaseHTTPRequestHandler):
|
|
2383
2384
|
server_version = f"ShuttleCheck/{__version__}"
|
|
2384
2385
|
token = ""
|
|
2386
|
+
# When the page last asked for anything. Only read when the app has fallen
|
|
2387
|
+
# back to a browser, where it is the one sign that anybody is still there.
|
|
2388
|
+
last_seen = 0.0
|
|
2385
2389
|
|
|
2386
2390
|
def log_message(self, *args): # keep the console for our own output
|
|
2387
2391
|
pass
|
|
2388
2392
|
|
|
2393
|
+
def parse_request(self):
|
|
2394
|
+
Handler.last_seen = time.monotonic()
|
|
2395
|
+
return super().parse_request()
|
|
2396
|
+
|
|
2389
2397
|
# -- helpers ----------------------------------------------------------
|
|
2390
2398
|
|
|
2391
2399
|
def _send(self, status: int, body: bytes, mime: str):
|
|
@@ -2499,6 +2507,29 @@ class Handler(BaseHTTPRequestHandler):
|
|
|
2499
2507
|
return self._json(500, {"error": f"{type(exc).__name__}: {exc}"})
|
|
2500
2508
|
|
|
2501
2509
|
|
|
2510
|
+
# How long a browser fallback may go unheard from before it counts as closed.
|
|
2511
|
+
# The page asks for /api/today every minute whatever screen is up, and a
|
|
2512
|
+
# background tab is throttled to about that, so ten quiet minutes is a tab that
|
|
2513
|
+
# was closed rather than one that is idle.
|
|
2514
|
+
#
|
|
2515
|
+
# Only the fallback needs this. A window ends the process when it closes; a tab
|
|
2516
|
+
# does not, and a packaged build has no console to close instead, so without
|
|
2517
|
+
# it the server outlives the tab and sits invisibly holding a port until the
|
|
2518
|
+
# next login.
|
|
2519
|
+
ABANDONED_AFTER = 600.0
|
|
2520
|
+
|
|
2521
|
+
|
|
2522
|
+
def _until_abandoned(server: threading.Thread, *,
|
|
2523
|
+
quiet: float = ABANDONED_AFTER, poll: float = 15.0) -> None:
|
|
2524
|
+
Handler.last_seen = time.monotonic()
|
|
2525
|
+
tick = threading.Event()
|
|
2526
|
+
while server.is_alive():
|
|
2527
|
+
tick.wait(poll)
|
|
2528
|
+
if time.monotonic() - Handler.last_seen > quiet:
|
|
2529
|
+
print(" nothing has asked for a while; stopping")
|
|
2530
|
+
return
|
|
2531
|
+
|
|
2532
|
+
|
|
2502
2533
|
def serve(folder: Path | None = None, *, port: int = 8765,
|
|
2503
2534
|
open_browser: bool = True, host: str = "127.0.0.1",
|
|
2504
2535
|
shell: bool = False) -> None:
|
|
@@ -2531,7 +2562,11 @@ def serve(folder: Path | None = None, *, port: int = 8765,
|
|
|
2531
2562
|
# and enormously better than an application that does nothing.
|
|
2532
2563
|
if open_browser:
|
|
2533
2564
|
window.open_browser(url)
|
|
2534
|
-
|
|
2565
|
+
_until_abandoned(server)
|
|
2566
|
+
else:
|
|
2567
|
+
# Nobody was shown anything, so there is no tab to outlive:
|
|
2568
|
+
# this is an ingest box, and it serves until it is stopped.
|
|
2569
|
+
server.join()
|
|
2535
2570
|
except KeyboardInterrupt:
|
|
2536
2571
|
print("\n stopped")
|
|
2537
2572
|
finally:
|
|
@@ -2829,7 +2829,18 @@ PAGES.settings = async (stage) => {
|
|
|
2829
2829
|
on("signIn", signIn);
|
|
2830
2830
|
const tg = $("#telOn"); if (tg) tg.onchange = async () => { await api("/api/settings/set", { key: "telemetry.optIn", value: tg.checked }); toast(tg.checked ? "Counts will be sent." : "Nothing will be sent, and the queue was deleted."); };
|
|
2831
2831
|
on("telShow", async () => { const r = await api("/api/telemetry/lastBatch"); $("#telOut").textContent = r.batch ? JSON.stringify(r.batch, null, 2) : "Nothing has been sent from this machine."; });
|
|
2832
|
-
|
|
2832
|
+
// The feed answers with `state`. This used to read `r.newer`, which nothing
|
|
2833
|
+
// sends, so every answer, a release that was out and a feed that could not
|
|
2834
|
+
// be reached alike, came back as "This is the newest release".
|
|
2835
|
+
on("updBtn", async () => {
|
|
2836
|
+
const out = $("#updOut"); out.textContent = "Asking";
|
|
2837
|
+
try {
|
|
2838
|
+
const r = await api("/api/updates/check");
|
|
2839
|
+
if (r.state === "newer") out.innerHTML = `ShuttleCheck ${esc(r.latest)} is out. ${r.url ? `<a href="${esc(r.url)}" data-act="open" data-url="${esc(r.url)}">Get it</a>` : ""}`;
|
|
2840
|
+
else if (r.state === "current") out.textContent = `${r.running} is the newest release.`;
|
|
2841
|
+
else out.textContent = r.detail || "Could not ask.";
|
|
2842
|
+
} catch (err) { out.textContent = err.message; }
|
|
2843
|
+
});
|
|
2833
2844
|
};
|
|
2834
2845
|
|
|
2835
2846
|
async function signIn() {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.4.2"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shuttlecheck
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: Check media filenames, folder structure and deliverables against a written convention. Read-only.
|
|
5
5
|
Author-email: MVRK Systems <hello@mvrk.systems>
|
|
6
6
|
License: Proprietary — free to use, no redistribution
|
|
@@ -275,6 +275,47 @@ def test_asking_for_no_browser_and_no_window_still_stops_cleanly(monkeypatch):
|
|
|
275
275
|
ui.serve(port=0, open_browser=False, shell=True)
|
|
276
276
|
|
|
277
277
|
|
|
278
|
+
def test_a_browser_fallback_stops_once_the_tab_has_gone_quiet(monkeypatch):
|
|
279
|
+
"""A packaged build has no console, so nothing else would ever stop it."""
|
|
280
|
+
server = threading.Thread(target=threading.Event().wait, daemon=True)
|
|
281
|
+
server.start()
|
|
282
|
+
clock = iter([100.0, 100.0, 104.0, 111.0])
|
|
283
|
+
monkeypatch.setattr(ui.time, "monotonic", lambda: next(clock))
|
|
284
|
+
ui._until_abandoned(server, quiet=10.0, poll=0.001)
|
|
285
|
+
assert server.is_alive(), "it stopped waiting; the server thread is a daemon"
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def test_a_browser_fallback_keeps_serving_while_the_page_still_asks(monkeypatch):
|
|
289
|
+
server = threading.Thread(target=threading.Event().wait, daemon=True)
|
|
290
|
+
server.start()
|
|
291
|
+
times = iter([0.0, 5.0, 9.0, 14.0, 18.0, 30.0])
|
|
292
|
+
seen = iter([None, 8.0, 12.0, 17.0, None])
|
|
293
|
+
|
|
294
|
+
def now():
|
|
295
|
+
value = next(times)
|
|
296
|
+
heard = next(seen, None)
|
|
297
|
+
if heard is not None:
|
|
298
|
+
ui.Handler.last_seen = heard
|
|
299
|
+
return value
|
|
300
|
+
|
|
301
|
+
monkeypatch.setattr(ui.time, "monotonic", now)
|
|
302
|
+
ui._until_abandoned(server, quiet=10.0, poll=0.001)
|
|
303
|
+
# It ran to the last tick, which is the only one more than ten past a request.
|
|
304
|
+
assert next(times, "spent") == "spent"
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def test_the_cli_can_open_the_window_a_build_opens(monkeypatch):
|
|
308
|
+
from shuttlecheck import cli
|
|
309
|
+
calls = {}
|
|
310
|
+
monkeypatch.setattr(cli, "serve", lambda root, **kw: calls.update(kw))
|
|
311
|
+
assert cli.main(["ui", "--window"]) == 0
|
|
312
|
+
assert calls["shell"] is True
|
|
313
|
+
assert cli.main(["ui"]) == 0
|
|
314
|
+
assert calls["shell"] is False
|
|
315
|
+
assert cli.main(["ui", "--window", "--no-browser"]) == 0
|
|
316
|
+
assert calls["shell"] is False, "--no-browser means nothing is shown at all"
|
|
317
|
+
|
|
318
|
+
|
|
278
319
|
def test_serving_without_a_shell_is_unchanged(monkeypatch):
|
|
279
320
|
"""A checkout and an ingest box in a rack still get the old behaviour."""
|
|
280
321
|
calls = []
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.4.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|