Skip to content

Commit b737cbe

Browse files
Merge pull request #24 from BrunoSilvaAndrade/develop
Fixing Issue ModuleNotFoundError: No module named 'parsers'
2 parents c8cfc76 + 1c83c7e commit b737cbe

File tree

2 files changed

+106
-94
lines changed

2 files changed

+106
-94
lines changed

parsers.py

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

pyconfigparser.py

Lines changed: 106 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,111 @@
1-
from parsers import ParseError, json_parser, yaml_parser
21
from schema import Schema, SchemaError
32
from typing import Any
43
from os import path
4+
import json
5+
import yaml
56
import os
67
import re
78

8-
VARIABLE_PATTERN = r'\$([a-zA-Z][\w]+|\{[a-zA-Z][\w]+\})$'
9-
DEFAULT_CONFIG_FILES = ('config.json', 'config.yaml', 'config.yml')
10-
ENTITY_NAME_PATTERN = r'^[a-zA-Z][\w]+$'
11-
SUPPORTED_EXTENSIONS = {
12-
'json': json_parser,
13-
'yaml': yaml_parser,
14-
'yml': yaml_parser
15-
}
9+
__all__ = [
10+
"ConfigError",
11+
"ConfigFileNotFoundError",
12+
"Config",
13+
"ConfigParser",
14+
"configparser"
15+
]
1616

1717

1818
class ConfigError(Exception):
1919
pass
2020

2121

22-
class ConfigFileNotFoundError(ConfigError):
22+
class ConfigFileNotFoundError(Exception):
2323
pass
2424

2525

26+
def _json_parser(file_buff):
27+
try:
28+
return json.loads(file_buff)
29+
except json.JSONDecodeError as e:
30+
raise ConfigError('Unable to decode config file using json', e)
31+
32+
33+
def _yaml_parser(file_buff):
34+
try:
35+
return yaml.safe_load(file_buff)
36+
except yaml.YAMLError as e:
37+
raise ConfigError('Unable to decode config file using yaml', e)
38+
39+
40+
def _validate_schema(schema, config_obj):
41+
if schema is None:
42+
return config_obj
43+
elif type(schema) not in (dict, list):
44+
raise ConfigError('The first config\'s schema element should be a Map or a List')
45+
46+
return Schema(schema).validate(config_obj)
47+
48+
49+
def _get_file_buff(path_file: str):
50+
with open(path_file, 'r') as f:
51+
return f.read()
52+
53+
54+
def _get_file_parser(file_path):
55+
try:
56+
extension = file_path.split('.')[-1]
57+
return _SUPPORTED_EXTENSIONS[extension]
58+
except KeyError:
59+
raise ConfigError(f'Supported extensions: {list(_SUPPORTED_EXTENSIONS.keys())}')
60+
61+
62+
def _get_file_path(config_dir, file_name):
63+
file_path = f'{os.getcwd()}/{config_dir}/'
64+
if type(file_name) is str:
65+
file_name = [file_name]
66+
67+
for f_name in file_name:
68+
if path.isfile(file_path + f_name):
69+
return file_path + f_name
70+
71+
raise ConfigFileNotFoundError(f'Config file {file_path}{file_name} was not found')
72+
73+
74+
def _is_a_valid_object_key(key):
75+
if re.search(_ENTITY_NAME_PATTERN, key) is None:
76+
raise ConfigError(f'The key {key} is invalid. The entity keys only may have words, number and underscores.')
77+
78+
79+
def _is_variable(data):
80+
return type(data) is str and re.search(_VARIABLE_PATTERN, data) is not None
81+
82+
83+
def _interpol_variable(data, ignore_unset_env_vars):
84+
try:
85+
return os.environ[_extract_env_variable_key(data)]
86+
except KeyError:
87+
if ignore_unset_env_vars:
88+
return None
89+
raise ConfigError(f'Environment variable {data} was not found')
90+
91+
92+
def _extract_env_variable_key(variable):
93+
variable = variable[1:]
94+
if variable[0] == '{':
95+
return variable[1:-1]
96+
return variable
97+
98+
99+
_VARIABLE_PATTERN = r'\$([a-zA-Z][\w]+|\{[a-zA-Z][\w]+\})$'
100+
_DEFAULT_CONFIG_FILES = ('config.json', 'config.yaml', 'config.yml')
101+
_ENTITY_NAME_PATTERN = r'^[a-zA-Z][\w]+$'
102+
_SUPPORTED_EXTENSIONS = {
103+
'json': _json_parser,
104+
'yaml': _yaml_parser,
105+
'yml': _yaml_parser
106+
}
107+
108+
26109
class Config:
27110

28111
def __getitem__(self, item):
@@ -45,7 +128,7 @@ class ConfigParser:
45128
def __init__(self):
46129
self.__instance = None
47130
self.__hold_an_instance = True
48-
self.__ignore_unsetted_env_vars = False
131+
self.__ignore_unset_env_vars = False
49132

50133
@property
51134
def hold_an_instance(self):
@@ -59,100 +142,49 @@ def hold_an_instance(self, value):
59142

60143
@property
61144
def ignore_unset_env_vars(self):
62-
return self.__ignore_unsetted_env_vars
145+
return self.__ignore_unset_env_vars
63146

64147
@ignore_unset_env_vars.setter
65148
def ignore_unset_env_vars(self, value):
66149
if type(value) is not bool:
67150
raise ValueError('value must be a bool')
68-
self.__ignore_unsetted_env_vars = value
151+
self.__ignore_unset_env_vars = value
69152

70-
def get_config(self, schema: dict = None, config_dir: str = 'config', file_name: Any = DEFAULT_CONFIG_FILES):
153+
def get_config(self, schema: dict = None, config_dir: str = 'config', file_name: Any = _DEFAULT_CONFIG_FILES):
71154
if self.__hold_an_instance:
72155
if self.__instance is None:
73156
self.__instance = self.__create_new_instance(schema, config_dir, file_name)
74157
return self.__instance
75158
return self.__create_new_instance(schema, config_dir, file_name)
76159

77160
def __create_new_instance(self, schema, config_dir, file_name):
78-
file_path = self.__get_file_path(config_dir, file_name)
79-
parser = self.__get_file_parser(file_path)
80-
file_buff = self.__get_file_buff(file_path)
161+
file_path = _get_file_path(config_dir, file_name)
162+
parser = _get_file_parser(file_path)
163+
file_buff = _get_file_buff(file_path)
81164

82165
try:
83-
config = self.__validate_schema(schema, parser(file_buff))
166+
config = _validate_schema(schema, parser(file_buff))
84167
return self.__dict_2_obj(config)
85-
except ParseError as e:
86-
raise ConfigError(e)
87168
except SchemaError as e:
88169
raise ConfigError('Schema validation error', e)
89170

90-
def __get_file_parser(self, file_path):
91-
try:
92-
extension = file_path.split('.')[-1]
93-
return SUPPORTED_EXTENSIONS[extension]
94-
except KeyError:
95-
raise ConfigError(f'Supported extensions: {list(SUPPORTED_EXTENSIONS.keys())}')
96-
97-
def __get_file_path(self, config_dir, file_name):
98-
file_path = f'{os.getcwd()}/{config_dir}/'
99-
if type(file_name) is str:
100-
file_name = [file_name]
101-
102-
for f_name in file_name:
103-
if path.isfile(file_path + f_name):
104-
return file_path + f_name
105-
106-
raise ConfigFileNotFoundError(f'Config file {file_path}{file_name} was not found')
107-
108-
def __validate_schema(self, schema, config_obj):
109-
if schema is None:
110-
return config_obj
111-
elif type(schema) not in (dict, list):
112-
raise ConfigError('The first config\'s schema element should be a Map or a List')
113-
114-
return Schema(schema).validate(config_obj)
115-
116-
def __get_file_buff(self, path_file: str):
117-
with open(path_file, 'r') as f:
118-
return f.read()
119-
120171
def __dict_2_obj(self, data: Any):
121172
_type = type(data)
122173

123174
if _type is dict:
124175
obj = Config()
125176
for key, value in data.items():
126-
self.__is_a_valid_object_key(key)
177+
_is_a_valid_object_key(key)
127178
setattr(obj, key, self.__dict_2_obj(value))
128179
return obj
180+
129181
if _type in (list, set, tuple):
130182
return list(map(lambda v: self.__dict_2_obj(v), data))
183+
131184
else:
132-
if self.__is_variable(data):
133-
return self.__interpol_variable(data)
185+
if _is_variable(data):
186+
return _interpol_variable(data, self.__ignore_unset_env_vars)
134187
return data
135188

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-
144-
def __is_a_valid_object_key(self, key):
145-
if re.search(ENTITY_NAME_PATTERN, key) is None:
146-
raise ConfigError(f'The key {key} is invalid. The entity keys only may have words, number and underscores.')
147-
148-
def __is_variable(self, data):
149-
return type(data) is str and re.search(VARIABLE_PATTERN, data) is not None
150-
151-
def __extract_env_variable_key(self, variable):
152-
variable = variable[1:]
153-
if variable[0] == '{':
154-
return variable[1:-1]
155-
return variable
156-
157189

158190
configparser = ConfigParser()

0 commit comments

Comments
 (0)