From d9dc894a8b5e475b5b8479d7b435668ff7384f5b Mon Sep 17 00:00:00 2001 From: Paul Hallett Date: Wed, 4 Oct 2023 09:25:45 +1300 Subject: [PATCH 1/2] Add contributing file --- CONTRIBUTING.md | 96 +++++++++++++++++++++++++++++++ Makefile | 6 ++ tests/async_test_client/client.py | 16 +++--- tests/async_test_client/http.py | 2 +- tests/test_client/client.py | 16 +++--- tests/test_client/http.py | 2 +- 6 files changed, 120 insertions(+), 18 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..61a9ec4 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,96 @@ +# Contributing + +First things first: thank you for contributing! This project will be succesful thanks to everyone who contributes, and we're happy to have you. + +## Bug or issue? + +To raise a bug or issue please use [our GitHub](https://github.com/phalt/clientele/issues). + +Please check the issue has not be raised before by using the search feature. + +When submitting an issue or bug, please make sure you provide thorough detail on: + +1. The version of clientele you are using +2. Any errors or outputs you see in your terminal +3. The OpenAPI schema you are using (this is particularly important). + +## Contribution + +If you want to directly contribute you can do so in two ways: + +1. Documentation +2. Code + +### Documentation + +We use [mkdocs](https://www.mkdocs.org/) and [GitHub pages](https://pages.github.com/) to deploy our docs. + +Fixing grammar, spelling mistakes, or expanding the documentation to cover features that are not yet documented, are all valuable contributions. + +Please see the **Set up** instructions below to run the docs locally on your computer. + +### Code + +Contribution by writing code for new features, or fixing bugs, is a great way to contribute to the project. + +#### Set up + +Clone the repo: + +```sh +git@github.com:phalt/clientele.git +cd clientele +``` + +Move to a feature branch: + +```sh +git branch -B my-branch-name +``` + +Install all the dependencies: + +```sh +python3.11 -m venv .venv +source .venv/bin/activate +make install +``` + +To make sure you have things set up correctly, please run the tests: + +```sh +make test +``` + +### Preparing changes for review + +Once you have made changes, here is a good check list to run through to get it published for review: + +Regenerate the test clients to see what has changed, and if tests pass: + +```sh +make generate-test-clients +make test +``` + +Check your `git diff` to see if anything drastic has changed. If changes happen that you did not expect, something has gone wrong. We want to make sure the clients do not change drastically when adding new features unless it is intended. + +Format and lint the code: + +```sh +make lint +``` + +Make sure you add to `CHANGELOG.md` and `docs/CHANGELOG.md` what changes you have made. + +Make sure you add your name to `CONTRIBUTORS.md` as well! + +### Making a pull request + +Please push your changes up to a feature branch and make a new [pull request](https://github.com/phalt/clientele/compare) on GitHub. + +Please add a description to the PR and some information about why the change is being made. + +After a review you might need to make more changes. + +Once accepted, a core contributor will merge your changes! diff --git a/Makefile b/Makefile index 2b879be..5920586 100644 --- a/Makefile +++ b/Makefile @@ -37,3 +37,9 @@ test: ## Run tests shell: ## Run an ipython shell poetry run ipython + +generate-test-clients: ## regenerate the test clients in the tests/ directory + poetry install + clientele generate -f example_openapi_specs/best.json -o tests/test_client/ + clientele generate -f example_openapi_specs/best.json -o tests/async_test_client/ --asyncio t + black tests/ diff --git a/tests/async_test_client/client.py b/tests/async_test_client/client.py index c928903..1e4e3fb 100644 --- a/tests/async_test_client/client.py +++ b/tests/async_test_client/client.py @@ -11,7 +11,7 @@ async def complex_model_request_complex_model_request_get() -> schemas.ComplexModelResponse: """Complex Model Request""" - response = await http.get(url="/complex-model-request") + response = await http.get(url=f"/complex-model-request") return http.handle_response( complex_model_request_complex_model_request_get, response ) @@ -24,14 +24,14 @@ async def header_request_header_request_get( headers_dict = ( headers and headers.model_dump(by_alias=True, exclude_unset=True) or None ) - response = await http.get(url="/header-request", headers=headers_dict) + response = await http.get(url=f"/header-request", headers=headers_dict) return http.handle_response(header_request_header_request_get, response) async def optional_parameters_request_optional_parameters_get() -> schemas.OptionalParametersResponse: """Optional Parameters Request""" - response = await http.get(url="/optional-parameters") + response = await http.get(url=f"/optional-parameters") return http.handle_response( optional_parameters_request_optional_parameters_get, response ) @@ -42,7 +42,7 @@ async def request_data_request_data_post( ) -> typing.Union[schemas.HTTPValidationError, schemas.RequestDataResponse]: """Request Data""" - response = await http.post(url="/request-data", data=data.model_dump()) + response = await http.post(url=f"/request-data", data=data.model_dump()) return http.handle_response(request_data_request_data_post, response) @@ -51,7 +51,7 @@ async def request_data_request_data_put( ) -> typing.Union[schemas.HTTPValidationError, schemas.RequestDataResponse]: """Request Data""" - response = await http.put(url="/request-data", data=data.model_dump()) + response = await http.put(url=f"/request-data", data=data.model_dump()) return http.handle_response(request_data_request_data_put, response) @@ -69,14 +69,14 @@ async def request_data_path_request_data( async def request_delete_request_delete_delete() -> schemas.DeleteResponse: """Request Delete""" - response = await http.delete(url="/request-delete") + response = await http.delete(url=f"/request-delete") return http.handle_response(request_delete_request_delete_delete, response) async def security_required_request_security_required_get() -> schemas.SecurityRequiredResponse: """Security Required Request""" - response = await http.get(url="/security-required") + response = await http.get(url=f"/security-required") return http.handle_response( security_required_request_security_required_get, response ) @@ -103,7 +103,7 @@ async def query_request_optional_query_get( async def simple_request_simple_request_get() -> schemas.SimpleResponse: """Simple Request""" - response = await http.get(url="/simple-request") + response = await http.get(url=f"/simple-request") return http.handle_response(simple_request_simple_request_get, response) diff --git a/tests/async_test_client/http.py b/tests/async_test_client/http.py index 4603486..d3c453e 100644 --- a/tests/async_test_client/http.py +++ b/tests/async_test_client/http.py @@ -114,7 +114,7 @@ def handle_response(func, response): auth_key = c.get_bearer_token() headers = c.additional_headers() -headers.update(Authorization="Bearer " + auth_key) +headers.update(Authorization=f"Bearer " + auth_key) client = httpx.AsyncClient(headers=headers) diff --git a/tests/test_client/client.py b/tests/test_client/client.py index 82b0d03..9f36f6b 100644 --- a/tests/test_client/client.py +++ b/tests/test_client/client.py @@ -11,7 +11,7 @@ def complex_model_request_complex_model_request_get() -> schemas.ComplexModelResponse: """Complex Model Request""" - response = http.get(url="/complex-model-request") + response = http.get(url=f"/complex-model-request") return http.handle_response( complex_model_request_complex_model_request_get, response ) @@ -24,7 +24,7 @@ def header_request_header_request_get( headers_dict = ( headers and headers.model_dump(by_alias=True, exclude_unset=True) or None ) - response = http.get(url="/header-request", headers=headers_dict) + response = http.get(url=f"/header-request", headers=headers_dict) return http.handle_response(header_request_header_request_get, response) @@ -33,7 +33,7 @@ def optional_parameters_request_optional_parameters_get() -> ( ): """Optional Parameters Request""" - response = http.get(url="/optional-parameters") + response = http.get(url=f"/optional-parameters") return http.handle_response( optional_parameters_request_optional_parameters_get, response ) @@ -44,7 +44,7 @@ def request_data_request_data_post( ) -> typing.Union[schemas.HTTPValidationError, schemas.RequestDataResponse]: """Request Data""" - response = http.post(url="/request-data", data=data.model_dump()) + response = http.post(url=f"/request-data", data=data.model_dump()) return http.handle_response(request_data_request_data_post, response) @@ -53,7 +53,7 @@ def request_data_request_data_put( ) -> typing.Union[schemas.HTTPValidationError, schemas.RequestDataResponse]: """Request Data""" - response = http.put(url="/request-data", data=data.model_dump()) + response = http.put(url=f"/request-data", data=data.model_dump()) return http.handle_response(request_data_request_data_put, response) @@ -69,7 +69,7 @@ def request_data_path_request_data( def request_delete_request_delete_delete() -> schemas.DeleteResponse: """Request Delete""" - response = http.delete(url="/request-delete") + response = http.delete(url=f"/request-delete") return http.handle_response(request_delete_request_delete_delete, response) @@ -78,7 +78,7 @@ def security_required_request_security_required_get() -> ( ): """Security Required Request""" - response = http.get(url="/security-required") + response = http.get(url=f"/security-required") return http.handle_response( security_required_request_security_required_get, response ) @@ -105,7 +105,7 @@ def query_request_optional_query_get( def simple_request_simple_request_get() -> schemas.SimpleResponse: """Simple Request""" - response = http.get(url="/simple-request") + response = http.get(url=f"/simple-request") return http.handle_response(simple_request_simple_request_get, response) diff --git a/tests/test_client/http.py b/tests/test_client/http.py index a6aed4f..e8e25b2 100644 --- a/tests/test_client/http.py +++ b/tests/test_client/http.py @@ -114,7 +114,7 @@ def handle_response(func, response): auth_key = c.get_bearer_token() headers = c.additional_headers() -headers.update(Authorization="Bearer " + auth_key) +headers.update(Authorization=f"Bearer " + auth_key) client = httpx.Client(headers=headers) From 0b6fae48106acfe054f4e7bdce17c594c2631849 Mon Sep 17 00:00:00 2001 From: Paul Hallett Date: Thu, 5 Oct 2023 08:54:13 +1300 Subject: [PATCH 2/2] Update docs pages --- docs/usage.md | 63 ++++++++++++++++++++++++++++++++++++--------------- mkdocs.yml | 2 +- 2 files changed, 46 insertions(+), 19 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index 9118a7f..3f599e0 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -1,25 +1,19 @@ -# 📝 Commands +# 📝 Use Clientele -## Validate - -Validate lets you check if an OpenAPI schema will work with clientele. Some OpenAPI schema generators do not comply properly with the specification and it is a good way to check if your schema is correct. - -```sh -clientele validate -u http://path.com/to/openapi.json -``` +!!! note -Alternatively you can provide a local file: + You can type `clientele COMMAND --help` at anytime to see explicit information about the available arguments. -```sh -clientele validate -f /path/to/openapi.json -``` +## `generate` -## Generate +Generate a Python HTTP Client from an OpenAPI Schema. ### From a URL -Assuming the OpenAPI schema is available on the internet somewhere, you can query it to generate your client. +Use the `-u` or `--url` argument. + +`-o` or `--output` is the target directory for the generate client. ```sh clientele generate -u https://raw.githubusercontent.com/phalt/clientele/main/example_openapi_specs/best.json -o my_client/ @@ -27,17 +21,17 @@ clientele generate -u https://raw.githubusercontent.com/phalt/clientele/main/exa !!! note - The example above uses a test OpenAPI format, and will work if you copy/paste it! + The example above uses one of our test schemas, and will work if you copy/paste it! ### From a file -Alternatively, if you have a local file you can use it to generate your client. +Alternatively you can provide a local file using the `-f` or `--file` argument. ```sh clientele generate -f path/to/file.json -o my_client/ ``` -### Async Client +### Async.io If you prefer an [asyncio](https://docs.python.org/3/library/asyncio.html) client, just pass `--asyncio t` to your command. @@ -45,6 +39,39 @@ If you prefer an [asyncio](https://docs.python.org/3/library/asyncio.html) clien clientele generate -f path/to/file.json -o my_client/ --asyncio t ``` +## `validate` + +Validate lets you check if an OpenAPI schema will work with clientele. + !!! note - You can use this command later to swap between a sync and async client so long as the OpenAPI schema remains the same, so don't worry about making a hard decision now. + Some OpenAPI schema generators do not conform to the [specification](https://spec.openapis.org/oas/v3.1.0). + + Clientele uses [openapi-core](https://openapi-core.readthedocs.io/en/latest/) to validate the schema. + +### From a URL + +Use the `-u` or `--url` argument. + +`-o` or `--output` is the target directory for the generate client. + +```sh +clientele validate -u http://path.com/to/openapi.json +``` + +### From a file path + +Alternatively you can provide a local file using the `-f` or `--file` argument. + +```sh +clientele validate -f /path/to/openapi.json +``` + +## `version` + +Print the current version of Clientele: + +```sh +> clientele version +Clientele 0.7.0 +``` diff --git a/mkdocs.yml b/mkdocs.yml index 916ab68..a0816c1 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -10,7 +10,7 @@ repo_url: https://github.com/phalt/clientele nav: - Home: index.md - Install: install.md - - Commands: usage.md + - Use: usage.md - Client Example: examples.md - Testing: testing.md - Compatibility: compatibility.md