oe-python-template 0.13.14__py3-none-any.whl → 0.13.16__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.
@@ -1,13 +1,15 @@
1
1
  """Logging configuration and utilities."""
2
2
 
3
3
  import logging as python_logging
4
+ import os
4
5
  import typing as t
5
6
  from logging import FileHandler
7
+ from pathlib import Path
6
8
  from typing import Annotated, Literal
7
9
 
8
10
  import click
9
11
  import logfire
10
- from pydantic import Field
12
+ from pydantic import AfterValidator, Field
11
13
  from pydantic_settings import BaseSettings, SettingsConfigDict
12
14
  from rich.console import Console
13
15
  from rich.logging import RichHandler
@@ -31,6 +33,44 @@ def get_logger(name: str | None) -> python_logging.Logger:
31
33
  return python_logging.getLogger(f"{__project_name__}.{name}")
32
34
 
33
35
 
36
+ def _validate_file_name(file_name: str | None) -> str | None:
37
+ """Validate the file_name is valid and the file writeable.
38
+
39
+ - Checks file_name does not yet exist or is a file
40
+ - If not yet existing, checks it can be created
41
+ - If existing file, checks file is writeable
42
+
43
+ Args:
44
+ file_name: The file name of the log file
45
+
46
+ Returns:
47
+ str | None: The validated file name
48
+
49
+ Raises:
50
+ ValueError: If file name is not valid or the file not writeable
51
+ """
52
+ if file_name is None:
53
+ return file_name
54
+
55
+ file_path = Path(file_name)
56
+ if file_path.exists():
57
+ if not file_path.is_file():
58
+ message = f"File name {file_path.absolute()} is not a file"
59
+ raise ValueError(message)
60
+ if not os.access(file_path, os.W_OK):
61
+ message = f"File {file_path.absolute()} is not writable"
62
+ raise ValueError(message)
63
+ else:
64
+ try:
65
+ file_path.touch(exist_ok=False)
66
+ file_path.unlink()
67
+ except OSError as e:
68
+ message = f"File {file_path.absolute()} cannot be created: {e}"
69
+ raise ValueError(message) from e
70
+
71
+ return file_name
72
+
73
+
34
74
  class LogSettings(BaseSettings):
35
75
  """Settings for configuring logging behavior."""
36
76
 
@@ -51,6 +91,7 @@ class LogSettings(BaseSettings):
51
91
  ]
52
92
  file_name: Annotated[
53
93
  str,
94
+ AfterValidator(_validate_file_name),
54
95
  Field(description="Name of the log file", default=f"{__project_name__}.log"),
55
96
  ]
56
97
  console_enabled: Annotated[
@@ -77,7 +77,7 @@ def _validate_sentry_domain(netloc_with_auth: str) -> None:
77
77
  raise ValueError(_ERR_MSG_INVALID_DOMAIN)
78
78
 
79
79
 
80
- def validate_https_dsn(value: SecretStr | None) -> SecretStr | None:
80
+ def _validate_https_dsn(value: SecretStr | None) -> SecretStr | None:
81
81
  """Validate that the Sentry DSN is a valid HTTPS URL.
82
82
 
83
83
  Args:
@@ -124,7 +124,7 @@ class SentrySettings(OpaqueSettings):
124
124
  dsn: Annotated[
125
125
  SecretStr | None,
126
126
  BeforeValidator(strip_to_none_before_validator),
127
- AfterValidator(validate_https_dsn),
127
+ AfterValidator(_validate_https_dsn),
128
128
  PlainSerializer(func=OpaqueSettings.serialize_sensitive_info, return_type=str, when_used="always"),
129
129
  Field(description="Sentry DSN", examples=["https://SECRET@SECRET.ingest.de.sentry.io/SECRET"], default=None),
130
130
  ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oe-python-template
3
- Version: 0.13.14
3
+ Version: 0.13.16
4
4
  Summary: 🧠 Copier template to scaffold Python projects compliant with best practices and modern tooling.
5
5
  Project-URL: Homepage, https://oe-python-template.readthedocs.io/en/latest/
6
6
  Project-URL: Documentation, https://oe-python-template.readthedocs.io/en/latest/
@@ -24,17 +24,17 @@ oe_python_template/utils/_constants.py,sha256=FRe5ZNaBwpBPwOHZVWYOlI-ijamfzdBVr8
24
24
  oe_python_template/utils/_di.py,sha256=KdjiD4xZ_QSfbddkKWwsPJmG5YrIg6dzuBrlsd-FhxA,2189
25
25
  oe_python_template/utils/_gui.py,sha256=PmMTSmUOxbf6pmYCIgKrK5wNheh35aGd90I12y3L7Uc,5720
26
26
  oe_python_template/utils/_health.py,sha256=35QOWe2r5InrEpGtuVMym9dI5aRHS0HWf4BHBRAUIj0,4102
27
- oe_python_template/utils/_log.py,sha256=ZW4gs540SdjVK-2KeheLfDY15d_3xpO5FyGn7wTXyaM,3592
27
+ oe_python_template/utils/_log.py,sha256=5tMW1xY_FlpPEfZNeaTCdngBF3FKp8VWmQatt4_7RFU,4863
28
28
  oe_python_template/utils/_logfire.py,sha256=wZYNVowQx7kh3XJoJ59FjUKdrta7tp6cXOJRUT6lDU8,2128
29
29
  oe_python_template/utils/_notebook.py,sha256=oBQw9IBcXjuhzd1ECfOEPN4WJHGOm9xiPtrs11GtWG4,1777
30
30
  oe_python_template/utils/_process.py,sha256=40R0NZMqJUn0iUPERzohSUpJgU1HcJApIg1HipIxFCw,941
31
- oe_python_template/utils/_sentry.py,sha256=7nONiWZP0hWX0QAEPcg7No3FF1BF4S-Sl0wgG7xLw8g,6367
31
+ oe_python_template/utils/_sentry.py,sha256=6SZknbGBpdZHYUpF-11qk6UYBM-c79U8D9sF4517kdU,6369
32
32
  oe_python_template/utils/_service.py,sha256=atHAejvBucKXjzhsMSdOBBFa7rRD74zcV70Pp0pl0Tg,1038
33
33
  oe_python_template/utils/_settings.py,sha256=owFoaHEzJnVD3EVyOWF4rfIY7g6eLnU6rN0m4VHhCbA,2464
34
34
  oe_python_template/utils/boot.py,sha256=Qgq1sjT8d3fcfibnMyx5CVUJ_KKXgFI3ozZUIJbhh4I,2921
35
35
  oe_python_template/utils/.vendored/bottle.py,sha256=kZAZmh3nRzCUf-9IKGpv0yqlMciZMA_DNaaMDdcQmt0,175437
36
- oe_python_template-0.13.14.dist-info/METADATA,sha256=535E3ddxUlLQusQdLrJGP0NyadIxqL-_H8v7p_NVYgk,34476
37
- oe_python_template-0.13.14.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
38
- oe_python_template-0.13.14.dist-info/entry_points.txt,sha256=IroSSWhLGxus9rxcashkYQda39TTvf7LbUMYtOKXUBE,66
39
- oe_python_template-0.13.14.dist-info/licenses/LICENSE,sha256=5H409K6xzz9U5eUaoAHQExNkoWJRlU0LEj6wL2QJ34s,1113
40
- oe_python_template-0.13.14.dist-info/RECORD,,
36
+ oe_python_template-0.13.16.dist-info/METADATA,sha256=zqRR7YIXUY-XV10xXh4MvmdN2SFKaPGJNmcuvsyDAuo,34476
37
+ oe_python_template-0.13.16.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
38
+ oe_python_template-0.13.16.dist-info/entry_points.txt,sha256=IroSSWhLGxus9rxcashkYQda39TTvf7LbUMYtOKXUBE,66
39
+ oe_python_template-0.13.16.dist-info/licenses/LICENSE,sha256=5H409K6xzz9U5eUaoAHQExNkoWJRlU0LEj6wL2QJ34s,1113
40
+ oe_python_template-0.13.16.dist-info/RECORD,,