edq-utils 0.0.5__py3-none-any.whl → 0.0.7__py3-none-any.whl

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.

Potentially problematic release.


This version of edq-utils might be problematic. Click here for more details.

Files changed (62) hide show
  1. edq/__init__.py +1 -1
  2. edq/cli/config/__init__.py +3 -0
  3. edq/cli/config/list.py +69 -0
  4. edq/cli/http/__init__.py +3 -0
  5. edq/cli/http/exchange-server.py +71 -0
  6. edq/cli/http/send-exchange.py +45 -0
  7. edq/cli/http/verify-exchanges.py +38 -0
  8. edq/cli/testing/__init__.py +3 -0
  9. edq/cli/testing/cli-test.py +8 -5
  10. edq/cli/version.py +2 -1
  11. edq/core/argparser.py +28 -3
  12. edq/core/config.py +268 -0
  13. edq/core/config_test.py +1038 -0
  14. edq/procedure/__init__.py +0 -0
  15. edq/procedure/verify_exchanges.py +85 -0
  16. edq/testing/asserts.py +0 -1
  17. edq/testing/cli.py +17 -1
  18. edq/testing/httpserver.py +553 -0
  19. edq/testing/httpserver_test.py +424 -0
  20. edq/testing/run.py +40 -10
  21. edq/testing/testdata/cli/data/configs/empty/edq-config.json +1 -0
  22. edq/testing/testdata/cli/data/configs/simple-1/edq-config.json +4 -0
  23. edq/testing/testdata/cli/data/configs/simple-2/edq-config.json +3 -0
  24. edq/testing/testdata/cli/data/configs/value-number/edq-config.json +3 -0
  25. edq/testing/testdata/cli/tests/config/list/config_list_base.txt +16 -0
  26. edq/testing/testdata/cli/tests/config/list/config_list_config_value_number.txt +10 -0
  27. edq/testing/testdata/cli/tests/config/list/config_list_ignore_config.txt +14 -0
  28. edq/testing/testdata/cli/tests/config/list/config_list_no_config.txt +8 -0
  29. edq/testing/testdata/cli/tests/config/list/config_list_show_origin.txt +13 -0
  30. edq/testing/testdata/cli/tests/config/list/config_list_skip_header.txt +10 -0
  31. edq/testing/testdata/http/exchanges/simple.httpex.json +5 -0
  32. edq/testing/testdata/http/exchanges/simple_anchor.httpex.json +5 -0
  33. edq/testing/testdata/http/exchanges/simple_file.httpex.json +10 -0
  34. edq/testing/testdata/http/exchanges/simple_file_binary.httpex.json +10 -0
  35. edq/testing/testdata/http/exchanges/simple_file_get_params.httpex.json +14 -0
  36. edq/testing/testdata/http/exchanges/simple_file_multiple.httpex.json +13 -0
  37. edq/testing/testdata/http/exchanges/simple_file_name.httpex.json +11 -0
  38. edq/testing/testdata/http/exchanges/simple_file_post_multiple.httpex.json +13 -0
  39. edq/testing/testdata/http/exchanges/simple_file_post_params.httpex.json +14 -0
  40. edq/testing/testdata/http/exchanges/simple_headers.httpex.json +8 -0
  41. edq/testing/testdata/http/exchanges/simple_jsonresponse_dict.httpex.json +7 -0
  42. edq/testing/testdata/http/exchanges/simple_jsonresponse_list.httpex.json +9 -0
  43. edq/testing/testdata/http/exchanges/simple_params.httpex.json +9 -0
  44. edq/testing/testdata/http/exchanges/simple_post.httpex.json +5 -0
  45. edq/testing/testdata/http/exchanges/simple_post_params.httpex.json +9 -0
  46. edq/testing/testdata/http/exchanges/simple_post_urlparams.httpex.json +5 -0
  47. edq/testing/testdata/http/exchanges/simple_urlparams.httpex.json +5 -0
  48. edq/testing/testdata/http/exchanges/specialcase_listparams_explicit.httpex.json +8 -0
  49. edq/testing/testdata/http/exchanges/specialcase_listparams_url.httpex.json +5 -0
  50. edq/testing/testdata/http/files/a.txt +1 -0
  51. edq/testing/testdata/http/files/tiny.png +0 -0
  52. edq/testing/unittest.py +12 -7
  53. edq/util/dirent.py +2 -0
  54. edq/util/json.py +21 -4
  55. edq/util/net.py +895 -0
  56. edq_utils-0.0.7.dist-info/METADATA +156 -0
  57. edq_utils-0.0.7.dist-info/RECORD +78 -0
  58. edq_utils-0.0.5.dist-info/METADATA +0 -63
  59. edq_utils-0.0.5.dist-info/RECORD +0 -34
  60. {edq_utils-0.0.5.dist-info → edq_utils-0.0.7.dist-info}/WHEEL +0 -0
  61. {edq_utils-0.0.5.dist-info → edq_utils-0.0.7.dist-info}/licenses/LICENSE +0 -0
  62. {edq_utils-0.0.5.dist-info → edq_utils-0.0.7.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,11 @@
1
+ {
2
+ "method": "GET",
3
+ "url": "simple",
4
+ "files": [
5
+ {
6
+ "path": "../files/a.txt",
7
+ "name": "foo.txt"
8
+ }
9
+ ],
10
+ "response_body": "simple_file_name"
11
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "method": "POST",
3
+ "url": "simple",
4
+ "files": [
5
+ {
6
+ "path": "../files/a.txt"
7
+ },
8
+ {
9
+ "path": "../files/tiny.png"
10
+ }
11
+ ],
12
+ "response_body": "simple_file_post_multiple"
13
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "method": "POST",
3
+ "url": "simple",
4
+ "parameters": {
5
+ "a": "1",
6
+ "b": "2"
7
+ },
8
+ "files": [
9
+ {
10
+ "path": "../files/a.txt"
11
+ }
12
+ ],
13
+ "response_body": "simple_file_post_params"
14
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "method": "GET",
3
+ "url": "simple",
4
+ "headers": {
5
+ "a": "1"
6
+ },
7
+ "response_body": "simple_headers"
8
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "method": "GET",
3
+ "url": "simple/jsonresponse/dict",
4
+ "response_body": {
5
+ "a": 1
6
+ }
7
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "method": "GET",
3
+ "url": "simple/jsonresponse/list",
4
+ "response_body": [
5
+ {
6
+ "a": 1
7
+ }
8
+ ]
9
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "method": "GET",
3
+ "url": "simple",
4
+ "parameters": {
5
+ "a": "1",
6
+ "b": "2"
7
+ },
8
+ "response_body": "simple_params"
9
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "method": "POST",
3
+ "url": "simple",
4
+ "response_body": "simple_post"
5
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "method": "POST",
3
+ "url": "simple",
4
+ "parameters": {
5
+ "a": "1",
6
+ "b": "2"
7
+ },
8
+ "response_body": "simple_post_params"
9
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "method": "POST",
3
+ "url": "simple?c=3&d=4",
4
+ "response_body": "simple_post_urlparams"
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "method": "GET",
3
+ "url": "simple?c=3&d=4",
4
+ "response_body": "simple_urlparams"
5
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "method": "GET",
3
+ "url": "simple",
4
+ "parameters": {
5
+ "a": ["1", "2"]
6
+ },
7
+ "response_body": "specialcase_listparams_explicit"
8
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "method": "GET",
3
+ "url": "simple?b=1&b=2",
4
+ "response_body": "specialcase_listparams_url"
5
+ }
@@ -0,0 +1 @@
1
+ a
Binary file
edq/testing/unittest.py CHANGED
@@ -14,12 +14,11 @@ class BaseTest(unittest.TestCase):
14
14
  maxDiff = None
15
15
  """ Don't limit the size of diffs. """
16
16
 
17
- def assertJSONDictEqual(self, a: typing.Any, b: typing.Any) -> None: # pylint: disable=invalid-name
17
+ def assertJSONDictEqual(self, a: typing.Any, b: typing.Any, message: typing.Union[str, None] = None) -> None: # pylint: disable=invalid-name
18
18
  """
19
19
  Like unittest.TestCase.assertDictEqual(),
20
20
  but will try to convert each comparison argument to a dict if it is not already,
21
- and uses an assertion message containing the full JSON representation of the arguments.
22
-
21
+ and uses a default assertion message containing the full JSON representation of the arguments.
23
22
  """
24
23
 
25
24
  if (not isinstance(a, dict)):
@@ -37,17 +36,23 @@ class BaseTest(unittest.TestCase):
37
36
  a_json = edq.util.json.dumps(a, indent = 4)
38
37
  b_json = edq.util.json.dumps(b, indent = 4)
39
38
 
40
- super().assertDictEqual(a, b, FORMAT_STR % (a_json, b_json))
39
+ if (message is None):
40
+ message = FORMAT_STR % (a_json, b_json)
41
+
42
+ super().assertDictEqual(a, b, msg = message)
41
43
 
42
- def assertJSONListEqual(self, a: typing.List[typing.Any], b: typing.List[typing.Any]) -> None: # pylint: disable=invalid-name
44
+ def assertJSONListEqual(self, a: typing.List[typing.Any], b: typing.List[typing.Any], message: typing.Union[str, None] = None) -> None: # pylint: disable=invalid-name
43
45
  """
44
- Call assertListEqual(), but supply a message containing the full JSON representation of the arguments.
46
+ Call assertDictEqual(), but supply a default message containing the full JSON representation of the arguments.
45
47
  """
46
48
 
47
49
  a_json = edq.util.json.dumps(a, indent = 4)
48
50
  b_json = edq.util.json.dumps(b, indent = 4)
49
51
 
50
- super().assertListEqual(a, b, FORMAT_STR % (a_json, b_json))
52
+ if (message is None):
53
+ message = FORMAT_STR % (a_json, b_json)
54
+
55
+ super().assertListEqual(a, b, msg = message)
51
56
 
52
57
  def format_error_string(self, ex: typing.Union[BaseException, None]) -> str:
53
58
  """
edq/util/dirent.py CHANGED
@@ -41,6 +41,8 @@ def get_temp_path(prefix: str = '', suffix: str = '', rm: bool = True) -> str:
41
41
  while ((path is None) or exists(path)):
42
42
  path = os.path.join(tempfile.gettempdir(), prefix + str(uuid.uuid4()) + suffix)
43
43
 
44
+ path = os.path.realpath(path)
45
+
44
46
  if (rm):
45
47
  atexit.register(remove, path)
46
48
 
edq/util/json.py CHANGED
@@ -4,37 +4,45 @@ Specifically, we try to be flexible when reading (using JSON5),
4
4
  and strict when writing (using vanilla JSON).
5
5
  """
6
6
 
7
- import abc
8
7
  import enum
9
8
  import json
9
+ import os
10
10
  import typing
11
11
 
12
12
  import json5
13
13
 
14
14
  import edq.util.dirent
15
15
 
16
- class DictConverter(abc.ABC):
16
+ class DictConverter():
17
17
  """
18
18
  A base class for class that can represent (serialize) and reconstruct (deserialize) themselves as/from a dict.
19
19
  The intention is that the dict can then be cleanly converted to/from JSON.
20
+
21
+ General (but inefficient) implementations of several core Python equality, comparison, and representation methods are provided.
20
22
  """
21
23
 
22
- @abc.abstractmethod
23
24
  def to_dict(self) -> typing.Dict[str, typing.Any]:
24
25
  """
25
26
  Return a dict that can be used to represent this object.
26
27
  If the dict is passed to from_dict(), an identical object should be reconstructed.
28
+
29
+ A general (but inefficient) implementation is provided by default.
27
30
  """
28
31
 
32
+ return vars(self).copy()
33
+
29
34
  @classmethod
30
- @abc.abstractmethod
31
35
  # Note that `typing.Self` is returned, but that is introduced in Python 3.12.
32
36
  def from_dict(cls, data: typing.Dict[str, typing.Any]) -> typing.Any:
33
37
  """
34
38
  Return an instance of this subclass created using the given dict.
35
39
  If the dict came from to_dict(), the returned object should be identical to the original.
40
+
41
+ A general (but inefficient) implementation is provided by default.
36
42
  """
37
43
 
44
+ return cls(**data)
45
+
38
46
  def __eq__(self, other: object) -> bool:
39
47
  """
40
48
  Check for equality.
@@ -49,6 +57,12 @@ class DictConverter(abc.ABC):
49
57
 
50
58
  return bool(self.to_dict() == other.to_dict()) # type: ignore[attr-defined]
51
59
 
60
+ def __lt__(self, other: 'DictConverter') -> bool:
61
+ return dumps(self) < dumps(other)
62
+
63
+ def __hash__(self) -> int:
64
+ return hash(dumps(self))
65
+
52
66
  def __str__(self) -> str:
53
67
  return dumps(self)
54
68
 
@@ -107,6 +121,9 @@ def load_path(
107
121
  otherwise use JSON5.
108
122
  """
109
123
 
124
+ if (os.path.isdir(path)):
125
+ raise IsADirectoryError(f"Cannot open JSON file, expected a file but got a directory at '{path}'.")
126
+
110
127
  try:
111
128
  with open(path, 'r', encoding = encoding) as file:
112
129
  return load(file, strict = strict, **kwargs)