Skip to content

Commit adb9d7c

Browse files
authored
Merge pull request #4 from whacked/update-custom-dotenv-path
update handling of non-default .env paths
2 parents 588bb11 + 6e5f0c3 commit adb9d7c

4 files changed

Lines changed: 68 additions & 22 deletions

File tree

flake.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
'' + ''
8181
### SHORTCUTS
8282
alias check='python -m schematized_config'
83+
alias start-jupyter='jupyter notebook'
8384
''; # join strings with +
8485
};
8586

nbs/00_core.ipynb

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"cells": [
33
{
4+
"attachments": {},
45
"cell_type": "markdown",
56
"metadata": {},
67
"source": [
@@ -221,23 +222,25 @@
221222
" CONFIG_VALIDATOR_JSON_SCHEMA_ENVVAR_NAME = 'CONFIG_VALIDATOR_JSON_SCHEMA'\n",
222223
"\n",
223224
" @classmethod\n",
224-
" def load_json(cls, json_source: Union[str, dict]=None) -> dict:\n",
225+
" def load_json(cls, json_source: Union[str, dict]=None, storage_driver: FS = None) -> dict:\n",
225226
" '''\n",
226227
" convenience method to return a dict from either\n",
227228
" a file path or an already-loaded dict\n",
228229
" '''\n",
230+
" storage_driver = storage_driver or cls.DEFAULT_STORAGE_DRIVER\n",
229231
" if isinstance(json_source, str):\n",
230-
" with cls.DEFAULT_STORAGE_DRIVER.open(json_source) as ifile:\n",
232+
" with storage_driver.open(json_source) as ifile:\n",
231233
" return json.load(ifile)\n",
232234
" elif isinstance(json_source, dict):\n",
233235
" return json_source\n",
234236
"\n",
235237
" @classmethod\n",
236-
" def get_default_json_schema(cls):\n",
238+
" def get_default_json_schema(cls, storage_driver: FS = None) -> dict:\n",
239+
" storage_driver = storage_driver or cls.DEFAULT_STORAGE_DRIVER\n",
237240
" if cls.CONFIG_VALIDATOR_JSON_SCHEMA_ENVVAR_NAME in os.environ:\n",
238241
" expected_json_schema_path = \\\n",
239242
" os.environ[cls.CONFIG_VALIDATOR_JSON_SCHEMA_ENVVAR_NAME]\n",
240-
" with cls.DEFAULT_STORAGE_DRIVER.open(expected_json_schema_path) as ifile:\n",
243+
" with storage_driver.open(expected_json_schema_path) as ifile:\n",
241244
" return json.load(ifile)\n",
242245
" return None\n",
243246
"\n",
@@ -270,16 +273,18 @@
270273
" return coerced_config\n",
271274
" \n",
272275
" @classmethod\n",
273-
" def load_validated_config(cls, json_schema: Union[str, dict], config: dict):\n",
274-
" return cls(json_schema).load_config(config)\n",
276+
" def load_validated_config(cls, json_schema: Union[str, dict], config: dict, **kwargs):\n",
277+
" return cls(json_schema, **kwargs).load_config(config)\n",
275278
"\n",
276279
" @classmethod\n",
277-
" def load_validated_environment(cls, json_schema: Union[str, dict]=None):\n",
278-
" return cls.load_validated_config(json_schema, dict(os.environ))\n",
280+
" def load_validated_environment(cls, json_schema: Union[str, dict]=None, **kwargs):\n",
281+
" return cls.load_validated_config(json_schema, dict(os.environ), **kwargs)\n",
279282
" \n",
280283
" @classmethod\n",
281-
" def load_dotenv(cls, json_schema: Union[str, dict]=None, dotenv_path: str=None):\n",
282-
" config = dotenv.dotenv_values(dotenv_path)\n",
284+
" def load_dotenv(cls, json_schema: Union[str, dict]=None, dotenv_path: str=None, storage_driver: FS=None):\n",
285+
" storage_driver = storage_driver or cls.DEFAULT_STORAGE_DRIVER\n",
286+
" with storage_driver.open(dotenv_path) as ifile:\n",
287+
" config = dotenv.dotenv_values(stream=ifile)\n",
283288
" return cls.load_validated_config(\n",
284289
" json_schema or cls.get_default_json_schema(), config)"
285290
]
@@ -509,7 +514,8 @@
509514
"from fs.memoryfs import MemoryFS\n",
510515
"memfs = MemoryFS()\n",
511516
"\n",
512-
"with memfs.open('schema.json', 'w') as ofile:\n",
517+
"memfs.makedirs('extra-long-directory-place', recreate=True)\n",
518+
"with memfs.open('extra-long-directory-place/schema.json', 'w') as ofile:\n",
513519
" ofile.write(json.dumps(example_properties_schema))\n",
514520
" os.environ['CONFIG_VALIDATOR_JSON_SCHEMA'] = ofile.name\n",
515521
"\n",
@@ -526,7 +532,26 @@
526532
" 'MY_INTEGER_VALUE': -85,\n",
527533
" 'A_NUMERIC_VALUE': 12300.0,\n",
528534
" '_____A_STRING_VALUE____with_default__': 'underscores_and spaces',\n",
529-
"})"
535+
"})\n",
536+
"\n",
537+
"# test loading dotenv from an arbitrary file\n",
538+
"memfs.makedirs('special-bespoke-location', recreate=True)\n",
539+
"with memfs.open('special-bespoke-location/my-own.env', 'w') as ofile:\n",
540+
" ofile.write('\\n'.join([\n",
541+
" 'string_value_with_enum=only',\n",
542+
" 'MY_INTEGER_VALUE=9989998',\n",
543+
" 'A_NUMERIC_VALUE=1167.89',\n",
544+
" ]))\n",
545+
"\n",
546+
"validated_dotenv = validator.load_dotenv(dotenv_path='special-bespoke-location/my-own.env')\n",
547+
"test_eq(validated_dotenv, {\n",
548+
" 'string_value_with_enum': 'only',\n",
549+
" 'MY_INTEGER_VALUE': 9989998,\n",
550+
" 'A_NUMERIC_VALUE': 1167.89,\n",
551+
" '_____A_STRING_VALUE____with_default__': 'underscores_and spaces',\n",
552+
"})\n",
553+
"\n",
554+
"test_fail(validator.load_dotenv, kwargs={'dotenv_path': 'non-existent-location-own.env'})"
530555
]
531556
},
532557
{

nbs/index.ipynb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,22 @@
3535
"```"
3636
]
3737
},
38+
{
39+
"cell_type": "markdown",
40+
"metadata": {},
41+
"source": [
42+
"# development"
43+
]
44+
},
45+
{
46+
"cell_type": "markdown",
47+
"metadata": {},
48+
"source": [
49+
"assuming you have [nix](https://nixos.org/download.html) installed and ready, make sure `nix-command` and `flake` are enabled (oneliner: run `export NIX_CONFIG=\"experimental-features = nix-command flakes\"` in the terminal), then enter the dev shell using `nix develop`\n",
50+
"\n",
51+
"start the jupyter notebook using the provided alias or just `jupyter notebook`, and hack away"
52+
]
53+
},
3854
{
3955
"cell_type": "markdown",
4056
"metadata": {},

schematized_config/core.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -98,23 +98,25 @@ class ConfigValidator(object):
9898
CONFIG_VALIDATOR_JSON_SCHEMA_ENVVAR_NAME = 'CONFIG_VALIDATOR_JSON_SCHEMA'
9999

100100
@classmethod
101-
def load_json(cls, json_source: Union[str, dict]=None) -> dict:
101+
def load_json(cls, json_source: Union[str, dict]=None, storage_driver: FS = None) -> dict:
102102
'''
103103
convenience method to return a dict from either
104104
a file path or an already-loaded dict
105105
'''
106+
storage_driver = storage_driver or cls.DEFAULT_STORAGE_DRIVER
106107
if isinstance(json_source, str):
107-
with cls.DEFAULT_STORAGE_DRIVER.open(json_source) as ifile:
108+
with storage_driver.open(json_source) as ifile:
108109
return json.load(ifile)
109110
elif isinstance(json_source, dict):
110111
return json_source
111112

112113
@classmethod
113-
def get_default_json_schema(cls):
114+
def get_default_json_schema(cls, storage_driver: FS = None) -> dict:
115+
storage_driver = storage_driver or cls.DEFAULT_STORAGE_DRIVER
114116
if cls.CONFIG_VALIDATOR_JSON_SCHEMA_ENVVAR_NAME in os.environ:
115117
expected_json_schema_path = \
116118
os.environ[cls.CONFIG_VALIDATOR_JSON_SCHEMA_ENVVAR_NAME]
117-
with cls.DEFAULT_STORAGE_DRIVER.open(expected_json_schema_path) as ifile:
119+
with storage_driver.open(expected_json_schema_path) as ifile:
118120
return json.load(ifile)
119121
return None
120122

@@ -147,15 +149,17 @@ def load_config(self, config: dict):
147149
return coerced_config
148150

149151
@classmethod
150-
def load_validated_config(cls, json_schema: Union[str, dict], config: dict):
151-
return cls(json_schema).load_config(config)
152+
def load_validated_config(cls, json_schema: Union[str, dict], config: dict, **kwargs):
153+
return cls(json_schema, **kwargs).load_config(config)
152154

153155
@classmethod
154-
def load_validated_environment(cls, json_schema: Union[str, dict]=None):
155-
return cls.load_validated_config(json_schema, dict(os.environ))
156+
def load_validated_environment(cls, json_schema: Union[str, dict]=None, **kwargs):
157+
return cls.load_validated_config(json_schema, dict(os.environ), **kwargs)
156158

157159
@classmethod
158-
def load_dotenv(cls, json_schema: Union[str, dict]=None, dotenv_path: str=None):
159-
config = dotenv.dotenv_values(dotenv_path)
160+
def load_dotenv(cls, json_schema: Union[str, dict]=None, dotenv_path: str=None, storage_driver: FS=None):
161+
storage_driver = storage_driver or cls.DEFAULT_STORAGE_DRIVER
162+
with storage_driver.open(dotenv_path) as ifile:
163+
config = dotenv.dotenv_values(stream=ifile)
160164
return cls.load_validated_config(
161165
json_schema or cls.get_default_json_schema(), config)

0 commit comments

Comments
 (0)