shuttlecheck 0.4.3__tar.gz → 0.4.4__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.
Files changed (158) hide show
  1. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/PKG-INFO +1 -1
  2. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/pyproject.toml +1 -1
  3. shuttlecheck-0.4.4/shuttlecheck/api_common.py +58 -0
  4. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/extensions.py +9 -7
  5. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/seal_api.py +3 -1
  6. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/ui.py +7 -45
  7. shuttlecheck-0.4.4/shuttlecheck/version.py +1 -0
  8. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck.egg-info/PKG-INFO +1 -1
  9. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck.egg-info/SOURCES.txt +1 -0
  10. shuttlecheck-0.4.3/shuttlecheck/version.py +0 -1
  11. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/LICENSE +0 -0
  12. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/PYPI.md +0 -0
  13. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/README.md +0 -0
  14. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/setup.cfg +0 -0
  15. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/__init__.py +0 -0
  16. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/admission.py +0 -0
  17. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/ale.py +0 -0
  18. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/aliases.py +0 -0
  19. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/arrivals.py +0 -0
  20. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/attribution.py +0 -0
  21. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/auth.py +0 -0
  22. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/certificate.py +0 -0
  23. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/checks.py +0 -0
  24. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/cli.py +0 -0
  25. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/completeness.py +0 -0
  26. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/conventions.py +0 -0
  27. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/delivery.py +0 -0
  28. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/demo.py +0 -0
  29. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/demo_convention.yaml +0 -0
  30. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/endpoints.py +0 -0
  31. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/infer.py +0 -0
  32. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/jobs.py +0 -0
  33. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/journal.py +0 -0
  34. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/layoutlog.py +0 -0
  35. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/listener.py +0 -0
  36. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/marks.py +0 -0
  37. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/mhl.py +0 -0
  38. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/originals.py +0 -0
  39. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/patterns.py +0 -0
  40. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/prefolder.py +0 -0
  41. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/probe.py +0 -0
  42. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/provenance.py +0 -0
  43. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/receive.py +0 -0
  44. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/report.py +0 -0
  45. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/say.py +0 -0
  46. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/schedule.py +0 -0
  47. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/schema.json +0 -0
  48. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/seal.py +0 -0
  49. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/sidecar.py +0 -0
  50. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/sizing.py +0 -0
  51. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/spec.py +0 -0
  52. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/store.py +0 -0
  53. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/support.py +0 -0
  54. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/telemetry-v1.schema.json +0 -0
  55. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/telemetry.py +0 -0
  56. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/templates.py +0 -0
  57. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/today.py +0 -0
  58. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/transport.py +0 -0
  59. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/ui_assets/app.css +0 -0
  60. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/ui_assets/app.html +0 -0
  61. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/ui_assets/app.js +0 -0
  62. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/ui_assets/classic.css +0 -0
  63. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/ui_assets/classic.html +0 -0
  64. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/ui_assets/classic.js +0 -0
  65. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/ui_assets/fonts/display-LICENSE.txt +0 -0
  66. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/ui_assets/fonts/display.woff2 +0 -0
  67. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/ui_assets/fonts/inter-LICENSE.txt +0 -0
  68. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/ui_assets/fonts/inter.woff2 +0 -0
  69. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/ui_assets/fonts/mono-LICENSE.txt +0 -0
  70. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/ui_assets/fonts/mono.woff2 +0 -0
  71. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/updates.py +0 -0
  72. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/validate.py +0 -0
  73. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/walkthrough.py +0 -0
  74. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck/window.py +0 -0
  75. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck.egg-info/dependency_links.txt +0 -0
  76. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck.egg-info/entry_points.txt +0 -0
  77. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck.egg-info/requires.txt +0 -0
  78. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/shuttlecheck.egg-info/top_level.txt +0 -0
  79. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_admission.py +0 -0
  80. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_ale.py +0 -0
  81. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_aliases.py +0 -0
  82. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_allocate.py +0 -0
  83. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_arrivals.py +0 -0
  84. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_auth.py +0 -0
  85. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_auth_packaged.py +0 -0
  86. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_check_against.py +0 -0
  87. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_classify.py +0 -0
  88. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_cli.py +0 -0
  89. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_completeness.py +0 -0
  90. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_consoles.py +0 -0
  91. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_conventions.py +0 -0
  92. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_conventions_routes.py +0 -0
  93. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_counting_files.py +0 -0
  94. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_dailies.py +0 -0
  95. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_dailiesdrop.py +0 -0
  96. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_delivery.py +0 -0
  97. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_device_flow.py +0 -0
  98. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_due.py +0 -0
  99. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_endpoints.py +0 -0
  100. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_enrolment.py +0 -0
  101. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_fleet_units.py +0 -0
  102. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_folders.py +0 -0
  103. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_fonts.py +0 -0
  104. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_groups.py +0 -0
  105. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_infer.py +0 -0
  106. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_infer_keys.py +0 -0
  107. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_jobs.py +0 -0
  108. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_keepable.py +0 -0
  109. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_lamps.py +0 -0
  110. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_listener.py +0 -0
  111. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_marks_api.py +0 -0
  112. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_message_style.py +0 -0
  113. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_meters_measure.py +0 -0
  114. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_mhl.py +0 -0
  115. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_min_version.py +0 -0
  116. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_monitor.py +0 -0
  117. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_no_convention.py +0 -0
  118. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_one_file_is_not_a_pattern.py +0 -0
  119. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_originals.py +0 -0
  120. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_path_length.py +0 -0
  121. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_pick.py +0 -0
  122. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_pointed_at_the_job.py +0 -0
  123. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_prefolder.py +0 -0
  124. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_problems.py +0 -0
  125. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_provenance.py +0 -0
  126. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_rack.py +0 -0
  127. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_receive.py +0 -0
  128. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_rename_token.py +0 -0
  129. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_report.py +0 -0
  130. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_reveal.py +0 -0
  131. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_rollcall_schedule.py +0 -0
  132. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_signal_path.py +0 -0
  133. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_sizing.py +0 -0
  134. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_sizing_history.py +0 -0
  135. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_source_attach.py +0 -0
  136. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_store.py +0 -0
  137. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_support.py +0 -0
  138. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_sweeping.py +0 -0
  139. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_telemetry.py +0 -0
  140. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_templates.py +0 -0
  141. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_the_04_window.py +0 -0
  142. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_the_analyser.py +0 -0
  143. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_the_pipeline.py +0 -0
  144. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_today.py +0 -0
  145. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_today_screen.py +0 -0
  146. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_trademark.py +0 -0
  147. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_transport.py +0 -0
  148. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_ui.py +0 -0
  149. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_ui_routes.py +0 -0
  150. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_unread_sources.py +0 -0
  151. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_updates.py +0 -0
  152. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_validate.py +0 -0
  153. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_verify.py +0 -0
  154. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_walk.py +0 -0
  155. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_web_seal.py +0 -0
  156. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_what_the_far_end_reads.py +0 -0
  157. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_where_it_belongs.py +0 -0
  158. {shuttlecheck-0.4.3 → shuttlecheck-0.4.4}/tests/test_window.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shuttlecheck
3
- Version: 0.4.3
3
+ Version: 0.4.4
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"
3
+ version = "0.4.4"
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"
@@ -0,0 +1,58 @@
1
+ """What every set of app endpoints shares, kept apart from the route table.
2
+
3
+ `ui` builds its route table when it is imported, and building it asks Pro for
4
+ its routes, which imports `shuttlecheck_pro.web`. If `web` (or `seal_api`,
5
+ which `web` imports) reached into `ui` for these, importing `web` first would
6
+ start `ui`, `ui` would ask for `web`'s handlers, and `web` would not have
7
+ defined them yet. So they live here, in a module that imports nothing of the
8
+ app, and `ui` imports them back under the same names.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from pathlib import Path
14
+
15
+ import yaml
16
+
17
+ from .spec import Spec, SpecError, check_document
18
+
19
+
20
+ class ApiError(Exception):
21
+ """A refusal the page is expected to render.
22
+
23
+ `detail` is merged into the JSON body beside the message. Most refusals
24
+ need nothing: the sentence is the whole answer. A few are a comparison --
25
+ this many now, that many when you looked, and a page that has to read
26
+ those numbers back out of an English sentence will get them wrong the first
27
+ time the sentence is reworded.
28
+ """
29
+
30
+ def __init__(self, message: str, status: int = 400, **detail):
31
+ super().__init__(message)
32
+ self.status = status
33
+ self.detail = detail
34
+
35
+
36
+ def _spec_from_text(text: str, root: Path) -> Spec:
37
+ """Build a Spec anchored at <root>/_SPEC so relative sources still resolve."""
38
+ try:
39
+ doc = yaml.safe_load(text)
40
+ except yaml.YAMLError as exc:
41
+ raise ApiError(f"the spec is not valid YAML: {exc}")
42
+ try:
43
+ check_document(doc, "the spec in the editor")
44
+ return Spec(doc, root / "_SPEC" / "spec.yaml")
45
+ except SpecError as exc:
46
+ raise ApiError(str(exc))
47
+
48
+
49
+ def _folder(payload: dict) -> Path:
50
+ raw = (payload.get("path") or "").strip().strip('"')
51
+ if not raw:
52
+ raise ApiError("no folder given")
53
+ path = Path(raw).expanduser()
54
+ if not path.exists():
55
+ raise ApiError(f"nothing at {path}")
56
+ if not path.is_dir():
57
+ raise ApiError(f"{path} is a file, not a folder")
58
+ return path.resolve()
@@ -1,9 +1,10 @@
1
1
  """Optional extensions.
2
2
 
3
- The open package is the read-only half: work out a convention, check a tree
4
- against it, check a drive that arrived. Everything that writes to media --
5
- conforming, the journal, sealing, vendor packs, ships separately and is
6
- licensed.
3
+ The open package works out a convention, checks a tree against it, checks a
4
+ drive that arrived, and seals a drive. The extension adds the operations that
5
+ rename media (conforming, undoing a run, renaming by hand) plus vendor packs.
6
+ A licence pays for the renaming and nothing else: sealing and vendor packs are
7
+ free, by decision, since 0.4. See docs/COMMERCIAL.md.
7
8
 
8
9
  The base package must never require the extension, must never import it at
9
10
  module scope, and must behave as a complete tool without it. What it does do is
@@ -42,9 +43,10 @@ def require(what: str):
42
43
  raise ExtensionMissing(
43
44
  f"{what} is part of ShuttleCheck Pro, which is not installed on this "
44
45
  f"machine.\n"
45
- f"The open package covers init, validate, verify and the app. "
46
- f"everything that only reads.\n"
47
- f"Conforming, sealing, the journal and vendor packs are licensed: "
46
+ f"The open package covers init, validate, verify, seal and the "
47
+ f"app.\n"
48
+ f"Conforming, undoing a run and vendor packs come with Pro; only "
49
+ f"conforming and undoing need a licence: "
48
50
  f"https://mvrk.systems/shuttlecheck")
49
51
  return module
50
52
 
@@ -21,7 +21,9 @@ from shuttlecheck import jobs, mhl, provenance, store
21
21
  from shuttlecheck.sidecar import SIDECAR_DIR
22
22
  from shuttlecheck.spec import SpecError, find_convention, load_spec
23
23
  from shuttlecheck.validate import Validator
24
- from shuttlecheck.ui import ApiError, _folder, _spec_from_text
24
+ # Not from shuttlecheck.ui: importing ui builds its route table, which
25
+ # imports this module's handlers before they exist.
26
+ from shuttlecheck.api_common import ApiError, _folder, _spec_from_text
25
27
  from shuttlecheck.seal import NOT_MEDIA, _existing_checksums, choose_algorithm
26
28
  from shuttlecheck.seal import seal as seal_drive
27
29
 
@@ -45,6 +45,9 @@ from importlib import resources
45
45
  from pathlib import Path
46
46
  from urllib.parse import urlparse
47
47
 
48
+ # Defined apart from this module so the handlers that live elsewhere can use
49
+ # them without importing this one, whose import builds the route table.
50
+ from .api_common import ApiError, _folder, _spec_from_text
48
51
  from . import (auth, endpoints, extensions, jobs, listener, receive, store,
49
52
  support, telemetry, today, updates, window)
50
53
  from .delivery import FFProbeProber
@@ -69,22 +72,6 @@ MIME = {".html": "text/html; charset=utf-8", ".css": "text/css; charset=utf-8",
69
72
  MAX_BODY = 8 * 1024 * 1024
70
73
 
71
74
 
72
- class ApiError(Exception):
73
- """A refusal the page is expected to render.
74
-
75
- `detail` is merged into the JSON body beside the message. Most refusals
76
- need nothing: the sentence is the whole answer. A few are a comparison --
77
- this many now, that many when you looked, and a page that has to read
78
- those numbers back out of an English sentence will get them wrong the first
79
- time the sentence is reworded.
80
- """
81
-
82
- def __init__(self, message: str, status: int = 400, **detail):
83
- super().__init__(message)
84
- self.status = status
85
- self.detail = detail
86
-
87
-
88
75
  # --------------------------------------------------------------------------
89
76
  # Payload builders: one shape the page can rely on
90
77
  # --------------------------------------------------------------------------
@@ -120,19 +107,6 @@ def _inference(report) -> dict:
120
107
  }
121
108
 
122
109
 
123
- def _spec_from_text(text: str, root: Path) -> Spec:
124
- """Build a Spec anchored at <root>/_SPEC so relative sources still resolve."""
125
- try:
126
- doc = yaml.safe_load(text)
127
- except yaml.YAMLError as exc:
128
- raise ApiError(f"the spec is not valid YAML: {exc}")
129
- try:
130
- check_document(doc, "the spec in the editor")
131
- return Spec(doc, root / "_SPEC" / "spec.yaml")
132
- except SpecError as exc:
133
- raise ApiError(str(exc))
134
-
135
-
136
110
  # Places a person almost never means to point a tool at, and what to call
137
111
  # each one when asking. Read from the environment rather than hard-coded, so a
138
112
  # machine whose Windows lives on D: is covered and a test can point them
@@ -186,18 +160,6 @@ def sweeping(path: Path) -> str:
186
160
  return _sweeping_places().get(resolved, "")
187
161
 
188
162
 
189
- def _folder(payload: dict) -> Path:
190
- raw = (payload.get("path") or "").strip().strip('"')
191
- if not raw:
192
- raise ApiError("no folder given")
193
- path = Path(raw).expanduser()
194
- if not path.exists():
195
- raise ApiError(f"nothing at {path}")
196
- if not path.is_dir():
197
- raise ApiError(f"{path} is a file, not a folder")
198
- return path.resolve()
199
-
200
-
201
163
  # --------------------------------------------------------------------------
202
164
  # API
203
165
  # --------------------------------------------------------------------------
@@ -2360,10 +2322,10 @@ def build_routes() -> dict:
2360
2322
  "/api/support/preview": api_support_preview,
2361
2323
  "/api/support/build": api_support_build,
2362
2324
  }
2363
- # Imported here rather than at module scope: seal_api reads ApiError and
2364
- # the folder helpers out of this module, so a top-level import would be a
2365
- # cycle. Sealing is free, so these sit in the table before Pro is asked
2366
- # for anything.
2325
+ # Sealing is free, so these sit in the table before Pro is asked for
2326
+ # anything. seal_api takes ApiError and the folder helpers from
2327
+ # api_common, never from this module: this function runs while this
2328
+ # module is still being imported.
2367
2329
  from .seal_api import api_seal, api_seal_preview
2368
2330
  routes["/api/seal/preview"] = api_seal_preview
2369
2331
  routes["/api/seal"] = api_seal
@@ -0,0 +1 @@
1
+ __version__ = "0.4.4"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shuttlecheck
3
- Version: 0.4.3
3
+ Version: 0.4.4
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
@@ -6,6 +6,7 @@ shuttlecheck/__init__.py
6
6
  shuttlecheck/admission.py
7
7
  shuttlecheck/ale.py
8
8
  shuttlecheck/aliases.py
9
+ shuttlecheck/api_common.py
9
10
  shuttlecheck/arrivals.py
10
11
  shuttlecheck/attribution.py
11
12
  shuttlecheck/auth.py
@@ -1 +0,0 @@
1
- __version__ = "0.4.3"
File without changes
File without changes
File without changes
File without changes