Skip to content

Commit 287d2c0

Browse files
Merge pull request #4 from hmohammad2520-org/2-env-mixin
Adding ENVMod to classmods
2 parents b240dc3 + 2f3c2d7 commit 287d2c0

2 files changed

Lines changed: 78 additions & 5 deletions

File tree

classmods/_env_mod.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ def register(cls, *, exclude: Optional[List[str]] = None) -> Callable:
9595
Decorator to register class methods for env parsing.
9696
9797
Raise:
98-
TypeError: if a object is not env parsable.
98+
TypeError: If an argument is not env parsable.
9999
100100
Example:
101101
>>> class APIService:
@@ -110,10 +110,9 @@ def register(cls, *, exclude: Optional[List[str]] = None) -> Callable:
110110
) -> none:
111111
... ...
112112
113-
In this example ENVMod will create env items for each object in init except ssl_key.
113+
In this example ENVMod will create env items for each argument except ssl_key.
114114
115115
Note: Make sure you add type hints to get the same type when loading from env file.
116-
117116
"""
118117
exclude = exclude or []
119118

@@ -128,7 +127,7 @@ def decorator(func: Callable) -> Callable:
128127
type_hints = get_type_hints(func)
129128

130129
for param in sig.parameters.values():
131-
if param.name == 'self' or param.name in exclude:
130+
if param.name in ['self', 'cls'] or param.name in exclude:
132131
continue
133132

134133
param_type = type_hints.get(param.name, str)
@@ -196,17 +195,21 @@ def cast(value: str, _type: Type) -> Any:
196195
if value.lower() in ('1', 'true', 'yes'): return True
197196
elif value.lower() in ('0', 'false', 'no'): return False
198197
else: raise ValueError(f"Casting env is not a valid bool: {value}. valid bool: '0', 'false', 'no', '1', 'true', 'yes'")
198+
199199
return _type(value)
200200

201201
result = {}
202202
for arg, env_key in mapping.items():
203203
value = os.environ.get(env_key)
204-
if value is None:
204+
if value is None or value == '':
205205
result[arg] = None
206206
continue
207207

208208
result[arg] = cast(value, types.get(arg, str))
209209

210+
# Remove None from results
211+
result = {k: v for k, v in result.items() if v is not None}
212+
210213
return result
211214

212215
@classmethod

test/test_envmod.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import os
2+
from typing import Callable
3+
from classmods import ENVMod
4+
5+
class TestClass:
6+
@ENVMod.register(exclude=['service'])
7+
def __init__(self, name: str, age: int, service: Callable|None = None):
8+
"""
9+
Test Class.
10+
11+
Args:
12+
name: your name.
13+
age: your age.
14+
"""
15+
self.name = name
16+
self.age = age
17+
18+
@ENVMod.register()
19+
def _connect(self, host: str, timeout: float, port: int = 80):
20+
""" No Doc For Args"""
21+
self.host = host
22+
self.timeout = timeout
23+
self.port = port
24+
25+
@ENVMod.register()
26+
def _disconnect(cls):
27+
...
28+
29+
30+
def test_file_creations():
31+
ENVMod.save_example('dev_env_example.txt')
32+
ENVMod.sync_env_file()
33+
assert os.path.exists('dev_env_example.txt')
34+
assert os.path.exists('.env')
35+
36+
with open('.env', 'w') as f:
37+
f.writelines([
38+
'TESTCLASS_NAME=test_name\n',
39+
'TESTCLASS_AGE=25\n',
40+
'TESTCLASS_HOST=127.0.0.1\n',
41+
'TESTCLASS_TIMEOUT=1.43\n',
42+
])
43+
44+
def test_env_vars():
45+
ENVMod.sync_env_file()
46+
ENVMod.load_dotenv()
47+
keys = os.environ.keys()
48+
assert 'TESTCLASS_NAME' in keys
49+
assert 'TESTCLASS_AGE' in keys
50+
assert 'TESTCLASS_HOST' in keys
51+
assert 'TESTCLASS_TIMEOUT' in keys
52+
53+
def test_env_values():
54+
ENVMod.sync_env_file()
55+
ENVMod.load_dotenv()
56+
assert os.environ.get('TESTCLASS_NAME') == 'test_name'
57+
assert os.environ.get('TESTCLASS_AGE') == '25'
58+
assert os.environ.get('TESTCLASS_HOST') == '127.0.0.1'
59+
assert os.environ.get('TESTCLASS_TIMEOUT') == '1.43'
60+
61+
def test_load_args():
62+
ENVMod.sync_env_file()
63+
ENVMod.load_dotenv()
64+
test_object = TestClass(**ENVMod.load_args(TestClass.__init__))
65+
test_object._connect(**ENVMod.load_args(TestClass._connect))
66+
assert test_object.name == 'test_name'
67+
assert test_object.age == 25
68+
assert test_object.host == '127.0.0.1'
69+
assert test_object.timeout == 1.43
70+
assert test_object.port == 80

0 commit comments

Comments
 (0)