Skip to content

Commit eae3dd1

Browse files
committed
Restore logging prefix
1 parent e703450 commit eae3dd1

5 files changed

Lines changed: 76 additions & 70 deletions

File tree

pyproject.toml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "sanescansrv"
7-
version = "2.0.0"
7+
version = "2.1.0"
88
authors = [
99
{ name="CoolCat467" },
1010
]
@@ -55,3 +55,13 @@ warn_unused_ignores = true
5555
[tool.black]
5656
line-length = 79
5757
target-version = ['py311']
58+
59+
[tool.isort]
60+
profile = "black"
61+
combine_as_imports = true
62+
line_length = 79
63+
skip = [".git", ".github", ".venv"]
64+
65+
[tool.pycln]
66+
all = true
67+
disable_all_dunder_policy = true

src/sanescansrv/__init__.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
from sanescansrv.server import __author__, __title__, __version__
2-
from sanescansrv.server import sane_run as run
1+
from sanescansrv.server import (
2+
__author__,
3+
__title__,
4+
__version__,
5+
sane_run as run,
6+
)
37

48
print(f"{__title__} v{__version__} Copyright (C) 2023 {__author__}\n")
59

src/sanescansrv/config.ini

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/sanescansrv/logger.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,24 @@
1313
import time
1414
from os import makedirs, path
1515

16+
PROGRAM_TITLE: str = __title__
17+
18+
19+
def set_title(title: str) -> None:
20+
"""Set program title"""
21+
global PROGRAM_TITLE
22+
PROGRAM_TITLE = title
23+
1624

1725
def log(message: str, level: int = 1, log_dir: str | None = None) -> None:
1826
"""Log a message to console and log file."""
1927
levels = ["DEBUG", "INFO", "ERROR"]
2028

2129
if log_dir is None:
22-
log_dir = path.join(path.dirname(__file__), "logs")
30+
# log_dir = path.join(path.dirname(__file__), "logs")
31+
log_dir = path.abspath(
32+
path.expanduser(path.join("~", ".sanescansrv", "logs"))
33+
)
2334
if not path.exists(log_dir):
2435
makedirs(log_dir, exist_ok=True)
2536
filename = time.strftime("log_%Y_%m_%d.log")
@@ -29,7 +40,9 @@ def log(message: str, level: int = 1, log_dir: str | None = None) -> None:
2940
log_time = time.asctime()
3041
log_message_text = message.encode("unicode_escape").decode("utf-8")
3142

32-
log_msg = f"[{__title__}] [{log_time}] [{log_level}] {log_message_text}"
43+
log_msg = (
44+
f"[{PROGRAM_TITLE}] [{log_time}] [{log_level}] {log_message_text}"
45+
)
3346

3447
if not path.exists(log_file):
3548
with open(log_file, mode="w", encoding="utf-8") as file:

src/sanescansrv/server.py

Lines changed: 44 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#!/usr/bin/env python3
22
# -*- coding: utf-8 -*-
3-
# Scanner Web Server - Website to talk to scanimage
3+
# Scanner Web Server - Website to talk to SANE scanners
44

5-
"""Scanner Web Server - Website to talk to scanimage
5+
"""Scanner Web Server - Website to talk to SANE scanners
66
Copyright (C) 2022 CoolCat467
77
88
This program is free software: you can redistribute it and/or modify
@@ -23,6 +23,7 @@
2323
__title__ = "Sane Scanner Web Server"
2424
__author__ = "CoolCat467"
2525
__version__ = "2.1.0"
26+
__license__ = "GPLv3"
2627

2728

2829
import socket
@@ -40,19 +41,19 @@
4041
from hypercorn.trio import serve
4142
from jinja2 import Template
4243
from quart import Response, request
43-
from quart.templating import render_template as quart_render_template
4444
from quart.templating import stream_template as quart_stream_template
4545
from quart_trio import QuartTrio
4646
from werkzeug import Response as wkresp
4747

48-
from sanescansrv import htmlgen
48+
from sanescansrv import htmlgen, logger
4949
from sanescansrv.logger import log
5050

51+
# For some reason error class is not exposed nicely; Let's fix that
5152
SaneError = sane._sane.error
52-
53+
logger.set_title(__title__)
5354

5455
# Stolen from WOOF (Web Offer One File), Copyright (C) 2004-2009 Simon Budig,
55-
# avalable at http://www.home.unix-ag.org/simon/woof
56+
# available at http://www.home.unix-ag.org/simon/woof
5657
# with modifications
5758

5859
# Utility function to guess the IP (as a string) where the server can be
@@ -107,6 +108,7 @@ def __init__(
107108
self.title = title
108109
self.options = options
109110
self.default = default
111+
self.unit = unit
110112
self.desc = desc
111113
self.set = self.default
112114

@@ -117,37 +119,17 @@ def as_argument(self) -> str:
117119
def __repr__(self) -> str:
118120
return (
119121
f"DeviceSetting({self.name!r}, {self.title!r}, "
120-
f"{self.options!r}, {self.default!r}, {self.desc!r})"
122+
f"{self.options!r}, {self.default!r}, {self.unit!r}, "
123+
f"{self.desc!r})"
121124
)
122125

123126

124-
app: Final = QuartTrio(
127+
app: Final = QuartTrio( # pylint: disable=invalid-name
125128
__name__,
126129
static_folder="static",
127130
template_folder="templates",
128-
) # pylint: disable=invalid-name
129-
app_storage: Final[dict[str, Any]] = {} # pylint: disable=invalid-name
130-
131-
132-
async def render_template(
133-
template_name_or_list: str | list[str], **context: Any
134-
) -> str:
135-
"""Render the template with the context given.
136-
137-
Arguments:
138-
template_name_or_list: Template name to render of a list of
139-
possible template names.
140-
context: The variables to pass to the template.
141-
142-
Patched to remove blank lines left by jinja statements"""
143-
content = await quart_render_template(template_name_or_list, **context)
144-
new_content = []
145-
for line in content.splitlines():
146-
new_line = line.rstrip()
147-
if not new_line:
148-
continue
149-
new_content.append(new_line)
150-
return "\n".join(new_content)
131+
)
132+
APP_STORAGE: Final[dict[str, Any]] = {}
151133

152134

153135
async def stream_template(
@@ -165,7 +147,7 @@ async def stream_template(
165147
context: The variables to make available in the template.
166148
167149
Patched to remove blank lines left by jinja statements"""
168-
# Generate stream in this async block before context is lost
150+
# Generate stream in this async scope before context is lost
169151
stream = await quart_stream_template(template_name_or_list, **context)
170152

171153
# Create async generator filter
@@ -220,7 +202,7 @@ def get_device_settings(device_addr: str) -> list[DeviceSetting]:
220202
default = "None"
221203
try:
222204
default = str(getattr(device, option.py_name))
223-
except Exception:
205+
except (AttributeError, ValueError):
224206
pass
225207
unit = sane.UNIT_STR[option.unit].removeprefix("UNIT_")
226208

@@ -245,7 +227,7 @@ def display_progress(current: int, total: int) -> None:
245227

246228

247229
def preform_scan(device_name: str, out_type: str = "png") -> str:
248-
"Scan using device and return path."
230+
"""Scan using device and return path."""
249231
if out_type not in {"pnm", "tiff", "png", "jpeg"}:
250232
raise ValueError("Output type must be pnm, tiff, png, or jpeg")
251233
filename = f"scan.{out_type}"
@@ -255,7 +237,7 @@ def preform_scan(device_name: str, out_type: str = "png") -> str:
255237
ints = {"TYPE_BOOL", "TYPE_INT"}
256238

257239
with sane.open(device_name) as device:
258-
for setting in app_storage["device_settings"][device_name]:
240+
for setting in APP_STORAGE["device_settings"][device_name]:
259241
name = setting.name.replace("-", "_")
260242
value: str | int = setting.set
261243
if sane.TYPE_STR[device[name].type] in ints:
@@ -273,16 +255,16 @@ def preform_scan(device_name: str, out_type: str = "png") -> str:
273255

274256
@app.get("/")
275257
async def root_get() -> AsyncIterator[str]:
276-
"Main page get request"
258+
"""Main page get request"""
277259
scanners = {}
278260
default = "none"
279261

280-
if app_storage["scanners"]:
281-
scanners = {k: k for k in app_storage["scanners"]}
262+
if APP_STORAGE["scanners"]:
263+
scanners = {k: k for k in APP_STORAGE["scanners"]}
282264
# Since radio_select_dict is if comparison for
283265
# default, if default device does not exist
284266
# there simply won't be a default shown.
285-
default = app_storage["default_device"]
267+
default = APP_STORAGE["default_device"]
286268

287269
return await stream_template(
288270
"root_get.html.jinja",
@@ -293,13 +275,13 @@ async def root_get() -> AsyncIterator[str]:
293275

294276
@app.post("/")
295277
async def root_post() -> Response | wkresp:
296-
"Main page post handling"
278+
"""Main page post handling"""
297279
multi_dict = await request.form
298280
data = multi_dict.to_dict()
299281

300282
# Validate input
301283
img_format = data.get("img_format", "png")
302-
device = app_storage["scanners"].get(data.get("scanner"), "none")
284+
device = APP_STORAGE["scanners"].get(data.get("scanner"), "none")
303285

304286
if img_format not in {"pnm", "tiff", "png", "jpeg"}:
305287
return app.redirect("/")
@@ -313,18 +295,18 @@ async def root_post() -> Response | wkresp:
313295

314296
@app.get("/update_scanners")
315297
async def update_scanners_get() -> wkresp:
316-
"Update scanners get handling"
317-
app_storage["scanners"] = get_devices()
318-
for device in app_storage["scanners"].values():
319-
app_storage["device_settings"][device] = get_device_settings(device)
298+
"""Update scanners get handling"""
299+
APP_STORAGE["scanners"] = get_devices()
300+
for device in APP_STORAGE["scanners"].values():
301+
APP_STORAGE["device_settings"][device] = get_device_settings(device)
320302
return app.redirect("scanners")
321303

322304

323305
@app.get("/scanners")
324306
async def scanners_get() -> AsyncIterator[str]:
325-
"Scanners page get handling"
307+
"""Scanners page get handling"""
326308
scanners = {}
327-
for display in app_storage.get("scanners", {}):
309+
for display in APP_STORAGE.get("scanners", {}):
328310
scanner_url = urlencode({"scanner": display})
329311
scanners[f"/settings?{scanner_url}"] = display
330312

@@ -335,7 +317,7 @@ async def scanners_get() -> AsyncIterator[str]:
335317

336318

337319
def get_setting_radio(setting: DeviceSetting) -> str:
338-
"Return setting radio section"
320+
"""Return setting radio section"""
339321
options = {x.title(): x for x in setting.options}
340322
if set(options.keys()) == {"1", "0"}:
341323
options = {"True": "1", "False": "0"}
@@ -346,14 +328,14 @@ def get_setting_radio(setting: DeviceSetting) -> str:
346328

347329
@app.get("/settings")
348330
async def settings_get() -> AsyncIterator[str] | wkresp:
349-
"Settings page get handling"
331+
"""Settings page get handling"""
350332
scanner = request.args.get("scanner", "none")
351333

352-
if scanner == "none" or scanner not in app_storage["scanners"]:
334+
if scanner == "none" or scanner not in APP_STORAGE["scanners"]:
353335
return app.redirect("/scanners")
354336

355-
device = app_storage["scanners"][scanner]
356-
scanner_settings = app_storage["device_settings"].get(device, [])
337+
device = APP_STORAGE["scanners"][scanner]
338+
scanner_settings = APP_STORAGE["device_settings"].get(device, [])
357339

358340
return await stream_template(
359341
"settings_get.html.jinja",
@@ -366,14 +348,14 @@ async def settings_get() -> AsyncIterator[str] | wkresp:
366348

367349
@app.post("/settings")
368350
async def settings_post() -> wkresp:
369-
"Settings page post handling"
351+
"""Settings page post handling"""
370352
scanner = request.args.get("scanner", "none")
371353

372-
if scanner == "none" or scanner not in app_storage["scanners"]:
354+
if scanner == "none" or scanner not in APP_STORAGE["scanners"]:
373355
return app.redirect("/scanners")
374356

375-
device = app_storage["scanners"][scanner]
376-
scanner_settings = app_storage["device_settings"][device]
357+
device = APP_STORAGE["scanners"][scanner]
358+
scanner_settings = APP_STORAGE["device_settings"][device]
377359

378360
valid_settings = {
379361
setting.name: idx for idx, setting in enumerate(scanner_settings)
@@ -389,7 +371,7 @@ async def settings_post() -> wkresp:
389371
idx = valid_settings[setting_name]
390372
if new_value not in scanner_settings[idx].options:
391373
continue
392-
app_storage["device_settings"][device][idx].set = new_value
374+
APP_STORAGE["device_settings"][device][idx].set = new_value
393375

394376
# Return to page for that scanner
395377
return app.redirect(request.url)
@@ -423,9 +405,9 @@ async def serve_scanner(
423405

424406
config_obj = Config.from_mapping(config)
425407

426-
app_storage["scanners"] = {}
427-
app_storage["default_device"] = device_name
428-
app_storage["device_settings"] = {}
408+
APP_STORAGE["scanners"] = {}
409+
APP_STORAGE["default_device"] = device_name
410+
APP_STORAGE["device_settings"] = {}
429411

430412
print(f"Serving on http://{location}\n(CTRL + C to quit)")
431413

@@ -438,7 +420,7 @@ async def serve_scanner(
438420

439421

440422
def run() -> None:
441-
"Run scanner server"
423+
"""Run scanner server"""
442424
root_dir = path.abspath(path.expanduser(path.join("~", ".sanescansrv")))
443425
if not path.exists(root_dir):
444426
makedirs(root_dir, exist_ok=True)
@@ -500,7 +482,7 @@ def run() -> None:
500482

501483

502484
def sane_run() -> None:
503-
"""Run but also handle initializing and uninitializing SANE"""
485+
"""Run but also handle initializing and un-initializing SANE"""
504486
try:
505487
sane.init()
506488
run()

0 commit comments

Comments
 (0)