1, replace logging with loguru
2, replace string format with f-string
This commit is contained in:
debugtalk
2020-03-07 12:16:11 +08:00
parent 556b6ea367
commit 7213f86f80
18 changed files with 189 additions and 187 deletions
+1
View File
@@ -6,6 +6,7 @@
- replace logging with [loguru](https://github.com/Delgan/loguru) - replace logging with [loguru](https://github.com/Delgan/loguru)
- remove support for Python 2.7 - remove support for Python 2.7
- replace string format with f-string
## 2.5.7 (2020-02-21) ## 2.5.7 (2020-02-21)
+8 -9
View File
@@ -1,9 +1,10 @@
import os import os
import unittest import unittest
from loguru import logger
from sentry_sdk import capture_message from sentry_sdk import capture_message
from httprunner import (__version__, exceptions, loader, logger, parser, from httprunner import (__version__, exceptions, loader, parser,
report, runner, utils) report, runner, utils)
@@ -32,8 +33,6 @@ class HttpRunner(object):
log_file (str): log file path. log_file (str): log file path.
""" """
logger.setup_logger(log_level, log_file)
self.exception_stage = "initialize HttpRunner()" self.exception_stage = "initialize HttpRunner()"
kwargs = { kwargs = {
"failfast": failfast, "failfast": failfast,
@@ -99,7 +98,7 @@ class HttpRunner(object):
times = int(times) times = int(times)
except ValueError: except ValueError:
raise exceptions.ParamsError( raise exceptions.ParamsError(
"times should be digit, given: {}".format(times)) f"times should be digit, given: {times}")
for times_index in range(times): for times_index in range(times):
# suppose one testcase should not have more than 9999 steps, # suppose one testcase should not have more than 9999 steps,
@@ -130,7 +129,7 @@ class HttpRunner(object):
for testcase in test_suite: for testcase in test_suite:
testcase_name = testcase.config.get("name") testcase_name = testcase.config.get("name")
logger.log_info("Start to run testcase: {}".format(testcase_name)) logger.info(f"Start to run testcase: {testcase_name}")
result = self.unittest_runner.run(testcase) result = self.unittest_runner.run(testcase)
if result.wasSuccessful(): if result.wasSuccessful():
@@ -197,11 +196,11 @@ class HttpRunner(object):
parsed_testcases = parser.parse_tests(tests_mapping) parsed_testcases = parser.parse_tests(tests_mapping)
parse_failed_testfiles = parser.get_parse_failed_testfiles() parse_failed_testfiles = parser.get_parse_failed_testfiles()
if parse_failed_testfiles: if parse_failed_testfiles:
logger.log_warning("parse failures occurred ...") logger.warning("parse failures occurred ...")
utils.dump_logs(parse_failed_testfiles, project_mapping, "parse_failed") utils.dump_logs(parse_failed_testfiles, project_mapping, "parse_failed")
if len(parsed_testcases) == 0: if len(parsed_testcases) == 0:
logger.log_error("failed to parse all cases, abort.") logger.error("failed to parse all cases, abort.")
raise exceptions.ParseTestsFailure raise exceptions.ParseTestsFailure
if self.save_tests: if self.save_tests:
@@ -295,7 +294,7 @@ class HttpRunner(object):
dict: result summary dict: result summary
""" """
logger.log_info("HttpRunner version: {}".format(__version__)) logger.info(f"HttpRunner version: {__version__}")
if loader.is_test_path(path_or_tests): if loader.is_test_path(path_or_tests):
return self.run_path(path_or_tests, dot_env_path, mapping) return self.run_path(path_or_tests, dot_env_path, mapping)
elif loader.is_test_content(path_or_tests): elif loader.is_test_content(path_or_tests):
@@ -303,4 +302,4 @@ class HttpRunner(object):
loader.init_pwd(project_working_directory) loader.init_pwd(project_working_directory)
return self.run_tests(path_or_tests) return self.run_tests(path_or_tests)
else: else:
raise exceptions.ParamsError("Invalid testcase path or testcases: {}".format(path_or_tests)) raise exceptions.ParamsError(f"Invalid testcase path or testcases: {path_or_tests}")
+6 -7
View File
@@ -3,11 +3,11 @@ import os
import sys import sys
import sentry_sdk import sentry_sdk
from loguru import logger
from httprunner import __description__, __version__, exceptions from httprunner import __description__, __version__, exceptions
from httprunner.api import HttpRunner from httprunner.api import HttpRunner
from httprunner.loader import load_cases from httprunner.loader import load_cases
from httprunner.logger import color_print, log_error
from httprunner.report import gen_html_report from httprunner.report import gen_html_report
from httprunner.utils import (create_scaffold, from httprunner.utils import (create_scaffold,
prettify_json_file, init_sentry_sdk) prettify_json_file, init_sentry_sdk)
@@ -67,19 +67,19 @@ def main():
sys.exit(0) sys.exit(0)
if args.version: if args.version:
color_print("{}".format(__version__), "GREEN") print(f"{__version__}")
sys.exit(0) sys.exit(0)
if args.validate: if args.validate:
for validate_path in args.validate: for validate_path in args.validate:
try: try:
color_print("validate test file: {}".format(validate_path), "GREEN") logger.info(f"validate test file: {validate_path}")
load_cases(validate_path, args.dot_env_path) load_cases(validate_path, args.dot_env_path)
except exceptions.MyBaseError as ex: except exceptions.MyBaseError as ex:
log_error(str(ex)) logger.error(str(ex))
continue continue
color_print("done!", "BLUE") logger.info("done!")
sys.exit(0) sys.exit(0)
if args.prettify: if args.prettify:
@@ -111,8 +111,7 @@ def main():
) )
err_code |= (0 if summary and summary["success"] else 1) err_code |= (0 if summary and summary["success"] else 1)
except Exception as ex: except Exception as ex:
color_print("!!!!!!!!!! exception stage: {} !!!!!!!!!!".format(runner.exception_stage), "YELLOW") logger.error(f"!!!!!!!!!! exception stage: {runner.exception_stage} !!!!!!!!!!\n{str(ex)}")
color_print(str(ex), "RED")
sentry_sdk.capture_exception(ex) sentry_sdk.capture_exception(ex)
err_code = 1 err_code = 1
+13 -14
View File
@@ -4,11 +4,12 @@ import time
import requests import requests
import urllib3 import urllib3
from loguru import logger
from requests import Request, Response from requests import Request, Response
from requests.exceptions import (InvalidSchema, InvalidURL, MissingSchema, from requests.exceptions import (InvalidSchema, InvalidURL, MissingSchema,
RequestException) RequestException)
from httprunner import logger, response from httprunner import response
from httprunner.utils import lower_dict_keys, omit_long_data from httprunner.utils import lower_dict_keys, omit_long_data
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
@@ -18,10 +19,10 @@ def get_req_resp_record(resp_obj):
""" get request and response info from Response() object. """ get request and response info from Response() object.
""" """
def log_print(req_resp_dict, r_type): def log_print(req_resp_dict, r_type):
msg = "\n================== {} details ==================\n".format(r_type) msg = f"\n================== {r_type} details ==================\n"
for key, value in req_resp_dict[r_type].items(): for key, value in req_resp_dict[r_type].items():
msg += "{:<16} : {}\n".format(key, repr(value)) msg += "{:<16} : {}\n".format(key, repr(value))
logger.log_debug(msg) logger.debug(msg)
req_resp_dict = { req_resp_dict = {
"request": {}, "request": {},
@@ -214,15 +215,13 @@ class HttpSession(requests.Session):
try: try:
response.raise_for_status() response.raise_for_status()
except RequestException as e: except RequestException as ex:
logger.log_error(u"{exception}".format(exception=str(e))) logger.error(f"{str(ex)}")
else: else:
logger.log_info( logger.info(
"""status_code: {}, response_time(ms): {} ms, response_length: {} bytes\n""".format( f"status_code: {response.status_code}, "
response.status_code, f"response_time(ms): {response_time_ms} ms, "
response_time_ms, f"response_length: {content_size} bytes\n"
content_size
)
) )
return response return response
@@ -234,9 +233,9 @@ class HttpSession(requests.Session):
""" """
try: try:
msg = "processed request:\n" msg = "processed request:\n"
msg += "> {method} {url}\n".format(method=method, url=url) msg += f"> {method} {url}\n"
msg += "> kwargs: {kwargs}".format(kwargs=kwargs) msg += f"> kwargs: {kwargs}"
logger.log_debug(msg) logger.debug(msg)
return requests.Session.request(self, method, url, **kwargs) return requests.Session.request(self, method, url, **kwargs)
except (MissingSchema, InvalidSchema, InvalidURL): except (MissingSchema, InvalidSchema, InvalidURL):
raise raise
+9 -8
View File
@@ -18,8 +18,9 @@ import multiprocessing
import os import os
import sys import sys
from loguru import logger
from httprunner import __version__ from httprunner import __version__
from httprunner import logger
from httprunner.utils import init_sentry_sdk from httprunner.utils import init_sentry_sdk
init_sentry_sdk() init_sentry_sdk()
@@ -31,7 +32,7 @@ def parse_locustfile(file_path):
if file_path is a YAML/JSON file, convert it to locustfile if file_path is a YAML/JSON file, convert it to locustfile
""" """
if not os.path.isfile(file_path): if not os.path.isfile(file_path):
logger.color_print("file path invalid, exit.", "RED") logger.error("file path invalid, exit.")
sys.exit(1) sys.exit(1)
file_suffix = os.path.splitext(file_path)[1] file_suffix = os.path.splitext(file_path)[1]
@@ -41,7 +42,7 @@ def parse_locustfile(file_path):
locustfile_path = gen_locustfile(file_path) locustfile_path = gen_locustfile(file_path)
else: else:
# '' or other suffix # '' or other suffix
logger.color_print("file type should be YAML/JSON/Python, exit.", "RED") logger.error("file type should be YAML/JSON/Python, exit.")
sys.exit(1) sys.exit(1)
return locustfile_path return locustfile_path
@@ -105,7 +106,7 @@ def run_locusts_with_processes(sys_argv, processes_count):
def main(): def main():
""" Performance test with locust: parse command line options and run commands. """ Performance test with locust: parse command line options and run commands.
""" """
print("HttpRunner version: {}".format(__version__)) print(f"HttpRunner version: {__version__}")
sys.argv[0] = 'locust' sys.argv[0] = 'locust'
if len(sys.argv) == 1: if len(sys.argv) == 1:
sys.argv.extend(["-h"]) sys.argv.extend(["-h"])
@@ -130,7 +131,7 @@ def main():
# default # default
loglevel = "WARNING" loglevel = "WARNING"
logger.setup_logger(loglevel) # logger.setup_logger(loglevel)
# get testcase file path # get testcase file path
try: try:
@@ -147,7 +148,7 @@ def main():
""" locusts -f locustfile.py --processes 4 """ locusts -f locustfile.py --processes 4
""" """
if "--no-web" in sys.argv: if "--no-web" in sys.argv:
logger.log_error("conflict parameter args: --processes & --no-web. \nexit.") logger.error("conflict parameter args: --processes & --no-web. \nexit.")
sys.exit(1) sys.exit(1)
processes_index = sys.argv.index('--processes') processes_index = sys.argv.index('--processes')
@@ -157,7 +158,7 @@ def main():
locusts -f locustfile.py --processes locusts -f locustfile.py --processes
""" """
processes_count = multiprocessing.cpu_count() processes_count = multiprocessing.cpu_count()
logger.log_warning("processes count not specified, use {} by default.".format(processes_count)) logger.warning(f"processes count not specified, use {processes_count} by default.")
else: else:
try: try:
""" locusts -f locustfile.py --processes 4 """ """ locusts -f locustfile.py --processes 4 """
@@ -166,7 +167,7 @@ def main():
except ValueError: except ValueError:
""" locusts -f locustfile.py --processes -P 8888 """ """ locusts -f locustfile.py --processes -P 8888 """
processes_count = multiprocessing.cpu_count() processes_count = multiprocessing.cpu_count()
logger.log_warning("processes count not specified, use {} by default.".format(processes_count)) logger.warning(f"processes count not specified, use {processes_count} by default.")
sys.argv.pop(processes_index) sys.argv.pop(processes_index)
run_locusts_with_processes(sys.argv, processes_count) run_locusts_with_processes(sys.argv, processes_count)
+2 -2
View File
@@ -85,12 +85,12 @@ def prepare_upload_test(test_dict):
""" """
upload_json = test_dict["request"].pop("upload", {}) upload_json = test_dict["request"].pop("upload", {})
if not upload_json: if not upload_json:
raise ParamsError("invalid upload info: {}".format(upload_json)) raise ParamsError(f"invalid upload info: {upload_json}")
params_list = [] params_list = []
for key, value in upload_json.items(): for key, value in upload_json.items():
test_dict["variables"][key] = value test_dict["variables"][key] = value
params_list.append("{}=${}".format(key, key)) params_list.append(f"{key}=${key}")
params_str = ", ".join(params_list) params_str = ", ".join(params_list)
test_dict["variables"]["m_encoder"] = "${multipart_encoder(" + params_str + ")}" test_dict["variables"]["m_encoder"] = "${multipart_encoder(" + params_str + ")}"
+9 -7
View File
@@ -1,7 +1,9 @@
import importlib import importlib
import os import os
from httprunner import exceptions, logger, utils from loguru import logger
from httprunner import exceptions, utils
from httprunner.loader.check import JsonSchemaChecker from httprunner.loader.check import JsonSchemaChecker
from httprunner.loader.load import load_module_functions, load_file, load_dot_env_file, \ from httprunner.loader.load import load_module_functions, load_file, load_dot_env_file, \
load_folder_files load_folder_files
@@ -53,7 +55,7 @@ def __extend_with_api_ref(raw_testinfo):
if api_name in tests_def_mapping["api"]: if api_name in tests_def_mapping["api"]:
block = tests_def_mapping["api"][api_name] block = tests_def_mapping["api"][api_name]
elif not os.path.isfile(api_name): elif not os.path.isfile(api_name):
raise exceptions.ApiNotFound("{} not found!".format(api_name)) raise exceptions.ApiNotFound(f"{api_name} not found!")
else: else:
block = load_file(api_name) block = load_file(api_name)
@@ -84,7 +86,7 @@ def __extend_with_testcase_ref(raw_testinfo):
testcase_dict = load_testcase_v2(loaded_testcase) testcase_dict = load_testcase_v2(loaded_testcase)
else: else:
raise exceptions.FileFormatError( raise exceptions.FileFormatError(
"Invalid format testcase: {}".format(testcase_path)) f"Invalid format testcase: {testcase_path}")
tests_def_mapping["testcases"][testcase_path] = testcase_dict tests_def_mapping["testcases"][testcase_path] = testcase_dict
else: else:
@@ -186,8 +188,8 @@ def load_testcase(raw_testcase):
elif key == "test": elif key == "test":
tests.append(load_teststep(test_block)) tests.append(load_teststep(test_block))
else: else:
logger.log_warning( logger.warning(
"unexpected block key: {}. block key should only be 'config' or 'test'.".format(key) f"unexpected block key: {key}. block key should only be 'config' or 'test'."
) )
return { return {
@@ -485,9 +487,9 @@ def load_cases(path, dot_env_path=None):
try: try:
loaded_content = load_test_file(path) loaded_content = load_test_file(path)
except exceptions.ApiNotFound as ex: except exceptions.ApiNotFound as ex:
logger.log_warning("Invalid api reference in {}: {}".format(path, ex)) logger.warning(f"Invalid api reference in {path}: {ex}")
except exceptions.FileFormatError: except exceptions.FileFormatError:
logger.log_warning("Invalid test file format: {}".format(path)) logger.warning(f"Invalid test file format: {path}")
if not loaded_content: if not loaded_content:
pass pass
+3 -2
View File
@@ -4,8 +4,9 @@ import os
import platform import platform
import jsonschema import jsonschema
from loguru import logger
from httprunner import exceptions, logger from httprunner import exceptions
schemas_root_dir = os.path.join(os.path.dirname(__file__), "schemas") schemas_root_dir = os.path.join(os.path.dirname(__file__), "schemas")
common_schema_path = os.path.join(schemas_root_dir, "common.schema.json") common_schema_path = os.path.join(schemas_root_dir, "common.schema.json")
@@ -50,7 +51,7 @@ class JsonSchemaChecker(object):
try: try:
jsonschema.validate(content, scheme, resolver=resolver) jsonschema.validate(content, scheme, resolver=resolver)
except jsonschema.exceptions.ValidationError as ex: except jsonschema.exceptions.ValidationError as ex:
logger.log_error(str(ex)) logger.error(str(ex))
raise exceptions.FileFormatError raise exceptions.FileFormatError
return True return True
+8 -8
View File
@@ -5,9 +5,10 @@ import os
import types import types
import yaml import yaml
from loguru import logger
from httprunner import builtin from httprunner import builtin
from httprunner import exceptions, logger, utils from httprunner import exceptions, utils
from httprunner.loader.locate import get_project_working_directory from httprunner.loader.locate import get_project_working_directory
try: try:
@@ -25,7 +26,7 @@ def _load_yaml_file(yaml_file):
try: try:
yaml_content = yaml.load(stream) yaml_content = yaml.load(stream)
except yaml.YAMLError as ex: except yaml.YAMLError as ex:
logger.log_error(str(ex)) logger.error(str(ex))
raise exceptions.FileFormatError raise exceptions.FileFormatError
return yaml_content return yaml_content
@@ -38,8 +39,8 @@ def _load_json_file(json_file):
try: try:
json_content = json.load(data_file) json_content = json.load(data_file)
except exceptions.JSONDecodeError: except exceptions.JSONDecodeError:
err_msg = u"JSONDecodeError: JSON file format error: {}".format(json_file) err_msg = f"JSONDecodeError: JSON file format error: {json_file}"
logger.log_error(err_msg) logger.error(err_msg)
raise exceptions.FileFormatError(err_msg) raise exceptions.FileFormatError(err_msg)
return json_content return json_content
@@ -90,7 +91,7 @@ def load_csv_file(csv_file):
def load_file(file_path): def load_file(file_path):
if not os.path.isfile(file_path): if not os.path.isfile(file_path):
raise exceptions.FileNotFound("{} does not exist.".format(file_path)) raise exceptions.FileNotFound(f"{file_path} does not exist.")
file_suffix = os.path.splitext(file_path)[1].lower() file_suffix = os.path.splitext(file_path)[1].lower()
if file_suffix == '.json': if file_suffix == '.json':
@@ -101,8 +102,7 @@ def load_file(file_path):
return load_csv_file(file_path) return load_csv_file(file_path)
else: else:
# '' or other suffix # '' or other suffix
err_msg = u"Unsupported file format: {}".format(file_path) logger.warning(f"Unsupported file format: {file_path}")
logger.log_warning(err_msg)
return [] return []
@@ -169,7 +169,7 @@ def load_dot_env_file(dot_env_path):
if not os.path.isfile(dot_env_path): if not os.path.isfile(dot_env_path):
return {} return {}
logger.log_info("Loading environment variables from {}".format(dot_env_path)) logger.info(f"Loading environment variables from {dot_env_path}")
env_variables_mapping = {} env_variables_mapping = {}
with io.open(dot_env_path, 'r', encoding='utf-8') as fp: with io.open(dot_env_path, 'r', encoding='utf-8') as fp:
+8 -6
View File
@@ -1,7 +1,9 @@
import os import os
import sys import sys
from httprunner import exceptions, logger from loguru import logger
from httprunner import exceptions
project_working_directory = None project_working_directory = None
@@ -26,7 +28,7 @@ def locate_file(start_path, file_name):
elif os.path.isdir(start_path): elif os.path.isdir(start_path):
start_dir_path = start_path start_dir_path = start_path
else: else:
raise exceptions.FileNotFound("invalid path: {}".format(start_path)) raise exceptions.FileNotFound(f"invalid path: {start_path}")
file_path = os.path.join(start_dir_path, file_name) file_path = os.path.join(start_dir_path, file_name)
if os.path.isfile(file_path): if os.path.isfile(file_path):
@@ -34,14 +36,14 @@ def locate_file(start_path, file_name):
# current working directory # current working directory
if os.path.abspath(start_dir_path) == os.getcwd(): if os.path.abspath(start_dir_path) == os.getcwd():
raise exceptions.FileNotFound("{} not found in {}".format(file_name, start_path)) raise exceptions.FileNotFound(f"{file_name} not found in {start_path}")
# system root dir # system root dir
# Windows, e.g. 'E:\\' # Windows, e.g. 'E:\\'
# Linux/Darwin, '/' # Linux/Darwin, '/'
parent_dir = os.path.dirname(start_dir_path) parent_dir = os.path.dirname(start_dir_path)
if parent_dir == start_dir_path: if parent_dir == start_dir_path:
raise exceptions.FileNotFound("{} not found in {}".format(file_name, start_path)) raise exceptions.FileNotFound(f"{file_name} not found in {start_path}")
# locate recursive upward # locate recursive upward
return locate_file(parent_dir, file_name) return locate_file(parent_dir, file_name)
@@ -85,8 +87,8 @@ def init_project_working_directory(test_path):
def prepare_path(path): def prepare_path(path):
if not os.path.exists(path): if not os.path.exists(path):
err_msg = "path not exist: {}".format(path) err_msg = f"path not exist: {path}"
logger.log_error(err_msg) logger.error(err_msg)
raise exceptions.FileNotFound(err_msg) raise exceptions.FileNotFound(err_msg)
if not os.path.isabs(path): if not os.path.isabs(path):
+11 -10
View File
@@ -6,8 +6,9 @@ import collections
import json import json
import re import re
from loguru import logger
from httprunner import exceptions, utils, loader from httprunner import exceptions, utils, loader
from httprunner import logger
from httprunner.compat import basestring, numeric_types, str from httprunner.compat import basestring, numeric_types, str
# use $$ to escape $ notation # use $$ to escape $ notation
@@ -286,7 +287,7 @@ def uniform_validator(validator):
""" """
if not isinstance(validator, dict): if not isinstance(validator, dict):
raise exceptions.ParamsError("invalid validator: {}".format(validator)) raise exceptions.ParamsError(f"invalid validator: {validator}")
if "check" in validator and "expect" in validator: if "check" in validator and "expect" in validator:
# format1 # format1
@@ -300,12 +301,12 @@ def uniform_validator(validator):
compare_values = validator[comparator] compare_values = validator[comparator]
if not isinstance(compare_values, list) or len(compare_values) != 2: if not isinstance(compare_values, list) or len(compare_values) != 2:
raise exceptions.ParamsError("invalid validator: {}".format(validator)) raise exceptions.ParamsError(f"invalid validator: {validator}")
check_item, expect_value = compare_values check_item, expect_value = compare_values
else: else:
raise exceptions.ParamsError("invalid validator: {}".format(validator)) raise exceptions.ParamsError(f"invalid validator: {validator}")
# uniform comparator, e.g. lt => less_than, eq => equals # uniform comparator, e.g. lt => less_than, eq => equals
comparator = get_uniform_comparator(comparator) comparator = get_uniform_comparator(comparator)
@@ -410,7 +411,7 @@ def get_mapping_variable(variable_name, variables_mapping):
try: try:
return variables_mapping[variable_name] return variables_mapping[variable_name]
except KeyError: except KeyError:
raise exceptions.VariableNotFound("{} is not found.".format(variable_name)) raise exceptions.VariableNotFound(f"{variable_name} is not found.")
def get_mapping_function(function_name, functions_mapping): def get_mapping_function(function_name, functions_mapping):
@@ -455,7 +456,7 @@ def get_mapping_function(function_name, functions_mapping):
except AttributeError: except AttributeError:
pass pass
raise exceptions.FunctionNotFound("{} is not found.".format(function_name)) raise exceptions.FunctionNotFound(f"{function_name} is not found.")
def parse_function_params(params): def parse_function_params(params):
@@ -578,12 +579,12 @@ class LazyFunction(object):
if self._kwargs: if self._kwargs:
args_string += ", " args_string += ", "
str_kwargs = [ str_kwargs = [
"{}={}".format(key, str(value)) f"{key}={str(value)}"
for key, value in self._kwargs.items() for key, value in self._kwargs.items()
] ]
args_string += ", ".join(str_kwargs) args_string += ", ".join(str_kwargs)
return "LazyFunction({}({}))".format(self.func_name, args_string) return f"LazyFunction({self.func_name}({args_string}))"
def __prepare_cache_key(self, args, kwargs): def __prepare_cache_key(self, args, kwargs):
return self.func_name, repr(args), repr(kwargs) return self.func_name, repr(args), repr(kwargs)
@@ -698,7 +699,7 @@ class LazyString(object):
self._string += escape_braces(remain_string) self._string += escape_braces(remain_string)
def __repr__(self): def __repr__(self):
return "LazyString({})".format(self.raw_string) return f"LazyString({self.raw_string})"
def to_value(self, variables_mapping=None): def to_value(self, variables_mapping=None):
""" parse lazy data with evaluated variables mapping. """ parse lazy data with evaluated variables mapping.
@@ -1247,7 +1248,7 @@ def _parse_testcase(testcase, project_mapping, session_variables_set=None):
testcase_type = testcase["type"] testcase_type = testcase["type"]
testcase_path = testcase.get("path") testcase_path = testcase.get("path")
logger.log_error("failed to parse testcase: {}, error: {}".format(testcase_path, ex)) logger.error(f"failed to parse testcase: {testcase_path}, error: {ex}")
global parse_failed_testfiles global parse_failed_testfiles
if testcase_type not in parse_failed_testfiles: if testcase_type not in parse_failed_testfiles:
+6 -6
View File
@@ -3,8 +3,8 @@ import os
from datetime import datetime from datetime import datetime
from jinja2 import Template from jinja2 import Template
from loguru import logger
from httprunner import logger
from httprunner.exceptions import SummaryEmpty from httprunner.exceptions import SummaryEmpty
@@ -19,7 +19,7 @@ def gen_html_report(summary, report_template=None, report_dir=None, report_file=
""" """
if not summary["time"] or summary["stat"]["testcases"]["total"] == 0: if not summary["time"] or summary["stat"]["testcases"]["total"] == 0:
logger.log_error("test result summary is empty ! {}".format(summary)) logger.error(f"test result summary is empty ! {summary}")
raise SummaryEmpty raise SummaryEmpty
if not report_template: if not report_template:
@@ -27,11 +27,11 @@ def gen_html_report(summary, report_template=None, report_dir=None, report_file=
os.path.abspath(os.path.dirname(__file__)), os.path.abspath(os.path.dirname(__file__)),
"template.html" "template.html"
) )
logger.log_debug("No html report template specified, use default.") logger.debug("No html report template specified, use default.")
else: else:
logger.log_info("render with html report template: {}".format(report_template)) logger.info(f"render with html report template: {report_template}")
logger.log_info("Start to render Html report ...") logger.info("Start to render Html report ...")
start_at_timestamp = summary["time"]["start_at"] start_at_timestamp = summary["time"]["start_at"]
utc_time_iso_8601_str = datetime.utcfromtimestamp(start_at_timestamp).isoformat() utc_time_iso_8601_str = datetime.utcfromtimestamp(start_at_timestamp).isoformat()
@@ -58,7 +58,7 @@ def gen_html_report(summary, report_template=None, report_dir=None, report_file=
).render(summary) ).render(summary)
fp_w.write(rendered_content) fp_w.write(rendered_content)
logger.log_info("Generated Html report: {}".format(report_path)) logger.info(f"Generated Html report: {report_path}")
return report_path return report_path
+2 -2
View File
@@ -1,7 +1,7 @@
import time import time
import unittest import unittest
from httprunner import logger from loguru import logger
class HtmlTestResult(unittest.TextTestResult): class HtmlTestResult(unittest.TextTestResult):
@@ -27,7 +27,7 @@ class HtmlTestResult(unittest.TextTestResult):
def startTest(self, test): def startTest(self, test):
""" add start test time """ """ add start test time """
super(HtmlTestResult, self).startTest(test) super(HtmlTestResult, self).startTest(test)
logger.color_print(test.shortDescription(), "yellow") logger.info(test.shortDescription())
def addSuccess(self, test): def addSuccess(self, test):
super(HtmlTestResult, self).addSuccess(test) super(HtmlTestResult, self).addSuccess(test)
+1 -1
View File
@@ -205,7 +205,7 @@ def stringify_summary(summary):
for index, suite_summary in enumerate(summary["details"]): for index, suite_summary in enumerate(summary["details"]):
if not suite_summary.get("name"): if not suite_summary.get("name"):
suite_summary["name"] = "testcase {}".format(index) suite_summary["name"] = f"testcase {index}"
for record in suite_summary.get("records"): for record in suite_summary.get("records"):
meta_datas = record['meta_datas'] meta_datas = record['meta_datas']
+40 -39
View File
@@ -2,8 +2,9 @@ import re
from collections import OrderedDict from collections import OrderedDict
import jsonpath import jsonpath
from loguru import logger
from httprunner import exceptions, logger, utils from httprunner import exceptions, utils
from httprunner.compat import basestring, is_py2 from httprunner.compat import basestring, is_py2
text_extractor_regexp_compile = re.compile(r".*\(.*\).*") text_extractor_regexp_compile = re.compile(r".*\(.*\).*")
@@ -32,8 +33,8 @@ class ResponseObject(object):
self.__dict__[key] = value self.__dict__[key] = value
return value return value
except AttributeError: except AttributeError:
err_msg = "ResponseObject does not have attribute: {}".format(key) err_msg = f"ResponseObject does not have attribute: {key}"
logger.log_error(err_msg) logger.error(err_msg)
raise exceptions.ParamsError(err_msg) raise exceptions.ParamsError(err_msg)
def _extract_field_with_jsonpath(self, field: str) -> list: def _extract_field_with_jsonpath(self, field: str) -> list:
@@ -81,9 +82,9 @@ class ResponseObject(object):
assert result assert result
return result return result
except (AssertionError, exceptions.JSONDecodeError): except (AssertionError, exceptions.JSONDecodeError):
err_msg = u"Failed to extract data with jsonpath! => {}\n".format(field) err_msg = f"Failed to extract data with jsonpath! => {field}\n"
err_msg += u"response body: {}\n".format(self.text) err_msg += f"response body: {self.text}\n"
logger.log_error(err_msg) logger.error(err_msg)
raise exceptions.ExtractFailure(err_msg) raise exceptions.ExtractFailure(err_msg)
def _extract_field_with_regex(self, field): def _extract_field_with_regex(self, field):
@@ -108,9 +109,9 @@ class ResponseObject(object):
""" """
matched = re.search(field, self.text) matched = re.search(field, self.text)
if not matched: if not matched:
err_msg = u"Failed to extract data with regex! => {}\n".format(field) err_msg = f"Failed to extract data with regex! => {field}\n"
err_msg += u"response body: {}\n".format(self.text) err_msg += f"response body: {self.text}\n"
logger.log_error(err_msg) logger.error(err_msg)
raise exceptions.ExtractFailure(err_msg) raise exceptions.ExtractFailure(err_msg)
return matched.group(1) return matched.group(1)
@@ -141,8 +142,8 @@ class ResponseObject(object):
if top_query in ["status_code", "encoding", "ok", "reason", "url"]: if top_query in ["status_code", "encoding", "ok", "reason", "url"]:
if sub_query: if sub_query:
# status_code.XX # status_code.XX
err_msg = u"Failed to extract: {}\n".format(field) err_msg = f"Failed to extract: {field}\n"
logger.log_error(err_msg) logger.error(err_msg)
raise exceptions.ParamsError(err_msg) raise exceptions.ParamsError(err_msg)
return getattr(self, top_query) return getattr(self, top_query)
@@ -157,27 +158,27 @@ class ResponseObject(object):
try: try:
return cookies[sub_query] return cookies[sub_query]
except KeyError: except KeyError:
err_msg = u"Failed to extract cookie! => {}\n".format(field) err_msg = f"Failed to extract cookie! => {field}\n"
err_msg += u"response cookies: {}\n".format(cookies) err_msg += f"response cookies: {cookies}\n"
logger.log_error(err_msg) logger.error(err_msg)
raise exceptions.ExtractFailure(err_msg) raise exceptions.ExtractFailure(err_msg)
# elapsed # elapsed
elif top_query == "elapsed": elif top_query == "elapsed":
available_attributes = u"available attributes: days, seconds, microseconds, total_seconds" available_attributes = u"available attributes: days, seconds, microseconds, total_seconds"
if not sub_query: if not sub_query:
err_msg = u"elapsed is datetime.timedelta instance, attribute should also be specified!\n" err_msg = "elapsed is datetime.timedelta instance, attribute should also be specified!\n"
err_msg += available_attributes err_msg += available_attributes
logger.log_error(err_msg) logger.error(err_msg)
raise exceptions.ParamsError(err_msg) raise exceptions.ParamsError(err_msg)
elif sub_query in ["days", "seconds", "microseconds"]: elif sub_query in ["days", "seconds", "microseconds"]:
return getattr(self.elapsed, sub_query) return getattr(self.elapsed, sub_query)
elif sub_query == "total_seconds": elif sub_query == "total_seconds":
return self.elapsed.total_seconds() return self.elapsed.total_seconds()
else: else:
err_msg = "{} is not valid datetime.timedelta attribute.\n".format(sub_query) err_msg = f"{sub_query} is not valid datetime.timedelta attribute.\n"
err_msg += available_attributes err_msg += available_attributes
logger.log_error(err_msg) logger.error(err_msg)
raise exceptions.ParamsError(err_msg) raise exceptions.ParamsError(err_msg)
# headers # headers
@@ -190,9 +191,9 @@ class ResponseObject(object):
try: try:
return headers[sub_query] return headers[sub_query]
except KeyError: except KeyError:
err_msg = u"Failed to extract header! => {}\n".format(field) err_msg = f"Failed to extract header! => {field}\n"
err_msg += u"response headers: {}\n".format(headers) err_msg += f"response headers: {headers}\n"
logger.log_error(err_msg) logger.error(err_msg)
raise exceptions.ExtractFailure(err_msg) raise exceptions.ExtractFailure(err_msg)
# response body # response body
@@ -214,9 +215,9 @@ class ResponseObject(object):
return utils.query_json(body, sub_query) return utils.query_json(body, sub_query)
else: else:
# content = "<html>abcdefg</html>", content.xxx # content = "<html>abcdefg</html>", content.xxx
err_msg = u"Failed to extract attribute from response body! => {}\n".format(field) err_msg = f"Failed to extract attribute from response body! => {field}\n"
err_msg += u"response body: {}\n".format(body) err_msg += f"response body: {body}\n"
logger.log_error(err_msg) logger.error(err_msg)
raise exceptions.ExtractFailure(err_msg) raise exceptions.ExtractFailure(err_msg)
# new set response attributes in teardown_hooks # new set response attributes in teardown_hooks
@@ -235,30 +236,30 @@ class ResponseObject(object):
return utils.query_json(attributes, sub_query) return utils.query_json(attributes, sub_query)
else: else:
# content = "attributes.new_attribute_not_exist" # content = "attributes.new_attribute_not_exist"
err_msg = u"Failed to extract cumstom set attribute from teardown hooks! => {}\n".format(field) err_msg = f"Failed to extract cumstom set attribute from teardown hooks! => {field}\n"
err_msg += u"response set attributes: {}\n".format(attributes) err_msg += f"response set attributes: {attributes}\n"
logger.log_error(err_msg) logger.error(err_msg)
raise exceptions.TeardownHooksFailure(err_msg) raise exceptions.TeardownHooksFailure(err_msg)
# others # others
else: else:
err_msg = u"Failed to extract attribute from response! => {}\n".format(field) err_msg = f"Failed to extract attribute from response! => {field}\n"
err_msg += u"available response attributes: status_code, cookies, elapsed, headers, content, " \ err_msg += "available response attributes: status_code, cookies, elapsed, headers, content, " \
u"text, json, encoding, ok, reason, url.\n\n" "text, json, encoding, ok, reason, url.\n\n"
err_msg += u"If you want to set attribute in teardown_hooks, take the following example as reference:\n" err_msg += "If you want to set attribute in teardown_hooks, take the following example as reference:\n"
err_msg += u"response.new_attribute = 'new_attribute_value'\n" err_msg += "response.new_attribute = 'new_attribute_value'\n"
logger.log_error(err_msg) logger.error(err_msg)
raise exceptions.ParamsError(err_msg) raise exceptions.ParamsError(err_msg)
def extract_field(self, field): def extract_field(self, field):
""" extract value from requests.Response. """ extract value from requests.Response.
""" """
if not isinstance(field, basestring): if not isinstance(field, basestring):
err_msg = u"Invalid extractor! => {}\n".format(field) err_msg = f"Invalid extractor! => {field}\n"
logger.log_error(err_msg) logger.error(err_msg)
raise exceptions.ParamsError(err_msg) raise exceptions.ParamsError(err_msg)
msg = "extract: {}".format(field) msg = f"extract: {field}"
if field.startswith("$"): if field.startswith("$"):
value = self._extract_field_with_jsonpath(field) value = self._extract_field_with_jsonpath(field)
@@ -270,8 +271,8 @@ class ResponseObject(object):
if is_py2 and isinstance(value, unicode): if is_py2 and isinstance(value, unicode):
value = value.encode("utf-8") value = value.encode("utf-8")
msg += "\t=> {}".format(value) msg += f"\t=> {value}"
logger.log_debug(msg) logger.debug(msg)
return value return value
@@ -295,7 +296,7 @@ class ResponseObject(object):
if not extractors: if not extractors:
return {} return {}
logger.log_debug("start to extract from response object.") logger.debug("start to extract from response object.")
extracted_variables_mapping = OrderedDict() extracted_variables_mapping = OrderedDict()
extract_binds_order_dict = utils.ensure_mapping_format(extractors) extract_binds_order_dict = utils.ensure_mapping_format(extractors)
+23 -24
View File
@@ -3,7 +3,9 @@
from enum import Enum from enum import Enum
from unittest.case import SkipTest from unittest.case import SkipTest
from httprunner import exceptions, logger, response, utils from loguru import logger
from httprunner import exceptions, response, utils
from httprunner.client import HttpSession from httprunner.client import HttpSession
from httprunner.context import SessionContext from httprunner.context import SessionContext
from httprunner.validator import Validator from httprunner.validator import Validator
@@ -116,12 +118,12 @@ class Runner(object):
elif "skipIf" in test_dict: elif "skipIf" in test_dict:
skip_if_condition = test_dict["skipIf"] skip_if_condition = test_dict["skipIf"]
if self.session_context.eval_content(skip_if_condition): if self.session_context.eval_content(skip_if_condition):
skip_reason = "{} evaluate to True".format(skip_if_condition) skip_reason = f"{skip_if_condition} evaluate to True"
elif "skipUnless" in test_dict: elif "skipUnless" in test_dict:
skip_unless_condition = test_dict["skipUnless"] skip_unless_condition = test_dict["skipUnless"]
if not self.session_context.eval_content(skip_unless_condition): if not self.session_context.eval_content(skip_unless_condition):
skip_reason = "{} evaluate to False".format(skip_unless_condition) skip_reason = f"{skip_unless_condition} evaluate to False"
if skip_reason: if skip_reason:
raise SkipTest(skip_reason) raise SkipTest(skip_reason)
@@ -140,7 +142,7 @@ class Runner(object):
hook_type (HookTypeEnum): setup/teardown hook_type (HookTypeEnum): setup/teardown
""" """
logger.log_debug("call {} hook actions.".format(hook_type.name)) logger.debug(f"call {hook_type.name} hook actions.")
for action in actions: for action in actions:
if isinstance(action, dict) and len(action) == 1: if isinstance(action, dict) and len(action) == 1:
@@ -148,17 +150,14 @@ class Runner(object):
# {"var": "${func()}"} # {"var": "${func()}"}
var_name, hook_content = list(action.items())[0] var_name, hook_content = list(action.items())[0]
hook_content_eval = self.session_context.eval_content(hook_content) hook_content_eval = self.session_context.eval_content(hook_content)
logger.log_debug( logger.debug(
"assignment with hook: {} = {} => {}".format( f"assignment with hook: {var_name} = {hook_content} => {hook_content_eval}")
var_name, hook_content, hook_content_eval
)
)
self.session_context.update_test_variables( self.session_context.update_test_variables(
var_name, hook_content_eval var_name, hook_content_eval
) )
else: else:
# format 2 # format 2
logger.log_debug("call hook function: {}".format(action)) logger.debug(f"call hook function: {action}")
# TODO: check hook function if valid # TODO: check hook function if valid
self.session_context.eval_content(action) self.session_context.eval_content(action)
@@ -230,9 +229,8 @@ class Runner(object):
except KeyError: except KeyError:
raise exceptions.ParamsError("URL or METHOD missed!") raise exceptions.ParamsError("URL or METHOD missed!")
logger.log_info("{method} {url}".format(method=method, url=parsed_url)) logger.info(f"{method} {parsed_url}")
logger.log_debug( logger.debug(f"request kwargs(raw): {parsed_test_request}")
"request kwargs(raw): {kwargs}".format(kwargs=parsed_test_request))
# request # request
resp = self.http_client_session.request( resp = self.http_client_session.request(
@@ -248,21 +246,22 @@ class Runner(object):
# log request # log request
err_msg += "====== request details ======\n" err_msg += "====== request details ======\n"
err_msg += "url: {}\n".format(parsed_url) err_msg += f"url: {parsed_url}\n"
err_msg += "method: {}\n".format(method) err_msg += f"method: {method}\n"
err_msg += "headers: {}\n".format(parsed_test_request.pop("headers", {})) headers = parsed_test_request.pop("headers", {})
err_msg += f"headers: {headers}\n"
for k, v in parsed_test_request.items(): for k, v in parsed_test_request.items():
v = utils.omit_long_data(v) v = utils.omit_long_data(v)
err_msg += "{}: {}\n".format(k, repr(v)) err_msg += f"{k}: {repr(v)}\n"
err_msg += "\n" err_msg += "\n"
# log response # log response
err_msg += "====== response details ======\n" err_msg += "====== response details ======\n"
err_msg += "status_code: {}\n".format(resp_obj.status_code) err_msg += f"status_code: {resp_obj.status_code}\n"
err_msg += "headers: {}\n".format(resp_obj.headers) err_msg += f"headers: {resp_obj.headers}\n"
err_msg += "body: {}\n".format(repr(resp_obj.text)) err_msg += f"body: {repr(resp_obj.text)}\n"
logger.log_error(err_msg) logger.error(err_msg)
# teardown hooks # teardown hooks
teardown_hooks = test_dict.get("teardown_hooks", []) teardown_hooks = test_dict.get("teardown_hooks", [])
@@ -395,9 +394,9 @@ class Runner(object):
output = {} output = {}
for variable in output_variables_list: for variable in output_variables_list:
if variable not in variables_mapping: if variable not in variables_mapping:
logger.log_warning( logger.warning(
"variable '{}' can not be found in variables mapping, " f"variable '{variable}' can not be found in variables mapping, "
"failed to export!".format(variable) "failed to export!"
) )
continue continue
+21 -21
View File
@@ -22,7 +22,7 @@ absolute_http_url_regexp = re.compile(r"^https?://", re.I)
def init_sentry_sdk(): def init_sentry_sdk():
sentry_sdk.init( sentry_sdk.init(
dsn="https://cc6dd86fbe9f4e7fbd95248cfcff114d@sentry.io/1862849", dsn="https://cc6dd86fbe9f4e7fbd95248cfcff114d@sentry.io/1862849",
release="httprunner@{}".format(__version__) release=f"httprunner@{__version__}"
) )
with sentry_sdk.configure_scope() as scope: with sentry_sdk.configure_scope() as scope:
@@ -34,7 +34,7 @@ def set_os_environ(variables_mapping):
""" """
for variable in variables_mapping: for variable in variables_mapping:
os.environ[variable] = variables_mapping[variable] os.environ[variable] = variables_mapping[variable]
logger.debug("Set OS environment variable: {}".format(variable)) logger.debug(f"Set OS environment variable: {variable}")
def unset_os_environ(variables_mapping): def unset_os_environ(variables_mapping):
@@ -42,7 +42,7 @@ def unset_os_environ(variables_mapping):
""" """
for variable in variables_mapping: for variable in variables_mapping:
os.environ.pop(variable) os.environ.pop(variable)
logger.debug("Unset OS environment variable: {}".format(variable)) logger.debug(f"Unset OS environment variable: {variable}")
def get_os_environ(variable_name): def get_os_environ(variable_name):
@@ -109,7 +109,7 @@ def query_json(json_content, query, delimiter='.'):
""" """
raise_flag = False raise_flag = False
response_body = u"response body: {}\n".format(json_content) response_body = f"response body: {json_content}\n"
try: try:
for key in query.split(delimiter): for key in query.split(delimiter):
if isinstance(json_content, (list, basestring)): if isinstance(json_content, (list, basestring)):
@@ -118,13 +118,13 @@ def query_json(json_content, query, delimiter='.'):
json_content = json_content[key] json_content = json_content[key]
else: else:
logger.error( logger.error(
"invalid type value: {}({})".format(json_content, type(json_content))) f"invalid type value: {json_content}({type(json_content)})")
raise_flag = True raise_flag = True
except (KeyError, ValueError, IndexError): except (KeyError, ValueError, IndexError):
raise_flag = True raise_flag = True
if raise_flag: if raise_flag:
err_msg = u"Failed to extract! => {}\n".format(query) err_msg = f"Failed to extract! => {query}\n"
err_msg += response_body err_msg += response_body
logger.error(err_msg) logger.error(err_msg)
raise exceptions.ExtractFailure(err_msg) raise exceptions.ExtractFailure(err_msg)
@@ -371,21 +371,21 @@ def create_scaffold(project_name):
""" create scaffold with specified project name. """ create scaffold with specified project name.
""" """
if os.path.isdir(project_name): if os.path.isdir(project_name):
logger.warning(u"Folder {} exists, please specify a new folder name.".format(project_name)) logger.warning(f"Folder {project_name} exists, please specify a new folder name.")
return return
logger.info("Start to create new project: {}".format(project_name)) logger.info(f"Start to create new project: {project_name}")
logger.info("CWD: {}".format(os.getcwd())) logger.info(f"CWD: {os.getcwd()}")
def create_folder(path): def create_folder(path):
os.makedirs(path) os.makedirs(path)
msg = "created folder: {}".format(path) msg = f"created folder: {path}"
logger.info(msg) logger.info(msg)
def create_file(path, file_content=""): def create_file(path, file_content=""):
with open(path, 'w') as f: with open(path, 'w') as f:
f.write(file_content) f.write(file_content)
msg = "created file: {}".format(path) msg = f"created file: {path}"
logger.info(msg) logger.info(msg)
demo_api_content = """ demo_api_content = """
@@ -526,14 +526,14 @@ def prettify_json_file(file_list):
""" """
for json_file in set(file_list): for json_file in set(file_list):
if not json_file.endswith(".json"): if not json_file.endswith(".json"):
logger.warning("Only JSON file format can be prettified, skip: {}".format(json_file)) logger.warning(f"Only JSON file format can be prettified, skip: {json_file}")
continue continue
logger.info("Start to prettify JSON file: {}".format(json_file)) logger.info(f"Start to prettify JSON file: {json_file}")
dir_path = os.path.dirname(json_file) dir_path = os.path.dirname(json_file)
file_name, file_suffix = os.path.splitext(os.path.basename(json_file)) file_name, file_suffix = os.path.splitext(os.path.basename(json_file))
outfile = os.path.join(dir_path, "{}.pretty.json".format(file_name)) outfile = os.path.join(dir_path, f"{file_name}.pretty.json")
with io.open(json_file, 'r', encoding='utf-8') as stream: with io.open(json_file, 'r', encoding='utf-8') as stream:
try: try:
@@ -545,7 +545,7 @@ def prettify_json_file(file_list):
json.dump(obj, out, indent=4, separators=(',', ': ')) json.dump(obj, out, indent=4, separators=(',', ': '))
out.write('\n') out.write('\n')
print("success: {}".format(outfile)) print(f"success: {outfile}")
def omit_long_data(body, omit_len=512): def omit_long_data(body, omit_len=512):
@@ -560,7 +560,7 @@ def omit_long_data(body, omit_len=512):
omitted_body = body[0:omit_len] omitted_body = body[0:omit_len]
appendix_str = " ... OMITTED {} CHARACTORS ...".format(body_len - omit_len) appendix_str = f" ... OMITTED {body_len - omit_len} CHARACTORS ..."
if isinstance(body, bytes): if isinstance(body, bytes):
appendix_str = appendix_str.encode("utf-8") appendix_str = appendix_str.encode("utf-8")
@@ -604,11 +604,11 @@ def dump_json_file(json_data, json_file_abs_path):
cls=PythonObjectEncoder cls=PythonObjectEncoder
) )
msg = "dump file: {}".format(json_file_abs_path) msg = f"dump file: {json_file_abs_path}"
logger.info(msg) logger.info(msg)
except TypeError as ex: except TypeError as ex:
msg = "Failed to dump json file: {}\nReason: {}".format(json_file_abs_path, ex) msg = f"Failed to dump json file: {json_file_abs_path}\nReason: {ex}"
logger.error(msg) logger.error(msg)
@@ -620,7 +620,7 @@ def prepare_dump_json_file_abs_path(project_mapping, tag_name):
if not test_path: if not test_path:
# running passed in testcase/testsuite data structure # running passed in testcase/testsuite data structure
dump_file_name = "tests_mapping.{}.json".format(tag_name) dump_file_name = f"tests_mapping.{tag_name}.json"
dumped_json_file_abs_path = os.path.join(pwd_dir_path, "logs", dump_file_name) dumped_json_file_abs_path = os.path.join(pwd_dir_path, "logs", dump_file_name)
return dumped_json_file_abs_path return dumped_json_file_abs_path
@@ -630,12 +630,12 @@ def prepare_dump_json_file_abs_path(project_mapping, tag_name):
if os.path.isdir(test_path): if os.path.isdir(test_path):
file_foder_path = os.path.join(logs_dir_path, test_path_relative_path) file_foder_path = os.path.join(logs_dir_path, test_path_relative_path)
dump_file_name = "all.{}.json".format(tag_name) dump_file_name = f"all.{tag_name}.json"
else: else:
file_relative_folder_path, test_file = os.path.split(test_path_relative_path) file_relative_folder_path, test_file = os.path.split(test_path_relative_path)
file_foder_path = os.path.join(logs_dir_path, file_relative_folder_path) file_foder_path = os.path.join(logs_dir_path, file_relative_folder_path)
test_file_name, _file_suffix = os.path.splitext(test_file) test_file_name, _file_suffix = os.path.splitext(test_file)
dump_file_name = "{}.{}.json".format(test_file_name, tag_name) dump_file_name = f"{test_file_name}.{tag_name}.json"
dumped_json_file_abs_path = os.path.join(file_foder_path, dump_file_name) dumped_json_file_abs_path = os.path.join(file_foder_path, dump_file_name)
return dumped_json_file_abs_path return dumped_json_file_abs_path
+18 -21
View File
@@ -3,7 +3,9 @@
import sys import sys
import traceback import traceback
from httprunner import exceptions, logger, parser from loguru import logger
from httprunner import exceptions, parser
class Validator(object): class Validator(object):
@@ -70,12 +72,12 @@ class Validator(object):
} }
script = "\n ".join(script) script = "\n ".join(script)
code = """ code = f"""
# encoding: utf-8 # encoding: utf-8
def run_validate_script(): def run_validate_script():
{} {script}
""".format(script) """
variables = { variables = {
"status_code": self.resp_obj.status_code, "status_code": self.resp_obj.status_code,
@@ -88,12 +90,12 @@ def run_validate_script():
try: try:
exec(code, variables) exec(code, variables)
except SyntaxError as ex: except SyntaxError as ex:
logger.log_warning("SyntaxError in python validate script: {}".format(ex)) logger.warning(f"SyntaxError in python validate script: {ex}")
result["check_result"] = "fail" result["check_result"] = "fail"
result["output"] = "<br/>".join([ result["output"] = "<br/>".join([
"ErrorMessage: {}".format(ex.msg), f"ErrorMessage: {ex.msg}",
"ErrorLine: {}".format(ex.lineno), f"ErrorLine: {ex.lineno}",
"ErrorText: {}".format(ex.text) f"ErrorText: {ex.text}"
]) ])
return result return result
@@ -101,7 +103,7 @@ def run_validate_script():
# run python validate script # run python validate script
variables["run_validate_script"]() variables["run_validate_script"]()
except Exception as ex: except Exception as ex:
logger.log_warning("run python validate script failed: {}".format(ex)) logger.warning(f"run python validate script failed: {ex}")
result["check_result"] = "fail" result["check_result"] = "fail"
_type, _value, _tb = sys.exc_info() _type, _value, _tb = sys.exc_info()
@@ -118,8 +120,8 @@ def run_validate_script():
line_no = "N/A" line_no = "N/A"
result["output"] = "<br/>".join([ result["output"] = "<br/>".join([
"ErrorType: {}".format(_type.__name__), f"ErrorType: {_type.__name__}",
"ErrorLine: {}".format(line_no) f"ErrorLine: {line_no}"
]) ])
return result return result
@@ -131,7 +133,7 @@ def run_validate_script():
if not validators: if not validators:
return return
logger.log_debug("start to validate.") logger.debug("start to validate.")
validate_pass = True validate_pass = True
failures = [] failures = []
@@ -154,7 +156,7 @@ def run_validate_script():
# validator should be LazyFunction object # validator should be LazyFunction object
if not isinstance(validator, parser.LazyFunction): if not isinstance(validator, parser.LazyFunction):
raise exceptions.ValidationFailure( raise exceptions.ValidationFailure(
"validator should be parsed first: {}".format(validators)) f"validator should be parsed first: {validators}")
# evaluate validator args with context variable mapping. # evaluate validator args with context variable mapping.
validator_args = validator.get_args() validator_args = validator.get_args()
@@ -171,18 +173,13 @@ def run_validate_script():
"expect": expect_item, "expect": expect_item,
"expect_value": expect_value "expect_value": expect_value
} }
validate_msg = "\nvalidate: {} {} {}({})".format( validate_msg = f"\nvalidate: {check_item} {comparator} {expect_value}({type(expect_value).__name__})"
check_item,
comparator,
expect_value,
type(expect_value).__name__
)
try: try:
validator.to_value(self.session_context.test_variables_mapping) validator.to_value(self.session_context.test_variables_mapping)
validator_dict["check_result"] = "pass" validator_dict["check_result"] = "pass"
validate_msg += "\t==> pass" validate_msg += "\t==> pass"
logger.log_debug(validate_msg) logger.debug(validate_msg)
except (AssertionError, TypeError): except (AssertionError, TypeError):
validate_pass = False validate_pass = False
validator_dict["check_result"] = "fail" validator_dict["check_result"] = "fail"
@@ -194,7 +191,7 @@ def run_validate_script():
expect_value, expect_value,
type(expect_value).__name__ type(expect_value).__name__
) )
logger.log_error(validate_msg) logger.error(validate_msg)
failures.append(validate_msg) failures.append(validate_msg)
self.validation_results["validate_extractor"].append(validator_dict) self.validation_results["validate_extractor"].append(validator_dict)