typerconf 2.2__tar.gz → 2.3__tar.gz
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.
- {typerconf-2.2 → typerconf-2.3}/PKG-INFO +1 -1
- {typerconf-2.2 → typerconf-2.3}/pyproject.toml +1 -1
- {typerconf-2.2 → typerconf-2.3}/src/typerconf/__init__.py +5 -2
- {typerconf-2.2 → typerconf-2.3}/src/typerconf/init.nw +78 -6
- {typerconf-2.2 → typerconf-2.3}/LICENSE +0 -0
- {typerconf-2.2 → typerconf-2.3}/README.md +0 -0
- {typerconf-2.2 → typerconf-2.3}/src/typerconf/.gitignore +0 -0
- {typerconf-2.2 → typerconf-2.3}/src/typerconf/Makefile +0 -0
|
@@ -16,7 +16,7 @@ dirs = appdirs.AppDirs(basename)
|
|
|
16
16
|
class Config:
|
|
17
17
|
"""Navigates nested JSON structures by dot-separated addressing."""
|
|
18
18
|
|
|
19
|
-
def __init__(self, json_data=
|
|
19
|
+
def __init__(self, json_data=None,
|
|
20
20
|
conf_file=None):
|
|
21
21
|
"""
|
|
22
22
|
Constructs a config object to navigate from JSON data `json_data`.
|
|
@@ -30,7 +30,10 @@ class Config:
|
|
|
30
30
|
|
|
31
31
|
To not enable write back, load file contents with the `.read_config` method.
|
|
32
32
|
"""
|
|
33
|
-
|
|
33
|
+
if not json_data:
|
|
34
|
+
self.__data = {}
|
|
35
|
+
else:
|
|
36
|
+
self.__data = json_data
|
|
34
37
|
if isinstance(conf_file, io.IOBase):
|
|
35
38
|
try:
|
|
36
39
|
self.__conf_file = conf_file.name
|
|
@@ -123,14 +123,17 @@ Both work with these dot-separated addresses.
|
|
|
123
123
|
class Config:
|
|
124
124
|
"""Navigates nested JSON structures by dot-separated addressing."""
|
|
125
125
|
|
|
126
|
-
def __init__(self, json_data=
|
|
126
|
+
def __init__(self, json_data=None,
|
|
127
127
|
<<Config constructor args>>):
|
|
128
128
|
"""
|
|
129
129
|
Constructs a config object to navigate from JSON data `json_data`.
|
|
130
130
|
|
|
131
131
|
<<Config constructor args doc>>
|
|
132
132
|
"""
|
|
133
|
-
|
|
133
|
+
if not json_data:
|
|
134
|
+
self.__data = {}
|
|
135
|
+
else:
|
|
136
|
+
self.__data = json_data
|
|
134
137
|
<<Config attributes>>
|
|
135
138
|
|
|
136
139
|
<<Config methods for get and set>>
|
|
@@ -138,7 +141,27 @@ class Config:
|
|
|
138
141
|
<<Config methods for reading from and writing to file>>
|
|
139
142
|
@
|
|
140
143
|
|
|
141
|
-
We
|
|
144
|
+
We want to test the constructor.
|
|
145
|
+
<<test functions>>=
|
|
146
|
+
def test_constructor():
|
|
147
|
+
test_key = "courses"
|
|
148
|
+
test_value = "test"
|
|
149
|
+
|
|
150
|
+
conf = Config(json_data={test_key: test_value})
|
|
151
|
+
assert test_key in conf.get()
|
|
152
|
+
|
|
153
|
+
assert test_key not in Config(json_data={}).get()
|
|
154
|
+
assert test_key not in Config().get()
|
|
155
|
+
|
|
156
|
+
conf = Config()
|
|
157
|
+
conf.set(test_key, test_value)
|
|
158
|
+
assert conf.get(test_key) == test_value
|
|
159
|
+
|
|
160
|
+
assert test_key not in Config().get()
|
|
161
|
+
@
|
|
162
|
+
|
|
163
|
+
We will use the following test data for the test functions in the remainder of
|
|
164
|
+
the text.
|
|
142
165
|
<<test functions>>=
|
|
143
166
|
test_data = {
|
|
144
167
|
"courses": {
|
|
@@ -278,6 +301,16 @@ def test_set_path_list():
|
|
|
278
301
|
assert gotten_value == value
|
|
279
302
|
@
|
|
280
303
|
|
|
304
|
+
We also want to test short paths.
|
|
305
|
+
<<test functions>>=
|
|
306
|
+
def test_set_short_path():
|
|
307
|
+
value = "Test Tester"
|
|
308
|
+
path = "contact"
|
|
309
|
+
conf.set(path, value)
|
|
310
|
+
|
|
311
|
+
assert conf.get(path) == value
|
|
312
|
+
@
|
|
313
|
+
|
|
281
314
|
When we want to remove a node, the pythonic way is to simply try to remove it.
|
|
282
315
|
If it doesn't exist, we silently fail.
|
|
283
316
|
The reasoning is as follows: the goal is to remove something; if it doesn't
|
|
@@ -306,6 +339,19 @@ def test_set_path_remove():
|
|
|
306
339
|
assert False
|
|
307
340
|
@
|
|
308
341
|
|
|
342
|
+
We also want to remove from a longer path.
|
|
343
|
+
<<test functions>>=
|
|
344
|
+
def test_set_path_list():
|
|
345
|
+
path = "courses.prgx22.TAs"
|
|
346
|
+
conf.set(path, None)
|
|
347
|
+
try:
|
|
348
|
+
conf.get(path)
|
|
349
|
+
except KeyError:
|
|
350
|
+
assert True
|
|
351
|
+
else:
|
|
352
|
+
assert False
|
|
353
|
+
@
|
|
354
|
+
|
|
309
355
|
We want to traverse the tree, we want to go to the immediate parent of the leaf
|
|
310
356
|
that we want to set a value for (or delete).
|
|
311
357
|
We iterate through the path.
|
|
@@ -754,12 +800,14 @@ written to the file.
|
|
|
754
800
|
<<test functions>>=
|
|
755
801
|
def test_writeback_constructor():
|
|
756
802
|
with tempfile.NamedTemporaryFile("w") as tmp_conf_file:
|
|
757
|
-
tmp_conf_file_name =
|
|
803
|
+
tmp_conf_file_name = tmp_conf_file.name
|
|
758
804
|
path = "the.path"
|
|
759
805
|
first_value = "1st"
|
|
760
806
|
second_value = "2nd"
|
|
761
807
|
|
|
762
808
|
initial_conf = Config()
|
|
809
|
+
assert initial_conf.get() == {}
|
|
810
|
+
|
|
763
811
|
initial_conf.set(path, first_value)
|
|
764
812
|
initial_conf.write_config(tmp_conf_file_name)
|
|
765
813
|
|
|
@@ -768,6 +816,8 @@ def test_writeback_constructor():
|
|
|
768
816
|
conf.set(path, second_value)
|
|
769
817
|
|
|
770
818
|
last_conf = Config()
|
|
819
|
+
assert last_conf.get() == {}
|
|
820
|
+
|
|
771
821
|
last_conf.read_config(tmp_conf_file_name)
|
|
772
822
|
assert last_conf.get(path) == second_value
|
|
773
823
|
<<test imports>>=
|
|
@@ -921,6 +971,8 @@ if values == "":
|
|
|
921
971
|
values = None
|
|
922
972
|
@
|
|
923
973
|
|
|
974
|
+
\subsection{Testing the config command}
|
|
975
|
+
|
|
924
976
|
Let's test this command.
|
|
925
977
|
We'll set up the testing.
|
|
926
978
|
<<test functions>>=
|
|
@@ -936,7 +988,7 @@ Let's look at the actual tests.
|
|
|
936
988
|
<<run tests on [[cli]]>>=
|
|
937
989
|
# set example data
|
|
938
990
|
result = runner.invoke(cli,
|
|
939
|
-
|
|
991
|
+
["courses.datintro22.url", "--set", "https://..."])
|
|
940
992
|
assert result.exit_code == 0
|
|
941
993
|
|
|
942
994
|
# try access nonexisting
|
|
@@ -949,7 +1001,7 @@ assert "courses.datintro22.url = https://..." in result.stdout
|
|
|
949
1001
|
|
|
950
1002
|
# clear config
|
|
951
1003
|
result = runner.invoke(cli,
|
|
952
|
-
|
|
1004
|
+
["courses", "--set", ""])
|
|
953
1005
|
assert result.exit_code == 0
|
|
954
1006
|
|
|
955
1007
|
# check that it's cleared
|
|
@@ -972,6 +1024,26 @@ def test_cli_not_default_conf():
|
|
|
972
1024
|
<<run tests on [[cli]]>>
|
|
973
1025
|
@
|
|
974
1026
|
|
|
1027
|
+
We'll do another round of tests, but this time for shorter paths.
|
|
1028
|
+
<<test functions>>=
|
|
1029
|
+
def test_short_paths():
|
|
1030
|
+
result = runner.invoke(cli, ["contact"])
|
|
1031
|
+
assert result.exit_code != 0
|
|
1032
|
+
|
|
1033
|
+
result = runner.invoke(cli,
|
|
1034
|
+
["contact", "--set", "me"])
|
|
1035
|
+
assert result.exit_code == 0
|
|
1036
|
+
|
|
1037
|
+
result = runner.invoke(cli, ["contact"])
|
|
1038
|
+
assert "contact = me" in result.stdout
|
|
1039
|
+
|
|
1040
|
+
result = runner.invoke(cli,
|
|
1041
|
+
["contact", "--set", ""])
|
|
1042
|
+
assert result.exit_code == 0
|
|
1043
|
+
|
|
1044
|
+
result = runner.invoke(cli, ["contact"])
|
|
1045
|
+
assert result.exit_code != 0
|
|
1046
|
+
@
|
|
975
1047
|
|
|
976
1048
|
\subsection{Autocompleting the path}
|
|
977
1049
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|