azpaddypy 0.4.0__py3-none-any.whl → 0.4.2__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.
- azpaddypy/mgmt/__init__.py +3 -0
- azpaddypy/mgmt/local_env_manager.py +202 -0
- {azpaddypy-0.4.0.dist-info → azpaddypy-0.4.2.dist-info}/METADATA +1 -1
- {azpaddypy-0.4.0.dist-info → azpaddypy-0.4.2.dist-info}/RECORD +7 -6
- {azpaddypy-0.4.0.dist-info → azpaddypy-0.4.2.dist-info}/WHEEL +0 -0
- {azpaddypy-0.4.0.dist-info → azpaddypy-0.4.2.dist-info}/licenses/LICENSE +0 -0
- {azpaddypy-0.4.0.dist-info → azpaddypy-0.4.2.dist-info}/top_level.txt +0 -0
azpaddypy/mgmt/__init__.py
CHANGED
@@ -6,8 +6,11 @@ __version__ = "0.1.0"
|
|
6
6
|
|
7
7
|
from azpaddypy.mgmt.logging import AzureLogger
|
8
8
|
from azpaddypy.mgmt.identity import AzureIdentity
|
9
|
+
from azpaddypy.mgmt.local_env_manager import LocalDevelopmentSettings, create_local_env_manager
|
9
10
|
|
10
11
|
__all__ = [
|
11
12
|
"AzureLogger",
|
12
13
|
"AzureIdentity",
|
14
|
+
"LocalDevelopmentSettings",
|
15
|
+
"create_local_env_manager",
|
13
16
|
]
|
@@ -0,0 +1,202 @@
|
|
1
|
+
import os
|
2
|
+
import json
|
3
|
+
import pathlib
|
4
|
+
from typing import Dict, Optional, Union
|
5
|
+
from .logging import AzureLogger
|
6
|
+
|
7
|
+
|
8
|
+
class LocalDevelopmentSettings:
|
9
|
+
"""Manages loading of local development settings from .env and JSON files.
|
10
|
+
|
11
|
+
This class provides a standardized way to load configuration from
|
12
|
+
.env files and Azure Functions-style `local.settings.json` files into
|
13
|
+
environment variables, making local development environments consistent
|
14
|
+
with deployed Azure environments.
|
15
|
+
|
16
|
+
It supports overriding existing environment variables and provides clear
|
17
|
+
logging for loaded settings.
|
18
|
+
|
19
|
+
Attributes:
|
20
|
+
logger: An instance of AzureLogger for structured logging.
|
21
|
+
"""
|
22
|
+
|
23
|
+
def __init__(
|
24
|
+
self,
|
25
|
+
service_name: str = "local_dev_settings",
|
26
|
+
service_version: str = "1.0.0",
|
27
|
+
logger: Optional[AzureLogger] = None,
|
28
|
+
connection_string: Optional[str] = None,
|
29
|
+
):
|
30
|
+
"""Initializes the LocalDevelopmentSettings manager.
|
31
|
+
|
32
|
+
Args:
|
33
|
+
service_name: The name of the service using the settings manager.
|
34
|
+
service_version: The version of the service.
|
35
|
+
logger: An optional existing AzureLogger instance.
|
36
|
+
connection_string: Application Insights connection string for a new logger.
|
37
|
+
"""
|
38
|
+
if logger:
|
39
|
+
self.logger = logger
|
40
|
+
else:
|
41
|
+
self.logger = AzureLogger(
|
42
|
+
service_name=service_name,
|
43
|
+
service_version=service_version,
|
44
|
+
connection_string=connection_string,
|
45
|
+
enable_console_logging=True,
|
46
|
+
)
|
47
|
+
self.logger.info("LocalDevelopmentSettings initialized.")
|
48
|
+
|
49
|
+
def load_from_dotenv(
|
50
|
+
self,
|
51
|
+
dotenv_path: Union[str, pathlib.Path],
|
52
|
+
override: bool = False
|
53
|
+
) -> bool:
|
54
|
+
"""Loads key-value pairs from a .env file into environment variables.
|
55
|
+
|
56
|
+
Args:
|
57
|
+
dotenv_path: The path to the .env file.
|
58
|
+
override: If True, existing environment variables will be overwritten.
|
59
|
+
|
60
|
+
Returns:
|
61
|
+
True if the file was loaded successfully, False otherwise.
|
62
|
+
"""
|
63
|
+
dotenv_path = pathlib.Path(dotenv_path)
|
64
|
+
if not dotenv_path.is_file():
|
65
|
+
self.logger.warning(f".env file not found at {dotenv_path}. Skipping.")
|
66
|
+
return False
|
67
|
+
|
68
|
+
try:
|
69
|
+
with open(dotenv_path, "r") as f:
|
70
|
+
for line in f:
|
71
|
+
line = line.strip()
|
72
|
+
if not line or line.startswith("#"):
|
73
|
+
continue
|
74
|
+
|
75
|
+
parts = line.split("=", 1)
|
76
|
+
if len(parts) != 2:
|
77
|
+
continue
|
78
|
+
|
79
|
+
key, value = parts[0].strip(), parts[1].strip()
|
80
|
+
value = value.replace('"', "")
|
81
|
+
|
82
|
+
if key not in os.environ or override:
|
83
|
+
os.environ[key] = value
|
84
|
+
self.logger.debug(f"Loaded from .env: {key}={value[:8]}...")
|
85
|
+
else:
|
86
|
+
self.logger.debug(f"Skipping from .env (exists): {key}")
|
87
|
+
|
88
|
+
self.logger.info(f"Successfully loaded settings from {dotenv_path}")
|
89
|
+
return True
|
90
|
+
except Exception as e:
|
91
|
+
self.logger.error(f"Error reading .env file at {dotenv_path}: {e}", exc_info=True)
|
92
|
+
return False
|
93
|
+
|
94
|
+
def load_from_json(
|
95
|
+
self,
|
96
|
+
json_path: Union[str, pathlib.Path],
|
97
|
+
override: bool = False
|
98
|
+
) -> bool:
|
99
|
+
"""Loads settings from a JSON file (e.g., local.settings.json).
|
100
|
+
|
101
|
+
The JSON file is expected to have a "Values" key containing a
|
102
|
+
dictionary of settings.
|
103
|
+
|
104
|
+
Args:
|
105
|
+
json_path: The path to the JSON settings file.
|
106
|
+
override: If True, existing environment variables will be overwritten.
|
107
|
+
|
108
|
+
Returns:
|
109
|
+
True if the file was loaded successfully, False otherwise.
|
110
|
+
"""
|
111
|
+
json_path = pathlib.Path(json_path)
|
112
|
+
if not json_path.is_file():
|
113
|
+
self.logger.warning(f"JSON settings file not found at {json_path}. Skipping.")
|
114
|
+
return False
|
115
|
+
|
116
|
+
try:
|
117
|
+
with open(json_path, "r") as f:
|
118
|
+
settings = json.load(f)
|
119
|
+
|
120
|
+
if "Values" in settings and isinstance(settings["Values"], dict):
|
121
|
+
for key, value in settings["Values"].items():
|
122
|
+
if key not in os.environ or override:
|
123
|
+
os.environ[key] = str(value)
|
124
|
+
self.logger.debug(f"Loaded from JSON: {key}={str(value)[:8]}...")
|
125
|
+
else:
|
126
|
+
self.logger.debug(f"Skipping from JSON (exists): {key}")
|
127
|
+
self.logger.info(f"Successfully loaded settings from {json_path}")
|
128
|
+
return True
|
129
|
+
else:
|
130
|
+
self.logger.warning(f"No 'Values' dictionary found in {json_path}. Skipping.")
|
131
|
+
return False
|
132
|
+
except json.JSONDecodeError:
|
133
|
+
self.logger.error(f"Error decoding JSON from {json_path}.", exc_info=True)
|
134
|
+
return False
|
135
|
+
except Exception as e:
|
136
|
+
self.logger.error(f"Error reading JSON file at {json_path}: {e}", exc_info=True)
|
137
|
+
return False
|
138
|
+
|
139
|
+
def apply_settings(
|
140
|
+
self,
|
141
|
+
settings: Dict[str, str],
|
142
|
+
override: bool = True
|
143
|
+
):
|
144
|
+
"""Applies a dictionary of settings to the environment variables.
|
145
|
+
|
146
|
+
Args:
|
147
|
+
settings: A dictionary of key-value pairs to set as environment variables.
|
148
|
+
override: If True, existing environment variables will be overwritten.
|
149
|
+
"""
|
150
|
+
for key, value in settings.items():
|
151
|
+
if key not in os.environ or override:
|
152
|
+
os.environ[key] = str(value)
|
153
|
+
self.logger.debug(f"Applied setting: {key}={str(value)[:8]}...")
|
154
|
+
else:
|
155
|
+
self.logger.debug(f"Skipping setting (exists): {key}")
|
156
|
+
self.logger.info(f"Applied {len(settings)} settings to environment.")
|
157
|
+
|
158
|
+
def print_settings(self):
|
159
|
+
"""Prints the current settings as a dictionary."""
|
160
|
+
for key, value in os.environ.items():
|
161
|
+
self.logger.debug(f"Setting: {key}={value[:8]}...")
|
162
|
+
|
163
|
+
|
164
|
+
def create_local_env_manager(
|
165
|
+
file_path: str = ".env",
|
166
|
+
settings: Optional[Dict[str, str]] = None,
|
167
|
+
logger: Optional[AzureLogger] = None,
|
168
|
+
override_json: bool = True,
|
169
|
+
override_dotenv: bool = True,
|
170
|
+
override_settings: bool = True
|
171
|
+
):
|
172
|
+
"""Convenience function to load settings from multiple sources.
|
173
|
+
|
174
|
+
This function orchestrates loading settings from a `local.settings.json` file,
|
175
|
+
a `.env` file, and a direct dictionary of settings, in that order.
|
176
|
+
|
177
|
+
Args:
|
178
|
+
file_path: Base path for `.env` or `local.settings.json`. The function
|
179
|
+
will look for both.
|
180
|
+
settings: A dictionary of settings to apply.
|
181
|
+
logger: An optional AzureLogger instance.
|
182
|
+
override_json: Whether settings from JSON should override existing env vars.
|
183
|
+
override_dotenv: Whether settings from .env should override existing env vars.
|
184
|
+
override_settings: Whether settings from the dictionary should override.
|
185
|
+
"""
|
186
|
+
manager = LocalDevelopmentSettings(logger=logger)
|
187
|
+
|
188
|
+
# Try loading local.settings.json
|
189
|
+
json_path = pathlib.Path(file_path).parent / "local.settings.json"
|
190
|
+
if json_path.is_file():
|
191
|
+
manager.load_from_json(json_path, override=override_json)
|
192
|
+
|
193
|
+
# Try loading .env
|
194
|
+
dotenv_path = pathlib.Path(file_path)
|
195
|
+
if dotenv_path.is_file() and dotenv_path.name == ".env":
|
196
|
+
manager.load_from_dotenv(dotenv_path, override=override_dotenv)
|
197
|
+
|
198
|
+
# Apply dictionary settings
|
199
|
+
if settings:
|
200
|
+
manager.apply_settings(settings, override=override_settings)
|
201
|
+
|
202
|
+
return manager
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: azpaddypy
|
3
|
-
Version: 0.4.
|
3
|
+
Version: 0.4.2
|
4
4
|
Summary: Comprehensive Python logger for Azure, integrating OpenTelemetry for advanced, structured, and distributed tracing.
|
5
5
|
Classifier: Programming Language :: Python :: 3
|
6
6
|
Classifier: Operating System :: OS Independent
|
@@ -1,11 +1,12 @@
|
|
1
1
|
azpaddypy/__init__.py,sha256=hrWNAh4OHZOvm3Pbhq5eUjO-pSRYn0h0W0J87tc-lNI,45
|
2
|
-
azpaddypy/mgmt/__init__.py,sha256
|
2
|
+
azpaddypy/mgmt/__init__.py,sha256=waW9EAnTFDh2530ieQX1Z0r0Z-ZKHRwabVDfapjfN58,441
|
3
3
|
azpaddypy/mgmt/identity.py,sha256=mA_krQslMsK_sDob-z-QA0B9khK_JUO2way7xwPopR8,12001
|
4
|
+
azpaddypy/mgmt/local_env_manager.py,sha256=fC9E3V8eMgMMgD1UtH596ntjAVhLaE5eQLG86NYpr5Y,7960
|
4
5
|
azpaddypy/mgmt/logging.py,sha256=3ZLSKwpX7Tprthrkm3uN4ph2n2CxiGYUNri7jBJuXEY,36514
|
5
6
|
azpaddypy/resources/__init__.py,sha256=Bvt3VK4RqwoxYpoh6EbLXIR18RuFPKaLP6zLL-icyFk,314
|
6
7
|
azpaddypy/resources/keyvault.py,sha256=4J08vLqoLFd1_UUDBji2oG2fatZaPkgnRyT_Z6wHAOc,20312
|
7
|
-
azpaddypy-0.4.
|
8
|
-
azpaddypy-0.4.
|
9
|
-
azpaddypy-0.4.
|
10
|
-
azpaddypy-0.4.
|
11
|
-
azpaddypy-0.4.
|
8
|
+
azpaddypy-0.4.2.dist-info/licenses/LICENSE,sha256=hQ6t0g2QaewGCQICHqTckBFbMVakGmoyTAzDpmEYV4c,1089
|
9
|
+
azpaddypy-0.4.2.dist-info/METADATA,sha256=OWfKqs9WR2Y7wI1Qx0HGFJNUo02zmVSHwsx8jLT16d8,665
|
10
|
+
azpaddypy-0.4.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
11
|
+
azpaddypy-0.4.2.dist-info/top_level.txt,sha256=hsDuboDhT61320ML8X479ezSTwT3rrlDWz1_Z45B2cs,10
|
12
|
+
azpaddypy-0.4.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|