diff --git a/.changeset/added_an_output_path_option_to_generate.md b/.changeset/added_an_output_path_option_to_generate.md new file mode 100644 index 000000000..864352375 --- /dev/null +++ b/.changeset/added_an_output_path_option_to_generate.md @@ -0,0 +1,9 @@ +--- +default: minor +--- + +# Added an `--output-path` option to `generate` + +Rather than changing directories before running `generate` you can now specify an output directory with `--output-path`. +Note that the project name will _not_ be appended to the `--output-path`, whatever path you specify is where the +generated code will be placed. diff --git a/.changeset/added_an_overwrite_flag_to_generate.md b/.changeset/added_an_overwrite_flag_to_generate.md new file mode 100644 index 000000000..9c38bb2e8 --- /dev/null +++ b/.changeset/added_an_overwrite_flag_to_generate.md @@ -0,0 +1,8 @@ +--- +default: minor +--- + +# Added an `--overwrite` flag to `generate` + +You can now tell `openapi-python-client` to overwrite an existing directory, rather than deleting it yourself before +running `generate`. diff --git a/.changeset/remove_the_update_command.md b/.changeset/remove_the_update_command.md new file mode 100644 index 000000000..51a790af1 --- /dev/null +++ b/.changeset/remove_the_update_command.md @@ -0,0 +1,18 @@ +--- +default: major +--- + +# Removed the `update` command + +The `update` command is no more, you can (mostly) replace its usage with some new flags on the `generate` command. + +If you had a package named `my-api-client` in the current working directory, the `update` command previously would update the `my_api_client` module within it. You can now _almost_ perfectly replicate this behavior using `openapi-python-client generate --meta=none --output-path=my-api-client/my_api_client --overwrite`. + +The only difference is that `my-api-client` would have run `post_hooks` in the `my-api-client` directory, +but `generate` will run `post_hooks` in the `output-path` directory. + +Alternatively, you can now also run `openapi-python-client generate --meta= --overwrite` to regenerate +the entire client, if you don't care about keeping any changes you've made to the generated client. + +Please comment on [discussion #824](https://github.com/openapi-generators/openapi-python-client/discussions/824) +(or a new discussion, as appropriate) to aid in designing future features that fill any gaps this leaves for you. diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index eb5c60b3b..747c6f79f 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -42,9 +42,6 @@ jobs: - name: Check formatting run: pdm run ruff format . --check - - name: Run safety - run: pdm safety_check - - name: Run mypy run: pdm mypy --show-error-codes diff --git a/end_to_end_tests/invalid_openapi.yaml b/end_to_end_tests/invalid_openapi.yaml new file mode 100644 index 000000000..ccd0237db --- /dev/null +++ b/end_to_end_tests/invalid_openapi.yaml @@ -0,0 +1,19 @@ +openapi: "3.1.0" +info: + title: "There's something wrong with me" + version: "0.1.0" +paths: + "/{optional}": + get: + parameters: + - in: "path" + name: "optional" + schema: + type: "string" + responses: + "200": + description: "Successful Response" + content: + "application/json": + schema: + const: "Why have a fixed response? I dunno" diff --git a/end_to_end_tests/test_end_to_end.py b/end_to_end_tests/test_end_to_end.py index 9087beca3..f101152f3 100644 --- a/end_to_end_tests/test_end_to_end.py +++ b/end_to_end_tests/test_end_to_end.py @@ -215,16 +215,21 @@ def test_custom_templates(): ) -@pytest.mark.parametrize( - "command", ("generate", "update") -) -def test_bad_url(command: str): +def test_bad_url(): runner = CliRunner() - result = runner.invoke(app, [command, "--url=not_a_url"]) + result = runner.invoke(app, ["generate", "--url=not_a_url"]) assert result.exit_code == 1 assert "Could not get OpenAPI document from provided URL" in result.stdout +def test_invalid_document(): + runner = CliRunner() + path = Path(__file__).parent / "invalid_openapi.yaml" + result = runner.invoke(app, ["generate", f"--path={path}", "--fail-on-warning"]) + assert result.exit_code == 1 + assert "Warning(s) encountered while generating" in result.stdout + + def test_custom_post_hooks(): shutil.rmtree(Path.cwd() / "my-test-api-client", ignore_errors=True) runner = CliRunner() @@ -248,16 +253,6 @@ def test_generate_dir_already_exists(): shutil.rmtree(Path.cwd() / "my-test-api-client", ignore_errors=True) -def test_update_dir_not_found(): - project_dir = Path.cwd() / "my-test-api-client" - shutil.rmtree(project_dir, ignore_errors=True) - runner = CliRunner() - openapi_document = Path(__file__).parent / "baseline_openapi_3.0.json" - result = runner.invoke(app, ["update", f"--path={openapi_document}"]) - assert result.exit_code == 1 - assert str(project_dir) in result.stdout - - @pytest.mark.parametrize( ("file_name", "content", "expected_error"), ( @@ -280,9 +275,19 @@ def test_invalid_openapi_document(file_name, content, expected_error): def test_update_integration_tests(): url = "https://raw.githubusercontent.com/openapi-generators/openapi-test-server/main/openapi.json" source_path = Path(__file__).parent.parent / "integration-tests" - project_path = Path.cwd() / "integration-tests" - if source_path != project_path: # Just in case someone runs this from root dir - shutil.copytree(source_path, project_path) - config_path = project_path / "config.yaml" - _run_command("update", url=url, config_path=config_path) - _compare_directories(source_path, project_path, expected_differences={}) + temp_dir = Path.cwd() / "test_update_integration_tests" + shutil.rmtree(temp_dir, ignore_errors=True) + shutil.copytree(source_path, temp_dir) + config_path = source_path / "config.yaml" + _run_command( + "generate", + extra_args=["--meta=none", "--overwrite", f"--output-path={source_path / 'integration_tests'}"], + url=url, + config_path=config_path + ) + _compare_directories(temp_dir, source_path, expected_differences={}) + import mypy.api + + out, err, status = mypy.api.run([str(temp_dir), "--strict"]) + assert status == 0, f"Type checking client failed: {out}" + shutil.rmtree(temp_dir) diff --git a/integration-tests/config.yaml b/integration-tests/config.yaml index 80153f799..8b6e35763 100644 --- a/integration-tests/config.yaml +++ b/integration-tests/config.yaml @@ -1,5 +1,4 @@ project_name_override: integration-tests post_hooks: - ruff check . --fix - - ruff format . - - mypy . --strict \ No newline at end of file + - ruff format . \ No newline at end of file diff --git a/integration-tests/integration_tests/py.typed b/integration-tests/integration_tests/py.typed deleted file mode 100644 index 1aad32711..000000000 --- a/integration-tests/integration_tests/py.typed +++ /dev/null @@ -1 +0,0 @@ -# Marker file for PEP 561 \ No newline at end of file diff --git a/openapi_python_client/__init__.py b/openapi_python_client/__init__.py index 5f36e2fbc..90bea54ee 100644 --- a/openapi_python_client/__init__.py +++ b/openapi_python_client/__init__.py @@ -65,12 +65,22 @@ def __init__( ) self.project_name: str = config.project_name_override or f"{utils.kebab_case(openapi.title).lower()}-client" - self.project_dir: Path = Path.cwd() - if config.meta_type != MetaType.NONE: - self.project_dir /= self.project_name - self.package_name: str = config.package_name_override or self.project_name.replace("-", "_") - self.package_dir: Path = self.project_dir / self.package_name + self.project_dir: Path # Where the generated code will be placed + self.package_dir: Path # Where the generated Python module will be placed (same as project_dir if no meta) + + if config.output_path is not None: + self.project_dir = config.output_path + elif config.meta_type == MetaType.NONE: + self.project_dir = Path.cwd() / self.package_name + else: + self.project_dir = Path.cwd() / self.project_name + + if config.meta_type == MetaType.NONE: + self.package_dir = self.project_dir + else: + self.package_dir = self.project_dir / self.package_name + self.package_description: str = utils.remove_string_escapes( f"A client library for accessing {self.openapi.title}" ) @@ -95,29 +105,16 @@ def __init__( def build(self) -> Sequence[GeneratorError]: """Create the project from templates""" - if self.config.meta_type == MetaType.NONE: - print(f"Generating {self.package_name}") - else: - print(f"Generating {self.project_name}") - try: - self.project_dir.mkdir() - except FileExistsError: - return [GeneratorError(detail="Directory already exists. Delete it or use the update command.")] - self._create_package() - self._build_metadata() - self._build_models() - self._build_api() - self._run_post_hooks() - return self._get_errors() - - def update(self) -> Sequence[GeneratorError]: - """Update an existing project""" + print(f"Generating {self.project_dir}") + if self.config.overwrite: + shutil.rmtree(self.project_dir, ignore_errors=True) - if not self.package_dir.is_dir(): - return [GeneratorError(detail=f"Directory {self.package_dir} not found")] - print(f"Updating {self.package_name}") - shutil.rmtree(self.package_dir) + try: + self.project_dir.mkdir() + except FileExistsError: + return [GeneratorError(detail="Directory already exists. Delete it or use the --overwrite option.")] self._create_package() + self._build_metadata() self._build_models() self._build_api() self._run_post_hooks() @@ -138,7 +135,7 @@ def _run_command(self, cmd: str) -> None: ) return try: - cwd = self.package_dir if self.config.meta_type == MetaType.NONE else self.project_dir + cwd = self.project_dir subprocess.run(cmd, cwd=cwd, shell=True, capture_output=True, check=True) except CalledProcessError as err: self.errors.append( @@ -158,7 +155,8 @@ def _get_errors(self) -> List[GeneratorError]: return errors def _create_package(self) -> None: - self.package_dir.mkdir() + if self.package_dir != self.project_dir: + self.package_dir.mkdir() # Package __init__.py package_init = self.package_dir / "__init__.py" @@ -303,7 +301,7 @@ def _get_project_for_url_or_path( ) -def create_new_client( +def generate( *, config: Config, custom_template_path: Optional[Path] = None, @@ -323,26 +321,6 @@ def create_new_client( return project.build() -def update_existing_client( - *, - config: Config, - custom_template_path: Optional[Path] = None, -) -> Sequence[GeneratorError]: - """ - Update an existing client library - - Returns: - A list containing any errors encountered when generating. - """ - project = _get_project_for_url_or_path( - custom_template_path=custom_template_path, - config=config, - ) - if isinstance(project, GeneratorError): - return [project] - return project.update() - - def _load_yaml_or_json(data: bytes, content_type: Optional[str]) -> Union[Dict[str, Any], GeneratorError]: if content_type == "application/json": try: diff --git a/openapi_python_client/cli.py b/openapi_python_client/cli.py index 22478ab04..e8fd50f9e 100644 --- a/openapi_python_client/cli.py +++ b/openapi_python_client/cli.py @@ -21,7 +21,14 @@ def _version_callback(value: bool) -> None: def _process_config( - *, url: Optional[str], path: Optional[Path], config_path: Optional[Path], meta_type: MetaType, file_encoding: str + *, + url: Optional[str], + path: Optional[Path], + config_path: Optional[Path], + meta_type: MetaType, + file_encoding: str, + overwrite: bool, + output_path: Optional[Path], ) -> Config: source: Union[Path, str] if url and not path: @@ -49,7 +56,7 @@ def _process_config( except Exception as err: raise typer.BadParameter("Unable to parse config") from err - return Config.from_sources(config_file, meta_type, source, file_encoding) + return Config.from_sources(config_file, meta_type, source, file_encoding, overwrite, output_path=output_path) # noinspection PyUnusedLocal @@ -117,62 +124,46 @@ def handle_errors(errors: Sequence[GeneratorError], fail_on_warning: bool = Fals raise typer.Exit(code=1) -custom_template_path_options = { - "help": "A path to a directory containing custom template(s)", - "file_okay": False, - "dir_okay": True, - "readable": True, - "resolve_path": True, -} - -_meta_option = typer.Option( - MetaType.POETRY, - help="The type of metadata you want to generate.", -) - -CONFIG_OPTION = typer.Option(None, "--config", help="Path to the config file to use") - - @app.command() def generate( - url: Optional[str] = typer.Option(None, help="A URL to read the JSON from"), - path: Optional[Path] = typer.Option(None, help="A path to the JSON file"), - custom_template_path: Optional[Path] = typer.Option(None, **custom_template_path_options), # type: ignore - meta: MetaType = _meta_option, + url: Optional[str] = typer.Option(None, help="A URL to read the OpenAPI document from"), + path: Optional[Path] = typer.Option(None, help="A path to the OpenAPI document"), + custom_template_path: Optional[Path] = typer.Option( + None, + help="A path to a directory containing custom template(s)", + file_okay=False, + dir_okay=True, + readable=True, + resolve_path=True, + ), # type: ignore + meta: MetaType = typer.Option( + MetaType.POETRY, + help="The type of metadata you want to generate.", + ), file_encoding: str = typer.Option("utf-8", help="Encoding used when writing generated"), - config_path: Optional[Path] = CONFIG_OPTION, + config_path: Optional[Path] = typer.Option(None, "--config", help="Path to the config file to use"), fail_on_warning: bool = False, + overwrite: bool = typer.Option(False, help="Overwrite the existing client if it exists"), + output_path: Optional[Path] = typer.Option( + None, + help="Path to write the generated code to. " + "Defaults to the OpenAPI document title converted to kebab or snake case (depending on meta type). " + "Can also be overridden with `project_name_override` or `package_name_override` in config.", + ), ) -> None: """Generate a new OpenAPI Client library""" - from . import create_new_client - - config = _process_config(url=url, path=path, config_path=config_path, meta_type=meta, file_encoding=file_encoding) - errors = create_new_client( - custom_template_path=custom_template_path, - config=config, + from . import generate + + config = _process_config( + url=url, + path=path, + config_path=config_path, + meta_type=meta, + file_encoding=file_encoding, + overwrite=overwrite, + output_path=output_path, ) - handle_errors(errors, fail_on_warning) - - -@app.command() -def update( - url: Optional[str] = typer.Option(None, help="A URL to read the JSON from"), - path: Optional[Path] = typer.Option(None, help="A path to the JSON file"), - custom_template_path: Optional[Path] = typer.Option(None, **custom_template_path_options), # type: ignore - meta: MetaType = _meta_option, - file_encoding: str = typer.Option("utf-8", help="Encoding used when writing generated"), - config_path: Optional[Path] = CONFIG_OPTION, - fail_on_warning: bool = False, -) -> None: - """Update an existing OpenAPI Client library - - The update command performs the same operations as generate except it does not overwrite specific metadata for the - generated client such as the README.md, .gitignore, and pyproject.toml. - """ - from . import update_existing_client - - config = _process_config(config_path=config_path, meta_type=meta, url=url, path=path, file_encoding=file_encoding) - errors = update_existing_client( + errors = generate( custom_template_path=custom_template_path, config=config, ) diff --git a/openapi_python_client/config.py b/openapi_python_client/config.py index 535755cca..740e06309 100644 --- a/openapi_python_client/config.py +++ b/openapi_python_client/config.py @@ -73,10 +73,17 @@ class Config: document_source: Union[Path, str] file_encoding: str content_type_overrides: Dict[str, str] + overwrite: bool + output_path: Optional[Path] @staticmethod def from_sources( - config_file: ConfigFile, meta_type: MetaType, document_source: Union[Path, str], file_encoding: str + config_file: ConfigFile, + meta_type: MetaType, + document_source: Union[Path, str], + file_encoding: str, + overwrite: bool, + output_path: Optional[Path], ) -> "Config": if config_file.post_hooks is not None: post_hooks = config_file.post_hooks @@ -104,5 +111,7 @@ def from_sources( http_timeout=config_file.http_timeout, document_source=document_source, file_encoding=file_encoding, + overwrite=overwrite, + output_path=output_path, ) return config diff --git a/pdm.lock b/pdm.lock index 555007b6e..68099c263 100644 --- a/pdm.lock +++ b/pdm.lock @@ -5,14 +5,14 @@ groups = ["default", "dev"] strategy = ["cross_platform", "inherit_metadata"] lock_version = "4.4.1" -content_hash = "sha256:cf2b9eebb1ee290dba283b2732207f7c20bc4d8920e071179eb7f7da975ff2b9" +content_hash = "sha256:8c81482bbbefbab7b565283f94bc1ea7bff579c3019f9957be1ad0450483ecc9" [[package]] name = "annotated-types" version = "0.6.0" requires_python = ">=3.8" summary = "Reusable constraint types to use with typing.Annotated" -groups = ["default", "dev"] +groups = ["default"] dependencies = [ "typing-extensions>=4.0.0; python_version < \"3.9\"", ] @@ -49,188 +49,23 @@ files = [ {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, ] -[[package]] -name = "authlib" -version = "1.3.0" -requires_python = ">=3.8" -summary = "The ultimate Python library in building OAuth and OpenID Connect servers and clients." -groups = ["dev"] -dependencies = [ - "cryptography", -] -files = [ - {file = "Authlib-1.3.0-py2.py3-none-any.whl", hash = "sha256:9637e4de1fb498310a56900b3e2043a206b03cb11c05422014b0302cbc814be3"}, - {file = "Authlib-1.3.0.tar.gz", hash = "sha256:959ea62a5b7b5123c5059758296122b57cd2585ae2ed1c0622c21b371ffdae06"}, -] - [[package]] name = "certifi" version = "2024.2.2" requires_python = ">=3.6" summary = "Python package for providing Mozilla's CA Bundle." -groups = ["default", "dev"] +groups = ["default"] files = [ {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, ] -[[package]] -name = "cffi" -version = "1.16.0" -requires_python = ">=3.8" -summary = "Foreign Function Interface for Python calling C code." -groups = ["dev"] -marker = "platform_python_implementation != \"PyPy\"" -dependencies = [ - "pycparser", -] -files = [ - {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, - {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, - {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, - {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, - {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, - {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, - {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, - {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, - {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, - {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, - {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, - {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, - {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, - {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, - {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, -] - -[[package]] -name = "charset-normalizer" -version = "3.3.2" -requires_python = ">=3.7.0" -summary = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -groups = ["dev"] -files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, -] - [[package]] name = "click" version = "8.1.7" requires_python = ">=3.7" summary = "Composable command line interface toolkit" -groups = ["default", "dev"] +groups = ["default"] dependencies = [ "colorama; platform_system == \"Windows\"", ] @@ -377,65 +212,6 @@ files = [ {file = "coverage-7.5.1.tar.gz", hash = "sha256:54de9ef3a9da981f7af93eafde4ede199e0846cd819eb27c88e2b712aae9708c"}, ] -[[package]] -name = "cryptography" -version = "42.0.7" -requires_python = ">=3.7" -summary = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." -groups = ["dev"] -dependencies = [ - "cffi>=1.12; platform_python_implementation != \"PyPy\"", -] -files = [ - {file = "cryptography-42.0.7-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:a987f840718078212fdf4504d0fd4c6effe34a7e4740378e59d47696e8dfb477"}, - {file = "cryptography-42.0.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:bd13b5e9b543532453de08bcdc3cc7cebec6f9883e886fd20a92f26940fd3e7a"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a79165431551042cc9d1d90e6145d5d0d3ab0f2d66326c201d9b0e7f5bf43604"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a47787a5e3649008a1102d3df55424e86606c9bae6fb77ac59afe06d234605f8"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:02c0eee2d7133bdbbc5e24441258d5d2244beb31da5ed19fbb80315f4bbbff55"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:5e44507bf8d14b36b8389b226665d597bc0f18ea035d75b4e53c7b1ea84583cc"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7f8b25fa616d8b846aef64b15c606bb0828dbc35faf90566eb139aa9cff67af2"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:93a3209f6bb2b33e725ed08ee0991b92976dfdcf4e8b38646540674fc7508e13"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e6b8f1881dac458c34778d0a424ae5769de30544fc678eac51c1c8bb2183e9da"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3de9a45d3b2b7d8088c3fbf1ed4395dfeff79d07842217b38df14ef09ce1d8d7"}, - {file = "cryptography-42.0.7-cp37-abi3-win32.whl", hash = "sha256:789caea816c6704f63f6241a519bfa347f72fbd67ba28d04636b7c6b7da94b0b"}, - {file = "cryptography-42.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:8cb8ce7c3347fcf9446f201dc30e2d5a3c898d009126010cbd1f443f28b52678"}, - {file = "cryptography-42.0.7-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:a3a5ac8b56fe37f3125e5b72b61dcde43283e5370827f5233893d461b7360cd4"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:779245e13b9a6638df14641d029add5dc17edbef6ec915688f3acb9e720a5858"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d563795db98b4cd57742a78a288cdbdc9daedac29f2239793071fe114f13785"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:31adb7d06fe4383226c3e963471f6837742889b3c4caa55aac20ad951bc8ffda"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:efd0bf5205240182e0f13bcaea41be4fdf5c22c5129fc7ced4a0282ac86998c9"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a9bc127cdc4ecf87a5ea22a2556cab6c7eda2923f84e4f3cc588e8470ce4e42e"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:3577d029bc3f4827dd5bf8bf7710cac13527b470bbf1820a3f394adb38ed7d5f"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2e47577f9b18723fa294b0ea9a17d5e53a227867a0a4904a1a076d1646d45ca1"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1a58839984d9cb34c855197043eaae2c187d930ca6d644612843b4fe8513c886"}, - {file = "cryptography-42.0.7-cp39-abi3-win32.whl", hash = "sha256:e6b79d0adb01aae87e8a44c2b64bc3f3fe59515280e00fb6d57a7267a2583cda"}, - {file = "cryptography-42.0.7-cp39-abi3-win_amd64.whl", hash = "sha256:16268d46086bb8ad5bf0a2b5544d8a9ed87a0e33f5e77dd3c3301e63d941a83b"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2954fccea107026512b15afb4aa664a5640cd0af630e2ee3962f2602693f0c82"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:362e7197754c231797ec45ee081f3088a27a47c6c01eff2ac83f60f85a50fe60"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4f698edacf9c9e0371112792558d2f705b5645076cc0aaae02f816a0171770fd"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5482e789294854c28237bba77c4c83be698be740e31a3ae5e879ee5444166582"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e9b2a6309f14c0497f348d08a065d52f3020656f675819fc405fb63bbcd26562"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d8e3098721b84392ee45af2dd554c947c32cc52f862b6a3ae982dbb90f577f14"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c65f96dad14f8528a447414125e1fc8feb2ad5a272b8f68477abbcc1ea7d94b9"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36017400817987670037fbb0324d71489b6ead6231c9604f8fc1f7d008087c68"}, - {file = "cryptography-42.0.7.tar.gz", hash = "sha256:ecbfbc00bf55888edda9868a4cf927205de8499e7fabe6c050322298382953f2"}, -] - -[[package]] -name = "dparse" -version = "0.6.4b0" -requires_python = ">=3.7" -summary = "A parser for Python dependency files" -groups = ["dev"] -dependencies = [ - "packaging", - "tomli; python_version < \"3.11\"", -] -files = [ - {file = "dparse-0.6.4b0-py3-none-any.whl", hash = "sha256:592ff183348b8a5ea0a18442a7965e29445d3a26063654ec2c7e8ef42cd5753c"}, - {file = "dparse-0.6.4b0.tar.gz", hash = "sha256:f8d49b41a527f3d16a269f854e6665245b325e50e41d2c213810cb984553e5c8"}, -] - [[package]] name = "exceptiongroup" version = "1.2.1" @@ -497,7 +273,7 @@ name = "idna" version = "3.7" requires_python = ">=3.5" summary = "Internationalized Domain Names in Applications (IDNA)" -groups = ["default", "dev"] +groups = ["default"] files = [ {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, @@ -519,7 +295,7 @@ name = "jinja2" version = "3.1.4" requires_python = ">=3.7" summary = "A very fast and expressive template engine." -groups = ["default", "dev"] +groups = ["default"] dependencies = [ "MarkupSafe>=2.0", ] @@ -533,7 +309,7 @@ name = "markdown-it-py" version = "3.0.0" requires_python = ">=3.8" summary = "Python port of markdown-it. Markdown parsing, done right!" -groups = ["default", "dev"] +groups = ["default"] dependencies = [ "mdurl~=0.1", ] @@ -547,7 +323,7 @@ name = "markupsafe" version = "2.1.5" requires_python = ">=3.7" summary = "Safely add untrusted strings to HTML/XML markup." -groups = ["default", "dev"] +groups = ["default"] files = [ {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, @@ -602,26 +378,12 @@ files = [ {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] -[[package]] -name = "marshmallow" -version = "3.21.2" -requires_python = ">=3.8" -summary = "A lightweight library for converting complex datatypes to and from native Python datatypes." -groups = ["dev"] -dependencies = [ - "packaging>=17.0", -] -files = [ - {file = "marshmallow-3.21.2-py3-none-any.whl", hash = "sha256:70b54a6282f4704d12c0a41599682c5c5450e843b9ec406308653b47c59648a1"}, - {file = "marshmallow-3.21.2.tar.gz", hash = "sha256:82408deadd8b33d56338d2182d455db632c6313aa2af61916672146bb32edc56"}, -] - [[package]] name = "mdurl" version = "0.1.2" requires_python = ">=3.7" summary = "Markdown URL utilities" -groups = ["default", "dev"] +groups = ["default"] files = [ {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, @@ -729,24 +491,12 @@ files = [ {file = "psutil-5.9.8.tar.gz", hash = "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c"}, ] -[[package]] -name = "pycparser" -version = "2.22" -requires_python = ">=3.8" -summary = "C parser in Python" -groups = ["dev"] -marker = "platform_python_implementation != \"PyPy\"" -files = [ - {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, - {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, -] - [[package]] name = "pydantic" version = "2.7.1" requires_python = ">=3.8" summary = "Data validation using Python type hints" -groups = ["default", "dev"] +groups = ["default"] dependencies = [ "annotated-types>=0.4.0", "pydantic-core==2.18.2", @@ -762,7 +512,7 @@ name = "pydantic-core" version = "2.18.2" requires_python = ">=3.8" summary = "Core functionality for Pydantic validation and serialization" -groups = ["default", "dev"] +groups = ["default"] dependencies = [ "typing-extensions!=4.7.0,>=4.6.0", ] @@ -853,7 +603,7 @@ name = "pygments" version = "2.18.0" requires_python = ">=3.8" summary = "Pygments is a syntax highlighting package written in Python." -groups = ["default", "dev"] +groups = ["default"] files = [ {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, @@ -932,29 +682,12 @@ files = [ {file = "python_multipart-0.0.9.tar.gz", hash = "sha256:03f54688c663f1b7977105f021043b0793151e4cb1c1a9d4a11fc13d622c4026"}, ] -[[package]] -name = "requests" -version = "2.31.0" -requires_python = ">=3.7" -summary = "Python HTTP for Humans." -groups = ["dev"] -dependencies = [ - "certifi>=2017.4.17", - "charset-normalizer<4,>=2", - "idna<4,>=2.5", - "urllib3<3,>=1.21.1", -] -files = [ - {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, - {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, -] - [[package]] name = "rich" version = "13.7.1" requires_python = ">=3.7.0" summary = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" -groups = ["default", "dev"] +groups = ["default"] dependencies = [ "markdown-it-py>=2.2.0", "pygments<3.0.0,>=2.13.0", @@ -1070,69 +803,12 @@ files = [ {file = "ruff-0.4.4.tar.gz", hash = "sha256:f87ea42d5cdebdc6a69761a9d0bc83ae9b3b30d0ad78952005ba6568d6c022af"}, ] -[[package]] -name = "safety" -version = "3.2.0" -requires_python = ">=3.7" -summary = "Checks installed dependencies for known vulnerabilities and licenses." -groups = ["dev"] -dependencies = [ - "Authlib>=1.2.0", - "Click>=8.0.2", - "dparse>=0.6.4b0", - "jinja2>=3.1.0", - "marshmallow>=3.15.0", - "packaging>=21.0", - "pydantic>=1.10.12", - "requests", - "rich", - "ruamel-yaml>=0.17.21", - "safety-schemas>=0.0.2", - "setuptools>=65.5.1", - "typer", - "typing-extensions>=4.7.1", - "urllib3>=1.26.5", -] -files = [ - {file = "safety-3.2.0-py3-none-any.whl", hash = "sha256:a432fc9d17e79a4386c4f093656b617c56f839cde022649cfa796d72c7a544de"}, - {file = "safety-3.2.0.tar.gz", hash = "sha256:8bd5cab5f3d8a61ce0ea6e98f267c1006d056097c45c644fee7afeff7d5949c1"}, -] - -[[package]] -name = "safety-schemas" -version = "0.0.2" -requires_python = ">=3.7" -summary = "Schemas for Safety tools" -groups = ["dev"] -dependencies = [ - "dparse>=0.6.4b0", - "packaging>=21.0", - "pydantic", - "ruamel-yaml>=0.17.21", - "typing-extensions>=4.7.1", -] -files = [ - {file = "safety_schemas-0.0.2-py3-none-any.whl", hash = "sha256:277c077ce6e53221874a87c29515ffdd2f3773a6db4d035a9f67cc98db3b8c7f"}, - {file = "safety_schemas-0.0.2.tar.gz", hash = "sha256:7d1b040ec06480f05cff6b45ea7a93e09c8942df864fb0d01ddeb67c323cfa8c"}, -] - -[[package]] -name = "setuptools" -version = "69.5.1" -requires_python = ">=3.8" -summary = "Easily download, build, install, upgrade, and uninstall Python packages" -groups = ["dev"] -files = [ - {file = "setuptools-69.5.1-py3-none-any.whl", hash = "sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32"}, - {file = "setuptools-69.5.1.tar.gz", hash = "sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987"}, -] - [[package]] name = "shellingham" version = "1.5.4" requires_python = ">=3.7" summary = "Tool to Detect Surrounding Shell" -groups = ["default", "dev"] +groups = ["default"] files = [ {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, @@ -1194,7 +870,7 @@ name = "typer" version = "0.12.3" requires_python = ">=3.7" summary = "Typer, build great CLIs. Easy to code. Based on Python type hints." -groups = ["default", "dev"] +groups = ["default"] dependencies = [ "click>=8.0.0", "rich>=10.11.0", @@ -1248,14 +924,3 @@ files = [ {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, ] - -[[package]] -name = "urllib3" -version = "2.2.1" -requires_python = ">=3.8" -summary = "HTTP library with thread-safe connection pooling, file post, and more." -groups = ["dev"] -files = [ - {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, - {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, -] diff --git a/pyproject.toml b/pyproject.toml index 6c9c339f3..0fc06b695 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -85,13 +85,13 @@ ignore_missing_imports = true junit_family = "xunit2" + [tool.pdm.dev-dependencies] dev = [ "pytest", "pytest-mock", "mypy", "taskipy", - "safety", "pytest-cov", "python-multipart", "types-PyYAML<7.0.0,>=6.0.3", @@ -110,9 +110,8 @@ includes = [ [tool.pdm.scripts] lint = "ruff check --fix ." format = "ruff format ." -safety_check = { shell = "pdm export -o requirements.txt && safety check -r requirements.txt --bare && rm requirements.txt" } mypy = "mypy openapi_python_client" -check = { composite = ["lint", "format", "safety_check", "mypy", "test"] } +check = { composite = ["lint", "format", "mypy", "test"] } regen = {composite = ["regen_e2e", "regen_integration"]} e2e = "pytest openapi_python_client end_to_end_tests/test_end_to_end.py" re = {composite = ["regen_e2e", "e2e"]} diff --git a/tests/conftest.py b/tests/conftest.py index 44fbe717c..91b67752c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -28,7 +28,12 @@ def config() -> Config: """Create a default config for when it doesn't matter""" return Config.from_sources( - ConfigFile(), MetaType.POETRY, document_source=Path("openapi.yaml"), file_encoding="utf-8" + ConfigFile(), + MetaType.POETRY, + document_source=Path("openapi.yaml"), + file_encoding="utf-8", + overwrite=False, + output_path=None, ) diff --git a/tests/test_cli.py b/tests/test_cli.py index 1b3c21501..bb73cb48c 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,30 +1,18 @@ -from unittest.mock import MagicMock - -import pytest from typer.testing import CliRunner -from openapi_python_client.parser.errors import GeneratorError, ParseError - runner = CliRunner() -def test_version(mocker): - generate = mocker.patch("openapi_python_client.cli.generate") +def test_version(): from openapi_python_client.cli import app result = runner.invoke(app, ["--version", "generate"]) - generate.assert_not_called() assert result.exit_code == 0 assert "openapi-python-client version: " in result.stdout -@pytest.fixture -def _create_new_client(mocker) -> MagicMock: - return mocker.patch("openapi_python_client.create_new_client", return_value=[]) - - -def test_bad_config(_create_new_client): +def test_bad_config(): from openapi_python_client.cli import app config_path = "config/path" @@ -37,23 +25,22 @@ def test_bad_config(_create_new_client): class TestGenerate: - def test_generate_no_params(self, _create_new_client): + def test_generate_no_params(self): from openapi_python_client.cli import app result = runner.invoke(app, ["generate"]) assert result.exit_code == 1, result.output - _create_new_client.assert_not_called() - def test_generate_url_and_path(self, _create_new_client): + def test_generate_url_and_path(self): from openapi_python_client.cli import app result = runner.invoke(app, ["generate", "--path=blah", "--url=otherblah"]) assert result.exit_code == 1 - _create_new_client.assert_not_called() + assert result.output == "Provide either --url or --path, not both\n" - def test_generate_encoding_errors(self, _create_new_client): + def test_generate_encoding_errors(self): path = "cool/path" file_encoding = "error-file-encoding" from openapi_python_client.cli import app @@ -62,96 +49,3 @@ def test_generate_encoding_errors(self, _create_new_client): assert result.exit_code == 1 assert result.output == f"Unknown encoding : {file_encoding}\n" - - def test_generate_handle_errors(self, _create_new_client): - _create_new_client.return_value = [GeneratorError(detail="this is a message")] - path = "cool/path" - from openapi_python_client.cli import app - - result = runner.invoke(app, ["generate", f"--path={path}"]) - - assert result.exit_code == 1 - assert result.output == ( - "Error(s) encountered while generating, client was not created\n\n" - "Unable to generate the client\n\n" - "this is a message\n\n\n" - "If you believe this was a mistake or this tool is missing a feature you need, please open an issue at " - "https://github.com/openapi-generators/openapi-python-client/issues/new/choose\n" - ) - - def test_generate_handle_multiple_warnings(self, _create_new_client): - error_1 = ParseError(data={"test": "data"}, detail="this is a message") - error_2 = ParseError(data={"other": "data"}, detail="this is another message", header="Custom Header") - _create_new_client.return_value = [error_1, error_2] - path = "cool/path" - from openapi_python_client.cli import app - - result = runner.invoke(app, ["generate", f"--path={path}"]) - - assert result.exit_code == 0 - assert result.output == ( - "Warning(s) encountered while generating. Client was generated, but some pieces may be missing\n\n" - "Unable to parse this part of your OpenAPI document: \n\n" - "this is a message\n\n" - "{'test': 'data'}\n\n" - "Custom Header\n\n" - "this is another message\n\n" - "{'other': 'data'}\n\n" - "If you believe this was a mistake or this tool is missing a feature you need, please open an issue at " - "https://github.com/openapi-generators/openapi-python-client/issues/new/choose\n" - ) - - def test_generate_fail_on_warning(self, _create_new_client): - error_1 = ParseError(data={"test": "data"}, detail="this is a message") - error_2 = ParseError(data={"other": "data"}, detail="this is another message", header="Custom Header") - _create_new_client.return_value = [error_1, error_2] - path = "cool/path" - from openapi_python_client.cli import app - - result = runner.invoke(app, ["generate", f"--path={path}", "--fail-on-warning"]) - - assert result.exit_code == 1 - assert result.output == ( - "Warning(s) encountered while generating. Client was generated, but some pieces may be missing\n\n" - "Unable to parse this part of your OpenAPI document: \n\n" - "this is a message\n\n" - "{'test': 'data'}\n\n" - "Custom Header\n\n" - "this is another message\n\n" - "{'other': 'data'}\n\n" - "If you believe this was a mistake or this tool is missing a feature you need, please open an issue at " - "https://github.com/openapi-generators/openapi-python-client/issues/new/choose\n" - ) - - -@pytest.fixture -def _update_existing_client(mocker): - return mocker.patch("openapi_python_client.update_existing_client") - - -class TestUpdate: - def test_update_no_params(self, _update_existing_client): - from openapi_python_client.cli import app - - result = runner.invoke(app, ["update"]) - - assert result.exit_code == 1 - _update_existing_client.assert_not_called() - - def test_update_url_and_path(self, _update_existing_client): - from openapi_python_client.cli import app - - result = runner.invoke(app, ["update", "--path=blah", "--url=otherblah"]) - - assert result.exit_code == 1 - _update_existing_client.assert_not_called() - - def test_update_encoding_errors(self, _update_existing_client): - path = "cool/path" - file_encoding = "error-file-encoding" - from openapi_python_client.cli import app - - result = runner.invoke(app, ["update", f"--path={path}", f"--file-encoding={file_encoding}"]) - - assert result.exit_code == 1 - assert result.output == f"Unknown encoding : {file_encoding}\n"