Skip to content

Commit 9411646

Browse files
author
BrunoSilvaAndrade
committed
feat: Adding a switch to ignore env vars which was not found
Enabling this ignoring switch the parser will set None to the unresolved env vars
1 parent ae6a1e1 commit 9411646

File tree

3 files changed

+85
-23
lines changed

3 files changed

+85
-23
lines changed

README.md

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,13 @@ HOW TO USE
3030
---
3131
By default, the config file will look for the following config files in the `.config` directory: `config.json`, `config.yaml`, `config.yml`.
3232

33-
You can also pass a config directory of your preference (assuming your current directory).
33+
You can also pass a config directory and or config file of your preference (assuming your current directory).
34+
35+
```python
36+
from pyconfigparser import configparser
37+
38+
configparser.get_config(CONFIG_SCHEMA, config_dir='your_config_dir_path', file_name='your_config_file_name')
39+
```
3440

3541
Schema validation
3642
---
@@ -98,7 +104,7 @@ A json config file would be something like:
98104
}
99105
```
100106

101-
The instance of Config Class:
107+
The config instance
102108
```python
103109
from pyconfigparser import configparser, ConfigError
104110
import logging
@@ -155,6 +161,18 @@ from pyconfigparser import configparser
155161
configparser.hold_an_instance = False
156162
```
157163

164+
Environment Variables Interpolation
165+
---
166+
If the process does not find a value already set to your env variables
167+
It will raise a ConfigError. But you can disable this behavior, and the parser will set `None` to these unresolved env vars
168+
169+
```python
170+
from pyconfigparser import configparser
171+
172+
configparser.ignore_unset_env_vars = True
173+
config = configparser.get_config()
174+
```
175+
158176
CONTRIBUTE
159177
---
160178
---

pyconfigparser.py

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class ConfigParser:
4545
def __init__(self):
4646
self.__instance = None
4747
self.__hold_an_instance = True
48+
self.__ignore_unsetted_env_vars = False
4849

4950
@property
5051
def hold_an_instance(self):
@@ -56,15 +57,22 @@ def hold_an_instance(self, value):
5657
raise ValueError('value must be a bool')
5758
self.__hold_an_instance = value
5859

59-
def get_config(self, schema: dict = None, config_dir: str = 'config', file_name: Any = DEFAULT_CONFIG_FILES):
60+
@property
61+
def ignore_unset_env_vars(self):
62+
return self.__ignore_unsetted_env_vars
6063

61-
if self.__instance is None:
62-
instance = self.__create_new_instance(schema, config_dir, file_name)
63-
if self.__hold_an_instance:
64-
self.__instance = instance
65-
else:
66-
return instance
67-
return self.__instance
64+
@ignore_unset_env_vars.setter
65+
def ignore_unset_env_vars(self, value):
66+
if type(value) is not bool:
67+
raise ValueError('value must be a bool')
68+
self.__ignore_unsetted_env_vars = value
69+
70+
def get_config(self, schema: dict = None, config_dir: str = 'config', file_name: Any = DEFAULT_CONFIG_FILES):
71+
if self.__hold_an_instance:
72+
if self.__instance is None:
73+
self.__instance = self.__create_new_instance(schema, config_dir, file_name)
74+
return self.__instance
75+
return self.__create_new_instance(schema, config_dir, file_name)
6876

6977
def __create_new_instance(self, schema, config_dir, file_name):
7078
file_path = self.__get_file_path(config_dir, file_name)
@@ -125,19 +133,21 @@ def __dict_2_obj(self, data: Any):
125133
return self.__interpol_variable(data)
126134
return data
127135

136+
def __interpol_variable(self, data):
137+
try:
138+
return os.environ[self.__extract_env_variable_key(data)]
139+
except KeyError:
140+
if self.__ignore_unsetted_env_vars:
141+
return None
142+
raise ConfigError(f'Environment variable {data} was not found')
143+
128144
def __is_a_valid_object_key(self, key):
129145
if re.search(ENTITY_NAME_PATTERN, key) is None:
130146
raise ConfigError(f'The key {key} is invalid. The entity keys only may have words, number and underscores.')
131147

132148
def __is_variable(self, data):
133149
return type(data) is str and re.search(VARIABLE_PATTERN, data) is not None
134150

135-
def __interpol_variable(self, data):
136-
try:
137-
return os.environ[self.__extract_env_variable_key(data)]
138-
except KeyError:
139-
raise ConfigError(f'Environment variable {data} was not found')
140-
141151
def __extract_env_variable_key(self, variable):
142152
variable = variable[1:]
143153
if variable[0] == '{':

test_configparser.py

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from pyconfigparser import configparser, ConfigError, ConfigFileNotFoundError
1+
from pyconfigparser import ConfigParser, ConfigError, ConfigFileNotFoundError
22
from config.schemas import SIMPLE_SCHEMA_CONFIG, UNSUPPORTED_OBJECT_KEYS_SCHEMA
33
import unittest
44
import os
@@ -9,25 +9,32 @@
99

1010
class ConfigTestCase(unittest.TestCase):
1111
def setUp(self) -> None:
12-
configparser.hold_an_instance = False
1312
os.environ['DATE_FORMAT_TEST'] = DT_FMT_TEST
1413
os.environ['LOG_LEVEL_TEST'] = VAR_LOG_LEVEL_INFO
1514

1615
def test_schema_checking(self):
16+
configparser = ConfigParser()
1717
self.assertRaises(ConfigError, configparser.get_config, 1)
1818

1919
def test_config_without_file(self):
20+
configparser = ConfigParser()
2021
self.assertRaises(ConfigFileNotFoundError, configparser.get_config, SIMPLE_SCHEMA_CONFIG,
2122
'config',
2223
'some_non_exists_file.json')
2324

2425
def test_undefined_env_var(self):
2526
try:
27+
configparser = ConfigParser()
2628
configparser.get_config(file_name='config.yaml')
2729
except Exception as e:
2830
self.assertIn('Environment', str(e))
2931

32+
configparser = ConfigParser()
33+
configparser.ignore_unset_env_vars = True
34+
configparser.get_config(file_name='config.yaml')
35+
3036
def test_to_access_attr_from_config(self):
37+
configparser = ConfigParser()
3138
config = configparser.get_config(SIMPLE_SCHEMA_CONFIG)
3239
self.assertEqual(VAR_LOG_LEVEL_INFO, config.core.logging.level)
3340
self.assertEqual(DT_FMT_TEST, config.core.logging.datefmt)
@@ -36,28 +43,55 @@ def test_to_access_attr_from_config(self):
3643
self.assertEqual('Mike', config.core.obj_list[0]['name']) # <- using subscriptable access
3744

3845
def test_access_fake_attr(self):
46+
configparser = ConfigParser()
3947
config = configparser.get_config(SIMPLE_SCHEMA_CONFIG)
4048
self.assertRaises(AttributeError, lambda: config.fake_attr)
4149

4250
def test_unsupported_object_key(self):
51+
configparser = ConfigParser()
4352
self.assertRaises(ConfigError, configparser.get_config, UNSUPPORTED_OBJECT_KEYS_SCHEMA,
4453
file_name='unsupported_object_key.json')
4554

46-
def test_set_hold_an_invalid_instance(self):
47-
def assign_a_bad_type():
48-
configparser.hold_an_instance = []
49-
self.assertRaises(ValueError, assign_a_bad_type)
50-
5155
def test_config_with_wrong_json_model(self):
56+
configparser = ConfigParser()
5257
self.assertRaises(ConfigError, configparser.get_config, SIMPLE_SCHEMA_CONFIG, file_name='wrong_model.json')
5358

5459
def test_config_file_with_unsupported_extension(self):
60+
configparser = ConfigParser()
5561
self.assertRaises(ConfigError, configparser.get_config, SIMPLE_SCHEMA_CONFIG, file_name='config.bad_extension')
5662

5763
def test_bad_decoder_error(self):
64+
configparser = ConfigParser()
5865
self.assertRaises(ConfigError, configparser.get_config, SIMPLE_SCHEMA_CONFIG, file_name='bad_content.json')
5966
self.assertRaises(ConfigError, configparser.get_config, SIMPLE_SCHEMA_CONFIG, file_name='bad_content.yaml')
6067

68+
def test_caching_instance(self):
69+
configparser = ConfigParser()
70+
config1 = configparser.get_config()
71+
config2 = configparser.get_config()
72+
self.assertIs(config1, config2)
73+
configparser.hold_an_instance = False
74+
75+
config2 = configparser.get_config()
76+
self.assertIsNot(config1, config2)
77+
78+
def test_configparser_config_switches(self):
79+
configparser = ConfigParser()
80+
81+
def assign_a_bad_type_hold_an_instance():
82+
configparser.hold_an_instance = []
83+
84+
def assign_a_bad_type_ignore_unsetted_env_vars():
85+
configparser.ignore_unset_env_vars = []
86+
87+
self.assertRaises(ValueError, assign_a_bad_type_hold_an_instance)
88+
self.assertRaises(ValueError, assign_a_bad_type_ignore_unsetted_env_vars)
89+
configparser.hold_an_instance = False
90+
configparser.ignore_unset_env_vars = True
91+
self.assertIs(configparser.hold_an_instance, False)
92+
self.assertIs(configparser.ignore_unset_env_vars, True)
93+
self.assertIsInstance(configparser.ignore_unset_env_vars, bool)
94+
6195

6296
if __name__ == '__main__':
6397
unittest.main()

0 commit comments

Comments
 (0)