diff --git a/httprunner/compat.py b/httprunner/compat.py index ae88f4c9..72716b22 100644 --- a/httprunner/compat.py +++ b/httprunner/compat.py @@ -7,6 +7,7 @@ httprunner.compat This module handles import compatibility issues between Python 2 and Python 3. """ +from collections import OrderedDict try: import simplejson as json @@ -39,8 +40,6 @@ except AttributeError: JSONDecodeError = ValueError if is_py2: - from urllib3.packages.ordered_dict import OrderedDict - builtin_str = str bytes = str str = unicode @@ -51,8 +50,6 @@ if is_py2: FileNotFoundError = IOError elif is_py3: - from collections import OrderedDict - builtin_str = str str = str bytes = bytes diff --git a/httprunner/parser.py b/httprunner/parser.py index 7ea6788b..6c22c7e3 100644 --- a/httprunner/parser.py +++ b/httprunner/parser.py @@ -1,7 +1,6 @@ # encoding: utf-8 import ast -import copy import os import re @@ -601,7 +600,6 @@ def parse_tests(testcases, variables_mapping=None): list: parsed testcases list, with config variables/parameters/name/request parsed. """ - # exception_stage = "parse tests" variables_mapping = variables_mapping or {} parsed_testcases_list = [] @@ -629,7 +627,7 @@ def parse_tests(testcases, variables_mapping=None): ) or [{}] for parameter_mapping in cartesian_product_parameters_list: - testcase_dict = copy.deepcopy(testcase) + testcase_dict = utils.deepcopy_dict(testcase) config = testcase_dict.get("config") # parse config variables diff --git a/httprunner/utils.py b/httprunner/utils.py index 94ad82a1..fc09ebe1 100644 --- a/httprunner/utils.py +++ b/httprunner/utils.py @@ -203,6 +203,42 @@ def convert_mappinglist_to_orderdict(mapping_list): return ordered_dict +def deepcopy_dict(data): + """ deepcopy dict data, ignore file object (_io.BufferedReader) + + Args: + data (dict): dict data structure + { + 'a': 1, + 'b': [2, 4], + 'c': lambda x: x+1, + 'd': open('LICENSE'), + 'f': { + 'f1': {'a1': 2}, + 'f2': io.open('LICENSE', 'rb'), + } + } + + Returns: + dict: deep copied dict data, with file object unchanged. + + """ + try: + return copy.deepcopy(data) + except TypeError: + copied_data = {} + for key, value in data.items(): + if isinstance(value, dict): + copied_data[key] = deepcopy_dict(value) + else: + try: + copied_data[key] = copy.deepcopy(value) + except TypeError: + copied_data[key] = value + + return copied_data + + def update_ordered_dict(ordered_dict, override_mapping): """ override ordered_dict with new mapping. diff --git a/tests/test_utils.py b/tests/test_utils.py index c382bed0..963e56c5 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,3 +1,4 @@ +import io import os import shutil @@ -214,6 +215,26 @@ class TestUtils(ApiServerUnittest): self.assertIsInstance(ordered_dict, dict) self.assertIn("a", ordered_dict) + def test_deepcopy_dict(self): + data = { + 'a': 1, + 'b': [2, 4], + 'c': lambda x: x+1, + 'd': open('LICENSE'), + 'f': { + 'f1': {'a1': 2}, + 'f2': io.open('LICENSE', 'rb'), + } + } + new_data = utils.deepcopy_dict(data) + data["a"] = 0 + self.assertEqual(new_data["a"], 1) + data["f"]["f1"] = 123 + self.assertEqual(new_data["f"]["f1"], {'a1': 2}) + self.assertNotEqual(id(new_data["b"]), id(data["b"])) + self.assertEqual(id(new_data["c"]), id(data["c"])) + # self.assertEqual(id(new_data["d"]), id(data["d"])) + def test_update_ordered_dict(self): map_list = [ {"a": 1},