zebra-day 1.0.2__py3-none-any.whl → 2.1.4__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.
Files changed (174) hide show
  1. zebra_day/__init__.py +7 -2
  2. zebra_day/_version.py +1 -0
  3. zebra_day/cli/__init__.py +80 -30
  4. zebra_day/cli/cognito.py +15 -9
  5. zebra_day/cli/gui.py +101 -13
  6. zebra_day/cli/printer.py +34 -27
  7. zebra_day/cli/template.py +19 -15
  8. zebra_day/cmd_mgr.py +3 -6
  9. zebra_day/docs/gx420d-gx430d-ug-en.pdf +0 -0
  10. zebra_day/docs/hardware_config_guide.md +149 -0
  11. zebra_day/docs/programatic_guide.md +181 -0
  12. zebra_day/docs/qln420_zebra_manual.pdf +0 -0
  13. zebra_day/docs/uid_screed_light.md +38 -0
  14. zebra_day/docs/zd620-zd420-ug-en.pdf +0 -0
  15. zebra_day/docs/zebra_day_ui_guide.md +194 -0
  16. zebra_day/etc/printer_config.json +5 -11
  17. zebra_day/etc/printer_config.template.json +5 -11
  18. zebra_day/etc/tmp_printers120.json +10 -0
  19. zebra_day/etc/tmp_printers139.json +10 -0
  20. zebra_day/etc/tmp_printers145.json +10 -0
  21. zebra_day/etc/tmp_printers147.json +10 -0
  22. zebra_day/etc/tmp_printers207.json +10 -0
  23. zebra_day/etc/tmp_printers34.json +10 -0
  24. zebra_day/etc/tmp_printers389.json +10 -0
  25. zebra_day/etc/tmp_printers398.json +10 -0
  26. zebra_day/etc/tmp_printers437.json +10 -0
  27. zebra_day/etc/tmp_printers439.json +10 -0
  28. zebra_day/etc/tmp_printers440.json +10 -0
  29. zebra_day/etc/tmp_printers469.json +10 -0
  30. zebra_day/etc/tmp_printers485.json +10 -0
  31. zebra_day/etc/tmp_printers508.json +10 -0
  32. zebra_day/etc/tmp_printers531.json +10 -0
  33. zebra_day/etc/tmp_printers540.json +10 -0
  34. zebra_day/etc/tmp_printers542.json +10 -0
  35. zebra_day/etc/tmp_printers543.json +10 -0
  36. zebra_day/etc/tmp_printers552.json +10 -0
  37. zebra_day/etc/tmp_printers715.json +10 -0
  38. zebra_day/etc/tmp_printers835.json +10 -0
  39. zebra_day/etc/tmp_printers842.json +10 -0
  40. zebra_day/etc/tmp_printers931.json +10 -0
  41. zebra_day/etc/tmp_printers969.json +10 -0
  42. zebra_day/etc/tmp_printers972.json +10 -0
  43. zebra_day/exceptions.py +1 -1
  44. zebra_day/files/blank_preview.png +0 -0
  45. zebra_day/files/corners_20cmX30cm_preview.png +0 -0
  46. zebra_day/files/corners_smallTube_preview.png +0 -0
  47. zebra_day/files/generic_2inX1in_preview.png +0 -0
  48. zebra_day/files/test_png_12020.png +0 -0
  49. zebra_day/files/test_png_12352.png +0 -0
  50. zebra_day/files/test_png_15472.png +0 -0
  51. zebra_day/files/test_png_24493.png +0 -0
  52. zebra_day/files/test_png_2897.png +0 -0
  53. zebra_day/files/test_png_30069.png +0 -0
  54. zebra_day/files/test_png_31690.png +0 -0
  55. zebra_day/files/test_png_33804.png +0 -0
  56. zebra_day/files/test_png_34737.png +0 -0
  57. zebra_day/files/test_png_4161.png +0 -0
  58. zebra_day/files/test_png_44748.png +0 -0
  59. zebra_day/files/test_png_4635.png +0 -0
  60. zebra_day/files/test_png_47791.png +0 -0
  61. zebra_day/files/test_png_47799.png +0 -0
  62. zebra_day/files/test_png_55588.png +0 -0
  63. zebra_day/files/test_png_56349.png +0 -0
  64. zebra_day/files/test_png_58809.png +0 -0
  65. zebra_day/files/test_png_5936.png +0 -0
  66. zebra_day/files/test_png_64110.png +0 -0
  67. zebra_day/files/test_png_64891.png +0 -0
  68. zebra_day/files/test_png_67242.png +0 -0
  69. zebra_day/files/test_png_69002.png +0 -0
  70. zebra_day/files/test_png_70065.png +0 -0
  71. zebra_day/files/test_png_72366.png +0 -0
  72. zebra_day/files/test_png_77793.png +0 -0
  73. zebra_day/files/test_png_89893.png +0 -0
  74. zebra_day/files/test_png_9572.png +0 -0
  75. zebra_day/files/tube_20mmX30mmA_preview.png +0 -0
  76. zebra_day/imgs/.hold +0 -0
  77. zebra_day/imgs/bar_ltpurp.png +0 -0
  78. zebra_day/imgs/bar_purp.png +0 -0
  79. zebra_day/imgs/bar_purp3.png +0 -0
  80. zebra_day/imgs/bar_red.png +0 -0
  81. zebra_day/imgs/legacy/UBC_gantt_chart.png +0 -0
  82. zebra_day/imgs/legacy/gx420d_network_config.png +0 -0
  83. zebra_day/imgs/legacy/gx420d_printer_config.png +0 -0
  84. zebra_day/imgs/legacy/ngrok.png +0 -0
  85. zebra_day/imgs/legacy/printer_details.png +0 -0
  86. zebra_day/imgs/legacy/quick_start_test_label.png +0 -0
  87. zebra_day/imgs/legacy/quick_start_test_label2.png +0 -0
  88. zebra_day/imgs/legacy/zd620_network_config.png +0 -0
  89. zebra_day/imgs/legacy/zd620_printer_config.png +0 -0
  90. zebra_day/imgs/legacy/zday_quick_gui.png +0 -0
  91. zebra_day/imgs/legacy/zebra_day_alt_css_dog.png +0 -0
  92. zebra_day/imgs/legacy/zebra_day_alt_css_flower.png +0 -0
  93. zebra_day/imgs/legacy/zebra_day_alt_css_main.png +0 -0
  94. zebra_day/imgs/legacy/zebra_day_available_zpl_templates.png +0 -0
  95. zebra_day/imgs/legacy/zebra_day_bkup_pconfig.png +0 -0
  96. zebra_day/imgs/legacy/zebra_day_home.png +0 -0
  97. zebra_day/imgs/legacy/zebra_day_manual_print.png +0 -0
  98. zebra_day/imgs/legacy/zebra_day_printer_fleet_json.png +0 -0
  99. zebra_day/imgs/legacy/zebra_day_quick_ex.png +0 -0
  100. zebra_day/imgs/legacy/zebra_day_zpl_template_IRLa.png +0 -0
  101. zebra_day/imgs/legacy/zebra_day_zpl_template_IRLb.png +0 -0
  102. zebra_day/imgs/ui_api_docs.png +0 -0
  103. zebra_day/imgs/ui_config.png +0 -0
  104. zebra_day/imgs/ui_dashboard.png +0 -0
  105. zebra_day/imgs/ui_print_request.png +0 -0
  106. zebra_day/imgs/ui_printers.png +0 -0
  107. zebra_day/imgs/ui_templates.png +0 -0
  108. zebra_day/logging_config.py +4 -9
  109. zebra_day/mkcert.py +157 -0
  110. zebra_day/paths.py +1 -2
  111. zebra_day/print_mgr.py +261 -185
  112. zebra_day/templates/modern/config.html +7 -0
  113. zebra_day/templates/modern/config_backups.html +59 -0
  114. zebra_day/templates/modern/config_editor.html +95 -0
  115. zebra_day/templates/modern/config_new.html +93 -0
  116. zebra_day/templates/modern/print_request.html +70 -8
  117. zebra_day/templates/modern/printer_detail.html +161 -34
  118. zebra_day/templates/modern/printers.html +17 -6
  119. zebra_day/templates/modern/template_editor.html +7 -4
  120. zebra_day/web/__init__.py +1 -1
  121. zebra_day/web/app.py +99 -17
  122. zebra_day/web/auth.py +17 -15
  123. zebra_day/web/middleware.py +8 -5
  124. zebra_day/web/routers/__init__.py +0 -1
  125. zebra_day/web/routers/api.py +330 -31
  126. zebra_day/web/routers/ui.py +174 -591
  127. zebra_day/zpl_renderer.py +45 -34
  128. {zebra_day-1.0.2.dist-info → zebra_day-2.1.4.dist-info}/METADATA +144 -74
  129. zebra_day-2.1.4.dist-info/RECORD +240 -0
  130. zebra_day/bin/fetch_zebra_config.py +0 -15
  131. zebra_day/bin/generate_coord_grid_zpl.py +0 -50
  132. zebra_day/bin/print_zpl_from_file.py +0 -21
  133. zebra_day/bin/probe_new_label_dimensions.py +0 -75
  134. zebra_day/bin/scan_for_networed_zebra_printers.py +0 -23
  135. zebra_day/bin/scan_for_networed_zebra_printers_arp_scan.sh +0 -1
  136. zebra_day/bin/scan_for_networed_zebra_printers_curl.sh +0 -30
  137. zebra_day/bin/zserve.py +0 -1062
  138. zebra_day/templates/base.html +0 -36
  139. zebra_day/templates/bpr.html +0 -72
  140. zebra_day/templates/build_new_config.html +0 -36
  141. zebra_day/templates/build_print_request.html +0 -32
  142. zebra_day/templates/chg_ui_style.html +0 -19
  143. zebra_day/templates/edit_template.html +0 -128
  144. zebra_day/templates/edit_zpl.html +0 -37
  145. zebra_day/templates/index.html +0 -82
  146. zebra_day/templates/legacy/base.html +0 -37
  147. zebra_day/templates/legacy/bpr.html +0 -72
  148. zebra_day/templates/legacy/build_new_config.html +0 -36
  149. zebra_day/templates/legacy/build_print_request.html +0 -32
  150. zebra_day/templates/legacy/chg_ui_style.html +0 -19
  151. zebra_day/templates/legacy/edit_template.html +0 -128
  152. zebra_day/templates/legacy/edit_zpl.html +0 -37
  153. zebra_day/templates/legacy/index.html +0 -82
  154. zebra_day/templates/legacy/list_prior_configs.html +0 -24
  155. zebra_day/templates/legacy/print_result.html +0 -30
  156. zebra_day/templates/legacy/printer_details.html +0 -25
  157. zebra_day/templates/legacy/printer_status.html +0 -70
  158. zebra_day/templates/legacy/save_result.html +0 -17
  159. zebra_day/templates/legacy/send_print_request.html +0 -34
  160. zebra_day/templates/legacy/simple_print.html +0 -94
  161. zebra_day/templates/legacy/view_pstation_json.html +0 -29
  162. zebra_day/templates/list_prior_configs.html +0 -24
  163. zebra_day/templates/print_result.html +0 -30
  164. zebra_day/templates/printer_details.html +0 -25
  165. zebra_day/templates/printer_status.html +0 -70
  166. zebra_day/templates/save_result.html +0 -17
  167. zebra_day/templates/send_print_request.html +0 -34
  168. zebra_day/templates/simple_print.html +0 -94
  169. zebra_day/templates/view_pstation_json.html +0 -29
  170. zebra_day-1.0.2.dist-info/RECORD +0 -179
  171. {zebra_day-1.0.2.dist-info → zebra_day-2.1.4.dist-info}/WHEEL +0 -0
  172. {zebra_day-1.0.2.dist-info → zebra_day-2.1.4.dist-info}/entry_points.txt +0 -0
  173. {zebra_day-1.0.2.dist-info → zebra_day-2.1.4.dist-info}/licenses/LICENSE +0 -0
  174. {zebra_day-1.0.2.dist-info → zebra_day-2.1.4.dist-info}/top_level.txt +0 -0
@@ -32,7 +32,7 @@
32
32
  {% if printers %}
33
33
  <div class="card">
34
34
  <div class="card-header">
35
- <h3 class="card-title">Printers{% if lab %} in {{ lab }}{% endif %}</h3>
35
+ <h3 class="card-title">Printers{% if lab %} in {{ lab_name | default(lab) }}{% endif %}</h3>
36
36
  <a href="/config?action=scan&lab={{ lab | default('') }}" class="btn btn-outline btn-sm">
37
37
  <i class="fas fa-sync"></i> Rescan
38
38
  </a>
@@ -42,6 +42,7 @@
42
42
  <thead>
43
43
  <tr>
44
44
  <th>Printer</th>
45
+ <th>Location</th>
45
46
  <th>IP Address</th>
46
47
  <th>Status</th>
47
48
  <th>Label Styles</th>
@@ -53,7 +54,17 @@
53
54
  <tr>
54
55
  <td>
55
56
  <strong>{{ printer.name }}</strong><br>
56
- <small class="text-muted">{{ printer.model | default('Unknown model') }}</small>
57
+ <small class="text-muted">{{ printer.manufacturer | default('zebra') | title }} {{ printer.model | default('Unknown model') }}</small>
58
+ {% if printer.id != printer.name %}
59
+ <br><small class="text-muted">ID: {{ printer.id }}</small>
60
+ {% endif %}
61
+ </td>
62
+ <td>
63
+ {% if printer.lab_location %}
64
+ <span class="badge badge-info">{{ printer.lab_location }}</span>
65
+ {% else %}
66
+ <span class="text-muted">—</span>
67
+ {% endif %}
57
68
  </td>
58
69
  <td>
59
70
  {% if printer.ip_address != 'dl_png' %}
@@ -64,9 +75,9 @@
64
75
  </td>
65
76
  <td>
66
77
  {% if printer.status == 'online' %}
67
- <span class="badge badge-success">Online</span>
78
+ <span class="badge badge-success"><i class="fas fa-check-circle"></i> Online</span>
68
79
  {% else %}
69
- <span class="badge badge-error">Offline</span>
80
+ <span class="badge badge-error"><i class="fas fa-times-circle"></i> Offline</span>
70
81
  {% endif %}
71
82
  </td>
72
83
  <td>
@@ -78,10 +89,10 @@
78
89
  {% endif %}
79
90
  </td>
80
91
  <td>
81
- <a href="/printers/{{ lab }}/{{ printer.name }}" class="btn btn-sm btn-outline">
92
+ <a href="/printers/{{ lab }}/{{ printer.id }}" class="btn btn-sm btn-outline">
82
93
  <i class="fas fa-info-circle"></i> Details
83
94
  </a>
84
- <a href="/print?lab={{ lab }}&printer={{ printer.name }}" class="btn btn-sm btn-primary">
95
+ <a href="/print?lab={{ lab }}&printer={{ printer.id }}" class="btn btn-sm btn-primary">
85
96
  <i class="fas fa-print"></i> Print
86
97
  </a>
87
98
  </td>
@@ -113,11 +113,14 @@
113
113
  var lab = labSelect.value;
114
114
 
115
115
  printerSelect.innerHTML = '<option value="">Select printer...</option>';
116
- if (lab && labsDict[lab]) {
117
- for (var printer in labsDict[lab]) {
116
+ if (lab && labsDict[lab] && labsDict[lab].printers) {
117
+ // v2 schema: printers are nested under 'printers' key
118
+ var printers = labsDict[lab].printers;
119
+ for (var printerId in printers) {
120
+ var printerInfo = printers[printerId];
118
121
  var option = document.createElement('option');
119
- option.value = printer;
120
- option.text = printer;
122
+ option.value = printerId;
123
+ option.text = printerInfo.printer_name || printerId;
121
124
  printerSelect.appendChild(option);
122
125
  }
123
126
  }
zebra_day/web/__init__.py CHANGED
@@ -3,7 +3,7 @@ zebra_day web application module.
3
3
 
4
4
  FastAPI-based web interface for managing Zebra printers and label templates.
5
5
  """
6
+
6
7
  from zebra_day.web.app import create_app
7
8
 
8
9
  __all__ = ["create_app"]
9
-
zebra_day/web/app.py CHANGED
@@ -3,20 +3,21 @@ FastAPI application factory for zebra_day.
3
3
 
4
4
  This module provides the main FastAPI application for the zebra_day web interface.
5
5
  """
6
+
6
7
  from __future__ import annotations
7
8
 
8
9
  import os
9
10
  import subprocess
11
+ from importlib.resources import files
10
12
  from pathlib import Path
11
- from typing import Literal, Optional
13
+ from typing import Literal
12
14
 
13
- from fastapi import FastAPI, Request
15
+ from fastapi import FastAPI
14
16
  from fastapi.staticfiles import StaticFiles
15
17
  from fastapi.templating import Jinja2Templates
16
- from importlib.resources import files
17
18
 
18
- from zebra_day.logging_config import get_logger
19
19
  from zebra_day import paths as xdg
20
+ from zebra_day.logging_config import get_logger
20
21
  from zebra_day.web.middleware import RequestLoggingMiddleware, print_rate_limiter
21
22
 
22
23
  _log = get_logger(__name__)
@@ -39,7 +40,7 @@ def create_app(
39
40
  *,
40
41
  debug: bool = False,
41
42
  css_theme: str = "lsmc.css",
42
- auth: Optional[Literal["none", "cognito"]] = None,
43
+ auth: Literal["none", "cognito"] | None = None,
43
44
  ) -> FastAPI:
44
45
  """
45
46
  Create and configure the FastAPI application.
@@ -76,7 +77,7 @@ def create_app(
76
77
  from zebra_day.web.auth import CognitoAuthMiddleware, setup_cognito_auth
77
78
 
78
79
  cognito_auth = setup_cognito_auth(app)
79
- app.add_middleware(CognitoAuthMiddleware, cognito_auth=cognito_auth)
80
+ app.add_middleware(CognitoAuthMiddleware, cognito_auth=cognito_auth) # type: ignore[arg-type]
80
81
  app.state.cognito_auth = cognito_auth
81
82
  app.state.auth_mode = "cognito"
82
83
  _log.info("Cognito authentication middleware enabled")
@@ -96,9 +97,14 @@ def create_app(
96
97
  app.mount("/static", StaticFiles(directory=str(_STATIC_PATH)), name="static")
97
98
 
98
99
  # Also mount package directories that need to be served
99
- files_dir = _PKG_PATH / "files"
100
- if files_dir.exists():
101
- app.mount("/files", StaticFiles(directory=str(files_dir)), name="files")
100
+ # Package files directory (for templates, previews generated in-package)
101
+ pkg_files_dir = _PKG_PATH / "files"
102
+ pkg_files_dir.mkdir(parents=True, exist_ok=True)
103
+ app.mount("/files", StaticFiles(directory=str(pkg_files_dir)), name="files")
104
+
105
+ # XDG generated files directory (for PNG downloads from dl_png printer)
106
+ xdg_generated_dir = xdg.get_generated_files_dir()
107
+ app.mount("/generated", StaticFiles(directory=str(xdg_generated_dir)), name="generated")
102
108
 
103
109
  etc_dir = _PKG_PATH / "etc"
104
110
  if etc_dir.exists():
@@ -109,7 +115,7 @@ def create_app(
109
115
  app.state.templates = templates
110
116
 
111
117
  # Register routers
112
- from zebra_day.web.routers import ui, api
118
+ from zebra_day.web.routers import api, ui
113
119
 
114
120
  app.include_router(ui.router)
115
121
  app.include_router(api.router, prefix="/api/v1", tags=["api"])
@@ -141,11 +147,30 @@ def create_app(
141
147
  return app
142
148
 
143
149
 
150
+ def get_default_cert_paths() -> tuple[Path | None, Path | None]:
151
+ """
152
+ Get default certificate paths from XDG config directory.
153
+
154
+ Returns:
155
+ Tuple of (cert_path, key_path) or (None, None) if not found.
156
+ """
157
+ config_dir = xdg.get_config_dir()
158
+ cert_dir = config_dir / "certs"
159
+ cert_file = cert_dir / "server.crt"
160
+ key_file = cert_dir / "server.key"
161
+
162
+ if cert_file.exists() and key_file.exists():
163
+ return cert_file, key_file
164
+ return None, None
165
+
166
+
144
167
  def run_server(
145
168
  host: str = "0.0.0.0",
146
169
  port: int = 8118,
147
170
  reload: bool = False,
148
171
  auth: Literal["none", "cognito"] = "none",
172
+ ssl_certfile: str | None = None,
173
+ ssl_keyfile: str | None = None,
149
174
  ):
150
175
  """
151
176
  Run the FastAPI server using uvicorn.
@@ -155,17 +180,74 @@ def run_server(
155
180
  port: Port to listen on
156
181
  reload: Enable auto-reload for development
157
182
  auth: Authentication mode - "none" (public) or "cognito" (AWS Cognito)
183
+ ssl_certfile: Path to SSL certificate file (PEM format)
184
+ ssl_keyfile: Path to SSL private key file (PEM format)
185
+
186
+ If ssl_certfile and ssl_keyfile are not provided, the server will:
187
+ 1. Check SSL_CERT_PATH and SSL_KEY_PATH environment variables
188
+ 2. Check for certificates in ~/.config/zebra_day/certs/
189
+ 3. Fall back to HTTP with a warning if no certificates are found
158
190
  """
159
191
  import uvicorn
160
192
 
161
193
  # Store auth mode in environment for factory function
162
194
  os.environ["ZEBRA_DAY_AUTH_MODE"] = auth
163
195
 
164
- uvicorn.run(
165
- "zebra_day.web.app:create_app",
166
- host=host,
167
- port=port,
168
- reload=reload,
169
- factory=True,
170
- )
196
+ # Resolve SSL certificate paths
197
+ cert_path = ssl_certfile
198
+ key_path = ssl_keyfile
199
+
200
+ # Check environment variables if not provided
201
+ if not cert_path:
202
+ cert_path = os.environ.get("SSL_CERT_PATH")
203
+ if not key_path:
204
+ key_path = os.environ.get("SSL_KEY_PATH")
205
+
206
+ # Check default XDG paths if still not found
207
+ if not cert_path or not key_path:
208
+ default_cert, default_key = get_default_cert_paths()
209
+ if default_cert and default_key:
210
+ cert_path = str(default_cert)
211
+ key_path = str(default_key)
212
+
213
+ # Validate certificate files exist
214
+ use_ssl = False
215
+ if cert_path and key_path:
216
+ cert_exists = Path(cert_path).exists()
217
+ key_exists = Path(key_path).exists()
218
+ if cert_exists and key_exists:
219
+ use_ssl = True
220
+ _log.info("HTTPS enabled with certificates:")
221
+ _log.info(" Certificate: %s", cert_path)
222
+ _log.info(" Private key: %s", key_path)
223
+ else:
224
+ if not cert_exists:
225
+ _log.warning("SSL certificate not found: %s", cert_path)
226
+ if not key_exists:
227
+ _log.warning("SSL private key not found: %s", key_path)
228
+ _log.warning("Falling back to HTTP (insecure)")
229
+ else:
230
+ _log.warning(
231
+ "No SSL certificates configured. Running in HTTP mode (insecure). "
232
+ "For HTTPS, run: mkcert -install && mkcert -cert-file ~/.config/zebra_day/certs/server.crt "
233
+ "-key-file ~/.config/zebra_day/certs/server.key localhost 127.0.0.1 ::1"
234
+ )
235
+
236
+ # Build uvicorn config
237
+ uvicorn_kwargs: dict[str, str | int | bool | None] = {
238
+ "host": host,
239
+ "port": port,
240
+ "reload": reload,
241
+ "factory": True,
242
+ }
243
+
244
+ if use_ssl:
245
+ uvicorn_kwargs["ssl_certfile"] = cert_path
246
+ uvicorn_kwargs["ssl_keyfile"] = key_path
247
+ protocol = "https"
248
+ else:
249
+ protocol = "http"
250
+
251
+ _log.info("Starting server at %s://%s:%d", protocol, host, port)
171
252
 
253
+ uvicorn.run("zebra_day.web.app:create_app", **uvicorn_kwargs) # type: ignore[arg-type]
zebra_day/web/auth.py CHANGED
@@ -5,10 +5,10 @@ Provides optional Cognito authentication support via the daylily-cognito library
5
5
 
6
6
  from __future__ import annotations
7
7
 
8
- import os
9
- from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional
8
+ from collections.abc import Callable
9
+ from typing import TYPE_CHECKING, Any
10
10
 
11
- from fastapi import Depends, HTTPException, Request, status
11
+ from fastapi import HTTPException, Request, status
12
12
  from starlette.middleware.base import BaseHTTPMiddleware
13
13
  from starlette.responses import Response
14
14
 
@@ -20,7 +20,7 @@ if TYPE_CHECKING:
20
20
  _log = get_logger(__name__)
21
21
 
22
22
  # Endpoints that should never require authentication
23
- PUBLIC_PATHS: List[str] = [
23
+ PUBLIC_PATHS: list[str] = [
24
24
  "/healthz",
25
25
  "/readyz",
26
26
  "/docs",
@@ -30,7 +30,7 @@ PUBLIC_PATHS: List[str] = [
30
30
 
31
31
  # Try to import daylily-cognito components
32
32
  _COGNITO_AVAILABLE = False
33
- _COGNITO_IMPORT_ERROR: Optional[str] = None
33
+ _COGNITO_IMPORT_ERROR: str | None = None
34
34
 
35
35
  try:
36
36
  from daylily_cognito import CognitoAuth, CognitoConfig, create_auth_dependency
@@ -38,9 +38,9 @@ try:
38
38
  _COGNITO_AVAILABLE = True
39
39
  except ImportError as e:
40
40
  _COGNITO_IMPORT_ERROR = str(e)
41
- CognitoAuth = None # type: ignore[misc, assignment]
42
- CognitoConfig = None # type: ignore[misc, assignment]
43
- create_auth_dependency = None # type: ignore[misc, assignment]
41
+ CognitoAuth = None
42
+ CognitoConfig = None
43
+ create_auth_dependency = None
44
44
 
45
45
 
46
46
  def is_cognito_available() -> bool:
@@ -48,7 +48,7 @@ def is_cognito_available() -> bool:
48
48
  return _COGNITO_AVAILABLE
49
49
 
50
50
 
51
- def get_cognito_import_error() -> Optional[str]:
51
+ def get_cognito_import_error() -> str | None:
52
52
  """Get the import error message if daylily-cognito is not available."""
53
53
  return _COGNITO_IMPORT_ERROR
54
54
 
@@ -59,7 +59,7 @@ class CognitoAuthMiddleware(BaseHTTPMiddleware):
59
59
  Exempts health check endpoints and other public paths.
60
60
  """
61
61
 
62
- def __init__(self, app: "FastAPI", cognito_auth: Any) -> None:
62
+ def __init__(self, app: FastAPI, cognito_auth: Any) -> None:
63
63
  super().__init__(app)
64
64
  self.cognito_auth = cognito_auth
65
65
  self.get_current_user = create_auth_dependency(cognito_auth, optional=False)
@@ -70,11 +70,13 @@ class CognitoAuthMiddleware(BaseHTTPMiddleware):
70
70
 
71
71
  # Allow public endpoints without authentication
72
72
  if any(path.startswith(public) for public in PUBLIC_PATHS):
73
- return await call_next(request)
73
+ response = await call_next(request)
74
+ return response # type: ignore[no-any-return]
74
75
 
75
76
  # Allow static files without authentication
76
77
  if path.startswith("/static") or path.startswith("/files") or path.startswith("/etc"):
77
- return await call_next(request)
78
+ response = await call_next(request)
79
+ return response # type: ignore[no-any-return]
78
80
 
79
81
  # Check for Authorization header
80
82
  auth_header = request.headers.get("Authorization")
@@ -116,10 +118,11 @@ class CognitoAuthMiddleware(BaseHTTPMiddleware):
116
118
  headers={"WWW-Authenticate": "Bearer"},
117
119
  )
118
120
 
119
- return await call_next(request)
121
+ response = await call_next(request)
122
+ return response # type: ignore[no-any-return]
120
123
 
121
124
 
122
- def setup_cognito_auth(app: "FastAPI") -> Any:
125
+ def setup_cognito_auth(app: FastAPI) -> Any:
123
126
  """Configure Cognito authentication for the FastAPI app.
124
127
 
125
128
  Reads configuration from environment variables:
@@ -169,4 +172,3 @@ def setup_cognito_auth(app: "FastAPI") -> Any:
169
172
  )
170
173
 
171
174
  return cognito_auth
172
-
@@ -3,12 +3,13 @@ Middleware for the zebra_day FastAPI application.
3
3
 
4
4
  Provides request logging and rate limiting functionality.
5
5
  """
6
+
6
7
  from __future__ import annotations
7
8
 
8
9
  import asyncio
9
10
  import time
10
11
  from collections import defaultdict
11
- from typing import Callable
12
+ from collections.abc import Callable
12
13
 
13
14
  from fastapi import Request, Response
14
15
  from starlette.middleware.base import BaseHTTPMiddleware
@@ -33,7 +34,7 @@ class RequestLoggingMiddleware(BaseHTTPMiddleware):
33
34
  client_ip = request.client.host if request.client else "unknown"
34
35
  method = request.method
35
36
  path = request.url.path
36
- query = str(request.query_params) if request.query_params else ""
37
+ str(request.query_params) if request.query_params else ""
37
38
 
38
39
  # Extract relevant parameters for print operations
39
40
  lab = request.query_params.get("lab", "")
@@ -86,7 +87,7 @@ class RequestLoggingMiddleware(BaseHTTPMiddleware):
86
87
  else:
87
88
  _log.info("Request completed", extra=log_context)
88
89
 
89
- return response
90
+ return response # type: ignore[no-any-return]
90
91
 
91
92
 
92
93
  class PrintRateLimiter:
@@ -136,7 +137,10 @@ class PrintRateLimiter:
136
137
 
137
138
  # Check rate limit
138
139
  if len(self._request_times[client_ip]) >= self.max_requests:
139
- return False, f"Rate limit exceeded: {self.max_requests} requests per {self.window_seconds}s"
140
+ return (
141
+ False,
142
+ f"Rate limit exceeded: {self.max_requests} requests per {self.window_seconds}s",
143
+ )
140
144
 
141
145
  # Try to acquire semaphore (non-blocking check)
142
146
  if self._semaphore.locked() and self._semaphore._value == 0:
@@ -156,4 +160,3 @@ class PrintRateLimiter:
156
160
 
157
161
  # Global rate limiter instance
158
162
  print_rate_limiter = PrintRateLimiter()
159
-
@@ -1,2 +1 @@
1
1
  """FastAPI routers for zebra_day web application."""
2
-