diff --git a/httpfpt/cli.py b/httpfpt/cli.py index 205b352..31d757e 100644 --- a/httpfpt/cli.py +++ b/httpfpt/cli.py @@ -1,13 +1,16 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- +from __future__ import annotations + import re import sys -from typing import Optional, Tuple +from typing import Tuple -import typer +import cappa +from cappa import Subcommands from pydantic import ValidationError -from rich import print -from typing_extensions import Annotated +from rich.prompt import Confirm +from typing_extensions import Annotated # noqa: TCH002 sys.path.append('..') @@ -18,243 +21,263 @@ from httpfpt.utils.data_manage.openapi import SwaggerParser from httpfpt.utils.data_manage.apifox import ApiFoxParser from httpfpt.utils.data_manage.git_repo import GitRepoPaser - -app = typer.Typer(add_completion=False, epilog='Made by :beating_heart: wu-clan', rich_markup_mode='rich') +from httpfpt.utils.rich_console import console -def get_version(version: bool) -> None: +def get_version() -> None: """获取版本号""" - if version: - ver = open('./__init__.py', 'rt').read() - mob = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", ver, re.M) - if mob: - print('Fastpt', mob.group(1)) - raise typer.Exit() - else: - raise RuntimeError('未查询到版本号') + ver = open('./__init__.py', 'rt').read() + mob = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", ver, re.M) + if mob: + console.print('\n🔥 HttpFpt', mob.group(1)) + else: + raise RuntimeError('未查询到版本号') -def testcase_date_verify(verify: str) -> None: +def testcase_data_verify(verify: str) -> None: """测试数据验证""" msg: str = '' try: count: int = 0 if verify.lower() == 'all': - typer.secho('🔥 开始验证所有测试数据结构...', fg='cyan', bold=True) + console.print('\n🔥 开始验证所有测试数据结构...') file_list = search_all_case_yaml_files() for file in file_list: file_data = read_yaml(None, filename=file) CaseData.model_validate(file_data) else: - typer.secho(f'🔥 开始验证 {verify} 测试数据结构...', fg='cyan', bold=True) + console.print(f'🔥 开始验证 {verify} 测试数据结构...') file_data = read_yaml(None, filename=verify) CaseData.model_validate(file_data) except ValidationError as e: count = e.error_count() msg += str(e) except Exception as e: - typer.secho(f'❌ 验证测试数据 {verify} 结构失败: {e}', fg='red', bold=True) - raise typer.Exit(1) + console.print(f'❌ 验证测试数据 {verify} 结构失败: {e}') + raise cappa.Exit(code=1) if count > 0: - typer.secho(f'❌ 验证测试数据 {verify} 结构失败: {msg}', fg='red', bold=True) - raise typer.Exit(1) + console.print(f'❌ 验证测试数据 {verify} 结构失败: {msg}') + raise cappa.Exit(code=1) else: - typer.secho('✅ 验证测试数据结构成功', fg='green', bold=True) - raise typer.Exit() + console.print('✅ 验证测试数据结构成功') -def generate_testcases(generate: bool) -> None: +def generate_testcases() -> None: """生成测试用例""" - if generate: - typer.secho( - '\n' - 'Warning: 此操作生成的测试用例是依赖测试数据文件而决定的,\n' - ' 如果你手动创建的测试用例与测试数据文件名称相吻合,\n' - ' 那么此操作将不能完全保证你的手动创建测试用例继续保留,\n' - ' 如果你依然执行此操作, 请谨慎选择重新生成所有测试用例。\n', - fg='bright_yellow', - bold=True, - ) - result = typer.confirm('⚠️ 是否重新生成所有测试用例?', default=False) - try: - if result: - typer.secho('🔥 开始重新生成所有测试用例...', fg='cyan', bold=True) - auto_generate_testcases(rewrite=True) - else: - typer.secho('🔥 开始生成新测试用例...', fg='cyan', bold=True) - auto_generate_testcases() - except Exception as e: - typer.secho(f'❌ 自动生成测试用例失败: {e}', fg='red', bold=True) - raise typer.Exit(1) + console.print( + '\n' + 'Warning: 此操作生成的测试用例是依赖测试数据文件而决定的,\n' + ' 如果你手动创建的测试用例与测试数据文件名称相吻合,\n' + ' 那么此操作将不能完全保证你的手动创建测试用例继续保留,\n' + ' 如果你依然执行此操作, 请谨慎选择重新生成所有测试用例。\n', + style='bold #ffd700', + ) + result = Confirm.ask('⚠️ 是否重新生成所有测试用例?', default=False) + try: + if result: + console.print('🔥 开始重新生成所有测试用例...') + auto_generate_testcases(rewrite=True) else: - raise typer.Exit() + console.print('🔥 开始生成新测试用例...') + auto_generate_testcases() + except Exception as e: + console.print(f'❌ 自动生成测试用例失败: {e}') + raise cappa.Exit(code=1) -def import_openapi_test_data(openapi: tuple) -> None: +def import_openapi_case_data(openapi: Tuple[str, str]) -> None: """导入 openapi 测试用例数据""" - typer.secho(f'正在导入测试用例数据到项目: {openapi[1]}', fg='bright_yellow', bold=True) - result = typer.confirm('确认执行此操作吗?', default=False) + console.print(f'\n📩 正在导入测试用例数据到项目: [#0087ff]{openapi[1]}[/#0087ff]') + result = Confirm.ask('❓ 确认执行此操作吗?', default=False) if result: - typer.secho('🔥 开始导入 openapi 数据...', fg='cyan', bold=True) + console.print('🔥 开始导入 openapi 数据...') try: SwaggerParser().import_openapi_to_yaml(openapi[0], openapi[1]) except Exception as e: - typer.secho('❌ 导入 openapi 数据失败', fg='red', bold=True) + console.print('❌ 导入 openapi 数据失败') raise e - else: - raise typer.Exit() - else: - raise typer.Abort() -def import_apifox_test_data(apifox: tuple) -> None: +def import_apifox_case_data(apifox: Tuple[str, str]) -> None: """导入 apifox 测试用例数据""" - typer.secho( - """ - Beta: 此命令目前处于测试阶段, 请谨慎使用。 - Warning: 如果现有文件名与导入文件名相同, 此命令目前会覆盖写入用例数据, 请谨慎操作。 - """, - fg='bright_yellow', - bold=True, + console.print( + '\n' 'Beta: 此命令目前处于测试阶段, 请谨慎使用。\n' 'Warning: 如果现有文件名与导入文件名相同, 此命令目前会覆盖写入用例数据, 请谨慎操作。\n', # noqa: E501 + style='bold #ffd700', ) - result = typer.confirm('⚠️ 确认执行此操作吗?', default=False) + result = Confirm.ask('⚠️ 确认执行此操作吗?', default=False) if result: - typer.secho('🔥 开始导入 apifox 数据...', fg='cyan', bold=True) + console.print('🔥 开始导入 apifox 数据...') try: ApiFoxParser().import_apifox_to_yaml(apifox[0], apifox[1]) except Exception as e: - typer.secho('❌ 导入 apifox 数据失败:', fg='red', bold=True) + console.print('❌ 导入 apifox 数据失败:') raise e - else: - raise typer.Exit() - else: - raise typer.Abort() -def import_har_test_data(har: tuple) -> None: +def import_har_case_data(har: Tuple[str, str]) -> None: """导入 har 测试用例数据""" - pass + console.print('\n🚧 此功能暂未开发') -def import_jmeter_test_data(jmeter: tuple) -> None: +def import_jmeter_case_data(jmeter: Tuple[str, str]) -> None: """导入 jmeter 测试用例数据""" - pass + console.print('\n🚧 此功能暂未开发') -def import_postman_test_data(postman: tuple) -> None: +def import_postman_case_data(postman: Tuple[str, str]) -> None: """导入 postman 测试用例数据""" - pass + console.print('\n🚧 此功能暂未开发') def import_git_case_data(src: str) -> None: """导入 git 仓库测试数据""" - typer.secho(f'正在导入 git 仓库测试数据到本地: {src}', fg='bright_yellow', bold=True) - typer.secho('🔥 开始导入 git 仓库测试数据...', fg='cyan', bold=True) + console.print(f'\n🚀 正在导入 git 仓库测试数据到本地: {src}') + console.print('🔥 开始导入 git 仓库测试数据...\n') try: GitRepoPaser.import_git_to_local(src) except Exception as e: - typer.secho(f'❌ 导入 git 仓库测试数据失败: {e}', fg='red', bold=True) + console.print(f'❌ 导入 git 仓库测试数据失败: {e}') raise e - else: - raise typer.Exit() -@app.callback(name='version') -def callback( - _get_version: Optional[bool] = typer.Option(None, '--version', '-V', help='打印版本号', callback=get_version), -) -> None: - pass +def httpfpt_cli(httpfpt: HttpFptCLI) -> None: + """CLI 入口""" + if httpfpt.version: + get_version() + if httpfpt.subcmd: + if isinstance(httpfpt.subcmd, TestCaseCLI): + data_verify = httpfpt.subcmd.data_verify + generate = httpfpt.subcmd.generate + if data_verify: + testcase_data_verify(data_verify) + if generate: + generate_testcases() + if isinstance(httpfpt.subcmd, ImportCLI): + openai = httpfpt.subcmd.openai + apifox = httpfpt.subcmd.apifox + har = httpfpt.subcmd.har + jmeter = httpfpt.subcmd.jmeter + postman = httpfpt.subcmd.postman + git = httpfpt.subcmd.git + if openai: + import_openapi_case_data(openai) + if apifox: + import_apifox_case_data(apifox) + if har: + import_har_case_data(har) + if jmeter: + import_jmeter_case_data(jmeter) + if postman: + import_postman_case_data(postman) + if git: + import_git_case_data(git) + + +@cappa.command(name='httpfpt-cli', invoke=httpfpt_cli) +class HttpFptCLI: + version: Annotated[ + bool, + cappa.Arg( + short='-V', + long=True, + default=False, + help='Print version information.', + ), + ] + subcmd: Subcommands[TestCaseCLI | ImportCLI | None] = None -@app.command('testcase', help='测试用例相关操作') -def testcase( - _testcase_date_verify: Annotated[ +@cappa.command(name='testcase', help='Test case tools', invoke=httpfpt_cli) +class TestCaseCLI: + data_verify: Annotated[ str, - typer.Option( - '--testcase-date-verify', - '-tdv', - metavar='', - show_default=False, - help='验证测试数据结构, 当指定文件名时, 验证指定文件, 当指定 "all" 时, 验证所有文件', - callback=testcase_date_verify, + cappa.Arg( + value_name='', + short='-dv', + long=True, + default='', + help='验证测试数据结构;当指定文件时, 仅验证指定文件, 当指定 "all" 时, 验证所有文件.', + required=False, + ), + ] + generate: Annotated[ + bool, + cappa.Arg( + short='-gt', + long=True, + default=False, + help='自动生成测试用例.', + required=False, ), - ], - _generate_testcases: Annotated[ - Optional[bool], - typer.Option('--generate-testcases', '-gt', help='自动生成测试用例', callback=generate_testcases), - ] = None, -) -> None: - pass - - -@app.command('import', help='导入测试用例数据') -def import_testcase_data( - _import_openapi_testcase_data: Annotated[ + ] + + +@cappa.command(name='import', help='Import test case data', invoke=httpfpt_cli) +class ImportCLI: + openai: Annotated[ Tuple[str, str], - typer.Option( - '--import-openapi-testcase-data', - '-io', - '-is', - show_default=False, - metavar='', - help='导入 openapi / swagger 数据到 yaml 数据文件; 通过 json_file / url 导入; project: 指定项目名', - callback=import_openapi_test_data, + cappa.Arg( + value_name=' ', + short='-io', + long='--import-openapi', + default=(), + help='导入 openapi 数据到 yaml 数据文件; 支持 json 文件 / url 导入, 需要指定 project 项目名.', + required=False, ), - ], - _import_apifox_testcase_data: Annotated[ + ] + apifox: Annotated[ Tuple[str, str], - typer.Option( - '--import-apifox-testcase-data', - '-ia', - show_default=False, - metavar='', - help='Beta: 导入 apifox 数据到 yaml 数据文件; 通过 json_file 导入; project: 指定项目名', - callback=import_apifox_test_data, + cappa.Arg( + value_name=' ', + short='-ia', + long='--import-apifox', + default=(), + help='Beta: 导入 apifox 数据到 yaml 数据文件; 支持 json 文件导入, 需要指定 project 项目名.', + required=False, ), - ], - _import_har_testcase_data: Annotated[ + ] + har: Annotated[ Tuple[str, str], - typer.Option( - '--import-har-testcase-data', - '-ih', - show_default=False, - help='TODO: Not started yet', - callback=import_har_test_data, + cappa.Arg( + short='-ih', + long='--import-har', + default=(), + help='TODO: Not started yet.', + required=False, ), - ], - _import_jmeter_testcase_data: Annotated[ + ] + jmeter: Annotated[ Tuple[str, str], - typer.Option( - '--import-jmeter-testcase-data', - '-ij', - show_default=False, - help='TODO: Not started yet', - callback=import_jmeter_test_data, + cappa.Arg( + short='-ij', + long='--import-jmeter', + default=(), + help='TODO: Not started yet.', + required=False, ), - ], - _import_postman_testcase_data: Annotated[ + ] + postman: Annotated[ Tuple[str, str], - typer.Option( - '--import-postman-testcase-data', - '-ipm', - show_default=False, - help='TODO: Not started yet', - callback=import_postman_test_data, + cappa.Arg( + short='-ip', + long='--import-postman', + default=(), + help='TODO: Not started yet.', + required=False, ), - ], - _import_git_repo_testcase_data: Annotated[ + ] + git: Annotated[ str, - typer.Option( - '--import-git-repo-testcase-data', - '-igr', - show_default=False, - help='导入 git 仓库测试数据到本地', - callback=import_git_case_data, + cappa.Arg( + value_name='', + short='-ig', + long='--import-git', + default='', + help='导入 git 仓库测试数据到本地.', + required=False, ), - ], -) -> None: - pass + ] if __name__ == '__main__': - app() + cappa.invoke(HttpFptCLI) diff --git a/httpfpt/db/redis_db.py b/httpfpt/db/redis_db.py index 36dcd22..6aa520d 100644 --- a/httpfpt/db/redis_db.py +++ b/httpfpt/db/redis_db.py @@ -80,7 +80,7 @@ def delete_prefix(self, prefix: str) -> None: for key in self.scan_iter(match=f'{prefix}*'): self.delete(key) - def exists(self, *key: Any) -> int: + def exists(self, *key: Any) -> Any: """ 判断 redis 数据是否存在 diff --git a/httpfpt/utils/case_auto_generator.py b/httpfpt/utils/case_auto_generator.py index 998710e..d2bf930 100644 --- a/httpfpt/utils/case_auto_generator.py +++ b/httpfpt/utils/case_auto_generator.py @@ -3,11 +3,10 @@ import os.path from pathlib import Path -import typer - from httpfpt.core.get_conf import PROJECT_NAME from httpfpt.core.path_conf import TEST_CASE_PATH from httpfpt.utils.file_control import search_all_case_yaml_files, search_all_testcase_files, get_file_property +from httpfpt.utils.rich_console import console def auto_generate_testcases(rewrite: bool = False) -> None: @@ -48,10 +47,10 @@ def auto_generate_testcases(rewrite: bool = False) -> None: else: create_file_root_names.append(root_name) if len(create_file_root_names) == 0: - typer.secho('😝 用例已经很完善了, 添加新测试用例数据后再来生成吧~', fg='green', bold=True) + console.print('😝 用例已经很完善了, 添加新测试用例数据后再来生成吧~') return - typer.secho('⏳ 疯狂自动生成中...', fg='green', bold=True) + console.print('⏳ 疯狂自动生成中...') for create_file_root_name in create_file_root_names: for yaml_filename in yaml_filenames: @@ -96,6 +95,6 @@ def {testcase_func_name}(self, data): Path(case_path).parent.mkdir(parents=True, exist_ok=True) with open(case_path, 'w', encoding='utf-8') as f: f.write(case_code) - typer.secho(f'📄 Created: {get_file_property(case_path)[0]}', fg='green', bold=True) + console.print(f'📄 Created: {get_file_property(case_path)[0]}') - typer.secho('✅ 测试用例自动生成完成', fg='green', bold=True) + console.print('✅ 测试用例自动生成完成') diff --git a/httpfpt/utils/data_manage/apifox.py b/httpfpt/utils/data_manage/apifox.py index 6c5c717..fe1531d 100644 --- a/httpfpt/utils/data_manage/apifox.py +++ b/httpfpt/utils/data_manage/apifox.py @@ -4,14 +4,13 @@ import os from typing import Optional, Union -import typer - from httpfpt.common.json_handler import read_json_file from httpfpt.common.yaml_handler import write_yaml from httpfpt.core.get_conf import PROJECT_NAME from httpfpt.core.path_conf import YAML_DATA_PATH from httpfpt.utils.data_manage.base_format import format_value from httpfpt.utils.file_control import get_file_property +from httpfpt.utils.rich_console import console class ApiFoxParser: @@ -56,7 +55,7 @@ def import_apifox_to_yaml(self, source: str, project: Optional[str] = None) -> N else: pass # todo 二叉树数据解析 if (len(tag_case) or len(root_case)) > 0: - typer.secho('⏳ 奋力导入中...', fg='green', bold=True) + console.print('⏳ 奋力导入中...') # 写入项目 tag 目录 if len(tag_case) > 0: for k, v in tag_case.items(): @@ -78,10 +77,9 @@ def import_apifox_to_yaml(self, source: str, project: Optional[str] = None) -> N case_file_data, mode='w', ) + console.print('✅ 导入 apifox 数据成功') except Exception as e: raise e - else: - typer.secho('✅ 导入 apifox 数据成功') @staticmethod def get_apifox_params(value: dict) -> Union[dict, None]: diff --git a/httpfpt/utils/data_manage/git_repo.py b/httpfpt/utils/data_manage/git_repo.py index 50b9ad8..53b22b3 100644 --- a/httpfpt/utils/data_manage/git_repo.py +++ b/httpfpt/utils/data_manage/git_repo.py @@ -3,13 +3,13 @@ import os import shutil -import typer from pydantic import ValidationError from httpfpt.common.yaml_handler import read_yaml from httpfpt.schemas.case_data import CaseData from httpfpt.utils.file_control import search_all_case_yaml_files from httpfpt.utils.pydantic_parser import parse_error +from httpfpt.utils.rich_console import console class GitRepoPaser: @@ -23,33 +23,35 @@ def import_git_to_local(src: str) -> None: """ if 'https' not in src: - raise ValueError('❌ git 仓库克隆地址错误, 请使用 https 地址') + raise ValueError('❌ Git 仓库克隆地址错误, 请使用 https 地址') try: online_dir_path = os.path.join(os.path.abspath('./data/test_data'), 'online_test_data') - typer.echo(online_dir_path) + console.print(online_dir_path) if os.path.exists(online_dir_path): shutil.rmtree(online_dir_path) os.makedirs(online_dir_path) result = os.system(f'cd {online_dir_path} && git clone {src}') except Exception as e: - raise RuntimeError(f'❌ git 仓库测试数据拉取失败:{e}') + raise RuntimeError(f'❌ Git 仓库测试数据拉取失败:{e}') + if result == 0: + console.print('\n✅ Git 仓库数据文件拉取成功') else: - if result == 0: - typer.secho('✅ git 仓库数据文件拉取成功') - else: - raise RuntimeError('❌ git 仓库测试数据拉取失败') + raise RuntimeError('❌ Git 仓库测试数据拉取失败,请检查 Git 地址是否正确') + console.print('\n🔥 开始自动验证测试数据结构...') all_yaml_file = search_all_case_yaml_files(online_dir_path) + if len(all_yaml_file) == 0: + raise FileNotFoundError('❌ 未在拉取的 Git 仓库中找到测试用例数据文件,请检查 Git 地址是否正确') all_case_data = [] for file in all_yaml_file: read_data = read_yaml(None, filename=file) all_case_data.append(read_data) + count: int = 0 for case_data in all_case_data: try: - count: int = 0 CaseData.model_validate(case_data) except ValidationError as e: - count = parse_error(e) - if count > 0: - raise ValueError(f'导入 Git 用例数据校验失败,共有 {count} 处错误, 错误详情请查看日志') + count += parse_error(e) + if count > 0: + raise ValueError(f'❌ Git 仓库用例数据校验失败,共有 {count} 处错误, 错误详情请查看日志') diff --git a/httpfpt/utils/data_manage/openapi.py b/httpfpt/utils/data_manage/openapi.py index f3850b8..f1789a6 100644 --- a/httpfpt/utils/data_manage/openapi.py +++ b/httpfpt/utils/data_manage/openapi.py @@ -6,7 +6,7 @@ from typing import Union, Optional import requests -import typer +from rich.prompt import Confirm from httpfpt.common.json_handler import read_json_file from httpfpt.common.yaml_handler import write_yaml @@ -14,6 +14,7 @@ from httpfpt.core.path_conf import YAML_DATA_PATH from httpfpt.utils.data_manage.base_format import format_value from httpfpt.utils.file_control import get_file_property +from httpfpt.utils.rich_console import console from httpfpt.utils.time_control import get_current_timestamp @@ -62,7 +63,7 @@ def import_openapi_to_yaml(self, openapi_source: str, project: Optional[str] = N # 根目录测试用例数据 root_case = {} - is_tag = typer.confirm('是否按openapi标签划分数据存放目录?', default=True) + is_tag = Confirm.ask('❓ 是否按 openapi 标签划分数据存放目录?', default=True) for url, values in self.data['paths'].items(): for method, values_map in values.items(): params = self.get_swagger_params(values_map) @@ -164,15 +165,15 @@ def import_openapi_to_yaml(self, openapi_source: str, project: Optional[str] = N ] ) file_list.append(root_filename) - typer.secho('⚠️ 即将创建以下数据文件:', fg='yellow', bold=True) + console.print('⚠️ 即将创建以下数据文件:') for i in file_list: - typer.secho(f'{i}', fg='cyan', bold=True) - is_force_write = typer.confirm( - text='请检查是否存在同名文件, 此操作将强制覆盖写入所有数据文件, 是否继续执行? (此操作不可逆)', default=False # noqa: E501 + console.print(f'\n\tdata\\test_data\\{i}') + is_force_write = Confirm.ask( + '\n👁️ 请检查是否存在同名文件, 此操作将强制覆盖写入所有数据文件, 是否继续执行? (此操作不可逆)', default=False # noqa: E501 ) # 强制写入 if is_force_write: - typer.secho('⏳ 奋力导入中...', fg='green', bold=True) + console.print('⏳ 奋力导入中...') # 写入项目 tag 目录 if len(tag_case) > 0: for k, v in tag_case.items(): @@ -216,8 +217,8 @@ def import_openapi_to_yaml(self, openapi_source: str, project: Optional[str] = N ) # 选择写入 else: - typer.secho('⚠️ 已取消强制覆写入所有数据文件', fg='yellow', bold=True) - is_next = typer.confirm('是否进行逐一选择创建数据文件吗?', abort=True) + console.print('⚠️ 已取消强制覆写入所有数据文件') + is_next = Confirm.ask('❓ 是否进行逐一选择创建数据文件?', default=True) if is_next: # 写入项目 tag 目录 if len(tag_case) > 0: @@ -233,7 +234,7 @@ def import_openapi_to_yaml(self, openapi_source: str, project: Optional[str] = N else f'openapi_{k}.yaml', ] ) - is_write = typer.confirm(text=f'是否需要创建 {tag_filename} 数据文件?', default=True) + is_write = Confirm.ask(f'❓ 是否需要创建 {tag_filename} 数据文件?', default=True) if is_write: write_yaml(YAML_DATA_PATH, tag_filename, case_file_data, mode='w') # 写入项目根目录 @@ -251,7 +252,7 @@ def import_openapi_to_yaml(self, openapi_source: str, project: Optional[str] = N if not openapi_source.startswith('http') else f'openapi_{k}.yaml' ) - is_write = typer.confirm(text=f'是否需要创建 {root_filename} 数据文件?', default=True) + is_write = Confirm.ask(f'❓ 是否需要创建 {root_filename} 数据文件?', default=True) if is_write: case_file_data = {'config': config, 'test_steps': v} write_yaml( @@ -260,10 +261,9 @@ def import_openapi_to_yaml(self, openapi_source: str, project: Optional[str] = N case_file_data, mode='w', ) + console.print('✅ 导入 openapi 数据成功') except Exception as e: raise e - else: - typer.secho('✅ 导入 openapi 数据成功', fg='green', bold=True) def get_swagger_data(self, openapi_source: str) -> None: """ @@ -361,10 +361,10 @@ def get_swagger_request_data(self, value: Union[dict, str]) -> Union[dict, None] if len(value['parameters']) > 0: for i in value['parameters']: if i.get('type') is None: - data[i['name']] = format_value('object') + data[i['name']] = format_value('object') # type: ignore else: if i.get('type') != 'file': - data[i['name']] = format_value(i.get('type', 'object')) + data[i['name']] = format_value(i.get('type', 'object')) # type: ignore return data if len(data) > 0 else None else: if not isinstance(value, dict): diff --git a/httpfpt/utils/rich_console.py b/httpfpt/utils/rich_console.py new file mode 100644 index 0000000..d193f2b --- /dev/null +++ b/httpfpt/utils/rich_console.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +from rich import get_console + +console = get_console() diff --git a/requirements.txt b/requirements.txt index 8711133..3271cbd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ allure-pytest==2.13.2 cache3==0.2.1 +cappa==0.10.2 cryptography==41.0.4 dbutils==3.0.2 dirty_equals==0.6.0 @@ -7,24 +8,20 @@ faker==13.15.0 httpx==0.23.0 jinja2==3.1.2 loguru==0.6.0 -openpyxl==3.0.7 pre-commit==3.2.2 pydantic==2.3.0 pymysql==0.9.3 -pyright==1.1.315 +pyright==1.1.332 pytest==7.4.1 pytest-html==4.0.0 pytest-metadata==3.0.0 pytest-pretty==1.2.0 pytest-xdist==2.5.0 -python-dateutil==2.8.2 python-dotenv==0.20.0 python-jsonpath==0.9.0 pyyaml==6.0.1 -redis==4.5.4 +redis[hiredis]==5.0.1 requests==2.31.0 +rich==13.6.0 rtoml==0.9.0 -ruff==0.0.262 -text-unidecode==1.3 -typer[all]==0.9.0 xlrd==1.2.0