diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index dad69c2..4dedd56 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -14,6 +14,12 @@ jobs: - uses: actions/setup-python@v4 with: python-version: 3.x + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + version: 1.5.1 + - name: Install dependencies + run: poetry install --with docs - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV - uses: actions/cache@v3 with: @@ -21,5 +27,6 @@ jobs: path: .cache restore-keys: | mkdocs-material- - - run: pip install mkdocs-material - - run: mkdocs gh-deploy --force + - name: Deploy Documentation + run: | + poetry run mkdocs gh-deploy --force diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 17d44ff..c584a30 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,7 +24,7 @@ jobs: - name: Upgrade pip run: | - pip install --constraint=.github/workflows/constraints.txt pip + pip install --upgrade pip pip --version - name: Install Poetry uses: snok/install-poetry@v1 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2749d96..6b08a48 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -34,7 +34,7 @@ jobs: - name: Upgrade pip run: | - pip install --constraint=.github/workflows/constraints.txt pip + pip install pip pip --version - name: Upgrade pip in virtual environments shell: python diff --git a/README.md b/README.md index 775a375..4bc2ea2 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,140 @@ -# geoserverx -A GeoServer REST API client influenced by HTTPX +# GeoServerX ------------ +A modern, powerful GeoServer REST API client influenced by HTTPX, offering Sync, Async, and CLI capabilities. -`geoserverx` allows `Sync`, `Async` as well as `CLI` Capabilities to talk to your geoserver REST APIs which makes it ideal to be used in software development project which relies on content of geoserver. +[![Downloads](https://pepy.tech/badge/geoserverx)](https://pepy.tech/project/geoserverx) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) +[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff) +[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/) +[![Built with Material for MkDocs](https://img.shields.io/badge/Material_for_MkDocs-526CFE?style=for-the-badge&logo=MaterialForMkDocs&logoColor=white)](https://squidfunk.github.io/mkdocs-material/) -Here is a simplistic view of how geoserverx works under the hood -![architecture](/docs/assets/images/arch.png "architecture") +## Features +- 🚀 Synchronous and Asynchronous API support +- 🖥️ Command Line Interface (CLI) +- 🔄 Complete GeoServer REST API coverage +- 🏗️ Modern Pythonic interface +- 📦 Easy to install and use +- 📝 Type hints for better development experience +## Installation +```bash +pip install geoserverx +``` +## Quick Start -## Contribution guide +### Synchronous Usage -### Feature/Bug request -Please open new issue if you want to report any bug or send feature request +```python +from geoserverx._sync.gsx import SyncGeoServerX -### Running on local -`geoserverx` is built with [poetry](https://python-poetry.org/) and it uses following dependencies and dev-dependencies +# Initialize with default GeoServer settings +# Default: URL=http://localhost:8080/geoserver/rest, username=admin, password=geoserver +geo_server = SyncGeoServerX() -![layout](/docs/assets/images/layout.png "layout") \ No newline at end of file +# Custom initialization +geo_server = SyncGeoServerX( + url="http://your-server:8080/geoserver/rest", + username="your_username", + password="your_password" +) + +# Get all workspaces +workspaces = geo_server.get_all_workspaces() + +# Access workspace information +print(workspaces) # Print Workspaces Model +print(workspaces.workspaces) # Print detailed list of workspaces +print(workspaces.workspaces.workspace[0].name) # Print first workspace name +``` + +### Asynchronous Usage + +```python +from geoserverx._async.gsx import AsyncGeoServerX +import asyncio + +async def main(): + geo_server = AsyncGeoServerX() + workspaces = await geo_server.get_all_workspaces() + print(workspaces) + +asyncio.run(main()) +``` + +### CLI Usage + +```bash +# Get help +geoserverx --help + +# List workspaces +geoserverx workspaces list + +# Add a new workspace +geoserverx workspaces create --name my_workspace +``` + +## Documentation + +Detailed documentation is available through [Material for MkDocs](https://geobeyond.github.io/geoserverx/) + +## Development Setup + +Install Poetry (dependency management tool): + +```bash + curl -sSL https://install.python-poetry.org | python3 - +``` + +```bash +# Clone the repository: +git clone https://github.com/geobeyond/geoserverx.git +cd geoserverx +``` + +```bash +# Install dependencies: +poetry install +``` + +```bash + +# Activate virtual environment: +poetry shell +``` + +## Contributing + +We welcome contributions! Here's how you can help: + +- Check for open issues or create a new one to discuss new features or bugs. +- Fork the repo and create a new branch for your contribution. +- Write your code and tests. +- Send a pull request. + +## Development Guidelines + +- Follow [Black](https://black.readthedocs.io/en/stable/) code style +- Use [isort](https://pycqa.github.io/isort/index.html) ([black profile](https://pycqa.github.io/isort/docs/configuration/black_compatibility.html)) for import sorting +- Use [Ruff](https://docs.astral.sh/ruff/) for linting +- Ensure all tests pass +- Add tests for new features +- Update documentation as needed + +## Bug Reports and Feature Requests + +Please use the GitHub issue tracker to report bugs or request features. + +## License + +This project is licensed under the MIT License - see the LICENSE file for details. + +## Acknowledgments + +- HTTPX for inspiration +- GeoServer community +- All contributors who have helped shape this project diff --git a/docs/index.md b/docs/index.md index cb2ee97..92e83d3 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,3 +1,11 @@ +--- +hide: + - navigation + - toc + +title : GeoServerX +description: modern python and CLI package for communicating with GeoServer +--- # Welcome to geoserverx `geoserverx` is a modern Python package that provides an efficient and scalable way to interact with Geoserver REST APIs. It leverages the asynchronous capabilities of Python to offer a high-performance and reliable solution for managing Geoserver data and services. @@ -24,13 +32,22 @@ pip install geoserverx After which , It can be used in Python projects using sync, async methods or can ve used as Command Line tool +## Architecture + +`geoserverx` is built on top of `httpx` and `pydantic` libraries. It uses `httpx` for making HTTP requests and `pydantic` for data validation. The package is designed to be modular and extensible, allowing for easy integration with other libraries and frameworks. + +The package is structured into two main components: the `SyncGeoServerX` class and the `AsyncGeoServerX` class. The `SyncGeoServerX` class provides synchronous methods for interacting with Geoserver, while the `AsyncGeoServerX` class provides asynchronous methods using the `anyio` library + +![layout](./assets/images/layout.png){ align=left } + + ## For testing purpose -If you don't have geoserver installed locally, feel free to use following command to quickly spin up Geoserver using [Docker](https://www.docker.com/) +If you don't have GeoServer installed locally, feel free to use following command to quickly spin up Geoserver using [Docker](https://www.docker.com/)
```console -docker run -e GEOSERVER_ADMIN_USER=admin -e GEOSERVER_ADMIN_PASSWORD=geoserver -e SAMPLE_DATA=true -p 8080:8080 kartoza/geoserver +docker run -e GEOSERVER_ADMIN_USER=admin -e GEOSERVER_ADMIN_PASSWORD=geoserver -e SAMPLE_DATA=true -p 8080:8080 kartoza/GeoServer ```
-Please not that this will work on amd64 architecture machines. \ No newline at end of file +Please note that this will work on amd64 architecture machines. \ No newline at end of file diff --git a/docs/pages/async/example.md b/docs/pages/async/example.md index 02723fd..a87c61d 100644 --- a/docs/pages/async/example.md +++ b/docs/pages/async/example.md @@ -7,7 +7,7 @@ Here, we'll have a look at implementation `geoserverx` asynchronous Class ## Setup Class instance -`AsyncGeoServerX` Class has default username, password, url which points to default geoserver settings. +`AsyncGeoServerX` Class has default username, password, url which points to default GeoServer settings. ```Python # Import class from package from geoserverx._async.gsx import AsyncGeoServerX @@ -15,7 +15,7 @@ import asyncio # Create class Instance with default paramaters client = AsyncGeoServerX() ``` -We'll assume connection to local geoserver with default credentials +We'll assume connection to local GeoServer with default credentials ## Get all workspaces @@ -29,7 +29,7 @@ async def get_info_raster_workspaces(url, username, password): print(await client.get_all_workspaces()) async def main(): - await asyncio.gather(get_info_raster_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver'),get_info_raster_workspaces(url='http://89.233.108.250:8080/geoserver/rest',username='admin', password='myP'),get_info_raster_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver')) + await asyncio.gather(get_info_raster_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer'),get_info_raster_workspaces(url='http://locahost:8080/geoserver/rest',username='admin', password='myP'),get_info_raster_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer')) asyncio.run(main()) @@ -53,7 +53,7 @@ async def get_info_raster_workspaces(url, username, password,workspace): print(await client.get_workspace(workspace)) async def main(): - await asyncio.gather(get_info_raster_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver',workspace='cesium')) + await asyncio.gather(get_info_raster_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer',workspace='cesium')) asyncio.run(main()) @@ -80,13 +80,13 @@ async def create_single_workspaces(url, username, password,workspace,default,iso async def main(): await asyncio.gather(create_single_workspaces( - url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver', + url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer', workspace='AsyncMyDefault',default=True,isolated= False), create_single_workspaces( - url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver', + url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer', workspace='AsyncMyHidden',default=False,isolated= True), create_single_workspaces( - url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver', + url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer', workspace='AsyncMySimple',default=False,isolated= False)) asyncio.run(main()) @@ -114,7 +114,7 @@ async def create_single_workspaces(url, username, password,workspace): async def main(): await asyncio.gather(create_single_workspaces( - url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver', + url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer', workspace='cesium')) asyncio.run(main()) @@ -138,7 +138,7 @@ async def get_info_vector_workspaces(url, username, password,workspace,store): async def main(): await asyncio.gather(get_info_vector_workspaces( - url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver', + url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer', workspace='cesium',store='myshp')) asyncio.run(main()) @@ -163,7 +163,7 @@ def add_vector_workspaces(url, username, password,workspace,store,file): client = SyncGeoServerX(username, password,url) return client.create_file_store(workspace, store, file, service_type='shapefile') -result = add_vector_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver', +result = add_vector_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer', workspace='cesium',store='myshp', file='safe_users.zip' ) print(result.json()) @@ -188,7 +188,7 @@ async def get_all_raster_workspaces(url, username, password,workspace): async def main(): await asyncio.gather(get_all_raster_workspaces( - url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver',workspace='cesium')) + url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer',workspace='cesium')) asyncio.run(main()) @@ -211,7 +211,7 @@ async def get_info_raster_workspaces(url, username, password,workspace,store): async def main(): await asyncio.gather(get_info_raster_workspaces( - url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver',workspace='cesium',store='dsm')) + url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer',workspace='cesium',store='dsm')) asyncio.run(main()) @@ -221,7 +221,7 @@ coverageStore=CoveragesStoreModelDetail(name='dsm', description=None, enabled=Tr ''' ``` -## Get all Styles in geoserver +## Get all Styles in GeoServer ```Python hl_lines="7" from geoserverx._async.gsx import AsyncGeoServerX @@ -234,7 +234,7 @@ async def get_info_raster_workspaces(url, username, password): async def main(): await asyncio.gather(get_info_raster_workspaces( - url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver')) + url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer')) asyncio.run(main()) @@ -244,7 +244,7 @@ styles=allStyle(style=[allStyleList(name='burg', href='http://localhost:8080/geo ''' ``` -## Get Single Style in geoserver +## Get Single Style in GeoServer ```Python hl_lines="7" from geoserverx._async.gsx import AsyncGeoServerX @@ -257,7 +257,7 @@ async def get_info_raster_workspaces(url, username, password,style): async def main(): await asyncio.gather(get_info_raster_workspaces( - url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver',style='poi')) + url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer',style='poi')) asyncio.run(main()) ''' Console diff --git a/docs/pages/async/index.md b/docs/pages/async/index.md index 2521835..f4f8110 100644 --- a/docs/pages/async/index.md +++ b/docs/pages/async/index.md @@ -7,7 +7,7 @@ ## Setup Class instance -`AsyncGeoServerX` Class has default username, password, url which points to default geoserver settings. +`AsyncGeoServerX` Class has default username, password, url which points to default GeoServer settings. ```Python # Import class from package from geoserverx._async.gsx import AsyncGeoServerX diff --git a/docs/pages/async/raster-store.md b/docs/pages/async/raster-store.md index a0e8a51..7403a86 100644 --- a/docs/pages/async/raster-store.md +++ b/docs/pages/async/raster-store.md @@ -1,10 +1,10 @@ # Raster Stores -`geoserverx` allows users to access all/one raster stores from geoserver +`geoserverx` allows users to access all/one raster stores from GeoServer ## Get all raster stores -This command fetches all Vector store available in given workspace from geoserver. +This command fetches all Vector store available in given workspace from GeoServer. ```py # Get all raster stores available in `cite` workspace @@ -14,7 +14,7 @@ await client.get_raster_stores_in_workspaces('cite') ## Get single raster store -This command fetches all Information about raster store available in given workspace from geoserver. +This command fetches all Information about raster store available in given workspace from GeoServer. ```Python # Get all information about `image` raster stores available in `cite` workspace diff --git a/docs/pages/async/style.md b/docs/pages/async/style.md index 56a3da0..1424e19 100644 --- a/docs/pages/async/style.md +++ b/docs/pages/async/style.md @@ -3,19 +3,19 @@ ## Get all Styles -This command fetches all Styles available in geoserver. +This command fetches all Styles available in GeoServer. ```Python -# Get all styles available in geoserver +# Get all styles available in GeoServer await client.get_all_styles() ``` ## Get single Style -This command fetches information about particular Style from geoserver. +This command fetches information about particular Style from GeoServer. ```py -# Get information about `population` style from geoserver +# Get information about `population` style from GeoServer await client.get_style('population') ``` diff --git a/docs/pages/async/vector-store.md b/docs/pages/async/vector-store.md index 21e1f3a..f281594 100644 --- a/docs/pages/async/vector-store.md +++ b/docs/pages/async/vector-store.md @@ -1,9 +1,9 @@ # Vector Stores -`geoserverx` allows users to access all/one vector stores from geoserver. As of now, `geoserverx` also supports new vector store creation for `shapefile` and `gpkg` data +`geoserverx` allows users to access all/one vector stores from GeoServer. As of now, `geoserverx` also supports new vector store creation for `shapefile` and `gpkg` data ## Get all Vector stores -This command fetches all Vector store available in given workspace from geoserver. +This command fetches all Vector store available in given workspace from GeoServer. ```Python # Get all vector stores available in `cite` workspace @@ -13,7 +13,7 @@ await client.get_vector_stores_in_workspaces('cite') ## Get single Vector store -This command fetches all Information about Vector store available in given workspace from geoserver. +This command fetches all Information about Vector store available in given workspace from GeoServer. ```Python # Get all information about `shape` vector stores available in `cite` workspace @@ -52,4 +52,20 @@ await client.create_pg_store( username="XXXXXXXX", password="XXXXXXXX", database="test") +``` + +## Get all Vector layers +This command fetches all Vector layers available in given workspace from GeoServer. + +```Python +# Get all vector layers available in `cite` workspace +await client.get_all_layers(workspace='cite') +``` + +## Get single Vector layer +This command fetches all Information about Vector layer available in given workspace from GeoServer. + +```Python +# Get all information about `roads` vector layers available in `cite` workspace +await client.get_vector_layer(workspace='cite', store='shape', layer='roads') ``` \ No newline at end of file diff --git a/docs/pages/async/workspace.md b/docs/pages/async/workspace.md index d843dc7..4b7347b 100644 --- a/docs/pages/async/workspace.md +++ b/docs/pages/async/workspace.md @@ -1,31 +1,71 @@ -# Workspaces +# Workspaces -`geoserverx` allows users to access all/one workspace from geoserver, along with ability to add new workspaces. +`geoserverx` allows users to access all/one workspace from GeoServer, along with ability to do CRUD operations on workspaces. + +!!! get "Get started" +To start using `geoserverx` in Sync mode, create a new instance of `AsyncGeoServerX` Class, read more about it [here](https://geobeyond.github.io/geoserverx/pages/async/) ## Get all workspaces -This command fetches all workspaces available in geoserver. No paramters are required to be passed. -```Python -# Get all workspaces in geoserver +This command fetches all workspaces available in GeoServer. No parameters are required to be passed. + +```py +# Get all workspaces in GeoServer await client.get_all_workspaces() ``` ## Get single workspace -This command fetches workspace with paramter as name of it from geoserver. + +Fetches workspace details. + ```Python # Get workspace with name `cite` await client.get_workspace('cite') ``` ## Create workspace -This command allows user to create new workspace. + +This command allows user to create new workspace. Creating new workspace requires following parameters -* Name `str` : To define Name of the workspace -* default `bool` : To define whether to keep workspace as default or not -* Isolated `bool` : To define whether to keep workspace Isolated or not - +| Parameter | Required | Default value | Data type | Description | +| --------- | ----------------------------- | ------------- | --------- | ------------------------------------------------------ | +| Name | :white_check_mark: | | `str` | To define Name of the workspace | +| default | :negative_squared_cross_mark: | `False` | `bool` | To define whether to keep workspace as default or not | +| isolated | :negative_squared_cross_mark: | `False` | `bool` | To define whether to keep workspace as Isolated or not | + ```Python #Create new workspace with name `my_wrkspc` , make it Default and Isolated await client.create_workspace(name='my_wrkspc',default=True,Isolated=True) ``` + +## Delete workspace + +This command allows user to delete workspace. + +| Parameter | Required | Default value | Data type | Description | +| --------- | ----------------------------- | ------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | +| workspace | :white_check_mark: | | `str` | Name of the workspace | +| recurse | :negative_squared_cross_mark: | `False` | `bool` | This parameter recursively deletes all layers referenced by the specified workspace, including data stores, coverage stores, feature types, and so on | + +```Python +#Delete workspace with name `my_wrkspc`. +await client.delete_workspace(workspace='my_wrkspc',recurse=True) +``` + +## Update workspace + +This command allows user to update existing workspace. +Updating workspace requires following parameters + +| Parameter | Required | Data type | Description | +| --------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ | +| name | :white_check_mark: | `str` | Name of the workspace to be updated | +| update | :white_check_mark: | [`UpdateWorkspaceInfo`](https://github.com/geobeyond/geoserverx/blob/b7757c9f0130864b06c40c2faa17afc841fc705f/src/geoserverx/models/workspace.py#L42) | To define body of the update request | + +```Python +#Updating workspace with name `my_wrkspc` , make is Isolated and rename it to `my_new_wrkspc` +from geoserverx.models.workspace import UpdateWorkspaceInfo + +await client.update_workspace(name='my_wrkspc',update=UpdateWorkspaceInfo(name='my_new_wrkspc',isolated=True)) +``` diff --git a/docs/pages/cli/example.md b/docs/pages/cli/example.md index 30a304e..3a5edda 100644 --- a/docs/pages/cli/example.md +++ b/docs/pages/cli/example.md @@ -20,7 +20,7 @@ Error: Missing command. ``` -We'll assume connection to local geoserver with default credentials +We'll assume connection to local GeoServer with default credentials ## Get all workspaces diff --git a/docs/pages/cli/index.md b/docs/pages/cli/index.md index 9eb6ecb..8dee7dc 100644 --- a/docs/pages/cli/index.md +++ b/docs/pages/cli/index.md @@ -1,6 +1,6 @@ # Command line access -`geoserverx` allows users to leverage power of command line to communicate with geoserver. +`geoserverx` allows users to leverage power of command line to communicate with GeoServer. `gsx` is a command line tool by `geoserverx`. ## Installation diff --git a/docs/pages/cli/raster-store.md b/docs/pages/cli/raster-store.md index bbdb2da..818e2d9 100644 --- a/docs/pages/cli/raster-store.md +++ b/docs/pages/cli/raster-store.md @@ -1,6 +1,6 @@ # Raster Stores -`geoserverx` allows users to access all/one raster stores from geoserver. As of now, `geoserverx` also supports new raster store creation for `shapefile` and `gpkg` data +`geoserverx` allows users to access all/one raster stores from GeoServer. As of now, `geoserverx` also supports new raster store creation for `shapefile` and `gpkg` data !!! get "Get started" To start using `geoserverx` using command line, activate the Environment where package is installed and use `gsx` command @@ -30,8 +30,8 @@ As listed above, `raster-st-wp` command accepts following parameters. * request type ( sync or async ) * url - Geoserver REST URL -* password - Password for geoserver -* username - Username for geoserver +* password - Password for GeoServer +* username - Username for GeoServer All these parameters have default value setup which will work for local default installation. Apart from this `workspace` paramters must be added which aims at the workspace we are interested in @@ -64,7 +64,7 @@ Options: --store TEXT Store name [required] --url TEXT Geoserver REST URL [default: http://127.0.0.1:8080/geoserver/rest/] - --password TEXT Geoserver Password [default: geoserver] + --password TEXT Geoserver Password [default: GeoServer] --username TEXT Geoserver username [default: admin] --help Show this message and exit. diff --git a/docs/pages/cli/style.md b/docs/pages/cli/style.md index 824a095..0dcf297 100644 --- a/docs/pages/cli/style.md +++ b/docs/pages/cli/style.md @@ -1,6 +1,6 @@ # Style -`geoserverx` allows users to access all/one raster stores from geoserver. As of now, `geoserverx` also supports new raster store creation for `shapefile` and `gpkg` data +`geoserverx` allows users to access all/one raster stores from GeoServer. As of now, `geoserverx` also supports new raster store creation for `shapefile` and `gpkg` data !!! get "Get started" To start using `geoserverx` using command line, activate the Environment where package is installed and use `gsx` command @@ -19,7 +19,7 @@ Options: --request [sync|async] [default: requestEnum._sync] --url TEXT Geoserver REST URL [default: http://127.0.0.1:8080/geoserver/rest/] - --password TEXT Geoserver Password [default: geoserver] + --password TEXT Geoserver Password [default: GeoServer] --username TEXT Geoserver username [default: admin] --help Show this message and exit. ``` @@ -29,8 +29,8 @@ As listed above, `styles` command accepts following parameters. * request type ( sync or async ) * url - Geoserver REST URL -* password - Password for geoserver -* username - Username for geoserver +* password - Password for GeoServer +* username - Username for GeoServer All these parameters have default value setup which will work for local default installation. @@ -67,7 +67,7 @@ Options: --url TEXT Geoserver REST URL [default: http://127.0.0.1:8080/geoserver/rest/] --style TEXT Style name [required] - --password TEXT Geoserver Password [default: geoserver] + --password TEXT Geoserver Password [default: GeoServer] --username TEXT Geoserver username [default: admin] --help Show this message and exit. diff --git a/docs/pages/cli/vector-store.md b/docs/pages/cli/vector-store.md index 6280f15..bad2e1b 100644 --- a/docs/pages/cli/vector-store.md +++ b/docs/pages/cli/vector-store.md @@ -1,6 +1,6 @@ # Vector Stores -`geoserverx` allows users to access all/one vector stores from geoserver. As of now, `geoserverx` also supports new vector store creation for `shapefile` and `gpkg` data +`geoserverx` allows users to access all/one vector stores from GeoServer. As of now, `geoserverx` also supports new vector store creation for `shapefile` and `gpkg` data !!! get "Get started" To start using `geoserverx` using command line, activate the Environment where package is installed and use `gsx` command @@ -19,7 +19,7 @@ Options: --workspace TEXT Workspace name [required] --url TEXT Geoserver REST URL [default: http://127.0.0.1:8080/geoserver/rest/] - --password TEXT Geoserver Password [default: geoserver] + --password TEXT Geoserver Password [default: GeoServer] --username TEXT Geoserver username [default: admin] --help Show this message and exit. ``` @@ -29,8 +29,8 @@ As listed above, `vector-st-wp` command accepts following parameters. * request type ( sync or async ) * url - Geoserver REST URL -* password - Password for geoserver -* username - Username for geoserver +* password - Password for GeoServer +* username - Username for GeoServer All these parameters have default value setup which will work for local default installation. Apart from this `workspace` paramters must be added which aims at the workspace we are interested in @@ -59,7 +59,7 @@ Options: --store TEXT Store name [required] --url TEXT Geoserver REST URL [default: http://127.0.0.1:8080/geoserver/rest/] - --password TEXT Geoserver Password [default: geoserver] + --password TEXT Geoserver Password [default: GeoServer] --username TEXT Geoserver username [default: admin] --help Show this message and exit. diff --git a/docs/pages/cli/workspace.md b/docs/pages/cli/workspace.md index 6f26dbd..4c6362a 100644 --- a/docs/pages/cli/workspace.md +++ b/docs/pages/cli/workspace.md @@ -1,12 +1,10 @@ # Workspaces -`geoserverx` allows users to access all/one workspace from geoserver, along with ability to add new workspaces. +`geoserverx` allows users to access all/one workspace from GeoServer, along with ability to add new workspaces. !!! get "Get started" To start using `geoserverx` using command line, activate the Environment where package is installed and use `gsx` command - - ## Paramters for all workspaces command
@@ -22,40 +20,44 @@ Options: --request [sync|async] [default: requestEnum._sync] --url TEXT Geoserver REST URL [default: http://127.0.0.1:8080/geoserver/rest/] - --password TEXT Geoserver Password [default: geoserver] + --password TEXT Geoserver Password [default: GeoServer] --username TEXT Geoserver username [default: admin] --help Show this message and exit. ``` +
As listed above, `workspaces` command accepts four parameters. * request type ( sync or async ) * url - Geoserver REST URL -* password - Password for geoserver -* username - Username for geoserver +* password - Password for GeoServer +* username - Username for GeoServer All these parameters have default value setup which will work for local default installation ## Get all workspaces
+ ```console $ gsx workspaces {"workspaces": {"workspace": [{"name": "cesium", "href": "http://127.0.0.1:8080/geoserver/rest/workspaces/cesium.json"}]}} ``` +
-## Get all workspaces of hosted geoserver +## Get all workspaces of hosted GeoServer
```console -$ gsx workspaces --url http://89.233.108.250:8080/geoserver/rest --password myPassword --username admin +$ gsx workspaces --url http://locahost:8080/geoserver/rest --password myPassword --username admin {"workspaces": {"workspace": [{"name": "giz", "href": -"http://89.233.108.250:8080/geoserver/rest/workspaces/giz.json"}]}} +"http://locahost:8080/geoserver/rest/workspaces/giz.json"}]}} ``` +
@@ -74,20 +76,21 @@ Options: --workspace TEXT Workspace name [required] --url TEXT Geoserver REST URL [default: http://127.0.0.1:8080/geoserver/rest/] - --password TEXT Geoserver Password [default: geoserver] + --password TEXT Geoserver Password [default: GeoServer] --username TEXT Geoserver username [default: admin] --help Show this message and exit. ``` + As listed above, `workspace` accepts `workspace` parameter as the name of workspace - ## Get single workspaces
+ ```console -$ gsx workspace --workspace cesium +$ gsx workspace cesium {"workspace": {"name": "cesium", "isolated": false, "dateCreated": "2023-02-13 06:43:28.793 UTC", "dataStores": "http://127.0.0.1:8080/geoserver/rest/workspaces/cesium/datastores.json", @@ -96,10 +99,10 @@ $ gsx workspace --workspace cesium "wmsStores": "http://127.0.0.1:8080/geoserver/rest/workspaces/cesium/wmsstores.json", "wmtsStores": "http://127.0.0.1:8080/geoserver/rest/workspaces/cesium/wmtsstores.json"}} ``` -
+ -## Paramters for create workspace command +## Parameters for create workspace command
@@ -116,10 +119,11 @@ Options: --isolated / --no-isolated Make workspace isolated? [default: no-isolated] --url TEXT Geoserver REST URL [default: http://127.0.0.1:8080/geoserver/rest/] - --password TEXT Geoserver Password [default: geoserver] + --password TEXT Geoserver Password [default: GeoServer] --username TEXT Geoserver username [default: admin] --help Show this message and exit. ``` +
As listed above, `create-workspace` command accepts parameters as follows @@ -128,12 +132,95 @@ As listed above, `create-workspace` command accepts parameters as follows * --default/--no-default - To keep workspace either default or not * --isolated/--no-isolated - To keep workspace either isolated or not - ## Create single workspaces
```console -$ gsx create-workspace --workspace mydefaultws --default +$ gsx create-workspace mydefaultws --default code=201 response='Data added successfully' ``` -
\ No newline at end of file + + +## Parameters for delete workspace command + +
+ +```console +$ gsx delete-workspace --help +Usage: gsx delete-workspace [OPTIONS] + + Delete workspace in the Geoserver + +Arguments: + WORKSPACE [required] + +Options: + --request [sync|async] [default: requestEnum._sync] + --recurse / --no-recurse Delete all stores,layers,styles,etc. [default: + no-recurse] + --url TEXT Geoserver REST URL [default: + http://127.0.0.1:8080/geoserver/rest/] + --password TEXT Geoserver Password [default: geoserver] + --username TEXT Geoserver username [default: admin] + --help Show this message and exit. +``` + +
+ +As listed above, `delete-workspace` command accepts parameters as follows + +* --current_name - name of workspace +* --recurse / --no-recurse - This parameter recursively deletes all layers referenced by the specified workspace, including data stores, coverage stores, feature types, and so on + +## Delete single workspaces + +
+```console +gsx delete-workspace my_wrkspace --recurse +{"code":200,"response":"Executed successfully"} +``` +
+ + +## Parameters for update workspace command + +
+ +```console +$ gsx update-workspace --help +Usage: gsx update-workspace [OPTIONS] + + Add workspace in the Geoserver + +Arguments: + CURRENT_NAME [required] + +Options: + --request [sync|async] [default: requestEnum._sync] + --new-name TEXT New Workspace name + --isolated / --no-isolated Make workspace isolated? [default: no-isolated] + --url TEXT Geoserver REST URL [default: + http://127.0.0.1:8080/geoserver/rest/] + --password TEXT Geoserver Password [default: geoserver] + --username TEXT Geoserver username [default: admin] + --help Show this message and exit. +``` + +
+ +As listed above, `update-workspace` command accepts parameters as follows + +* --current-name - name of current workspace +* --new-name - name of new workspace +* --isolated/--no-isolated - To keep workspace either isolated or not + +## Update single workspaces + +
+ +```console +gsx update-workspace d --new-name duster +{"code":200,"response":"Executed successfully"} +``` + +
diff --git a/docs/pages/sync/example.md b/docs/pages/sync/example.md index 5f90623..d097089 100644 --- a/docs/pages/sync/example.md +++ b/docs/pages/sync/example.md @@ -7,14 +7,14 @@ Here, we'll have a look at implementation `geoserverx` synchronous Class ## Setup Class instance -`SyncGeoServerX` Class has default username, password, url which points to default geoserver settings. +`SyncGeoServerX` Class has default username, password, url which points to default GeoServer settings. ```Python # Import class from package from geoserverx._sync.gsx import SyncGeoServerX # Create class Instance with default paramaters client = SyncGeoServerX() ``` -We'll assume connection to local geoserver with default credentials +We'll assume connection to local GeoServer with default credentials ## Get all workspaces @@ -28,7 +28,7 @@ def get_all_gs_workspaces(url, username, password): client = SyncGeoServerX(username, password,url) return client.get_all_workspaces() -result = get_all_gs_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver') +result = get_all_gs_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer') print(result.json()) ''' Console -------------start----------------- @@ -52,7 +52,7 @@ def get_single_workspaces(url, username, password,workspace): client = SyncGeoServerX(username, password,url) return client.get_workspace(workspace) -result = get_single_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver',workspace='cesium') +result = get_single_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer',workspace='cesium') print(result.json()) ''' Console @@ -79,13 +79,13 @@ def create_single_workspaces(url, username, password,workspace,default,isolated) client = SyncGeoServerX(username, password,url) return client.create_workspace(workspace, default,isolated) -first = create_single_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver', +first = create_single_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer', workspace='MyDefault',default=True,isolated= False) print(first.json()) -second = create_single_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver', +second = create_single_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer', workspace='MyHidden',default=False,isolated= True) print(second.json()) -third = create_single_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver', +third = create_single_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer', workspace='MySimple',default=False,isolated= False) print(third.json()) ''' Console @@ -112,7 +112,7 @@ def get_all_vector_workspaces(url, username, password,workspace): client = SyncGeoServerX(username, password,url) return client.get_vector_stores_in_workspaces(workspace) -result = get_vector_store(url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver', +result = get_vector_store(url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer', workspace='cesium') print(result.json()) @@ -135,7 +135,7 @@ def get_info_vector_workspaces(url, username, password,workspace,store): client = SyncGeoServerX(username, password,url) return client.get_vector_store(workspace,store) -result = get_info_vector_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver', +result = get_info_vector_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer', workspace='cesium',store='mysqldb' ) print(result.json()) @@ -160,7 +160,7 @@ def add_vector_workspaces(url, username, password,workspace,store,file): client = SyncGeoServerX(username, password,url) return client.create_file_store(workspace, store, file, service_type='shapefile') -result = add_vector_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver', +result = add_vector_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer', workspace='cesium',store='natural_earth', file='/Users/krishnaglodha/Downloads/ne_10m_populated_places_simple/ne_10m_populated_places_simple.shp' ) print(result.json()) ''' Console @@ -183,7 +183,7 @@ def get_all_raster_workspaces(url, username, password,workspace): client = SyncGeoServerX(username, password,url) return client.get_raster_stores_in_workspaces(workspace) -result = get_all_raster_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver', +result = get_all_raster_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer', workspace='cesium') print(result.json()) @@ -205,7 +205,7 @@ def get_info_raster_workspaces(url, username, password,workspace,store): client = SyncGeoServerX(username, password,url) return client.get_raster_store(workspace,store) -result = get_info_raster_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver', +result = get_info_raster_workspaces(url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer', workspace='cesium',store='dsm' ) print(result.json()) @@ -215,7 +215,7 @@ print(result.json()) ''' ``` -## Get all Styles in geoserver +## Get all Styles in GeoServer ```Python hl_lines="8" # Import Class from Package @@ -227,7 +227,7 @@ def get_all_styles(url, username, password): client = SyncGeoServerX(username, password,url) return client.get_all_styles() -result = get_all_styles(url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver' ) +result = get_all_styles(url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer' ) print(result.json()) ''' Console @@ -236,7 +236,7 @@ print(result.json()) ''' ``` -## Get Single Style in geoserver +## Get Single Style in GeoServer ```Python hl_lines="8" # Import Class from Package @@ -248,7 +248,7 @@ def get_style_info(url, username, password,style): client = SyncGeoServerX(username, password,url) return client.get_style(style) -result = get_style_info(url='http://localhost:8080/geoserver/rest/',username='admin', password='geoserver',style='poi' ) +result = get_style_info(url='http://localhost:8080/geoserver/rest/',username='admin', password='GeoServer',style='poi' ) print(result.json()) ''' Console -------------start----------------- diff --git a/docs/pages/sync/index.md b/docs/pages/sync/index.md index 1158c4a..41e57fa 100644 --- a/docs/pages/sync/index.md +++ b/docs/pages/sync/index.md @@ -7,7 +7,7 @@ ## Setup Class instance -`SyncGeoServerX` Class has default username, password, url which points to default geoserver settings. +`SyncGeoServerX` Class has default username, password, url which points to default GeoServer settings. ```Python # Import class from package from geoserverx._sync.gsx import SyncGeoServerX diff --git a/docs/pages/sync/raster-store.md b/docs/pages/sync/raster-store.md index dfb0061..74ed476 100644 --- a/docs/pages/sync/raster-store.md +++ b/docs/pages/sync/raster-store.md @@ -1,10 +1,10 @@ # Raster Stores -`geoserverx` allows users to access all/one raster stores from geoserver +`geoserverx` allows users to access all/one raster stores from GeoServer ## Get all raster stores -This command fetches all Vector store available in given workspace from geoserver. +This command fetches all Vector store available in given workspace from GeoServer. ```py # Get all raster stores available in `cite` workspace @@ -14,7 +14,7 @@ client.get_raster_stores_in_workspaces('cite') ## Get single raster store -This command fetches all Information about raster store available in given workspace from geoserver. +This command fetches all Information about raster store available in given workspace from GeoServer. ```Python # Get all information about `image` raster stores available in `cite` workspace diff --git a/docs/pages/sync/style.md b/docs/pages/sync/style.md index 53d5e32..0de53fa 100644 --- a/docs/pages/sync/style.md +++ b/docs/pages/sync/style.md @@ -3,19 +3,19 @@ ## Get all Styles -This command fetches all Styles available in geoserver. +This command fetches all Styles available in GeoServer. ```Python -# Get all styles available in geoserver +# Get all styles available in GeoServer client.get_all_styles() ``` ## Get single Style -This command fetches information about particular Style from geoserver. +This command fetches information about particular Style from GeoServer. ```py -# Get information about `population` style from geoserver +# Get information about `population` style from GeoServer client.get_style('population') ``` diff --git a/docs/pages/sync/vector-store.md b/docs/pages/sync/vector-store.md index 4959553..19c150e 100644 --- a/docs/pages/sync/vector-store.md +++ b/docs/pages/sync/vector-store.md @@ -1,9 +1,9 @@ # Vector Stores -`geoserverx` allows users to access all/one vector stores from geoserver. As of now, `geoserverx` also supports new vector store creation for `shapefile` and `gpkg` data +`geoserverx` allows users to access all/one vector stores from GeoServer. As of now, `geoserverx` also supports new vector store creation for `shapefile` and `gpkg` data ## Get all Vector stores -This command fetches all Vector store available in given workspace from geoserver. +This command fetches all Vector store available in given workspace from GeoServer. ```Python # Get all vector stores available in `cite` workspace @@ -13,7 +13,7 @@ client.get_vector_stores_in_workspaces('cite') ## Get single Vector store -This command fetches all Information about Vector store available in given workspace from geoserver. +This command fetches all Information about Vector store available in given workspace from GeoServer. ```Python # Get all information about `shape` vector stores available in `cite` workspace @@ -53,3 +53,19 @@ client.create_pg_store( password="XXXXXXXX", database="test") ``` + +## Get all Vector layers +This command fetches all Vector layers available in given workspace from GeoServer. + +```Python +# Get all vector layers available in `cite` workspace +client.get_all_layers(workspace='cite') +``` + +## Get single Vector layer +This command fetches all Information about Vector layer available in given workspace from GeoServer. + +```Python +# Get all information about `roads` vector layers available in `cite` workspace +client.get_vector_layer(workspace='cite', store='shape', layer='roads') +``` diff --git a/docs/pages/sync/workspace.md b/docs/pages/sync/workspace.md index 1d572de..e2b6568 100644 --- a/docs/pages/sync/workspace.md +++ b/docs/pages/sync/workspace.md @@ -1,31 +1,69 @@ -# Workspaces +# Workspaces -`geoserverx` allows users to access all/one workspace from geoserver, along with ability to add new workspaces. +`geoserverx` allows users to access all/one workspace from GeoServer, along with ability to do CRUD operations on workspaces. + +!!! get "Get started" +To start using `geoserverx` in Sync mode, create a new instance of `SyncGeoServerX` Class, read more about it [here](https://geobeyond.github.io/geoserverx/pages/sync/) ## Get all workspaces -This command fetches all workspaces available in geoserver. No paramters are required to be passed. + +This command fetches all workspaces available in GeoServer. No paramters are required to be passed. ```Python -# Get all workspaces in geoserver +# Get all workspaces in GeoServer client.get_all_workspaces() ``` ## Get single workspace -This command fetches workspace with paramter as name of it from geoserver. + +This command fetches workspace with parameter as name of it from GeoServer. + ```Python # Get workspace with name `cite` client.get_workspace('cite') ``` ## Create workspace -This command allows user to create new workspace. -Creating new workspace requires following parameters -* Name `str` : To define Name of the workspace -* default `bool` : To define whether to keep workspace as default or not -* Isolated `bool` : To define whether to keep workspace Isolated or not - +This command allows user to create new workspace. + +| Parameter | Required | Default value | Data type | Description | +| --------- | ----------------------------- | ------------- | --------- | ----------------------------------------------------- | +| Name | :white_check_mark: | | `str` | To define Name of the workspace | +| default | :negative_squared_cross_mark: | `False` | `bool` | To define whether to keep workspace as default or not | +| isolated | :negative_squared_cross_mark: | `False` | `bool` | To define whether to keep workspace as default or not | + ```Python #Create new workspace with name `my_wrkspc` , make it Default and Isolated client.create_workspace(name='my_wrkspc',default=True,Isolated=True) ``` + +## Delete workspace + +This command allows user to delete workspace. + +| Parameter | Required | Default value | Data type | Description | +| --------- | ----------------------------- | ------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | +| workspace | :white_check_mark: | | `str` | Name of the workspace | +| recurse | :negative_squared_cross_mark: | `False` | `bool` | This parameter recursively deletes all layers referenced by the specified workspace, including data stores, coverage stores, feature types, and so on | + +```Python +#Delete workspace with name `my_wrkspc`. +client.delete_workspace(workspace='my_wrkspc',recurse=True) +``` + +## Update workspace + +This command allows user to update existing workspace. + +| Parameter | Required | Data type | Description | +| --------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ | +| name | :white_check_mark: | `str` | Name of the workspace to be updated | +| update | :white_check_mark: | [`UpdateWorkspaceInfo`](https://github.com/geobeyond/geoserverx/blob/b7757c9f0130864b06c40c2faa17afc841fc705f/src/geoserverx/models/workspace.py#L42) | To define body of the update request | + +```Python +#Updating workspace with name `my_wrkspc` , make is Isolated and rename it to `my_new_wrkspc` +from geoserverx.models.workspace import UpdateWorkspaceInfo + +client.update_workspace(name='my_wrkspc',update=UpdateWorkspaceInfo(name='my_new_wrkspc',isolated=True)) +``` diff --git a/mkdocs.yml b/mkdocs.yml index b462618..ef6b764 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,17 +1,23 @@ site_name: geoserverx site_description: "geoserverx is a modern python and CLI package for communicating with Geoserver." +site_url: https://geobeyond.github.io/geoserverx/ site_author: Geobeyond -copyright: "© 2023 Geobeyond" +copyright: "© 2024 Geobeyond" theme: name: material - # logo: assets/images/logo.png + icon: + logo: material/package-variant + favicon: material/package-variant palette: - primary: green + primary: white features: - content.code.copy - navigation.tabs - navigation.tabs.sticky repo_url: https://github.com/geobeyond/geoserverx +plugins: + - social + - search nav: - Home: index.md - Sync : @@ -43,6 +49,10 @@ markdown_extensions: - footnotes # notes bottom of page - attr_list # used to size images - md_in_html # used to size images + - tables + - pymdownx.emoji: + emoji_index: !!python/name:material.extensions.emoji.twemoji + emoji_generator: !!python/name:material.extensions.emoji.to_svg - pymdownx.tabbed: alternate_style: true @@ -54,4 +64,7 @@ extra_css: extra_javascript: - assets/javascripts/termynal.js - - assets/javascripts/custom.js \ No newline at end of file + - assets/javascripts/custom.js + +extra: + generator: false \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index 6a5bb40..68db8b7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -71,7 +71,7 @@ tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] name = "babel" version = "2.16.0" description = "Internationalization utilities" -category = "main" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -84,34 +84,34 @@ dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] [[package]] name = "black" -version = "24.8.0" +version = "24.10.0" description = "The uncompromising code formatter." category = "dev" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "black-24.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:09cdeb74d494ec023ded657f7092ba518e8cf78fa8386155e4a03fdcc44679e6"}, - {file = "black-24.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:81c6742da39f33b08e791da38410f32e27d632260e599df7245cccee2064afeb"}, - {file = "black-24.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:707a1ca89221bc8a1a64fb5e15ef39cd755633daa672a9db7498d1c19de66a42"}, - {file = "black-24.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d6417535d99c37cee4091a2f24eb2b6d5ec42b144d50f1f2e436d9fe1916fe1a"}, - {file = "black-24.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fb6e2c0b86bbd43dee042e48059c9ad7830abd5c94b0bc518c0eeec57c3eddc1"}, - {file = "black-24.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:837fd281f1908d0076844bc2b801ad2d369c78c45cf800cad7b61686051041af"}, - {file = "black-24.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62e8730977f0b77998029da7971fa896ceefa2c4c4933fcd593fa599ecbf97a4"}, - {file = "black-24.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:72901b4913cbac8972ad911dc4098d5753704d1f3c56e44ae8dce99eecb0e3af"}, - {file = "black-24.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7c046c1d1eeb7aea9335da62472481d3bbf3fd986e093cffd35f4385c94ae368"}, - {file = "black-24.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:649f6d84ccbae73ab767e206772cc2d7a393a001070a4c814a546afd0d423aed"}, - {file = "black-24.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b59b250fdba5f9a9cd9d0ece6e6d993d91ce877d121d161e4698af3eb9c1018"}, - {file = "black-24.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:6e55d30d44bed36593c3163b9bc63bf58b3b30e4611e4d88a0c3c239930ed5b2"}, - {file = "black-24.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:505289f17ceda596658ae81b61ebbe2d9b25aa78067035184ed0a9d855d18afd"}, - {file = "black-24.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b19c9ad992c7883ad84c9b22aaa73562a16b819c1d8db7a1a1a49fb7ec13c7d2"}, - {file = "black-24.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f13f7f386f86f8121d76599114bb8c17b69d962137fc70efe56137727c7047e"}, - {file = "black-24.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:f490dbd59680d809ca31efdae20e634f3fae27fba3ce0ba3208333b713bc3920"}, - {file = "black-24.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eab4dd44ce80dea27dc69db40dab62d4ca96112f87996bca68cd75639aeb2e4c"}, - {file = "black-24.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3c4285573d4897a7610054af5a890bde7c65cb466040c5f0c8b732812d7f0e5e"}, - {file = "black-24.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e84e33b37be070ba135176c123ae52a51f82306def9f7d063ee302ecab2cf47"}, - {file = "black-24.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:73bbf84ed136e45d451a260c6b73ed674652f90a2b3211d6a35e78054563a9bb"}, - {file = "black-24.8.0-py3-none-any.whl", hash = "sha256:972085c618ee94f402da1af548a4f218c754ea7e5dc70acb168bfaca4c2542ed"}, - {file = "black-24.8.0.tar.gz", hash = "sha256:2500945420b6784c38b9ee885af039f5e7471ef284ab03fa35ecdde4688cd83f"}, + {file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"}, + {file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"}, + {file = "black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f"}, + {file = "black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"}, + {file = "black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad"}, + {file = "black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50"}, + {file = "black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392"}, + {file = "black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175"}, + {file = "black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3"}, + {file = "black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65"}, + {file = "black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f"}, + {file = "black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8"}, + {file = "black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981"}, + {file = "black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b"}, + {file = "black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2"}, + {file = "black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b"}, + {file = "black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd"}, + {file = "black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f"}, + {file = "black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800"}, + {file = "black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7"}, + {file = "black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d"}, + {file = "black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875"}, ] [package.dependencies] @@ -125,10 +125,53 @@ typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} [package.extras] colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] +d = ["aiohttp (>=3.10)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] +[[package]] +name = "cairocffi" +version = "1.7.1" +description = "cffi-based cairo bindings for Python" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "cairocffi-1.7.1-py3-none-any.whl", hash = "sha256:9803a0e11f6c962f3b0ae2ec8ba6ae45e957a146a004697a1ac1bbf16b073b3f"}, + {file = "cairocffi-1.7.1.tar.gz", hash = "sha256:2e48ee864884ec4a3a34bfa8c9ab9999f688286eb714a15a43ec9d068c36557b"}, +] + +[package.dependencies] +cffi = ">=1.1.0" + +[package.extras] +doc = ["sphinx", "sphinx_rtd_theme"] +test = ["numpy", "pikepdf", "pytest", "ruff"] +xcb = ["xcffib (>=1.4.0)"] + +[[package]] +name = "cairosvg" +version = "2.7.1" +description = "A Simple SVG Converter based on Cairo" +category = "dev" +optional = false +python-versions = ">=3.5" +files = [ + {file = "CairoSVG-2.7.1-py3-none-any.whl", hash = "sha256:8a5222d4e6c3f86f1f7046b63246877a63b49923a1cd202184c3a634ef546b3b"}, + {file = "CairoSVG-2.7.1.tar.gz", hash = "sha256:432531d72347291b9a9ebfb6777026b607563fd8719c46ee742db0aef7271ba0"}, +] + +[package.dependencies] +cairocffi = "*" +cssselect2 = "*" +defusedxml = "*" +pillow = "*" +tinycss2 = "*" + +[package.extras] +doc = ["sphinx", "sphinx-rtd-theme"] +test = ["flake8", "isort", "pytest"] + [[package]] name = "certifi" version = "2024.8.30" @@ -223,102 +266,117 @@ pycparser = "*" [[package]] name = "charset-normalizer" -version = "3.3.2" +version = "3.4.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "main" +category = "dev" optional = false python-versions = ">=3.7.0" 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-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, - {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"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, + {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, + {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, ] [[package]] @@ -363,6 +421,38 @@ files = [ [package.extras] test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"] +[[package]] +name = "cssselect2" +version = "0.7.0" +description = "CSS selectors for Python ElementTree" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "cssselect2-0.7.0-py3-none-any.whl", hash = "sha256:fd23a65bfd444595913f02fc71f6b286c29261e354c41d722ca7a261a49b5969"}, + {file = "cssselect2-0.7.0.tar.gz", hash = "sha256:1ccd984dab89fc68955043aca4e1b03e0cf29cad9880f6e28e3ba7a74b14aa5a"}, +] + +[package.dependencies] +tinycss2 = "*" +webencodings = "*" + +[package.extras] +doc = ["sphinx", "sphinx_rtd_theme"] +test = ["flake8", "isort", "pytest"] + +[[package]] +name = "defusedxml" +version = "0.7.1" +description = "XML bomb protection for Python stdlib modules" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, + {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, +] + [[package]] name = "exceptiongroup" version = "1.2.2" @@ -382,7 +472,7 @@ test = ["pytest (>=6)"] name = "ghp-import" version = "2.1.0" description = "Copy your docs directly to the gh-pages branch." -category = "main" +category = "dev" optional = false python-versions = "*" files = [ @@ -456,35 +546,42 @@ socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "idna" -version = "3.8" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "idna-3.8-py3-none-any.whl", hash = "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac"}, - {file = "idna-3.8.tar.gz", hash = "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + [[package]] name = "importlib-metadata" -version = "8.4.0" +version = "8.5.0" description = "Read metadata from Python packages" -category = "main" +category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-8.4.0-py3-none-any.whl", hash = "sha256:66f342cc6ac9818fc6ff340576acd24d65ba0b3efabb2b4ac08b598965a4a2f1"}, - {file = "importlib_metadata-8.4.0.tar.gz", hash = "sha256:9a547d3bc3608b025f93d403fdd1aae741c24fbb8314df4b155675742ce303c5"}, + {file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"}, + {file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"}, ] [package.dependencies] -zipp = ">=0.5" +zipp = ">=3.20" [package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] perf = ["ipython"] -test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] +test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +type = ["pytest-mypy"] [[package]] name = "iniconfig" @@ -517,7 +614,7 @@ colors = ["colorama (>=0.4.6)"] name = "jinja2" version = "3.1.4" description = "A very fast and expressive template engine." -category = "main" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -535,7 +632,7 @@ i18n = ["Babel (>=2.7)"] name = "markdown" version = "3.7" description = "Python implementation of John Gruber's Markdown." -category = "main" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -552,79 +649,80 @@ testing = ["coverage", "pyyaml"] [[package]] name = "markupsafe" -version = "2.1.5" +version = "3.0.2" description = "Safely add untrusted strings to HTML/XML markup." -category = "main" +category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" 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"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, - {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, ] [[package]] name = "mergedeep" version = "1.3.4" description = "A deep merge function for 🐍." -category = "main" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -636,7 +734,7 @@ files = [ name = "mkdocs" version = "1.6.1" description = "Project documentation with Markdown." -category = "main" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -668,7 +766,7 @@ min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-imp name = "mkdocs-get-deps" version = "0.2.0" description = "MkDocs extension that lists all dependencies according to a mkdocs.yml file" -category = "main" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -684,14 +782,14 @@ pyyaml = ">=5.1" [[package]] name = "mkdocs-material" -version = "9.5.34" +version = "9.5.43" description = "Documentation that simply works" -category = "main" +category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "mkdocs_material-9.5.34-py3-none-any.whl", hash = "sha256:54caa8be708de2b75167fd4d3b9f3d949579294f49cb242515d4653dbee9227e"}, - {file = "mkdocs_material-9.5.34.tar.gz", hash = "sha256:1e60ddf716cfb5679dfd65900b8a25d277064ed82d9a53cd5190e3f894df7840"}, + {file = "mkdocs_material-9.5.43-py3-none-any.whl", hash = "sha256:4aae0664c456fd12837a3192e0225c17960ba8bf55d7f0a7daef7e4b0b914a34"}, + {file = "mkdocs_material-9.5.43.tar.gz", hash = "sha256:83be7ff30b65a1e4930dfa4ab911e75780a3afc9583d162692e434581cb46979"}, ] [package.dependencies] @@ -716,7 +814,7 @@ recommended = ["mkdocs-minify-plugin (>=0.7,<1.0)", "mkdocs-redirects (>=1.2,<2. name = "mkdocs-material-extensions" version = "1.3.1" description = "Extension pack for Python Markdown and MkDocs Material." -category = "main" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -726,45 +824,56 @@ files = [ [[package]] name = "mypy" -version = "0.960" +version = "1.13.0" description = "Optional static typing for Python" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "mypy-0.960-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3a3e525cd76c2c4f90f1449fd034ba21fcca68050ff7c8397bb7dd25dd8b8248"}, - {file = "mypy-0.960-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7a76dc4f91e92db119b1be293892df8379b08fd31795bb44e0ff84256d34c251"}, - {file = "mypy-0.960-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ffdad80a92c100d1b0fe3d3cf1a4724136029a29afe8566404c0146747114382"}, - {file = "mypy-0.960-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7d390248ec07fa344b9f365e6ed9d205bd0205e485c555bed37c4235c868e9d5"}, - {file = "mypy-0.960-cp310-cp310-win_amd64.whl", hash = "sha256:925aa84369a07846b7f3b8556ccade1f371aa554f2bd4fb31cb97a24b73b036e"}, - {file = "mypy-0.960-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:239d6b2242d6c7f5822163ee082ef7a28ee02e7ac86c35593ef923796826a385"}, - {file = "mypy-0.960-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f1ba54d440d4feee49d8768ea952137316d454b15301c44403db3f2cb51af024"}, - {file = "mypy-0.960-cp36-cp36m-win_amd64.whl", hash = "sha256:cb7752b24528c118a7403ee955b6a578bfcf5879d5ee91790667c8ea511d2085"}, - {file = "mypy-0.960-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:826a2917c275e2ee05b7c7b736c1e6549a35b7ea5a198ca457f8c2ebea2cbecf"}, - {file = "mypy-0.960-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3eabcbd2525f295da322dff8175258f3fc4c3eb53f6d1929644ef4d99b92e72d"}, - {file = "mypy-0.960-cp37-cp37m-win_amd64.whl", hash = "sha256:f47322796c412271f5aea48381a528a613f33e0a115452d03ae35d673e6064f8"}, - {file = "mypy-0.960-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2c7f8bb9619290836a4e167e2ef1f2cf14d70e0bc36c04441e41487456561409"}, - {file = "mypy-0.960-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fbfb873cf2b8d8c3c513367febde932e061a5f73f762896826ba06391d932b2a"}, - {file = "mypy-0.960-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cc537885891382e08129d9862553b3d00d4be3eb15b8cae9e2466452f52b0117"}, - {file = "mypy-0.960-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:481f98c6b24383188c928f33dd2f0776690807e12e9989dd0419edd5c74aa53b"}, - {file = "mypy-0.960-cp38-cp38-win_amd64.whl", hash = "sha256:29dc94d9215c3eb80ac3c2ad29d0c22628accfb060348fd23d73abe3ace6c10d"}, - {file = "mypy-0.960-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:33d53a232bb79057f33332dbbb6393e68acbcb776d2f571ba4b1d50a2c8ba873"}, - {file = "mypy-0.960-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8d645e9e7f7a5da3ec3bbcc314ebb9bb22c7ce39e70367830eb3c08d0140b9ce"}, - {file = "mypy-0.960-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:85cf2b14d32b61db24ade8ac9ae7691bdfc572a403e3cb8537da936e74713275"}, - {file = "mypy-0.960-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a85a20b43fa69efc0b955eba1db435e2ffecb1ca695fe359768e0503b91ea89f"}, - {file = "mypy-0.960-cp39-cp39-win_amd64.whl", hash = "sha256:0ebfb3f414204b98c06791af37a3a96772203da60636e2897408517fcfeee7a8"}, - {file = "mypy-0.960-py3-none-any.whl", hash = "sha256:bfd4f6536bd384c27c392a8b8f790fd0ed5c0cf2f63fc2fed7bce56751d53026"}, - {file = "mypy-0.960.tar.gz", hash = "sha256:d4fccf04c1acf750babd74252e0f2db6bd2ac3aa8fe960797d9f3ef41cf2bfd4"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80"}, + {file = "mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7"}, + {file = "mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f"}, + {file = "mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d"}, + {file = "mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b"}, + {file = "mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73"}, + {file = "mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e"}, + {file = "mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2"}, + {file = "mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0"}, + {file = "mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62"}, + {file = "mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8"}, + {file = "mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7"}, + {file = "mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:100fac22ce82925f676a734af0db922ecfea991e1d7ec0ceb1e115ebe501301a"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bcb0bb7f42a978bb323a7c88f1081d1b5dee77ca86f4100735a6f541299d8fb"}, + {file = "mypy-1.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bde31fc887c213e223bbfc34328070996061b0833b0a4cfec53745ed61f3519b"}, + {file = "mypy-1.13.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07de989f89786f62b937851295ed62e51774722e5444a27cecca993fc3f9cd74"}, + {file = "mypy-1.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:4bde84334fbe19bad704b3f5b78c4abd35ff1026f8ba72b29de70dda0916beb6"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732"}, + {file = "mypy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc"}, + {file = "mypy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d"}, + {file = "mypy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24"}, + {file = "mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a"}, + {file = "mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e"}, ] [package.dependencies] -mypy-extensions = ">=0.4.3" +mypy-extensions = ">=1.0.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = ">=3.10" +typing-extensions = ">=4.6.0" [package.extras] dmypy = ["psutil (>=4.0)"] -python2 = ["typed-ast (>=1.4.0,<2)"] +faster-cache = ["orjson"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] reports = ["lxml"] [[package]] @@ -798,7 +907,7 @@ attrs = ">=19.2.0" name = "packaging" version = "24.1" description = "Core utilities for Python packages" -category = "main" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -810,7 +919,7 @@ files = [ name = "paginate" version = "0.5.7" description = "Divides large result sets into pages for easier browsing" -category = "main" +category = "dev" optional = false python-versions = "*" files = [ @@ -826,7 +935,7 @@ lint = ["black"] name = "pathspec" version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." -category = "main" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -834,22 +943,115 @@ files = [ {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, ] +[[package]] +name = "pillow" +version = "11.0.0" +description = "Python Imaging Library (Fork)" +category = "dev" +optional = false +python-versions = ">=3.9" +files = [ + {file = "pillow-11.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:6619654954dc4936fcff82db8eb6401d3159ec6be81e33c6000dfd76ae189947"}, + {file = "pillow-11.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b3c5ac4bed7519088103d9450a1107f76308ecf91d6dabc8a33a2fcfb18d0fba"}, + {file = "pillow-11.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a65149d8ada1055029fcb665452b2814fe7d7082fcb0c5bed6db851cb69b2086"}, + {file = "pillow-11.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88a58d8ac0cc0e7f3a014509f0455248a76629ca9b604eca7dc5927cc593c5e9"}, + {file = "pillow-11.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:c26845094b1af3c91852745ae78e3ea47abf3dbcd1cf962f16b9a5fbe3ee8488"}, + {file = "pillow-11.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:1a61b54f87ab5786b8479f81c4b11f4d61702830354520837f8cc791ebba0f5f"}, + {file = "pillow-11.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:674629ff60030d144b7bca2b8330225a9b11c482ed408813924619c6f302fdbb"}, + {file = "pillow-11.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:598b4e238f13276e0008299bd2482003f48158e2b11826862b1eb2ad7c768b97"}, + {file = "pillow-11.0.0-cp310-cp310-win32.whl", hash = "sha256:9a0f748eaa434a41fccf8e1ee7a3eed68af1b690e75328fd7a60af123c193b50"}, + {file = "pillow-11.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:a5629742881bcbc1f42e840af185fd4d83a5edeb96475a575f4da50d6ede337c"}, + {file = "pillow-11.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:ee217c198f2e41f184f3869f3e485557296d505b5195c513b2bfe0062dc537f1"}, + {file = "pillow-11.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1c1d72714f429a521d8d2d018badc42414c3077eb187a59579f28e4270b4b0fc"}, + {file = "pillow-11.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:499c3a1b0d6fc8213519e193796eb1a86a1be4b1877d678b30f83fd979811d1a"}, + {file = "pillow-11.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8b2351c85d855293a299038e1f89db92a2f35e8d2f783489c6f0b2b5f3fe8a3"}, + {file = "pillow-11.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f4dba50cfa56f910241eb7f883c20f1e7b1d8f7d91c750cd0b318bad443f4d5"}, + {file = "pillow-11.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5ddbfd761ee00c12ee1be86c9c0683ecf5bb14c9772ddbd782085779a63dd55b"}, + {file = "pillow-11.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:45c566eb10b8967d71bf1ab8e4a525e5a93519e29ea071459ce517f6b903d7fa"}, + {file = "pillow-11.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b4fd7bd29610a83a8c9b564d457cf5bd92b4e11e79a4ee4716a63c959699b306"}, + {file = "pillow-11.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cb929ca942d0ec4fac404cbf520ee6cac37bf35be479b970c4ffadf2b6a1cad9"}, + {file = "pillow-11.0.0-cp311-cp311-win32.whl", hash = "sha256:006bcdd307cc47ba43e924099a038cbf9591062e6c50e570819743f5607404f5"}, + {file = "pillow-11.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:52a2d8323a465f84faaba5236567d212c3668f2ab53e1c74c15583cf507a0291"}, + {file = "pillow-11.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:16095692a253047fe3ec028e951fa4221a1f3ed3d80c397e83541a3037ff67c9"}, + {file = "pillow-11.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2c0a187a92a1cb5ef2c8ed5412dd8d4334272617f532d4ad4de31e0495bd923"}, + {file = "pillow-11.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:084a07ef0821cfe4858fe86652fffac8e187b6ae677e9906e192aafcc1b69903"}, + {file = "pillow-11.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8069c5179902dcdce0be9bfc8235347fdbac249d23bd90514b7a47a72d9fecf4"}, + {file = "pillow-11.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f02541ef64077f22bf4924f225c0fd1248c168f86e4b7abdedd87d6ebaceab0f"}, + {file = "pillow-11.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:fcb4621042ac4b7865c179bb972ed0da0218a076dc1820ffc48b1d74c1e37fe9"}, + {file = "pillow-11.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:00177a63030d612148e659b55ba99527803288cea7c75fb05766ab7981a8c1b7"}, + {file = "pillow-11.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8853a3bf12afddfdf15f57c4b02d7ded92c7a75a5d7331d19f4f9572a89c17e6"}, + {file = "pillow-11.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3107c66e43bda25359d5ef446f59c497de2b5ed4c7fdba0894f8d6cf3822dafc"}, + {file = "pillow-11.0.0-cp312-cp312-win32.whl", hash = "sha256:86510e3f5eca0ab87429dd77fafc04693195eec7fd6a137c389c3eeb4cfb77c6"}, + {file = "pillow-11.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:8ec4a89295cd6cd4d1058a5e6aec6bf51e0eaaf9714774e1bfac7cfc9051db47"}, + {file = "pillow-11.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:27a7860107500d813fcd203b4ea19b04babe79448268403172782754870dac25"}, + {file = "pillow-11.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bcd1fb5bb7b07f64c15618c89efcc2cfa3e95f0e3bcdbaf4642509de1942a699"}, + {file = "pillow-11.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e038b0745997c7dcaae350d35859c9715c71e92ffb7e0f4a8e8a16732150f38"}, + {file = "pillow-11.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ae08bd8ffc41aebf578c2af2f9d8749d91f448b3bfd41d7d9ff573d74f2a6b2"}, + {file = "pillow-11.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d69bfd8ec3219ae71bcde1f942b728903cad25fafe3100ba2258b973bd2bc1b2"}, + {file = "pillow-11.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:61b887f9ddba63ddf62fd02a3ba7add935d053b6dd7d58998c630e6dbade8527"}, + {file = "pillow-11.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:c6a660307ca9d4867caa8d9ca2c2658ab685de83792d1876274991adec7b93fa"}, + {file = "pillow-11.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:73e3a0200cdda995c7e43dd47436c1548f87a30bb27fb871f352a22ab8dcf45f"}, + {file = "pillow-11.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fba162b8872d30fea8c52b258a542c5dfd7b235fb5cb352240c8d63b414013eb"}, + {file = "pillow-11.0.0-cp313-cp313-win32.whl", hash = "sha256:f1b82c27e89fffc6da125d5eb0ca6e68017faf5efc078128cfaa42cf5cb38798"}, + {file = "pillow-11.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ba470552b48e5835f1d23ecb936bb7f71d206f9dfeee64245f30c3270b994de"}, + {file = "pillow-11.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:846e193e103b41e984ac921b335df59195356ce3f71dcfd155aa79c603873b84"}, + {file = "pillow-11.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4ad70c4214f67d7466bea6a08061eba35c01b1b89eaa098040a35272a8efb22b"}, + {file = "pillow-11.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6ec0d5af64f2e3d64a165f490d96368bb5dea8b8f9ad04487f9ab60dc4bb6003"}, + {file = "pillow-11.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c809a70e43c7977c4a42aefd62f0131823ebf7dd73556fa5d5950f5b354087e2"}, + {file = "pillow-11.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:4b60c9520f7207aaf2e1d94de026682fc227806c6e1f55bba7606d1c94dd623a"}, + {file = "pillow-11.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1e2688958a840c822279fda0086fec1fdab2f95bf2b717b66871c4ad9859d7e8"}, + {file = "pillow-11.0.0-cp313-cp313t-win32.whl", hash = "sha256:607bbe123c74e272e381a8d1957083a9463401f7bd01287f50521ecb05a313f8"}, + {file = "pillow-11.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c39ed17edea3bc69c743a8dd3e9853b7509625c2462532e62baa0732163a904"}, + {file = "pillow-11.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:75acbbeb05b86bc53cbe7b7e6fe00fbcf82ad7c684b3ad82e3d711da9ba287d3"}, + {file = "pillow-11.0.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2e46773dc9f35a1dd28bd6981332fd7f27bec001a918a72a79b4133cf5291dba"}, + {file = "pillow-11.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2679d2258b7f1192b378e2893a8a0a0ca472234d4c2c0e6bdd3380e8dfa21b6a"}, + {file = "pillow-11.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eda2616eb2313cbb3eebbe51f19362eb434b18e3bb599466a1ffa76a033fb916"}, + {file = "pillow-11.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ec184af98a121fb2da42642dea8a29ec80fc3efbaefb86d8fdd2606619045d"}, + {file = "pillow-11.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:8594f42df584e5b4bb9281799698403f7af489fba84c34d53d1c4bfb71b7c4e7"}, + {file = "pillow-11.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:c12b5ae868897c7338519c03049a806af85b9b8c237b7d675b8c5e089e4a618e"}, + {file = "pillow-11.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:70fbbdacd1d271b77b7721fe3cdd2d537bbbd75d29e6300c672ec6bb38d9672f"}, + {file = "pillow-11.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5178952973e588b3f1360868847334e9e3bf49d19e169bbbdfaf8398002419ae"}, + {file = "pillow-11.0.0-cp39-cp39-win32.whl", hash = "sha256:8c676b587da5673d3c75bd67dd2a8cdfeb282ca38a30f37950511766b26858c4"}, + {file = "pillow-11.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:94f3e1780abb45062287b4614a5bc0874519c86a777d4a7ad34978e86428b8dd"}, + {file = "pillow-11.0.0-cp39-cp39-win_arm64.whl", hash = "sha256:290f2cc809f9da7d6d622550bbf4c1e57518212da51b6a30fe8e0a270a5b78bd"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1187739620f2b365de756ce086fdb3604573337cc28a0d3ac4a01ab6b2d2a6d2"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fbbcb7b57dc9c794843e3d1258c0fbf0f48656d46ffe9e09b63bbd6e8cd5d0a2"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d203af30149ae339ad1b4f710d9844ed8796e97fda23ffbc4cc472968a47d0b"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21a0d3b115009ebb8ac3d2ebec5c2982cc693da935f4ab7bb5c8ebe2f47d36f2"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:73853108f56df97baf2bb8b522f3578221e56f646ba345a372c78326710d3830"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e58876c91f97b0952eb766123bfef372792ab3f4e3e1f1a2267834c2ab131734"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:224aaa38177597bb179f3ec87eeefcce8e4f85e608025e9cfac60de237ba6316"}, + {file = "pillow-11.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5bd2d3bdb846d757055910f0a59792d33b555800813c3b39ada1829c372ccb06"}, + {file = "pillow-11.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:375b8dd15a1f5d2feafff536d47e22f69625c1aa92f12b339ec0b2ca40263273"}, + {file = "pillow-11.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:daffdf51ee5db69a82dd127eabecce20729e21f7a3680cf7cbb23f0829189790"}, + {file = "pillow-11.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7326a1787e3c7b0429659e0a944725e1b03eeaa10edd945a86dead1913383944"}, + {file = "pillow-11.0.0.tar.gz", hash = "sha256:72bacbaf24ac003fea9bff9837d1eedb6088758d41e100c1552930151f677739"}, +] + +[package.extras] +docs = ["furo", "olefile", "sphinx (>=8.1)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] +fpx = ["olefile"] +mic = ["olefile"] +tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] +typing = ["typing-extensions"] +xmp = ["defusedxml"] + [[package]] name = "platformdirs" -version = "4.2.2" +version = "4.3.6" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." -category = "main" +category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, - {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, ] [package.extras] -docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] -type = ["mypy (>=1.8)"] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] [[package]] name = "pluggy" @@ -1021,14 +1223,14 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pymdown-extensions" -version = "10.9" +version = "10.12" description = "Extension pack for Python Markdown." -category = "main" +category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "pymdown_extensions-10.9-py3-none-any.whl", hash = "sha256:d323f7e90d83c86113ee78f3fe62fc9dee5f56b54d912660703ea1816fed5626"}, - {file = "pymdown_extensions-10.9.tar.gz", hash = "sha256:6ff740bcd99ec4172a938970d42b96128bdc9d4b9bcad72494f29921dc69b753"}, + {file = "pymdown_extensions-10.12-py3-none-any.whl", hash = "sha256:49f81412242d3527b8b4967b990df395c89563043bc51a3d2d7d500e52123b77"}, + {file = "pymdown_extensions-10.12.tar.gz", hash = "sha256:b0ee1e0b2bef1071a47891ab17003bfe5bf824a398e13f49f8ed653b699369a7"}, ] [package.dependencies] @@ -1084,7 +1286,7 @@ testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy name = "python-dateutil" version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" -category = "main" +category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ @@ -1099,7 +1301,7 @@ six = ">=1.5" name = "pyyaml" version = "6.0.2" description = "YAML parser and emitter for Python" -category = "main" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1162,7 +1364,7 @@ files = [ name = "pyyaml-env-tag" version = "0.1" description = "A custom YAML tag for referencing environment variables in YAML files. " -category = "main" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1175,98 +1377,113 @@ pyyaml = "*" [[package]] name = "regex" -version = "2024.7.24" +version = "2024.9.11" description = "Alternative regular expression module, to replace re." -category = "main" +category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "regex-2024.7.24-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b0d3f567fafa0633aee87f08b9276c7062da9616931382993c03808bb68ce"}, - {file = "regex-2024.7.24-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3426de3b91d1bc73249042742f45c2148803c111d1175b283270177fdf669024"}, - {file = "regex-2024.7.24-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f273674b445bcb6e4409bf8d1be67bc4b58e8b46fd0d560055d515b8830063cd"}, - {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23acc72f0f4e1a9e6e9843d6328177ae3074b4182167e34119ec7233dfeccf53"}, - {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65fd3d2e228cae024c411c5ccdffae4c315271eee4a8b839291f84f796b34eca"}, - {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c414cbda77dbf13c3bc88b073a1a9f375c7b0cb5e115e15d4b73ec3a2fbc6f59"}, - {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf7a89eef64b5455835f5ed30254ec19bf41f7541cd94f266ab7cbd463f00c41"}, - {file = "regex-2024.7.24-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19c65b00d42804e3fbea9708f0937d157e53429a39b7c61253ff15670ff62cb5"}, - {file = "regex-2024.7.24-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7a5486ca56c8869070a966321d5ab416ff0f83f30e0e2da1ab48815c8d165d46"}, - {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6f51f9556785e5a203713f5efd9c085b4a45aecd2a42573e2b5041881b588d1f"}, - {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a4997716674d36a82eab3e86f8fa77080a5d8d96a389a61ea1d0e3a94a582cf7"}, - {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c0abb5e4e8ce71a61d9446040c1e86d4e6d23f9097275c5bd49ed978755ff0fe"}, - {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:18300a1d78cf1290fa583cd8b7cde26ecb73e9f5916690cf9d42de569c89b1ce"}, - {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:416c0e4f56308f34cdb18c3f59849479dde5b19febdcd6e6fa4d04b6c31c9faa"}, - {file = "regex-2024.7.24-cp310-cp310-win32.whl", hash = "sha256:fb168b5924bef397b5ba13aabd8cf5df7d3d93f10218d7b925e360d436863f66"}, - {file = "regex-2024.7.24-cp310-cp310-win_amd64.whl", hash = "sha256:6b9fc7e9cc983e75e2518496ba1afc524227c163e43d706688a6bb9eca41617e"}, - {file = "regex-2024.7.24-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:382281306e3adaaa7b8b9ebbb3ffb43358a7bbf585fa93821300a418bb975281"}, - {file = "regex-2024.7.24-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4fdd1384619f406ad9037fe6b6eaa3de2749e2e12084abc80169e8e075377d3b"}, - {file = "regex-2024.7.24-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3d974d24edb231446f708c455fd08f94c41c1ff4f04bcf06e5f36df5ef50b95a"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2ec4419a3fe6cf8a4795752596dfe0adb4aea40d3683a132bae9c30b81e8d73"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb563dd3aea54c797adf513eeec819c4213d7dbfc311874eb4fd28d10f2ff0f2"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:45104baae8b9f67569f0f1dca5e1f1ed77a54ae1cd8b0b07aba89272710db61e"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:994448ee01864501912abf2bad9203bffc34158e80fe8bfb5b031f4f8e16da51"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fac296f99283ac232d8125be932c5cd7644084a30748fda013028c815ba3364"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7e37e809b9303ec3a179085415cb5f418ecf65ec98cdfe34f6a078b46ef823ee"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:01b689e887f612610c869421241e075c02f2e3d1ae93a037cb14f88ab6a8934c"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f6442f0f0ff81775eaa5b05af8a0ffa1dda36e9cf6ec1e0d3d245e8564b684ce"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:871e3ab2838fbcb4e0865a6e01233975df3a15e6fce93b6f99d75cacbd9862d1"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c918b7a1e26b4ab40409820ddccc5d49871a82329640f5005f73572d5eaa9b5e"}, - {file = "regex-2024.7.24-cp311-cp311-win32.whl", hash = "sha256:2dfbb8baf8ba2c2b9aa2807f44ed272f0913eeeba002478c4577b8d29cde215c"}, - {file = "regex-2024.7.24-cp311-cp311-win_amd64.whl", hash = "sha256:538d30cd96ed7d1416d3956f94d54e426a8daf7c14527f6e0d6d425fcb4cca52"}, - {file = "regex-2024.7.24-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:fe4ebef608553aff8deb845c7f4f1d0740ff76fa672c011cc0bacb2a00fbde86"}, - {file = "regex-2024.7.24-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:74007a5b25b7a678459f06559504f1eec2f0f17bca218c9d56f6a0a12bfffdad"}, - {file = "regex-2024.7.24-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7df9ea48641da022c2a3c9c641650cd09f0cd15e8908bf931ad538f5ca7919c9"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a1141a1dcc32904c47f6846b040275c6e5de0bf73f17d7a409035d55b76f289"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80c811cfcb5c331237d9bad3bea2c391114588cf4131707e84d9493064d267f9"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7214477bf9bd195894cf24005b1e7b496f46833337b5dedb7b2a6e33f66d962c"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d55588cba7553f0b6ec33130bc3e114b355570b45785cebdc9daed8c637dd440"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:558a57cfc32adcf19d3f791f62b5ff564922942e389e3cfdb538a23d65a6b610"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a512eed9dfd4117110b1881ba9a59b31433caed0c4101b361f768e7bcbaf93c5"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:86b17ba823ea76256b1885652e3a141a99a5c4422f4a869189db328321b73799"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5eefee9bfe23f6df09ffb6dfb23809f4d74a78acef004aa904dc7c88b9944b05"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:731fcd76bbdbf225e2eb85b7c38da9633ad3073822f5ab32379381e8c3c12e94"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eaef80eac3b4cfbdd6de53c6e108b4c534c21ae055d1dbea2de6b3b8ff3def38"}, - {file = "regex-2024.7.24-cp312-cp312-win32.whl", hash = "sha256:185e029368d6f89f36e526764cf12bf8d6f0e3a2a7737da625a76f594bdfcbfc"}, - {file = "regex-2024.7.24-cp312-cp312-win_amd64.whl", hash = "sha256:2f1baff13cc2521bea83ab2528e7a80cbe0ebb2c6f0bfad15be7da3aed443908"}, - {file = "regex-2024.7.24-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:66b4c0731a5c81921e938dcf1a88e978264e26e6ac4ec96a4d21ae0354581ae0"}, - {file = "regex-2024.7.24-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:88ecc3afd7e776967fa16c80f974cb79399ee8dc6c96423321d6f7d4b881c92b"}, - {file = "regex-2024.7.24-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:64bd50cf16bcc54b274e20235bf8edbb64184a30e1e53873ff8d444e7ac656b2"}, - {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb462f0e346fcf41a901a126b50f8781e9a474d3927930f3490f38a6e73b6950"}, - {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a82465ebbc9b1c5c50738536fdfa7cab639a261a99b469c9d4c7dcbb2b3f1e57"}, - {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:68a8f8c046c6466ac61a36b65bb2395c74451df2ffb8458492ef49900efed293"}, - {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac8e84fff5d27420f3c1e879ce9929108e873667ec87e0c8eeb413a5311adfe"}, - {file = "regex-2024.7.24-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba2537ef2163db9e6ccdbeb6f6424282ae4dea43177402152c67ef869cf3978b"}, - {file = "regex-2024.7.24-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:43affe33137fcd679bdae93fb25924979517e011f9dea99163f80b82eadc7e53"}, - {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:c9bb87fdf2ab2370f21e4d5636e5317775e5d51ff32ebff2cf389f71b9b13750"}, - {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:945352286a541406f99b2655c973852da7911b3f4264e010218bbc1cc73168f2"}, - {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:8bc593dcce679206b60a538c302d03c29b18e3d862609317cb560e18b66d10cf"}, - {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3f3b6ca8eae6d6c75a6cff525c8530c60e909a71a15e1b731723233331de4169"}, - {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c51edc3541e11fbe83f0c4d9412ef6c79f664a3745fab261457e84465ec9d5a8"}, - {file = "regex-2024.7.24-cp38-cp38-win32.whl", hash = "sha256:d0a07763776188b4db4c9c7fb1b8c494049f84659bb387b71c73bbc07f189e96"}, - {file = "regex-2024.7.24-cp38-cp38-win_amd64.whl", hash = "sha256:8fd5afd101dcf86a270d254364e0e8dddedebe6bd1ab9d5f732f274fa00499a5"}, - {file = "regex-2024.7.24-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0ffe3f9d430cd37d8fa5632ff6fb36d5b24818c5c986893063b4e5bdb84cdf24"}, - {file = "regex-2024.7.24-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:25419b70ba00a16abc90ee5fce061228206173231f004437730b67ac77323f0d"}, - {file = "regex-2024.7.24-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:33e2614a7ce627f0cdf2ad104797d1f68342d967de3695678c0cb84f530709f8"}, - {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d33a0021893ede5969876052796165bab6006559ab845fd7b515a30abdd990dc"}, - {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04ce29e2c5fedf296b1a1b0acc1724ba93a36fb14031f3abfb7abda2806c1535"}, - {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b16582783f44fbca6fcf46f61347340c787d7530d88b4d590a397a47583f31dd"}, - {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:836d3cc225b3e8a943d0b02633fb2f28a66e281290302a79df0e1eaa984ff7c1"}, - {file = "regex-2024.7.24-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:438d9f0f4bc64e8dea78274caa5af971ceff0f8771e1a2333620969936ba10be"}, - {file = "regex-2024.7.24-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:973335b1624859cb0e52f96062a28aa18f3a5fc77a96e4a3d6d76e29811a0e6e"}, - {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c5e69fd3eb0b409432b537fe3c6f44ac089c458ab6b78dcec14478422879ec5f"}, - {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fbf8c2f00904eaf63ff37718eb13acf8e178cb940520e47b2f05027f5bb34ce3"}, - {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ae2757ace61bc4061b69af19e4689fa4416e1a04840f33b441034202b5cd02d4"}, - {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:44fc61b99035fd9b3b9453f1713234e5a7c92a04f3577252b45feefe1b327759"}, - {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:84c312cdf839e8b579f504afcd7b65f35d60b6285d892b19adea16355e8343c9"}, - {file = "regex-2024.7.24-cp39-cp39-win32.whl", hash = "sha256:ca5b2028c2f7af4e13fb9fc29b28d0ce767c38c7facdf64f6c2cd040413055f1"}, - {file = "regex-2024.7.24-cp39-cp39-win_amd64.whl", hash = "sha256:7c479f5ae937ec9985ecaf42e2e10631551d909f203e31308c12d703922742f9"}, - {file = "regex-2024.7.24.tar.gz", hash = "sha256:9cfd009eed1a46b27c14039ad5bbc5e71b6367c5b2e6d5f5da0ea91600817506"}, + {file = "regex-2024.9.11-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1494fa8725c285a81d01dc8c06b55287a1ee5e0e382d8413adc0a9197aac6408"}, + {file = "regex-2024.9.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0e12c481ad92d129c78f13a2a3662317e46ee7ef96c94fd332e1c29131875b7d"}, + {file = "regex-2024.9.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:16e13a7929791ac1216afde26f712802e3df7bf0360b32e4914dca3ab8baeea5"}, + {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46989629904bad940bbec2106528140a218b4a36bb3042d8406980be1941429c"}, + {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a906ed5e47a0ce5f04b2c981af1c9acf9e8696066900bf03b9d7879a6f679fc8"}, + {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9a091b0550b3b0207784a7d6d0f1a00d1d1c8a11699c1a4d93db3fbefc3ad35"}, + {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ddcd9a179c0a6fa8add279a4444015acddcd7f232a49071ae57fa6e278f1f71"}, + {file = "regex-2024.9.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6b41e1adc61fa347662b09398e31ad446afadff932a24807d3ceb955ed865cc8"}, + {file = "regex-2024.9.11-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ced479f601cd2f8ca1fd7b23925a7e0ad512a56d6e9476f79b8f381d9d37090a"}, + {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:635a1d96665f84b292e401c3d62775851aedc31d4f8784117b3c68c4fcd4118d"}, + {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c0256beda696edcf7d97ef16b2a33a8e5a875affd6fa6567b54f7c577b30a137"}, + {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:3ce4f1185db3fbde8ed8aa223fc9620f276c58de8b0d4f8cc86fd1360829edb6"}, + {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:09d77559e80dcc9d24570da3745ab859a9cf91953062e4ab126ba9d5993688ca"}, + {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a22ccefd4db3f12b526eccb129390942fe874a3a9fdbdd24cf55773a1faab1a"}, + {file = "regex-2024.9.11-cp310-cp310-win32.whl", hash = "sha256:f745ec09bc1b0bd15cfc73df6fa4f726dcc26bb16c23a03f9e3367d357eeedd0"}, + {file = "regex-2024.9.11-cp310-cp310-win_amd64.whl", hash = "sha256:01c2acb51f8a7d6494c8c5eafe3d8e06d76563d8a8a4643b37e9b2dd8a2ff623"}, + {file = "regex-2024.9.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2cce2449e5927a0bf084d346da6cd5eb016b2beca10d0013ab50e3c226ffc0df"}, + {file = "regex-2024.9.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b37fa423beefa44919e009745ccbf353d8c981516e807995b2bd11c2c77d268"}, + {file = "regex-2024.9.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:64ce2799bd75039b480cc0360907c4fb2f50022f030bf9e7a8705b636e408fad"}, + {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4cc92bb6db56ab0c1cbd17294e14f5e9224f0cc6521167ef388332604e92679"}, + {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d05ac6fa06959c4172eccd99a222e1fbf17b5670c4d596cb1e5cde99600674c4"}, + {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:040562757795eeea356394a7fb13076ad4f99d3c62ab0f8bdfb21f99a1f85664"}, + {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6113c008a7780792efc80f9dfe10ba0cd043cbf8dc9a76ef757850f51b4edc50"}, + {file = "regex-2024.9.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e5fb5f77c8745a60105403a774fe2c1759b71d3e7b4ca237a5e67ad066c7199"}, + {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:54d9ff35d4515debf14bc27f1e3b38bfc453eff3220f5bce159642fa762fe5d4"}, + {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:df5cbb1fbc74a8305b6065d4ade43b993be03dbe0f8b30032cced0d7740994bd"}, + {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7fb89ee5d106e4a7a51bce305ac4efb981536301895f7bdcf93ec92ae0d91c7f"}, + {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a738b937d512b30bf75995c0159c0ddf9eec0775c9d72ac0202076c72f24aa96"}, + {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e28f9faeb14b6f23ac55bfbbfd3643f5c7c18ede093977f1df249f73fd22c7b1"}, + {file = "regex-2024.9.11-cp311-cp311-win32.whl", hash = "sha256:18e707ce6c92d7282dfce370cd205098384b8ee21544e7cb29b8aab955b66fa9"}, + {file = "regex-2024.9.11-cp311-cp311-win_amd64.whl", hash = "sha256:313ea15e5ff2a8cbbad96ccef6be638393041b0a7863183c2d31e0c6116688cf"}, + {file = "regex-2024.9.11-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b0d0a6c64fcc4ef9c69bd5b3b3626cc3776520a1637d8abaa62b9edc147a58f7"}, + {file = "regex-2024.9.11-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:49b0e06786ea663f933f3710a51e9385ce0cba0ea56b67107fd841a55d56a231"}, + {file = "regex-2024.9.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5b513b6997a0b2f10e4fd3a1313568e373926e8c252bd76c960f96fd039cd28d"}, + {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee439691d8c23e76f9802c42a95cfeebf9d47cf4ffd06f18489122dbb0a7ad64"}, + {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8f877c89719d759e52783f7fe6e1c67121076b87b40542966c02de5503ace42"}, + {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23b30c62d0f16827f2ae9f2bb87619bc4fba2044911e2e6c2eb1af0161cdb766"}, + {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85ab7824093d8f10d44330fe1e6493f756f252d145323dd17ab6b48733ff6c0a"}, + {file = "regex-2024.9.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8dee5b4810a89447151999428fe096977346cf2f29f4d5e29609d2e19e0199c9"}, + {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:98eeee2f2e63edae2181c886d7911ce502e1292794f4c5ee71e60e23e8d26b5d"}, + {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:57fdd2e0b2694ce6fc2e5ccf189789c3e2962916fb38779d3e3521ff8fe7a822"}, + {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d552c78411f60b1fdaafd117a1fca2f02e562e309223b9d44b7de8be451ec5e0"}, + {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a0b2b80321c2ed3fcf0385ec9e51a12253c50f146fddb2abbb10f033fe3d049a"}, + {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:18406efb2f5a0e57e3a5881cd9354c1512d3bb4f5c45d96d110a66114d84d23a"}, + {file = "regex-2024.9.11-cp312-cp312-win32.whl", hash = "sha256:e464b467f1588e2c42d26814231edecbcfe77f5ac414d92cbf4e7b55b2c2a776"}, + {file = "regex-2024.9.11-cp312-cp312-win_amd64.whl", hash = "sha256:9e8719792ca63c6b8340380352c24dcb8cd7ec49dae36e963742a275dfae6009"}, + {file = "regex-2024.9.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c157bb447303070f256e084668b702073db99bbb61d44f85d811025fcf38f784"}, + {file = "regex-2024.9.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4db21ece84dfeefc5d8a3863f101995de646c6cb0536952c321a2650aa202c36"}, + {file = "regex-2024.9.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:220e92a30b426daf23bb67a7962900ed4613589bab80382be09b48896d211e92"}, + {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb1ae19e64c14c7ec1995f40bd932448713d3c73509e82d8cd7744dc00e29e86"}, + {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f47cd43a5bfa48f86925fe26fbdd0a488ff15b62468abb5d2a1e092a4fb10e85"}, + {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9d4a76b96f398697fe01117093613166e6aa8195d63f1b4ec3f21ab637632963"}, + {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ea51dcc0835eea2ea31d66456210a4e01a076d820e9039b04ae8d17ac11dee6"}, + {file = "regex-2024.9.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7aaa315101c6567a9a45d2839322c51c8d6e81f67683d529512f5bcfb99c802"}, + {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c57d08ad67aba97af57a7263c2d9006d5c404d721c5f7542f077f109ec2a4a29"}, + {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8404bf61298bb6f8224bb9176c1424548ee1181130818fcd2cbffddc768bed8"}, + {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dd4490a33eb909ef5078ab20f5f000087afa2a4daa27b4c072ccb3cb3050ad84"}, + {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:eee9130eaad130649fd73e5cd92f60e55708952260ede70da64de420cdcad554"}, + {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6a2644a93da36c784e546de579ec1806bfd2763ef47babc1b03d765fe560c9f8"}, + {file = "regex-2024.9.11-cp313-cp313-win32.whl", hash = "sha256:e997fd30430c57138adc06bba4c7c2968fb13d101e57dd5bb9355bf8ce3fa7e8"}, + {file = "regex-2024.9.11-cp313-cp313-win_amd64.whl", hash = "sha256:042c55879cfeb21a8adacc84ea347721d3d83a159da6acdf1116859e2427c43f"}, + {file = "regex-2024.9.11-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:35f4a6f96aa6cb3f2f7247027b07b15a374f0d5b912c0001418d1d55024d5cb4"}, + {file = "regex-2024.9.11-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:55b96e7ce3a69a8449a66984c268062fbaa0d8ae437b285428e12797baefce7e"}, + {file = "regex-2024.9.11-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cb130fccd1a37ed894824b8c046321540263013da72745d755f2d35114b81a60"}, + {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:323c1f04be6b2968944d730e5c2091c8c89767903ecaa135203eec4565ed2b2b"}, + {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be1c8ed48c4c4065ecb19d882a0ce1afe0745dfad8ce48c49586b90a55f02366"}, + {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b5b029322e6e7b94fff16cd120ab35a253236a5f99a79fb04fda7ae71ca20ae8"}, + {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6fff13ef6b5f29221d6904aa816c34701462956aa72a77f1f151a8ec4f56aeb"}, + {file = "regex-2024.9.11-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:587d4af3979376652010e400accc30404e6c16b7df574048ab1f581af82065e4"}, + {file = "regex-2024.9.11-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:079400a8269544b955ffa9e31f186f01d96829110a3bf79dc338e9910f794fca"}, + {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f9268774428ec173654985ce55fc6caf4c6d11ade0f6f914d48ef4719eb05ebb"}, + {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:23f9985c8784e544d53fc2930fc1ac1a7319f5d5332d228437acc9f418f2f168"}, + {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:ae2941333154baff9838e88aa71c1d84f4438189ecc6021a12c7573728b5838e"}, + {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:e93f1c331ca8e86fe877a48ad64e77882c0c4da0097f2212873a69bbfea95d0c"}, + {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:846bc79ee753acf93aef4184c040d709940c9d001029ceb7b7a52747b80ed2dd"}, + {file = "regex-2024.9.11-cp38-cp38-win32.whl", hash = "sha256:c94bb0a9f1db10a1d16c00880bdebd5f9faf267273b8f5bd1878126e0fbde771"}, + {file = "regex-2024.9.11-cp38-cp38-win_amd64.whl", hash = "sha256:2b08fce89fbd45664d3df6ad93e554b6c16933ffa9d55cb7e01182baaf971508"}, + {file = "regex-2024.9.11-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:07f45f287469039ffc2c53caf6803cd506eb5f5f637f1d4acb37a738f71dd066"}, + {file = "regex-2024.9.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4838e24ee015101d9f901988001038f7f0d90dc0c3b115541a1365fb439add62"}, + {file = "regex-2024.9.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6edd623bae6a737f10ce853ea076f56f507fd7726bee96a41ee3d68d347e4d16"}, + {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c69ada171c2d0e97a4b5aa78fbb835e0ffbb6b13fc5da968c09811346564f0d3"}, + {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02087ea0a03b4af1ed6ebab2c54d7118127fee8d71b26398e8e4b05b78963199"}, + {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69dee6a020693d12a3cf892aba4808fe168d2a4cef368eb9bf74f5398bfd4ee8"}, + {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:297f54910247508e6e5cae669f2bc308985c60540a4edd1c77203ef19bfa63ca"}, + {file = "regex-2024.9.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ecea58b43a67b1b79805f1a0255730edaf5191ecef84dbc4cc85eb30bc8b63b9"}, + {file = "regex-2024.9.11-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:eab4bb380f15e189d1313195b062a6aa908f5bd687a0ceccd47c8211e9cf0d4a"}, + {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0cbff728659ce4bbf4c30b2a1be040faafaa9eca6ecde40aaff86f7889f4ab39"}, + {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:54c4a097b8bc5bb0dfc83ae498061d53ad7b5762e00f4adaa23bee22b012e6ba"}, + {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:73d6d2f64f4d894c96626a75578b0bf7d9e56dcda8c3d037a2118fdfe9b1c664"}, + {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:e53b5fbab5d675aec9f0c501274c467c0f9a5d23696cfc94247e1fb56501ed89"}, + {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0ffbcf9221e04502fc35e54d1ce9567541979c3fdfb93d2c554f0ca583a19b35"}, + {file = "regex-2024.9.11-cp39-cp39-win32.whl", hash = "sha256:e4c22e1ac1f1ec1e09f72e6c44d8f2244173db7eb9629cc3a346a8d7ccc31142"}, + {file = "regex-2024.9.11-cp39-cp39-win_amd64.whl", hash = "sha256:faa3c142464efec496967359ca99696c896c591c56c53506bac1ad465f66e919"}, + {file = "regex-2024.9.11.tar.gz", hash = "sha256:6c188c307e8433bcb63dc1915022deb553b4203a70722fc542c363bf120a01fd"}, ] [[package]] name = "requests" version = "2.32.3" description = "Python HTTP for Humans." -category = "main" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1320,37 +1537,37 @@ jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"] [[package]] name = "ruff" -version = "0.6.3" +version = "0.6.9" description = "An extremely fast Python linter and code formatter, written in Rust." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.6.3-py3-none-linux_armv6l.whl", hash = "sha256:97f58fda4e309382ad30ede7f30e2791d70dd29ea17f41970119f55bdb7a45c3"}, - {file = "ruff-0.6.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:3b061e49b5cf3a297b4d1c27ac5587954ccb4ff601160d3d6b2f70b1622194dc"}, - {file = "ruff-0.6.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:34e2824a13bb8c668c71c1760a6ac7d795ccbd8d38ff4a0d8471fdb15de910b1"}, - {file = "ruff-0.6.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bddfbb8d63c460f4b4128b6a506e7052bad4d6f3ff607ebbb41b0aa19c2770d1"}, - {file = "ruff-0.6.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ced3eeb44df75353e08ab3b6a9e113b5f3f996bea48d4f7c027bc528ba87b672"}, - {file = "ruff-0.6.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47021dff5445d549be954eb275156dfd7c37222acc1e8014311badcb9b4ec8c1"}, - {file = "ruff-0.6.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7d7bd20dc07cebd68cc8bc7b3f5ada6d637f42d947c85264f94b0d1cd9d87384"}, - {file = "ruff-0.6.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:500f166d03fc6d0e61c8e40a3ff853fa8a43d938f5d14c183c612df1b0d6c58a"}, - {file = "ruff-0.6.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42844ff678f9b976366b262fa2d1d1a3fe76f6e145bd92c84e27d172e3c34500"}, - {file = "ruff-0.6.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70452a10eb2d66549de8e75f89ae82462159855e983ddff91bc0bce6511d0470"}, - {file = "ruff-0.6.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:65a533235ed55f767d1fc62193a21cbf9e3329cf26d427b800fdeacfb77d296f"}, - {file = "ruff-0.6.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d2e2c23cef30dc3cbe9cc5d04f2899e7f5e478c40d2e0a633513ad081f7361b5"}, - {file = "ruff-0.6.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d8a136aa7d228975a6aee3dd8bea9b28e2b43e9444aa678fb62aeb1956ff2351"}, - {file = "ruff-0.6.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:f92fe93bc72e262b7b3f2bba9879897e2d58a989b4714ba6a5a7273e842ad2f8"}, - {file = "ruff-0.6.3-py3-none-win32.whl", hash = "sha256:7a62d3b5b0d7f9143d94893f8ba43aa5a5c51a0ffc4a401aa97a81ed76930521"}, - {file = "ruff-0.6.3-py3-none-win_amd64.whl", hash = "sha256:746af39356fee2b89aada06c7376e1aa274a23493d7016059c3a72e3b296befb"}, - {file = "ruff-0.6.3-py3-none-win_arm64.whl", hash = "sha256:14a9528a8b70ccc7a847637c29e56fd1f9183a9db743bbc5b8e0c4ad60592a82"}, - {file = "ruff-0.6.3.tar.gz", hash = "sha256:183b99e9edd1ef63be34a3b51fee0a9f4ab95add123dbf89a71f7b1f0c991983"}, + {file = "ruff-0.6.9-py3-none-linux_armv6l.whl", hash = "sha256:064df58d84ccc0ac0fcd63bc3090b251d90e2a372558c0f057c3f75ed73e1ccd"}, + {file = "ruff-0.6.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:140d4b5c9f5fc7a7b074908a78ab8d384dd7f6510402267bc76c37195c02a7ec"}, + {file = "ruff-0.6.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53fd8ca5e82bdee8da7f506d7b03a261f24cd43d090ea9db9a1dc59d9313914c"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645d7d8761f915e48a00d4ecc3686969761df69fb561dd914a773c1a8266e14e"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eae02b700763e3847595b9d2891488989cac00214da7f845f4bcf2989007d577"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d5ccc9e58112441de8ad4b29dcb7a86dc25c5f770e3c06a9d57e0e5eba48829"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:417b81aa1c9b60b2f8edc463c58363075412866ae4e2b9ab0f690dc1e87ac1b5"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c866b631f5fbce896a74a6e4383407ba7507b815ccc52bcedabb6810fdb3ef7"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b118afbb3202f5911486ad52da86d1d52305b59e7ef2031cea3425142b97d6f"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a67267654edc23c97335586774790cde402fb6bbdb3c2314f1fc087dee320bfa"}, + {file = "ruff-0.6.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3ef0cc774b00fec123f635ce5c547dac263f6ee9fb9cc83437c5904183b55ceb"}, + {file = "ruff-0.6.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:12edd2af0c60fa61ff31cefb90aef4288ac4d372b4962c2864aeea3a1a2460c0"}, + {file = "ruff-0.6.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:55bb01caeaf3a60b2b2bba07308a02fca6ab56233302406ed5245180a05c5625"}, + {file = "ruff-0.6.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:925d26471fa24b0ce5a6cdfab1bb526fb4159952385f386bdcc643813d472039"}, + {file = "ruff-0.6.9-py3-none-win32.whl", hash = "sha256:eb61ec9bdb2506cffd492e05ac40e5bc6284873aceb605503d8494180d6fc84d"}, + {file = "ruff-0.6.9-py3-none-win_amd64.whl", hash = "sha256:785d31851c1ae91f45b3d8fe23b8ae4b5170089021fbb42402d811135f0b7117"}, + {file = "ruff-0.6.9-py3-none-win_arm64.whl", hash = "sha256:a9641e31476d601f83cd602608739a0840e348bda93fec9f1ee816f8b6798b93"}, + {file = "ruff-0.6.9.tar.gz", hash = "sha256:b076ef717a8e5bc819514ee1d602bbdca5b4420ae13a9cf61a0c0a4f53a2baa2"}, ] [[package]] name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" -category = "main" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -1382,16 +1599,35 @@ files = [ {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, ] +[[package]] +name = "tinycss2" +version = "1.4.0" +description = "A tiny CSS parser" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289"}, + {file = "tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7"}, +] + +[package.dependencies] +webencodings = ">=0.4" + +[package.extras] +doc = ["sphinx", "sphinx_rtd_theme"] +test = ["pytest", "ruff"] + [[package]] name = "tomli" -version = "2.0.1" +version = "2.0.2" description = "A lil' TOML parser" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, + {file = "tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38"}, + {file = "tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"}, ] [[package]] @@ -1450,14 +1686,14 @@ files = [ [[package]] name = "urllib3" -version = "2.2.2" +version = "2.2.3" description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" +category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, - {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, + {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, + {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, ] [package.extras] @@ -1468,57 +1704,69 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "watchdog" -version = "5.0.2" +version = "6.0.0" description = "Filesystem events monitoring" -category = "main" +category = "dev" optional = false python-versions = ">=3.9" files = [ - {file = "watchdog-5.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d961f4123bb3c447d9fcdcb67e1530c366f10ab3a0c7d1c0c9943050936d4877"}, - {file = "watchdog-5.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72990192cb63872c47d5e5fefe230a401b87fd59d257ee577d61c9e5564c62e5"}, - {file = "watchdog-5.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6bec703ad90b35a848e05e1b40bf0050da7ca28ead7ac4be724ae5ac2653a1a0"}, - {file = "watchdog-5.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:dae7a1879918f6544201d33666909b040a46421054a50e0f773e0d870ed7438d"}, - {file = "watchdog-5.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c4a440f725f3b99133de610bfec93d570b13826f89616377715b9cd60424db6e"}, - {file = "watchdog-5.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8b2918c19e0d48f5f20df458c84692e2a054f02d9df25e6c3c930063eca64c1"}, - {file = "watchdog-5.0.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:aa9cd6e24126d4afb3752a3e70fce39f92d0e1a58a236ddf6ee823ff7dba28ee"}, - {file = "watchdog-5.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f627c5bf5759fdd90195b0c0431f99cff4867d212a67b384442c51136a098ed7"}, - {file = "watchdog-5.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d7594a6d32cda2b49df3fd9abf9b37c8d2f3eab5df45c24056b4a671ac661619"}, - {file = "watchdog-5.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba32efcccfe2c58f4d01115440d1672b4eb26cdd6fc5b5818f1fb41f7c3e1889"}, - {file = "watchdog-5.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:963f7c4c91e3f51c998eeff1b3fb24a52a8a34da4f956e470f4b068bb47b78ee"}, - {file = "watchdog-5.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8c47150aa12f775e22efff1eee9f0f6beee542a7aa1a985c271b1997d340184f"}, - {file = "watchdog-5.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:14dd4ed023d79d1f670aa659f449bcd2733c33a35c8ffd88689d9d243885198b"}, - {file = "watchdog-5.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b84bff0391ad4abe25c2740c7aec0e3de316fdf7764007f41e248422a7760a7f"}, - {file = "watchdog-5.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3e8d5ff39f0a9968952cce548e8e08f849141a4fcc1290b1c17c032ba697b9d7"}, - {file = "watchdog-5.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fb223456db6e5f7bd9bbd5cd969f05aae82ae21acc00643b60d81c770abd402b"}, - {file = "watchdog-5.0.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9814adb768c23727a27792c77812cf4e2fd9853cd280eafa2bcfa62a99e8bd6e"}, - {file = "watchdog-5.0.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:901ee48c23f70193d1a7bc2d9ee297df66081dd5f46f0ca011be4f70dec80dab"}, - {file = "watchdog-5.0.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:638bcca3d5b1885c6ec47be67bf712b00a9ab3d4b22ec0881f4889ad870bc7e8"}, - {file = "watchdog-5.0.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:5597c051587f8757798216f2485e85eac583c3b343e9aa09127a3a6f82c65ee8"}, - {file = "watchdog-5.0.2-py3-none-manylinux2014_armv7l.whl", hash = "sha256:53ed1bf71fcb8475dd0ef4912ab139c294c87b903724b6f4a8bd98e026862e6d"}, - {file = "watchdog-5.0.2-py3-none-manylinux2014_i686.whl", hash = "sha256:29e4a2607bd407d9552c502d38b45a05ec26a8e40cc7e94db9bb48f861fa5abc"}, - {file = "watchdog-5.0.2-py3-none-manylinux2014_ppc64.whl", hash = "sha256:b6dc8f1d770a8280997e4beae7b9a75a33b268c59e033e72c8a10990097e5fde"}, - {file = "watchdog-5.0.2-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:d2ab34adc9bf1489452965cdb16a924e97d4452fcf88a50b21859068b50b5c3b"}, - {file = "watchdog-5.0.2-py3-none-manylinux2014_s390x.whl", hash = "sha256:7d1aa7e4bb0f0c65a1a91ba37c10e19dabf7eaaa282c5787e51371f090748f4b"}, - {file = "watchdog-5.0.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:726eef8f8c634ac6584f86c9c53353a010d9f311f6c15a034f3800a7a891d941"}, - {file = "watchdog-5.0.2-py3-none-win32.whl", hash = "sha256:bda40c57115684d0216556671875e008279dea2dc00fcd3dde126ac8e0d7a2fb"}, - {file = "watchdog-5.0.2-py3-none-win_amd64.whl", hash = "sha256:d010be060c996db725fbce7e3ef14687cdcc76f4ca0e4339a68cc4532c382a73"}, - {file = "watchdog-5.0.2-py3-none-win_ia64.whl", hash = "sha256:3960136b2b619510569b90f0cd96408591d6c251a75c97690f4553ca88889769"}, - {file = "watchdog-5.0.2.tar.gz", hash = "sha256:dcebf7e475001d2cdeb020be630dc5b687e9acdd60d16fea6bb4508e7b94cf76"}, + {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26"}, + {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112"}, + {file = "watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3"}, + {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c"}, + {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2"}, + {file = "watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c"}, + {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948"}, + {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860"}, + {file = "watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0"}, + {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c"}, + {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134"}, + {file = "watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b"}, + {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8"}, + {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a"}, + {file = "watchdog-6.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c"}, + {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881"}, + {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11"}, + {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa"}, + {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2"}, + {file = "watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a"}, + {file = "watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680"}, + {file = "watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f"}, + {file = "watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282"}, ] [package.extras] watchmedo = ["PyYAML (>=3.10)"] +[[package]] +name = "webencodings" +version = "0.5.1" +description = "Character encoding aliases for legacy web content" +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, + {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, +] + [[package]] name = "zipp" -version = "3.20.1" +version = "3.20.2" description = "Backport of pathlib-compatible object wrapper for zip files" -category = "main" +category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.20.1-py3-none-any.whl", hash = "sha256:9960cd8967c8f85a56f920d5d507274e74f9ff813a0ab8889a5b5be2daf44064"}, - {file = "zipp-3.20.1.tar.gz", hash = "sha256:c22b14cc4763c5a5b04134207736c107db42e9d3ef2d9779d465f5f1bcba572b"}, + {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"}, + {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"}, ] [package.extras] @@ -1532,4 +1780,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "a6b55e8736cd5e7c85d70dbba83dab0f4015b49c31c8285678bc18202bbdc2da" +content-hash = "7ca9a6f403992890916796e63cc7dd2131a19e89c78df8120469e6d0ed7bf2e2" diff --git a/pyproject.toml b/pyproject.toml index 9bae9bd..fbbf3e2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,8 +1,9 @@ [tool.poetry] name = "geoserverx" -version = "0.0.3" -description = "" +version = "0.0.4" +description = "geoserverx is a modern python and CLI package for communicating with Geoserver." authors = ["krishnaglodha "] +readme = "README.md" [tool.poetry.scripts] gsx = "geoserverx.cli.cli:app" @@ -13,18 +14,25 @@ httpx = "^0.24.1" pydantic = "2.8.2" typer = "^0.4.1" rich = "^12.5.1" -mkdocs-material = "^9.0.14" [tool.poetry.group.dev.dependencies] pytest = "^7.1.2" respx = "^0.20.1" -mypy = "^0.960" +mypy = "*" ruff = "^0.6.3" black = "^24.8.0" isort = "^5.10.1" pytest-asyncio = "^0.21.0" anyio = {extras = ["trio"], version = "^3.3.4"} +[tool.poetry.group.docs] +optional = true +[tool.poetry.group.docs.dependencies] +mkdocs-material = "^9.5.0" +pillow = "*" +CairoSVG= "*" + + [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" diff --git a/social/2be55c97396bb6811061ba3194e30e4d.png b/social/2be55c97396bb6811061ba3194e30e4d.png new file mode 100644 index 0000000..ec12df3 Binary files /dev/null and b/social/2be55c97396bb6811061ba3194e30e4d.png differ diff --git a/social/53d44762e0d6016d6de24215dfdd6676.png b/social/53d44762e0d6016d6de24215dfdd6676.png new file mode 100644 index 0000000..76a19ee Binary files /dev/null and b/social/53d44762e0d6016d6de24215dfdd6676.png differ diff --git a/social/548c1d117ad531ea470f4c6f675062a4.png b/social/548c1d117ad531ea470f4c6f675062a4.png new file mode 100644 index 0000000..afa50a9 Binary files /dev/null and b/social/548c1d117ad531ea470f4c6f675062a4.png differ diff --git a/social/92f5fd10f5766422436223bc15a7c8ef.png b/social/92f5fd10f5766422436223bc15a7c8ef.png new file mode 100644 index 0000000..937503b Binary files /dev/null and b/social/92f5fd10f5766422436223bc15a7c8ef.png differ diff --git a/social/9eef2d77b3d71b7533499b2f651f63d4.png b/social/9eef2d77b3d71b7533499b2f651f63d4.png new file mode 100644 index 0000000..252fc56 Binary files /dev/null and b/social/9eef2d77b3d71b7533499b2f651f63d4.png differ diff --git a/social/a05d671ab8d4f043eadc8e9f00b2feec.png b/social/a05d671ab8d4f043eadc8e9f00b2feec.png new file mode 100644 index 0000000..4df9440 Binary files /dev/null and b/social/a05d671ab8d4f043eadc8e9f00b2feec.png differ diff --git a/social/ab5486e06e38b9b0518f6930cc6a8248.png b/social/ab5486e06e38b9b0518f6930cc6a8248.png new file mode 100644 index 0000000..e58ca7c Binary files /dev/null and b/social/ab5486e06e38b9b0518f6930cc6a8248.png differ diff --git a/social/df41e99874754a66cab3b04028b0eb6b.png b/social/df41e99874754a66cab3b04028b0eb6b.png new file mode 100644 index 0000000..68df687 Binary files /dev/null and b/social/df41e99874754a66cab3b04028b0eb6b.png differ diff --git a/social/f510d45f3b407da60e907251443fcf59.png b/social/f510d45f3b407da60e907251443fcf59.png new file mode 100644 index 0000000..326a76e Binary files /dev/null and b/social/f510d45f3b407da60e907251443fcf59.png differ diff --git a/social/fonts/Roboto/Black Italic.ttf b/social/fonts/Roboto/Black Italic.ttf new file mode 100644 index 0000000..0a4dfd0 Binary files /dev/null and b/social/fonts/Roboto/Black Italic.ttf differ diff --git a/social/fonts/Roboto/Black.ttf b/social/fonts/Roboto/Black.ttf new file mode 100644 index 0000000..58fa175 Binary files /dev/null and b/social/fonts/Roboto/Black.ttf differ diff --git a/social/fonts/Roboto/Bold Italic.ttf b/social/fonts/Roboto/Bold Italic.ttf new file mode 100644 index 0000000..5e39ae9 Binary files /dev/null and b/social/fonts/Roboto/Bold Italic.ttf differ diff --git a/social/fonts/Roboto/Bold.ttf b/social/fonts/Roboto/Bold.ttf new file mode 100644 index 0000000..e64db79 Binary files /dev/null and b/social/fonts/Roboto/Bold.ttf differ diff --git a/social/fonts/Roboto/Italic.ttf b/social/fonts/Roboto/Italic.ttf new file mode 100644 index 0000000..65498ee Binary files /dev/null and b/social/fonts/Roboto/Italic.ttf differ diff --git a/social/fonts/Roboto/Light Italic.ttf b/social/fonts/Roboto/Light Italic.ttf new file mode 100644 index 0000000..867b76d Binary files /dev/null and b/social/fonts/Roboto/Light Italic.ttf differ diff --git a/social/fonts/Roboto/Light.ttf b/social/fonts/Roboto/Light.ttf new file mode 100644 index 0000000..a7e0284 Binary files /dev/null and b/social/fonts/Roboto/Light.ttf differ diff --git a/social/fonts/Roboto/Medium Italic.ttf b/social/fonts/Roboto/Medium Italic.ttf new file mode 100644 index 0000000..4e3bf0d Binary files /dev/null and b/social/fonts/Roboto/Medium Italic.ttf differ diff --git a/social/fonts/Roboto/Medium.ttf b/social/fonts/Roboto/Medium.ttf new file mode 100644 index 0000000..0707e15 Binary files /dev/null and b/social/fonts/Roboto/Medium.ttf differ diff --git a/social/fonts/Roboto/Regular.ttf b/social/fonts/Roboto/Regular.ttf new file mode 100644 index 0000000..2d116d9 Binary files /dev/null and b/social/fonts/Roboto/Regular.ttf differ diff --git a/social/fonts/Roboto/Thin Italic.ttf b/social/fonts/Roboto/Thin Italic.ttf new file mode 100644 index 0000000..b2c3933 Binary files /dev/null and b/social/fonts/Roboto/Thin Italic.ttf differ diff --git a/social/fonts/Roboto/Thin.ttf b/social/fonts/Roboto/Thin.ttf new file mode 100644 index 0000000..ab68508 Binary files /dev/null and b/social/fonts/Roboto/Thin.ttf differ diff --git a/src/geoserverx/_async/gsx.py b/src/geoserverx/_async/gsx.py index d313d79..d621433 100644 --- a/src/geoserverx/_async/gsx.py +++ b/src/geoserverx/_async/gsx.py @@ -19,6 +19,8 @@ from geoserverx.models.workspace import ( NewWorkspace, NewWorkspaceInfo, + UpdateWorkspace, + UpdateWorkspaceInfo, WorkspaceModel, WorkspacesModel, ) @@ -45,7 +47,7 @@ class AsyncGeoServerX: username: str = "admin" password: str = "geoserver" url: str = "http://127.0.0.1:8080/geoserver/rest/" - head = {"Content-Type": "application/json"} + headers = {"Content-Type": "application/json"} def __post_init__(self): if not self.username and not self.password and not self.url: @@ -97,10 +99,10 @@ def response_recognise(self, r) -> GSResponse: # check if certain module/plugin exists in geoserver async def check_modules(self, name) -> Union[bool, GSResponse]: - Client = self.http_client + client = self.http_client try: - response = await Client.get("about/status.json") - response.raise_for_status() # Raises an HTTPError for bad responses (4xx and 5xx) + response = await client.get("about/status.json") + response.raise_for_status() # Raises an HTTPError for bad response (4xx and 5xx) # Extract and check the modules modules = [ @@ -122,107 +124,110 @@ async def check_modules(self, name) -> Union[bool, GSResponse]: # Handle Module not found exception return GSResponse(code=412, response=str(e)) - # Get all workspaces async def get_all_workspaces(self) -> Union[WorkspacesModel, GSResponse]: - Client = self.http_client - responses = await Client.get("workspaces") - if responses.status_code == 200: - return WorkspacesModel.model_validate(responses.json()) + client = self.http_client + response = await client.get("workspaces") + if response.status_code == 200: + return WorkspacesModel.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # Get specific workspaces async def get_workspace(self, workspace: str) -> Union[WorkspaceModel, GSResponse]: - Client = self.http_client - responses = await Client.get(f"workspaces/{workspace}") - if responses.status_code == 200: - return WorkspaceModel.model_validate(responses.json()) + client = self.http_client + response = await client.get(f"workspaces/{workspace}") + if response.status_code == 200: + return WorkspaceModel.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) + + async def delete_workspace( + self, workspace: str, recurse: bool = False + ) -> GSResponse: + client = self.http_client + response = await client.delete( + f"workspaces/{workspace}", params={"recurse": recurse} + ) + return self.response_recognise(response.status_code) - # Create workspace async def create_workspace( self, name: str, default: bool = False, Isolated: bool = False ) -> GSResponse: - Client = self.http_client + client = self.http_client payload: NewWorkspace = NewWorkspace( workspace=NewWorkspaceInfo(name=name, isolated=Isolated) ) - responses = await Client.post( - f"workspaces?default={default}", + response = await client.post( + "workspaces", data=payload.model_dump_json(), - headers=self.head, + headers=self.headers, + params={"default": default}, ) - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) + + async def update_workspace( + self, name: str, update: UpdateWorkspaceInfo + ) -> GSResponse: + client = self.http_client + update_ws = UpdateWorkspace(workspace=update) + response = await client.put( + f"workspaces/{name}.json", + data=update_ws.model_dump_json(exclude_none=True), + headers=self.headers, + ) + return self.response_recognise(response.status_code) - # Get vector stores in specific workspaces async def get_vector_stores_in_workspaces(self, workspace: str) -> DataStoresModel: - Client = self.http_client - responses = await Client.get(f"workspaces/{workspace}/datastores") - if responses.status_code == 200: - return DataStoresModel.model_validate(responses.json()) + client = self.http_client + response = await client.get(f"workspaces/{workspace}/datastores") + if response.status_code == 200: + return DataStoresModel.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # Get raster stores in specific workspaces async def get_raster_stores_in_workspaces( self, workspace: str ) -> CoveragesStoresModel: - Client = self.http_client - responses = await Client.get(f"workspaces/{workspace}/coveragestores") - if responses.status_code == 200: - return CoveragesStoresModel.model_validate(responses.json()) + client = self.http_client + response = await client.get(f"workspaces/{workspace}/coveragestores") + if response.status_code == 200: + return CoveragesStoresModel.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # Get vector store information in specific workspaces async def get_vector_store(self, workspace: str, store: str) -> DataStoreModel: url = f"workspaces/{workspace}/datastores/{store}.json" - Client = self.http_client - responses = await Client.get(url) - if responses.status_code == 200: - return DataStoreModel.model_validate(responses.json()) + client = self.http_client + response = await client.get(url) + if response.status_code == 200: + return DataStoreModel.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # Get raster store information in specific workspaces async def get_raster_store(self, workspace: str, store: str) -> CoveragesStoreModel: url = f"workspaces/{workspace}/coveragestores/{store}.json" - Client = self.http_client - responses = await Client.get(url) - if responses.status_code == 200: - return CoveragesStoreModel.model_validate(responses.json()) + client = self.http_client + response = await client.get(url) + if response.status_code == 200: + return CoveragesStoreModel.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # Get all styles in GS async def get_all_styles(self) -> AllStylesModel: - Client = self.http_client - responses = await Client.get("styles") - if responses.status_code == 200: - return AllStylesModel.model_validate(responses.json()) + client = self.http_client + response = await client.get("styles") + if response.status_code == 200: + return AllStylesModel.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # Get specific style in GS async def get_style(self, style: str) -> StyleModel: - Client = self.http_client - responses = await Client.get(f"styles/{style}.json") - if responses.status_code == 200: - return StyleModel.model_validate(responses.json()) + client = self.http_client + response = await client.get(f"styles/{style}.json") + if response.status_code == 200: + return StyleModel.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # Add postgres db async def create_pg_store( self, name: str, @@ -243,17 +248,16 @@ async def create_pg_store( user=username, passwd=password, dbtype="postgis", - ).dict(exclude_none=True), + ).model_dump(exclude_none=True), ) ) - Client = self.http_client - responses = await Client.post( + client = self.http_client + response = await client.post( f"workspaces/{workspace}/datastores/", data=payload.model_dump_json(), - headers=self.head, + headers=self.headers, ) - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) async def create_file_store(self, workspace: str, store: str, file, service_type): service: AddDataStoreProtocol = CreateFileStore() @@ -274,8 +278,8 @@ async def create_file_store(self, workspace: str, store: str, file, service_type ) else: raise ValueError(f"Service type {service_type} not supported") - responses = await service.addFile(self.http_client, workspace, store) - return self.response_recognise(responses) + response = await service.addFile(self.http_client, workspace, store) + return self.response_recognise(response) if service_type == "shapefile": service = ShapefileStore( @@ -292,54 +296,46 @@ async def create_file_store(self, workspace: str, store: str, file, service_type raise ValueError(f"Service type {service_type} not supported") await service.addFile(self.http_client, workspace, store) - # Get all layers async def get_all_layers( self, workspace: Optional[str] = None ) -> Union[LayersModel, GSResponse]: - Client = self.http_client + client = self.http_client if workspace: - responses = await Client.get(f"/workspaces/{workspace}/layers") + response = await client.get(f"/workspaces/{workspace}/layers") else: - responses = await Client.get("layers") - if responses.status_code == 200: - return LayersModel.model_validate(responses.json()) + response = await client.get("layers") + if response.status_code == 200: + return LayersModel.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # Get specific layer async def get_layer( self, workspace: str, layer: str ) -> Union[LayerModel, GSResponse]: - Client = self.http_client - responses = await Client.get(f"layers/{workspace}:{layer}") - if responses.status_code == 200: - return LayerModel.model_validate(responses.json()) + client = self.http_client + response = await client.get(f"layers/{workspace}:{layer}") + if response.status_code == 200: + return LayerModel.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # Delete specific layer async def delete_layer(self, workspace: str, layer: str) -> GSResponse: - Client = self.http_client - responses = await Client.delete(f"layers/{workspace}:{layer}") - results = self.response_recognise(responses.status_code) - return results + client = self.http_client + response = await client.delete(f"layers/{workspace}:{layer}") + return self.response_recognise(response.status_code) - # Get all layer groups async def get_all_layer_groups( self, workspace: Optional[str] = None ) -> Union[LayerGroupsModel, GSResponse]: - Client = self.http_client + client = self.http_client if workspace: - responses = await Client.get(f"workspaces/{workspace}/layergroups") + response = await client.get(f"workspaces/{workspace}/layergroups") else: - responses = await Client.get("layergroups") - if responses.status_code == 200: - return LayerGroupsModel.model_validate(responses.json()) + response = await client.get("layergroups") + if response.status_code == 200: + return LayerGroupsModel.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) # Reset geoserver async def reset_geoserver(self) -> GSResponse: @@ -369,39 +365,35 @@ async def reload_geoserver(self) -> GSResponse: # Get all geofence rules async def get_all_geofence_rules(self) -> Union[RulesResponse, GSResponse]: - Client = self.http_client + client = self.http_client # Check if the geofence plugin exists module_check = await self.check_modules("geofence") # If the module check fails, return the GSResponse directly if isinstance(module_check, GSResponse): return module_check - responses = await Client.get( + response = await client.get( "geofence/rules/", headers={"Accept": "application/json"} ) - if responses.status_code == 200: - return RulesResponse.model_validate(responses.json()) + if response.status_code == 200: + return RulesResponse.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # Get geofence rule by id async def get_geofence_rule(self, id: int) -> Union[Rule, GSResponse]: - Client = self.http_client + client = self.http_client # Check if the geofence plugin exists module_check = await self.check_modules("geofence") # If the module check fails, return the GSResponse directly if isinstance(module_check, GSResponse): return module_check - responses = await Client.get( + response = await client.get( f"geofence/rules/id/{id}", headers={"Accept": "application/json"} ) - if responses.status_code == 200: - return Rule.model_validate(responses.json()) + if response.status_code == 200: + return Rule.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # Create geofence on geoserver async def create_geofence(self, rule: Rule) -> GSResponse: PostingRule = NewRule(Rule=rule) # Check if the geofence plugin exists @@ -409,11 +401,10 @@ async def create_geofence(self, rule: Rule) -> GSResponse: # If the module check fails, return the GSResponse directly if isinstance(module_check, GSResponse): return module_check - Client = self.http_client - responses = await Client.post( + client = self.http_client + response = await client.post( "geofence/rules", content=PostingRule.model_dump_json(), - headers=self.head, + headers=self.headers, ) - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) diff --git a/src/geoserverx/_sync/gsx.py b/src/geoserverx/_sync/gsx.py index f5103a1..6555e90 100644 --- a/src/geoserverx/_sync/gsx.py +++ b/src/geoserverx/_sync/gsx.py @@ -22,6 +22,8 @@ from geoserverx.models.workspace import ( NewWorkspace, NewWorkspaceInfo, + UpdateWorkspace, + UpdateWorkspaceInfo, WorkspaceModel, WorkspacesModel, ) @@ -48,7 +50,7 @@ class SyncGeoServerX: username: str = "admin" password: str = "geoserver" url: str = "http://127.0.0.1:8080/geoserver/rest/" - head = {"Content-Type": "application/json"} + headers = {"Content-Type": "application/json"} def __post_init__(self): if not self.username and not self.password and not self.url: @@ -112,10 +114,10 @@ def inner_function(*args, **kwargs): # check if certain module/plugin exists in geoserver @exception_handler def check_modules(self, name) -> Union[bool, GSResponse]: - Client = self.http_client + client = self.http_client try: - response = Client.get("about/status.json") - response.raise_for_status() # Raises an HTTPError for bad responses (4xx and 5xx) + response = client.get("about/status.json") + response.raise_for_status() # Raises an HTTPError for bad response (4xx and 5xx) # Extract and check the modules modules = [ @@ -137,29 +139,30 @@ def check_modules(self, name) -> Union[bool, GSResponse]: # Handle Module not found exception return GSResponse(code=412, response=str(e)) - # Get all workspaces @exception_handler def get_all_workspaces(self) -> Union[WorkspacesModel, GSResponse]: - Client = self.http_client - responses = Client.get("workspaces") - if responses.status_code == 200: - return WorkspacesModel.model_validate(responses.json()) + client = self.http_client + response = client.get("workspaces") + if response.status_code == 200: + return WorkspacesModel.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # Get specific workspaces @exception_handler def get_workspace(self, workspace: str) -> Union[WorkspaceModel, GSResponse]: - Client = self.http_client - responses = Client.get(f"workspaces/{workspace}") - if responses.status_code == 200: - return WorkspaceModel.model_validate(responses.json()) + client = self.http_client + response = client.get(f"workspaces/{workspace}") + if response.status_code == 200: + return WorkspaceModel.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) + + @exception_handler + def delete_workspace(self, workspace: str, recurse: bool = False) -> GSResponse: + client = self.http_client + response = client.delete(f"workspaces/{workspace}", params={"recurse": recurse}) + return self.response_recognise(response.status_code) - # Create workspace on geoserver @exception_handler def create_workspace( self, name: str, default: bool = False, Isolated: bool = False @@ -167,125 +170,118 @@ def create_workspace( payload: NewWorkspace = NewWorkspace( workspace=NewWorkspaceInfo(name=name, isolated=Isolated) ) - Client = self.http_client - responses = Client.post( - f"workspaces?default={default}", + client = self.http_client + response = client.post( + "workspaces", content=payload.model_dump_json(), - headers=self.head, + params={"default": default}, + headers=self.headers, ) - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) + + @exception_handler + def update_workspace(self, name: str, update: UpdateWorkspaceInfo) -> GSResponse: + client = self.http_client + update_ws = UpdateWorkspace(workspace=update) + response = client.put( + f"workspaces/{name}.json", + data=update_ws.model_dump_json(exclude_none=True), + headers=self.headers, + ) + return self.response_recognise(response.status_code) - # Get vector stores in specific workspaces @exception_handler def get_vector_stores_in_workspaces(self, workspace: str) -> DataStoresModel: - Client = self.http_client - responses = Client.get(f"workspaces/{workspace}/datastores") - if responses.status_code == 200: - return DataStoresModel.model_validate(responses.json()) + client = self.http_client + response = client.get(f"workspaces/{workspace}/datastores") + if response.status_code == 200: + return DataStoresModel.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # Get raster stores in specific workspaces @exception_handler def get_raster_stores_in_workspaces(self, workspace: str) -> CoveragesStoresModel: - Client = self.http_client - responses = Client.get(f"workspaces/{workspace}/coveragestores") - if responses.status_code == 200: - return CoveragesStoresModel.model_validate(responses.json()) + client = self.http_client + response = client.get(f"workspaces/{workspace}/coveragestores") + if response.status_code == 200: + return CoveragesStoresModel.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # Get vector store information in specific workspaces @exception_handler def get_vector_store(self, workspace: str, store: str) -> DataStoreModel: url = f"workspaces/{workspace}/datastores/{store}.json" - Client = self.http_client - responses = Client.get(url) - if responses.status_code == 200: - return DataStoreModel.model_validate(responses.json()) + client = self.http_client + response = client.get(url) + if response.status_code == 200: + return DataStoreModel.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # create vector store in specific workspaces @exception_handler def create_vector_store(self, workspace: str, store: DataStoresModel) -> GSResponse: - Client = self.http_client - responses = Client.post( + client = self.http_client + response = client.post( f"workspaces/{workspace}/datastores", content=store.model_dump_json(), - headers=self.head, + headers=self.headers, ) - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # Get raster store information in specific workspaces @exception_handler def get_raster_store(self, workspace: str, store: str) -> CoveragesStoreModel: url = f"workspaces/{workspace}/coveragestores/{store}.json" - Client = self.http_client - responses = Client.get(url) - if responses.status_code == 200: - return CoveragesStoreModel.model_validate(responses.json()) + client = self.http_client + response = client.get(url) + if response.status_code == 200: + return CoveragesStoreModel.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # Get raster store information in specific workspaces @exception_handler def create_raster_store( self, workspace: str, store: CoveragesStoreModel ) -> GSResponse: - Client = self.http_client - responses = Client.post( + client = self.http_client + response = client.post( f"workspaces/{workspace}/coveragestores", content=store.model_dump_json(), - headers=self.head, + headers=self.headers, ) - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # delete store in specific workspaces @exception_handler def delete_store( self, workspace: str, store: str, type: str ) -> GSResponse: # TODO : add enum for type - Client = self.http_client + client = self.http_client if type == "raster": - responses = Client.delete( - f"/workspaces/{workspace}/coveragestores/{store}", headers=self.head + response = client.delete( + f"/workspaces/{workspace}/coveragestores/{store}", headers=self.headers ) elif type == "vector": - responses = Client.delete( - f"/workspaces/{workspace}/datastores/{store}", headers=self.head + response = client.delete( + f"/workspaces/{workspace}/datastores/{store}", headers=self.headers ) - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # Get all styles in GS @exception_handler def get_all_styles(self) -> AllStylesModel: - Client = self.http_client - responses = Client.get("styles") - if responses.status_code == 200: - return AllStylesModel.model_validate(responses.json()) + client = self.http_client + response = client.get("styles") + if response.status_code == 200: + return AllStylesModel.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # Get specific style in GS @exception_handler def get_style(self, style: str) -> StyleModel: - Client = self.http_client - responses = Client.get(f"styles/{style}.json") - if responses.status_code == 200: - return StyleModel.model_validate(responses.json()) + client = self.http_client + response = client.get(f"styles/{style}.json") + if response.status_code == 200: + return StyleModel.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) @exception_handler def create_file_store( @@ -303,10 +299,9 @@ def create_file_store( ) else: raise ValueError(f"Service type {service_type} not supported") - responses = service.addFile(self.http_client, workspace, store) - return self.response_recognise(responses) + response = service.addFile(self.http_client, workspace, store) + return self.response_recognise(response) - # Create workspace @exception_handler def create_pg_store( self, @@ -328,76 +323,70 @@ def create_pg_store( user=username, passwd=password, dbtype="postgis", - ).dict(exclude_none=True), + ).model_dump(exclude_none=True), ) ) - Client = self.http_client - responses = Client.post( + client = self.http_client + response = client.post( f"workspaces/{workspace}/datastores/", data=payload.model_dump_json(), - headers=self.head, + headers=self.headers, ) - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # Get all layers @exception_handler def get_all_layers( self, workspace: Optional[str] = None ) -> Union[LayersModel, GSResponse]: - Client = self.http_client + client = self.http_client if workspace: - responses = Client.get(f"/workspaces/{workspace}/layers") + response = client.get(f"/workspaces/{workspace}/layers") else: - responses = Client.get("layers") - if responses.status_code == 200: - return LayersModel.model_validate(responses.json()) + response = client.get("layers") + if response.status_code == 200: + return LayersModel.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) @exception_handler def get_vector_layer( self, workspace: str, store: str, layer: str ) -> Union[FeatureTypesModel, GSResponse]: - Client = self.http_client - responses = Client.get( + client = self.http_client + response = client.get( f"/workspaces/{workspace}/datastores/{store}/featuretypes/{layer}.json" ) - if responses.status_code == 200: + if response.status_code == 200: try: - return FeatureTypesModel.parse_obj(responses.json()) + return FeatureTypesModel.parse_obj(response.json()) except ValidationError as validation_error: print("Pydantic Validation Error:") print(validation_error) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) @exception_handler def get_raster_layer( self, workspace: str, store: str, layer: str ) -> Union[CoverageModel, GSResponse]: - Client = self.http_client - responses = Client.get( + client = self.http_client + response = client.get( f"/workspaces/{workspace}/coveragestores/{store}/coverages/{layer}.json" ) - if responses.status_code == 200: - return CoverageModel.parse_obj(responses.json()) + if response.status_code == 200: + return CoverageModel.parse_obj(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # Get specific layer @exception_handler def get_layer( self, workspace: str, layer: str, detail: bool = False ) -> Union[LayerModel, FeatureTypesModel, GSResponse]: - Client = self.http_client - responses = Client.get(f"layers/{workspace}:{layer}") - if responses.status_code == 200: + client = self.http_client + response = client.get(f"layers/{workspace}:{layer}") + if response.status_code == 200: if detail: - res = responses.json() + res = response.json() if res["layer"]["type"] == "VECTOR": result = self.get_vector_layer( workspace, @@ -411,58 +400,51 @@ def get_layer( ) return CoverageModel.parse_obj(result.dict()) else: - return LayerModel.parse_obj(responses.json()) + return LayerModel.parse_obj(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) @exception_handler def create_vector_layer( self, workspace: str, layer: FeatureTypesModel ) -> GSResponse: - Client = self.http_client - responses = Client.post( + client = self.http_client + response = client.post( f"/workspaces/{workspace}/featuretypes", data=layer.model_dump(by_alias=True, exclude_none=True), - headers=self.head, + headers=self.headers, ) - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) @exception_handler def create_raster_layer(self, workspace: str, layer: CoverageModel) -> GSResponse: - Client = self.http_client - responses = Client.post( + client = self.http_client + response = client.post( f"/workspaces/{workspace}/coverages", data=layer.model_dump_json(), - headers=self.head, + headers=self.headers, ) - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # Delete specific layer @exception_handler def delete_layer(self, workspace: str, layer: str) -> GSResponse: - Client = self.http_client - responses = Client.delete(f"layers/{workspace}:{layer}") - results = self.response_recognise(responses.status_code) - return results + client = self.http_client + response = client.delete(f"layers/{workspace}:{layer}") + return self.response_recognise(response.status_code) - # Get all layer groups @exception_handler def get_all_layer_groups( self, workspace: Optional[str] = None ) -> Union[LayerGroupsModel, GSResponse]: - Client = self.http_client + client = self.http_client if workspace: - responses = Client.get(f"workspaces/{workspace}/layergroups") + response = client.get(f"workspaces/{workspace}/layergroups") else: - responses = Client.get("layergroups") - if responses.status_code == 200: - return LayerGroupsModel.model_validate(responses.json()) + response = client.get("layergroups") + if response.status_code == 200: + return LayerGroupsModel.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) # Reset geoserver @exception_handler @@ -495,41 +477,35 @@ def reload_geoserver(self) -> GSResponse: # Get all geofence rules @exception_handler def get_all_geofence_rules(self) -> Union[RulesResponse, GSResponse]: - Client = self.http_client + client = self.http_client # Check if the geofence plugin exists module_check = self.check_modules("geofence") # If the module check fails, return the GSResponse directly if isinstance(module_check, GSResponse): return module_check # Make the HTTP request to fetch geofence rules - responses = Client.get( - "geofence/rules/", headers={"Accept": "application/json"} - ) - if responses.status_code == 200: - return RulesResponse.model_validate(responses.json()) + response = client.get("geofence/rules/", headers={"Accept": "application/json"}) + if response.status_code == 200: + return RulesResponse.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # Get geofence rule by id @exception_handler def get_geofence_rule(self, id: int) -> Union[GetRule, GSResponse]: - Client = self.http_client + client = self.http_client # Check if the geofence plugin exists module_check = self.check_modules("geofence") # If the module check fails, return the GSResponse directly if isinstance(module_check, GSResponse): return module_check - responses = Client.get( + response = client.get( f"geofence/rules/id/{id}", headers={"Accept": "application/json"} ) - if responses.status_code == 200: - return Rule.model_validate(responses.json()) + if response.status_code == 200: + return Rule.model_validate(response.json()) else: - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) - # Create geofence on geoserver @exception_handler def create_geofence(self, rule: Rule) -> GSResponse: PostingRule = NewRule(Rule=rule) @@ -538,11 +514,10 @@ def create_geofence(self, rule: Rule) -> GSResponse: # If the module check fails, return the GSResponse directly if isinstance(module_check, GSResponse): return module_check - Client = self.http_client - responses = Client.post( + client = self.http_client + response = client.post( "geofence/rules", content=PostingRule.model_dump_json(), - headers=self.head, + headers=self.headers, ) - results = self.response_recognise(responses.status_code) - return results + return self.response_recognise(response.status_code) diff --git a/src/geoserverx/cli/cli.py b/src/geoserverx/cli/cli.py index c1f11f5..b1ef193 100644 --- a/src/geoserverx/cli/cli.py +++ b/src/geoserverx/cli/cli.py @@ -1,13 +1,22 @@ -import json from enum import Enum from pathlib import Path +from typing import Optional import typer from rich import print +from rich.console import Console +from rich.table import Table from geoserverx._sync.gsx import SyncGeoServerX +from geoserverx.models.workspace import UpdateWorkspaceInfo app = typer.Typer() +console = Console() + + +class OutputFormats(str, Enum): + json = "json" + table = "table" @app.callback() @@ -29,7 +38,6 @@ class vectorFileEnum(str, Enum): gpkg = "gpkg" -# get all workspaces @SyncGeoServerX.exception_handler @app.command(help="Get all workspaces in the Geoserver") def workspaces( @@ -39,53 +47,102 @@ def workspaces( ), password: str = typer.Option("geoserver", help="Geoserver Password"), username: str = typer.Option("admin", help="Geoserver username"), + output: OutputFormats = typer.Option(OutputFormats.table), ): """ Get all workspaces in the Geoserver + looks like - gsx workspaces --url --username --password """ if request.value == "sync": client = SyncGeoServerX(username, password, url) - result = client.get_all_workspaces().model_dump_json() + result = client.get_all_workspaces() if "code" in result: - typer.secho(result, fg=typer.colors.RED) - else: print(result) + else: + if output == "json": + print(result.model_dump_json(indent=2)) + else: + try: + table = Table("Name", "Link") + for workspace in result.workspaces.workspace: + table.add_row(workspace.name, workspace.href) + console.print(table) + except AttributeError: + print(result.response) else: - typer.echo("Async support will be shortly") + print("Async support will be shortly") -# get workspace @SyncGeoServerX.exception_handler @app.command(help="Get workspace in the Geoserver") def workspace( + workspace: str, request: requestEnum = requestEnum._sync, - workspace: str = typer.Option(..., help="Workspace name"), url: str = typer.Option( "http://127.0.0.1:8080/geoserver/rest/", help="Geoserver REST URL" ), password: str = typer.Option("geoserver", help="Geoserver Password"), username: str = typer.Option("admin", help="Geoserver username"), + output: OutputFormats = typer.Option(OutputFormats.table), ): """ Get workspace in the Geoserver + looks like - gsx workspace --url --username --password """ if request.value == "sync": client = SyncGeoServerX(username, password, url) - result = client.get_workspace(workspace).model_dump_json() + result = client.get_workspace(workspace) if "code" in result: - typer.secho(result, fg=typer.colors.RED) - else: print(result) + else: + if output == "json": + print(result.model_dump_json(indent=2)) + else: + try: + table = Table("Column", "Value") + table.add_row("name", result.workspace.name) + table.add_row("isolated", str(result.workspace.isolated)) + table.add_row("dateCreated", result.workspace.dateCreated) + table.add_row("dataStores", result.workspace.dataStores) + table.add_row("coverageStores", result.workspace.coverageStores) + table.add_row("wmsStores", result.workspace.wmsStores) + table.add_row("wmtsStores", result.workspace.wmtsStores) + console.print(table) + except AttributeError: + print(result.response) else: - typer.echo("Async support will be shortly") + print("Async support will be shortly") + + +@SyncGeoServerX.exception_handler +@app.command(help="Delete workspace in the Geoserver") +def delete_workspace( + workspace: str, + request: requestEnum = requestEnum._sync, + recurse: bool = typer.Option(False, help="Delete all stores,layers,styles,etc."), + url: str = typer.Option( + "http://127.0.0.1:8080/geoserver/rest/", help="Geoserver REST URL" + ), + password: str = typer.Option("geoserver", help="Geoserver Password"), + username: str = typer.Option("admin", help="Geoserver username"), +): + """ + Delete workspace in the Geoserver + looks like - gsx delete-workspace --recurse/--no-recurse --url --username --password + """ + if request.value == "sync": + client = SyncGeoServerX(username, password, url) + result = client.delete_workspace(workspace, recurse) + print(result.response) + else: + print("Async support will be shortly") -# create workspace @SyncGeoServerX.exception_handler @app.command(help="Add workspace in the Geoserver") def create_workspace( + workspace: str, request: requestEnum = requestEnum._sync, - workspace: str = typer.Option(..., help="Workspace name"), default: bool = typer.Option(False, help="Make workspace default?"), isolated: bool = typer.Option(False, help="Make workspace isolated?"), url: str = typer.Option( @@ -96,21 +153,46 @@ def create_workspace( ): """ Add workspace in the Geoserver - looks like - gsx create-workspace --workspace --default/--no-default --isolated/--no-isolated --username --password + looks like - gsx create-workspace --default/--no-default --isolated/--no-isolated --url --username --password """ if request.value == "sync": client = SyncGeoServerX(username, password, url) - result = client.create_workspace(workspace, default, isolated).model_dump_json() - if json.loads(result)["code"] == 201: - typer.secho(result, fg=typer.colors.GREEN) - else: - typer.secho(result, fg=typer.colors.RED) + result = client.create_workspace(workspace, default, isolated) + print(result.response) else: - typer.echo("Async support will be shortly") + print("Async support will be shortly") + + +@SyncGeoServerX.exception_handler +@app.command(help="Add workspace in the Geoserver") +def update_workspace( + current_name: str, + request: requestEnum = requestEnum._sync, + new_name: Optional[str] = typer.Option(None, help="New Workspace name"), + isolated: Optional[bool] = typer.Option(False, help="Make workspace isolated?"), + url: str = typer.Option( + "http://127.0.0.1:8080/geoserver/rest/", help="Geoserver REST URL" + ), + password: str = typer.Option("geoserver", help="Geoserver Password"), + username: str = typer.Option("admin", help="Geoserver username"), +): + """ + Update existing workspace in the Geoserver + looks like - gsx update-workspace --new-name --isolated/--no-isolated --username --password + """ + if request.value == "sync": + client = SyncGeoServerX(username, password, url) + result = client.update_workspace( + current_name, + UpdateWorkspaceInfo(name=new_name, isolated=isolated), + ) + print(result.response) + + else: + print("Async support will be shortly") -# Get vector stores in specific workspaces @SyncGeoServerX.exception_handler @app.command(help="Get vector stores in specific workspaces") def vector_st_wp( @@ -128,15 +210,11 @@ def vector_st_wp( if request.value == "sync": client = SyncGeoServerX(username, password, url) result = client.get_vector_stores_in_workspaces(workspace).model_dump_json() - if "code" in result: - typer.secho(result, fg=typer.colors.RED) - else: - print(result) + print(result) else: - typer.echo("Async support will be shortly") + print("Async support will be shortly") -# Get raster stores in specific workspaces @SyncGeoServerX.exception_handler @app.command(help="Get raster stores in specific workspaces") def raster_st_wp( @@ -154,15 +232,11 @@ def raster_st_wp( if request.value == "sync": client = SyncGeoServerX(username, password, url) result = client.get_raster_stores_in_workspaces(workspace).model_dump_json() - if "code" in result: - typer.secho(result, fg=typer.colors.RED) - else: - print(result) + print(result) else: - typer.echo("Async support will be shortly") + print("Async support will be shortly") -# Get vector store information in specific workspaces @SyncGeoServerX.exception_handler @app.command(help="Get vector store information in specific workspaces") def vector_store( @@ -181,15 +255,11 @@ def vector_store( if request.value == "sync": client = SyncGeoServerX(username, password, url) result = client.get_vector_store(workspace, store).model_dump_json() - if "code" in result: - typer.secho(result, fg=typer.colors.RED) - else: - print(result) + print(result) else: - typer.echo("Async support will be shortly") + print("Async support will be shortly") -# Get raster store information in specific workspaces @SyncGeoServerX.exception_handler @app.command(help="Get raster store information in specific workspaces") def raster_store( @@ -208,15 +278,11 @@ def raster_store( if request.value == "sync": client = SyncGeoServerX(username, password, url) result = client.get_raster_store(workspace, store).model_dump_json() - if "code" in result: - typer.secho(result, fg=typer.colors.RED) - else: - print(result) + print(result) else: - typer.echo("Async support will be shortly") + print("Async support will be shortly") -# Get all styles in Geoserver @SyncGeoServerX.exception_handler @app.command(help="Get all styles in Geoserver") def styles( @@ -233,15 +299,11 @@ def styles( if request.value == "sync": client = SyncGeoServerX(username, password, url) result = client.get_all_styles().model_dump_json() - if "code" in result: - typer.secho(result, fg=typer.colors.RED) - else: - print(result) + print(result) else: - typer.echo("Async support will be shortly") + print("Async support will be shortly") -# Get style in Geoserver @SyncGeoServerX.exception_handler @app.command(help="Get style in Geoserver") def style( @@ -259,15 +321,11 @@ def style( if request.value == "sync": client = SyncGeoServerX(username, password, url) result = client.get_style(style).model_dump_json() - if "code" in result: - typer.secho(result, fg=typer.colors.RED) - else: - print(result) + print(result) else: - typer.echo("Async support will be shortly") + print("Async support will be shortly") -# Create Vector Layer in Geoserver @SyncGeoServerX.exception_handler @app.command(help="Create Vector Layer in Geoserver") def create_file( @@ -292,17 +350,13 @@ def create_file( result = client.create_file_store( workspace, store, files.read(), service_type ) - if result.code == 201: - typer.secho(result, fg=typer.colors.GREEN) - else: - typer.secho(result, fg=typer.colors.RED) + print(result) except Exception: - typer.secho("File path is incorrect", fg=typer.colors.YELLOW) + print("File path is incorrect") else: - typer.echo("Async support will be shortly") + print("Async support will be shortly") -# Create PostgreSQL store in Geoserver @SyncGeoServerX.exception_handler @app.command(help="Create PostgreSQL store in Geoserver") def create_pg_store( @@ -334,15 +388,11 @@ def create_pg_store( password=dbpwd, database=dbname, ) - if result.code == 201: - typer.secho(result, fg=typer.colors.GREEN) - else: - typer.secho(result, fg=typer.colors.RED) + print(result) else: - typer.echo("Async support will be shortly") + print("Async support will be shortly") -# get all layers @SyncGeoServerX.exception_handler @app.command(help="Get all layers in the Geoserver") def layers( @@ -360,15 +410,11 @@ def layers( if request.value == "sync": client = SyncGeoServerX(username, password, url) result = client.get_all_layers(workspace).model_dump_json() - if "code" in result: - typer.secho(result, fg=typer.colors.RED) - else: - print(result) + print(result) else: - typer.echo("Async support will be shortly") + print("Async support will be shortly") -# get layer @SyncGeoServerX.exception_handler @app.command(help="Get layer in the Geoserver") def layer( @@ -388,15 +434,11 @@ def layer( if request.value == "sync": client = SyncGeoServerX(username, password, url) result = client.get_layer(workspace, layer, detail).model_dump_json() - if "code" in result: - typer.secho(result, fg=typer.colors.RED) - else: - print(result) + print(result) else: - typer.echo("Async support will be shortly") + print("Async support will be shortly") -# get layer groups @SyncGeoServerX.exception_handler @app.command(help="Get layer groups in the Geoserver") def layer_groups( @@ -414,15 +456,11 @@ def layer_groups( if request.value == "sync": client = SyncGeoServerX(username, password, url) result = client.get_all_layer_groups(workspace).json() - if "layerGroups" in result: - typer.secho(result, fg=typer.colors.RED) - else: - print(result) + print(result) else: - typer.echo("Async support will be shortly") + print("Async support will be shortly") -# get all geofence rules @SyncGeoServerX.exception_handler @app.command(help="Get all geofence rules in the Geoserver") def geofence_rules( @@ -439,12 +477,9 @@ def geofence_rules( if request.value == "sync": client = SyncGeoServerX(username, password, url) result = client.get_all_geofence_rules().model_dump_json() - if "rules" in result: - typer.secho(result, fg=typer.colors.RED) - else: - print(result) + print(result) else: - typer.echo("Async support will be shortly") + print("Async support will be shortly") # Reset geoserver @@ -487,10 +522,7 @@ def geofence_rule( if request.value == "sync": client = SyncGeoServerX(username, password, url) result = client.get_geofence_rule(id).model_dump_json() - if "rule" in result: - typer.secho(result, fg=typer.colors.RED) - else: - print(result) + print(result) else: typer.echo("Async support will be shortly") @@ -515,3 +547,4 @@ def reload( typer.secho(result, fg=typer.colors.GREEN) else: typer.echo("Async support will be shortly") + print("Async support will be shortly") diff --git a/src/geoserverx/models/workspace.py b/src/geoserverx/models/workspace.py index 9edd5de..6900d73 100644 --- a/src/geoserverx/models/workspace.py +++ b/src/geoserverx/models/workspace.py @@ -19,7 +19,7 @@ class WorkspacesModel(BaseModel): class SingleWorkspace(BaseModel): name: str = ... isolated: bool = ... - dateCreated: Optional[str] + dateCreated: Optional[str] = None dataStores: str = ... coverageStores: str = ... wmsStores: str = ... @@ -37,3 +37,12 @@ class NewWorkspaceInfo(BaseModel): class NewWorkspace(BaseModel): workspace: NewWorkspaceInfo = ... + + +class UpdateWorkspaceInfo(BaseModel): + name: Optional[str] = None + isolated: Optional[bool] = None + + +class UpdateWorkspace(BaseModel): + workspace: UpdateWorkspaceInfo = ... diff --git a/tests/_async/test_gsx.py b/tests/_async/test_gsx.py index 2b39dbe..a7bfa68 100644 --- a/tests/_async/test_gsx.py +++ b/tests/_async/test_gsx.py @@ -7,6 +7,7 @@ from geoserverx._async.gsx import AsyncGeoServerX, GeoServerXAuth, GeoServerXError from geoserverx.models.geofence import Rule +from geoserverx.models.workspace import UpdateWorkspaceInfo baseUrl = "http://127.0.0.1:8080/geoserver/rest/" @@ -28,17 +29,6 @@ async def test_error(): assert True -@pytest.mark.asyncio -async def test_get_all_workspaces_validation( - create_a_client, respx_mock, bad_workspaces_connection -): - respx_mock.get(f"{baseUrl}workspaces").mock( - return_value=httpx.Response(404, json=bad_workspaces_connection) - ) - response = await create_a_client.get_all_workspaces() - assert response.code == 404 - - @pytest.mark.asyncio async def test_get_all_workspaces_success( create_a_client, respx_mock, good_workspaces_connection @@ -60,14 +50,26 @@ async def test_get_all_workspaces_NetworkError(create_a_client, respx_mock): # Test - get_workspace @pytest_mark.anyio +@pytest.mark.parametrize( + "workspace_name,status_code,response_data,expected_response", + [ + ("sfsf", 404, {"error": "not found"}, "Result not found"), + ], +) async def test_get_workspace_validation( - create_a_client, bad_workspace_connection, respx_mock + create_a_client, + respx_mock, + workspace_name, + status_code, + response_data, + expected_response, ): - respx_mock.get(f"{baseUrl}workspaces/sfsf").mock( - return_value=httpx.Response(404, json=bad_workspace_connection) + respx_mock.get(f"{baseUrl}workspaces/{workspace_name}").mock( + return_value=httpx.Response(status_code, json=response_data) ) - response = await create_a_client.get_workspace("sfsf") - assert response.response == "Result not found" + + response = await create_a_client.get_workspace(workspace_name) + assert response.response == expected_response @pytest_mark.anyio @@ -89,6 +91,65 @@ async def test_get_workspace_ConnectError(create_a_client, respx_mock): assert response.response == "Error in connecting to Geoserver" +# Test - update_workspace +@pytest_mark.anyio +@pytest.mark.parametrize( + "status_code,response_data,expected_response", + [ + (404, {"error": "not found"}, "Result not found"), + ], +) +async def test_update_workspace_validation( + create_a_client, + respx_mock, + status_code, + response_data, + expected_response, +): + respx_mock.put(f"{baseUrl}workspaces/tiger.json").mock( + return_value=httpx.Response(status_code, json=response_data) + ) + response = await create_a_client.update_workspace( + "tiger", UpdateWorkspaceInfo(isolated=True) + ) + assert response.response == expected_response + + +@pytest_mark.anyio +@pytest_mark.parametrize( + "workspace_info,status_code,response_data", + [ + ( + UpdateWorkspaceInfo(isolated=True), + 200, + {"workspace": {"isolated": True}}, + ) + ], +) +async def test_update_workspace_success( + create_a_client, + respx_mock, + workspace_info, + status_code, + response_data, +): + respx_mock.put(f"{baseUrl}workspaces/tiger.json").mock( + return_value=httpx.Response(status_code, json=response_data) + ) + response = await create_a_client.update_workspace("tiger", workspace_info) + assert response.code == status_code + + +@pytest_mark.anyio +async def test_update_workspace_ConnectError(create_a_client, respx_mock): + respx.put(f"{baseUrl}workspaces/tiger.json").mock(side_effect=httpx.ConnectError) + with pytest.raises(httpx.ConnectError): + response = await create_a_client.update_workspace( + "tiger", UpdateWorkspaceInfo(isolated=True) + ) + assert response.response == "Error in connecting to Geoserver" + + # Test - get_vector_stores_in_workspaces @pytest_mark.anyio async def test_get_vector_stores_in_workspaces_validation( @@ -292,7 +353,7 @@ async def test_get_style_ConnectError(create_a_client, respx_mock): async def test_create_workspace_validation( create_a_client, invalid_new_workspace_connection, respx_mock ): - respx_mock.post(f"{baseUrl}workspaces?default=False").mock( + respx_mock.post(f"{baseUrl}workspaces", params={"default": False}).mock( return_value=httpx.Response(404, json=invalid_new_workspace_connection) ) response = await create_a_client.create_workspace("pydad", False, True) @@ -303,7 +364,7 @@ async def test_create_workspace_validation( async def test_create_workspace_success( create_a_client, good_new_workspace_connection, respx_mock ): - respx_mock.post(f"{baseUrl}workspaces?default=False").mock( + respx_mock.post(f"{baseUrl}workspaces", params={"default": False}).mock( return_value=httpx.Response(201, json=good_new_workspace_connection) ) response = await create_a_client.create_workspace("pydad", False, True) @@ -312,7 +373,7 @@ async def test_create_workspace_success( @pytest_mark.anyio async def test_create_workspace_ConnectError(create_a_client, respx_mock): - respx_mock.post(f"{baseUrl}workspaces?default=False").mock( + respx_mock.post(f"{baseUrl}workspaces", params={"default": False}).mock( side_effect=httpx.ConnectError ) with pytest.raises(httpx.ConnectError): diff --git a/tests/_sync/test_gsx.py b/tests/_sync/test_gsx.py index 19a3d36..e1590b7 100644 --- a/tests/_sync/test_gsx.py +++ b/tests/_sync/test_gsx.py @@ -4,6 +4,7 @@ from geoserverx._sync.gsx import GeoServerXAuth, GeoServerXError, SyncGeoServerX from geoserverx.models.geofence import Rule +from geoserverx.models.workspace import UpdateWorkspaceInfo baseUrl = "http://127.0.0.1:8080/geoserver/rest/" @@ -24,17 +25,6 @@ def test_error(): assert True -# Test - get_all_workspaces -def test_get_all_workspaces_validation( - client: SyncGeoServerX, bad_workspaces_connection, respx_mock -): - respx_mock.get(f"{baseUrl}workspaces").mock( - return_value=httpx.Response(404, json=bad_workspaces_connection) - ) - response = client.get_all_workspaces() - assert response.code == 404 - - def test_get_all_workspaces_success( client: SyncGeoServerX, good_workspaces_connection, respx_mock ): @@ -52,14 +42,26 @@ def test_get_all_workspaces_NetworkError(client: SyncGeoServerX, respx_mock): # Test - get_workspace +@pytest_mark.parametrize( + "workspace_name,status_code,response_data,expected_response", + [ + ("sfsf", 404, {"error": "not found"}, "Result not found"), + ], +) def test_get_workspace_validation( - client: SyncGeoServerX, bad_workspace_connection, respx_mock + client: SyncGeoServerX, + respx_mock, + workspace_name, + status_code, + response_data, + expected_response, ): - respx_mock.get(f"{baseUrl}workspaces/sfsf").mock( - return_value=httpx.Response(404, json=bad_workspace_connection) + respx_mock.get(f"{baseUrl}workspaces/{workspace_name}").mock( + return_value=httpx.Response(status_code, json=response_data) ) - response = client.get_workspace("sfsf") - assert response.response == "Result not found" + + response = client.get_workspace(workspace_name) + assert response.response == expected_response def test_get_workspace_success( @@ -78,6 +80,64 @@ def test_get_workspace_ConnectError(client: SyncGeoServerX, respx_mock): assert response.response == "Error in connecting to Geoserver" +# Test - update_workspace +@pytest_mark.parametrize( + "workspace_name,status_code,response_data,expected_response", + [ + ("tiger", 404, {"error": "not found"}, "Result not found"), + ], +) +def test_update_workspace_validation( + client: SyncGeoServerX, + respx_mock, + workspace_name, + status_code, + response_data, + expected_response, +): + respx_mock.put(f"{baseUrl}workspaces/{workspace_name}.json").mock( + return_value=httpx.Response(status_code, json=response_data) + ) + response = client.update_workspace( + workspace_name, UpdateWorkspaceInfo(isolated=True) + ) + assert response.response == expected_response + + +@pytest_mark.parametrize( + "workspace_name,workspace_info,status_code,response_data", + [ + ( + "tiger", + UpdateWorkspaceInfo(isolated=True), + 200, + {"workspace": {"isolated": True}}, + ) + ], +) +def test_update_workspace_success( + client: SyncGeoServerX, + respx_mock, + workspace_name, + workspace_info, + status_code, + response_data, +): + respx_mock.put(f"{baseUrl}workspaces/{workspace_name}.json").mock( + return_value=httpx.Response(status_code, json=response_data) + ) + response = client.update_workspace(workspace_name, workspace_info) + assert response.code == status_code + + +def test_update_workspace_ConnectError(client: SyncGeoServerX, respx_mock): + respx_mock.put(f"{baseUrl}workspaces/tiger.json").mock( + side_effect=httpx.ConnectError + ) + response = client.update_workspace("tiger", UpdateWorkspaceInfo(isolated=True)) + assert response.response == "Error in connecting to Geoserver" + + # Test - get_vector_stores_in_workspaces def test_get_vector_stores_in_workspaces_validation( client: SyncGeoServerX, invalid_datastores_model_connection, respx_mock @@ -256,7 +316,7 @@ def test_get_style_ConnectError(client: SyncGeoServerX, respx_mock): def test_create_workspace_validation( client: SyncGeoServerX, invalid_new_workspace_connection, respx_mock ): - respx_mock.post(f"{baseUrl}workspaces?default=False").mock( + respx_mock.post(f"{baseUrl}workspaces", params={"default": False}).mock( return_value=httpx.Response(404, json=invalid_new_workspace_connection) ) response = client.create_workspace("pydad", False, True) @@ -266,7 +326,7 @@ def test_create_workspace_validation( def test_create_workspace_success( client: SyncGeoServerX, good_new_workspace_connection, respx_mock ): - respx_mock.post(f"{baseUrl}workspaces?default=False").mock( + respx_mock.post(f"{baseUrl}workspaces", params={"default": False}).mock( return_value=httpx.Response(201, json=good_new_workspace_connection) ) response = client.create_workspace("pydad", False, True) @@ -274,7 +334,7 @@ def test_create_workspace_success( def test_create_workspace_ConnectError(client: SyncGeoServerX, respx_mock): - respx_mock.post(f"{baseUrl}workspaces?default=False").mock( + respx_mock.post(f"{baseUrl}workspaces", params={"default": False}).mock( side_effect=httpx.ConnectError ) response = client.create_workspace("pydad", False, True) diff --git a/tests/cli/test_cli.py b/tests/cli/test_cli.py index c4ea456..6adaac6 100644 --- a/tests/cli/test_cli.py +++ b/tests/cli/test_cli.py @@ -1,4 +1,5 @@ import httpx +import pytest from typer.testing import CliRunner from geoserverx.cli.cli import app @@ -8,49 +9,121 @@ baseUrl = "http://127.0.0.1:8080/geoserver/rest/" -# Test - get_all_workspaces -def test_get_all_workspaces_validation(bad_workspaces_connection, respx_mock): +# Test - workspaces +def test_get_all_workspaces_success(respx_mock): + """Test getting all workspaces""" + # Test data + workspace_response = { + "workspaces": { + "workspace": [ + { + "name": "aa", + "href": "http://127.0.0.1:8080/geoserver/rest/workspaces/aa.json", + }, + { + "name": "aaba", + "href": "http://127.0.0.1:8080/geoserver/rest/workspaces/aaba.json", + }, + ] + } + } + # Mock the response respx_mock.get(f"{baseUrl}workspaces").mock( - return_value=httpx.Response(404, json=bad_workspaces_connection) + return_value=httpx.Response(200, json=workspace_response) ) - result = runner.invoke(app, ["workspaces"]) - assert "404" in result.stdout - - -def test_get_all_workspaces_success(good_workspaces_connection, respx_mock): - respx_mock.get(f"{baseUrl}workspaces").mock( - return_value=httpx.Response(200, json=good_workspaces_connection) - ) - result = runner.invoke(app, ["workspaces"]) - assert "pydad" in result.stdout - - -def test_get_all_workspaces_NetworkError(respx_mock): - respx_mock.get(f"{baseUrl}workspaces").mock(side_effect=httpx.ConnectError) - result = runner.invoke(app, ["workspaces"]) - assert "Error in connecting to Geoserver" in result.stdout + # Invoke the command + result = runner.invoke(app, ["workspaces", "--output", "json"]) + # Assertions + assert result.exit_code == 0 + for workspace in workspace_response["workspaces"]["workspace"]: + assert workspace["name"] in result.output # Test - get_workspace -def test_get_workspace_validation(bad_workspace_connection, respx_mock): - respx_mock.get(f"{baseUrl}workspaces/sfsf").mock( - return_value=httpx.Response(404, json=bad_workspace_connection) +@pytest.mark.parametrize( + "workspace_name,status_code,response_data,expected_response", + [ + ( + "sfsf", + 404, + {"code": 404, "response": "Result not found"}, + "Result not found", + ), + ], +) +def test_get_workspace_validation( + workspace_name, status_code, response_data, expected_response, respx_mock +): + respx_mock.get(f"{baseUrl}workspaces/{workspace_name}").mock( + return_value=httpx.Response(status_code, json=response_data) ) - result = runner.invoke(app, ["workspace", "--workspace", "sfsf"]) - assert "Result not found" in result.stdout + result = runner.invoke(app, ["workspace", "sfsf"]) + assert expected_response in result.stdout def test_get_workspace_success(good_workspace_connection, respx_mock): respx_mock.get(f"{baseUrl}workspaces/pydad").mock( return_value=httpx.Response(200, json=good_workspace_connection) ) - result = runner.invoke(app, ["workspace", "--workspace", "pydad"]) + result = runner.invoke(app, ["workspace", "pydad"]) assert "pydad" in result.stdout def test_get_workspace_ConnectError(respx_mock): respx_mock.get(f"{baseUrl}workspaces/pydad").mock(side_effect=httpx.ConnectError) - result = runner.invoke(app, ["workspace", "--workspace", "pydad"]) + result = runner.invoke(app, ["workspace", "pydad"]) + assert "Error in connecting to Geoserver" in result.stdout + + +# Test - update_workspace +@pytest.mark.parametrize( + "workspace_name,status_code,response_data,expected_response", + [ + ( + "tiger", + 404, + {"code": 404, "response": "Result not found"}, + "Result not found", + ), + ], +) +def test_update_workspace_validation( + respx_mock, workspace_name, status_code, response_data, expected_response +): + respx_mock.put(f"{baseUrl}workspaces/{workspace_name}.json").mock( + return_value=httpx.Response(status_code, json=response_data) + ) + result = runner.invoke(app, ["update-workspace", workspace_name, "--isolated"]) + assert expected_response in result.stdout + + +@pytest.mark.parametrize( + "workspace_name,workspace_info,status_code,response_data", + [ + ( + "tiger", + "--isolated", + 200, + "Executed successfully", + ) + ], +) +def test_update_workspace_success( + respx_mock, workspace_name, workspace_info, status_code, response_data +): + respx_mock.put(f"{baseUrl}workspaces/{workspace_name}.json").mock( + return_value=httpx.Response(status_code, json=response_data) + ) + print(workspace_info) + result = runner.invoke(app, ["update-workspace", workspace_name, workspace_info]) + assert response_data in result.stdout + + +def test_update_workspace_ConnectError(respx_mock): + respx_mock.put(f"{baseUrl}workspaces/tiger.json").mock( + side_effect=httpx.ConnectError + ) + result = runner.invoke(app, ["update-workspace", "tiger", "--isolated"]) assert "Error in connecting to Geoserver" in result.stdout @@ -224,32 +297,32 @@ def test_get_style_ConnectError(respx_mock): # Test - create_workspace def test_create_workspace_validation(invalid_new_workspace_connection, respx_mock): - respx_mock.post(f"{baseUrl}workspaces?default=False").mock( + respx_mock.post(f"{baseUrl}workspaces", params={"default": False}).mock( return_value=httpx.Response(404, json=invalid_new_workspace_connection) ) result = runner.invoke( app, - ["create-workspace", "--workspace", "burg", "--no-default", "--no-isolated"], + ["create-workspace", "burg", "--no-default", "--no-isolated"], ) assert "Result not found" in result.stdout def test_create_workspace_success(good_new_workspace_connection, respx_mock): - respx_mock.post(f"{baseUrl}workspaces?default=False").mock( + respx_mock.post(f"{baseUrl}workspaces", params={"default": False}).mock( return_value=httpx.Response(201, json=good_new_workspace_connection) ) result = runner.invoke( - app, ["create-workspace", "--workspace", "pydad", "--no-default", "--isolated"] + app, ["create-workspace", "pydad", "--no-default", "--isolated"] ) assert "Data added successfully" in result.stdout def test_create_workspace_ConnectError(respx_mock): - respx_mock.post(f"{baseUrl}workspaces?default=False").mock( + respx_mock.post(f"{baseUrl}workspaces", params={"default": False}).mock( side_effect=httpx.ConnectError ) result = runner.invoke( - app, ["create-workspace", "--workspace", "pydad", "--no-default", "--isolated"] + app, ["create-workspace", "pydad", "--no-default", "--isolated"] ) assert "Error in connecting to Geoserver" in result.stdout @@ -355,7 +428,6 @@ def test_get_layer_success(good_layer_connection, respx_mock): return_value=httpx.Response(200, json=good_layer_connection) ) result = runner.invoke(app, ["layer", "--workspace", "tiger", "--layer", "poi"]) - print(result) assert "poi" in result.stdout diff --git a/tests/conftest.py b/tests/conftest.py index 2b7c004..a80286e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -24,12 +24,6 @@ def good_workspaces_connection() -> dict: return item -@pytest.fixture -def bad_workspaces_connection() -> dict: - item = {"code": 502} - return item - - @pytest.fixture def good_workspace_connection() -> dict: item = { @@ -47,17 +41,11 @@ def good_workspace_connection() -> dict: @pytest.fixture -def bad_workspace_connection() -> dict: +def invalid_update_workspace_connection() -> dict: item = {"code": 404, "response": "Result not found"} return item -@pytest.fixture -def networkbad_workspace_connection() -> dict: - item = {"code": 503, "response": "Geoserver unavailable"} - return item - - @pytest.fixture def good_datastore_in_bulk_connection() -> dict: item = {"name": "just", "href": "https://www.linkedin.com/notifications/"} @@ -410,11 +398,11 @@ def good_all_styles_model_connection() -> dict: "style": [ { "name": "CUSD 2020 Census Blocks", - "href": "http://localhost:8080/geoserver/rest/styles/CUSD+2020+Census+Blocks.json", + "href": "http://localhost:8080/geoserver/rest/styles/CUSD.json", }, { "name": "Default Styler", - "href": "http://localhost:8080/geoserver/rest/styles/Default+Styler.json", + "href": "http://localhost:8080/geoserver/rest/styles/Default.json", }, ] }