edq-utils 0.0.5__tar.gz → 0.0.6__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.
Potentially problematic release.
This version of edq-utils might be problematic. Click here for more details.
- edq_utils-0.0.6/.mypy.ini +12 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/.pylintrc +2 -0
- edq_utils-0.0.6/PKG-INFO +156 -0
- edq_utils-0.0.6/README.md +110 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/__init__.py +1 -1
- edq_utils-0.0.6/edq/cli/config/__init__.py +3 -0
- edq_utils-0.0.6/edq/cli/config/list.py +69 -0
- edq_utils-0.0.6/edq/cli/http/__init__.py +3 -0
- edq_utils-0.0.6/edq/cli/http/exchange-server.py +71 -0
- edq_utils-0.0.6/edq/cli/http/send-exchange.py +45 -0
- edq_utils-0.0.6/edq/cli/http/verify-exchanges.py +38 -0
- edq_utils-0.0.6/edq/cli/testing/__init__.py +3 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/cli/testing/cli-test.py +8 -5
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/cli/version.py +2 -1
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/core/argparser.py +28 -3
- edq_utils-0.0.6/edq/core/config.py +268 -0
- edq_utils-0.0.6/edq/core/config_test.py +1038 -0
- edq_utils-0.0.6/edq/procedure/verify_exchanges.py +85 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/testing/asserts.py +0 -1
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/testing/cli.py +17 -1
- edq_utils-0.0.6/edq/testing/httpserver.py +553 -0
- edq_utils-0.0.6/edq/testing/httpserver_test.py +424 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/testing/run.py +40 -10
- edq_utils-0.0.6/edq/testing/testdata/cli/data/configs/empty/edq-config.json +1 -0
- edq_utils-0.0.6/edq/testing/testdata/cli/data/configs/simple-1/edq-config.json +4 -0
- edq_utils-0.0.6/edq/testing/testdata/cli/data/configs/simple-2/edq-config.json +3 -0
- edq_utils-0.0.6/edq/testing/testdata/cli/data/configs/value-number/edq-config.json +3 -0
- edq_utils-0.0.6/edq/testing/testdata/cli/tests/config/list/config_list_base.txt +16 -0
- edq_utils-0.0.6/edq/testing/testdata/cli/tests/config/list/config_list_config_value_number.txt +10 -0
- edq_utils-0.0.6/edq/testing/testdata/cli/tests/config/list/config_list_ignore_config.txt +14 -0
- edq_utils-0.0.6/edq/testing/testdata/cli/tests/config/list/config_list_no_config.txt +8 -0
- edq_utils-0.0.6/edq/testing/testdata/cli/tests/config/list/config_list_show_origin.txt +13 -0
- edq_utils-0.0.6/edq/testing/testdata/cli/tests/config/list/config_list_skip_header.txt +10 -0
- edq_utils-0.0.6/edq/testing/testdata/http/exchanges/simple.httpex.json +5 -0
- edq_utils-0.0.6/edq/testing/testdata/http/exchanges/simple_anchor.httpex.json +5 -0
- edq_utils-0.0.6/edq/testing/testdata/http/exchanges/simple_file.httpex.json +10 -0
- edq_utils-0.0.6/edq/testing/testdata/http/exchanges/simple_file_binary.httpex.json +10 -0
- edq_utils-0.0.6/edq/testing/testdata/http/exchanges/simple_file_get_params.httpex.json +14 -0
- edq_utils-0.0.6/edq/testing/testdata/http/exchanges/simple_file_multiple.httpex.json +13 -0
- edq_utils-0.0.6/edq/testing/testdata/http/exchanges/simple_file_name.httpex.json +11 -0
- edq_utils-0.0.6/edq/testing/testdata/http/exchanges/simple_file_post_multiple.httpex.json +13 -0
- edq_utils-0.0.6/edq/testing/testdata/http/exchanges/simple_file_post_params.httpex.json +14 -0
- edq_utils-0.0.6/edq/testing/testdata/http/exchanges/simple_headers.httpex.json +8 -0
- edq_utils-0.0.6/edq/testing/testdata/http/exchanges/simple_jsonresponse_dict.httpex.json +7 -0
- edq_utils-0.0.6/edq/testing/testdata/http/exchanges/simple_jsonresponse_list.httpex.json +9 -0
- edq_utils-0.0.6/edq/testing/testdata/http/exchanges/simple_params.httpex.json +9 -0
- edq_utils-0.0.6/edq/testing/testdata/http/exchanges/simple_post.httpex.json +5 -0
- edq_utils-0.0.6/edq/testing/testdata/http/exchanges/simple_post_params.httpex.json +9 -0
- edq_utils-0.0.6/edq/testing/testdata/http/exchanges/simple_post_urlparams.httpex.json +5 -0
- edq_utils-0.0.6/edq/testing/testdata/http/exchanges/simple_urlparams.httpex.json +5 -0
- edq_utils-0.0.6/edq/testing/testdata/http/exchanges/specialcase_listparams_explicit.httpex.json +8 -0
- edq_utils-0.0.6/edq/testing/testdata/http/exchanges/specialcase_listparams_url.httpex.json +5 -0
- edq_utils-0.0.6/edq/testing/testdata/http/files/a.txt +1 -0
- edq_utils-0.0.6/edq/testing/testdata/http/files/tiny.png +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/testing/unittest.py +12 -7
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/util/dirent.py +2 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/util/json.py +21 -4
- edq_utils-0.0.6/edq/util/net.py +894 -0
- edq_utils-0.0.6/edq_utils.egg-info/PKG-INFO +156 -0
- edq_utils-0.0.6/edq_utils.egg-info/SOURCES.txt +94 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq_utils.egg-info/requires.txt +1 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/requirements-dev.txt +1 -0
- edq_utils-0.0.5/.mypy.ini +0 -6
- edq_utils-0.0.5/PKG-INFO +0 -63
- edq_utils-0.0.5/README.md +0 -18
- edq_utils-0.0.5/edq_utils.egg-info/PKG-INFO +0 -63
- edq_utils-0.0.5/edq_utils.egg-info/SOURCES.txt +0 -50
- {edq_utils-0.0.5 → edq_utils-0.0.6}/.github/workflows/main.yml +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/.gitignore +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/LICENSE +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/cli/__init__.py +0 -0
- {edq_utils-0.0.5/edq/cli/testing → edq_utils-0.0.6/edq/core}/__init__.py +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/core/argparser_test.py +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/core/log.py +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/core/version.py +0 -0
- {edq_utils-0.0.5/edq/core → edq_utils-0.0.6/edq/procedure}/__init__.py +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/py.typed +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/testing/__init__.py +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/testing/cli_test.py +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/testing/testdata/cli/tests/platform_skip.txt +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/testing/testdata/cli/tests/version_base.txt +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/util/__init__.py +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/util/dirent_test.py +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/util/json_test.py +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/util/pyimport.py +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/util/pyimport_test.py +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/util/reflection.py +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/util/time.py +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq/util/time_test.py +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq_utils.egg-info/dependency_links.txt +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/edq_utils.egg-info/top_level.txt +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/pyproject.toml +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/requirements.txt +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/scripts/check_all.sh +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/scripts/check_lint.sh +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/scripts/check_python_version.sh +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/scripts/check_strict_types.sh +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/scripts/check_types.sh +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/scripts/gen_docs.sh +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/scripts/run_tests.sh +0 -0
- {edq_utils-0.0.5 → edq_utils-0.0.6}/setup.cfg +0 -0
|
@@ -444,9 +444,11 @@ disable=bad-inline-option,
|
|
|
444
444
|
too-many-arguments,
|
|
445
445
|
too-many-branches,
|
|
446
446
|
too-many-instance-attributes,
|
|
447
|
+
too-many-lines,
|
|
447
448
|
too-many-locals,
|
|
448
449
|
too-many-positional-arguments,
|
|
449
450
|
too-many-public-methods,
|
|
451
|
+
too-many-return-statements,
|
|
450
452
|
too-many-statements,
|
|
451
453
|
unused-argument,
|
|
452
454
|
use-symbolic-message-instead,
|
edq_utils-0.0.6/PKG-INFO
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: edq-utils
|
|
3
|
+
Version: 0.0.6
|
|
4
|
+
Summary: Common utilities used by EduLinq Python projects.
|
|
5
|
+
Author-email: Eriq Augustine <eriq@edulinq.org>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2025 EduLinq
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/edulinq/python-utils
|
|
29
|
+
Project-URL: Repository, https://github.com/edulinq/python-utils
|
|
30
|
+
Keywords: education,utilities
|
|
31
|
+
Classifier: Intended Audience :: Developers
|
|
32
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
33
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
34
|
+
Requires-Python: >=3.8
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
License-File: LICENSE
|
|
37
|
+
Requires-Dist: json5>=0.9.14
|
|
38
|
+
Provides-Extra: dev
|
|
39
|
+
Requires-Dist: mypy>=1.14.1; extra == "dev"
|
|
40
|
+
Requires-Dist: pdoc>=14.7.0; extra == "dev"
|
|
41
|
+
Requires-Dist: pylint; extra == "dev"
|
|
42
|
+
Requires-Dist: requests-toolbelt; extra == "dev"
|
|
43
|
+
Requires-Dist: twine; extra == "dev"
|
|
44
|
+
Requires-Dist: vermin; extra == "dev"
|
|
45
|
+
Dynamic: license-file
|
|
46
|
+
|
|
47
|
+
# EduLinq Python Utilities
|
|
48
|
+
|
|
49
|
+
Common utilities used by EduLinq Python projects.
|
|
50
|
+
|
|
51
|
+
## Installation / Requirements
|
|
52
|
+
|
|
53
|
+
This project requires [Python](https://www.python.org/) >= 3.8.
|
|
54
|
+
|
|
55
|
+
The project can be installed from PyPi with:
|
|
56
|
+
```
|
|
57
|
+
pip3 install edq-utils
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Standard Python requirements are listed in `pyproject.toml`.
|
|
61
|
+
The project and Python dependencies can be installed from source with:
|
|
62
|
+
```
|
|
63
|
+
pip3 install .
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Configuration System
|
|
67
|
+
|
|
68
|
+
This project provides a configuration system that supplies options (e.g., username, password) to a command-line interface (CLI) tool.
|
|
69
|
+
The configuration system follows a tiered order, allowing options to be specified and overridden from both files and command-line options.
|
|
70
|
+
|
|
71
|
+
### Configuration Sources
|
|
72
|
+
|
|
73
|
+
In addition to CLI options, the configuration system loads options from [JSON](https://en.wikipedia.org/wiki/JSON) files located across multiple directories.
|
|
74
|
+
By default, configuration files are named `edq-config.json`.
|
|
75
|
+
This value is customizable, but this document will assume the default is used.
|
|
76
|
+
|
|
77
|
+
For example, a configuration file containing the `user` and `pass` options might look like this:
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"user": "alice",
|
|
81
|
+
"pass": "password123"
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The table below summarizes the configuration sources in the order they are evaluated.
|
|
86
|
+
Values from earlier sources can be overwritten by values from later sources.
|
|
87
|
+
|
|
88
|
+
| Source | Description |
|
|
89
|
+
| :----- | :---------- |
|
|
90
|
+
| Global | Loaded from a file in a user-specific location, which is platform-dependent. |
|
|
91
|
+
| Local | Loaded from a file in the current or nearest ancestor directory. |
|
|
92
|
+
| CLI File | Loaded from one or more explicitly provided configuration files through the CLI. |
|
|
93
|
+
| CLI | Loaded from the command line. |
|
|
94
|
+
|
|
95
|
+
The system produces an error if a global or local configuration file is unreadable (but not missing), or if a CLI-specified file is unreadable or missing.
|
|
96
|
+
|
|
97
|
+
#### Global Configuration
|
|
98
|
+
|
|
99
|
+
Global configuration are options that are user specific and stick with the user between projects, these are well suited for options like login credentials.
|
|
100
|
+
The global configuration file defaults to `<platform-specific user configuration location>/edq-config.json`.
|
|
101
|
+
The configuration location is chosen according to the [XDG standard](https://en.wikipedia.org/wiki/Freedesktop.org#Base_Directory_Specification) (implemented by [platformdirs](https://github.com/tox-dev/platformdirs)).
|
|
102
|
+
Below are examples of user-specific configuration file paths for different operating systems:
|
|
103
|
+
- Linux -- `/home/<user>/.config/edq-config.json`
|
|
104
|
+
- Mac -- `/Users/<user>/Library/Application Support/edq-config.json`
|
|
105
|
+
- Windows -- `C:\Users\<user>\AppData\Local\edq-config.json`
|
|
106
|
+
|
|
107
|
+
The default global configuration location can be changed by passing a path to `--config-global` through the command line.
|
|
108
|
+
|
|
109
|
+
Below is an example command for specifying a global configuration path from the CLI:
|
|
110
|
+
```sh
|
|
111
|
+
python3 -m edq.cli.config.list --config-global ~/.config/custom-config.json
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
#### Local Configuration
|
|
115
|
+
|
|
116
|
+
Local configuration are options that are specific to a project or directory, like a project's build directory.
|
|
117
|
+
Local configuration files are searched in multiple locations, the first file found is used.
|
|
118
|
+
The local config search order is:
|
|
119
|
+
1. `edq-config.json` in the current directory.
|
|
120
|
+
2. A legacy file in the current directory (only if a legacy file is preconfigured).
|
|
121
|
+
3. `edq-config.json` in any ancestor directory on the path to root (including root itself).
|
|
122
|
+
|
|
123
|
+
#### CLI-Specified Config Files
|
|
124
|
+
|
|
125
|
+
CLI config files are options specified on the command line via a file.
|
|
126
|
+
These are useful for a common set of options you don’t need every time, such as login credentials for different user.
|
|
127
|
+
Any files passed via `--config-file` will be loaded in the order they appear on the command line.
|
|
128
|
+
Options from later files override options from previous files.
|
|
129
|
+
|
|
130
|
+
Below is an example of a CLI specified configuration paths:
|
|
131
|
+
```sh
|
|
132
|
+
python3 -m edq.cli.config.list --config-file ./edq-config.json --config-file ~/.secrets/edq-config.json
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
#### CLI Configuration
|
|
136
|
+
|
|
137
|
+
CLI configurations are options specified directly on the command line, these are useful for quick option overrides without editing config files.
|
|
138
|
+
Configuration options are passed to the command line by the `--config` flag in this format `<key>=<value>`.
|
|
139
|
+
The provided values overrides the values from configuration files.
|
|
140
|
+
Configuration options are structured as key value pairs and keys cannot contain the "=" character.
|
|
141
|
+
|
|
142
|
+
Below is an example of specifying a configuration option directly from the CLI:
|
|
143
|
+
```sh
|
|
144
|
+
python3 -m edq.cli.config.list --config user=alice --config pass=password123
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
#### CLI Config Options
|
|
148
|
+
|
|
149
|
+
The table below lists common configuration CLI options available for CLI tools using this library.
|
|
150
|
+
|
|
151
|
+
| CLI Option | Description |
|
|
152
|
+
| :-------------- | :---------- |
|
|
153
|
+
|`--config-global` | Override the global config file location. |
|
|
154
|
+
|`--config-file` | Load configuration options from a CLI specified file. |
|
|
155
|
+
| `--config` | Provide additional options to a CLI command. |
|
|
156
|
+
| `--help` | Display standard help text and the default global configuration file path for the current platform. |
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# EduLinq Python Utilities
|
|
2
|
+
|
|
3
|
+
Common utilities used by EduLinq Python projects.
|
|
4
|
+
|
|
5
|
+
## Installation / Requirements
|
|
6
|
+
|
|
7
|
+
This project requires [Python](https://www.python.org/) >= 3.8.
|
|
8
|
+
|
|
9
|
+
The project can be installed from PyPi with:
|
|
10
|
+
```
|
|
11
|
+
pip3 install edq-utils
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Standard Python requirements are listed in `pyproject.toml`.
|
|
15
|
+
The project and Python dependencies can be installed from source with:
|
|
16
|
+
```
|
|
17
|
+
pip3 install .
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Configuration System
|
|
21
|
+
|
|
22
|
+
This project provides a configuration system that supplies options (e.g., username, password) to a command-line interface (CLI) tool.
|
|
23
|
+
The configuration system follows a tiered order, allowing options to be specified and overridden from both files and command-line options.
|
|
24
|
+
|
|
25
|
+
### Configuration Sources
|
|
26
|
+
|
|
27
|
+
In addition to CLI options, the configuration system loads options from [JSON](https://en.wikipedia.org/wiki/JSON) files located across multiple directories.
|
|
28
|
+
By default, configuration files are named `edq-config.json`.
|
|
29
|
+
This value is customizable, but this document will assume the default is used.
|
|
30
|
+
|
|
31
|
+
For example, a configuration file containing the `user` and `pass` options might look like this:
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"user": "alice",
|
|
35
|
+
"pass": "password123"
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The table below summarizes the configuration sources in the order they are evaluated.
|
|
40
|
+
Values from earlier sources can be overwritten by values from later sources.
|
|
41
|
+
|
|
42
|
+
| Source | Description |
|
|
43
|
+
| :----- | :---------- |
|
|
44
|
+
| Global | Loaded from a file in a user-specific location, which is platform-dependent. |
|
|
45
|
+
| Local | Loaded from a file in the current or nearest ancestor directory. |
|
|
46
|
+
| CLI File | Loaded from one or more explicitly provided configuration files through the CLI. |
|
|
47
|
+
| CLI | Loaded from the command line. |
|
|
48
|
+
|
|
49
|
+
The system produces an error if a global or local configuration file is unreadable (but not missing), or if a CLI-specified file is unreadable or missing.
|
|
50
|
+
|
|
51
|
+
#### Global Configuration
|
|
52
|
+
|
|
53
|
+
Global configuration are options that are user specific and stick with the user between projects, these are well suited for options like login credentials.
|
|
54
|
+
The global configuration file defaults to `<platform-specific user configuration location>/edq-config.json`.
|
|
55
|
+
The configuration location is chosen according to the [XDG standard](https://en.wikipedia.org/wiki/Freedesktop.org#Base_Directory_Specification) (implemented by [platformdirs](https://github.com/tox-dev/platformdirs)).
|
|
56
|
+
Below are examples of user-specific configuration file paths for different operating systems:
|
|
57
|
+
- Linux -- `/home/<user>/.config/edq-config.json`
|
|
58
|
+
- Mac -- `/Users/<user>/Library/Application Support/edq-config.json`
|
|
59
|
+
- Windows -- `C:\Users\<user>\AppData\Local\edq-config.json`
|
|
60
|
+
|
|
61
|
+
The default global configuration location can be changed by passing a path to `--config-global` through the command line.
|
|
62
|
+
|
|
63
|
+
Below is an example command for specifying a global configuration path from the CLI:
|
|
64
|
+
```sh
|
|
65
|
+
python3 -m edq.cli.config.list --config-global ~/.config/custom-config.json
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
#### Local Configuration
|
|
69
|
+
|
|
70
|
+
Local configuration are options that are specific to a project or directory, like a project's build directory.
|
|
71
|
+
Local configuration files are searched in multiple locations, the first file found is used.
|
|
72
|
+
The local config search order is:
|
|
73
|
+
1. `edq-config.json` in the current directory.
|
|
74
|
+
2. A legacy file in the current directory (only if a legacy file is preconfigured).
|
|
75
|
+
3. `edq-config.json` in any ancestor directory on the path to root (including root itself).
|
|
76
|
+
|
|
77
|
+
#### CLI-Specified Config Files
|
|
78
|
+
|
|
79
|
+
CLI config files are options specified on the command line via a file.
|
|
80
|
+
These are useful for a common set of options you don’t need every time, such as login credentials for different user.
|
|
81
|
+
Any files passed via `--config-file` will be loaded in the order they appear on the command line.
|
|
82
|
+
Options from later files override options from previous files.
|
|
83
|
+
|
|
84
|
+
Below is an example of a CLI specified configuration paths:
|
|
85
|
+
```sh
|
|
86
|
+
python3 -m edq.cli.config.list --config-file ./edq-config.json --config-file ~/.secrets/edq-config.json
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
#### CLI Configuration
|
|
90
|
+
|
|
91
|
+
CLI configurations are options specified directly on the command line, these are useful for quick option overrides without editing config files.
|
|
92
|
+
Configuration options are passed to the command line by the `--config` flag in this format `<key>=<value>`.
|
|
93
|
+
The provided values overrides the values from configuration files.
|
|
94
|
+
Configuration options are structured as key value pairs and keys cannot contain the "=" character.
|
|
95
|
+
|
|
96
|
+
Below is an example of specifying a configuration option directly from the CLI:
|
|
97
|
+
```sh
|
|
98
|
+
python3 -m edq.cli.config.list --config user=alice --config pass=password123
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
#### CLI Config Options
|
|
102
|
+
|
|
103
|
+
The table below lists common configuration CLI options available for CLI tools using this library.
|
|
104
|
+
|
|
105
|
+
| CLI Option | Description |
|
|
106
|
+
| :-------------- | :---------- |
|
|
107
|
+
|`--config-global` | Override the global config file location. |
|
|
108
|
+
|`--config-file` | Load configuration options from a CLI specified file. |
|
|
109
|
+
| `--config` | Provide additional options to a CLI command. |
|
|
110
|
+
| `--help` | Display standard help text and the default global configuration file path for the current platform. |
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""
|
|
2
|
+
List the current configuration options.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
import edq.core.argparser
|
|
9
|
+
|
|
10
|
+
CONFIG_FIELD_SEPARATOR: str = "\t"
|
|
11
|
+
|
|
12
|
+
def run_cli(args: argparse.Namespace) -> int:
|
|
13
|
+
""" Run the CLI. """
|
|
14
|
+
|
|
15
|
+
rows = []
|
|
16
|
+
|
|
17
|
+
for (key, value) in args._config.items():
|
|
18
|
+
row = [key, str(value)]
|
|
19
|
+
if (args.show_origin):
|
|
20
|
+
config_source_obj = args._config_sources.get(key)
|
|
21
|
+
|
|
22
|
+
origin = config_source_obj.path
|
|
23
|
+
if (origin is None):
|
|
24
|
+
origin = config_source_obj.label
|
|
25
|
+
|
|
26
|
+
row.append(origin)
|
|
27
|
+
|
|
28
|
+
rows.append(CONFIG_FIELD_SEPARATOR.join(row))
|
|
29
|
+
|
|
30
|
+
rows.sort()
|
|
31
|
+
|
|
32
|
+
if (not args.skip_header):
|
|
33
|
+
header = ["Key", "Value"]
|
|
34
|
+
if (args.show_origin):
|
|
35
|
+
header.append("Origin")
|
|
36
|
+
|
|
37
|
+
rows.insert(0, (CONFIG_FIELD_SEPARATOR.join(header)))
|
|
38
|
+
|
|
39
|
+
print("\n".join(rows))
|
|
40
|
+
return 0
|
|
41
|
+
|
|
42
|
+
def main() -> int:
|
|
43
|
+
""" Get a parser, parse the args, and call run. """
|
|
44
|
+
|
|
45
|
+
return run_cli(_get_parser().parse_args())
|
|
46
|
+
|
|
47
|
+
def _get_parser() -> argparse.ArgumentParser:
|
|
48
|
+
""" Get a parser and add addition flags. """
|
|
49
|
+
|
|
50
|
+
parser = edq.core.argparser.get_default_parser(__doc__.strip())
|
|
51
|
+
modify_parser(parser)
|
|
52
|
+
|
|
53
|
+
return parser
|
|
54
|
+
|
|
55
|
+
def modify_parser(parser: argparse.ArgumentParser) -> None:
|
|
56
|
+
""" Add this CLI's flags to the given parser. """
|
|
57
|
+
|
|
58
|
+
parser.add_argument("--show-origin", dest = 'show_origin',
|
|
59
|
+
action = 'store_true',
|
|
60
|
+
help = "Display where each configuration's value was obtained from.",
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
parser.add_argument("--skip-header", dest = 'skip_header',
|
|
64
|
+
action = 'store_true',
|
|
65
|
+
help = 'Skip headers when displaying configs.',
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
if (__name__ == '__main__'):
|
|
69
|
+
sys.exit(main())
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# pylint: disable=invalid-name
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Start an HTTP test server that serves the specified HTTP exchanges.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
import edq.core.argparser
|
|
12
|
+
import edq.testing.httpserver
|
|
13
|
+
|
|
14
|
+
def run_cli(args: argparse.Namespace) -> int:
|
|
15
|
+
""" Run the CLI. """
|
|
16
|
+
|
|
17
|
+
match_options = {
|
|
18
|
+
'params_to_skip': args.ignore_params,
|
|
19
|
+
'headers_to_skip': args.ignore_headers,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
server = edq.testing.httpserver.HTTPTestServer(
|
|
23
|
+
port = args.port,
|
|
24
|
+
match_options = match_options,
|
|
25
|
+
verbose = True,
|
|
26
|
+
raise_on_404 = False,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
for path in args.paths:
|
|
30
|
+
path = os.path.abspath(path)
|
|
31
|
+
|
|
32
|
+
if (os.path.isfile(path)):
|
|
33
|
+
server.load_exchange(path)
|
|
34
|
+
else:
|
|
35
|
+
server.load_exchanges_dir(path)
|
|
36
|
+
|
|
37
|
+
server.start_and_wait()
|
|
38
|
+
|
|
39
|
+
return 0
|
|
40
|
+
|
|
41
|
+
def main() -> int:
|
|
42
|
+
""" Get a parser, parse the args, and call run. """
|
|
43
|
+
return run_cli(_get_parser().parse_args())
|
|
44
|
+
|
|
45
|
+
def _get_parser() -> argparse.ArgumentParser:
|
|
46
|
+
""" Get the parser. """
|
|
47
|
+
|
|
48
|
+
parser = edq.core.argparser.get_default_parser(__doc__.strip(),
|
|
49
|
+
include_net = True,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
parser.add_argument('paths', metavar = 'PATH',
|
|
53
|
+
type = str, nargs = '+',
|
|
54
|
+
help = 'Path to exchange files or dirs (which will be recursively searched for all exchange files).')
|
|
55
|
+
|
|
56
|
+
parser.add_argument('--port', dest = 'port',
|
|
57
|
+
action = 'store', type = int, default = None,
|
|
58
|
+
help = 'The port to run this test server on. If not set, a random open port will be chosen.')
|
|
59
|
+
|
|
60
|
+
parser.add_argument('--ignore-param', dest = 'ignore_params',
|
|
61
|
+
action = 'append', type = str, default = [],
|
|
62
|
+
help = 'Ignore this parameter during exchange matching.')
|
|
63
|
+
|
|
64
|
+
parser.add_argument('--ignore-header', dest = 'ignore_headers',
|
|
65
|
+
action = 'append', type = str, default = [],
|
|
66
|
+
help = 'Ignore this header during exchange matching.')
|
|
67
|
+
|
|
68
|
+
return parser
|
|
69
|
+
|
|
70
|
+
if (__name__ == '__main__'):
|
|
71
|
+
sys.exit(main())
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# pylint: disable=invalid-name
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Send an HTTP exchange to the target server.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
import edq.core.argparser
|
|
11
|
+
import edq.util.net
|
|
12
|
+
|
|
13
|
+
def run_cli(args: argparse.Namespace) -> int:
|
|
14
|
+
""" Run the CLI. """
|
|
15
|
+
|
|
16
|
+
exchange = edq.util.net.HTTPExchange.from_path(args.path)
|
|
17
|
+
_, body = exchange.make_request(args.server)
|
|
18
|
+
|
|
19
|
+
print(body)
|
|
20
|
+
|
|
21
|
+
return 0
|
|
22
|
+
|
|
23
|
+
def main() -> int:
|
|
24
|
+
""" Get a parser, parse the args, and call run. """
|
|
25
|
+
return run_cli(_get_parser().parse_args())
|
|
26
|
+
|
|
27
|
+
def _get_parser() -> argparse.ArgumentParser:
|
|
28
|
+
""" Get the parser. """
|
|
29
|
+
|
|
30
|
+
parser = edq.core.argparser.get_default_parser(__doc__.strip(),
|
|
31
|
+
include_net = True,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
parser.add_argument('server', metavar = 'SERVER',
|
|
35
|
+
action = 'store', type = str,
|
|
36
|
+
help = 'Server to send the exahnge to.')
|
|
37
|
+
|
|
38
|
+
parser.add_argument('path', metavar = 'PATH',
|
|
39
|
+
action = 'store', type = str,
|
|
40
|
+
help = 'Path to the exchange file.')
|
|
41
|
+
|
|
42
|
+
return parser
|
|
43
|
+
|
|
44
|
+
if (__name__ == '__main__'):
|
|
45
|
+
sys.exit(main())
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# pylint: disable=invalid-name
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Verify that exchanges sent to a given server have the same response.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
import edq.core.argparser
|
|
11
|
+
import edq.procedure.verify_exchanges
|
|
12
|
+
|
|
13
|
+
def run_cli(args: argparse.Namespace) -> int:
|
|
14
|
+
""" Run the CLI. """
|
|
15
|
+
|
|
16
|
+
return edq.procedure.verify_exchanges.run(args.paths, args.server)
|
|
17
|
+
|
|
18
|
+
def main() -> int:
|
|
19
|
+
""" Get a parser, parse the args, and call run. """
|
|
20
|
+
return run_cli(_get_parser().parse_args())
|
|
21
|
+
|
|
22
|
+
def _get_parser() -> argparse.ArgumentParser:
|
|
23
|
+
""" Get the parser. """
|
|
24
|
+
|
|
25
|
+
parser = edq.core.argparser.get_default_parser(__doc__.strip())
|
|
26
|
+
|
|
27
|
+
parser.add_argument('server', metavar = 'SERVER',
|
|
28
|
+
action = 'store', type = str, default = None,
|
|
29
|
+
help = 'Address of the server to send exchanges to.')
|
|
30
|
+
|
|
31
|
+
parser.add_argument('paths', metavar = 'PATH',
|
|
32
|
+
type = str, nargs = '+',
|
|
33
|
+
help = 'Path to exchange files or dirs (which will be recursively searched for all exchange files).')
|
|
34
|
+
|
|
35
|
+
return parser
|
|
36
|
+
|
|
37
|
+
if (__name__ == '__main__'):
|
|
38
|
+
sys.exit(main())
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# pylint: disable=invalid-name
|
|
2
2
|
|
|
3
3
|
"""
|
|
4
4
|
Run specified CLI test files.
|
|
@@ -10,15 +10,18 @@ import unittest
|
|
|
10
10
|
|
|
11
11
|
import edq.core.argparser
|
|
12
12
|
import edq.testing.cli
|
|
13
|
-
import edq.testing.
|
|
13
|
+
import edq.testing.unittest
|
|
14
|
+
|
|
15
|
+
class CLITest(edq.testing.unittest.BaseTest):
|
|
16
|
+
""" Test CLI invocations. """
|
|
14
17
|
|
|
15
18
|
def run_cli(args: argparse.Namespace) -> int:
|
|
16
19
|
""" Run the CLI. """
|
|
17
20
|
|
|
18
|
-
edq.testing.cli.add_test_paths(
|
|
21
|
+
edq.testing.cli.add_test_paths(CLITest, args.data_dir, args.paths)
|
|
19
22
|
|
|
20
23
|
runner = unittest.TextTestRunner(verbosity = 2)
|
|
21
|
-
tests = unittest.defaultTestLoader.loadTestsFromTestCase(
|
|
24
|
+
tests = unittest.defaultTestLoader.loadTestsFromTestCase(CLITest)
|
|
22
25
|
results = runner.run(tests)
|
|
23
26
|
|
|
24
27
|
return len(results.errors) + len(results.failures)
|
|
@@ -27,7 +30,7 @@ def main() -> int:
|
|
|
27
30
|
""" Get a parser, parse the args, and call run. """
|
|
28
31
|
return run_cli(_get_parser().parse_args())
|
|
29
32
|
|
|
30
|
-
def _get_parser() ->
|
|
33
|
+
def _get_parser() -> argparse.ArgumentParser:
|
|
31
34
|
""" Get the parser. """
|
|
32
35
|
|
|
33
36
|
parser = edq.core.argparser.get_default_parser(__doc__.strip())
|
|
@@ -16,9 +16,10 @@ def run_cli(args: argparse.Namespace) -> int:
|
|
|
16
16
|
|
|
17
17
|
def main() -> int:
|
|
18
18
|
""" Get a parser, parse the args, and call run. """
|
|
19
|
+
|
|
19
20
|
return run_cli(_get_parser().parse_args())
|
|
20
21
|
|
|
21
|
-
def _get_parser() ->
|
|
22
|
+
def _get_parser() -> argparse.ArgumentParser:
|
|
22
23
|
""" Get the parser. """
|
|
23
24
|
|
|
24
25
|
return edq.core.argparser.get_default_parser(__doc__.strip())
|
|
@@ -8,9 +8,12 @@ while post-callbacks are generally intended to act on the results of parsing.
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
import argparse
|
|
11
|
+
import functools
|
|
11
12
|
import typing
|
|
12
13
|
|
|
14
|
+
import edq.core.config
|
|
13
15
|
import edq.core.log
|
|
16
|
+
import edq.util.net
|
|
14
17
|
|
|
15
18
|
@typing.runtime_checkable
|
|
16
19
|
class PreParseFunction(typing.Protocol):
|
|
@@ -102,11 +105,33 @@ class Parser(argparse.ArgumentParser):
|
|
|
102
105
|
|
|
103
106
|
return parsed_args # type: ignore[no-any-return]
|
|
104
107
|
|
|
105
|
-
def get_default_parser(description: str
|
|
106
|
-
|
|
108
|
+
def get_default_parser(description: str,
|
|
109
|
+
version: typing.Union[str, None] = None,
|
|
110
|
+
include_log: bool = True,
|
|
111
|
+
include_config: bool = True,
|
|
112
|
+
include_net: bool = False,
|
|
113
|
+
config_options: typing.Union[typing.Dict[str, typing.Any], None] = None,
|
|
114
|
+
) -> Parser:
|
|
115
|
+
""" Get a parser with the requested default callbacks already attached. """
|
|
116
|
+
|
|
117
|
+
if (config_options is None):
|
|
118
|
+
config_options = {}
|
|
107
119
|
|
|
108
120
|
parser = Parser(description = description)
|
|
109
121
|
|
|
110
|
-
|
|
122
|
+
if (version is not None):
|
|
123
|
+
parser.add_argument('--version',
|
|
124
|
+
action = 'version', version = version)
|
|
125
|
+
|
|
126
|
+
if (include_log):
|
|
127
|
+
parser.register_callbacks('log', edq.core.log.set_cli_args, edq.core.log.init_from_args)
|
|
128
|
+
|
|
129
|
+
if (include_config):
|
|
130
|
+
config_pre_func = functools.partial(edq.core.config.set_cli_args, **config_options)
|
|
131
|
+
config_post_func = functools.partial(edq.core.config.load_config_into_args, **config_options)
|
|
132
|
+
parser.register_callbacks('config', config_pre_func, config_post_func)
|
|
133
|
+
|
|
134
|
+
if (include_net):
|
|
135
|
+
parser.register_callbacks('net', edq.util.net.set_cli_args, edq.util.net.init_from_args)
|
|
111
136
|
|
|
112
137
|
return parser
|