mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-12 02:21:29 +08:00
Merge pull request #943 from httprunner/v3
## 3.1.0 (2020-06-21) **Added** - feat: integrate [locust](https://locust.io/) v1.0 **Changed** - change: make converted referenced pytest files always relative to ProjectRootDir - change: log function details when call function failed - change: do not raise error if failed to get client/server address info
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -11,7 +11,6 @@ dist/*
|
||||
.python-version
|
||||
logs
|
||||
.coverage
|
||||
locustfile.py
|
||||
site/
|
||||
reports
|
||||
.venv
|
||||
|
||||
@@ -42,7 +42,7 @@ Thank you to all our sponsors! ✨🍰✨ ([become a sponsor](docs/sponsors.md))
|
||||
|
||||
> [霍格沃兹测试学院](https://ceshiren.com/) 是业界领先的测试开发技术高端教育品牌,隶属于测吧(北京)科技有限公司。学院课程均由 BAT 一线测试大咖执教,提供实战驱动的接口自动化测试、移动自动化测试、性能测试、持续集成与 DevOps 等技术培训,以及测试开发优秀人才内推服务。[点击学习!](https://ke.qq.com/course/254956?flowToken=1014690)
|
||||
|
||||
[霍格沃兹测试学院](https://ceshiren.com/) 是 HttpRunner 的首家金牌赞助商。
|
||||
霍格沃兹测试学院是 HttpRunner 的首家金牌赞助商。
|
||||
|
||||
### 开源服务赞助商(Open Source Sponsor)
|
||||
|
||||
|
||||
@@ -1,5 +1,22 @@
|
||||
# Release History
|
||||
|
||||
## 3.1.0 (2020-06-21)
|
||||
|
||||
**Added**
|
||||
|
||||
- feat: integrate [locust](https://locust.io/) v1.0
|
||||
|
||||
**Changed**
|
||||
|
||||
- change: make converted referenced pytest files always relative to ProjectRootDir
|
||||
- change: log function details when call function failed
|
||||
- change: do not raise error if failed to get client/server address info
|
||||
|
||||
**Fixed**
|
||||
|
||||
- fix: path handling error when har2case har file and cwd != ProjectRootDir
|
||||
- fix: missing list type for request body
|
||||
|
||||
## 3.0.13 (2020-06-17)
|
||||
|
||||
**Added**
|
||||
|
||||
@@ -24,18 +24,19 @@ $ pip3 install -U git+https://github.com/httprunner/httprunner.git@master
|
||||
|
||||
## Check Installation
|
||||
|
||||
When HttpRunner is installed, 4 commands will be added in your system.
|
||||
When HttpRunner is installed, 5 commands will be added in your system.
|
||||
|
||||
- `httprunner`: main command, used for all functions
|
||||
- `hrun`: alias for `httprunner run`, used to run YAML/JSON/pytest testcases
|
||||
- `hmake`: alias for `httprunner make`, used to convert YAML/JSON testcases to pytest files
|
||||
- `har2case`: alias for `httprunner har2case`, used to convert HAR to YAML/JSON testcases
|
||||
- `locusts`: used to run load test with [locust][locust]
|
||||
|
||||
To see `HttpRunner` version:
|
||||
|
||||
```text
|
||||
$ httprunner -V # hrun -V
|
||||
3.0.10
|
||||
3.1.0
|
||||
```
|
||||
|
||||
To see available options, run:
|
||||
@@ -60,5 +61,8 @@ optional arguments:
|
||||
-V, --version show version
|
||||
```
|
||||
|
||||
> Notice: `locusts` is an individual command, for the reason to monkey patch ssl at beginning to avoid RecursionError when running locust.
|
||||
|
||||
[PyPI]: https://pypi.python.org/pypi
|
||||
[github-actions]: https://github.com/httprunner/httprunner/actions
|
||||
[github-actions]: https://github.com/httprunner/httprunner/actions
|
||||
[locust]: http://locust.io/
|
||||
|
||||
168
docs/user/run_loadtest.md
Normal file
168
docs/user/run_loadtest.md
Normal file
@@ -0,0 +1,168 @@
|
||||
# Run load test
|
||||
|
||||
> Integrated since HttpRunner 3.1.0
|
||||
|
||||
With reuse of [`Locust`][Locust], you can run load test without extra work.
|
||||
|
||||
```text
|
||||
$ locusts -V
|
||||
locust 1.0.3
|
||||
```
|
||||
|
||||
For full usage, you can run `locusts -h` to see help, and you will find that it is the same with `locust -h`.
|
||||
|
||||
The only difference is the `-f/--locustfile` argument. When you specify `-f` with a YAML/JSON testcase file, it will convert to pytest first and then run load test with HttpRunner's builtin locustfile(httprunner/ext/locust/locustfile.py).
|
||||
|
||||
```text
|
||||
$ locusts -f examples/postman_echo/request_methods/request_with_variables.yml
|
||||
2020-06-18 18:14:29.877 | INFO | httprunner.make:make_testcase:317 - start to make testcase: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/examples/postman_echo/request_methods/request_with_variables.yml
|
||||
2020-06-18 18:14:29.878 | INFO | httprunner.make:make_testcase:390 - generated testcase: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/examples/postman_echo/request_methods/request_with_variables_test.py
|
||||
2020-06-18 18:14:29.878 | INFO | httprunner.make:format_pytest_with_black:154 - format pytest cases with black ...
|
||||
reformatted /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/examples/postman_echo/request_methods/request_with_variables_test.py
|
||||
All done! ✨ 🍰 ✨
|
||||
1 file reformatted, 1 file left unchanged.
|
||||
[2020-06-18 18:14:30,241] LeodeMacBook-Pro.local/INFO/locust.main: Starting web interface at http://:8089
|
||||
[2020-06-18 18:14:30,249] LeodeMacBook-Pro.local/INFO/locust.main: Starting Locust 1.0.3
|
||||
```
|
||||
|
||||
In this case, you can reuse all features of [`Locust`][Locust].
|
||||
|
||||
```text
|
||||
$ locusts -h
|
||||
Usage: locust [OPTIONS] [UserClass ...]
|
||||
|
||||
Common options:
|
||||
-h, --help show this help message and exit
|
||||
-f LOCUSTFILE, --locustfile LOCUSTFILE
|
||||
Python module file to import, e.g. '../other.py'.
|
||||
Default: locustfile
|
||||
--config CONFIG Config file path
|
||||
-H HOST, --host HOST Host to load test in the following format:
|
||||
http://10.21.32.33
|
||||
-u NUM_USERS, --users NUM_USERS
|
||||
Number of concurrent Locust users. Only used together
|
||||
with --headless
|
||||
-r HATCH_RATE, --hatch-rate HATCH_RATE
|
||||
The rate per second in which users are spawned. Only
|
||||
used together with --headless
|
||||
-t RUN_TIME, --run-time RUN_TIME
|
||||
Stop after the specified amount of time, e.g. (300s,
|
||||
20m, 3h, 1h30m, etc.). Only used together with
|
||||
--headless
|
||||
-l, --list Show list of possible User classes and exit
|
||||
|
||||
Web UI options:
|
||||
--web-host WEB_HOST Host to bind the web interface to. Defaults to '*'
|
||||
(all interfaces)
|
||||
--web-port WEB_PORT, -P WEB_PORT
|
||||
Port on which to run web host
|
||||
--headless Disable the web interface, and instead start the load
|
||||
test immediately. Requires -u and -t to be specified.
|
||||
--web-auth WEB_AUTH Turn on Basic Auth for the web interface. Should be
|
||||
supplied in the following format: username:password
|
||||
--tls-cert TLS_CERT Optional path to TLS certificate to use to serve over
|
||||
HTTPS
|
||||
--tls-key TLS_KEY Optional path to TLS private key to use to serve over
|
||||
HTTPS
|
||||
|
||||
Master options:
|
||||
Options for running a Locust Master node when running Locust distributed. A Master node need Worker nodes that connect to it before it can run load tests.
|
||||
|
||||
--master Set locust to run in distributed mode with this
|
||||
process as master
|
||||
--master-bind-host MASTER_BIND_HOST
|
||||
Interfaces (hostname, ip) that locust master should
|
||||
bind to. Only used when running with --master.
|
||||
Defaults to * (all available interfaces).
|
||||
--master-bind-port MASTER_BIND_PORT
|
||||
Port that locust master should bind to. Only used when
|
||||
running with --master. Defaults to 5557.
|
||||
--expect-workers EXPECT_WORKERS
|
||||
How many workers master should expect to connect
|
||||
before starting the test (only when --headless used).
|
||||
|
||||
Worker options:
|
||||
|
||||
Options for running a Locust Worker node when running Locust distributed.
|
||||
Only the LOCUSTFILE (-f option) need to be specified when starting a Worker, since other options such as -u, -r, -t are specified on the Master node.
|
||||
|
||||
--worker Set locust to run in distributed mode with this
|
||||
process as worker
|
||||
--master-host MASTER_HOST
|
||||
Host or IP address of locust master for distributed
|
||||
load testing. Only used when running with --worker.
|
||||
Defaults to 127.0.0.1.
|
||||
--master-port MASTER_PORT
|
||||
The port to connect to that is used by the locust
|
||||
master for distributed load testing. Only used when
|
||||
running with --worker. Defaults to 5557.
|
||||
|
||||
Tag options:
|
||||
Locust tasks can be tagged using the @tag decorator. These options let specify which tasks to include or exclude during a test.
|
||||
|
||||
-T [TAG [TAG ...]], --tags [TAG [TAG ...]]
|
||||
List of tags to include in the test, so only tasks
|
||||
with any matching tags will be executed
|
||||
-E [TAG [TAG ...]], --exclude-tags [TAG [TAG ...]]
|
||||
List of tags to exclude from the test, so only tasks
|
||||
with no matching tags will be executed
|
||||
|
||||
Request statistics options:
|
||||
--csv CSV_PREFIX Store current request stats to files in CSV format.
|
||||
Setting this option will generate three files:
|
||||
[CSV_PREFIX]_stats.csv, [CSV_PREFIX]_stats_history.csv
|
||||
and [CSV_PREFIX]_failures.csv
|
||||
--csv-full-history Store each stats entry in CSV format to
|
||||
_stats_history.csv file
|
||||
--print-stats Print stats in the console
|
||||
--only-summary Only print the summary stats
|
||||
--reset-stats Reset statistics once hatching has been completed.
|
||||
Should be set on both master and workers when running
|
||||
in distributed mode
|
||||
|
||||
Logging options:
|
||||
--skip-log-setup Disable Locust's logging setup. Instead, the
|
||||
configuration is provided by the Locust test or Python
|
||||
defaults.
|
||||
--loglevel LOGLEVEL, -L LOGLEVEL
|
||||
Choose between DEBUG/INFO/WARNING/ERROR/CRITICAL.
|
||||
Default is INFO.
|
||||
--logfile LOGFILE Path to log file. If not set, log will go to
|
||||
stdout/stderr
|
||||
|
||||
Step load options:
|
||||
--step-load Enable Step Load mode to monitor how performance
|
||||
metrics varies when user load increases. Requires
|
||||
--step-users and --step-time to be specified.
|
||||
--step-users STEP_USERS
|
||||
User count to increase by step in Step Load mode. Only
|
||||
used together with --step-load
|
||||
--step-time STEP_TIME
|
||||
Step duration in Step Load mode, e.g. (300s, 20m, 3h,
|
||||
1h30m, etc.). Only used together with --step-load
|
||||
|
||||
Other options:
|
||||
--show-task-ratio Print table of the User classes' task execution ratio
|
||||
--show-task-ratio-json
|
||||
Print json data of the User classes' task execution
|
||||
ratio
|
||||
--version, -V Show program's version number and exit
|
||||
--exit-code-on-error EXIT_CODE_ON_ERROR
|
||||
Sets the process exit code to use when a test result
|
||||
contain any failure or error
|
||||
-s STOP_TIMEOUT, --stop-timeout STOP_TIMEOUT
|
||||
Number of seconds to wait for a simulated user to
|
||||
complete any executing task before exiting. Default is
|
||||
to terminate immediately. This parameter only needs to
|
||||
be specified for the master process when running
|
||||
Locust distributed.
|
||||
|
||||
User classes:
|
||||
UserClass Optionally specify which User classes that should be
|
||||
used (available User classes can be listed with -l or
|
||||
--list)
|
||||
```
|
||||
|
||||
Enjoy!
|
||||
|
||||
[Locust]: http://locust.io/
|
||||
@@ -418,6 +418,29 @@ timestamp_six_digits = str(int(time.time() * 1000))[-6:])
|
||||
|
||||
In other words, all requests in one testcase will have the same `HRUN-Request-ID` prefix, and each request will have a unique `HRUN-Request-ID` suffix.
|
||||
|
||||
## Client & Server IP:PORT
|
||||
|
||||
Sometimes, logging remote server IP and port can be great helpful for trouble shooting, especially when there are multiple servers and we want to checkout which one returns error.
|
||||
|
||||
Since version `3.0.13`, HttpRunner will log client & server IP:Port in debug level.
|
||||
|
||||
```text
|
||||
2020-06-18 11:32:38.366 | INFO | httprunner.runner:__run_step:278 - run step begin: post raw text >>>>>>
|
||||
2020-06-18 11:32:38.687 | DEBUG | httprunner.client:request:187 - client IP: 10.90.205.63, Port: 62802
|
||||
2020-06-18 11:32:38.687 | DEBUG | httprunner.client:request:195 - server IP: 34.233.204.163, Port: 443
|
||||
```
|
||||
|
||||
as well as testcase summary.
|
||||
|
||||
```text
|
||||
"address": {
|
||||
"client_ip": "10.90.205.63",
|
||||
"client_port": 62802,
|
||||
"server_ip": "34.233.204.163",
|
||||
"server_port": 443
|
||||
},
|
||||
```
|
||||
|
||||
## arguments for v2.x compatibility
|
||||
|
||||
Besides all the arguments of `pytest`, `hrun` also has several other arguments to keep compatibility with HttpRunner v2.x.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# NOTE: Generated By HttpRunner v3.0.13
|
||||
# FROM: examples/httpbin/basic.yml
|
||||
# NOTE: Generated By HttpRunner v3.1.0
|
||||
# FROM: basic.yml
|
||||
|
||||
from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# NOTE: Generated By HttpRunner v3.0.13
|
||||
# FROM: examples/httpbin/hooks.yml
|
||||
# NOTE: Generated By HttpRunner v3.1.0
|
||||
# FROM: hooks.yml
|
||||
|
||||
from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# NOTE: Generated By HttpRunner v3.0.13
|
||||
# FROM: examples/httpbin/load_image.yml
|
||||
# NOTE: Generated By HttpRunner v3.1.0
|
||||
# FROM: load_image.yml
|
||||
|
||||
from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# NOTE: Generated By HttpRunner v3.0.13
|
||||
# FROM: examples/httpbin/upload.yml
|
||||
# NOTE: Generated By HttpRunner v3.1.0
|
||||
# FROM: upload.yml
|
||||
|
||||
from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# NOTE: Generated By HttpRunner v3.0.13
|
||||
# FROM: examples/httpbin/validate.yml
|
||||
# NOTE: Generated By HttpRunner v3.1.0
|
||||
# FROM: validate.yml
|
||||
|
||||
from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ testcases:
|
||||
-
|
||||
name: request with functions
|
||||
testcase: request_methods/request_with_functions.yml
|
||||
weight: 2
|
||||
variables:
|
||||
foo1: testcase_ref_bar11
|
||||
expect_foo1: testcase_ref_bar11
|
||||
@@ -13,6 +14,7 @@ testcases:
|
||||
-
|
||||
name: request with referenced testcase
|
||||
testcase: request_methods/request_with_testcase_reference.yml
|
||||
weight: 3
|
||||
variables:
|
||||
foo1: testcase_ref_bar12
|
||||
expect_foo1: testcase_ref_bar12
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# NOTE: Generated By HttpRunner v3.0.13
|
||||
# FROM: examples/postman_echo/request_methods/request_with_functions.yml
|
||||
# NOTE: Generated By HttpRunner v3.1.0
|
||||
# FROM: request_methods/request_with_functions.yml
|
||||
|
||||
from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase
|
||||
|
||||
@@ -18,6 +18,7 @@ class TestCaseRequestWithFunctions(HttpRunner):
|
||||
.base_url("https://postman-echo.com")
|
||||
.verify(False)
|
||||
.export(*["foo3"])
|
||||
.locust_weight(2)
|
||||
)
|
||||
|
||||
teststeps = [
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# NOTE: Generated By HttpRunner v3.0.13
|
||||
# FROM: examples/postman_echo/request_methods/request_with_testcase_reference.yml
|
||||
# NOTE: Generated By HttpRunner v3.1.0
|
||||
# FROM: request_methods/request_with_testcase_reference.yml
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, os.getcwd())
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase
|
||||
|
||||
from examples.postman_echo.request_methods.request_with_functions_test import (
|
||||
from request_methods.request_with_functions_test import (
|
||||
TestCaseRequestWithFunctions as RequestWithFunctions,
|
||||
)
|
||||
|
||||
@@ -26,6 +26,7 @@ class TestCaseRequestWithTestcaseReference(HttpRunner):
|
||||
)
|
||||
.base_url("https://postman-echo.com")
|
||||
.verify(False)
|
||||
.locust_weight(3)
|
||||
)
|
||||
|
||||
teststeps = [
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# NOTE: Generated By HttpRunner v3.0.13
|
||||
# FROM: examples/postman_echo/request_methods/hardcode.yml
|
||||
# NOTE: Generated By HttpRunner v3.1.0
|
||||
# FROM: request_methods/hardcode.yml
|
||||
|
||||
from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ config:
|
||||
expect_foo2: config_bar2
|
||||
base_url: "https://postman-echo.com"
|
||||
verify: False
|
||||
weight: 2
|
||||
export: ["foo3"]
|
||||
|
||||
teststeps:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# NOTE: Generated By HttpRunner v3.0.13
|
||||
# FROM: examples/postman_echo/request_methods/request_with_functions.yml
|
||||
# NOTE: Generated By HttpRunner v3.1.0
|
||||
# FROM: request_methods/request_with_functions.yml
|
||||
|
||||
from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase
|
||||
|
||||
@@ -18,6 +18,7 @@ class TestCaseRequestWithFunctions(HttpRunner):
|
||||
.base_url("https://postman-echo.com")
|
||||
.verify(False)
|
||||
.export(*["foo3"])
|
||||
.locust_weight(2)
|
||||
)
|
||||
|
||||
teststeps = [
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# NOTE: Generated By HttpRunner v3.0.13
|
||||
# FROM: examples/postman_echo/request_methods/request_with_testcase_reference.yml
|
||||
# NOTE: Generated By HttpRunner v3.1.0
|
||||
# FROM: request_methods/request_with_testcase_reference.yml
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, os.getcwd())
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase
|
||||
|
||||
from examples.postman_echo.request_methods.request_with_functions_test import (
|
||||
from request_methods.request_with_functions_test import (
|
||||
TestCaseRequestWithFunctions as RequestWithFunctions,
|
||||
)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# NOTE: Generated By HttpRunner v3.0.13
|
||||
# FROM: examples/postman_echo/request_methods/request_with_variables.yml
|
||||
# NOTE: Generated By HttpRunner v3.1.0
|
||||
# FROM: request_methods/request_with_variables.yml
|
||||
|
||||
from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# NOTE: Generated By HttpRunner v3.0.13
|
||||
# FROM: examples/postman_echo/request_methods/validate_with_functions.yml
|
||||
# NOTE: Generated By HttpRunner v3.1.0
|
||||
# FROM: request_methods/validate_with_functions.yml
|
||||
|
||||
from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# NOTE: Generated By HttpRunner v3.0.13
|
||||
# FROM: examples/postman_echo/request_methods/validate_with_variables.yml
|
||||
# NOTE: Generated By HttpRunner v3.1.0
|
||||
# FROM: request_methods/validate_with_variables.yml
|
||||
|
||||
from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
__version__ = "3.0.13"
|
||||
__version__ = "3.1.0"
|
||||
__description__ = "One-stop solution for HTTP(S) testing."
|
||||
|
||||
# import firstly for monkey patch if needed
|
||||
from httprunner.ext.locust import main_locusts
|
||||
from httprunner.runner import HttpRunner
|
||||
from httprunner.testcase import Config, Step, RunRequest, RunTestCase
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ from requests.exceptions import (
|
||||
RequestException,
|
||||
)
|
||||
|
||||
from httprunner.exceptions import NetworkFailure
|
||||
from httprunner.models import RequestData, ResponseData
|
||||
from httprunner.models import SessionData, ReqRespData
|
||||
from httprunner.utils import lower_dict_keys, omit_long_data
|
||||
@@ -186,7 +185,7 @@ class HttpSession(requests.Session):
|
||||
self.data.address.client_port = client_port
|
||||
logger.debug(f"client IP: {client_ip}, Port: {client_port}")
|
||||
except AttributeError as ex:
|
||||
raise NetworkFailure(f"failed to get client address info: {ex}")
|
||||
logger.warning(f"failed to get client address info: {ex}")
|
||||
|
||||
try:
|
||||
server_ip, server_port = response.raw.connection.sock.getpeername()
|
||||
@@ -194,7 +193,7 @@ class HttpSession(requests.Session):
|
||||
self.data.address.server_port = server_port
|
||||
logger.debug(f"server IP: {server_ip}, Port: {server_port}")
|
||||
except AttributeError as ex:
|
||||
raise NetworkFailure(f"failed to get server address info: {ex}")
|
||||
logger.warning(f"failed to get server address info: {ex}")
|
||||
|
||||
# get length of the response content
|
||||
content_size = int(dict(response.headers).get("content-length") or 0)
|
||||
|
||||
@@ -8,9 +8,9 @@ from typing import List, Dict, Text, Union, Any
|
||||
from loguru import logger
|
||||
|
||||
from httprunner import exceptions
|
||||
from httprunner.loader import load_project_meta
|
||||
from httprunner.loader import load_project_meta, convert_relative_project_root_dir
|
||||
from httprunner.parser import parse_data
|
||||
from httprunner.utils import sort_dict_by_custom_order, ensure_file_path_valid
|
||||
from httprunner.utils import sort_dict_by_custom_order
|
||||
|
||||
|
||||
def convert_variables(
|
||||
@@ -46,7 +46,7 @@ def convert_variables(
|
||||
)
|
||||
|
||||
|
||||
def convert_jmespath(raw: Text) -> Text:
|
||||
def _convert_jmespath(raw: Text) -> Text:
|
||||
if not isinstance(raw, Text):
|
||||
raise exceptions.TestCaseFormatError(f"Invalid jmespath extractor: {raw}")
|
||||
|
||||
@@ -78,7 +78,7 @@ def convert_jmespath(raw: Text) -> Text:
|
||||
return ".".join(raw_list)
|
||||
|
||||
|
||||
def convert_extractors(extractors: Union[List, Dict]) -> Dict:
|
||||
def _convert_extractors(extractors: Union[List, Dict]) -> Dict:
|
||||
""" convert extract list(v2) to dict(v3)
|
||||
|
||||
Args:
|
||||
@@ -106,26 +106,26 @@ def convert_extractors(extractors: Union[List, Dict]) -> Dict:
|
||||
sys.exit(1)
|
||||
|
||||
for k, v in v3_extractors.items():
|
||||
v3_extractors[k] = convert_jmespath(v)
|
||||
v3_extractors[k] = _convert_jmespath(v)
|
||||
|
||||
return v3_extractors
|
||||
|
||||
|
||||
def convert_validators(validators: List) -> List:
|
||||
def _convert_validators(validators: List) -> List:
|
||||
for v in validators:
|
||||
if "check" in v and "expect" in v:
|
||||
# format1: {"check": "content.abc", "assert": "eq", "expect": 201}
|
||||
v["check"] = convert_jmespath(v["check"])
|
||||
v["check"] = _convert_jmespath(v["check"])
|
||||
|
||||
elif len(v) == 1:
|
||||
# format2: {'eq': ['status_code', 201]}
|
||||
comparator = list(v.keys())[0]
|
||||
v[comparator][0] = convert_jmespath(v[comparator][0])
|
||||
v[comparator][0] = _convert_jmespath(v[comparator][0])
|
||||
|
||||
return validators
|
||||
|
||||
|
||||
def sort_request_by_custom_order(request: Dict) -> Dict:
|
||||
def _sort_request_by_custom_order(request: Dict) -> Dict:
|
||||
custom_order = [
|
||||
"method",
|
||||
"url",
|
||||
@@ -146,7 +146,7 @@ def sort_request_by_custom_order(request: Dict) -> Dict:
|
||||
return sort_dict_by_custom_order(request, custom_order)
|
||||
|
||||
|
||||
def sort_step_by_custom_order(step: Dict) -> Dict:
|
||||
def _sort_step_by_custom_order(step: Dict) -> Dict:
|
||||
custom_order = [
|
||||
"name",
|
||||
"variables",
|
||||
@@ -161,7 +161,7 @@ def sort_step_by_custom_order(step: Dict) -> Dict:
|
||||
return sort_dict_by_custom_order(step, custom_order)
|
||||
|
||||
|
||||
def ensure_step_attachment(step: Dict) -> Dict:
|
||||
def _ensure_step_attachment(step: Dict) -> Dict:
|
||||
test_dict = {
|
||||
"name": step["name"],
|
||||
}
|
||||
@@ -176,13 +176,13 @@ def ensure_step_attachment(step: Dict) -> Dict:
|
||||
test_dict["teardown_hooks"] = step["teardown_hooks"]
|
||||
|
||||
if "extract" in step:
|
||||
test_dict["extract"] = convert_extractors(step["extract"])
|
||||
test_dict["extract"] = _convert_extractors(step["extract"])
|
||||
|
||||
if "export" in step:
|
||||
test_dict["export"] = step["export"]
|
||||
|
||||
if "validate" in step:
|
||||
test_dict["validate"] = convert_validators(step["validate"])
|
||||
test_dict["validate"] = _convert_validators(step["validate"])
|
||||
|
||||
if "validate_script" in step:
|
||||
test_dict["validate_script"] = step["validate_script"]
|
||||
@@ -191,12 +191,14 @@ def ensure_step_attachment(step: Dict) -> Dict:
|
||||
|
||||
|
||||
def ensure_testcase_v3_api(api_content: Dict) -> Dict:
|
||||
teststep = {
|
||||
"request": api_content["request"],
|
||||
}
|
||||
teststep.update(ensure_step_attachment(api_content))
|
||||
logger.info("convert api in v2 to testcase format v3")
|
||||
|
||||
teststep = sort_step_by_custom_order(teststep)
|
||||
teststep = {
|
||||
"request": _sort_request_by_custom_order(api_content["request"]),
|
||||
}
|
||||
teststep.update(_ensure_step_attachment(api_content))
|
||||
|
||||
teststep = _sort_step_by_custom_order(teststep)
|
||||
|
||||
return {
|
||||
"config": {"name": api_content["name"]},
|
||||
@@ -205,13 +207,25 @@ def ensure_testcase_v3_api(api_content: Dict) -> Dict:
|
||||
|
||||
|
||||
def ensure_testcase_v3(test_content: Dict) -> Dict:
|
||||
logger.info("ensure compatibility with testcase format v2")
|
||||
|
||||
v3_content = {"config": test_content["config"], "teststeps": []}
|
||||
|
||||
if "teststeps" not in test_content:
|
||||
logger.error(f"Miss teststeps: {test_content}")
|
||||
sys.exit(1)
|
||||
|
||||
if not isinstance(test_content["teststeps"], list):
|
||||
logger.error(
|
||||
f'teststeps should be list type, got {type(test_content["teststeps"])}: {test_content["teststeps"]}'
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
for step in test_content["teststeps"]:
|
||||
teststep = {}
|
||||
|
||||
if "request" in step:
|
||||
teststep["request"] = step.pop("request")
|
||||
teststep["request"] = _sort_request_by_custom_order(step.pop("request"))
|
||||
elif "api" in step:
|
||||
teststep["testcase"] = step.pop("api")
|
||||
elif "testcase" in step:
|
||||
@@ -219,9 +233,9 @@ def ensure_testcase_v3(test_content: Dict) -> Dict:
|
||||
else:
|
||||
raise exceptions.TestCaseFormatError(f"Invalid teststep: {step}")
|
||||
|
||||
teststep.update(ensure_step_attachment(step))
|
||||
teststep.update(_ensure_step_attachment(step))
|
||||
|
||||
teststep = sort_step_by_custom_order(teststep)
|
||||
teststep = _sort_step_by_custom_order(teststep)
|
||||
v3_content["teststeps"].append(teststep)
|
||||
|
||||
return v3_content
|
||||
@@ -232,23 +246,28 @@ def ensure_cli_args(args: List) -> List:
|
||||
"""
|
||||
# remove deprecated --failfast
|
||||
if "--failfast" in args:
|
||||
logger.warning(f"remove deprecated argument: --failfast")
|
||||
args.pop(args.index("--failfast"))
|
||||
|
||||
# convert --report-file to --html
|
||||
if "--report-file" in args:
|
||||
logger.warning(f"replace deprecated argument --report-file with --html")
|
||||
index = args.index("--report-file")
|
||||
args[index] = "--html"
|
||||
args.append("--self-contained-html")
|
||||
|
||||
# keep compatibility with --save-tests in v2
|
||||
if "--save-tests" in args:
|
||||
logger.warning(
|
||||
f"generate conftest.py keep compatibility with --save-tests in v2"
|
||||
)
|
||||
args.pop(args.index("--save-tests"))
|
||||
generate_conftest_for_summary(args)
|
||||
_generate_conftest_for_summary(args)
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def generate_conftest_for_summary(args: List):
|
||||
def _generate_conftest_for_summary(args: List):
|
||||
|
||||
for arg in args:
|
||||
if os.path.exists(arg):
|
||||
@@ -259,9 +278,6 @@ def generate_conftest_for_summary(args: List):
|
||||
logger.error(f"No valid test path specified! \nargs: {args}")
|
||||
sys.exit(1)
|
||||
|
||||
project_meta = load_project_meta(test_path)
|
||||
project_root_dir = ensure_file_path_valid(project_meta.RootDir)
|
||||
conftest_path = os.path.join(project_root_dir, "conftest.py")
|
||||
conftest_content = '''# NOTICE: Generated By HttpRunner.
|
||||
import json
|
||||
import os
|
||||
@@ -328,9 +344,13 @@ def session_fixture(request):
|
||||
|
||||
'''
|
||||
|
||||
project_meta = load_project_meta(test_path)
|
||||
project_root_dir = project_meta.RootDir
|
||||
conftest_path = os.path.join(project_root_dir, "conftest.py")
|
||||
|
||||
test_path = os.path.abspath(test_path)
|
||||
logs_dir_path = os.path.join(project_root_dir, "logs")
|
||||
test_path_relative_path = test_path[len(project_root_dir) + 1 :]
|
||||
test_path_relative_path = convert_relative_project_root_dir(test_path)
|
||||
|
||||
if os.path.isdir(test_path):
|
||||
file_foder_path = os.path.join(logs_dir_path, test_path_relative_path)
|
||||
|
||||
@@ -27,10 +27,6 @@ class TeardownHooksFailure(MyBaseFailure):
|
||||
pass
|
||||
|
||||
|
||||
class NetworkFailure(MyBaseFailure):
|
||||
pass
|
||||
|
||||
|
||||
""" error type exceptions
|
||||
these exceptions will mark test as error
|
||||
"""
|
||||
|
||||
@@ -8,14 +8,9 @@ Usage:
|
||||
$ hrun har2case demo.har -2y
|
||||
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
from loguru import logger
|
||||
from sentry_sdk import capture_message
|
||||
|
||||
from httprunner.compat import ensure_path_sep
|
||||
from httprunner.ext.har2case.core import HarParser
|
||||
from sentry_sdk import capture_message
|
||||
|
||||
|
||||
def init_har2case_parser(subparsers):
|
||||
@@ -56,14 +51,6 @@ def init_har2case_parser(subparsers):
|
||||
|
||||
def main_har2case(args):
|
||||
har_source_file = args.har_source_file
|
||||
if not har_source_file or not har_source_file.endswith(".har"):
|
||||
logger.error("HAR file not specified.")
|
||||
sys.exit(1)
|
||||
|
||||
har_source_file = ensure_path_sep(har_source_file)
|
||||
if not os.path.isfile(har_source_file):
|
||||
logger.error(f"HAR file not exists: {har_source_file}")
|
||||
sys.exit(1)
|
||||
|
||||
if args.to_yaml:
|
||||
output_file_type = "YAML"
|
||||
|
||||
@@ -3,7 +3,9 @@ import json
|
||||
import os
|
||||
import sys
|
||||
import urllib.parse as urlparse
|
||||
from typing import Text
|
||||
|
||||
from httprunner.compat import ensure_path_sep
|
||||
from loguru import logger
|
||||
from sentry_sdk import capture_exception
|
||||
|
||||
@@ -16,9 +18,26 @@ except ImportError:
|
||||
JSONDecodeError = ValueError
|
||||
|
||||
|
||||
def ensure_file_path(path: Text) -> Text:
|
||||
|
||||
if not path or not path.endswith(".har"):
|
||||
logger.error("HAR file not specified.")
|
||||
sys.exit(1)
|
||||
|
||||
path = ensure_path_sep(path)
|
||||
if not os.path.isfile(path):
|
||||
logger.error(f"HAR file not exists: {path}")
|
||||
sys.exit(1)
|
||||
|
||||
if not os.path.isabs(path):
|
||||
path = os.path.join(os.getcwd(), path)
|
||||
|
||||
return path
|
||||
|
||||
|
||||
class HarParser(object):
|
||||
def __init__(self, har_file_path, filter_str=None, exclude_str=None):
|
||||
self.har_file_path = har_file_path
|
||||
self.har_file_path = ensure_file_path(har_file_path)
|
||||
self.filter_str = filter_str
|
||||
self.exclude_str = exclude_str or ""
|
||||
|
||||
|
||||
115
httprunner/ext/locust/__init__.py
Normal file
115
httprunner/ext/locust/__init__.py
Normal file
@@ -0,0 +1,115 @@
|
||||
import importlib.util
|
||||
import inspect
|
||||
import os
|
||||
import sys
|
||||
from typing import List
|
||||
|
||||
if sys.argv[0].endswith("locusts"):
|
||||
try:
|
||||
# monkey patch ssl at beginning to avoid RecursionError when running locust.
|
||||
from gevent import monkey
|
||||
|
||||
monkey.patch_ssl()
|
||||
from locust import main as locust_main
|
||||
except ImportError:
|
||||
msg = """
|
||||
Locust is not installed, install first and try again.
|
||||
install with pip:
|
||||
$ pip install locust
|
||||
"""
|
||||
print(msg)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
from loguru import logger
|
||||
|
||||
""" converted pytest files from YAML/JSON testcases
|
||||
"""
|
||||
pytest_files: List = []
|
||||
|
||||
|
||||
def is_httprunner_testcase(item):
|
||||
""" check if a variable is a HttpRunner testcase class
|
||||
"""
|
||||
from httprunner import HttpRunner
|
||||
|
||||
# TODO: skip referenced testcase
|
||||
return bool(
|
||||
inspect.isclass(item)
|
||||
and issubclass(item, HttpRunner)
|
||||
and item.__name__ != "HttpRunner"
|
||||
)
|
||||
|
||||
|
||||
def prepare_locust_tests() -> List:
|
||||
""" prepare locust testcases
|
||||
|
||||
Returns:
|
||||
list: testcase class list
|
||||
"""
|
||||
|
||||
locust_tests = []
|
||||
|
||||
for pytest_file in pytest_files:
|
||||
spec = importlib.util.spec_from_file_location("module.name", pytest_file)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
|
||||
for name, item in vars(module).items():
|
||||
|
||||
if not is_httprunner_testcase(item):
|
||||
continue
|
||||
|
||||
for _ in range(item.config.weight):
|
||||
locust_tests.append(item)
|
||||
|
||||
return locust_tests
|
||||
|
||||
|
||||
def main_locusts():
|
||||
""" locusts entrance
|
||||
"""
|
||||
from httprunner.utils import init_sentry_sdk
|
||||
from sentry_sdk import capture_message
|
||||
|
||||
init_sentry_sdk()
|
||||
capture_message("start to run locusts")
|
||||
|
||||
# avoid print too much log details in console
|
||||
logger.remove()
|
||||
logger.add(sys.stderr, level="WARNING")
|
||||
|
||||
sys.argv[0] = "locust"
|
||||
if len(sys.argv) == 1:
|
||||
sys.argv.extend(["-h"])
|
||||
|
||||
if sys.argv[1] in ["-h", "--help", "-V", "--version"]:
|
||||
locust_main.main()
|
||||
|
||||
def get_arg_index(*target_args):
|
||||
for arg in target_args:
|
||||
if arg not in sys.argv:
|
||||
continue
|
||||
|
||||
return sys.argv.index(arg) + 1
|
||||
|
||||
return None
|
||||
|
||||
# get testcase file path
|
||||
testcase_index = get_arg_index("-f", "--locustfile")
|
||||
if not testcase_index:
|
||||
print("Testcase file is not specified, exit 1.")
|
||||
sys.exit(1)
|
||||
|
||||
from httprunner.make import main_make
|
||||
|
||||
global pytest_files
|
||||
testcase_file_path = sys.argv[testcase_index]
|
||||
pytest_files = main_make([testcase_file_path])
|
||||
if not pytest_files:
|
||||
print("No valid testcases found, exit 1.")
|
||||
sys.exit(1)
|
||||
|
||||
sys.argv[testcase_index] = os.path.join(os.path.dirname(__file__), "locustfile.py")
|
||||
|
||||
locust_main.main()
|
||||
30
httprunner/ext/locust/locustfile.py
Normal file
30
httprunner/ext/locust/locustfile.py
Normal file
@@ -0,0 +1,30 @@
|
||||
import random
|
||||
|
||||
from locust import task, HttpUser, between
|
||||
|
||||
from httprunner.ext.locust import prepare_locust_tests
|
||||
|
||||
|
||||
class HttpRunnerUser(HttpUser):
|
||||
host = ""
|
||||
wait_time = between(5, 15)
|
||||
|
||||
def on_start(self):
|
||||
locust_tests = prepare_locust_tests()
|
||||
self.testcase_runners = [
|
||||
testcase().with_session(self.client) for testcase in locust_tests
|
||||
]
|
||||
|
||||
@task
|
||||
def test_any(self):
|
||||
test_runner = random.choice(self.testcase_runners)
|
||||
try:
|
||||
test_runner.run()
|
||||
except Exception as ex:
|
||||
self.environment.events.request_failure.fire(
|
||||
request_type="Failed",
|
||||
name=test_runner.config.name,
|
||||
response_time=0,
|
||||
response_length=0,
|
||||
exception=ex,
|
||||
)
|
||||
@@ -46,10 +46,9 @@ import os
|
||||
import sys
|
||||
from typing import Text, NoReturn
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from httprunner.parser import parse_variables_mapping
|
||||
from httprunner.models import TStep, FunctionsMapping
|
||||
from httprunner.parser import parse_variables_mapping
|
||||
from loguru import logger
|
||||
|
||||
try:
|
||||
import filetype
|
||||
@@ -146,7 +145,7 @@ def multipart_encoder(**kwargs):
|
||||
# value is not absolute file path, check if it is relative file path
|
||||
from httprunner.loader import load_project_meta
|
||||
|
||||
project_meta = load_project_meta(os.getcwd())
|
||||
project_meta = load_project_meta("")
|
||||
|
||||
_file_path = os.path.join(project_meta.RootDir, value)
|
||||
is_exists_file = os.path.isfile(_file_path)
|
||||
|
||||
@@ -78,7 +78,6 @@ def load_testcase(testcase: Dict) -> TestCase:
|
||||
testcase_obj = TestCase.parse_obj(testcase)
|
||||
except ValidationError as ex:
|
||||
err_msg = f"TestCase ValidationError:\nerror: {ex}\ncontent: {testcase}"
|
||||
logger.error(err_msg)
|
||||
raise exceptions.TestCaseFormatError(err_msg)
|
||||
|
||||
return testcase_obj
|
||||
@@ -99,7 +98,6 @@ def load_testsuite(testsuite: Dict) -> TestSuite:
|
||||
testsuite_obj = TestSuite.parse_obj(testsuite)
|
||||
except ValidationError as ex:
|
||||
err_msg = f"TestSuite ValidationError:\nfile: {path}\nerror: {ex}"
|
||||
logger.error(err_msg)
|
||||
raise exceptions.TestSuiteFormatError(err_msg)
|
||||
|
||||
return testsuite_obj
|
||||
@@ -287,6 +285,7 @@ def locate_file(start_path: Text, file_name: Text) -> Text:
|
||||
|
||||
file_path = os.path.join(start_dir_path, file_name)
|
||||
if os.path.isfile(file_path):
|
||||
# ensure absolute
|
||||
return os.path.abspath(file_path)
|
||||
|
||||
# system root dir
|
||||
@@ -431,3 +430,23 @@ def load_project_meta(test_path: Text, reload: bool = False) -> ProjectMeta:
|
||||
project_meta.debugtalk_path = debugtalk_path
|
||||
|
||||
return project_meta
|
||||
|
||||
|
||||
def convert_relative_project_root_dir(abs_path: Text) -> Text:
|
||||
""" convert absolute path to relative path, based on project_meta.RootDir
|
||||
|
||||
Args:
|
||||
abs_path: absolute path
|
||||
|
||||
Returns: relative path based on project_meta.RootDir
|
||||
|
||||
"""
|
||||
_project_meta = load_project_meta(abs_path)
|
||||
if not abs_path.startswith(_project_meta.RootDir):
|
||||
raise exceptions.ParamsError(
|
||||
f"failed to convert absolute path to relative path based on project_meta.RootDir\n"
|
||||
f"abs_path: {abs_path}\n"
|
||||
f"project_meta.RootDir: {_project_meta.RootDir}"
|
||||
)
|
||||
|
||||
return abs_path[len(_project_meta.RootDir) + 1 :]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import os
|
||||
import string
|
||||
import subprocess
|
||||
import sys
|
||||
from shutil import copyfile
|
||||
from typing import Text, List, Tuple, Dict, Set, NoReturn
|
||||
|
||||
import jinja2
|
||||
@@ -21,9 +21,10 @@ from httprunner.loader import (
|
||||
load_testcase,
|
||||
load_testsuite,
|
||||
load_project_meta,
|
||||
convert_relative_project_root_dir,
|
||||
)
|
||||
from httprunner.response import uniform_validator
|
||||
from httprunner.utils import ensure_file_path_valid, override_config_variables
|
||||
from httprunner.utils import override_config_variables
|
||||
|
||||
""" cache converted pytest files, avoid duplicate making
|
||||
"""
|
||||
@@ -36,11 +37,15 @@ pytest_files_run_set: Set = set()
|
||||
__TEMPLATE__ = jinja2.Template(
|
||||
"""# NOTE: Generated By HttpRunner v{{ version }}
|
||||
# FROM: {{ testcase_path }}
|
||||
{% if imports_list %}
|
||||
import os
|
||||
{% if imports_list and diff_levels > 0 %}
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, os.getcwd())
|
||||
sys.path.insert(0, str(Path(__file__)
|
||||
{% for _ in range(diff_levels) %}
|
||||
.parent
|
||||
{% endfor %}
|
||||
))
|
||||
{% endif %}
|
||||
from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase
|
||||
{% for import_str in imports_list %}
|
||||
@@ -80,24 +85,51 @@ def __ensure_absolute(path: Text) -> Text:
|
||||
absolute_path = os.path.join(project_meta.RootDir, path)
|
||||
|
||||
if not os.path.isfile(absolute_path):
|
||||
raise exceptions.ParamsError(f"Invalid testcase file path: {absolute_path}")
|
||||
logger.error(f"Invalid testcase file path: {absolute_path}")
|
||||
sys.exit(1)
|
||||
|
||||
return absolute_path
|
||||
|
||||
|
||||
def __ensure_cwd_relative(path: Text) -> Text:
|
||||
""" convert absolute path to relative path, based on os.getcwd()
|
||||
def ensure_file_abs_path_valid(file_abs_path: Text) -> Text:
|
||||
""" ensure file path valid for pytest, handle cases when directory name includes dot/hyphen/space
|
||||
|
||||
Args:
|
||||
path: absolute path
|
||||
file_abs_path: absolute file path
|
||||
|
||||
Returns: relative path based on os.getcwd()
|
||||
Returns:
|
||||
ensured valid absolute file path
|
||||
|
||||
"""
|
||||
if os.path.isabs(path):
|
||||
return path[len(os.getcwd()) + 1 :]
|
||||
else:
|
||||
return path
|
||||
project_meta = load_project_meta(file_abs_path)
|
||||
raw_abs_file_name, file_suffix = os.path.splitext(file_abs_path)
|
||||
file_suffix = file_suffix.lower()
|
||||
|
||||
raw_file_relative_name = convert_relative_project_root_dir(raw_abs_file_name)
|
||||
if raw_file_relative_name == "":
|
||||
return file_abs_path
|
||||
|
||||
path_names = []
|
||||
for name in raw_file_relative_name.rstrip(os.sep).split(os.sep):
|
||||
|
||||
if name[0] in string.digits:
|
||||
# ensure file name not startswith digit
|
||||
# 19 => T19, 2C => T2C
|
||||
name = f"T{name}"
|
||||
|
||||
if name.startswith("."):
|
||||
# avoid ".csv" been converted to "_csv"
|
||||
pass
|
||||
else:
|
||||
# handle cases when directory name includes dot/hyphen/space
|
||||
name = name.replace(" ", "_").replace(".", "_").replace("-", "_")
|
||||
|
||||
path_names.append(name)
|
||||
|
||||
new_file_path = os.path.join(
|
||||
project_meta.RootDir, f"{os.sep.join(path_names)}{file_suffix}"
|
||||
)
|
||||
return new_file_path
|
||||
|
||||
|
||||
def __ensure_testcase_module(path: Text) -> NoReturn:
|
||||
@@ -111,43 +143,18 @@ def __ensure_testcase_module(path: Text) -> NoReturn:
|
||||
f.write("# NOTICE: Generated By HttpRunner. DO NOT EDIT!\n")
|
||||
|
||||
|
||||
def __ensure_project_meta_files(tests_path: Text) -> NoReturn:
|
||||
""" ensure project meta files exist in generated pytest folder files
|
||||
include debugtalk.py and .env
|
||||
"""
|
||||
project_meta = load_project_meta(tests_path)
|
||||
|
||||
# handle cases when generated pytest directory are different from original yaml/json testcases
|
||||
debugtalk_path = project_meta.debugtalk_path
|
||||
if debugtalk_path:
|
||||
debugtalk_new_path = ensure_file_path_valid(debugtalk_path)
|
||||
if debugtalk_new_path != debugtalk_path:
|
||||
logger.info(f"copy debugtalk.py to {debugtalk_new_path}")
|
||||
copyfile(debugtalk_path, debugtalk_new_path)
|
||||
|
||||
global pytest_files_made_cache_mapping
|
||||
pytest_files_made_cache_mapping[debugtalk_new_path] = ""
|
||||
|
||||
dot_csv_path = project_meta.dot_env_path
|
||||
if dot_csv_path:
|
||||
dot_csv_new_path = ensure_file_path_valid(dot_csv_path)
|
||||
if dot_csv_new_path != dot_csv_path:
|
||||
logger.info(f"copy .env to {dot_csv_new_path}")
|
||||
copyfile(dot_csv_path, dot_csv_new_path)
|
||||
|
||||
|
||||
def convert_testcase_path(testcase_path: Text) -> Tuple[Text, Text]:
|
||||
def convert_testcase_path(testcase_abs_path: Text) -> Tuple[Text, Text]:
|
||||
"""convert single YAML/JSON testcase path to python file"""
|
||||
testcase_new_path = ensure_file_path_valid(testcase_path)
|
||||
testcase_new_path = ensure_file_abs_path_valid(testcase_abs_path)
|
||||
|
||||
dir_path = os.path.dirname(testcase_new_path)
|
||||
file_name, _ = os.path.splitext(os.path.basename(testcase_new_path))
|
||||
testcase_python_path = os.path.join(dir_path, f"{file_name}_test.py")
|
||||
testcase_python_abs_path = os.path.join(dir_path, f"{file_name}_test.py")
|
||||
|
||||
# convert title case, e.g. request_with_variables => RequestWithVariables
|
||||
name_in_title_case = file_name.title().replace("_", "")
|
||||
|
||||
return testcase_python_path, name_in_title_case
|
||||
return testcase_python_abs_path, name_in_title_case
|
||||
|
||||
|
||||
def format_pytest_with_black(*python_paths: Text) -> NoReturn:
|
||||
@@ -184,6 +191,9 @@ def make_config_chain_style(config: Dict) -> Text:
|
||||
if "export" in config:
|
||||
config_chain_style += f'.export(*{config["export"]})'
|
||||
|
||||
if "weight" in config:
|
||||
config_chain_style += f'.locust_weight({config["weight"]})'
|
||||
|
||||
return config_chain_style
|
||||
|
||||
|
||||
@@ -316,18 +326,20 @@ def make_testcase(testcase: Dict, dir_path: Text = None) -> Text:
|
||||
testcase_abs_path = __ensure_absolute(testcase["config"]["path"])
|
||||
logger.info(f"start to make testcase: {testcase_abs_path}")
|
||||
|
||||
testcase_python_path, testcase_cls_name = convert_testcase_path(testcase_abs_path)
|
||||
testcase_python_abs_path, testcase_cls_name = convert_testcase_path(
|
||||
testcase_abs_path
|
||||
)
|
||||
if dir_path:
|
||||
testcase_python_path = os.path.join(
|
||||
dir_path, os.path.basename(testcase_python_path)
|
||||
testcase_python_abs_path = os.path.join(
|
||||
dir_path, os.path.basename(testcase_python_abs_path)
|
||||
)
|
||||
|
||||
global pytest_files_made_cache_mapping
|
||||
if testcase_python_path in pytest_files_made_cache_mapping:
|
||||
return testcase_python_path
|
||||
if testcase_python_abs_path in pytest_files_made_cache_mapping:
|
||||
return testcase_python_abs_path
|
||||
|
||||
config = testcase["config"]
|
||||
config["path"] = __ensure_cwd_relative(testcase_python_path)
|
||||
config["path"] = convert_relative_project_root_dir(testcase_python_abs_path)
|
||||
config["variables"] = convert_variables(
|
||||
config.get("variables", {}), testcase_abs_path
|
||||
)
|
||||
@@ -348,25 +360,32 @@ def make_testcase(testcase: Dict, dir_path: Text = None) -> Text:
|
||||
test_content = ensure_testcase_v3_api(test_content)
|
||||
|
||||
test_content.setdefault("config", {})["path"] = ref_testcase_path
|
||||
ref_testcase_python_path = make_testcase(test_content)
|
||||
ref_testcase_python_abs_path = make_testcase(test_content)
|
||||
|
||||
# prepare ref testcase class name
|
||||
ref_testcase_cls_name = pytest_files_made_cache_mapping[
|
||||
ref_testcase_python_path
|
||||
ref_testcase_python_abs_path
|
||||
]
|
||||
teststep["testcase"] = ref_testcase_cls_name
|
||||
|
||||
# prepare import ref testcase
|
||||
ref_testcase_python_path = ref_testcase_python_path[len(os.getcwd()) + 1 :]
|
||||
ref_module_name, _ = os.path.splitext(ref_testcase_python_path)
|
||||
ref_testcase_python_relative_path = convert_relative_project_root_dir(
|
||||
ref_testcase_python_abs_path
|
||||
)
|
||||
ref_module_name, _ = os.path.splitext(ref_testcase_python_relative_path)
|
||||
ref_module_name = ref_module_name.replace(os.sep, ".")
|
||||
imports_list.append(
|
||||
f"from {ref_module_name} import TestCase{ref_testcase_cls_name} as {ref_testcase_cls_name}"
|
||||
)
|
||||
|
||||
testcase_path = convert_relative_project_root_dir(testcase_abs_path)
|
||||
# current file compared to ProjectRootDir
|
||||
diff_levels = len(testcase_path.split(os.sep))
|
||||
|
||||
data = {
|
||||
"version": __version__,
|
||||
"testcase_path": __ensure_cwd_relative(testcase_abs_path),
|
||||
"testcase_path": testcase_path,
|
||||
"diff_levels": diff_levels,
|
||||
"class_name": f"TestCase{testcase_cls_name}",
|
||||
"imports_list": imports_list,
|
||||
"config_chain_style": make_config_chain_style(config),
|
||||
@@ -377,19 +396,19 @@ def make_testcase(testcase: Dict, dir_path: Text = None) -> Text:
|
||||
content = __TEMPLATE__.render(data)
|
||||
|
||||
# ensure new file's directory exists
|
||||
dir_path = os.path.dirname(testcase_python_path)
|
||||
dir_path = os.path.dirname(testcase_python_abs_path)
|
||||
if not os.path.exists(dir_path):
|
||||
os.makedirs(dir_path)
|
||||
|
||||
with open(testcase_python_path, "w", encoding="utf-8") as f:
|
||||
with open(testcase_python_abs_path, "w", encoding="utf-8") as f:
|
||||
f.write(content)
|
||||
|
||||
pytest_files_made_cache_mapping[testcase_python_path] = testcase_cls_name
|
||||
__ensure_testcase_module(testcase_python_path)
|
||||
pytest_files_made_cache_mapping[testcase_python_abs_path] = testcase_cls_name
|
||||
__ensure_testcase_module(testcase_python_abs_path)
|
||||
|
||||
logger.info(f"generated testcase: {testcase_python_path}")
|
||||
logger.info(f"generated testcase: {testcase_python_abs_path}")
|
||||
|
||||
return testcase_python_path
|
||||
return testcase_python_abs_path
|
||||
|
||||
|
||||
def make_testsuite(testsuite: Dict) -> NoReturn:
|
||||
@@ -406,7 +425,7 @@ def make_testsuite(testsuite: Dict) -> NoReturn:
|
||||
logger.info(f"start to make testsuite: {testsuite_path}")
|
||||
|
||||
# create directory with testsuite file name, put its testcases under this directory
|
||||
testsuite_path = ensure_file_path_valid(testsuite_path)
|
||||
testsuite_path = ensure_file_abs_path_valid(testsuite_path)
|
||||
testsuite_dir, file_suffix = os.path.splitext(testsuite_path)
|
||||
# demo_testsuite.yml => demo_testsuite_yml
|
||||
testsuite_dir = f"{testsuite_dir}_{file_suffix.lstrip('.')}"
|
||||
@@ -442,6 +461,10 @@ def make_testsuite(testsuite: Dict) -> NoReturn:
|
||||
)
|
||||
testcase_dict["config"]["variables"].update(testcase_variables)
|
||||
|
||||
# override weight
|
||||
weight = testcase.get("weight", 1)
|
||||
testcase_dict["config"]["weight"] = weight
|
||||
|
||||
# make testcase
|
||||
testcase_pytest_path = make_testcase(testcase_dict, testsuite_dir)
|
||||
pytest_files_run_set.add(testcase_pytest_path)
|
||||
@@ -455,6 +478,7 @@ def __make(tests_path: Text) -> NoReturn:
|
||||
tests_path: should be in absolute path
|
||||
|
||||
"""
|
||||
logger.info(f"make path: {tests_path}")
|
||||
test_files = []
|
||||
if os.path.isdir(tests_path):
|
||||
files_list = load_folder_files(tests_path)
|
||||
@@ -472,11 +496,14 @@ def __make(tests_path: Text) -> NoReturn:
|
||||
try:
|
||||
test_content = load_test_file(test_file)
|
||||
except (exceptions.FileNotFound, exceptions.FileFormatError) as ex:
|
||||
logger.warning(ex)
|
||||
logger.warning(f"Invalid test file: {test_file}\n{type(ex).__name__}: {ex}")
|
||||
continue
|
||||
|
||||
if not isinstance(test_content, Dict):
|
||||
logger.warning(f"test content not in dict format. \npath: {test_file}")
|
||||
logger.warning(
|
||||
f"Invalid test file: {test_file}\n"
|
||||
f"reason: test content not in dict format."
|
||||
)
|
||||
continue
|
||||
|
||||
# api in v2 format, convert to v3 testcase
|
||||
@@ -485,10 +512,18 @@ def __make(tests_path: Text) -> NoReturn:
|
||||
|
||||
if "config" not in test_content:
|
||||
logger.warning(
|
||||
f"Invalid testcase/testsuite: missing config part in testcase/testsuite.\npath: {test_file}"
|
||||
f"Invalid testcase/testsuite file: {test_file}\n"
|
||||
f"reason: missing config part."
|
||||
)
|
||||
continue
|
||||
elif not isinstance(test_content["config"], Dict):
|
||||
logger.warning(
|
||||
f"Invalid testcase/testsuite file: {test_file}\n"
|
||||
f"reason: config should be dict type, got {test_content['config']}"
|
||||
)
|
||||
continue
|
||||
|
||||
# ensure path absolute
|
||||
test_content.setdefault("config", {})["path"] = test_file
|
||||
|
||||
# testcase
|
||||
@@ -496,19 +531,28 @@ def __make(tests_path: Text) -> NoReturn:
|
||||
try:
|
||||
testcase_pytest_path = make_testcase(test_content)
|
||||
pytest_files_run_set.add(testcase_pytest_path)
|
||||
except exceptions.TestCaseFormatError:
|
||||
except exceptions.TestCaseFormatError as ex:
|
||||
logger.warning(
|
||||
f"Invalid testcase file: {test_file}\n{type(ex).__name__}: {ex}"
|
||||
)
|
||||
continue
|
||||
|
||||
# testsuite
|
||||
elif "testcases" in test_content:
|
||||
try:
|
||||
make_testsuite(test_content)
|
||||
except exceptions.TestSuiteFormatError:
|
||||
except exceptions.TestSuiteFormatError as ex:
|
||||
logger.warning(
|
||||
f"Invalid testsuite file: {test_file}\n{type(ex).__name__}: {ex}"
|
||||
)
|
||||
continue
|
||||
|
||||
# invalid format
|
||||
else:
|
||||
logger.warning(f"skip invalid testcase/testsuite file: {test_file}")
|
||||
logger.warning(
|
||||
f"Invalid test file: {test_file}\n"
|
||||
f"reason: file content is neither testcase nor testsuite"
|
||||
)
|
||||
|
||||
|
||||
def main_make(tests_paths: List[Text]) -> List[Text]:
|
||||
@@ -526,8 +570,6 @@ def main_make(tests_paths: List[Text]) -> List[Text]:
|
||||
logger.error(ex)
|
||||
sys.exit(1)
|
||||
|
||||
__ensure_project_meta_files(tests_path)
|
||||
|
||||
# format pytest files
|
||||
pytest_files_format_list = pytest_files_made_cache_mapping.keys()
|
||||
format_pytest_with_black(*pytest_files_format_list)
|
||||
|
||||
@@ -41,6 +41,7 @@ class TConfig(BaseModel):
|
||||
# teardown_hooks: Hooks = []
|
||||
export: Export = []
|
||||
path: Text = None
|
||||
weight: int = 1
|
||||
|
||||
|
||||
class TRequest(BaseModel):
|
||||
@@ -85,7 +86,7 @@ class ProjectMeta(BaseModel):
|
||||
dot_env_path: Text = "" # .env file path
|
||||
functions: FunctionsMapping = {} # functions defined in debugtalk.py
|
||||
env: Env = {}
|
||||
RootDir: Text = os.getcwd() # project root directory, the path debugtalk.py located
|
||||
RootDir: Text = os.getcwd() # project root directory (ensure absolute), the path debugtalk.py located
|
||||
|
||||
|
||||
class TestsMapping(BaseModel):
|
||||
@@ -122,7 +123,7 @@ class RequestData(BaseModel):
|
||||
url: Url
|
||||
headers: Headers = {}
|
||||
cookies: Cookies = {}
|
||||
body: Union[Text, bytes, Dict, None] = {}
|
||||
body: Union[Text, bytes, Dict, List, None] = {}
|
||||
|
||||
|
||||
class ResponseData(BaseModel):
|
||||
|
||||
@@ -3,6 +3,7 @@ import builtins
|
||||
import re
|
||||
from typing import Any, Set, Text, Callable, List, Dict
|
||||
|
||||
from loguru import logger
|
||||
from sentry_sdk import capture_exception
|
||||
|
||||
from httprunner import loader, utils, exceptions
|
||||
@@ -331,10 +332,20 @@ def parse_string(
|
||||
function_meta = parse_function_params(func_params_str)
|
||||
args = function_meta["args"]
|
||||
kwargs = function_meta["kwargs"]
|
||||
|
||||
parsed_args = parse_data(args, variables_mapping, functions_mapping)
|
||||
parsed_kwargs = parse_data(kwargs, variables_mapping, functions_mapping)
|
||||
func_eval_value = func(*parsed_args, **parsed_kwargs)
|
||||
|
||||
try:
|
||||
func_eval_value = func(*parsed_args, **parsed_kwargs)
|
||||
except Exception as ex:
|
||||
logger.error(
|
||||
f"call function error:\n"
|
||||
f"func_name: {func_name}\n"
|
||||
f"args: {parsed_args}\n"
|
||||
f"kwargs: {parsed_kwargs}\n"
|
||||
f"{type(ex).__name__}: {ex}"
|
||||
)
|
||||
raise
|
||||
|
||||
func_raw_str = "${" + func_name + f"({func_params_str})" + "}"
|
||||
if func_raw_str == raw_string:
|
||||
|
||||
@@ -203,24 +203,30 @@ class HttpRunner(object):
|
||||
|
||||
# validate
|
||||
validators = step.validators
|
||||
session_success = False
|
||||
try:
|
||||
resp_obj.validate(
|
||||
validators, variables_mapping, self.__project_meta.functions
|
||||
)
|
||||
self.__session.data.success = True
|
||||
session_success = True
|
||||
except ValidationFailure:
|
||||
self.__session.data.success = False
|
||||
session_success = False
|
||||
log_req_resp_details()
|
||||
# log testcase duration before raise ValidationFailure
|
||||
self.__duration = time.time() - self.__start_at
|
||||
raise
|
||||
finally:
|
||||
# save request & response meta data
|
||||
self.__session.data.validators = resp_obj.validation_results
|
||||
self.success = self.__session.data.success
|
||||
# save step data
|
||||
step_data.success = self.__session.data.success
|
||||
step_data.data = self.__session.data
|
||||
self.success = session_success
|
||||
step_data.success = session_success
|
||||
|
||||
if hasattr(self.__session, "data"):
|
||||
# httprunner.client.HttpSession, not locust.clients.HttpSession
|
||||
# save request & response meta data
|
||||
self.__session.data.success = session_success
|
||||
self.__session.data.validators = resp_obj.validation_results
|
||||
|
||||
# save step data
|
||||
step_data.data = self.__session.data
|
||||
|
||||
return step_data
|
||||
|
||||
|
||||
@@ -17,18 +17,23 @@ class Config(object):
|
||||
self.__base_url = ""
|
||||
self.__verify = False
|
||||
self.__export = []
|
||||
self.__weight = 1
|
||||
|
||||
caller_frame = inspect.stack()[1]
|
||||
self.__path = caller_frame.filename
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
def name(self) -> Text:
|
||||
return self.__name
|
||||
|
||||
@property
|
||||
def path(self):
|
||||
def path(self) -> Text:
|
||||
return self.__path
|
||||
|
||||
@property
|
||||
def weight(self) -> int:
|
||||
return self.__weight
|
||||
|
||||
def variables(self, **variables) -> "Config":
|
||||
self.__variables.update(variables)
|
||||
return self
|
||||
@@ -45,6 +50,10 @@ class Config(object):
|
||||
self.__export.extend(export_var_name)
|
||||
return self
|
||||
|
||||
def locust_weight(self, weight: int) -> "Config":
|
||||
self.__weight = weight
|
||||
return self
|
||||
|
||||
def perform(self) -> TConfig:
|
||||
return TConfig(
|
||||
name=self.__name,
|
||||
@@ -53,6 +62,7 @@ class Config(object):
|
||||
variables=self.__variables,
|
||||
export=list(set(self.__export)),
|
||||
path=self.__path,
|
||||
weight=self.__weight,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -3,16 +3,14 @@ import copy
|
||||
import json
|
||||
import os.path
|
||||
import platform
|
||||
import string
|
||||
import uuid
|
||||
from typing import Dict, List, Any, Text
|
||||
from typing import Dict, List, Any
|
||||
|
||||
import sentry_sdk
|
||||
from loguru import logger
|
||||
|
||||
from httprunner import __version__
|
||||
from httprunner import exceptions
|
||||
from httprunner.models import VariablesMapping
|
||||
from loguru import logger
|
||||
|
||||
|
||||
def init_sentry_sdk():
|
||||
@@ -181,48 +179,6 @@ def sort_dict_by_custom_order(raw_dict: Dict, custom_order: List):
|
||||
)
|
||||
|
||||
|
||||
def ensure_file_path_valid(file_path: Text) -> Text:
|
||||
""" ensure file path valid for pytest, handle cases when directory name includes dot/hyphen/space
|
||||
|
||||
Args:
|
||||
file_path: absolute or relative file path
|
||||
|
||||
Returns:
|
||||
ensured valid absolute file path
|
||||
|
||||
"""
|
||||
raw_file_name, file_suffix = os.path.splitext(file_path)
|
||||
file_suffix = file_suffix.lower()
|
||||
|
||||
if os.path.isabs(file_path):
|
||||
raw_file_relative_name = raw_file_name[len(os.getcwd()) + 1 :]
|
||||
else:
|
||||
raw_file_relative_name = raw_file_name
|
||||
|
||||
if raw_file_relative_name == "":
|
||||
return file_path
|
||||
|
||||
path_names = []
|
||||
for name in raw_file_relative_name.rstrip(os.sep).split(os.sep):
|
||||
|
||||
if name[0] in string.digits:
|
||||
# ensure file name not startswith digit
|
||||
# 19 => T19, 2C => T2C
|
||||
name = f"T{name}"
|
||||
|
||||
if name.startswith("."):
|
||||
# avoid ".csv" been converted to "_csv"
|
||||
pass
|
||||
else:
|
||||
# handle cases when directory name includes dot/hyphen/space
|
||||
name = name.replace(" ", "_").replace(".", "_").replace("-", "_")
|
||||
|
||||
path_names.append(name)
|
||||
|
||||
new_file_path = os.path.join(os.getcwd(), f"{os.sep.join(path_names)}{file_suffix}")
|
||||
return new_file_path
|
||||
|
||||
|
||||
class ExtendJSONEncoder(json.JSONEncoder):
|
||||
""" especially used to safely dump json data with python object, such as MultipartEncoder
|
||||
"""
|
||||
|
||||
@@ -59,5 +59,6 @@ nav:
|
||||
- Write Testcase: user/write_testcase.md
|
||||
- Run Testcase: user/run_testcase.md
|
||||
- Testing Report: user/testing_report.md
|
||||
- Run load test: user/run_loadtest.md
|
||||
- Sponsors: sponsors.md
|
||||
- CHANGELOG: CHANGELOG.md
|
||||
|
||||
558
poetry.lock
generated
558
poetry.lock
generated
@@ -95,7 +95,19 @@ description = "Python package for providing Mozilla's CA Bundle."
|
||||
name = "certifi"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "2020.4.5.1"
|
||||
version = "2020.4.5.2"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Foreign Function Interface for Python calling C code."
|
||||
marker = "platform_python_implementation == \"CPython\" and sys_platform == \"win32\""
|
||||
name = "cffi"
|
||||
optional = true
|
||||
python-versions = "*"
|
||||
version = "1.14.0"
|
||||
|
||||
[package.dependencies]
|
||||
pycparser = "*"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
@@ -122,6 +134,17 @@ optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
version = "0.4.3"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "A drop-in replacement for argparse that allows options to also be set via config files and/or environment variables."
|
||||
name = "configargparse"
|
||||
optional = true
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
version = "1.2.3"
|
||||
|
||||
[package.extras]
|
||||
yaml = ["pyyaml"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "PEP 567 Backport"
|
||||
@@ -177,6 +200,80 @@ optional = true
|
||||
python-versions = "*"
|
||||
version = "1.0.7"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "A simple framework for building complex web applications."
|
||||
name = "flask"
|
||||
optional = true
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
version = "1.1.2"
|
||||
|
||||
[package.dependencies]
|
||||
Jinja2 = ">=2.10.1"
|
||||
Werkzeug = ">=0.15"
|
||||
click = ">=5.1"
|
||||
itsdangerous = ">=0.24"
|
||||
|
||||
[package.extras]
|
||||
dev = ["pytest", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"]
|
||||
docs = ["sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"]
|
||||
dotenv = ["python-dotenv"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "HTTP basic access authentication for Flask."
|
||||
name = "flask-basicauth"
|
||||
optional = true
|
||||
python-versions = "*"
|
||||
version = "0.2.0"
|
||||
|
||||
[package.dependencies]
|
||||
Flask = "*"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Coroutine-based network library"
|
||||
name = "gevent"
|
||||
optional = true
|
||||
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*"
|
||||
version = "20.6.2"
|
||||
|
||||
[package.dependencies]
|
||||
cffi = ">=1.12.2"
|
||||
greenlet = ">=0.4.16"
|
||||
setuptools = "*"
|
||||
"zope.event" = "*"
|
||||
"zope.interface" = "*"
|
||||
|
||||
[package.extras]
|
||||
dnspython = ["dnspython (>=1.16.0)", "idna"]
|
||||
docs = ["repoze.sphinx.autointerface", "sphinxcontrib-programoutput"]
|
||||
monitor = ["psutil (>=5.7.0)"]
|
||||
recommended = ["dnspython (>=1.16.0)", "idna", "cffi (>=1.12.2)", "selectors2", "backports.socketpair", "psutil (>=5.7.0)"]
|
||||
test = ["dnspython (>=1.16.0)", "idna", "requests", "objgraph", "cffi (>=1.12.2)", "selectors2", "futures", "mock", "backports.socketpair", "contextvars (2.4)", "coverage (<5.0)", "coveralls (>=1.7.0)", "psutil (>=5.7.0)"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "http client library for gevent"
|
||||
name = "geventhttpclient"
|
||||
optional = true
|
||||
python-versions = "*"
|
||||
version = "1.4.2"
|
||||
|
||||
[package.dependencies]
|
||||
certifi = "*"
|
||||
gevent = ">=0.13"
|
||||
six = "*"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Lightweight in-process concurrent programming"
|
||||
marker = "platform_python_implementation == \"CPython\""
|
||||
name = "greenlet"
|
||||
optional = true
|
||||
python-versions = "*"
|
||||
version = "0.4.16"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
|
||||
@@ -221,14 +318,22 @@ marker = "python_version < \"3.8\""
|
||||
name = "importlib-metadata"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
|
||||
version = "1.6.0"
|
||||
version = "1.6.1"
|
||||
|
||||
[package.dependencies]
|
||||
zipp = ">=0.5"
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx", "rst.linker"]
|
||||
testing = ["packaging", "importlib-resources"]
|
||||
testing = ["packaging", "pep517", "importlib-resources (>=1.3)"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Various helpers to pass data to untrusted environments and back."
|
||||
name = "itsdangerous"
|
||||
optional = true
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "1.1.0"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
@@ -252,6 +357,25 @@ optional = false
|
||||
python-versions = "*"
|
||||
version = "0.9.5"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Developer friendly load testing framework"
|
||||
name = "locust"
|
||||
optional = true
|
||||
python-versions = ">=3.6"
|
||||
version = "1.0.3"
|
||||
|
||||
[package.dependencies]
|
||||
ConfigArgParse = ">=1.0"
|
||||
Flask-BasicAuth = ">=0.2.0"
|
||||
flask = ">=1.1.2"
|
||||
gevent = ">=1.5.0"
|
||||
geventhttpclient = ">=1.4.2"
|
||||
msgpack = ">=0.6.2"
|
||||
psutil = ">=5.6.7"
|
||||
pyzmq = ">=16.0.2"
|
||||
requests = ">=2.9.1"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Python logging made (stupidly) simple"
|
||||
@@ -285,7 +409,15 @@ description = "More routines for operating on iterables, beyond itertools"
|
||||
name = "more-itertools"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
version = "8.3.0"
|
||||
version = "8.4.0"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "MessagePack (de)serializer."
|
||||
name = "msgpack"
|
||||
optional = true
|
||||
python-versions = "*"
|
||||
version = "1.0.0"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
@@ -323,13 +455,33 @@ version = ">=0.12"
|
||||
[package.extras]
|
||||
dev = ["pre-commit", "tox"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Cross-platform lib for process and system monitoring in Python."
|
||||
name = "psutil"
|
||||
optional = true
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "5.7.0"
|
||||
|
||||
[package.extras]
|
||||
enum = ["enum34"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "library with cross-python path, ini-parsing, io, code, log facilities"
|
||||
name = "py"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "1.8.1"
|
||||
version = "1.8.2"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "C parser in Python"
|
||||
marker = "platform_python_implementation == \"CPython\" and sys_platform == \"win32\""
|
||||
name = "pycparser"
|
||||
optional = true
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "2.20"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
@@ -363,7 +515,7 @@ description = "pytest: simple powerful testing with Python"
|
||||
name = "pytest"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
version = "5.4.2"
|
||||
version = "5.4.3"
|
||||
|
||||
[package.dependencies]
|
||||
atomicwrites = ">=1.0"
|
||||
@@ -414,13 +566,21 @@ optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
version = "5.3.1"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Python bindings for 0MQ"
|
||||
name = "pyzmq"
|
||||
optional = true
|
||||
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*"
|
||||
version = "19.0.1"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Alternative regular expression module, to replace re."
|
||||
name = "regex"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "2020.5.14"
|
||||
version = "2020.6.8"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
@@ -428,7 +588,7 @@ description = "Python HTTP for Humans."
|
||||
name = "requests"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
version = "2.23.0"
|
||||
version = "2.24.0"
|
||||
|
||||
[package.dependencies]
|
||||
certifi = ">=2017.4.17"
|
||||
@@ -554,11 +714,11 @@ version = "0.14.0"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Measures number of Terminal column cells of wide-character codes"
|
||||
description = "Measures the displayed width of unicode strings in a terminal"
|
||||
name = "wcwidth"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.1.9"
|
||||
version = "0.2.4"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
@@ -568,6 +728,18 @@ optional = false
|
||||
python-versions = ">=3.6"
|
||||
version = "8.0.2"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "The comprehensive WSGI web application library."
|
||||
name = "werkzeug"
|
||||
optional = true
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
version = "1.0.1"
|
||||
|
||||
[package.extras]
|
||||
dev = ["pytest", "pytest-timeout", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinx-issues"]
|
||||
watchdog = ["watchdog"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "A small Python utility to set file creation time on Windows"
|
||||
@@ -593,12 +765,44 @@ version = "3.1.0"
|
||||
docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
|
||||
testing = ["jaraco.itertools", "func-timeout"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Very basic event publishing system"
|
||||
name = "zope.event"
|
||||
optional = true
|
||||
python-versions = "*"
|
||||
version = "4.4"
|
||||
|
||||
[package.dependencies]
|
||||
setuptools = "*"
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx"]
|
||||
test = ["zope.testrunner"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Interfaces for Python"
|
||||
name = "zope.interface"
|
||||
optional = true
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
version = "5.1.0"
|
||||
|
||||
[package.dependencies]
|
||||
setuptools = "*"
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx", "repoze.sphinx.autointerface"]
|
||||
test = ["coverage (>=5.0.3)", "zope.event", "zope.testing"]
|
||||
testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"]
|
||||
|
||||
[extras]
|
||||
allure = ["allure-pytest"]
|
||||
locust = ["locust"]
|
||||
upload = ["requests-toolbelt", "filetype"]
|
||||
|
||||
[metadata]
|
||||
content-hash = "581cacf33c8afe330e5b6a965d5e16f6266718249cbdfed0d080b7536c5c4590"
|
||||
content-hash = "e47b74393605334573a83551e91effda69586b32c65e1acb468901bf5596374d"
|
||||
python-versions = "^3.6"
|
||||
|
||||
[metadata.files]
|
||||
@@ -631,8 +835,38 @@ black = [
|
||||
{file = "black-19.10b0.tar.gz", hash = "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"},
|
||||
]
|
||||
certifi = [
|
||||
{file = "certifi-2020.4.5.1-py2.py3-none-any.whl", hash = "sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304"},
|
||||
{file = "certifi-2020.4.5.1.tar.gz", hash = "sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519"},
|
||||
{file = "certifi-2020.4.5.2-py2.py3-none-any.whl", hash = "sha256:9cd41137dc19af6a5e03b630eefe7d1f458d964d406342dd3edf625839b944cc"},
|
||||
{file = "certifi-2020.4.5.2.tar.gz", hash = "sha256:5ad7e9a056d25ffa5082862e36f119f7f7cec6457fa07ee2f8c339814b80c9b1"},
|
||||
]
|
||||
cffi = [
|
||||
{file = "cffi-1.14.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1cae98a7054b5c9391eb3249b86e0e99ab1e02bb0cc0575da191aedadbdf4384"},
|
||||
{file = "cffi-1.14.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:cf16e3cf6c0a5fdd9bc10c21687e19d29ad1fe863372b5543deaec1039581a30"},
|
||||
{file = "cffi-1.14.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:f2b0fa0c01d8a0c7483afd9f31d7ecf2d71760ca24499c8697aeb5ca37dc090c"},
|
||||
{file = "cffi-1.14.0-cp27-cp27m-win32.whl", hash = "sha256:99f748a7e71ff382613b4e1acc0ac83bf7ad167fb3802e35e90d9763daba4d78"},
|
||||
{file = "cffi-1.14.0-cp27-cp27m-win_amd64.whl", hash = "sha256:c420917b188a5582a56d8b93bdd8e0f6eca08c84ff623a4c16e809152cd35793"},
|
||||
{file = "cffi-1.14.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:399aed636c7d3749bbed55bc907c3288cb43c65c4389964ad5ff849b6370603e"},
|
||||
{file = "cffi-1.14.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:cab50b8c2250b46fe738c77dbd25ce017d5e6fb35d3407606e7a4180656a5a6a"},
|
||||
{file = "cffi-1.14.0-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:001bf3242a1bb04d985d63e138230802c6c8d4db3668fb545fb5005ddf5bb5ff"},
|
||||
{file = "cffi-1.14.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:e56c744aa6ff427a607763346e4170629caf7e48ead6921745986db3692f987f"},
|
||||
{file = "cffi-1.14.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b8c78301cefcf5fd914aad35d3c04c2b21ce8629b5e4f4e45ae6812e461910fa"},
|
||||
{file = "cffi-1.14.0-cp35-cp35m-win32.whl", hash = "sha256:8c0ffc886aea5df6a1762d0019e9cb05f825d0eec1f520c51be9d198701daee5"},
|
||||
{file = "cffi-1.14.0-cp35-cp35m-win_amd64.whl", hash = "sha256:8a6c688fefb4e1cd56feb6c511984a6c4f7ec7d2a1ff31a10254f3c817054ae4"},
|
||||
{file = "cffi-1.14.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:95cd16d3dee553f882540c1ffe331d085c9e629499ceadfbda4d4fde635f4b7d"},
|
||||
{file = "cffi-1.14.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:66e41db66b47d0d8672d8ed2708ba91b2f2524ece3dee48b5dfb36be8c2f21dc"},
|
||||
{file = "cffi-1.14.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:028a579fc9aed3af38f4892bdcc7390508adabc30c6af4a6e4f611b0c680e6ac"},
|
||||
{file = "cffi-1.14.0-cp36-cp36m-win32.whl", hash = "sha256:cef128cb4d5e0b3493f058f10ce32365972c554572ff821e175dbc6f8ff6924f"},
|
||||
{file = "cffi-1.14.0-cp36-cp36m-win_amd64.whl", hash = "sha256:337d448e5a725bba2d8293c48d9353fc68d0e9e4088d62a9571def317797522b"},
|
||||
{file = "cffi-1.14.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e577934fc5f8779c554639376beeaa5657d54349096ef24abe8c74c5d9c117c3"},
|
||||
{file = "cffi-1.14.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:62ae9af2d069ea2698bf536dcfe1e4eed9090211dbaafeeedf5cb6c41b352f66"},
|
||||
{file = "cffi-1.14.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:14491a910663bf9f13ddf2bc8f60562d6bc5315c1f09c704937ef17293fb85b0"},
|
||||
{file = "cffi-1.14.0-cp37-cp37m-win32.whl", hash = "sha256:c43866529f2f06fe0edc6246eb4faa34f03fe88b64a0a9a942561c8e22f4b71f"},
|
||||
{file = "cffi-1.14.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2089ed025da3919d2e75a4d963d008330c96751127dd6f73c8dc0c65041b4c26"},
|
||||
{file = "cffi-1.14.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3b911c2dbd4f423b4c4fcca138cadde747abdb20d196c4a48708b8a2d32b16dd"},
|
||||
{file = "cffi-1.14.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:7e63cbcf2429a8dbfe48dcc2322d5f2220b77b2e17b7ba023d6166d84655da55"},
|
||||
{file = "cffi-1.14.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:3d311bcc4a41408cf5854f06ef2c5cab88f9fded37a3b95936c9879c1640d4c2"},
|
||||
{file = "cffi-1.14.0-cp38-cp38-win32.whl", hash = "sha256:675686925a9fb403edba0114db74e741d8181683dcf216be697d208857e04ca8"},
|
||||
{file = "cffi-1.14.0-cp38-cp38-win_amd64.whl", hash = "sha256:00789914be39dffba161cfc5be31b55775de5ba2235fe49aa28c148236c4e06b"},
|
||||
{file = "cffi-1.14.0.tar.gz", hash = "sha256:2d384f4a127a15ba701207f7639d94106693b6cd64173d6c8988e2c25f3ac2b6"},
|
||||
]
|
||||
chardet = [
|
||||
{file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"},
|
||||
@@ -646,6 +880,9 @@ colorama = [
|
||||
{file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"},
|
||||
{file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"},
|
||||
]
|
||||
configargparse = [
|
||||
{file = "ConfigArgParse-1.2.3.tar.gz", hash = "sha256:edd17be986d5c1ba2e307150b8e5f5107aba125f3574dddd02c85d5cdcfd37dc"},
|
||||
]
|
||||
contextvars = [
|
||||
{file = "contextvars-2.4.tar.gz", hash = "sha256:f38c908aaa59c14335eeea12abea5f443646216c4e29380d7bf34d2018e2c39e"},
|
||||
]
|
||||
@@ -695,6 +932,110 @@ filetype = [
|
||||
{file = "filetype-1.0.7-py2.py3-none-any.whl", hash = "sha256:353369948bb1c09b8b3ea3d78390b5586e9399bff9aab894a1dff954e31a66f6"},
|
||||
{file = "filetype-1.0.7.tar.gz", hash = "sha256:da393ece8d98b47edf2dd5a85a2c8733e44b769e32c71af4cd96ed8d38d96aa7"},
|
||||
]
|
||||
flask = [
|
||||
{file = "Flask-1.1.2-py2.py3-none-any.whl", hash = "sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"},
|
||||
{file = "Flask-1.1.2.tar.gz", hash = "sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060"},
|
||||
]
|
||||
flask-basicauth = [
|
||||
{file = "Flask-BasicAuth-0.2.0.tar.gz", hash = "sha256:df5ebd489dc0914c224419da059d991eb72988a01cdd4b956d52932ce7d501ff"},
|
||||
]
|
||||
gevent = [
|
||||
{file = "gevent-20.6.2-cp27-cp27m-macosx_10_15_x86_64.whl", hash = "sha256:b03890bbddbae5667f5baad517417056496ff5e92c3c7945b27cc08f55a9fcb2"},
|
||||
{file = "gevent-20.6.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1ea0d34cb78cdf37870be3bfb9330ebda89197bed9e048c14f4a90dec19a33e0"},
|
||||
{file = "gevent-20.6.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:73eb4cf3114fbb5dd801bd0b93941adfa2fa6d99e91976c20a121ea14b8b39b9"},
|
||||
{file = "gevent-20.6.2-cp27-cp27m-win32.whl", hash = "sha256:f41cc8e853ac2252bc58f6feabd74b8aae613e2d19097c5373463122f4dc08f0"},
|
||||
{file = "gevent-20.6.2-cp27-cp27m-win_amd64.whl", hash = "sha256:d3baff87d935a5eeffb0e4f7cd5ffe258d2430cd62aeee2e5396f85da07df435"},
|
||||
{file = "gevent-20.6.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:7d8408854ce892f987305a0e9bf5c051f4ea29453665454396d6afb620c719b6"},
|
||||
{file = "gevent-20.6.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:ea2e4584950186b71d648bde6af40dae4d4c6f43db25a732ec056b27a7a83afe"},
|
||||
{file = "gevent-20.6.2-cp35-cp35m-win32.whl", hash = "sha256:c0f4340e40e0f9dfe93a52a12ddf5b1eeda9bbc89b99bf3b9b23acab0dfae0a4"},
|
||||
{file = "gevent-20.6.2-cp35-cp35m-win_amd64.whl", hash = "sha256:13c74d6784ef5ada2666abf2bb310d27a1d14291f7cac46148f336b19f714d40"},
|
||||
{file = "gevent-20.6.2-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:78bd94f6f2ac366155169df3507068f6381f2ad77625633189ce183f86a57597"},
|
||||
{file = "gevent-20.6.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0b16dd85eddaf6acdad373ce90ed4da09ef466cbc5e0ee5932d13f099929e844"},
|
||||
{file = "gevent-20.6.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:a47556cac07e31b3cef8fd701599b3b1365961fe3736471f41807ffa27c5c848"},
|
||||
{file = "gevent-20.6.2-cp36-cp36m-win32.whl", hash = "sha256:bef18b8bd3b728240b9bbd699737216b793d6c97b482431f69dcbe328ad73692"},
|
||||
{file = "gevent-20.6.2-cp36-cp36m-win_amd64.whl", hash = "sha256:d0a67a20ce325f6a2068e0bd9fbf83db8a5f5ced972ed8ac5c20079a7d98c7d1"},
|
||||
{file = "gevent-20.6.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:b17915b65b49a425115ddc3087484c81b1e47ce38c931d18bb14e453753e4d06"},
|
||||
{file = "gevent-20.6.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ebb8a545112110e3a6edf905ae1556b0538fc148c743aa7d8cfaebbbc23de31d"},
|
||||
{file = "gevent-20.6.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6c864b5604166ac8351e3128a1135b883b9e978fd24afbd75a249dcb42bc8ab5"},
|
||||
{file = "gevent-20.6.2-cp37-cp37m-win32.whl", hash = "sha256:e5ca5ee80a9d9e697c9fc22b4bbce9ad06870f83fc8e7774e5504892ef702476"},
|
||||
{file = "gevent-20.6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:f2a02d9004ccb18edd9eaf6f25da9a7763de41a69754d5e4d872a8cbf8bd0b72"},
|
||||
{file = "gevent-20.6.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:354f932c284fa45826b32f42927d892096cce05671b50b3ff59528230217ad47"},
|
||||
{file = "gevent-20.6.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:67776cb33b638a3c61a0351d9d1e8f33a46b47de619e249de1159892f9ff035c"},
|
||||
{file = "gevent-20.6.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:68764aca061bbbbade43727e797f9c28042f6d90cca5fb6514ef726d43ab00ca"},
|
||||
{file = "gevent-20.6.2-cp38-cp38-win32.whl", hash = "sha256:0f3fbb1703b10609856e5dffb0e358bf5edf57e52dc7cd7226e3f8674fdc0a0f"},
|
||||
{file = "gevent-20.6.2-cp38-cp38-win_amd64.whl", hash = "sha256:a18d8dd9bfa994a22f30adfa0563d80f0809140045c34f85535f422813d25855"},
|
||||
{file = "gevent-20.6.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:9527087984f1659be899b3300d5d61c7c5b01d8beae106aff5160316da8bc56f"},
|
||||
{file = "gevent-20.6.2-pp27-pypy_73-macosx_10_7_x86_64.whl", hash = "sha256:76ef4c6e3332e6f7278142d791b28695adfce39735900fccef2a0f1d894f6b36"},
|
||||
{file = "gevent-20.6.2-pp27-pypy_73-win32.whl", hash = "sha256:3cb2f6978615d52e4e4e667b035c11a7272bb68b14d119faf1b138164b2f354f"},
|
||||
{file = "gevent-20.6.2.tar.gz", hash = "sha256:a23c2abf08e851c988723f6a2996d495f513a2c0dc70f9956af03af8debdb5d1"},
|
||||
]
|
||||
geventhttpclient = [
|
||||
{file = "geventhttpclient-1.4.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:7b7e827418ecc926271111ef9a5f832063c28250487d77292442a94dce040ab8"},
|
||||
{file = "geventhttpclient-1.4.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:6f662227cf8ec2f061d67e9bcc4e2a83ccae4b91c812a0f4a8dd4b239300860f"},
|
||||
{file = "geventhttpclient-1.4.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5c7a6211bd5747edf7e38a489369c510d06cfd293ec56be1bdd2045766075f8b"},
|
||||
{file = "geventhttpclient-1.4.2-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:7e0686068f4dca0148e98957ac6804acb819d4a32886b75e4af8b7a4fafb0729"},
|
||||
{file = "geventhttpclient-1.4.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:8d2874c86012b9c34de7a610b3e7762eca80da7591f945464afe3b024f99ea38"},
|
||||
{file = "geventhttpclient-1.4.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:e089d1613fc30fd631cd82223abd8187bd9f3ccba70a58df38eb8139928c9237"},
|
||||
{file = "geventhttpclient-1.4.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:f2c2d6a8c5973d1ab918443a7739ddc4bb1b3948ca676feccfe6b10076a13275"},
|
||||
{file = "geventhttpclient-1.4.2-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:565dff607131b04b8a2e302065f47be235a2adefe30443401f2dc3d58972d18f"},
|
||||
{file = "geventhttpclient-1.4.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:bcad86491ef10b281f43a93ca65bb65aec6afc7856badc8cb4745daa4b43fe33"},
|
||||
{file = "geventhttpclient-1.4.2-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:e4179375224242a64e965d709282af91491a6de40f2117df81a2a775f94d2bc3"},
|
||||
{file = "geventhttpclient-1.4.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:49e0aed4b7cc7eef09294376c77690528e4a21a37a8a0e99efa940561183a0f5"},
|
||||
{file = "geventhttpclient-1.4.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9324187592cbd66764a28a8f49dafb2bf68a07612bb4adf27a0777a35ba53cb6"},
|
||||
{file = "geventhttpclient-1.4.2-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:b6cbcc500635b228a39c2a0b290059bdc8f7254776b6bc628bd7384ce0446125"},
|
||||
{file = "geventhttpclient-1.4.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:682581949303c175abbaf686df819d403104ecc6b0355108c6cc473cc539a505"},
|
||||
{file = "geventhttpclient-1.4.2-cp35-cp35m-win32.whl", hash = "sha256:3df9cad44fddc775b06f7a9e8bea763bb8198ba426a8ce62bb79cb44bb7e419f"},
|
||||
{file = "geventhttpclient-1.4.2-cp35-cp35m-win_amd64.whl", hash = "sha256:052899e60f63529a5ffc581987fef2893f445a62ebdb5f51f02444b9153b9e00"},
|
||||
{file = "geventhttpclient-1.4.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:edd11d6b22993008a98235f02344f79783d7727f05d4cd4cc638591b2cf00346"},
|
||||
{file = "geventhttpclient-1.4.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a391afadf1d7005d1f584470c5a2b03588c23c25b42ebed6a385ffb1e5deb61b"},
|
||||
{file = "geventhttpclient-1.4.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:80570bf577de010cb3cff704bc9df2d76b3398144e6224e35558a9f3f794f863"},
|
||||
{file = "geventhttpclient-1.4.2-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:df9ce998dbaef4e4aa6d9b2bc129d69c9ec41a71df30808298f6b8cc2e3cee18"},
|
||||
{file = "geventhttpclient-1.4.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:3becac3ec54cc74caadcf87a309343d3298a8ca0ef6d3c4f7ab197be0acefdcb"},
|
||||
{file = "geventhttpclient-1.4.2-cp36-cp36m-win32.whl", hash = "sha256:a2ba13a6dc4343e9be64288fb89c077586350d201945565b5b882431a7cc111e"},
|
||||
{file = "geventhttpclient-1.4.2-cp36-cp36m-win_amd64.whl", hash = "sha256:79a302b9448fee4d2a334278c0cb679195ec0ed4de0832bf46797e90602d5832"},
|
||||
{file = "geventhttpclient-1.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bef49de16b0c4551731294e37a05b55415fc49fa3c4e5b6cfac0d41fd430627d"},
|
||||
{file = "geventhttpclient-1.4.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:a6eb1aa56bc52ba0adb281f7977662db8661b1398866674cf9be559cf23e2765"},
|
||||
{file = "geventhttpclient-1.4.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:dade5b1266e10f78104a4880163b1aca1ace8c1efbf0e71887b9cff78bfbdb2f"},
|
||||
{file = "geventhttpclient-1.4.2-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d09d59902ca62253a48f7a5ffbd6c591cca8a65fe15428a294f600333b891aaa"},
|
||||
{file = "geventhttpclient-1.4.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:b9bf31aed10e40116357f6eb1f3ac997030485ea8afd75fd00644dc6ccba1614"},
|
||||
{file = "geventhttpclient-1.4.2-cp37-cp37m-win32.whl", hash = "sha256:9141b2ce49adb317cf036a70f4543319abfde625b92e780794d806bcc1bcd1de"},
|
||||
{file = "geventhttpclient-1.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:302277ba05f941da34fac3fdd9e0f13693c8460fa82fd8d40aa34151537fc171"},
|
||||
{file = "geventhttpclient-1.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d8f2bbbc0f1cfd8d0b5b1c839be513e32a4d94c79f3b28aed5e0443866ee1ce5"},
|
||||
{file = "geventhttpclient-1.4.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:6018fc296c4d6a1ca0cfdf3a9fb23792e2302cbf5717dd0a25ee0c084bf8216a"},
|
||||
{file = "geventhttpclient-1.4.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:b68fbaff99f8a7701477b83e829b74c0f6d878953dea468cc52601093a4806d4"},
|
||||
{file = "geventhttpclient-1.4.2-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:94bf3480828190cb0cf3fae350b760aa12d9912b8eed5449ddb25867edae31f6"},
|
||||
{file = "geventhttpclient-1.4.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:28e4ef874d4153460c1e29323f543942a6b3be308c5a50c006d412f4f9e7fc9c"},
|
||||
{file = "geventhttpclient-1.4.2-cp38-cp38-win32.whl", hash = "sha256:1dcc1995146edbcb98e6343137ee4444fa5966ae534e5fac647b32357479e93f"},
|
||||
{file = "geventhttpclient-1.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:355417460ce971a01f1ee0b4c53c65505faa0e1cc757ed16d8cdcbc5e66b21ab"},
|
||||
{file = "geventhttpclient-1.4.2-pp27-pypy_73-macosx_10_7_x86_64.whl", hash = "sha256:074f9914ce8320f71ffaa1d48247a5f2d551e0df4a225e50d8cf162128116a6b"},
|
||||
{file = "geventhttpclient-1.4.2-pp27-pypy_73-manylinux1_x86_64.whl", hash = "sha256:71bc17ffab758b800d1ca1c0ac0c1a47aa8dd7e80c88e9c6b454f7082ab03f8a"},
|
||||
{file = "geventhttpclient-1.4.2-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:a5a9e5dc95618bf1d061de6862429f90bb8740b59449a47bfdadd4cc94eebb9f"},
|
||||
{file = "geventhttpclient-1.4.2-pp27-pypy_73-win32.whl", hash = "sha256:3b18bb76b175d36205889e2c33c1746b70ab156392d6d5f382d1b2b349fd53e1"},
|
||||
{file = "geventhttpclient-1.4.2-pp36-pypy36_pp73-macosx_10_7_x86_64.whl", hash = "sha256:dfa24eaf4310fc99c796fafac527e7c839670f15144936ab885b43705f2d6086"},
|
||||
{file = "geventhttpclient-1.4.2-pp36-pypy36_pp73-manylinux1_x86_64.whl", hash = "sha256:86feb2e8f2210af353fb00e85db672007e43dd993f53dab18453b0b230fd0673"},
|
||||
{file = "geventhttpclient-1.4.2-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:d393b8a84dd9edcfb92ebfd35065a19eb589ce082dae4b61222c5835146c81c7"},
|
||||
{file = "geventhttpclient-1.4.2-pp36-pypy36_pp73-win32.whl", hash = "sha256:0271d8ea2d4ad5b3fb753fb1df7e00aadfbe7d50d26fed714b97755f04011864"},
|
||||
{file = "geventhttpclient-1.4.2.tar.gz", hash = "sha256:967b11c4a37032f98c08f58176e4ac8de10473ab0c1f617acb8202d44b97fe21"},
|
||||
]
|
||||
greenlet = [
|
||||
{file = "greenlet-0.4.16-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:80cb0380838bf4e48da6adedb0c7cd060c187bb4a75f67a5aa9ec33689b84872"},
|
||||
{file = "greenlet-0.4.16-cp27-cp27m-win32.whl", hash = "sha256:df7de669cbf21de4b04a3ffc9920bc8426cab4c61365fa84d79bf97401a8bef7"},
|
||||
{file = "greenlet-0.4.16-cp27-cp27m-win_amd64.whl", hash = "sha256:1429dc183b36ec972055e13250d96e174491559433eb3061691b446899b87384"},
|
||||
{file = "greenlet-0.4.16-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:5ea034d040e6ab1d2ae04ab05a3f37dbd719c4dee3804b13903d4cc794b1336e"},
|
||||
{file = "greenlet-0.4.16-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c196a5394c56352e21cb7224739c6dd0075b69dd56f758505951d1d8d68cf8a9"},
|
||||
{file = "greenlet-0.4.16-cp35-cp35m-win32.whl", hash = "sha256:1000038ba0ea9032948e2156a9c15f5686f36945e8f9906e6b8db49f358e7b52"},
|
||||
{file = "greenlet-0.4.16-cp35-cp35m-win_amd64.whl", hash = "sha256:1b805231bfb7b2900a16638c3c8b45c694334c811f84463e52451e00c9412691"},
|
||||
{file = "greenlet-0.4.16-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:e5db19d4a7d41bbeb3dd89b49fc1bc7e6e515b51bbf32589c618655a0ebe0bf0"},
|
||||
{file = "greenlet-0.4.16-cp36-cp36m-win32.whl", hash = "sha256:eac2a3f659d5f41d6bbfb6a97733bc7800ea5e906dc873732e00cebb98cec9e4"},
|
||||
{file = "greenlet-0.4.16-cp36-cp36m-win_amd64.whl", hash = "sha256:7eed31f4efc8356e200568ba05ad645525f1fbd8674f1e5be61a493e715e3873"},
|
||||
{file = "greenlet-0.4.16-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:682328aa576ec393c1872615bcb877cf32d800d4a2f150e1a5dc7e56644010b1"},
|
||||
{file = "greenlet-0.4.16-cp37-cp37m-win32.whl", hash = "sha256:3a35e33902b2e6079949feed7a2dafa5ac6f019da97bd255842bb22de3c11bf5"},
|
||||
{file = "greenlet-0.4.16-cp37-cp37m-win_amd64.whl", hash = "sha256:b0b2a984bbfc543d144d88caad6cc7ff4a71be77102014bd617bd88cfb038727"},
|
||||
{file = "greenlet-0.4.16-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:d83c1d38658b0f81c282b41238092ed89d8f93c6e342224ab73fb39e16848721"},
|
||||
{file = "greenlet-0.4.16-cp38-cp38-win32.whl", hash = "sha256:e695ac8c3efe124d998230b219eb51afb6ef10524a50b3c45109c4b77a8a3a92"},
|
||||
{file = "greenlet-0.4.16-cp38-cp38-win_amd64.whl", hash = "sha256:133ba06bad4e5f2f8bf6a0ac434e0fd686df749a86b3478903b92ec3a9c0c90b"},
|
||||
{file = "greenlet-0.4.16.tar.gz", hash = "sha256:6e06eac722676797e8fce4adb8ad3dc57a1bb3adfb0dd3fdf8306c055a38456c"},
|
||||
]
|
||||
h11 = [
|
||||
{file = "h11-0.9.0-py2.py3-none-any.whl", hash = "sha256:4bc6d6a1238b7615b266ada57e0618568066f57dd6fa967d1290ec9309b2f2f1"},
|
||||
{file = "h11-0.9.0.tar.gz", hash = "sha256:33d4bca7be0fa039f4e84d50ab00531047e53d6ee8ffbc83501ea602c169cae1"},
|
||||
@@ -732,8 +1073,12 @@ immutables = [
|
||||
{file = "immutables-0.14.tar.gz", hash = "sha256:a0a1cc238b678455145bae291d8426f732f5255537ed6a5b7645949704c70a78"},
|
||||
]
|
||||
importlib-metadata = [
|
||||
{file = "importlib_metadata-1.6.0-py2.py3-none-any.whl", hash = "sha256:2a688cbaa90e0cc587f1df48bdc97a6eadccdcd9c35fb3f976a09e3b5016d90f"},
|
||||
{file = "importlib_metadata-1.6.0.tar.gz", hash = "sha256:34513a8a0c4962bc66d35b359558fd8a5e10cd472d37aec5f66858addef32c1e"},
|
||||
{file = "importlib_metadata-1.6.1-py2.py3-none-any.whl", hash = "sha256:15ec6c0fd909e893e3a08b3a7c76ecb149122fb14b7efe1199ddd4c7c57ea958"},
|
||||
{file = "importlib_metadata-1.6.1.tar.gz", hash = "sha256:0505dd08068cfec00f53a74a0ad927676d7757da81b7436a6eefe4c7cf75c545"},
|
||||
]
|
||||
itsdangerous = [
|
||||
{file = "itsdangerous-1.1.0-py2.py3-none-any.whl", hash = "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"},
|
||||
{file = "itsdangerous-1.1.0.tar.gz", hash = "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19"},
|
||||
]
|
||||
jinja2 = [
|
||||
{file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"},
|
||||
@@ -743,6 +1088,10 @@ jmespath = [
|
||||
{file = "jmespath-0.9.5-py2.py3-none-any.whl", hash = "sha256:695cb76fa78a10663425d5b73ddc5714eb711157e52704d69be03b1a02ba4fec"},
|
||||
{file = "jmespath-0.9.5.tar.gz", hash = "sha256:cca55c8d153173e21baa59983015ad0daf603f9cb799904ff057bfb8ff8dc2d9"},
|
||||
]
|
||||
locust = [
|
||||
{file = "locust-1.0.3-py3-none-any.whl", hash = "sha256:b80deea54f470d8fd61a8f610d87041ce908924fe3fca09700376de49aa89195"},
|
||||
{file = "locust-1.0.3.tar.gz", hash = "sha256:7c2e850a84275b6f7c5ad4a8abde3488df94c08d3b52e619d9c71cc6b8c853cb"},
|
||||
]
|
||||
loguru = [
|
||||
{file = "loguru-0.4.1-py3-none-any.whl", hash = "sha256:074b3caa6748452c1e4f2b302093c94b65d5a4c5a4d7743636b4121e06437b0e"},
|
||||
{file = "loguru-0.4.1.tar.gz", hash = "sha256:a6101fd435ac89ba5205a105a26a6ede9e4ddbb4408a6e167852efca47806d11"},
|
||||
@@ -778,8 +1127,28 @@ markupsafe = [
|
||||
{file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"},
|
||||
]
|
||||
more-itertools = [
|
||||
{file = "more-itertools-8.3.0.tar.gz", hash = "sha256:558bb897a2232f5e4f8e2399089e35aecb746e1f9191b6584a151647e89267be"},
|
||||
{file = "more_itertools-8.3.0-py3-none-any.whl", hash = "sha256:7818f596b1e87be009031c7653d01acc46ed422e6656b394b0f765ce66ed4982"},
|
||||
{file = "more-itertools-8.4.0.tar.gz", hash = "sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5"},
|
||||
{file = "more_itertools-8.4.0-py3-none-any.whl", hash = "sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2"},
|
||||
]
|
||||
msgpack = [
|
||||
{file = "msgpack-1.0.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:cec8bf10981ed70998d98431cd814db0ecf3384e6b113366e7f36af71a0fca08"},
|
||||
{file = "msgpack-1.0.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:aa5c057eab4f40ec47ea6f5a9825846be2ff6bf34102c560bad5cad5a677c5be"},
|
||||
{file = "msgpack-1.0.0-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:4233b7f86c1208190c78a525cd3828ca1623359ef48f78a6fea4b91bb995775a"},
|
||||
{file = "msgpack-1.0.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:b3758dfd3423e358bbb18a7cccd1c74228dffa7a697e5be6cb9535de625c0dbf"},
|
||||
{file = "msgpack-1.0.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:25b3bc3190f3d9d965b818123b7752c5dfb953f0d774b454fd206c18fe384fb8"},
|
||||
{file = "msgpack-1.0.0-cp36-cp36m-win32.whl", hash = "sha256:e7bbdd8e2b277b77782f3ce34734b0dfde6cbe94ddb74de8d733d603c7f9e2b1"},
|
||||
{file = "msgpack-1.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:5dba6d074fac9b24f29aaf1d2d032306c27f04187651511257e7831733293ec2"},
|
||||
{file = "msgpack-1.0.0-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:908944e3f038bca67fcfedb7845c4a257c7749bf9818632586b53bcf06ba4b97"},
|
||||
{file = "msgpack-1.0.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:db685187a415f51d6b937257474ca72199f393dad89534ebbdd7d7a3b000080e"},
|
||||
{file = "msgpack-1.0.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ea41c9219c597f1d2bf6b374d951d310d58684b5de9dc4bd2976db9e1e22c140"},
|
||||
{file = "msgpack-1.0.0-cp37-cp37m-win32.whl", hash = "sha256:e35b051077fc2f3ce12e7c6a34cf309680c63a842db3a0616ea6ed25ad20d272"},
|
||||
{file = "msgpack-1.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:5bea44181fc8e18eed1d0cd76e355073f00ce232ff9653a0ae88cb7d9e643322"},
|
||||
{file = "msgpack-1.0.0-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:c901e8058dd6653307906c5f157f26ed09eb94a850dddd989621098d347926ab"},
|
||||
{file = "msgpack-1.0.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:271b489499a43af001a2e42f42d876bb98ccaa7e20512ff37ca78c8e12e68f84"},
|
||||
{file = "msgpack-1.0.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7a22c965588baeb07242cb561b63f309db27a07382825fc98aecaf0827c1538e"},
|
||||
{file = "msgpack-1.0.0-cp38-cp38-win32.whl", hash = "sha256:002a0d813e1f7b60da599bdf969e632074f9eec1b96cbed8fb0973a63160a408"},
|
||||
{file = "msgpack-1.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:39c54fdebf5fa4dda733369012c59e7d085ebdfe35b6cf648f09d16708f1be5d"},
|
||||
{file = "msgpack-1.0.0.tar.gz", hash = "sha256:9534d5cc480d4aff720233411a1f765be90885750b07df772380b34c10ecb5c0"},
|
||||
]
|
||||
packaging = [
|
||||
{file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"},
|
||||
@@ -793,9 +1162,26 @@ pluggy = [
|
||||
{file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
|
||||
{file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
|
||||
]
|
||||
psutil = [
|
||||
{file = "psutil-5.7.0-cp27-none-win32.whl", hash = "sha256:298af2f14b635c3c7118fd9183843f4e73e681bb6f01e12284d4d70d48a60953"},
|
||||
{file = "psutil-5.7.0-cp27-none-win_amd64.whl", hash = "sha256:75e22717d4dbc7ca529ec5063000b2b294fc9a367f9c9ede1f65846c7955fd38"},
|
||||
{file = "psutil-5.7.0-cp35-cp35m-win32.whl", hash = "sha256:f344ca230dd8e8d5eee16827596f1c22ec0876127c28e800d7ae20ed44c4b310"},
|
||||
{file = "psutil-5.7.0-cp35-cp35m-win_amd64.whl", hash = "sha256:e2d0c5b07c6fe5a87fa27b7855017edb0d52ee73b71e6ee368fae268605cc3f5"},
|
||||
{file = "psutil-5.7.0-cp36-cp36m-win32.whl", hash = "sha256:a02f4ac50d4a23253b68233b07e7cdb567bd025b982d5cf0ee78296990c22d9e"},
|
||||
{file = "psutil-5.7.0-cp36-cp36m-win_amd64.whl", hash = "sha256:1413f4158eb50e110777c4f15d7c759521703bd6beb58926f1d562da40180058"},
|
||||
{file = "psutil-5.7.0-cp37-cp37m-win32.whl", hash = "sha256:d008ddc00c6906ec80040d26dc2d3e3962109e40ad07fd8a12d0284ce5e0e4f8"},
|
||||
{file = "psutil-5.7.0-cp37-cp37m-win_amd64.whl", hash = "sha256:73f35ab66c6c7a9ce82ba44b1e9b1050be2a80cd4dcc3352cc108656b115c74f"},
|
||||
{file = "psutil-5.7.0-cp38-cp38-win32.whl", hash = "sha256:60b86f327c198561f101a92be1995f9ae0399736b6eced8f24af41ec64fb88d4"},
|
||||
{file = "psutil-5.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:d84029b190c8a66a946e28b4d3934d2ca1528ec94764b180f7d6ea57b0e75e26"},
|
||||
{file = "psutil-5.7.0.tar.gz", hash = "sha256:685ec16ca14d079455892f25bd124df26ff9137664af445563c1bd36629b5e0e"},
|
||||
]
|
||||
py = [
|
||||
{file = "py-1.8.1-py2.py3-none-any.whl", hash = "sha256:c20fdd83a5dbc0af9efd622bee9a5564e278f6380fffcacc43ba6f43db2813b0"},
|
||||
{file = "py-1.8.1.tar.gz", hash = "sha256:5e27081401262157467ad6e7f851b7aa402c5852dbcb3dae06768434de5752aa"},
|
||||
{file = "py-1.8.2-py2.py3-none-any.whl", hash = "sha256:a673fa23d7000440cc885c17dbd34fafcb7d7a6e230b29f6766400de36a33c44"},
|
||||
{file = "py-1.8.2.tar.gz", hash = "sha256:f3b3a4c36512a4c4f024041ab51866f11761cc169670204b235f6b20523d4e6b"},
|
||||
]
|
||||
pycparser = [
|
||||
{file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"},
|
||||
{file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"},
|
||||
]
|
||||
pydantic = [
|
||||
{file = "pydantic-1.5.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2a6904e9f18dea58f76f16b95cba6a2f20b72d787abd84ecd67ebc526e61dce6"},
|
||||
@@ -821,8 +1207,8 @@ pyparsing = [
|
||||
{file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
|
||||
]
|
||||
pytest = [
|
||||
{file = "pytest-5.4.2-py3-none-any.whl", hash = "sha256:95c710d0a72d91c13fae35dce195633c929c3792f54125919847fdcdf7caa0d3"},
|
||||
{file = "pytest-5.4.2.tar.gz", hash = "sha256:eb2b5e935f6a019317e455b6da83dd8650ac9ffd2ee73a7b657a30873d67a698"},
|
||||
{file = "pytest-5.4.3-py3-none-any.whl", hash = "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1"},
|
||||
{file = "pytest-5.4.3.tar.gz", hash = "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8"},
|
||||
]
|
||||
pytest-html = [
|
||||
{file = "pytest-html-2.1.1.tar.gz", hash = "sha256:6a4ac391e105e391208e3eb9bd294a60dd336447fd8e1acddff3a6de7f4e57c5"},
|
||||
@@ -845,32 +1231,62 @@ pyyaml = [
|
||||
{file = "PyYAML-5.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee"},
|
||||
{file = "PyYAML-5.3.1.tar.gz", hash = "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d"},
|
||||
]
|
||||
pyzmq = [
|
||||
{file = "pyzmq-19.0.1-cp27-cp27m-macosx_10_9_intel.whl", hash = "sha256:58688a2dfa044fad608a8e70ba8d019d0b872ec2acd75b7b5e37da8905605891"},
|
||||
{file = "pyzmq-19.0.1-cp27-cp27m-win32.whl", hash = "sha256:87c78f6936e2654397ca2979c1d323ee4a889eef536cc77a938c6b5be33351a7"},
|
||||
{file = "pyzmq-19.0.1-cp27-cp27m-win_amd64.whl", hash = "sha256:97b6255ae77328d0e80593681826a0479cb7bac0ba8251b4dd882f5145a2293a"},
|
||||
{file = "pyzmq-19.0.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:15b4cb21118f4589c4db8be4ac12b21c8b4d0d42b3ee435d47f686c32fe2e91f"},
|
||||
{file = "pyzmq-19.0.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:931339ac2000d12fe212e64f98ce291e81a7ec6c73b125f17cf08415b753c087"},
|
||||
{file = "pyzmq-19.0.1-cp35-cp35m-macosx_10_9_intel.whl", hash = "sha256:2a88b8fabd9cc35bd59194a7723f3122166811ece8b74018147a4ed8489e6421"},
|
||||
{file = "pyzmq-19.0.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:bafd651b557dd81d89bd5f9c678872f3e7b7255c1c751b78d520df2caac80230"},
|
||||
{file = "pyzmq-19.0.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:8952f6ba6ae598e792703f3134af5a01af8f5c7cf07e9a148f05a12b02412cea"},
|
||||
{file = "pyzmq-19.0.1-cp35-cp35m-win32.whl", hash = "sha256:54aa24fd60c4262286fc64ca632f9e747c7cc3a3a1144827490e1dc9b8a3a960"},
|
||||
{file = "pyzmq-19.0.1-cp35-cp35m-win_amd64.whl", hash = "sha256:dcbc3f30c11c60d709c30a213dc56e88ac016fe76ac6768e64717bd976072566"},
|
||||
{file = "pyzmq-19.0.1-cp36-cp36m-macosx_10_9_intel.whl", hash = "sha256:6ca519309703e95d55965735a667809bbb65f52beda2fdb6312385d3e7a6d234"},
|
||||
{file = "pyzmq-19.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:4ee0bfd82077a3ff11c985369529b12853a4064320523f8e5079b630f9551448"},
|
||||
{file = "pyzmq-19.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ba6f24431b569aec674ede49cad197cad59571c12deed6ad8e3c596da8288217"},
|
||||
{file = "pyzmq-19.0.1-cp36-cp36m-win32.whl", hash = "sha256:956775444d01331c7eb412c5fb9bb62130dfaac77e09f32764ea1865234e2ca9"},
|
||||
{file = "pyzmq-19.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b08780e3a55215873b3b8e6e7ca8987f14c902a24b6ac081b344fd430d6ca7cd"},
|
||||
{file = "pyzmq-19.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:21f7d91f3536f480cb2c10d0756bfa717927090b7fb863e6323f766e5461ee1c"},
|
||||
{file = "pyzmq-19.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:bfff5ffff051f5aa47ba3b379d87bd051c3196b0c8a603e8b7ed68a6b4f217ec"},
|
||||
{file = "pyzmq-19.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:07fb8fe6826a229dada876956590135871de60dbc7de5a18c3bcce2ed1f03c98"},
|
||||
{file = "pyzmq-19.0.1-cp37-cp37m-win32.whl", hash = "sha256:342fb8a1dddc569bc361387782e8088071593e7eaf3e3ecf7d6bd4976edff112"},
|
||||
{file = "pyzmq-19.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:faee2604f279d31312bc455f3d024f160b6168b9c1dde22bf62d8c88a4deca8e"},
|
||||
{file = "pyzmq-19.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5b9d21fc56c8aacd2e6d14738021a9d64f3f69b30578a99325a728e38a349f85"},
|
||||
{file = "pyzmq-19.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:af0c02cf49f4f9eedf38edb4f3b6bb621d83026e7e5d76eb5526cc5333782fd6"},
|
||||
{file = "pyzmq-19.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5f1f2eb22aab606f808163eb1d537ac9a0ba4283fbeb7a62eb48d9103cf015c2"},
|
||||
{file = "pyzmq-19.0.1-cp38-cp38-win32.whl", hash = "sha256:f9d7e742fb0196992477415bb34366c12e9bb9a0699b8b3f221ff93b213d7bec"},
|
||||
{file = "pyzmq-19.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:5b99c2ae8089ef50223c28bac57510c163bfdff158c9e90764f812b94e69a0e6"},
|
||||
{file = "pyzmq-19.0.1-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:cf5d689ba9513b9753959164cf500079383bc18859f58bf8ce06d8d4bef2b054"},
|
||||
{file = "pyzmq-19.0.1-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:aaa8b40b676576fd7806839a5de8e6d5d1b74981e6376d862af6c117af2a3c10"},
|
||||
{file = "pyzmq-19.0.1.tar.gz", hash = "sha256:13a5638ab24d628a6ade8f794195e1a1acd573496c3b85af2f1183603b7bf5e0"},
|
||||
]
|
||||
regex = [
|
||||
{file = "regex-2020.5.14-cp27-cp27m-win32.whl", hash = "sha256:e565569fc28e3ba3e475ec344d87ed3cd8ba2d575335359749298a0899fe122e"},
|
||||
{file = "regex-2020.5.14-cp27-cp27m-win_amd64.whl", hash = "sha256:d466967ac8e45244b9dfe302bbe5e3337f8dc4dec8d7d10f5e950d83b140d33a"},
|
||||
{file = "regex-2020.5.14-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:27ff7325b297fb6e5ebb70d10437592433601c423f5acf86e5bc1ee2919b9561"},
|
||||
{file = "regex-2020.5.14-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ea55b80eb0d1c3f1d8d784264a6764f931e172480a2f1868f2536444c5f01e01"},
|
||||
{file = "regex-2020.5.14-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:c9bce6e006fbe771a02bda468ec40ffccbf954803b470a0345ad39c603402577"},
|
||||
{file = "regex-2020.5.14-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:d881c2e657c51d89f02ae4c21d9adbef76b8325fe4d5cf0e9ad62f850f3a98fd"},
|
||||
{file = "regex-2020.5.14-cp36-cp36m-win32.whl", hash = "sha256:99568f00f7bf820c620f01721485cad230f3fb28f57d8fbf4a7967ec2e446994"},
|
||||
{file = "regex-2020.5.14-cp36-cp36m-win_amd64.whl", hash = "sha256:70c14743320a68c5dac7fc5a0f685be63bc2024b062fe2aaccc4acc3d01b14a1"},
|
||||
{file = "regex-2020.5.14-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:a7c37f048ec3920783abab99f8f4036561a174f1314302ccfa4e9ad31cb00eb4"},
|
||||
{file = "regex-2020.5.14-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:89d76ce33d3266173f5be80bd4efcbd5196cafc34100fdab814f9b228dee0fa4"},
|
||||
{file = "regex-2020.5.14-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:51f17abbe973c7673a61863516bdc9c0ef467407a940f39501e786a07406699c"},
|
||||
{file = "regex-2020.5.14-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:ce5cc53aa9fbbf6712e92c7cf268274eaff30f6bd12a0754e8133d85a8fb0f5f"},
|
||||
{file = "regex-2020.5.14-cp37-cp37m-win32.whl", hash = "sha256:8044d1c085d49673aadb3d7dc20ef5cb5b030c7a4fa253a593dda2eab3059929"},
|
||||
{file = "regex-2020.5.14-cp37-cp37m-win_amd64.whl", hash = "sha256:c2062c7d470751b648f1cacc3f54460aebfc261285f14bc6da49c6943bd48bdd"},
|
||||
{file = "regex-2020.5.14-cp38-cp38-manylinux1_i686.whl", hash = "sha256:329ba35d711e3428db6b45a53b1b13a0a8ba07cbbcf10bbed291a7da45f106c3"},
|
||||
{file = "regex-2020.5.14-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:579ea215c81d18da550b62ff97ee187b99f1b135fd894a13451e00986a080cad"},
|
||||
{file = "regex-2020.5.14-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:3a9394197664e35566242686d84dfd264c07b20f93514e2e09d3c2b3ffdf78fe"},
|
||||
{file = "regex-2020.5.14-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ce367d21f33e23a84fb83a641b3834dd7dd8e9318ad8ff677fbfae5915a239f7"},
|
||||
{file = "regex-2020.5.14-cp38-cp38-win32.whl", hash = "sha256:1386e75c9d1574f6aa2e4eb5355374c8e55f9aac97e224a8a5a6abded0f9c927"},
|
||||
{file = "regex-2020.5.14-cp38-cp38-win_amd64.whl", hash = "sha256:7e61be8a2900897803c293247ef87366d5df86bf701083b6c43119c7c6c99108"},
|
||||
{file = "regex-2020.5.14.tar.gz", hash = "sha256:ce450ffbfec93821ab1fea94779a8440e10cf63819be6e176eb1973a6017aff5"},
|
||||
{file = "regex-2020.6.8-cp27-cp27m-win32.whl", hash = "sha256:fbff901c54c22425a5b809b914a3bfaf4b9570eee0e5ce8186ac71eb2025191c"},
|
||||
{file = "regex-2020.6.8-cp27-cp27m-win_amd64.whl", hash = "sha256:112e34adf95e45158c597feea65d06a8124898bdeac975c9087fe71b572bd938"},
|
||||
{file = "regex-2020.6.8-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:92d8a043a4241a710c1cf7593f5577fbb832cf6c3a00ff3fc1ff2052aff5dd89"},
|
||||
{file = "regex-2020.6.8-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:bae83f2a56ab30d5353b47f9b2a33e4aac4de9401fb582b55c42b132a8ac3868"},
|
||||
{file = "regex-2020.6.8-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:b2ba0f78b3ef375114856cbdaa30559914d081c416b431f2437f83ce4f8b7f2f"},
|
||||
{file = "regex-2020.6.8-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:95fa7726d073c87141f7bbfb04c284901f8328e2d430eeb71b8ffdd5742a5ded"},
|
||||
{file = "regex-2020.6.8-cp36-cp36m-win32.whl", hash = "sha256:e3cdc9423808f7e1bb9c2e0bdb1c9dc37b0607b30d646ff6faf0d4e41ee8fee3"},
|
||||
{file = "regex-2020.6.8-cp36-cp36m-win_amd64.whl", hash = "sha256:c78e66a922de1c95a208e4ec02e2e5cf0bb83a36ceececc10a72841e53fbf2bd"},
|
||||
{file = "regex-2020.6.8-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:08997a37b221a3e27d68ffb601e45abfb0093d39ee770e4257bd2f5115e8cb0a"},
|
||||
{file = "regex-2020.6.8-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2f6f211633ee8d3f7706953e9d3edc7ce63a1d6aad0be5dcee1ece127eea13ae"},
|
||||
{file = "regex-2020.6.8-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:55b4c25cbb3b29f8d5e63aeed27b49fa0f8476b0d4e1b3171d85db891938cc3a"},
|
||||
{file = "regex-2020.6.8-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:89cda1a5d3e33ec9e231ece7307afc101b5217523d55ef4dc7fb2abd6de71ba3"},
|
||||
{file = "regex-2020.6.8-cp37-cp37m-win32.whl", hash = "sha256:690f858d9a94d903cf5cada62ce069b5d93b313d7d05456dbcd99420856562d9"},
|
||||
{file = "regex-2020.6.8-cp37-cp37m-win_amd64.whl", hash = "sha256:1700419d8a18c26ff396b3b06ace315b5f2a6e780dad387e4c48717a12a22c29"},
|
||||
{file = "regex-2020.6.8-cp38-cp38-manylinux1_i686.whl", hash = "sha256:654cb773b2792e50151f0e22be0f2b6e1c3a04c5328ff1d9d59c0398d37ef610"},
|
||||
{file = "regex-2020.6.8-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:52e1b4bef02f4040b2fd547357a170fc1146e60ab310cdbdd098db86e929b387"},
|
||||
{file = "regex-2020.6.8-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:cf59bbf282b627130f5ba68b7fa3abdb96372b24b66bdf72a4920e8153fc7910"},
|
||||
{file = "regex-2020.6.8-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:5aaa5928b039ae440d775acea11d01e42ff26e1561c0ffcd3d805750973c6baf"},
|
||||
{file = "regex-2020.6.8-cp38-cp38-win32.whl", hash = "sha256:97712e0d0af05febd8ab63d2ef0ab2d0cd9deddf4476f7aa153f76feef4b2754"},
|
||||
{file = "regex-2020.6.8-cp38-cp38-win_amd64.whl", hash = "sha256:6ad8663c17db4c5ef438141f99e291c4d4edfeaacc0ce28b5bba2b0bf273d9b5"},
|
||||
{file = "regex-2020.6.8.tar.gz", hash = "sha256:e9b64e609d37438f7d6e68c2546d2cb8062f3adb27e6336bc129b51be20773ac"},
|
||||
]
|
||||
requests = [
|
||||
{file = "requests-2.23.0-py2.py3-none-any.whl", hash = "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee"},
|
||||
{file = "requests-2.23.0.tar.gz", hash = "sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6"},
|
||||
{file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"},
|
||||
{file = "requests-2.24.0.tar.gz", hash = "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b"},
|
||||
]
|
||||
requests-toolbelt = [
|
||||
{file = "requests-toolbelt-0.9.1.tar.gz", hash = "sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0"},
|
||||
@@ -934,8 +1350,8 @@ uvloop = [
|
||||
{file = "uvloop-0.14.0.tar.gz", hash = "sha256:123ac9c0c7dd71464f58f1b4ee0bbd81285d96cdda8bc3519281b8973e3a461e"},
|
||||
]
|
||||
wcwidth = [
|
||||
{file = "wcwidth-0.1.9-py2.py3-none-any.whl", hash = "sha256:cafe2186b3c009a04067022ce1dcd79cb38d8d65ee4f4791b8888d6599d1bbe1"},
|
||||
{file = "wcwidth-0.1.9.tar.gz", hash = "sha256:ee73862862a156bf77ff92b09034fc4825dd3af9cf81bc5b360668d425f3c5f1"},
|
||||
{file = "wcwidth-0.2.4-py2.py3-none-any.whl", hash = "sha256:79375666b9954d4a1a10739315816324c3e73110af9d0e102d906fdb0aec009f"},
|
||||
{file = "wcwidth-0.2.4.tar.gz", hash = "sha256:8c6b5b6ee1360b842645f336d9e5d68c55817c26d3050f46b235ef2bc650e48f"},
|
||||
]
|
||||
websockets = [
|
||||
{file = "websockets-8.0.2-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:e906128532a14b9d264a43eb48f9b3080d53a9bda819ab45bf56b8039dc606ac"},
|
||||
@@ -950,6 +1366,10 @@ websockets = [
|
||||
{file = "websockets-8.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:049e694abe33f8a1d99969fee7bfc0ae6761f7fd5f297c58ea933b27dd6805f2"},
|
||||
{file = "websockets-8.0.2.tar.gz", hash = "sha256:882a7266fa867a2ebb2c0baaa0f9159cabf131cf18c1b4270d79ad42f9208dc5"},
|
||||
]
|
||||
werkzeug = [
|
||||
{file = "Werkzeug-1.0.1-py2.py3-none-any.whl", hash = "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43"},
|
||||
{file = "Werkzeug-1.0.1.tar.gz", hash = "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"},
|
||||
]
|
||||
win32-setctime = [
|
||||
{file = "win32_setctime-1.0.1-py3-none-any.whl", hash = "sha256:568fd636c68350bcc54755213fe01966fe0a6c90b386c0776425944a0382abef"},
|
||||
{file = "win32_setctime-1.0.1.tar.gz", hash = "sha256:b47e5023ec7f0b4962950902b15bc56464a380d869f59d27dbf9ab423b23e8f9"},
|
||||
@@ -958,3 +1378,49 @@ zipp = [
|
||||
{file = "zipp-3.1.0-py3-none-any.whl", hash = "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b"},
|
||||
{file = "zipp-3.1.0.tar.gz", hash = "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96"},
|
||||
]
|
||||
"zope.event" = [
|
||||
{file = "zope.event-4.4-py2.py3-none-any.whl", hash = "sha256:d8e97d165fd5a0997b45f5303ae11ea3338becfe68c401dd88ffd2113fe5cae7"},
|
||||
{file = "zope.event-4.4.tar.gz", hash = "sha256:69c27debad9bdacd9ce9b735dad382142281ac770c4a432b533d6d65c4614bcf"},
|
||||
]
|
||||
"zope.interface" = [
|
||||
{file = "zope.interface-5.1.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:645a7092b77fdbc3f68d3cc98f9d3e71510e419f54019d6e282328c0dd140dcd"},
|
||||
{file = "zope.interface-5.1.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:d1fe9d7d09bb07228650903d6a9dc48ea649e3b8c69b1d263419cc722b3938e8"},
|
||||
{file = "zope.interface-5.1.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:a744132d0abaa854d1aad50ba9bc64e79c6f835b3e92521db4235a1991176813"},
|
||||
{file = "zope.interface-5.1.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:461d4339b3b8f3335d7e2c90ce335eb275488c587b61aca4b305196dde2ff086"},
|
||||
{file = "zope.interface-5.1.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:269b27f60bcf45438e8683269f8ecd1235fa13e5411de93dae3b9ee4fe7f7bc7"},
|
||||
{file = "zope.interface-5.1.0-cp27-cp27m-win32.whl", hash = "sha256:6874367586c020705a44eecdad5d6b587c64b892e34305bb6ed87c9bbe22a5e9"},
|
||||
{file = "zope.interface-5.1.0-cp27-cp27m-win_amd64.whl", hash = "sha256:8149ded7f90154fdc1a40e0c8975df58041a6f693b8f7edcd9348484e9dc17fe"},
|
||||
{file = "zope.interface-5.1.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:0103cba5ed09f27d2e3de7e48bb320338592e2fabc5ce1432cf33808eb2dfd8b"},
|
||||
{file = "zope.interface-5.1.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:b0becb75418f8a130e9d465e718316cd17c7a8acce6fe8fe07adc72762bee425"},
|
||||
{file = "zope.interface-5.1.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:fb55c182a3f7b84c1a2d6de5fa7b1a05d4660d866b91dbf8d74549c57a1499e8"},
|
||||
{file = "zope.interface-5.1.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:4f98f70328bc788c86a6a1a8a14b0ea979f81ae6015dd6c72978f1feff70ecda"},
|
||||
{file = "zope.interface-5.1.0-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:af2c14efc0bb0e91af63d00080ccc067866fb8cbbaca2b0438ab4105f5e0f08d"},
|
||||
{file = "zope.interface-5.1.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:f68bf937f113b88c866d090fea0bc52a098695173fc613b055a17ff0cf9683b6"},
|
||||
{file = "zope.interface-5.1.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:d7804f6a71fc2dda888ef2de266727ec2f3915373d5a785ed4ddc603bbc91e08"},
|
||||
{file = "zope.interface-5.1.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:74bf0a4f9091131de09286f9a605db449840e313753949fe07c8d0fe7659ad1e"},
|
||||
{file = "zope.interface-5.1.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:ba4261c8ad00b49d48bbb3b5af388bb7576edfc0ca50a49c11dcb77caa1d897e"},
|
||||
{file = "zope.interface-5.1.0-cp35-cp35m-win32.whl", hash = "sha256:ebb4e637a1fb861c34e48a00d03cffa9234f42bef923aec44e5625ffb9a8e8f9"},
|
||||
{file = "zope.interface-5.1.0-cp35-cp35m-win_amd64.whl", hash = "sha256:911714b08b63d155f9c948da2b5534b223a1a4fc50bb67139ab68b277c938578"},
|
||||
{file = "zope.interface-5.1.0-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:e74671e43ed4569fbd7989e5eecc7d06dc134b571872ab1d5a88f4a123814e9f"},
|
||||
{file = "zope.interface-5.1.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:b1d2ed1cbda2ae107283befd9284e650d840f8f7568cb9060b5466d25dc48975"},
|
||||
{file = "zope.interface-5.1.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ef739fe89e7f43fb6494a43b1878a36273e5924869ba1d866f752c5812ae8d58"},
|
||||
{file = "zope.interface-5.1.0-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:eb9b92f456ff3ec746cd4935b73c1117538d6124b8617bc0fe6fda0b3816e345"},
|
||||
{file = "zope.interface-5.1.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:dcefc97d1daf8d55199420e9162ab584ed0893a109f45e438b9794ced44c9fd0"},
|
||||
{file = "zope.interface-5.1.0-cp36-cp36m-win32.whl", hash = "sha256:f40db0e02a8157d2b90857c24d89b6310f9b6c3642369852cdc3b5ac49b92afc"},
|
||||
{file = "zope.interface-5.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:14415d6979356629f1c386c8c4249b4d0082f2ea7f75871ebad2e29584bd16c5"},
|
||||
{file = "zope.interface-5.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5e86c66a6dea8ab6152e83b0facc856dc4d435fe0f872f01d66ce0a2131b7f1d"},
|
||||
{file = "zope.interface-5.1.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:39106649c3082972106f930766ae23d1464a73b7d30b3698c986f74bf1256a34"},
|
||||
{file = "zope.interface-5.1.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:8cccf7057c7d19064a9e27660f5aec4e5c4001ffcf653a47531bde19b5aa2a8a"},
|
||||
{file = "zope.interface-5.1.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:562dccd37acec149458c1791da459f130c6cf8902c94c93b8d47c6337b9fb826"},
|
||||
{file = "zope.interface-5.1.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:da2844fba024dd58eaa712561da47dcd1e7ad544a257482392472eae1c86d5e5"},
|
||||
{file = "zope.interface-5.1.0-cp37-cp37m-win32.whl", hash = "sha256:1ae4693ccee94c6e0c88a4568fb3b34af8871c60f5ba30cf9f94977ed0e53ddd"},
|
||||
{file = "zope.interface-5.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:dd98c436a1fc56f48c70882cc243df89ad036210d871c7427dc164b31500dc11"},
|
||||
{file = "zope.interface-5.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b87ed2dc05cb835138f6a6e3595593fea3564d712cb2eb2de963a41fd35758c"},
|
||||
{file = "zope.interface-5.1.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:558a20a0845d1a5dc6ff87cd0f63d7dac982d7c3be05d2ffb6322a87c17fa286"},
|
||||
{file = "zope.interface-5.1.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7b726194f938791a6691c7592c8b9e805fc6d1b9632a833b9c0640828cd49cbc"},
|
||||
{file = "zope.interface-5.1.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:60a207efcd8c11d6bbeb7862e33418fba4e4ad79846d88d160d7231fcb42a5ee"},
|
||||
{file = "zope.interface-5.1.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:b054eb0a8aa712c8e9030065a59b5e6a5cf0746ecdb5f087cca5ec7685690c19"},
|
||||
{file = "zope.interface-5.1.0-cp38-cp38-win32.whl", hash = "sha256:27d287e61639d692563d9dab76bafe071fbeb26818dd6a32a0022f3f7ca884b5"},
|
||||
{file = "zope.interface-5.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:a5f8f85986197d1dd6444763c4a15c991bfed86d835a1f6f7d476f7198d5f56a"},
|
||||
{file = "zope.interface-5.1.0.tar.gz", hash = "sha256:40e4c42bd27ed3c11b2c983fecfb03356fae1209de10686d03c02c8696a1d90e"},
|
||||
]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "httprunner"
|
||||
version = "3.0.13"
|
||||
version = "3.1.0"
|
||||
description = "One-stop solution for HTTP(S) testing."
|
||||
license = "Apache-2.0"
|
||||
readme = "README.md"
|
||||
@@ -42,10 +42,12 @@ sentry-sdk = "^0.14.4"
|
||||
allure-pytest = {version = "^2.8.16", optional = true}
|
||||
requests-toolbelt = {version = "^0.9.1", optional = true}
|
||||
filetype = {version = "^1.0.7", optional = true}
|
||||
locust = {version = "^1.0.3", optional = true}
|
||||
|
||||
[tool.poetry.extras]
|
||||
allure = ["allure-pytest"] # pip install "httprunner[allure]", poetry install -E allure
|
||||
upload = ["requests-toolbelt", "filetype"] # pip install "httprunner[upload]", poetry install -E upload
|
||||
locust = ["locust"] # pip install "httprunner[locust]", poetry install -E locust
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
coverage = "^4.5.4"
|
||||
@@ -57,6 +59,7 @@ httprunner = "httprunner.cli:main"
|
||||
hrun = "httprunner.cli:main_hrun_alias"
|
||||
hmake = "httprunner.cli:main_make_alias"
|
||||
har2case = "httprunner.cli:main_har2case_alias"
|
||||
locusts = "httprunner.ext.locust:main_locusts"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry>=1.0.0"]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import io
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
@@ -40,10 +41,12 @@ class TestCli(unittest.TestCase):
|
||||
self.assertIn(__description__, self.captured_output.getvalue().strip())
|
||||
|
||||
def test_debug_pytest(self):
|
||||
exit_code = pytest.main(
|
||||
[
|
||||
"-s",
|
||||
"examples/postman_echo/request_methods/request_with_testcase_reference_test.py",
|
||||
]
|
||||
)
|
||||
self.assertEqual(exit_code, 0)
|
||||
cwd = os.getcwd()
|
||||
try:
|
||||
os.chdir(os.path.join(cwd, "examples", "postman_echo"))
|
||||
exit_code = pytest.main(
|
||||
["-s", "request_methods/request_with_testcase_reference_test.py",]
|
||||
)
|
||||
self.assertEqual(exit_code, 0)
|
||||
finally:
|
||||
os.chdir(cwd)
|
||||
|
||||
@@ -2,7 +2,6 @@ import os
|
||||
import unittest
|
||||
|
||||
from httprunner import compat, exceptions, loader
|
||||
from httprunner.compat import convert_variables, ensure_path_sep
|
||||
|
||||
|
||||
class TestCompat(unittest.TestCase):
|
||||
@@ -12,72 +11,72 @@ class TestCompat(unittest.TestCase):
|
||||
def test_convert_variables(self):
|
||||
raw_variables = [{"var1": 1}, {"var2": "val2"}]
|
||||
self.assertEqual(
|
||||
convert_variables(raw_variables, "tests/data/a-b.c/1.yml"),
|
||||
compat.convert_variables(raw_variables, "tests/data/a-b.c/1.yml"),
|
||||
{"var1": 1, "var2": "val2"},
|
||||
)
|
||||
raw_variables = {"var1": 1, "var2": "val2"}
|
||||
self.assertEqual(
|
||||
convert_variables(raw_variables, "tests/data/a-b.c/1.yml"),
|
||||
compat.convert_variables(raw_variables, "tests/data/a-b.c/1.yml"),
|
||||
{"var1": 1, "var2": "val2"},
|
||||
)
|
||||
raw_variables = "${get_variables()}"
|
||||
self.assertEqual(
|
||||
convert_variables(raw_variables, "tests/data/a-b.c/1.yml"),
|
||||
compat.convert_variables(raw_variables, "tests/data/a-b.c/1.yml"),
|
||||
{"foo1": "session_bar1"},
|
||||
)
|
||||
|
||||
with self.assertRaises(exceptions.TestCaseFormatError):
|
||||
raw_variables = [{"var1": 1}, {"var2": "val2", "var3": 3}]
|
||||
convert_variables(raw_variables, "tests/data/a-b.c/1.yml")
|
||||
compat.convert_variables(raw_variables, "tests/data/a-b.c/1.yml")
|
||||
with self.assertRaises(exceptions.TestCaseFormatError):
|
||||
convert_variables(None, "tests/data/a-b.c/1.yml")
|
||||
compat.convert_variables(None, "tests/data/a-b.c/1.yml")
|
||||
|
||||
def test_convert_jmespath(self):
|
||||
|
||||
self.assertEqual(compat.convert_jmespath("content.abc"), "body.abc")
|
||||
self.assertEqual(compat.convert_jmespath("json.abc"), "body.abc")
|
||||
self.assertEqual(compat._convert_jmespath("content.abc"), "body.abc")
|
||||
self.assertEqual(compat._convert_jmespath("json.abc"), "body.abc")
|
||||
self.assertEqual(
|
||||
compat.convert_jmespath("headers.Content-Type"), 'headers."Content-Type"'
|
||||
compat._convert_jmespath("headers.Content-Type"), 'headers."Content-Type"'
|
||||
)
|
||||
self.assertEqual(
|
||||
compat.convert_jmespath('headers."Content-Type"'), 'headers."Content-Type"'
|
||||
compat._convert_jmespath('headers."Content-Type"'), 'headers."Content-Type"'
|
||||
)
|
||||
self.assertEqual(
|
||||
compat.convert_jmespath("body.data.buildings.0.building_id"),
|
||||
compat._convert_jmespath("body.data.buildings.0.building_id"),
|
||||
"body.data.buildings[0].building_id",
|
||||
)
|
||||
with self.assertRaises(SystemExit):
|
||||
compat.convert_jmespath("2.buildings.0.building_id")
|
||||
compat._convert_jmespath("2.buildings.0.building_id")
|
||||
|
||||
def test_convert_extractors(self):
|
||||
self.assertEqual(
|
||||
compat.convert_extractors(
|
||||
compat._convert_extractors(
|
||||
[{"varA": "content.varA"}, {"varB": "json.varB"}]
|
||||
),
|
||||
{"varA": "body.varA", "varB": "body.varB"},
|
||||
)
|
||||
self.assertEqual(
|
||||
compat.convert_extractors([{"varA": "content.0.varA"}]),
|
||||
compat._convert_extractors([{"varA": "content.0.varA"}]),
|
||||
{"varA": "body[0].varA"},
|
||||
)
|
||||
self.assertEqual(
|
||||
compat.convert_extractors({"varA": "content.0.varA"}),
|
||||
compat._convert_extractors({"varA": "content.0.varA"}),
|
||||
{"varA": "body[0].varA"},
|
||||
)
|
||||
|
||||
def test_convert_validators(self):
|
||||
self.assertEqual(
|
||||
compat.convert_validators(
|
||||
compat._convert_validators(
|
||||
[{"check": "content.abc", "assert": "eq", "expect": 201}]
|
||||
),
|
||||
[{"check": "body.abc", "assert": "eq", "expect": 201}],
|
||||
)
|
||||
self.assertEqual(
|
||||
compat.convert_validators([{"eq": ["content.abc", 201]}]),
|
||||
compat._convert_validators([{"eq": ["content.abc", 201]}]),
|
||||
[{"eq": ["body.abc", 201]}],
|
||||
)
|
||||
self.assertEqual(
|
||||
compat.convert_validators([{"eq": ["content.0.name", 201]}]),
|
||||
compat._convert_validators([{"eq": ["content.0.name", 201]}]),
|
||||
[{"eq": ["body[0].name", 201]}],
|
||||
)
|
||||
|
||||
@@ -216,16 +215,16 @@ class TestCompat(unittest.TestCase):
|
||||
|
||||
def test_ensure_file_path(self):
|
||||
self.assertEqual(
|
||||
ensure_path_sep("demo\\test.yml"), os.sep.join(["demo", "test.yml"])
|
||||
compat.ensure_path_sep("demo\\test.yml"), os.sep.join(["demo", "test.yml"])
|
||||
)
|
||||
self.assertEqual(
|
||||
ensure_path_sep(os.path.join(os.getcwd(), "demo\\test.yml")),
|
||||
compat.ensure_path_sep(os.path.join(os.getcwd(), "demo\\test.yml")),
|
||||
os.path.join(os.getcwd(), os.sep.join(["demo", "test.yml"])),
|
||||
)
|
||||
self.assertEqual(
|
||||
ensure_path_sep("demo/test.yml"), os.sep.join(["demo", "test.yml"])
|
||||
compat.ensure_path_sep("demo/test.yml"), os.sep.join(["demo", "test.yml"])
|
||||
)
|
||||
self.assertEqual(
|
||||
ensure_path_sep(os.path.join(os.getcwd(), "demo/test.yml")),
|
||||
compat.ensure_path_sep(os.path.join(os.getcwd(), "demo/test.yml")),
|
||||
os.path.join(os.getcwd(), os.sep.join(["demo", "test.yml"])),
|
||||
)
|
||||
|
||||
@@ -6,7 +6,7 @@ config:
|
||||
teststeps:
|
||||
-
|
||||
name: request with functions
|
||||
testcase: 1.yml
|
||||
testcase: a-b.c/1.yml
|
||||
export:
|
||||
- session_foo2
|
||||
-
|
||||
|
||||
0
tests/data/a-b.c/中文case.yml
Normal file
0
tests/data/a-b.c/中文case.yml
Normal file
@@ -8,6 +8,7 @@ from httprunner.make import (
|
||||
make_config_chain_style,
|
||||
make_teststep_chain_style,
|
||||
pytest_files_run_set,
|
||||
ensure_file_abs_path_valid,
|
||||
)
|
||||
from httprunner import loader
|
||||
|
||||
@@ -64,7 +65,7 @@ class TestMake(unittest.TestCase):
|
||||
content = f.read()
|
||||
self.assertIn(
|
||||
"""
|
||||
from examples.postman_echo.request_methods.request_with_functions_test import (
|
||||
from request_methods.request_with_functions_test import (
|
||||
TestCaseRequestWithFunctions as RequestWithFunctions,
|
||||
)
|
||||
""",
|
||||
@@ -90,47 +91,57 @@ from examples.postman_echo.request_methods.request_with_functions_test import (
|
||||
testcase_python_list,
|
||||
)
|
||||
|
||||
def test_ensure_file_path_valid(self):
|
||||
self.assertEqual(
|
||||
ensure_file_abs_path_valid(
|
||||
os.path.join(os.getcwd(), "tests", "data", "a-b.c", "2 3.yml")
|
||||
),
|
||||
os.path.join(os.getcwd(), "tests", "data", "a_b_c", "T2_3.yml"),
|
||||
)
|
||||
loader.project_meta = None
|
||||
self.assertEqual(
|
||||
ensure_file_abs_path_valid(
|
||||
os.path.join(os.getcwd(), "examples", "postman_echo", "request_methods")
|
||||
),
|
||||
os.path.join(os.getcwd(), "examples", "postman_echo", "request_methods"),
|
||||
)
|
||||
loader.project_meta = None
|
||||
self.assertEqual(
|
||||
ensure_file_abs_path_valid(os.path.join(os.getcwd(), "README.md")),
|
||||
os.path.join(os.getcwd(), "README.md"),
|
||||
)
|
||||
loader.project_meta = None
|
||||
self.assertEqual(
|
||||
ensure_file_abs_path_valid(os.getcwd()), os.getcwd(),
|
||||
)
|
||||
loader.project_meta = None
|
||||
self.assertEqual(
|
||||
ensure_file_abs_path_valid(
|
||||
os.path.join(os.getcwd(), "tests", "data", ".csv")
|
||||
),
|
||||
os.path.join(os.getcwd(), "tests", "data", ".csv"),
|
||||
)
|
||||
|
||||
def test_convert_testcase_path(self):
|
||||
self.assertEqual(
|
||||
convert_testcase_path("mubu.login.yml"),
|
||||
(os.path.join(os.getcwd(), "mubu_login_test.py"), "MubuLogin"),
|
||||
convert_testcase_path(
|
||||
os.path.join(os.getcwd(), "tests", "data", "a-b.c", "2 3.yml")
|
||||
),
|
||||
(
|
||||
os.path.join(os.getcwd(), "tests", "data", "a_b_c", "T2_3_test.py"),
|
||||
"T23",
|
||||
),
|
||||
)
|
||||
self.assertEqual(
|
||||
convert_testcase_path(
|
||||
os.path.join(os.getcwd(), os.path.join("path", "to", "mubu.login.yml"))
|
||||
os.path.join(os.getcwd(), "tests", "data", "a-b.c", "中文case.yml")
|
||||
),
|
||||
(
|
||||
os.path.join(
|
||||
os.getcwd(), os.path.join("path", "to", "mubu_login_test.py")
|
||||
os.getcwd(),
|
||||
os.path.join("tests", "data", "a_b_c", "中文case_test.py"),
|
||||
),
|
||||
"MubuLogin",
|
||||
),
|
||||
)
|
||||
self.assertEqual(
|
||||
convert_testcase_path(os.path.join("path", "to 2", "mubu.login.yml")),
|
||||
(
|
||||
os.path.join(
|
||||
os.getcwd(), os.path.join("path", "to_2", "mubu_login_test.py")
|
||||
),
|
||||
"MubuLogin",
|
||||
),
|
||||
)
|
||||
self.assertEqual(
|
||||
convert_testcase_path(os.path.join("path", "to-2", "mubu login.yml")),
|
||||
(
|
||||
os.path.join(
|
||||
os.getcwd(), os.path.join("path", "to_2", "mubu_login_test.py")
|
||||
),
|
||||
"MubuLogin",
|
||||
),
|
||||
)
|
||||
self.assertEqual(
|
||||
convert_testcase_path(os.path.join("path", "to.2", "幕布login.yml")),
|
||||
(
|
||||
os.path.join(
|
||||
os.getcwd(), os.path.join("path", "to_2", "幕布login_test.py")
|
||||
),
|
||||
"幕布Login",
|
||||
"中文Case",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -35,6 +35,6 @@ class TestHttpRunner(unittest.TestCase):
|
||||
exit_code = main_run(["tests/data/a-b.c/2 3.yml"])
|
||||
self.assertEqual(exit_code, 0)
|
||||
self.assertTrue(os.path.exists("tests/data/a_b_c/__init__.py"))
|
||||
self.assertTrue(os.path.exists("tests/data/a_b_c/debugtalk.py"))
|
||||
self.assertTrue(os.path.exists("tests/data/debugtalk.py"))
|
||||
self.assertTrue(os.path.exists("tests/data/a_b_c/T1_test.py"))
|
||||
self.assertTrue(os.path.exists("tests/data/a_b_c/T2_3_test.py"))
|
||||
|
||||
@@ -5,7 +5,6 @@ import unittest
|
||||
|
||||
from httprunner import loader, utils
|
||||
from httprunner.utils import (
|
||||
ensure_file_path_valid,
|
||||
ExtendJSONEncoder,
|
||||
override_config_variables,
|
||||
)
|
||||
@@ -105,41 +104,6 @@ class TestUtils(unittest.TestCase):
|
||||
["A", "D", "C", "B"],
|
||||
)
|
||||
|
||||
def test_ensure_file_path_valid(self):
|
||||
self.assertEqual(
|
||||
ensure_file_path_valid(
|
||||
os.path.join("examples", "a-b.c", "d f", "hardcode.yml")
|
||||
),
|
||||
os.path.join(os.getcwd(), "examples", "a_b_c", "d_f", "hardcode.yml"),
|
||||
)
|
||||
self.assertEqual(
|
||||
ensure_file_path_valid(os.path.join("1", "2B", "3.yml")),
|
||||
os.path.join(os.getcwd(), "T1", "T2B", "T3.yml"),
|
||||
)
|
||||
self.assertEqual(
|
||||
ensure_file_path_valid(
|
||||
os.path.join("examples", "a-b.c", "2B", "hardcode.yml")
|
||||
),
|
||||
os.path.join(os.getcwd(), "examples", "a_b_c", "T2B", "hardcode.yml"),
|
||||
)
|
||||
self.assertEqual(
|
||||
ensure_file_path_valid(
|
||||
os.path.join("examples", "postman_echo", "request_methods")
|
||||
),
|
||||
os.path.join(os.getcwd(), "examples", "postman_echo", "request_methods"),
|
||||
)
|
||||
self.assertEqual(
|
||||
ensure_file_path_valid(os.path.join(os.getcwd(), "test.yml")),
|
||||
os.path.join(os.getcwd(), "test.yml"),
|
||||
)
|
||||
self.assertEqual(
|
||||
ensure_file_path_valid(os.getcwd()), os.getcwd(),
|
||||
)
|
||||
self.assertEqual(
|
||||
ensure_file_path_valid(os.path.join(os.getcwd(), "demo", ".csv")),
|
||||
os.path.join(os.getcwd(), "demo", ".csv"),
|
||||
)
|
||||
|
||||
def test_safe_dump_json(self):
|
||||
class A(object):
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user