http-content-parser 0.0.17__tar.gz → 0.0.19__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (18) hide show
  1. {http_content_parser-0.0.17 → http_content_parser-0.0.19}/.gitignore +4 -1
  2. {http_content_parser-0.0.17 → http_content_parser-0.0.19}/PKG-INFO +4 -4
  3. {http_content_parser-0.0.17 → http_content_parser-0.0.19}/README.md +1 -1
  4. {http_content_parser-0.0.17 → http_content_parser-0.0.19}/pyproject.toml +2 -2
  5. http_content_parser-0.0.19/src/http_content_parser/api_parser.py +165 -0
  6. {http_content_parser-0.0.17 → http_content_parser-0.0.19}/src/http_content_parser/curl_parser.py +7 -4
  7. {http_content_parser-0.0.17 → http_content_parser-0.0.19}/src/http_content_parser/generate_api_file.py +9 -30
  8. {http_content_parser-0.0.17 → http_content_parser-0.0.19}/src/http_content_parser/req_data.py +1 -1
  9. http_content_parser-0.0.19/tests/test_api_model_parser.py +10 -0
  10. http_content_parser-0.0.19/tests/test_curl.py +20 -0
  11. http_content_parser-0.0.17/tests/test_curl.py +0 -20
  12. {http_content_parser-0.0.17 → http_content_parser-0.0.19}/LICENSE +0 -0
  13. {http_content_parser-0.0.17 → http_content_parser-0.0.19}/requirements.txt +0 -0
  14. {http_content_parser-0.0.17 → http_content_parser-0.0.19}/src/http_content_parser/__init__.py +0 -0
  15. {http_content_parser-0.0.17 → http_content_parser-0.0.19}/src/http_content_parser/openapi_parser.py +0 -0
  16. {http_content_parser-0.0.17 → http_content_parser-0.0.19}/src/http_content_parser/param_util.py +0 -0
  17. {http_content_parser-0.0.17 → http_content_parser-0.0.19}/src/http_content_parser/postman_parser.py +0 -0
  18. {http_content_parser-0.0.17 → http_content_parser-0.0.19}/src/http_content_parser/swagger2_parser.py +0 -0
@@ -158,4 +158,7 @@ cython_debug/
158
158
  # and can be added to the global gitignore or merged into this file. For a more nuclear
159
159
  # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160
160
  #.idea/
161
- .vscode/
161
+ .vscode/
162
+
163
+ #
164
+ tmp
@@ -1,8 +1,8 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: http_content_parser
3
- Version: 0.0.17
3
+ Version: 0.0.19
4
4
  Summary: parse http's payload and response
5
- Author-email: max su <suleiabc@gmail.com>
5
+ Author-email: leo <suleiabc@gmail.com>
6
6
  License-File: LICENSE
7
7
  Classifier: License :: OSI Approved :: MIT License
8
8
  Classifier: Operating System :: OS Independent
@@ -24,5 +24,5 @@ python3 -m build
24
24
 
25
25
  ```bash
26
26
  rm -f dist/*
27
- python3 -m twine upload dist/*
27
+ python3 -m twine upload dist/*
28
28
  ```
@@ -12,5 +12,5 @@ python3 -m build
12
12
 
13
13
  ```bash
14
14
  rm -f dist/*
15
- python3 -m twine upload dist/*
15
+ python3 -m twine upload dist/*
16
16
  ```
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "http_content_parser"
7
- version = "0.0.17"
8
- authors = [{ name = "max su", email = "suleiabc@gmail.com" }]
7
+ version = "0.0.19"
8
+ authors = [{ name = "leo", email = "suleiabc@gmail.com" }]
9
9
  description = "parse http's payload and response"
10
10
  readme = "README.md"
11
11
  requires-python = ">=3.8"
@@ -0,0 +1,165 @@
1
+ # -*- coding: UTF-8 -*-
2
+ import copy
3
+ import json
4
+ import re
5
+ from http_content_parser.curl_parser import CurlParser
6
+ from http_content_parser.openapi_parser import OpenApiParser
7
+ from http_content_parser.postman_parser import parse_postman
8
+ from http_content_parser.req_data import ReqData
9
+ from http_content_parser.swagger2_parser import Swagger2Parser
10
+
11
+
12
+ class ApiModelParser:
13
+ def get_api_model_for_curl(self, curl_file, curl_filter=None) -> list[ReqData]:
14
+ # convert curl
15
+ payload_list = self.convert_curl_data_to_model(
16
+ curl_file_path=curl_file, url_filter=curl_filter
17
+ )
18
+ # handle duplicate key
19
+ new_payload_list = self.__handle_duplicate_api_label(payload_list)
20
+ return new_payload_list
21
+
22
+ def get_api_model_for_postman(self, json_dict: dict) -> list[ReqData]:
23
+ payload_list = self.convert_postman_to_model(postman_dict=json_dict)
24
+ # handle duplicate key
25
+ new_payload_list = self.__handle_duplicate_api_label(payload_list)
26
+ return new_payload_list
27
+
28
+ def get_api_model_for_swagger(self, json_dict: dict) -> list[ReqData]:
29
+ payload_list = self.convert_swagger_to_model(swagger2_dict=json_dict)
30
+ # handle duplicate key
31
+ new_payload_list = self.__handle_duplicate_api_label(payload_list)
32
+ return new_payload_list
33
+
34
+ def get_api_model_for_openapi(self, json_dict: dict) -> list[ReqData]:
35
+ payload_list = self.convert_openapi_to_model(openapi_dict=json_dict)
36
+ # handle duplicate key
37
+ new_payload_list = self.__handle_duplicate_api_label(payload_list)
38
+ return new_payload_list
39
+
40
+ def convert_curl_data_to_model(
41
+ self, curl_file_path: str, url_filter=None
42
+ ) -> list[ReqData]:
43
+ curl_parser = CurlParser()
44
+ payload_list = []
45
+ with open(curl_file_path, "rt") as f:
46
+ lines = f.readlines()
47
+ line_num_array = curl_parser.get_curl_line_num_scope(lines=lines)
48
+ for r in line_num_array:
49
+ res_dict = curl_parser.split_curl_to_struct(
50
+ lines, r[0], r[1], url_filter
51
+ )
52
+ req_model = ReqData(dd=res_dict)
53
+ url_content = curl_parser.parse_url(req_model.original_url)
54
+ req_model.temp_api_label = (
55
+ self.__replace_api_label_chars(url_content["path"][1:])
56
+ + "_"
57
+ + req_model.method
58
+ )
59
+ req_model.header = json.dumps(req_model.header)
60
+ req_model.query_param = json.dumps(url_content["query_params"])
61
+ req_model.path = url_content["path"][1:]
62
+ payload_list.append(req_model)
63
+ return payload_list
64
+
65
+ def convert_postman_to_model(self, postman_dict: dict) -> list[ReqData]:
66
+ api_infos = parse_postman(postman_dict)
67
+ payload_list = []
68
+ for api_info in api_infos:
69
+ req_data = ReqData()
70
+ req_data.path = api_info["path"]
71
+ req_data.header = json.dumps(api_info["header"])
72
+ req_data.body = api_info["body"]
73
+ req_data.query_param = json.dumps(api_info["query_param"])
74
+ req_data.original_url = api_info["url"]
75
+ req_data.method = api_info["method"].lower()
76
+ req_data.temp_api_label = (
77
+ self.__handle_http_path(api_info["path"].split("/"), "_")
78
+ .replace("{", "")
79
+ .replace("}", "")
80
+ + "_"
81
+ + api_info["method"].lower()
82
+ )
83
+ payload_list.append(req_data)
84
+ return payload_list
85
+
86
+ def convert_swagger_to_model(self, swagger2_dict: dict) -> list[ReqData]:
87
+ swagger_parser = Swagger2Parser(swagger2_dict)
88
+ api_dict = swagger_parser.get_swagger_api_info()
89
+ if not api_dict:
90
+ print("check your swagger json")
91
+ return
92
+ payload_list = []
93
+ for path, path_info in api_dict.items():
94
+ req_data = ReqData()
95
+ req_data.path = self.__handle_http_path(path.split("/")[:-1], "/")
96
+ req_data.temp_api_label = (
97
+ self.__handle_http_path(path.split("/"), "_")
98
+ .replace("{", "")
99
+ .replace("}", "")
100
+ )
101
+ req_data.method = path.split("/")[-1]
102
+ req_data.query_param = json.dumps(path_info["query_param"])
103
+ req_data.path_param = json.dumps(path_info["path_param"])
104
+ req_data.response = json.dumps(path_info.get("response", {}))
105
+ # swagger中body第一层和第二层key重复,只取第二层后的数据
106
+ for _, v in path_info["body_param"].items():
107
+ req_data.body = json.dumps(v)
108
+ payload_list.append(req_data)
109
+ return payload_list
110
+
111
+ def convert_openapi_to_model(self, openapi_dict: dict) -> list[ReqData]:
112
+ if not openapi_dict:
113
+ print("openapi dict is null")
114
+ return []
115
+ payload_list = []
116
+ parser = OpenApiParser(openapi_dict)
117
+ api_dict = parser.get_open_api_info()
118
+ if not api_dict:
119
+ print("check your swagger json")
120
+ return
121
+ for path, path_info in api_dict.items():
122
+ req_data = ReqData()
123
+ req_data.path = self.__handle_http_path(path.split("/")[:-1], "/")
124
+ req_data.temp_api_label = (
125
+ self.__handle_http_path(path.split("/"), "_")
126
+ .replace("{", "")
127
+ .replace("}", "")
128
+ )
129
+ req_data.method = path.split("/")[-1]
130
+ req_data.query_param = json.dumps(path_info["query_param"])
131
+ req_data.path_param = json.dumps(path_info["path_param"])
132
+ req_data.response = json.dumps(path_info.get("response", {}))
133
+ req_data.body = json.dumps(path_info["body_param"])
134
+ payload_list.append(req_data)
135
+ return payload_list
136
+
137
+ def __handle_http_path(self, path_list: list, split_char: str) -> str:
138
+ if not path_list:
139
+ return ""
140
+ url_path = ""
141
+ for u in path_list:
142
+ if u:
143
+ url_path += u + split_char
144
+ return url_path[:-1]
145
+
146
+ def __replace_api_label_chars(self, string: str) -> str:
147
+ pattern = r"[+/@?=.]" # 定义要匹配的特殊字符模式
148
+ replacement = "_" # 替换为的字符串
149
+
150
+ new_string = re.sub(pattern, replacement, string)
151
+ return new_string
152
+
153
+ def __handle_duplicate_api_label(
154
+ self, payload_list: list[ReqData]
155
+ ) -> list[ReqData]:
156
+ key_filter = {}
157
+ new_payload_list = copy.deepcopy(payload_list)
158
+ for payload, p_copy in zip(payload_list, new_payload_list):
159
+ k = payload.temp_api_label
160
+ if k in key_filter.keys():
161
+ p_copy.temp_api_label = k + "_" + str(key_filter[k])
162
+ key_filter[k] += 1
163
+ else:
164
+ key_filter[k] = 2
165
+ return new_payload_list
@@ -5,6 +5,8 @@ from urllib.parse import urlparse, parse_qs
5
5
 
6
6
  class CurlParser(object):
7
7
  def parse_url(self, url: str) -> dict:
8
+ if "://" not in url:
9
+ url = "http://" + url
8
10
  # 解析 URL
9
11
  parsed_url = urlparse(url)
10
12
  # 获取各个组成部分
@@ -62,7 +64,7 @@ class CurlParser(object):
62
64
  line_num_array.append([start_num, num])
63
65
  return line_num_array
64
66
 
65
- def split_curl_to_struct(self, lines, s, e, curl_filter=None) -> dict:
67
+ def split_curl_to_struct(self, lines, s, e, url_filter=None) -> dict:
66
68
  req_data = {}
67
69
  header = {}
68
70
  reduced_lines = self.reduce_curl_data_part(lines=lines, s=s, e=e)
@@ -70,8 +72,8 @@ class CurlParser(object):
70
72
  lines_i_str = str(reduced_lines[i])
71
73
  line_i_list = lines_i_str.split(" ")
72
74
  if "curl" in lines_i_str:
73
- if curl_filter:
74
- if curl_filter not in lines_i_str:
75
+ if url_filter:
76
+ if url_filter not in lines_i_str:
75
77
  # 如果curl_filter 不存在于当前Url中,则跳过本次循环
76
78
  continue
77
79
  for line_sub in line_i_list:
@@ -106,7 +108,8 @@ class CurlParser(object):
106
108
  curl_data = line_i_list[1]
107
109
  else:
108
110
  curl_data = line_i_list[0]
109
- body = re.sub( r"\n\s*", "", curl_data.replace(" \\\n", ""))
111
+ body = re.sub(r"\n\s*", "", curl_data.replace(" \\\n", ""))
112
+ # body = re.sub(r"\s*", "", curl_data.replace(" \\\n", ""))
110
113
  req_data["body"] = body[:-1]
111
114
 
112
115
  if not req_data.get("method"):
@@ -11,6 +11,7 @@ from http_content_parser.openapi_parser import OpenApiParser
11
11
  from http_content_parser.postman_parser import parse_postman
12
12
 
13
13
 
14
+ # TODO 不直接生成yaml文件,只生成dict,方便后续扩展
14
15
  class GenerateApiFile:
15
16
  def __init__(self) -> None:
16
17
  pass
@@ -39,7 +40,7 @@ class GenerateApiFile:
39
40
  def produce_api_yaml_for_curl(self, curl_file, yaml_file, curl_filter=None):
40
41
  # convert curl
41
42
  payload_list = self.convert_curl_data_to_model(
42
- curl_file_path=curl_file, curl_filter=curl_filter
43
+ curl_file_path=curl_file, url_filter=curl_filter
43
44
  )
44
45
  # handle duplicate key
45
46
  new_payload_list = self.handle_duplicate_yaml_key(payload_list)
@@ -56,11 +57,11 @@ class GenerateApiFile:
56
57
  p_copy.temp_api_label = k + "_" + str(key_filter[k])
57
58
  key_filter[k] += 1
58
59
  else:
59
- key_filter[k] = 1
60
+ key_filter[k] = 2
60
61
  return new_payload_list
61
62
 
62
63
  def convert_curl_data_to_model(
63
- self, curl_file_path, curl_filter=None
64
+ self, curl_file_path, url_filter=None
64
65
  ) -> list[ReqData]:
65
66
  curl_parser = CurlParser()
66
67
  payload_list = []
@@ -69,7 +70,7 @@ class GenerateApiFile:
69
70
  line_num_array = curl_parser.get_curl_line_num_scope(lines=lines)
70
71
  for r in line_num_array:
71
72
  res_dict = curl_parser.split_curl_to_struct(
72
- lines, r[0], r[1], curl_filter
73
+ lines, r[0], r[1], url_filter
73
74
  )
74
75
  req_model = ReqData(dd=res_dict)
75
76
  url_content = curl_parser.parse_url(req_model.original_url)
@@ -79,36 +80,14 @@ class GenerateApiFile:
79
80
  + req_model.method
80
81
  )
81
82
  req_model.header = json.dumps(req_model.header)
82
- req_model.query_param = json.dumps(url_content["query_params"])
83
+ if url_content["query_params"]:
84
+ req_model.query_param = json.dumps(url_content["query_params"])
85
+ else:
86
+ req_model.query_param = {}
83
87
  req_model.path = url_content["path"][1:]
84
88
  payload_list.append(req_model)
85
89
  return payload_list
86
90
 
87
- def convert_curl_data_to_model_old(
88
- self, curl_file_path, curl_filter=None
89
- ) -> list[ReqData]:
90
- curl_parser = CurlParser()
91
- payload_list = []
92
- with open(curl_file_path, "rt") as f:
93
- lines = f.readlines()
94
- line_num_array = curl_parser.get_curl_line_num_scope(lines=lines)
95
- for r in line_num_array:
96
- res_dict = curl_parser.split_curl_to_struct(
97
- lines, r[0], r[1], curl_filter
98
- )
99
- template = ReqData(dd=res_dict)
100
- split_url = curl_parser.split_url(template.original_url, "_")
101
- template.temp_api_label = (
102
- self.replace_api_label_chars(split_url["url_path"])
103
- + template.method
104
- )
105
- template.header = json.dumps(template.header)
106
- template.query_param = json.dumps(split_url["url_params"])
107
- split_url_origin = curl_parser.split_url(template.original_url, "/")
108
- template.path = split_url_origin["url_path"][:-1]
109
- payload_list.append(template)
110
- return payload_list
111
-
112
91
  def produce_api_yaml_for_swagger2(self, swagger2_dict, yaml_file):
113
92
  swagger_parser = Swagger2Parser(swagger2_dict)
114
93
  api_dict = swagger_parser.get_swagger_api_info()
@@ -1,7 +1,7 @@
1
1
  # -*- coding: UTF-8 -*-
2
2
 
3
3
  """
4
- __author__ = maxsulei
4
+ __author__ = leo
5
5
  """
6
6
 
7
7
 
@@ -0,0 +1,10 @@
1
+ from http_content_parser.api_parser import ApiModelParser
2
+
3
+
4
+ api_parser = ApiModelParser()
5
+
6
+
7
+ def test_curl_parser():
8
+ curl_file = "./tmp"
9
+ api_info = api_parser.get_api_model_for_curl(curl_file=curl_file)
10
+ print(api_info)
@@ -0,0 +1,20 @@
1
+ import json
2
+
3
+ from http_content_parser.generate_api_file import GenerateApiFile
4
+
5
+
6
+ def test_curl():
7
+ gaf = GenerateApiFile()
8
+ # with open("./postman.json", "r") as f:
9
+ # json_dict = json.load(f)
10
+ # gaf.produce_api_yaml_for_postman(json_dict, "./test.yaml")
11
+ curl_file = (
12
+ "./tmp"
13
+ )
14
+ gaf.produce_api_yaml_for_curl(curl_file=curl_file, yaml_file="api.yaml")
15
+
16
+
17
+ def test_for():
18
+ a = "#!/usr/bin/env bash \t\n \n echo \\n 66 >> /root/pre23"
19
+ b = a.replace("\n", "")
20
+ print(b)
@@ -1,20 +0,0 @@
1
- import json
2
-
3
- from http_content_parser.generate_api_file import GenerateApiFile
4
-
5
-
6
- def test_curl():
7
- gaf = GenerateApiFile()
8
- # with open("./postman.json", "r") as f:
9
- # json_dict = json.load(f)
10
- # gaf.produce_api_yaml_for_postman(json_dict, "./test.yaml")
11
- curl_file = ""
12
- res = gaf.produce_api_yaml_for_curl(curl_file=curl_file, yaml_file="api.yaml")
13
-
14
-
15
- def test_for():
16
- data = {"name": "John", "age": 30, "city": "New York"}
17
- temp = '{ "job_id":{{job_id}}, "product_id": 4, "local_user_id": 0}'
18
- temp = json.dumps(data)
19
- temp = json.loads(temp)
20
- print(temp)