python-ubercode-utils 1.0.9__tar.gz → 2.0.0__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.
Files changed (29) hide show
  1. {python-ubercode-utils-1.0.9/python_ubercode_utils.egg-info → python-ubercode-utils-2.0.0}/PKG-INFO +1 -1
  2. {python-ubercode-utils-1.0.9 → python-ubercode-utils-2.0.0/python_ubercode_utils.egg-info}/PKG-INFO +1 -1
  3. {python-ubercode-utils-1.0.9 → python-ubercode-utils-2.0.0}/python_ubercode_utils.egg-info/SOURCES.txt +3 -5
  4. {python-ubercode-utils-1.0.9 → python-ubercode-utils-2.0.0}/setup.py +1 -1
  5. python-ubercode-utils-1.0.9/test/test_json.py → python-ubercode-utils-2.0.0/test/test_data.py +67 -9
  6. {python-ubercode-utils-1.0.9 → python-ubercode-utils-2.0.0}/test/test_urls.py +10 -0
  7. {python-ubercode-utils-1.0.9 → python-ubercode-utils-2.0.0}/ubercode/utils/convert.py +28 -0
  8. python-ubercode-utils-1.0.9/ubercode/utils/xml.py → python-ubercode-utils-2.0.0/ubercode/utils/data.py +53 -12
  9. {python-ubercode-utils-1.0.9 → python-ubercode-utils-2.0.0}/ubercode/utils/urls.py +21 -17
  10. python-ubercode-utils-1.0.9/test/test_xml.py +0 -61
  11. python-ubercode-utils-1.0.9/ubercode/utils/json.py +0 -54
  12. {python-ubercode-utils-1.0.9 → python-ubercode-utils-2.0.0}/LICENSE +0 -0
  13. {python-ubercode-utils-1.0.9 → python-ubercode-utils-2.0.0}/MANIFEST.in +0 -0
  14. {python-ubercode-utils-1.0.9 → python-ubercode-utils-2.0.0}/README.md +0 -0
  15. {python-ubercode-utils-1.0.9 → python-ubercode-utils-2.0.0}/python_ubercode_utils.egg-info/dependency_links.txt +0 -0
  16. {python-ubercode-utils-1.0.9 → python-ubercode-utils-2.0.0}/python_ubercode_utils.egg-info/not-zip-safe +0 -0
  17. {python-ubercode-utils-1.0.9 → python-ubercode-utils-2.0.0}/python_ubercode_utils.egg-info/top_level.txt +0 -0
  18. {python-ubercode-utils-1.0.9 → python-ubercode-utils-2.0.0}/setup.cfg +0 -0
  19. {python-ubercode-utils-1.0.9 → python-ubercode-utils-2.0.0}/test/test_convert.py +0 -0
  20. {python-ubercode-utils-1.0.9 → python-ubercode-utils-2.0.0}/test/test_cursor.py +0 -0
  21. {python-ubercode-utils-1.0.9 → python-ubercode-utils-2.0.0}/test/test_dataframe.py +0 -0
  22. {python-ubercode-utils-1.0.9 → python-ubercode-utils-2.0.0}/test/test_environment.py +0 -0
  23. {python-ubercode-utils-1.0.9 → python-ubercode-utils-2.0.0}/test/test_logging.py +0 -0
  24. {python-ubercode-utils-1.0.9 → python-ubercode-utils-2.0.0}/ubercode/__init__.py +0 -0
  25. {python-ubercode-utils-1.0.9 → python-ubercode-utils-2.0.0}/ubercode/utils/__init__.py +0 -0
  26. {python-ubercode-utils-1.0.9 → python-ubercode-utils-2.0.0}/ubercode/utils/cursor.py +0 -0
  27. {python-ubercode-utils-1.0.9 → python-ubercode-utils-2.0.0}/ubercode/utils/dataframe.py +0 -0
  28. {python-ubercode-utils-1.0.9 → python-ubercode-utils-2.0.0}/ubercode/utils/environment.py +0 -0
  29. {python-ubercode-utils-1.0.9 → python-ubercode-utils-2.0.0}/ubercode/utils/logging.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-ubercode-utils
3
- Version: 1.0.9
3
+ Version: 2.0.0
4
4
  Summary: Core python utilities for all apps
5
5
  Home-page: https://github.com/sstacha/python-ubercode-utils
6
6
  Author: Steve Stacha
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-ubercode-utils
3
- Version: 1.0.9
3
+ Version: 2.0.0
4
4
  Summary: Core python utilities for all apps
5
5
  Home-page: https://github.com/sstacha/python-ubercode-utils
6
6
  Author: Steve Stacha
@@ -9,19 +9,17 @@ python_ubercode_utils.egg-info/not-zip-safe
9
9
  python_ubercode_utils.egg-info/top_level.txt
10
10
  test/test_convert.py
11
11
  test/test_cursor.py
12
+ test/test_data.py
12
13
  test/test_dataframe.py
13
14
  test/test_environment.py
14
- test/test_json.py
15
15
  test/test_logging.py
16
16
  test/test_urls.py
17
- test/test_xml.py
18
17
  ubercode/__init__.py
19
18
  ubercode/utils/__init__.py
20
19
  ubercode/utils/convert.py
21
20
  ubercode/utils/cursor.py
21
+ ubercode/utils/data.py
22
22
  ubercode/utils/dataframe.py
23
23
  ubercode/utils/environment.py
24
- ubercode/utils/json.py
25
24
  ubercode/utils/logging.py
26
- ubercode/utils/urls.py
27
- ubercode/utils/xml.py
25
+ ubercode/utils/urls.py
@@ -4,7 +4,7 @@ with open("README.md", "r") as fh:
4
4
  long_description = fh.read()
5
5
 
6
6
  setuptools.setup(name='python-ubercode-utils',
7
- version='1.0.9',
7
+ version='2.0.0',
8
8
  description='Core python utilities for all apps',
9
9
  long_description=long_description,
10
10
  long_description_content_type="text/markdown",
@@ -1,7 +1,8 @@
1
1
  import unittest
2
2
  from pathlib import Path
3
3
 
4
- from ubercode.utils.json import JSON
4
+ from ubercode.utils.data import JSON
5
+ from ubercode.utils.data import XML
5
6
 
6
7
 
7
8
  class TestJSON(unittest.TestCase):
@@ -48,12 +49,10 @@ class TestJSON(unittest.TestCase):
48
49
  """
49
50
  # test we can construct from a json string
50
51
  json = JSON(json_string=json_string)
51
- self.assertEqual(len(json.json_dict['people']), 3)
52
+ self.assertEqual(len(json.data['people']), 3)
52
53
  # test we can construct by chaining and reading file
53
- json2 = JSON().from_json_file(file_path)
54
- self.assertEqual(json.json_dict, json2.json_dict)
55
- # test the dict matches the to_dict() result
56
- self.assertEqual(json.json_dict, json.to_dict())
54
+ json2 = JSON().from_json_file(str(file_path))
55
+ self.assertEqual(json.data, json2.data)
57
56
  # test encoding
58
57
  json_string = """
59
58
  {
@@ -91,12 +90,71 @@ class TestJSON(unittest.TestCase):
91
90
  }
92
91
  """
93
92
  json = JSON(json_string=json_string, encode_ampersands=True)
94
- self.assertEqual(len(json.json_dict['people']), 3)
95
- first_name = json.to_dict()['people'][0]['firstName']
93
+ self.assertEqual(len(json.data['people']), 3)
94
+ first_name = json.data['people'][0]['firstName']
96
95
  self.assertEqual(first_name, "Joe & Baker")
97
96
  # make sure the second name isn't double encoded
98
- second_name = json.to_dict()['people'][1]['firstName']
97
+ second_name = json.data['people'][1]['firstName']
99
98
  self.assertEqual(second_name, "James &")
100
99
  # test the str function
101
100
  result = "{'people': [{'firstName': 'Joe & Baker', 'lastName': 'Jackson', 'gender': 'male', 'age': 28, 'number': '7349282382', 'groups': ['members', 'student']}, {'firstName': 'James &', 'lastName': 'Smith', 'gender': 'male', 'age': 32, 'number': '5678568567', 'groups': ['members', 'professional']}, {'firstName': 'Emily', 'lastName': 'Jones', 'gender': 'female', 'age': 24, 'number': '456754675'}]}"
102
101
  self.assertEqual(str(json), result)
102
+
103
+
104
+ class TestXML(unittest.TestCase):
105
+
106
+ # -------- common usages ----------
107
+ def test_XML(self):
108
+ # calculate the filename for our test.xml file from this file (much like settings does)
109
+ file_path = Path(__file__).resolve().parent / 'test.xml'
110
+ xml_string = """
111
+ <contacts>
112
+ <contact>
113
+ <name>Steve Stacha</name>
114
+ </contact>
115
+ <contact>
116
+ <name>Buggs Bunny</name>
117
+ </contact>
118
+ <contact>
119
+ <name>Daffy Duck</name>
120
+ </contact>
121
+ </contacts>
122
+ """
123
+ # test we can construct from an xml string
124
+ xml = XML(xml_string=xml_string)
125
+ # NOTE: because we used a multiline string we need to strip the extra newlines before and after <contacts>
126
+ self.assertEqual(str(xml), xml_string.strip())
127
+ # normal string doesn't need stripping
128
+ xml_compact_string = "<contacts><contact><name>Buggs Bunny</name></contact><contact><name>Daffy Duck</name></contact></contacts>"
129
+ xml2 = XML(xml_compact_string)
130
+ self.assertEqual(str(xml2), xml_compact_string)
131
+ # test we can create using the from_xml_string() method chaining
132
+ xml3 = XML().from_xml_string(xml_compact_string)
133
+ self.assertEqual(str(xml2), str(xml3))
134
+ # test that method chaining after constructor overrides the value in place
135
+ self.assertNotEqual(str(xml), str(xml2))
136
+ xml.from_xml_string(xml_compact_string)
137
+ self.assertEqual(str(xml), str(xml2))
138
+ # test that we can read from file
139
+ xml.from_xml_file(str(file_path))
140
+ # we should be back to before
141
+ self.assertEqual(str(xml), xml_string.strip())
142
+ # test an attribute
143
+ xml_string = """
144
+ <contacts>
145
+ <contact attr="1">
146
+ <name>Steve Stacha</name>
147
+ </contact>
148
+ <contact>
149
+ <name>Buggs & Bunny</name>
150
+ </contact>
151
+ <contact>
152
+ <name>Daffy Duck</name>
153
+ </contact>
154
+ </contacts>
155
+ """
156
+ xml = XML(xml_string=xml_string, encode_ampersands=True)
157
+ xml_dict = xml.to_dict()
158
+ self.assertEqual(xml_dict['contacts']['contact'][0]['@attr'], '1')
159
+
160
+
@@ -40,6 +40,16 @@ class TestUrls(unittest.TestCase):
40
40
  self.assertEqual(test_uri, str(parsed_url))
41
41
  parsed_url = ParsedUrl(test_uri, default_scheme='https')
42
42
  self.assertEqual("https:" + test_uri, str(parsed_url))
43
+ # test that mailto and tel links don't get defaulted
44
+ test_uri = 'mailto:me@mail.com?subject=mysubject&body=mybody'
45
+ parsed_url = ParsedUrl(test_uri, default_scheme='http', default_netloc='localhost:8000', default_filepath='/booger/')
46
+ self.assertEqual("mailto", str(parsed_url.scheme))
47
+ self.assertEqual(test_uri, parsed_url.url)
48
+ test_uri = 'tel: 222.222.2222'
49
+ parsed_url = ParsedUrl(test_uri, default_scheme='http', default_netloc='localhost:8000', default_filepath='/booger/')
50
+ self.assertEqual("tel", str(parsed_url.scheme))
51
+ self.assertEqual(test_uri, parsed_url.url)
52
+
43
53
 
44
54
  # --- basic retrieval
45
55
  # -------------------
@@ -250,3 +250,31 @@ def to_mask(value: str or None) -> str or None:
250
250
  _mask += value[-_iqtr:]
251
251
  return _mask
252
252
 
253
+ def obj_to_str(obj, property_filter_list=None):
254
+ """
255
+ Mostly used for debugging. Very useful to print the properties of an object on a line; condensing reasonably
256
+
257
+ :param obj: the object to inspect properties for
258
+ :param property_filter_list: any property names we want to omit
259
+ :return: a string containing the outputted properties
260
+ """
261
+ attbuf = ""
262
+ for key, value in vars(obj).items():
263
+ if property_filter_list and key in property_filter_list:
264
+ continue
265
+ if not key.startswith('__'):
266
+ if len(attbuf) > 0:
267
+ attbuf += ", "
268
+ # show the first 50 chars and last 25 chars
269
+ this_content = str(value)
270
+ this_content = this_content.replace('\n', ' ').replace('\r', '').strip()
271
+ if this_content:
272
+ if len(this_content) > 150:
273
+ attbuf += str(key) + ": [" + this_content[0:25] + " ... " + this_content[
274
+ len(this_content) - 25:len(
275
+ this_content)] + "]"
276
+ else:
277
+ attbuf += str(key) + ": " + this_content or ""
278
+ else:
279
+ attbuf += str(key) + ": " + this_content or ""
280
+ return "[" + attbuf + "]"
@@ -1,18 +1,59 @@
1
1
  """
2
- A collection of basic xml conversion helper utilities.
2
+ A collection of basic json/xml conversion helper utilities.
3
3
  """
4
- import xml.etree.ElementTree as Etree
4
+ import json
5
5
  import re
6
6
  # from typing import Self (Not available until 3.9; omitting for now)
7
+ import xml.etree.ElementTree as Etree
8
+ # from typing import Self (Not available until 3.9; omitting for now)
7
9
  from collections import defaultdict
8
10
 
9
11
 
10
- class XML:
11
- """ simple xml class to encapsulate basic xml operations """
12
- # the base implementation will be Etree from the base python lib
13
- xml_tree = None
12
+ class JSON:
13
+ """ simple json class to encapsulate basic json operations """
14
+ def __init__(self, json_string: str or None = None, encode_ampersands: bool = False):
15
+ # data is core python objects (list, dict, object, etc) from the core python JSON.loads
16
+ self.data = None
17
+ self.encode_ampersands = encode_ampersands
18
+ self.from_json_string(json_string)
19
+
20
+ def from_json_string(self, json_string: str):
21
+ """
22
+ read in from json_string
23
+ :param json_string:
24
+ :return: self
25
+ """
26
+ if json_string:
27
+ if self.encode_ampersands:
28
+ regex = re.compile(r"&(?!amp;|lt;|gt;)")
29
+ json_string = regex.sub("&amp;", json_string)
30
+ self.data = json.loads(json_string)
31
+ return self
14
32
 
33
+ def from_json_file(self, json_file_path: str):
34
+ """
35
+ read in from json_file
36
+ :param json_file_path: string to file
37
+ :return: self
38
+ """
39
+ with open(json_file_path, encoding='utf-8-sig') as json_file:
40
+ json_string = json_file.read()
41
+ if json_string:
42
+ if self.encode_ampersands:
43
+ regex = re.compile(r"&(?!amp;|lt;|gt;)")
44
+ json_string = regex.sub("&amp;", json_string)
45
+ self.data = json.loads(json_string)
46
+ return self
47
+
48
+ def __str__(self):
49
+ return str(self.data)
50
+
51
+
52
+ class XML:
53
+ """ simple xml class to encapsulate basic xml operations using build in python ETree """
15
54
  def __init__(self, xml_string: str or None = None, encode_ampersands: bool = False):
55
+ # data is core python ElementTree object
56
+ self.data = None
16
57
  self.encode_ampersands = encode_ampersands
17
58
  self.from_xml_string(xml_string)
18
59
 
@@ -26,7 +67,7 @@ class XML:
26
67
  if self.encode_ampersands:
27
68
  regex = re.compile(r"&(?!amp;|lt;|gt;)")
28
69
  xml_string = regex.sub("&amp;", xml_string)
29
- self.xml_tree = Etree.fromstring(xml_string)
70
+ self.data = Etree.fromstring(xml_string)
30
71
  return self
31
72
 
32
73
  def from_xml_file(self, xml_file_path: str):
@@ -46,7 +87,7 @@ class XML:
46
87
  else:
47
88
  tree = Etree.parse(xml_file_path)
48
89
  tree = tree.getroot()
49
- self.xml_tree = tree
90
+ self.data = tree
50
91
  return self
51
92
 
52
93
  def to_dict(self) -> dict:
@@ -54,10 +95,10 @@ class XML:
54
95
  output to dict
55
96
  :return: dict
56
97
  """
57
- return XML.tree_to_dict(self.xml_tree)
98
+ return XML.tree_to_dict(self.data)
58
99
 
59
100
  @staticmethod
60
- def tree_to_dict(t) -> dict:
101
+ def tree_to_dict(t: Etree) -> dict:
61
102
  """
62
103
  Convert an etree structure to a dictionary of values
63
104
  :param t: etree instance
@@ -83,6 +124,6 @@ class XML:
83
124
  return d
84
125
 
85
126
  def __str__(self):
86
- if self.xml_tree:
87
- return Etree.tostring(self.xml_tree, encoding='unicode')
127
+ if self.data:
128
+ return Etree.tostring(self.data, encoding='unicode')
88
129
  return ""
@@ -64,9 +64,11 @@ class ParsedUrl:
64
64
  raise Exception(
65
65
  f'Attempted to parse [{str(self.url_filter(url))}]. Url parameter must exist and be a relative or absolute url after filtering!')
66
66
  self.parsed = urlsplit(self.url_filter(url), default_scheme or "", allow_fragments=allow_fragments)
67
- if default_netloc and not self.parsed.netloc:
67
+ if default_scheme and not self.parsed.scheme and self.netloc:
68
+ self.scheme = default_scheme
69
+ if default_netloc and not self.parsed.netloc and self.scheme in ["http", "https", ""]:
68
70
  self.netloc = default_netloc
69
- if default_filepath and default_filepath not in self.filepath:
71
+ if default_filepath and default_filepath not in self.filepath and self.scheme in ["http", "https", ""]:
70
72
  # we have a parent path we need to append to the existing one
71
73
  new_path = str(PurePath(default_filepath, self.path))
72
74
  # note: I don't want .. since this is web urls; using normpath to remove them unless symlinks is true
@@ -80,10 +82,8 @@ class ParsedUrl:
80
82
  if new_path.endswith(default_filepath) or new_path.endswith(default_filepath[:-1]) and not new_path.endswith('/'):
81
83
  new_path += '/'
82
84
  self.path = new_path
83
- if default_scheme and not self.parsed.scheme and self.netloc:
84
- self.scheme = default_scheme
85
85
  # one last correction; if we have a scheme but no netloc lets omit the scheme so it doesn't give bad results
86
- if not self.parsed.netloc and self.parsed.scheme:
86
+ if not self.parsed.netloc and self.parsed.scheme and self.parsed.scheme in ['http', 'https']:
87
87
  self.parsed = self.parsed._replace(scheme='')
88
88
 
89
89
  @property
@@ -222,12 +222,12 @@ if __name__ == "__main__":
222
222
  # parsed_url = ParsedUrl(test_uri)
223
223
  # print(f"root domain [{test_uri}]: {parsed_url.get_root_domain()}")
224
224
  # print(f"url:{parsed_url.url}")
225
- # test_uri = "/?id=1&b=&c=3"
226
- # parsed_url = ParsedUrl(test_uri, default_netloc='ex.org')
227
- # print(f"root domain [{test_uri}]: {parsed_url.root_domain}")
228
- # print(f"url:{parsed_url.url}")
229
- # print(f"base: {parsed_url.base}")
230
- # print(f"rel: {parsed_url.rel}")
225
+ test_uri = "/?id=1&b=&c=3"
226
+ parsed_url = ParsedUrl(test_uri, default_netloc='ex.org')
227
+ print(f"root domain [{test_uri}]: {parsed_url.root_domain}")
228
+ print(f"url:{parsed_url.url}")
229
+ print(f"base: {parsed_url.base}")
230
+ print(f"rel: {parsed_url.rel}")
231
231
  # print(f"url after base: {parsed_url.url}")
232
232
  # parsed_url.domain = "ex.org"
233
233
  # print(f"root domain [{str(parsed_url)}]: {parsed_url.root_domain}")
@@ -241,9 +241,13 @@ if __name__ == "__main__":
241
241
  # print(f"test parent fragment only: {ParsedUrl(test_uri, default_netloc='localhost:8000', default_scheme='http', default_path='/mdb/')}")
242
242
  # test_uri = "#testproduct"
243
243
  # print(f"test parent fragment only: {ParsedUrl(test_uri, default_netloc='localhost:8000', default_scheme='http', default_path='/mdb/')}")
244
- test_uri = "/products/"
245
- purl = ParsedUrl(test_uri, default_scheme='http', default_netloc='localhost:8000', default_filepath='/blog')
246
- print(purl)
247
- test_uri = "../products/"
248
- purl = ParsedUrl(test_uri, default_scheme='http', default_netloc='localhost:8000', default_filepath='/')
249
- print(purl)
244
+ # test_uri = "/products/"
245
+ # purl = ParsedUrl(test_uri, default_scheme='http', default_netloc='localhost:8000', default_filepath='/blog')
246
+ # print(purl)
247
+ # test_uri = "../products/"
248
+ # purl = ParsedUrl(test_uri, default_scheme='http', default_netloc='localhost:8000', default_filepath='/')
249
+ # print(purl)
250
+ # # test mailto links
251
+ test_uri = 'mailto:me@mail.com?subject=mysubject&body=mybody'
252
+ purl = ParsedUrl(test_uri, default_scheme='http', default_netloc='localhost:8000')
253
+ print(purl)
@@ -1,61 +0,0 @@
1
- import unittest
2
- from ubercode.utils.xml import XML
3
- from pathlib import Path
4
-
5
-
6
- class TestXML(unittest.TestCase):
7
-
8
- # -------- common usages ----------
9
- def test_XML(self):
10
- # calculate the filename for our test.xml file from this file (much like settings does)
11
- file_path = Path(__file__).resolve().parent / 'test.xml'
12
- xml_string = """
13
- <contacts>
14
- <contact>
15
- <name>Steve Stacha</name>
16
- </contact>
17
- <contact>
18
- <name>Buggs Bunny</name>
19
- </contact>
20
- <contact>
21
- <name>Daffy Duck</name>
22
- </contact>
23
- </contacts>
24
- """
25
- # test we can construct from an xml string
26
- xml = XML(xml_string=xml_string)
27
- # NOTE: because we used a multiline string we need to strip the extra newlines before and after <contacts>
28
- self.assertEqual(str(xml), xml_string.strip())
29
- # normal string doesn't need stripping
30
- xml_compact_string = "<contacts><contact><name>Buggs Bunny</name></contact><contact><name>Daffy Duck</name></contact></contacts>"
31
- xml2 = XML(xml_compact_string)
32
- self.assertEqual(str(xml2), xml_compact_string)
33
- # test we can create using the from_xml_string() method chaining
34
- xml3 = XML().from_xml_string(xml_compact_string)
35
- self.assertEqual(str(xml2), str(xml3))
36
- # test that method chaining after constructor overrides the value in place
37
- self.assertNotEqual(str(xml), str(xml2))
38
- xml.from_xml_string(xml_compact_string)
39
- self.assertEqual(str(xml), str(xml2))
40
- # test that we can read from file
41
- xml.from_xml_file(file_path)
42
- # we should be back to before
43
- self.assertEqual(str(xml), xml_string.strip())
44
- # test an attribute
45
- xml_string = """
46
- <contacts>
47
- <contact attr="1">
48
- <name>Steve Stacha</name>
49
- </contact>
50
- <contact>
51
- <name>Buggs & Bunny</name>
52
- </contact>
53
- <contact>
54
- <name>Daffy Duck</name>
55
- </contact>
56
- </contacts>
57
- """
58
- xml = XML(xml_string=xml_string, encode_ampersands=True)
59
- xml_dict = xml.to_dict()
60
- self.assertEqual(xml_dict['contacts']['contact'][0]['@attr'], '1')
61
-
@@ -1,54 +0,0 @@
1
- """
2
- A collection of basic json conversion helper utilities.
3
- """
4
- import json
5
- import re
6
- # from typing import Self (Not available until 3.9; omitting for now)
7
-
8
-
9
- class JSON:
10
- """ simple json class to encapsulate basic json operations """
11
- # the base implementation will be dict
12
- json_dict = {}
13
-
14
- def __init__(self, json_string: str or None = None, encode_ampersands: bool = False):
15
- self.encode_ampersands = encode_ampersands
16
- self.from_json_string(json_string)
17
-
18
- def from_json_string(self, json_string: str):
19
- """
20
- read in from json_string
21
- :param json_string:
22
- :return: self
23
- """
24
- if json_string:
25
- if self.encode_ampersands:
26
- regex = re.compile(r"&(?!amp;|lt;|gt;)")
27
- json_string = regex.sub("&amp;", json_string)
28
- self.json_dict = json.loads(json_string)
29
- return self
30
-
31
- def from_json_file(self, json_file_path: str):
32
- """
33
- read in from json_file
34
- :param json_file_path: string to file
35
- :return: self
36
- """
37
- with open(json_file_path, encoding='utf-8-sig') as json_file:
38
- json_string = json_file.read()
39
- if json_string:
40
- if self.encode_ampersands:
41
- regex = re.compile(r"&(?!amp;|lt;|gt;)")
42
- json_string = regex.sub("&amp;", json_string)
43
- self.json_dict = json.loads(json_string)
44
- return self
45
-
46
- def to_dict(self) -> dict:
47
- """
48
- output to dict
49
- :return: dict
50
- """
51
- return self.json_dict
52
-
53
- def __str__(self):
54
- return str(self.json_dict)