diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 000000000..d8f8d4692 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +docs diff --git a/docs/framework/custom-server.mdx b/docs/framework/custom-server.mdx index 5b2c241ad..6129a62dd 100644 --- a/docs/framework/custom-server.mdx +++ b/docs/framework/custom-server.mdx @@ -58,9 +58,10 @@ Note the inclusion of the imported `ws_max_size` setting. This is important for Fine-tuning Uvicorn allows you to set up SSL, configure proxy headers, etc, which can prove vital in complex deployments. -Use server setup hook +If you want to disable server setup hook, you should use `enable_server_setup`: + ```python -asgi_app = writer.serve.get_asgi_app(app_path, mode, enable_server_setup=True) +asgi_app = writer.serve.get_asgi_app(app_path, mode, enable_server_setup=False) ``` ## Multiple apps at once diff --git a/docs/framework/images/tutorial/release_notes/release_gen_1.png b/docs/framework/images/tutorial/release_notes/release_gen_1.png new file mode 100644 index 000000000..46d014b02 Binary files /dev/null and b/docs/framework/images/tutorial/release_notes/release_gen_1.png differ diff --git a/docs/framework/images/tutorial/release_notes/release_gen_2.png b/docs/framework/images/tutorial/release_notes/release_gen_2.png new file mode 100644 index 000000000..37d4c1a55 Binary files /dev/null and b/docs/framework/images/tutorial/release_notes/release_gen_2.png differ diff --git a/docs/framework/images/tutorial/release_notes/release_gen_3.png b/docs/framework/images/tutorial/release_notes/release_gen_3.png new file mode 100644 index 000000000..405d53d3f Binary files /dev/null and b/docs/framework/images/tutorial/release_notes/release_gen_3.png differ diff --git a/docs/framework/images/tutorial/release_notes/release_gen_4.png b/docs/framework/images/tutorial/release_notes/release_gen_4.png new file mode 100644 index 000000000..3a197bb9b Binary files /dev/null and b/docs/framework/images/tutorial/release_notes/release_gen_4.png differ diff --git a/docs/framework/images/tutorial/release_notes/release_gen_5.png b/docs/framework/images/tutorial/release_notes/release_gen_5.png new file mode 100644 index 000000000..8a4491c45 Binary files /dev/null and b/docs/framework/images/tutorial/release_notes/release_gen_5.png differ diff --git a/docs/framework/images/tutorial/release_notes/release_gen_6.png b/docs/framework/images/tutorial/release_notes/release_gen_6.png new file mode 100644 index 000000000..6ad41d380 Binary files /dev/null and b/docs/framework/images/tutorial/release_notes/release_gen_6.png differ diff --git a/docs/framework/public/components/colorinput.png b/docs/framework/public/components/colorinput.png new file mode 100644 index 000000000..a0d96a8c5 Binary files /dev/null and b/docs/framework/public/components/colorinput.png differ diff --git a/docs/framework/public/components/jsonviewer.png b/docs/framework/public/components/jsonviewer.png new file mode 100644 index 000000000..2146de402 Binary files /dev/null and b/docs/framework/public/components/jsonviewer.png differ diff --git a/docs/framework/public/components/timeinput.png b/docs/framework/public/components/timeinput.png new file mode 100644 index 000000000..78b839001 Binary files /dev/null and b/docs/framework/public/components/timeinput.png differ diff --git a/docs/framework/release-notes-generator.mdx b/docs/framework/release-notes-generator.mdx new file mode 100644 index 000000000..e077d62fc --- /dev/null +++ b/docs/framework/release-notes-generator.mdx @@ -0,0 +1,412 @@ +--- +title: "Release notes generator" +--- +In this tutorial, you'll build a release notes generator using the Writer Framework. This application will help you generate release notes as formatted HTML for software updates based on user-provided data as a CSV file. You can check out the [finished code on GitHub](https://github.com/writer/framework-tutorials/tree/main/release-notes-generator/end) to see what you'll be building. + +The application consists of two main parts: the backend, which processes the uploaded CSV file and generates the release notes, and the frontend, which displays the release notes and allows users to download them. + +![Finished release notes generator application](/framework/images/tutorial/release_notes/release_gen_1.png) + +## Setting up your project +### Creating a Writer app and getting your API key + +From the Home screen, click on **Build an app**. + +![Writer home screen](/framework/images/tutorial/release_notes/release_gen_2.png) + +Select Framework as the app type you want to create, enabling you to generate keys and build your app with the Writer Framework. + +![App type selection](/framework/images/tutorial/release_notes/release_gen_3.png) + +On the next screen, you can edit your Writer application name at the top left. Underneath "Authenticate with an API key," click "Reveal" to view and copy your API key. + + +### Creating the application + +Next, open your terminal and navigate to the directory where you want to create your application directory. + + + + To pass your API key to the Writer Framework, you'll need to set an environment variable called `WRITER_API_KEY`. Here's how you can set this variable in your terminal session: + + + ```sh On macOS/Linux + export WRITER_API_KEY=[key] + ``` + + ```sh On Windows + set WRITER_API_KEY=[key] + ``` + + + + Run the following command to clone the `framework-tutorials` repo and navigate to the folder containing the starting point for this application. + + ``` + git clone https://github.com/writer/framework-tutorials.git + cd framework-tutorials/release-notes-generator/start + ``` + + + To edit your project, run the following commands. This will bring up the console, which displays Framework-wide messages and errors, including logs from the API. By default, the Writer Framework Builder is accessible at `localhost:3006`. If this port is in use, you can specify a different port. Open this address in your browser to view your default application setup. + + + ```bash Standard port + writer edit . + ``` + + ```bash Custom port + writer edit . --port=3007 + ``` + + + + +## Introduction to the application setup +The template includes some basic code, UI setup, and files to help you get started. + +### Included files +The files `prompts.py` and `html_template.py` contain helper functions for generating prompts for the AI model and formatting the output HTML, respectively. + +In the `sample-input` folder, you'll find a sample CSV file that you can use to test the application. + +Finally, the `custom.css` file in the `static` folder contains custom CSS styles for the application. + +### Dependency imports +In `main.py`, you'll see that the dependencies are already imported at the top: + +```python +import writer as wf +import writer.ai +import pandas as pd +from prompts import get_release_notes_summary_prompt, get_release_notes_desc_prompt, get_category_prompt +from html_template import format_output +``` + +These dependencies include the Writer Framework, the Writer AI module, and pandas for data manipulation. + +### Initial UI +The template includes a basic UI setup, including a Page component with a Header component. The Header component also includes an Image. If you want to change the logo image, you can replace the `logo_image_path` variable in the state with the path to your desired image in the `static` folder. + +## Building the release notes generator backend + +First, you'll create the backend for the release notes generator. Note that `prompts.py`, `html_template.py`, and `custom.css` are provided by the template used to generate the application. + +### Initializing the application state +First, set up the initial state for the application. This state will store the application's title, logo image path, file data, metrics, and processing status for each step. You'll also import a custom CSS file to style the application and create a placeholder DataFrame. + + + Create a placeholder DataFrame: + ```python + placeholder_data = { + 'Description': ['Description 1', 'Description 2', 'Description 3'], + 'Label': ['Label 1', 'Label 2', 'Label 3'] + } + initial_df = pd.DataFrame(placeholder_data) + ``` + + + Set up the initial state for the application: + ```python + initial_state = wf.init_state({ + "my_app": {"title": "MY APP"}, + "logo_image_path": 'static/Writer_Logo_black.svg', + "file": {"name": "", "file_path": ""}, + "metrics": {"new_features": 0, "caveats": 0, "fixed_issues": 0, "total": 0}, + "step1": { + "raw_csv": initial_df, + "completed": "no", + "generate-button-state": "yes", + "processing-message": None, + "styled-table": "

csv table

" + }, + "step2": { + "release-notes": None, + "completed": "no", + "formatted-release-notes": "notes should go here" + }, + }) + ``` +
+ + Import the custom CSS file below the initial state setup: + + ```python + initial_state.import_stylesheet(".description, .list, .summary, .category ", "/static/custom.css") + ``` + +
+ + +### Defining text completion functions +Next, using the prompts provided, define functions to get the category, release notes summary, and release notes description using AI completion. You'll use these functions to process the uploaded CSV file and generate release notes. + + + Define a function to get the category using AI completion: + ```python + def _get_category(desc, label): + prompt = get_category_prompt(desc, label) + label = writer.ai.complete(prompt) + return label + ``` + + + Define a function to get the release notes summary: + ```python + def _get_release_notes_summary(label, desc): + prompt = get_release_notes_summary_prompt(label, desc) + formatted_desc = writer.ai.complete(prompt) + return formatted_desc + ``` + + + Define a function to get the release notes description: + ```python + def _get_release_notes_desc(label, desc): + prompt = get_release_notes_desc_prompt(label, desc) + formatted_desc = writer.ai.complete(prompt) + return formatted_desc + ``` + + + +### Implementing file upload handler +Next, create a function to handle file uploads. This function will read the uploaded CSV file, process the data, and store it in the application state. + +```python +def onchangefile_handler(state, payload): + uploaded_file = payload[0] + name = uploaded_file.get("name") + state["file"]["name"] = name + state["step1"]["processing-message"] = f'+File {name} uploaded successfully.' + state["file"]["file_path"] = f"data/{name}" + file_data = uploaded_file.get("data") + with open(f"data/{name}", "wb") as file_handle: + file_handle.write(file_data) + + data = pd.read_csv(state["file"]["file_path"]) + df = pd.DataFrame(data) + state["step1"]["raw_csv"] = df + state["step1"]["generate-button-state"] = "no" +``` + +### Implementing helper functions +Next, define helper functions to handle back button clicks, write HTML to a file, download the HTML file, and generate HTML for each category. + + + Define a function to handle the back button click: + ```python + def handle_back_button_click(state): + state["step1"]["completed"] = "no" + ``` + + + Define a function to write HTML to a file: + ```python + def _write_html_to_file(html): + with open("data/output-html.html", "w") as file_handle: + file_handle.write(html) + ``` + + + Define a function to handle downloading the HTML file: + ```python + def handle_file_download(state): + html_data = wf.pack_file("data/output-html.html","text/html") + file_name = "output-html.html" + state.file_download(html_data,file_name) + ``` + + + Define a function to generate HTML for each category: + ```python + def _create_df_for_category(df,state): + unique_categories = df['Primary-Category'] + formatted_output_list = list() + for category in set(unique_categories): + df_category = df[df['Primary-Category']==category] + categories = {" New Feature": "new_features", " Caveat": "caveats", " Fixed Issue": "fixed_issues" } + curr_category = categories[category] + state["metrics"][curr_category]= df_category.shape[0] + formatted_output = format_output(category,df_category) + formatted_output_list.append(formatted_output) + return "".join(formatted_output_list) + ``` + + + Define a function to convert the CSV file to a DataFrame: + ```python + def _raw_csv_to_df(state): + data = pd.read_csv(state["file"]["file_path"]) + df = pd.DataFrame(data) + return df + ``` + + + +### Implementing the generate button handler +Finally, create a function to handle the generate button click. This function will process the uploaded CSV file, generate release notes, and store the formatted output in the application state. + +```python +def handle_generate_button_click(state): + state["step1"]["generate-button-state"] = "yes" + state["step1"]["processing-message-isVisible"] = True + state["step1"]["processing-message"] = "%Hang tight, preparing to process your file" + + notes_counter = 0 + df = _raw_csv_to_df(state) + csv_row_count = df.shape[0] + for index, row in df.iterrows(): + df.at[index,"Primary-Category"] = _get_category(label=row["Labels"], desc=row["Description"]) + df.at[index,"Release-Notes-Summary"] = _get_release_notes_summary(label=row["Labels"], desc=row["Description"]) + df.at[index,"Release-Notes-Description"] = _get_release_notes_desc(label=row["Labels"], desc=row["Description"]) + notes_counter += 1 + state["step1"]["processing-message"] = f'%Processing {notes_counter} of {csv_row_count} Release Notes' + + df_temp = df[["Primary-Category","Release-Notes-Summary","Release-Notes-Description"]] + df_sorted = df_temp.sort_values(by='Primary-Category') + + state["step2"]["release-notes"] = df_sorted + state["step1"]["completed"] = "yes" + state["step1"]["processing-message"] = "" + + html = _create_df_for_category(df_sorted,state) + _write_html_to_file(html) + state["step2"]["formatted-release-notes"] = html + state["metrics"]["total"] = df_sorted.shape[0] + + state["step1"]["generate-button-state"] = "no" +``` + +This completes the backend implementation. Next, you'll build the UI for the release notes generator. + +## Building the UI +With the code complete, you can now build the UI for the release notes generator. + +### Creating the main steps + +Add a Steps component to the Page. This will contain two main steps: "Load a CSV file" and "Release notes". + +#### Loading a CSV file step +First, you'll first build the UI for the "Load a CSV file" step. + + + + Create the first Step component and name it "Load a CSV file". Set IsCompleted to `@{step1.completed}`. + + + Within this Step, add a Message component with the message set to `@{step1.processing-message}`. Scroll down to the Visibility section of the settings. Select "Custom" and set the condition to `step1.processing-message`. + + + Add a Column Container component and add three Column components. For the first column, set the width to 0.5. For the third column, set "Content alignment (V)" to "Left" and "Content alignment (H)" to "Bottom." + + + In the middle column, place a File Input component labeled "Please upload your CSV file". Set its `wf-file-change` handler to `onchangefile_handler`. + + Below it, add another Message component displaying "+@\{file.name}". + + + In the second column, add a Button labeled "Generate release notes". Set its "Disabled" property to `@{step1.generate-button-state}` and its `wf-click` handler to `handle_generate_button_click`. You can also set the "Icon" property to `laps`. + + + Under the columns, create a Section component and set the title to "Raw CSV". + + + In this section, add a DataFrame component to display the raw CSV data. Configure its properties to use `@{step1.raw_csv}` as the data source. Toggle "Enable download," "Use Markdown," and "Text wrapping" to "yes". Set the Separator color to `#d4b2f7`. + + + +Your application should now look like this: + +![Release notes generator UI](/framework/images/tutorial/release_notes/release_gen_4.png) + +When using the sample data, the Raw CSV section will display the uploaded CSV file: + +![Raw CSV section](/framework/images/tutorial/release_notes/release_gen_5.png) + +#### Release notes step +Next, you'll build the UI for the "Release notes" step. To display the Release notes Step component, you'll need to double-click on it. + + + Create the second Step component and name it "Release notes". + + + Begin with a Separator component. + + + Follow with a Column Container component and a single Column component. + + + In the column, add a Button. Set its text to "Back" and set its `wf-click handler` to `handle_back_button_click`. Set the "Icon" property to `arrow_back`. + + + +### Tabs for Release notes display + +Below the Back button, add a Tabs component with two tabs: "Formatted release notes" and "Release notes". + +#### Formatted release notes tab +In the first tab, you'll display the formatted release notes. + + + In the first tab, add an HTML component. Set the "Element" property `div` and the "Styles" property to the following object: + + ``` + { + "padding": "16px", + "min-height": "64px", + "min-width": "64px", + "border-radius": "8px", + "background": "white", + } + ``` + + Finally, set the "HTML inside" property to `@{step2.formatted-release-notes}`. + + + Inside this component, create a three-column layout using a Column Container component and three Column components. + + + In each column, add three Metric components to display new features, caveats, and fixed issues, respectively. + Set the values of these components to `@{metrics.new_features}`, `@{metrics.caveats}`, and `@{metrics.fixed_issues}`. Then, set the Note text to "+New Features", "+Caveats", and "+Fixed Issues" respectively. The "+" sign will display styling that indicates a positive message. + + + Under the columns, add a "Download HTML" Button with its `wf-click` handler set to `handle_file_download`. + + + +The Formatted release notes tab should look like this when using the sample data: + +![Formatted release notes tab](/framework/images/tutorial/release_notes/release_gen_1.png) + +#### Release notes tab +Finally, you'll add a Dataframe component to the second tab to display the detailed release notes. + + + In the second tab, start with a Metric component to show the total number of release notes generated. Set the "Name" to "Number of release notes generated" and the "Value" to `@{metrics.total}`. + + + Follow this with a DataFrame component to display the detailed release notes, setting the "Data" property to `@{step2.release-notes}`. Configure it for text wrapping, downloading, and searching capabilities. Set the Separator color to `#d4b2f7`. + + + +The final Release notes section should look like this: + +![Release notes final UI](/framework/images/tutorial/release_notes/release_gen_6.png) + +You can [see the finished code on GitHub](https://github.com/writer/framework-tutorials/tree/main/release-notes-generator/end) or in `framework-tutorials/release-notes-generator/end` in the `tutorials` repo you cloned at the beginning of the tutorial. + +## Deploying the application + +To deploy the application to the Writer cloud, either terminate your current Writer Framework process or open a new terminal session and run the following command: + +``` +writer deploy . +``` + +You'll be prompted for your API key. + +Once the application is deployed, the CLI will return with the URL of your live application. + +## Conclusion +By following these steps, you've created a complete Release notes generator application using Writer Framework. To learn more, explore the rest of the Writer Framework documentation and the API documentation. \ No newline at end of file diff --git a/docs/mint.json b/docs/mint.json new file mode 100644 index 000000000..15e0eab03 --- /dev/null +++ b/docs/mint.json @@ -0,0 +1,158 @@ +{ + "$schema": "https://mintlify.com/schema.json", + "name": "Starter Kit", + "logo": { + "dark": "/logo/dark.svg", + "light": "/logo/writer_logo.svg" + }, + "favicon": "../favicon.svg", + "colors": { + "primary": "#0D9373", + "light": "#07C983", + "dark": "#0D9373", + "anchors": { + "from": "#0D9373", + "to": "#07C983" + } + }, + "tabs": [ + { + "name": "Framework", + "url": "framework" + }, + { + "name": "Components", + "url": "docs/components" + } + ], + "navigation": [ + { + "group": "Getting started", + "pages": [ + "framework/introduction", + "framework/quickstart", + "framework/ai-module" + ] + }, + { + "group": "Guides", + "pages": [ + "framework/application-state", + "framework/event-handlers", + "framework/builder-basics", + "framework/handling-inputs", + "framework/backend-driven-ui", + "framework/stylesheets", + "framework/frontend-scripts", + "framework/custom-components", + "framework/authentication" + ] + }, + { + "group": "Tutorials", + "pages": [ + "framework/chat-assistant", + "framework/social-post-generator", + "framework/product-description-generator", + "framework/release-notes-generator" + ] + }, + { + "group": "Deployment", + "pages": [ + "framework/deploy-with-docker", + "framework/testing" + ] + }, + { + "group": "Advanced", + "pages": [ + "framework/repeater", + "framework/backend-initiated-actions", + "framework/page-routes", + "framework/sessions", + "framework/custom-server", + "framework/state-schema" + ] + }, + { + "group": "Layout", + "pages": [ + "components/column", + "components/columns", + "components/header", + "components/horizontalstack", + "components/section", + "components/separator", + "components/sidebar", + "components/step", + "components/steps", + "components/tab", + "components/tabs" + ] + }, + { + "group": "Content", + "pages": [ + "components/avatar", + "components/chatbot", + "components/dataframe", + "components/heading", + "components/icon", + "components/image", + "components/link", + "components/message", + "components/metric", + "components/plotlygraph", + "components/tags", + "components/text", + "components/vegalitechart", + "components/videoplayer" + ] + }, + { + "group": "Input", + "pages": [ + "components/checkboxinput", + "components/dateinput", + "components/dropdowninput", + "components/fileinput", + "components/multiselectinput", + "components/numberinput", + "components/radioinput", + "components/ratinginput", + "components/selectinput", + "components/sliderinput", + "components/switchinput", + "components/textareainput", + "components/textinput" + ] + }, + { + "group": "Other", + "pages": [ + "components/button", + "components/html", + "components/pagination", + "components/repeater", + "components/reuse", + "components/timer", + "components/webcamcapture" + ] + }, + { + "group": "Embed", + "pages": [ + "components/googlemaps", + "components/mapbox", + "components/pdf", + "components/iframe" + ] + } + ], + "footerSocials": { + "x": "https://x.com/mintlify", + "github": "https://github.com/mintlify", + "linkedin": "https://www.linkedin.com/company/mintsearch" + } +} diff --git a/docs/package.json b/docs/package.json index ce219979e..21cc0e7c7 100644 --- a/docs/package.json +++ b/docs/package.json @@ -4,7 +4,7 @@ "description": "", "type": "module", "scripts": { - "preview": "cd docs; mintlify dev", + "preview": "mintlify dev", "test": "jest", "codegen": "node codegen/generator_components_pages.mjs" }, diff --git a/mint.json b/mint.json deleted file mode 100644 index 96eb0d947..000000000 --- a/mint.json +++ /dev/null @@ -1,154 +0,0 @@ -{ - "$schema": "https://mintlify.com/schema.json", - "name": "Starter Kit", - "logo": { - "dark": "/logo/dark.svg", - "light": "/logo/writer_logo.svg" - }, - "favicon": "/favicon.svg", - "colors": { - "primary": "#0D9373", - "light": "#07C983", - "dark": "#0D9373", - "anchors": { - "from": "#0D9373", - "to": "#07C983" - } - }, - "tabs": [ - { - "name": "Framework", - "url": "docs/framework" - }, - { - "name": "Components", - "url": "docs/components" - } - ], - "navigation": [ - { - "group": "Getting started", - "pages": [ - "docs/framework/introduction", - "docs/framework/quickstart", - "docs/framework/ai-module" - ] - }, - { - "group": "Guides", - "pages": [ - "docs/framework/application-state", - "docs/framework/event-handlers", - "docs/framework/builder-basics", - "docs/framework/handling-inputs", - "docs/framework/backend-driven-ui", - "docs/framework/stylesheets", - "docs/framework/frontend-scripts", - "docs/framework/custom-components", - "docs/framework/authentication" - ] - }, - { - "group": "Tutorials", - "pages": [ - "docs/framework/chat-assistant", - "docs/framework/social-post-generator", - "docs/framework/product-description-generator" - ] - }, - { - "group": "Deployment", - "pages": ["docs/framework/deploy-with-docker", "docs/framework/testing"] - }, - { - "group": "Advanced", - "pages": [ - "docs/framework/repeater", - "docs/framework/backend-initiated-actions", - "docs/framework/page-routes", - "docs/framework/sessions", - "docs/framework/custom-server", - "docs/framework/state-schema" - ] - }, - { - "group": "Layout", - "pages": [ - "docs/components/column", - "docs/components/columns", - "docs/components/header", - "docs/components/horizontalstack", - "docs/components/section", - "docs/components/separator", - "docs/components/sidebar", - "docs/components/step", - "docs/components/steps", - "docs/components/tab", - "docs/components/tabs" - ] - }, - { - "group": "Content", - "pages": [ - "docs/components/avatar", - "docs/components/chatbot", - "docs/components/dataframe", - "docs/components/heading", - "docs/components/icon", - "docs/components/image", - "docs/components/link", - "docs/components/message", - "docs/components/metric", - "docs/components/plotlygraph", - "docs/components/tags", - "docs/components/text", - "docs/components/vegalitechart", - "docs/components/videoplayer" - ] - }, - { - "group": "Input", - "pages": [ - "docs/components/checkboxinput", - "docs/components/dateinput", - "docs/components/dropdowninput", - "docs/components/fileinput", - "docs/components/multiselectinput", - "docs/components/numberinput", - "docs/components/radioinput", - "docs/components/ratinginput", - "docs/components/selectinput", - "docs/components/sliderinput", - "docs/components/switchinput", - "docs/components/textareainput", - "docs/components/textinput" - ] - }, - { - "group": "Other", - "pages": [ - "docs/components/button", - "docs/components/html", - "docs/components/pagination", - "docs/components/repeater", - "docs/components/reuse", - "docs/components/timer", - "docs/components/webcamcapture" - ] - }, - { - "group": "Embed", - "pages": [ - "docs/components/googlemaps", - "docs/components/mapbox", - "docs/components/pdf", - "docs/components/iframe" - ] - } - ], - "footerSocials": { - "x": "https://x.com/mintlify", - "github": "https://github.com/mintlify", - "linkedin": "https://www.linkedin.com/company/mintsearch" - } -} diff --git a/package-lock.json b/package-lock.json index b8fdb618a..cc0ba2909 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2587,6 +2587,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@fontsource-variable/material-symbols-outlined": { + "version": "5.0.34", + "resolved": "https://registry.npmjs.org/@fontsource-variable/material-symbols-outlined/-/material-symbols-outlined-5.0.34.tgz", + "integrity": "sha512-dC6BoXU93VMjNlfbn4YRdqsSOFp6Smue2KZgZJ8wy2x0OeyA73hgJyb5i6mV6JZnuaiJHMwqTfwJQ3FtSPKFnw==" + }, + "node_modules/@fontsource/poppins": { + "version": "5.0.14", + "resolved": "https://registry.npmjs.org/@fontsource/poppins/-/poppins-5.0.14.tgz", + "integrity": "sha512-nmM1zpPo3Uh4JcGAVSQuWaZNYh2FbbwWhZ5t6hRaynmJaNTBW85d3nEh9zMmzI0HX7X5xqQVdRHeDatKpOGsnA==" + }, "node_modules/@googlemaps/js-api-loader": { "version": "1.16.6", "resolved": "https://registry.npmjs.org/@googlemaps/js-api-loader/-/js-api-loader-1.16.6.tgz", @@ -11771,6 +11781,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/fuse.js": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.0.0.tgz", + "integrity": "sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q==", + "engines": { + "node": ">=10" + } + }, "node_modules/gauge": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", @@ -23090,11 +23108,14 @@ "version": "0.0.0", "dependencies": { "@apache-arrow/ts": "^15.0.2", + "@fontsource-variable/material-symbols-outlined": "^5.0.34", + "@fontsource/poppins": "^5.0.14", "@googlemaps/js-api-loader": "^1.16.6", "@monaco-editor/loader": "^1.3.3", "@tato30/vue-pdf": "^1.9.6", "arquero": "^5.2.0", "chroma-js": "^2.4.2", + "fuse.js": "7.0.0", "mapbox-gl": "3.2.0", "marked": "^12.0.1", "monaco-editor": "^0.47.0", diff --git a/poetry.lock b/poetry.lock index a96a8c614..c487023af 100644 --- a/poetry.lock +++ b/poetry.lock @@ -110,13 +110,13 @@ cryptography = "*" [[package]] name = "certifi" -version = "2024.6.2" +version = "2024.7.4" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"}, - {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"}, + {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, + {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, ] [[package]] @@ -394,13 +394,13 @@ wmi = ["wmi (>=1.5.1)"] [[package]] name = "email-validator" -version = "2.1.1" +version = "2.2.0" description = "A robust email address syntax and deliverability validation library." optional = false python-versions = ">=3.8" files = [ - {file = "email_validator-2.1.1-py3-none-any.whl", hash = "sha256:97d882d174e2a65732fb43bfce81a3a834cbc1bde8bf419e30ef5ea976370a05"}, - {file = "email_validator-2.1.1.tar.gz", hash = "sha256:200a70680ba08904be6d1eef729205cc0d687634399a5924d842533efb824b84"}, + {file = "email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631"}, + {file = "email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7"}, ] [package.dependencies] @@ -409,13 +409,13 @@ idna = ">=2.0.0" [[package]] name = "exceptiongroup" -version = "1.2.1" +version = "1.2.2" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, - {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, ] [package.extras] @@ -423,13 +423,13 @@ test = ["pytest (>=6)"] [[package]] name = "fastapi" -version = "0.111.0" +version = "0.111.1" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi-0.111.0-py3-none-any.whl", hash = "sha256:97ecbf994be0bcbdadedf88c3150252bed7b2087075ac99735403b1b76cc8fc0"}, - {file = "fastapi-0.111.0.tar.gz", hash = "sha256:b9db9dd147c91cb8b769f7183535773d8741dd46f9dc6676cd82eab510228cd7"}, + {file = "fastapi-0.111.1-py3-none-any.whl", hash = "sha256:4f51cfa25d72f9fbc3280832e84b32494cf186f50158d364a8765aabf22587bf"}, + {file = "fastapi-0.111.1.tar.gz", hash = "sha256:ddd1ac34cb1f76c2e2d7f8545a4bcb5463bce4834e81abf0b189e0c359ab2413"}, ] [package.dependencies] @@ -437,12 +437,10 @@ email_validator = ">=2.0.0" fastapi-cli = ">=0.0.2" httpx = ">=0.23.0" jinja2 = ">=2.11.2" -orjson = ">=3.2.1" pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" python-multipart = ">=0.0.7" starlette = ">=0.37.2,<0.38.0" typing-extensions = ">=4.8.0" -ujson = ">=4.0.1,<4.0.2 || >4.0.2,<4.1.0 || >4.1.0,<4.2.0 || >4.2.0,<4.3.0 || >4.3.0,<5.0.0 || >5.0.0,<5.1.0 || >5.1.0" uvicorn = {version = ">=0.12.0", extras = ["standard"]} [package.extras] @@ -620,13 +618,13 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "jsonschema" -version = "4.22.0" +version = "4.23.0" description = "An implementation of JSON Schema validation for Python" optional = false python-versions = ">=3.8" files = [ - {file = "jsonschema-4.22.0-py3-none-any.whl", hash = "sha256:ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802"}, - {file = "jsonschema-4.22.0.tar.gz", hash = "sha256:5b22d434a45935119af990552c862e5d6d564e8f6601206b305a61fdf661a2b7"}, + {file = "jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566"}, + {file = "jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4"}, ] [package.dependencies] @@ -637,7 +635,7 @@ rpds-py = ">=0.7.1" [package.extras] format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] -format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=24.6.0)"] [[package]] name = "jsonschema-specifications" @@ -759,38 +757,38 @@ files = [ [[package]] name = "mypy" -version = "1.10.0" +version = "1.10.1" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:da1cbf08fb3b851ab3b9523a884c232774008267b1f83371ace57f412fe308c2"}, - {file = "mypy-1.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:12b6bfc1b1a66095ab413160a6e520e1dc076a28f3e22f7fb25ba3b000b4ef99"}, - {file = "mypy-1.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e36fb078cce9904c7989b9693e41cb9711e0600139ce3970c6ef814b6ebc2b2"}, - {file = "mypy-1.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2b0695d605ddcd3eb2f736cd8b4e388288c21e7de85001e9f85df9187f2b50f9"}, - {file = "mypy-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:cd777b780312ddb135bceb9bc8722a73ec95e042f911cc279e2ec3c667076051"}, - {file = "mypy-1.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3be66771aa5c97602f382230165b856c231d1277c511c9a8dd058be4784472e1"}, - {file = "mypy-1.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8b2cbaca148d0754a54d44121b5825ae71868c7592a53b7292eeb0f3fdae95ee"}, - {file = "mypy-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ec404a7cbe9fc0e92cb0e67f55ce0c025014e26d33e54d9e506a0f2d07fe5de"}, - {file = "mypy-1.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e22e1527dc3d4aa94311d246b59e47f6455b8729f4968765ac1eacf9a4760bc7"}, - {file = "mypy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:a87dbfa85971e8d59c9cc1fcf534efe664d8949e4c0b6b44e8ca548e746a8d53"}, - {file = "mypy-1.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a781f6ad4bab20eef8b65174a57e5203f4be627b46291f4589879bf4e257b97b"}, - {file = "mypy-1.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b808e12113505b97d9023b0b5e0c0705a90571c6feefc6f215c1df9381256e30"}, - {file = "mypy-1.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f55583b12156c399dce2df7d16f8a5095291354f1e839c252ec6c0611e86e2e"}, - {file = "mypy-1.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4cf18f9d0efa1b16478c4c129eabec36148032575391095f73cae2e722fcf9d5"}, - {file = "mypy-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:bc6ac273b23c6b82da3bb25f4136c4fd42665f17f2cd850771cb600bdd2ebeda"}, - {file = "mypy-1.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9fd50226364cd2737351c79807775136b0abe084433b55b2e29181a4c3c878c0"}, - {file = "mypy-1.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f90cff89eea89273727d8783fef5d4a934be2fdca11b47def50cf5d311aff727"}, - {file = "mypy-1.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fcfc70599efde5c67862a07a1aaf50e55bce629ace26bb19dc17cece5dd31ca4"}, - {file = "mypy-1.10.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:075cbf81f3e134eadaf247de187bd604748171d6b79736fa9b6c9685b4083061"}, - {file = "mypy-1.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:3f298531bca95ff615b6e9f2fc0333aae27fa48052903a0ac90215021cdcfa4f"}, - {file = "mypy-1.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa7ef5244615a2523b56c034becde4e9e3f9b034854c93639adb667ec9ec2976"}, - {file = "mypy-1.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3236a4c8f535a0631f85f5fcdffba71c7feeef76a6002fcba7c1a8e57c8be1ec"}, - {file = "mypy-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a2b5cdbb5dd35aa08ea9114436e0d79aceb2f38e32c21684dcf8e24e1e92821"}, - {file = "mypy-1.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92f93b21c0fe73dc00abf91022234c79d793318b8a96faac147cd579c1671746"}, - {file = "mypy-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:28d0e038361b45f099cc086d9dd99c15ff14d0188f44ac883010e172ce86c38a"}, - {file = "mypy-1.10.0-py3-none-any.whl", hash = "sha256:f8c083976eb530019175aabadb60921e73b4f45736760826aa1689dda8208aee"}, - {file = "mypy-1.10.0.tar.gz", hash = "sha256:3d087fcbec056c4ee34974da493a826ce316947485cef3901f511848e687c131"}, + {file = "mypy-1.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e36f229acfe250dc660790840916eb49726c928e8ce10fbdf90715090fe4ae02"}, + {file = "mypy-1.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:51a46974340baaa4145363b9e051812a2446cf583dfaeba124af966fa44593f7"}, + {file = "mypy-1.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:901c89c2d67bba57aaaca91ccdb659aa3a312de67f23b9dfb059727cce2e2e0a"}, + {file = "mypy-1.10.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0cd62192a4a32b77ceb31272d9e74d23cd88c8060c34d1d3622db3267679a5d9"}, + {file = "mypy-1.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:a2cbc68cb9e943ac0814c13e2452d2046c2f2b23ff0278e26599224cf164e78d"}, + {file = "mypy-1.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bd6f629b67bb43dc0d9211ee98b96d8dabc97b1ad38b9b25f5e4c4d7569a0c6a"}, + {file = "mypy-1.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a1bbb3a6f5ff319d2b9d40b4080d46cd639abe3516d5a62c070cf0114a457d84"}, + {file = "mypy-1.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8edd4e9bbbc9d7b79502eb9592cab808585516ae1bcc1446eb9122656c6066f"}, + {file = "mypy-1.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6166a88b15f1759f94a46fa474c7b1b05d134b1b61fca627dd7335454cc9aa6b"}, + {file = "mypy-1.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:5bb9cd11c01c8606a9d0b83ffa91d0b236a0e91bc4126d9ba9ce62906ada868e"}, + {file = "mypy-1.10.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d8681909f7b44d0b7b86e653ca152d6dff0eb5eb41694e163c6092124f8246d7"}, + {file = "mypy-1.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:378c03f53f10bbdd55ca94e46ec3ba255279706a6aacaecac52ad248f98205d3"}, + {file = "mypy-1.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bacf8f3a3d7d849f40ca6caea5c055122efe70e81480c8328ad29c55c69e93e"}, + {file = "mypy-1.10.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:701b5f71413f1e9855566a34d6e9d12624e9e0a8818a5704d74d6b0402e66c04"}, + {file = "mypy-1.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:3c4c2992f6ea46ff7fce0072642cfb62af7a2484efe69017ed8b095f7b39ef31"}, + {file = "mypy-1.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:604282c886497645ffb87b8f35a57ec773a4a2721161e709a4422c1636ddde5c"}, + {file = "mypy-1.10.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37fd87cab83f09842653f08de066ee68f1182b9b5282e4634cdb4b407266bade"}, + {file = "mypy-1.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8addf6313777dbb92e9564c5d32ec122bf2c6c39d683ea64de6a1fd98b90fe37"}, + {file = "mypy-1.10.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cc3ca0a244eb9a5249c7c583ad9a7e881aa5d7b73c35652296ddcdb33b2b9c7"}, + {file = "mypy-1.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:1b3a2ffce52cc4dbaeee4df762f20a2905aa171ef157b82192f2e2f368eec05d"}, + {file = "mypy-1.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe85ed6836165d52ae8b88f99527d3d1b2362e0cb90b005409b8bed90e9059b3"}, + {file = "mypy-1.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2ae450d60d7d020d67ab440c6e3fae375809988119817214440033f26ddf7bf"}, + {file = "mypy-1.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6be84c06e6abd72f960ba9a71561c14137a583093ffcf9bbfaf5e613d63fa531"}, + {file = "mypy-1.10.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2189ff1e39db399f08205e22a797383613ce1cb0cb3b13d8bcf0170e45b96cc3"}, + {file = "mypy-1.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:97a131ee36ac37ce9581f4220311247ab6cba896b4395b9c87af0675a13a755f"}, + {file = "mypy-1.10.1-py3-none-any.whl", hash = "sha256:71d8ac0b906354ebda8ef1673e5fde785936ac1f29ff6987c7483cfbd5a4235a"}, + {file = "mypy-1.10.1.tar.gz", hash = "sha256:1f8f492d7db9e3593ef42d4f115f04e556130f2819ad33ab84551403e97dd4c0"}, ] [package.dependencies] @@ -860,70 +858,15 @@ files = [ {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, ] -[[package]] -name = "orjson" -version = "3.10.3" -description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" -optional = false -python-versions = ">=3.8" -files = [ - {file = "orjson-3.10.3-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9fb6c3f9f5490a3eb4ddd46fc1b6eadb0d6fc16fb3f07320149c3286a1409dd8"}, - {file = "orjson-3.10.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:252124b198662eee80428f1af8c63f7ff077c88723fe206a25df8dc57a57b1fa"}, - {file = "orjson-3.10.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9f3e87733823089a338ef9bbf363ef4de45e5c599a9bf50a7a9b82e86d0228da"}, - {file = "orjson-3.10.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8334c0d87103bb9fbbe59b78129f1f40d1d1e8355bbed2ca71853af15fa4ed3"}, - {file = "orjson-3.10.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1952c03439e4dce23482ac846e7961f9d4ec62086eb98ae76d97bd41d72644d7"}, - {file = "orjson-3.10.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c0403ed9c706dcd2809f1600ed18f4aae50be263bd7112e54b50e2c2bc3ebd6d"}, - {file = "orjson-3.10.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:382e52aa4270a037d41f325e7d1dfa395b7de0c367800b6f337d8157367bf3a7"}, - {file = "orjson-3.10.3-cp310-none-win32.whl", hash = "sha256:be2aab54313752c04f2cbaab4515291ef5af8c2256ce22abc007f89f42f49109"}, - {file = "orjson-3.10.3-cp310-none-win_amd64.whl", hash = "sha256:416b195f78ae461601893f482287cee1e3059ec49b4f99479aedf22a20b1098b"}, - {file = "orjson-3.10.3-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:73100d9abbbe730331f2242c1fc0bcb46a3ea3b4ae3348847e5a141265479700"}, - {file = "orjson-3.10.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:544a12eee96e3ab828dbfcb4d5a0023aa971b27143a1d35dc214c176fdfb29b3"}, - {file = "orjson-3.10.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:520de5e2ef0b4ae546bea25129d6c7c74edb43fc6cf5213f511a927f2b28148b"}, - {file = "orjson-3.10.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ccaa0a401fc02e8828a5bedfd80f8cd389d24f65e5ca3954d72c6582495b4bcf"}, - {file = "orjson-3.10.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a7bc9e8bc11bac40f905640acd41cbeaa87209e7e1f57ade386da658092dc16"}, - {file = "orjson-3.10.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3582b34b70543a1ed6944aca75e219e1192661a63da4d039d088a09c67543b08"}, - {file = "orjson-3.10.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1c23dfa91481de880890d17aa7b91d586a4746a4c2aa9a145bebdbaf233768d5"}, - {file = "orjson-3.10.3-cp311-none-win32.whl", hash = "sha256:1770e2a0eae728b050705206d84eda8b074b65ee835e7f85c919f5705b006c9b"}, - {file = "orjson-3.10.3-cp311-none-win_amd64.whl", hash = "sha256:93433b3c1f852660eb5abdc1f4dd0ced2be031ba30900433223b28ee0140cde5"}, - {file = "orjson-3.10.3-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a39aa73e53bec8d410875683bfa3a8edf61e5a1c7bb4014f65f81d36467ea098"}, - {file = "orjson-3.10.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0943a96b3fa09bee1afdfccc2cb236c9c64715afa375b2af296c73d91c23eab2"}, - {file = "orjson-3.10.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e852baafceff8da3c9defae29414cc8513a1586ad93e45f27b89a639c68e8176"}, - {file = "orjson-3.10.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18566beb5acd76f3769c1d1a7ec06cdb81edc4d55d2765fb677e3eaa10fa99e0"}, - {file = "orjson-3.10.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bd2218d5a3aa43060efe649ec564ebedec8ce6ae0a43654b81376216d5ebd42"}, - {file = "orjson-3.10.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cf20465e74c6e17a104ecf01bf8cd3b7b252565b4ccee4548f18b012ff2f8069"}, - {file = "orjson-3.10.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ba7f67aa7f983c4345eeda16054a4677289011a478ca947cd69c0a86ea45e534"}, - {file = "orjson-3.10.3-cp312-none-win32.whl", hash = "sha256:17e0713fc159abc261eea0f4feda611d32eabc35708b74bef6ad44f6c78d5ea0"}, - {file = "orjson-3.10.3-cp312-none-win_amd64.whl", hash = "sha256:4c895383b1ec42b017dd2c75ae8a5b862fc489006afde06f14afbdd0309b2af0"}, - {file = "orjson-3.10.3-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:be2719e5041e9fb76c8c2c06b9600fe8e8584e6980061ff88dcbc2691a16d20d"}, - {file = "orjson-3.10.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0175a5798bdc878956099f5c54b9837cb62cfbf5d0b86ba6d77e43861bcec2"}, - {file = "orjson-3.10.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:978be58a68ade24f1af7758626806e13cff7748a677faf95fbb298359aa1e20d"}, - {file = "orjson-3.10.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16bda83b5c61586f6f788333d3cf3ed19015e3b9019188c56983b5a299210eb5"}, - {file = "orjson-3.10.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ad1f26bea425041e0a1adad34630c4825a9e3adec49079b1fb6ac8d36f8b754"}, - {file = "orjson-3.10.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:9e253498bee561fe85d6325ba55ff2ff08fb5e7184cd6a4d7754133bd19c9195"}, - {file = "orjson-3.10.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0a62f9968bab8a676a164263e485f30a0b748255ee2f4ae49a0224be95f4532b"}, - {file = "orjson-3.10.3-cp38-none-win32.whl", hash = "sha256:8d0b84403d287d4bfa9bf7d1dc298d5c1c5d9f444f3737929a66f2fe4fb8f134"}, - {file = "orjson-3.10.3-cp38-none-win_amd64.whl", hash = "sha256:8bc7a4df90da5d535e18157220d7915780d07198b54f4de0110eca6b6c11e290"}, - {file = "orjson-3.10.3-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9059d15c30e675a58fdcd6f95465c1522b8426e092de9fff20edebfdc15e1cb0"}, - {file = "orjson-3.10.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d40c7f7938c9c2b934b297412c067936d0b54e4b8ab916fd1a9eb8f54c02294"}, - {file = "orjson-3.10.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d4a654ec1de8fdaae1d80d55cee65893cb06494e124681ab335218be6a0691e7"}, - {file = "orjson-3.10.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:831c6ef73f9aa53c5f40ae8f949ff7681b38eaddb6904aab89dca4d85099cb78"}, - {file = "orjson-3.10.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99b880d7e34542db89f48d14ddecbd26f06838b12427d5a25d71baceb5ba119d"}, - {file = "orjson-3.10.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2e5e176c994ce4bd434d7aafb9ecc893c15f347d3d2bbd8e7ce0b63071c52e25"}, - {file = "orjson-3.10.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b69a58a37dab856491bf2d3bbf259775fdce262b727f96aafbda359cb1d114d8"}, - {file = "orjson-3.10.3-cp39-none-win32.whl", hash = "sha256:b8d4d1a6868cde356f1402c8faeb50d62cee765a1f7ffcfd6de732ab0581e063"}, - {file = "orjson-3.10.3-cp39-none-win_amd64.whl", hash = "sha256:5102f50c5fc46d94f2033fe00d392588564378260d64377aec702f21a7a22912"}, - {file = "orjson-3.10.3.tar.gz", hash = "sha256:2b166507acae7ba2f7c315dcf185a9111ad5e992ac81f2d507aac39193c2c818"}, -] - [[package]] name = "packaging" -version = "24.0" +version = "24.1" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, - {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] [[package]] @@ -966,9 +909,9 @@ files = [ [package.dependencies] numpy = [ + {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, {version = ">=1.22.4", markers = "python_version < \"3.11\""}, {version = ">=1.23.2", markers = "python_version == \"3.11\""}, - {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" @@ -1088,13 +1031,13 @@ xlsxwriter = ["xlsxwriter"] [[package]] name = "prompt-toolkit" -version = "3.0.46" +version = "3.0.47" description = "Library for building powerful interactive command lines in Python" optional = false python-versions = ">=3.7.0" files = [ - {file = "prompt_toolkit-3.0.46-py3-none-any.whl", hash = "sha256:45abe60a8300f3c618b23c16c4bb98c6fc80af8ce8b17c7ae92db48db3ee63c1"}, - {file = "prompt_toolkit-3.0.46.tar.gz", hash = "sha256:869c50d682152336e23c4db7f74667639b5047494202ffe7670817053fd57795"}, + {file = "prompt_toolkit-3.0.47-py3-none-any.whl", hash = "sha256:0d7bfa67001d5e39d02c224b663abc33687405033a8c422d0d675a5a13361d10"}, + {file = "prompt_toolkit-3.0.47.tar.gz", hash = "sha256:1e1b29cb58080b1e69f207c893a1a7bf16d127a5c30c9d17a25a5d77792e5360"}, ] [package.dependencies] @@ -1161,109 +1104,122 @@ files = [ [[package]] name = "pydantic" -version = "2.7.3" +version = "2.8.2" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.7.3-py3-none-any.whl", hash = "sha256:ea91b002777bf643bb20dd717c028ec43216b24a6001a280f83877fd2655d0b4"}, - {file = "pydantic-2.7.3.tar.gz", hash = "sha256:c46c76a40bb1296728d7a8b99aa73dd70a48c3510111ff290034f860c99c419e"}, + {file = "pydantic-2.8.2-py3-none-any.whl", hash = "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8"}, + {file = "pydantic-2.8.2.tar.gz", hash = "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.18.4" -typing-extensions = ">=4.6.1" +pydantic-core = "2.20.1" +typing-extensions = [ + {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, + {version = ">=4.6.1", markers = "python_version < \"3.13\""}, +] [package.extras] email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.18.4" +version = "2.20.1" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.18.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f76d0ad001edd426b92233d45c746fd08f467d56100fd8f30e9ace4b005266e4"}, - {file = "pydantic_core-2.18.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:59ff3e89f4eaf14050c8022011862df275b552caef8082e37b542b066ce1ff26"}, - {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a55b5b16c839df1070bc113c1f7f94a0af4433fcfa1b41799ce7606e5c79ce0a"}, - {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4d0dcc59664fcb8974b356fe0a18a672d6d7cf9f54746c05f43275fc48636851"}, - {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8951eee36c57cd128f779e641e21eb40bc5073eb28b2d23f33eb0ef14ffb3f5d"}, - {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4701b19f7e3a06ea655513f7938de6f108123bf7c86bbebb1196eb9bd35cf724"}, - {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e00a3f196329e08e43d99b79b286d60ce46bed10f2280d25a1718399457e06be"}, - {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:97736815b9cc893b2b7f663628e63f436018b75f44854c8027040e05230eeddb"}, - {file = "pydantic_core-2.18.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6891a2ae0e8692679c07728819b6e2b822fb30ca7445f67bbf6509b25a96332c"}, - {file = "pydantic_core-2.18.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bc4ff9805858bd54d1a20efff925ccd89c9d2e7cf4986144b30802bf78091c3e"}, - {file = "pydantic_core-2.18.4-cp310-none-win32.whl", hash = "sha256:1b4de2e51bbcb61fdebd0ab86ef28062704f62c82bbf4addc4e37fa4b00b7cbc"}, - {file = "pydantic_core-2.18.4-cp310-none-win_amd64.whl", hash = "sha256:6a750aec7bf431517a9fd78cb93c97b9b0c496090fee84a47a0d23668976b4b0"}, - {file = "pydantic_core-2.18.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:942ba11e7dfb66dc70f9ae66b33452f51ac7bb90676da39a7345e99ffb55402d"}, - {file = "pydantic_core-2.18.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b2ebef0e0b4454320274f5e83a41844c63438fdc874ea40a8b5b4ecb7693f1c4"}, - {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a642295cd0c8df1b86fc3dced1d067874c353a188dc8e0f744626d49e9aa51c4"}, - {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f09baa656c904807e832cf9cce799c6460c450c4ad80803517032da0cd062e2"}, - {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:98906207f29bc2c459ff64fa007afd10a8c8ac080f7e4d5beff4c97086a3dabd"}, - {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19894b95aacfa98e7cb093cd7881a0c76f55731efad31073db4521e2b6ff5b7d"}, - {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fbbdc827fe5e42e4d196c746b890b3d72876bdbf160b0eafe9f0334525119c8"}, - {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f85d05aa0918283cf29a30b547b4df2fbb56b45b135f9e35b6807cb28bc47951"}, - {file = "pydantic_core-2.18.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e85637bc8fe81ddb73fda9e56bab24560bdddfa98aa64f87aaa4e4b6730c23d2"}, - {file = "pydantic_core-2.18.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2f5966897e5461f818e136b8451d0551a2e77259eb0f73a837027b47dc95dab9"}, - {file = "pydantic_core-2.18.4-cp311-none-win32.whl", hash = "sha256:44c7486a4228413c317952e9d89598bcdfb06399735e49e0f8df643e1ccd0558"}, - {file = "pydantic_core-2.18.4-cp311-none-win_amd64.whl", hash = "sha256:8a7164fe2005d03c64fd3b85649891cd4953a8de53107940bf272500ba8a788b"}, - {file = "pydantic_core-2.18.4-cp311-none-win_arm64.whl", hash = "sha256:4e99bc050fe65c450344421017f98298a97cefc18c53bb2f7b3531eb39bc7805"}, - {file = "pydantic_core-2.18.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:6f5c4d41b2771c730ea1c34e458e781b18cc668d194958e0112455fff4e402b2"}, - {file = "pydantic_core-2.18.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2fdf2156aa3d017fddf8aea5adfba9f777db1d6022d392b682d2a8329e087cef"}, - {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4748321b5078216070b151d5271ef3e7cc905ab170bbfd27d5c83ee3ec436695"}, - {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:847a35c4d58721c5dc3dba599878ebbdfd96784f3fb8bb2c356e123bdcd73f34"}, - {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c40d4eaad41f78e3bbda31b89edc46a3f3dc6e171bf0ecf097ff7a0ffff7cb1"}, - {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:21a5e440dbe315ab9825fcd459b8814bb92b27c974cbc23c3e8baa2b76890077"}, - {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01dd777215e2aa86dfd664daed5957704b769e726626393438f9c87690ce78c3"}, - {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4b06beb3b3f1479d32befd1f3079cc47b34fa2da62457cdf6c963393340b56e9"}, - {file = "pydantic_core-2.18.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:564d7922e4b13a16b98772441879fcdcbe82ff50daa622d681dd682175ea918c"}, - {file = "pydantic_core-2.18.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0eb2a4f660fcd8e2b1c90ad566db2b98d7f3f4717c64fe0a83e0adb39766d5b8"}, - {file = "pydantic_core-2.18.4-cp312-none-win32.whl", hash = "sha256:8b8bab4c97248095ae0c4455b5a1cd1cdd96e4e4769306ab19dda135ea4cdb07"}, - {file = "pydantic_core-2.18.4-cp312-none-win_amd64.whl", hash = "sha256:14601cdb733d741b8958224030e2bfe21a4a881fb3dd6fbb21f071cabd48fa0a"}, - {file = "pydantic_core-2.18.4-cp312-none-win_arm64.whl", hash = "sha256:c1322d7dd74713dcc157a2b7898a564ab091ca6c58302d5c7b4c07296e3fd00f"}, - {file = "pydantic_core-2.18.4-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:823be1deb01793da05ecb0484d6c9e20baebb39bd42b5d72636ae9cf8350dbd2"}, - {file = "pydantic_core-2.18.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ebef0dd9bf9b812bf75bda96743f2a6c5734a02092ae7f721c048d156d5fabae"}, - {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae1d6df168efb88d7d522664693607b80b4080be6750c913eefb77e34c12c71a"}, - {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f9899c94762343f2cc2fc64c13e7cae4c3cc65cdfc87dd810a31654c9b7358cc"}, - {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99457f184ad90235cfe8461c4d70ab7dd2680e28821c29eca00252ba90308c78"}, - {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18f469a3d2a2fdafe99296a87e8a4c37748b5080a26b806a707f25a902c040a8"}, - {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7cdf28938ac6b8b49ae5e92f2735056a7ba99c9b110a474473fd71185c1af5d"}, - {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:938cb21650855054dc54dfd9120a851c974f95450f00683399006aa6e8abb057"}, - {file = "pydantic_core-2.18.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:44cd83ab6a51da80fb5adbd9560e26018e2ac7826f9626bc06ca3dc074cd198b"}, - {file = "pydantic_core-2.18.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:972658f4a72d02b8abfa2581d92d59f59897d2e9f7e708fdabe922f9087773af"}, - {file = "pydantic_core-2.18.4-cp38-none-win32.whl", hash = "sha256:1d886dc848e60cb7666f771e406acae54ab279b9f1e4143babc9c2258213daa2"}, - {file = "pydantic_core-2.18.4-cp38-none-win_amd64.whl", hash = "sha256:bb4462bd43c2460774914b8525f79b00f8f407c945d50881568f294c1d9b4443"}, - {file = "pydantic_core-2.18.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:44a688331d4a4e2129140a8118479443bd6f1905231138971372fcde37e43528"}, - {file = "pydantic_core-2.18.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a2fdd81edd64342c85ac7cf2753ccae0b79bf2dfa063785503cb85a7d3593223"}, - {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86110d7e1907ab36691f80b33eb2da87d780f4739ae773e5fc83fb272f88825f"}, - {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:46387e38bd641b3ee5ce247563b60c5ca098da9c56c75c157a05eaa0933ed154"}, - {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:123c3cec203e3f5ac7b000bd82235f1a3eced8665b63d18be751f115588fea30"}, - {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dc1803ac5c32ec324c5261c7209e8f8ce88e83254c4e1aebdc8b0a39f9ddb443"}, - {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53db086f9f6ab2b4061958d9c276d1dbe3690e8dd727d6abf2321d6cce37fa94"}, - {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:abc267fa9837245cc28ea6929f19fa335f3dc330a35d2e45509b6566dc18be23"}, - {file = "pydantic_core-2.18.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a0d829524aaefdebccb869eed855e2d04c21d2d7479b6cada7ace5448416597b"}, - {file = "pydantic_core-2.18.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:509daade3b8649f80d4e5ff21aa5673e4ebe58590b25fe42fac5f0f52c6f034a"}, - {file = "pydantic_core-2.18.4-cp39-none-win32.whl", hash = "sha256:ca26a1e73c48cfc54c4a76ff78df3727b9d9f4ccc8dbee4ae3f73306a591676d"}, - {file = "pydantic_core-2.18.4-cp39-none-win_amd64.whl", hash = "sha256:c67598100338d5d985db1b3d21f3619ef392e185e71b8d52bceacc4a7771ea7e"}, - {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:574d92eac874f7f4db0ca653514d823a0d22e2354359d0759e3f6a406db5d55d"}, - {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1f4d26ceb5eb9eed4af91bebeae4b06c3fb28966ca3a8fb765208cf6b51102ab"}, - {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77450e6d20016ec41f43ca4a6c63e9fdde03f0ae3fe90e7c27bdbeaece8b1ed4"}, - {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d323a01da91851a4f17bf592faf46149c9169d68430b3146dcba2bb5e5719abc"}, - {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43d447dd2ae072a0065389092a231283f62d960030ecd27565672bd40746c507"}, - {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:578e24f761f3b425834f297b9935e1ce2e30f51400964ce4801002435a1b41ef"}, - {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:81b5efb2f126454586d0f40c4d834010979cb80785173d1586df845a632e4e6d"}, - {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ab86ce7c8f9bea87b9d12c7f0af71102acbf5ecbc66c17796cff45dae54ef9a5"}, - {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:90afc12421df2b1b4dcc975f814e21bc1754640d502a2fbcc6d41e77af5ec312"}, - {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:51991a89639a912c17bef4b45c87bd83593aee0437d8102556af4885811d59f5"}, - {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:293afe532740370aba8c060882f7d26cfd00c94cae32fd2e212a3a6e3b7bc15e"}, - {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b48ece5bde2e768197a2d0f6e925f9d7e3e826f0ad2271120f8144a9db18d5c8"}, - {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:eae237477a873ab46e8dd748e515c72c0c804fb380fbe6c85533c7de51f23a8f"}, - {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:834b5230b5dfc0c1ec37b2fda433b271cbbc0e507560b5d1588e2cc1148cf1ce"}, - {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e858ac0a25074ba4bce653f9b5d0a85b7456eaddadc0ce82d3878c22489fa4ee"}, - {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2fd41f6eff4c20778d717af1cc50eca52f5afe7805ee530a4fbd0bae284f16e9"}, - {file = "pydantic_core-2.18.4.tar.gz", hash = "sha256:ec3beeada09ff865c344ff3bc2f427f5e6c26401cc6113d77e372c3fdac73864"}, + {file = "pydantic_core-2.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3"}, + {file = "pydantic_core-2.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840"}, + {file = "pydantic_core-2.20.1-cp310-none-win32.whl", hash = "sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250"}, + {file = "pydantic_core-2.20.1-cp310-none-win_amd64.whl", hash = "sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c"}, + {file = "pydantic_core-2.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312"}, + {file = "pydantic_core-2.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b"}, + {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27"}, + {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b"}, + {file = "pydantic_core-2.20.1-cp311-none-win32.whl", hash = "sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a"}, + {file = "pydantic_core-2.20.1-cp311-none-win_amd64.whl", hash = "sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2"}, + {file = "pydantic_core-2.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231"}, + {file = "pydantic_core-2.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24"}, + {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1"}, + {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd"}, + {file = "pydantic_core-2.20.1-cp312-none-win32.whl", hash = "sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688"}, + {file = "pydantic_core-2.20.1-cp312-none-win_amd64.whl", hash = "sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d"}, + {file = "pydantic_core-2.20.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686"}, + {file = "pydantic_core-2.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83"}, + {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203"}, + {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0"}, + {file = "pydantic_core-2.20.1-cp313-none-win32.whl", hash = "sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e"}, + {file = "pydantic_core-2.20.1-cp313-none-win_amd64.whl", hash = "sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20"}, + {file = "pydantic_core-2.20.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91"}, + {file = "pydantic_core-2.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd"}, + {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa"}, + {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987"}, + {file = "pydantic_core-2.20.1-cp38-none-win32.whl", hash = "sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a"}, + {file = "pydantic_core-2.20.1-cp38-none-win_amd64.whl", hash = "sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434"}, + {file = "pydantic_core-2.20.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c"}, + {file = "pydantic_core-2.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1"}, + {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09"}, + {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab"}, + {file = "pydantic_core-2.20.1-cp39-none-win32.whl", hash = "sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2"}, + {file = "pydantic_core-2.20.1-cp39-none-win_amd64.whl", hash = "sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7"}, + {file = "pydantic_core-2.20.1.tar.gz", hash = "sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4"}, ] [package.dependencies] @@ -1492,110 +1448,110 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "rpds-py" -version = "0.18.1" +version = "0.19.0" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.8" files = [ - {file = "rpds_py-0.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d31dea506d718693b6b2cffc0648a8929bdc51c70a311b2770f09611caa10d53"}, - {file = "rpds_py-0.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:732672fbc449bab754e0b15356c077cc31566df874964d4801ab14f71951ea80"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a98a1f0552b5f227a3d6422dbd61bc6f30db170939bd87ed14f3c339aa6c7c9"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f1944ce16401aad1e3f7d312247b3d5de7981f634dc9dfe90da72b87d37887d"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38e14fb4e370885c4ecd734f093a2225ee52dc384b86fa55fe3f74638b2cfb09"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08d74b184f9ab6289b87b19fe6a6d1a97fbfea84b8a3e745e87a5de3029bf944"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d70129cef4a8d979caa37e7fe957202e7eee8ea02c5e16455bc9808a59c6b2f0"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ce0bb20e3a11bd04461324a6a798af34d503f8d6f1aa3d2aa8901ceaf039176d"}, - {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81c5196a790032e0fc2464c0b4ab95f8610f96f1f2fa3d4deacce6a79852da60"}, - {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f3027be483868c99b4985fda802a57a67fdf30c5d9a50338d9db646d590198da"}, - {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d44607f98caa2961bab4fa3c4309724b185b464cdc3ba6f3d7340bac3ec97cc1"}, - {file = "rpds_py-0.18.1-cp310-none-win32.whl", hash = "sha256:c273e795e7a0f1fddd46e1e3cb8be15634c29ae8ff31c196debb620e1edb9333"}, - {file = "rpds_py-0.18.1-cp310-none-win_amd64.whl", hash = "sha256:8352f48d511de5f973e4f2f9412736d7dea76c69faa6d36bcf885b50c758ab9a"}, - {file = "rpds_py-0.18.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6b5ff7e1d63a8281654b5e2896d7f08799378e594f09cf3674e832ecaf396ce8"}, - {file = "rpds_py-0.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8927638a4d4137a289e41d0fd631551e89fa346d6dbcfc31ad627557d03ceb6d"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:154bf5c93d79558b44e5b50cc354aa0459e518e83677791e6adb0b039b7aa6a7"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07f2139741e5deb2c5154a7b9629bc5aa48c766b643c1a6750d16f865a82c5fc"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c7672e9fba7425f79019db9945b16e308ed8bc89348c23d955c8c0540da0a07"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:489bdfe1abd0406eba6b3bb4fdc87c7fa40f1031de073d0cfb744634cc8fa261"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c20f05e8e3d4fc76875fc9cb8cf24b90a63f5a1b4c5b9273f0e8225e169b100"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:967342e045564cef76dfcf1edb700b1e20838d83b1aa02ab313e6a497cf923b8"}, - {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2cc7c1a47f3a63282ab0f422d90ddac4aa3034e39fc66a559ab93041e6505da7"}, - {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f7afbfee1157e0f9376c00bb232e80a60e59ed716e3211a80cb8506550671e6e"}, - {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9e6934d70dc50f9f8ea47081ceafdec09245fd9f6032669c3b45705dea096b88"}, - {file = "rpds_py-0.18.1-cp311-none-win32.whl", hash = "sha256:c69882964516dc143083d3795cb508e806b09fc3800fd0d4cddc1df6c36e76bb"}, - {file = "rpds_py-0.18.1-cp311-none-win_amd64.whl", hash = "sha256:70a838f7754483bcdc830444952fd89645569e7452e3226de4a613a4c1793fb2"}, - {file = "rpds_py-0.18.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3dd3cd86e1db5aadd334e011eba4e29d37a104b403e8ca24dcd6703c68ca55b3"}, - {file = "rpds_py-0.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:05f3d615099bd9b13ecf2fc9cf2d839ad3f20239c678f461c753e93755d629ee"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35b2b771b13eee8729a5049c976197ff58a27a3829c018a04341bcf1ae409b2b"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ee17cd26b97d537af8f33635ef38be873073d516fd425e80559f4585a7b90c43"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b646bf655b135ccf4522ed43d6902af37d3f5dbcf0da66c769a2b3938b9d8184"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19ba472b9606c36716062c023afa2484d1e4220548751bda14f725a7de17b4f6"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e30ac5e329098903262dc5bdd7e2086e0256aa762cc8b744f9e7bf2a427d3f8"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d58ad6317d188c43750cb76e9deacf6051d0f884d87dc6518e0280438648a9ac"}, - {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e1735502458621921cee039c47318cb90b51d532c2766593be6207eec53e5c4c"}, - {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f5bab211605d91db0e2995a17b5c6ee5edec1270e46223e513eaa20da20076ac"}, - {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2fc24a329a717f9e2448f8cd1f960f9dac4e45b6224d60734edeb67499bab03a"}, - {file = "rpds_py-0.18.1-cp312-none-win32.whl", hash = "sha256:1805d5901779662d599d0e2e4159d8a82c0b05faa86ef9222bf974572286b2b6"}, - {file = "rpds_py-0.18.1-cp312-none-win_amd64.whl", hash = "sha256:720edcb916df872d80f80a1cc5ea9058300b97721efda8651efcd938a9c70a72"}, - {file = "rpds_py-0.18.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:c827576e2fa017a081346dce87d532a5310241648eb3700af9a571a6e9fc7e74"}, - {file = "rpds_py-0.18.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aa3679e751408d75a0b4d8d26d6647b6d9326f5e35c00a7ccd82b78ef64f65f8"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0abeee75434e2ee2d142d650d1e54ac1f8b01e6e6abdde8ffd6eeac6e9c38e20"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed402d6153c5d519a0faf1bb69898e97fb31613b49da27a84a13935ea9164dfc"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:338dee44b0cef8b70fd2ef54b4e09bb1b97fc6c3a58fea5db6cc083fd9fc2724"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7750569d9526199c5b97e5a9f8d96a13300950d910cf04a861d96f4273d5b104"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:607345bd5912aacc0c5a63d45a1f73fef29e697884f7e861094e443187c02be5"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:207c82978115baa1fd8d706d720b4a4d2b0913df1c78c85ba73fe6c5804505f0"}, - {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6d1e42d2735d437e7e80bab4d78eb2e459af48c0a46e686ea35f690b93db792d"}, - {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:5463c47c08630007dc0fe99fb480ea4f34a89712410592380425a9b4e1611d8e"}, - {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:06d218939e1bf2ca50e6b0ec700ffe755e5216a8230ab3e87c059ebb4ea06afc"}, - {file = "rpds_py-0.18.1-cp38-none-win32.whl", hash = "sha256:312fe69b4fe1ffbe76520a7676b1e5ac06ddf7826d764cc10265c3b53f96dbe9"}, - {file = "rpds_py-0.18.1-cp38-none-win_amd64.whl", hash = "sha256:9437ca26784120a279f3137ee080b0e717012c42921eb07861b412340f85bae2"}, - {file = "rpds_py-0.18.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:19e515b78c3fc1039dd7da0a33c28c3154458f947f4dc198d3c72db2b6b5dc93"}, - {file = "rpds_py-0.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7b28c5b066bca9a4eb4e2f2663012debe680f097979d880657f00e1c30875a0"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:673fdbbf668dd958eff750e500495ef3f611e2ecc209464f661bc82e9838991e"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d960de62227635d2e61068f42a6cb6aae91a7fe00fca0e3aeed17667c8a34611"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:352a88dc7892f1da66b6027af06a2e7e5d53fe05924cc2cfc56495b586a10b72"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e0ee01ad8260184db21468a6e1c37afa0529acc12c3a697ee498d3c2c4dcaf3"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4c39ad2f512b4041343ea3c7894339e4ca7839ac38ca83d68a832fc8b3748ab"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aaa71ee43a703c321906813bb252f69524f02aa05bf4eec85f0c41d5d62d0f4c"}, - {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6cd8098517c64a85e790657e7b1e509b9fe07487fd358e19431cb120f7d96338"}, - {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:4adec039b8e2928983f885c53b7cc4cda8965b62b6596501a0308d2703f8af1b"}, - {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:32b7daaa3e9389db3695964ce8e566e3413b0c43e3394c05e4b243a4cd7bef26"}, - {file = "rpds_py-0.18.1-cp39-none-win32.whl", hash = "sha256:2625f03b105328729f9450c8badda34d5243231eef6535f80064d57035738360"}, - {file = "rpds_py-0.18.1-cp39-none-win_amd64.whl", hash = "sha256:bf18932d0003c8c4d51a39f244231986ab23ee057d235a12b2684ea26a353590"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cbfbea39ba64f5e53ae2915de36f130588bba71245b418060ec3330ebf85678e"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a3d456ff2a6a4d2adcdf3c1c960a36f4fd2fec6e3b4902a42a384d17cf4e7a65"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7700936ef9d006b7ef605dc53aa364da2de5a3aa65516a1f3ce73bf82ecfc7ae"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:51584acc5916212e1bf45edd17f3a6b05fe0cbb40482d25e619f824dccb679de"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:942695a206a58d2575033ff1e42b12b2aece98d6003c6bc739fbf33d1773b12f"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b906b5f58892813e5ba5c6056d6a5ad08f358ba49f046d910ad992196ea61397"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6f8e3fecca256fefc91bb6765a693d96692459d7d4c644660a9fff32e517843"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7732770412bab81c5a9f6d20aeb60ae943a9b36dcd990d876a773526468e7163"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:bd1105b50ede37461c1d51b9698c4f4be6e13e69a908ab7751e3807985fc0346"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:618916f5535784960f3ecf8111581f4ad31d347c3de66d02e728de460a46303c"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:17c6d2155e2423f7e79e3bb18151c686d40db42d8645e7977442170c360194d4"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6c4c4c3f878df21faf5fac86eda32671c27889e13570645a9eea0a1abdd50922"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:fab6ce90574645a0d6c58890e9bcaac8d94dff54fb51c69e5522a7358b80ab64"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:531796fb842b53f2695e94dc338929e9f9dbf473b64710c28af5a160b2a8927d"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:740884bc62a5e2bbb31e584f5d23b32320fd75d79f916f15a788d527a5e83644"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:998125738de0158f088aef3cb264a34251908dd2e5d9966774fdab7402edfab7"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e2be6e9dd4111d5b31ba3b74d17da54a8319d8168890fbaea4b9e5c3de630ae5"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0cee71bc618cd93716f3c1bf56653740d2d13ddbd47673efa8bf41435a60daa"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2c3caec4ec5cd1d18e5dd6ae5194d24ed12785212a90b37f5f7f06b8bedd7139"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:27bba383e8c5231cd559affe169ca0b96ec78d39909ffd817f28b166d7ddd4d8"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:a888e8bdb45916234b99da2d859566f1e8a1d2275a801bb8e4a9644e3c7e7909"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6031b25fb1b06327b43d841f33842b383beba399884f8228a6bb3df3088485ff"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48c2faaa8adfacefcbfdb5f2e2e7bdad081e5ace8d182e5f4ade971f128e6bb3"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:d85164315bd68c0806768dc6bb0429c6f95c354f87485ee3593c4f6b14def2bd"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6afd80f6c79893cfc0574956f78a0add8c76e3696f2d6a15bca2c66c415cf2d4"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa242ac1ff583e4ec7771141606aafc92b361cd90a05c30d93e343a0c2d82a89"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21be4770ff4e08698e1e8e0bce06edb6ea0626e7c8f560bc08222880aca6a6f"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c45a639e93a0c5d4b788b2613bd637468edd62f8f95ebc6fcc303d58ab3f0a8"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910e71711d1055b2768181efa0a17537b2622afeb0424116619817007f8a2b10"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b9bb1f182a97880f6078283b3505a707057c42bf55d8fca604f70dedfdc0772a"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1d54f74f40b1f7aaa595a02ff42ef38ca654b1469bef7d52867da474243cc633"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:8d2e182c9ee01135e11e9676e9a62dfad791a7a467738f06726872374a83db49"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:636a15acc588f70fda1661234761f9ed9ad79ebed3f2125d44be0862708b666e"}, - {file = "rpds_py-0.18.1.tar.gz", hash = "sha256:dc48b479d540770c811fbd1eb9ba2bb66951863e448efec2e2c102625328e92f"}, + {file = "rpds_py-0.19.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:fb37bd599f031f1a6fb9e58ec62864ccf3ad549cf14bac527dbfa97123edcca4"}, + {file = "rpds_py-0.19.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3384d278df99ec2c6acf701d067147320b864ef6727405d6470838476e44d9e8"}, + {file = "rpds_py-0.19.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e54548e0be3ac117595408fd4ca0ac9278fde89829b0b518be92863b17ff67a2"}, + {file = "rpds_py-0.19.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8eb488ef928cdbc05a27245e52de73c0d7c72a34240ef4d9893fdf65a8c1a955"}, + {file = "rpds_py-0.19.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5da93debdfe27b2bfc69eefb592e1831d957b9535e0943a0ee8b97996de21b5"}, + {file = "rpds_py-0.19.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:79e205c70afddd41f6ee79a8656aec738492a550247a7af697d5bd1aee14f766"}, + {file = "rpds_py-0.19.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:959179efb3e4a27610e8d54d667c02a9feaa86bbabaf63efa7faa4dfa780d4f1"}, + {file = "rpds_py-0.19.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a6e605bb9edcf010f54f8b6a590dd23a4b40a8cb141255eec2a03db249bc915b"}, + {file = "rpds_py-0.19.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9133d75dc119a61d1a0ded38fb9ba40a00ef41697cc07adb6ae098c875195a3f"}, + {file = "rpds_py-0.19.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd36b712d35e757e28bf2f40a71e8f8a2d43c8b026d881aa0c617b450d6865c9"}, + {file = "rpds_py-0.19.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:354f3a91718489912f2e0fc331c24eaaf6a4565c080e00fbedb6015857c00582"}, + {file = "rpds_py-0.19.0-cp310-none-win32.whl", hash = "sha256:ebcbf356bf5c51afc3290e491d3722b26aaf5b6af3c1c7f6a1b757828a46e336"}, + {file = "rpds_py-0.19.0-cp310-none-win_amd64.whl", hash = "sha256:75a6076289b2df6c8ecb9d13ff79ae0cad1d5fb40af377a5021016d58cd691ec"}, + {file = "rpds_py-0.19.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6d45080095e585f8c5097897313def60caa2046da202cdb17a01f147fb263b81"}, + {file = "rpds_py-0.19.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5c9581019c96f865483d031691a5ff1cc455feb4d84fc6920a5ffc48a794d8a"}, + {file = "rpds_py-0.19.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1540d807364c84516417115c38f0119dfec5ea5c0dd9a25332dea60b1d26fc4d"}, + {file = "rpds_py-0.19.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9e65489222b410f79711dc3d2d5003d2757e30874096b2008d50329ea4d0f88c"}, + {file = "rpds_py-0.19.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9da6f400eeb8c36f72ef6646ea530d6d175a4f77ff2ed8dfd6352842274c1d8b"}, + {file = "rpds_py-0.19.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:37f46bb11858717e0efa7893c0f7055c43b44c103e40e69442db5061cb26ed34"}, + {file = "rpds_py-0.19.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:071d4adc734de562bd11d43bd134330fb6249769b2f66b9310dab7460f4bf714"}, + {file = "rpds_py-0.19.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9625367c8955e4319049113ea4f8fee0c6c1145192d57946c6ffcd8fe8bf48dd"}, + {file = "rpds_py-0.19.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e19509145275d46bc4d1e16af0b57a12d227c8253655a46bbd5ec317e941279d"}, + {file = "rpds_py-0.19.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d438e4c020d8c39961deaf58f6913b1bf8832d9b6f62ec35bd93e97807e9cbc"}, + {file = "rpds_py-0.19.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:90bf55d9d139e5d127193170f38c584ed3c79e16638890d2e36f23aa1630b952"}, + {file = "rpds_py-0.19.0-cp311-none-win32.whl", hash = "sha256:8d6ad132b1bc13d05ffe5b85e7a01a3998bf3a6302ba594b28d61b8c2cf13aaf"}, + {file = "rpds_py-0.19.0-cp311-none-win_amd64.whl", hash = "sha256:7ec72df7354e6b7f6eb2a17fa6901350018c3a9ad78e48d7b2b54d0412539a67"}, + {file = "rpds_py-0.19.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:5095a7c838a8647c32aa37c3a460d2c48debff7fc26e1136aee60100a8cd8f68"}, + {file = "rpds_py-0.19.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f2f78ef14077e08856e788fa482107aa602636c16c25bdf59c22ea525a785e9"}, + {file = "rpds_py-0.19.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7cc6cb44f8636fbf4a934ca72f3e786ba3c9f9ba4f4d74611e7da80684e48d2"}, + {file = "rpds_py-0.19.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cf902878b4af334a09de7a45badbff0389e7cf8dc2e4dcf5f07125d0b7c2656d"}, + {file = "rpds_py-0.19.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:688aa6b8aa724db1596514751ffb767766e02e5c4a87486ab36b8e1ebc1aedac"}, + {file = "rpds_py-0.19.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57dbc9167d48e355e2569346b5aa4077f29bf86389c924df25c0a8b9124461fb"}, + {file = "rpds_py-0.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b4cf5a9497874822341c2ebe0d5850fed392034caadc0bad134ab6822c0925b"}, + {file = "rpds_py-0.19.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8a790d235b9d39c70a466200d506bb33a98e2ee374a9b4eec7a8ac64c2c261fa"}, + {file = "rpds_py-0.19.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1d16089dfa58719c98a1c06f2daceba6d8e3fb9b5d7931af4a990a3c486241cb"}, + {file = "rpds_py-0.19.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:bc9128e74fe94650367fe23f37074f121b9f796cabbd2f928f13e9661837296d"}, + {file = "rpds_py-0.19.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c8f77e661ffd96ff104bebf7d0f3255b02aa5d5b28326f5408d6284c4a8b3248"}, + {file = "rpds_py-0.19.0-cp312-none-win32.whl", hash = "sha256:5f83689a38e76969327e9b682be5521d87a0c9e5a2e187d2bc6be4765f0d4600"}, + {file = "rpds_py-0.19.0-cp312-none-win_amd64.whl", hash = "sha256:06925c50f86da0596b9c3c64c3837b2481337b83ef3519e5db2701df695453a4"}, + {file = "rpds_py-0.19.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:52e466bea6f8f3a44b1234570244b1cff45150f59a4acae3fcc5fd700c2993ca"}, + {file = "rpds_py-0.19.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e21cc693045fda7f745c790cb687958161ce172ffe3c5719ca1764e752237d16"}, + {file = "rpds_py-0.19.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b31f059878eb1f5da8b2fd82480cc18bed8dcd7fb8fe68370e2e6285fa86da6"}, + {file = "rpds_py-0.19.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1dd46f309e953927dd018567d6a9e2fb84783963650171f6c5fe7e5c41fd5666"}, + {file = "rpds_py-0.19.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34a01a4490e170376cd79258b7f755fa13b1a6c3667e872c8e35051ae857a92b"}, + {file = "rpds_py-0.19.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bcf426a8c38eb57f7bf28932e68425ba86def6e756a5b8cb4731d8e62e4e0223"}, + {file = "rpds_py-0.19.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f68eea5df6347d3f1378ce992d86b2af16ad7ff4dcb4a19ccdc23dea901b87fb"}, + {file = "rpds_py-0.19.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dab8d921b55a28287733263c0e4c7db11b3ee22aee158a4de09f13c93283c62d"}, + {file = "rpds_py-0.19.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6fe87efd7f47266dfc42fe76dae89060038f1d9cb911f89ae7e5084148d1cc08"}, + {file = "rpds_py-0.19.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:535d4b52524a961d220875688159277f0e9eeeda0ac45e766092bfb54437543f"}, + {file = "rpds_py-0.19.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:8b1a94b8afc154fbe36978a511a1f155f9bd97664e4f1f7a374d72e180ceb0ae"}, + {file = "rpds_py-0.19.0-cp38-none-win32.whl", hash = "sha256:7c98298a15d6b90c8f6e3caa6457f4f022423caa5fa1a1ca7a5e9e512bdb77a4"}, + {file = "rpds_py-0.19.0-cp38-none-win_amd64.whl", hash = "sha256:b0da31853ab6e58a11db3205729133ce0df26e6804e93079dee095be3d681dc1"}, + {file = "rpds_py-0.19.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:5039e3cef7b3e7a060de468a4a60a60a1f31786da94c6cb054e7a3c75906111c"}, + {file = "rpds_py-0.19.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab1932ca6cb8c7499a4d87cb21ccc0d3326f172cfb6a64021a889b591bb3045c"}, + {file = "rpds_py-0.19.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2afd2164a1e85226fcb6a1da77a5c8896c18bfe08e82e8ceced5181c42d2179"}, + {file = "rpds_py-0.19.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b1c30841f5040de47a0046c243fc1b44ddc87d1b12435a43b8edff7e7cb1e0d0"}, + {file = "rpds_py-0.19.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f757f359f30ec7dcebca662a6bd46d1098f8b9fb1fcd661a9e13f2e8ce343ba1"}, + {file = "rpds_py-0.19.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15e65395a59d2e0e96caf8ee5389ffb4604e980479c32742936ddd7ade914b22"}, + {file = "rpds_py-0.19.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb0f6eb3a320f24b94d177e62f4074ff438f2ad9d27e75a46221904ef21a7b05"}, + {file = "rpds_py-0.19.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b228e693a2559888790936e20f5f88b6e9f8162c681830eda303bad7517b4d5a"}, + {file = "rpds_py-0.19.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2575efaa5d949c9f4e2cdbe7d805d02122c16065bfb8d95c129372d65a291a0b"}, + {file = "rpds_py-0.19.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:5c872814b77a4e84afa293a1bee08c14daed1068b2bb1cc312edbf020bbbca2b"}, + {file = "rpds_py-0.19.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:850720e1b383df199b8433a20e02b25b72f0fded28bc03c5bd79e2ce7ef050be"}, + {file = "rpds_py-0.19.0-cp39-none-win32.whl", hash = "sha256:ce84a7efa5af9f54c0aa7692c45861c1667080814286cacb9958c07fc50294fb"}, + {file = "rpds_py-0.19.0-cp39-none-win_amd64.whl", hash = "sha256:1c26da90b8d06227d7769f34915913911222d24ce08c0ab2d60b354e2d9c7aff"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:75969cf900d7be665ccb1622a9aba225cf386bbc9c3bcfeeab9f62b5048f4a07"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8445f23f13339da640d1be8e44e5baf4af97e396882ebbf1692aecd67f67c479"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5a7c1062ef8aea3eda149f08120f10795835fc1c8bc6ad948fb9652a113ca55"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:462b0c18fbb48fdbf980914a02ee38c423a25fcc4cf40f66bacc95a2d2d73bc8"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3208f9aea18991ac7f2b39721e947bbd752a1abbe79ad90d9b6a84a74d44409b"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3444fe52b82f122d8a99bf66777aed6b858d392b12f4c317da19f8234db4533"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88cb4bac7185a9f0168d38c01d7a00addece9822a52870eee26b8d5b61409213"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6b130bd4163c93798a6b9bb96be64a7c43e1cec81126ffa7ffaa106e1fc5cef5"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:a707b158b4410aefb6b054715545bbb21aaa5d5d0080217290131c49c2124a6e"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:dc9ac4659456bde7c567107556ab065801622396b435a3ff213daef27b495388"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:81ea573aa46d3b6b3d890cd3c0ad82105985e6058a4baed03cf92518081eec8c"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3f148c3f47f7f29a79c38cc5d020edcb5ca780020fab94dbc21f9af95c463581"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0906357f90784a66e89ae3eadc2654f36c580a7d65cf63e6a616e4aec3a81be"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f629ecc2db6a4736b5ba95a8347b0089240d69ad14ac364f557d52ad68cf94b0"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c6feacd1d178c30e5bc37184526e56740342fd2aa6371a28367bad7908d454fc"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae8b6068ee374fdfab63689be0963333aa83b0815ead5d8648389a8ded593378"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78d57546bad81e0da13263e4c9ce30e96dcbe720dbff5ada08d2600a3502e526"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8b6683a37338818646af718c9ca2a07f89787551057fae57c4ec0446dc6224b"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e8481b946792415adc07410420d6fc65a352b45d347b78fec45d8f8f0d7496f0"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:bec35eb20792ea64c3c57891bc3ca0bedb2884fbac2c8249d9b731447ecde4fa"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:aa5476c3e3a402c37779e95f7b4048db2cb5b0ed0b9d006983965e93f40fe05a"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:19d02c45f2507b489fd4df7b827940f1420480b3e2e471e952af4d44a1ea8e34"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a3e2fd14c5d49ee1da322672375963f19f32b3d5953f0615b175ff7b9d38daed"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:93a91c2640645303e874eada51f4f33351b84b351a689d470f8108d0e0694210"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5b9fc03bf76a94065299d4a2ecd8dfbae4ae8e2e8098bbfa6ab6413ca267709"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5a4b07cdf3f84310c08c1de2c12ddadbb7a77568bcb16e95489f9c81074322ed"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba0ed0dc6763d8bd6e5de5cf0d746d28e706a10b615ea382ac0ab17bb7388633"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:474bc83233abdcf2124ed3f66230a1c8435896046caa4b0b5ab6013c640803cc"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:329c719d31362355a96b435f4653e3b4b061fcc9eba9f91dd40804ca637d914e"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef9101f3f7b59043a34f1dccbb385ca760467590951952d6701df0da9893ca0c"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:0121803b0f424ee2109d6e1f27db45b166ebaa4b32ff47d6aa225642636cd834"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:8344127403dea42f5970adccf6c5957a71a47f522171fafaf4c6ddb41b61703a"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:443cec402ddd650bb2b885113e1dcedb22b1175c6be223b14246a714b61cd521"}, + {file = "rpds_py-0.19.0.tar.gz", hash = "sha256:4fdc9afadbeb393b4bbbad75481e0ea78e4469f2e1d713a90811700830b553a9"}, ] [[package]] @@ -1677,13 +1633,13 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7 [[package]] name = "tenacity" -version = "8.3.0" +version = "8.5.0" description = "Retry code until it succeeds" optional = false python-versions = ">=3.8" files = [ - {file = "tenacity-8.3.0-py3-none-any.whl", hash = "sha256:3649f6443dbc0d9b01b9d8020a9c4ec7a1ff5f6f3c6c8a036ef371f573fe9185"}, - {file = "tenacity-8.3.0.tar.gz", hash = "sha256:953d4e6ad24357bceffbc9707bc74349aca9d245f68eb65419cf0c249a1949a2"}, + {file = "tenacity-8.5.0-py3-none-any.whl", hash = "sha256:b594c2a5945830c267ce6b79a166228323ed52718f30302c1359836112346687"}, + {file = "tenacity-8.5.0.tar.gz", hash = "sha256:8bc6c0c8a09b31e6cad13c47afbed1a567518250a9a171418582ed8d9c20ca78"}, ] [package.extras] @@ -1764,13 +1720,13 @@ files = [ [[package]] name = "types-requests" -version = "2.32.0.20240602" +version = "2.32.0.20240712" description = "Typing stubs for requests" optional = false python-versions = ">=3.8" files = [ - {file = "types-requests-2.32.0.20240602.tar.gz", hash = "sha256:3f98d7bbd0dd94ebd10ff43a7fbe20c3b8528acace6d8efafef0b6a184793f06"}, - {file = "types_requests-2.32.0.20240602-py3-none-any.whl", hash = "sha256:ed3946063ea9fbc6b5fc0c44fa279188bae42d582cb63760be6cb4b9d06c3de8"}, + {file = "types-requests-2.32.0.20240712.tar.gz", hash = "sha256:90c079ff05e549f6bf50e02e910210b98b8ff1ebdd18e19c873cd237737c1358"}, + {file = "types_requests-2.32.0.20240712-py3-none-any.whl", hash = "sha256:f754283e152c752e46e70942fa2a146b5bc70393522257bb85bd1ef7e019dcc3"}, ] [package.dependencies] @@ -1778,13 +1734,13 @@ urllib3 = ">=2" [[package]] name = "typing-extensions" -version = "4.12.1" +version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.12.1-py3-none-any.whl", hash = "sha256:6024b58b69089e5a89c347397254e35f1bf02a907728ec7fee9bf0fe837d203a"}, - {file = "typing_extensions-4.12.1.tar.gz", hash = "sha256:915f5e35ff76f56588223f15fdd5938f9a1cf9195c0de25130c627e4d597f6d1"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] @@ -1798,102 +1754,15 @@ files = [ {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, ] -[[package]] -name = "ujson" -version = "5.10.0" -description = "Ultra fast JSON encoder and decoder for Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "ujson-5.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2601aa9ecdbee1118a1c2065323bda35e2c5a2cf0797ef4522d485f9d3ef65bd"}, - {file = "ujson-5.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:348898dd702fc1c4f1051bc3aacbf894caa0927fe2c53e68679c073375f732cf"}, - {file = "ujson-5.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22cffecf73391e8abd65ef5f4e4dd523162a3399d5e84faa6aebbf9583df86d6"}, - {file = "ujson-5.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26b0e2d2366543c1bb4fbd457446f00b0187a2bddf93148ac2da07a53fe51569"}, - {file = "ujson-5.10.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:caf270c6dba1be7a41125cd1e4fc7ba384bf564650beef0df2dd21a00b7f5770"}, - {file = "ujson-5.10.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a245d59f2ffe750446292b0094244df163c3dc96b3ce152a2c837a44e7cda9d1"}, - {file = "ujson-5.10.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:94a87f6e151c5f483d7d54ceef83b45d3a9cca7a9cb453dbdbb3f5a6f64033f5"}, - {file = "ujson-5.10.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:29b443c4c0a113bcbb792c88bea67b675c7ca3ca80c3474784e08bba01c18d51"}, - {file = "ujson-5.10.0-cp310-cp310-win32.whl", hash = "sha256:c18610b9ccd2874950faf474692deee4223a994251bc0a083c114671b64e6518"}, - {file = "ujson-5.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:924f7318c31874d6bb44d9ee1900167ca32aa9b69389b98ecbde34c1698a250f"}, - {file = "ujson-5.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a5b366812c90e69d0f379a53648be10a5db38f9d4ad212b60af00bd4048d0f00"}, - {file = "ujson-5.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:502bf475781e8167f0f9d0e41cd32879d120a524b22358e7f205294224c71126"}, - {file = "ujson-5.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b91b5d0d9d283e085e821651184a647699430705b15bf274c7896f23fe9c9d8"}, - {file = "ujson-5.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:129e39af3a6d85b9c26d5577169c21d53821d8cf68e079060602e861c6e5da1b"}, - {file = "ujson-5.10.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f77b74475c462cb8b88680471193064d3e715c7c6074b1c8c412cb526466efe9"}, - {file = "ujson-5.10.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7ec0ca8c415e81aa4123501fee7f761abf4b7f386aad348501a26940beb1860f"}, - {file = "ujson-5.10.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ab13a2a9e0b2865a6c6db9271f4b46af1c7476bfd51af1f64585e919b7c07fd4"}, - {file = "ujson-5.10.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:57aaf98b92d72fc70886b5a0e1a1ca52c2320377360341715dd3933a18e827b1"}, - {file = "ujson-5.10.0-cp311-cp311-win32.whl", hash = "sha256:2987713a490ceb27edff77fb184ed09acdc565db700ee852823c3dc3cffe455f"}, - {file = "ujson-5.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:f00ea7e00447918ee0eff2422c4add4c5752b1b60e88fcb3c067d4a21049a720"}, - {file = "ujson-5.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:98ba15d8cbc481ce55695beee9f063189dce91a4b08bc1d03e7f0152cd4bbdd5"}, - {file = "ujson-5.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a9d2edbf1556e4f56e50fab7d8ff993dbad7f54bac68eacdd27a8f55f433578e"}, - {file = "ujson-5.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6627029ae4f52d0e1a2451768c2c37c0c814ffc04f796eb36244cf16b8e57043"}, - {file = "ujson-5.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8ccb77b3e40b151e20519c6ae6d89bfe3f4c14e8e210d910287f778368bb3d1"}, - {file = "ujson-5.10.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3caf9cd64abfeb11a3b661329085c5e167abbe15256b3b68cb5d914ba7396f3"}, - {file = "ujson-5.10.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6e32abdce572e3a8c3d02c886c704a38a1b015a1fb858004e03d20ca7cecbb21"}, - {file = "ujson-5.10.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a65b6af4d903103ee7b6f4f5b85f1bfd0c90ba4eeac6421aae436c9988aa64a2"}, - {file = "ujson-5.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:604a046d966457b6cdcacc5aa2ec5314f0e8c42bae52842c1e6fa02ea4bda42e"}, - {file = "ujson-5.10.0-cp312-cp312-win32.whl", hash = "sha256:6dea1c8b4fc921bf78a8ff00bbd2bfe166345f5536c510671bccececb187c80e"}, - {file = "ujson-5.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:38665e7d8290188b1e0d57d584eb8110951a9591363316dd41cf8686ab1d0abc"}, - {file = "ujson-5.10.0-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:618efd84dc1acbd6bff8eaa736bb6c074bfa8b8a98f55b61c38d4ca2c1f7f287"}, - {file = "ujson-5.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38d5d36b4aedfe81dfe251f76c0467399d575d1395a1755de391e58985ab1c2e"}, - {file = "ujson-5.10.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67079b1f9fb29ed9a2914acf4ef6c02844b3153913eb735d4bf287ee1db6e557"}, - {file = "ujson-5.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7d0e0ceeb8fe2468c70ec0c37b439dd554e2aa539a8a56365fd761edb418988"}, - {file = "ujson-5.10.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:59e02cd37bc7c44d587a0ba45347cc815fb7a5fe48de16bf05caa5f7d0d2e816"}, - {file = "ujson-5.10.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a890b706b64e0065f02577bf6d8ca3b66c11a5e81fb75d757233a38c07a1f20"}, - {file = "ujson-5.10.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:621e34b4632c740ecb491efc7f1fcb4f74b48ddb55e65221995e74e2d00bbff0"}, - {file = "ujson-5.10.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b9500e61fce0cfc86168b248104e954fead61f9be213087153d272e817ec7b4f"}, - {file = "ujson-5.10.0-cp313-cp313-win32.whl", hash = "sha256:4c4fc16f11ac1612f05b6f5781b384716719547e142cfd67b65d035bd85af165"}, - {file = "ujson-5.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:4573fd1695932d4f619928fd09d5d03d917274381649ade4328091ceca175539"}, - {file = "ujson-5.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a984a3131da7f07563057db1c3020b1350a3e27a8ec46ccbfbf21e5928a43050"}, - {file = "ujson-5.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:73814cd1b9db6fc3270e9d8fe3b19f9f89e78ee9d71e8bd6c9a626aeaeaf16bd"}, - {file = "ujson-5.10.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61e1591ed9376e5eddda202ec229eddc56c612b61ac6ad07f96b91460bb6c2fb"}, - {file = "ujson-5.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2c75269f8205b2690db4572a4a36fe47cd1338e4368bc73a7a0e48789e2e35a"}, - {file = "ujson-5.10.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7223f41e5bf1f919cd8d073e35b229295aa8e0f7b5de07ed1c8fddac63a6bc5d"}, - {file = "ujson-5.10.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d4dc2fd6b3067c0782e7002ac3b38cf48608ee6366ff176bbd02cf969c9c20fe"}, - {file = "ujson-5.10.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:232cc85f8ee3c454c115455195a205074a56ff42608fd6b942aa4c378ac14dd7"}, - {file = "ujson-5.10.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:cc6139531f13148055d691e442e4bc6601f6dba1e6d521b1585d4788ab0bfad4"}, - {file = "ujson-5.10.0-cp38-cp38-win32.whl", hash = "sha256:e7ce306a42b6b93ca47ac4a3b96683ca554f6d35dd8adc5acfcd55096c8dfcb8"}, - {file = "ujson-5.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:e82d4bb2138ab05e18f089a83b6564fee28048771eb63cdecf4b9b549de8a2cc"}, - {file = "ujson-5.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dfef2814c6b3291c3c5f10065f745a1307d86019dbd7ea50e83504950136ed5b"}, - {file = "ujson-5.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4734ee0745d5928d0ba3a213647f1c4a74a2a28edc6d27b2d6d5bd9fa4319e27"}, - {file = "ujson-5.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d47ebb01bd865fdea43da56254a3930a413f0c5590372a1241514abae8aa7c76"}, - {file = "ujson-5.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dee5e97c2496874acbf1d3e37b521dd1f307349ed955e62d1d2f05382bc36dd5"}, - {file = "ujson-5.10.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7490655a2272a2d0b072ef16b0b58ee462f4973a8f6bbe64917ce5e0a256f9c0"}, - {file = "ujson-5.10.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ba17799fcddaddf5c1f75a4ba3fd6441f6a4f1e9173f8a786b42450851bd74f1"}, - {file = "ujson-5.10.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2aff2985cef314f21d0fecc56027505804bc78802c0121343874741650a4d3d1"}, - {file = "ujson-5.10.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ad88ac75c432674d05b61184178635d44901eb749786c8eb08c102330e6e8996"}, - {file = "ujson-5.10.0-cp39-cp39-win32.whl", hash = "sha256:2544912a71da4ff8c4f7ab5606f947d7299971bdd25a45e008e467ca638d13c9"}, - {file = "ujson-5.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:3ff201d62b1b177a46f113bb43ad300b424b7847f9c5d38b1b4ad8f75d4a282a"}, - {file = "ujson-5.10.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5b6fee72fa77dc172a28f21693f64d93166534c263adb3f96c413ccc85ef6e64"}, - {file = "ujson-5.10.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:61d0af13a9af01d9f26d2331ce49bb5ac1fb9c814964018ac8df605b5422dcb3"}, - {file = "ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecb24f0bdd899d368b715c9e6664166cf694d1e57be73f17759573a6986dd95a"}, - {file = "ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fbd8fd427f57a03cff3ad6574b5e299131585d9727c8c366da4624a9069ed746"}, - {file = "ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:beeaf1c48e32f07d8820c705ff8e645f8afa690cca1544adba4ebfa067efdc88"}, - {file = "ujson-5.10.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:baed37ea46d756aca2955e99525cc02d9181de67f25515c468856c38d52b5f3b"}, - {file = "ujson-5.10.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7663960f08cd5a2bb152f5ee3992e1af7690a64c0e26d31ba7b3ff5b2ee66337"}, - {file = "ujson-5.10.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:d8640fb4072d36b08e95a3a380ba65779d356b2fee8696afeb7794cf0902d0a1"}, - {file = "ujson-5.10.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78778a3aa7aafb11e7ddca4e29f46bc5139131037ad628cc10936764282d6753"}, - {file = "ujson-5.10.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0111b27f2d5c820e7f2dbad7d48e3338c824e7ac4d2a12da3dc6061cc39c8e6"}, - {file = "ujson-5.10.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:c66962ca7565605b355a9ed478292da628b8f18c0f2793021ca4425abf8b01e5"}, - {file = "ujson-5.10.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ba43cc34cce49cf2d4bc76401a754a81202d8aa926d0e2b79f0ee258cb15d3a4"}, - {file = "ujson-5.10.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ac56eb983edce27e7f51d05bc8dd820586c6e6be1c5216a6809b0c668bb312b8"}, - {file = "ujson-5.10.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f44bd4b23a0e723bf8b10628288c2c7c335161d6840013d4d5de20e48551773b"}, - {file = "ujson-5.10.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c10f4654e5326ec14a46bcdeb2b685d4ada6911050aa8baaf3501e57024b804"}, - {file = "ujson-5.10.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0de4971a89a762398006e844ae394bd46991f7c385d7a6a3b93ba229e6dac17e"}, - {file = "ujson-5.10.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e1402f0564a97d2a52310ae10a64d25bcef94f8dd643fcf5d310219d915484f7"}, - {file = "ujson-5.10.0.tar.gz", hash = "sha256:b3cd8f3c5d8c7738257f1018880444f7b7d9b66232c64649f562d7ba86ad4bc1"}, -] - [[package]] name = "urllib3" -version = "2.2.1" +version = "2.2.2" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, - {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, + {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, + {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, ] [package.extras] @@ -2192,13 +2061,13 @@ files = [ [[package]] name = "writer-sdk" -version = "0.1.2" +version = "0.5.0" description = "The official Python library for the writer API" optional = false python-versions = ">=3.7" files = [ - {file = "writer_sdk-0.1.2-py3-none-any.whl", hash = "sha256:2072f5c13b8011a0c2ebe1b63fbc041642e9e9ca6eab7e976f7b3f20ad9931e5"}, - {file = "writer_sdk-0.1.2.tar.gz", hash = "sha256:3fa0b09a57ba969ca344024fa46305cd441cb45cb34d26d65a51a743477a4315"}, + {file = "writer_sdk-0.5.0-py3-none-any.whl", hash = "sha256:654e08fa0040126b8a8ae2468a9f2185997d94926a9322cee6278a721d098598"}, + {file = "writer_sdk-0.5.0.tar.gz", hash = "sha256:984f289f2576f8fbaec6893e9c83a0810a3084fbc536cc22666e0f620e8eff64"}, ] [package.dependencies] @@ -2212,4 +2081,4 @@ typing-extensions = ">=4.7,<5" [metadata] lock-version = "2.0" python-versions = ">=3.9.2, <4.0" -content-hash = "2b7dece7f8e0c504b0d1c393f324b8f86e382910106db130a9cfc129786fc138" +content-hash = "087a35e24f0286c5063c952de4bf460b036579e4956f1e598b9ac2172fa82cdd" diff --git a/pyproject.toml b/pyproject.toml index 217785bb0..dda4fb1e8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "writer" -version = "0.6.2rc2" +version = "0.6.2rc3" description = "An open-source, Python framework for building feature-rich apps that are fully integrated with the Writer platform." authors = ["Writer, Inc."] readme = "README.md" @@ -45,7 +45,7 @@ requests = "^2.31.0" uvicorn = ">= 0.20.0, < 1" watchdog = ">= 3.0.0, < 4" websockets = ">= 12, < 13" -writer-sdk = ">= 0.1.2, < 1" +writer-sdk = ">= 0.5.0, < 1" [tool.poetry.group.build] diff --git a/src/ui/.gitignore b/src/ui/.gitignore index e7d44cf12..624317c75 100644 --- a/src/ui/.gitignore +++ b/src/ui/.gitignore @@ -4,6 +4,7 @@ node_modules/ /blob-report/ /playwright/.cache/ storybook-static/ +src/stories/core_components/ *storybook.log /custom_components_dist diff --git a/src/ui/index.html b/src/ui/index.html index 446c389a2..1e34d5333 100644 --- a/src/ui/index.html +++ b/src/ui/index.html @@ -3,10 +3,6 @@ - - - - Writer Framework diff --git a/src/ui/src/builder/BuilderFieldsObject.vue b/src/ui/src/builder/BuilderFieldsObject.vue index f5bce3874..9d4ef6f1d 100644 --- a/src/ui/src/builder/BuilderFieldsObject.vue +++ b/src/ui/src/builder/BuilderFieldsObject.vue @@ -1,18 +1,16 @@ - -textarea { - resize: vertical; -} + diff --git a/src/ui/src/builder/BuilderFieldsWidth.vue b/src/ui/src/builder/BuilderFieldsWidth.vue index f2e8dcbd6..aa0f4d919 100644 --- a/src/ui/src/builder/BuilderFieldsWidth.vue +++ b/src/ui/src/builder/BuilderFieldsWidth.vue @@ -1,5 +1,10 @@ + + + + diff --git a/src/ui/src/core_components/content/CoreMessage.vue b/src/ui/src/core_components/content/CoreMessage.vue index b75e367ee..294b02f22 100644 --- a/src/ui/src/core_components/content/CoreMessage.vue +++ b/src/ui/src/core_components/content/CoreMessage.vue @@ -24,16 +24,13 @@ else: {{ messageWithoutPrefix }} -
-

Blank message

-
+ + + + + diff --git a/src/ui/src/core_components/input/CoreTimeInput.vue b/src/ui/src/core_components/input/CoreTimeInput.vue new file mode 100644 index 000000000..c64289dd5 --- /dev/null +++ b/src/ui/src/core_components/input/CoreTimeInput.vue @@ -0,0 +1,100 @@ + + + + + + diff --git a/src/ui/src/fonts.ts b/src/ui/src/fonts.ts new file mode 100644 index 000000000..64394e08b --- /dev/null +++ b/src/ui/src/fonts.ts @@ -0,0 +1,12 @@ +import "@fontsource-variable/material-symbols-outlined"; + +import "@fontsource/poppins/300-italic.css"; +import "@fontsource/poppins/300.css"; +import "@fontsource/poppins/400-italic.css"; +import "@fontsource/poppins/400.css"; +import "@fontsource/poppins/500-italic.css"; +import "@fontsource/poppins/500.css"; +import "@fontsource/poppins/600-italic.css"; +import "@fontsource/poppins/600.css"; +import "@fontsource/poppins/700-italic.css"; +import "@fontsource/poppins/700.css"; diff --git a/src/ui/src/main.ts b/src/ui/src/main.ts index 259868ddc..2afdf72b7 100644 --- a/src/ui/src/main.ts +++ b/src/ui/src/main.ts @@ -1,9 +1,10 @@ import * as vue from "vue"; import { App, createApp } from "vue"; -import injectionKeys from "./injectionKeys"; -import { generateCore } from "./core"; -import { generateBuilderManager } from "./builder/builderManager.js"; import VueDOMPurifyHTML from "vue-dompurify-html"; +import { generateBuilderManager } from "./builder/builderManager.js"; +import { generateCore } from "./core"; +import "./fonts"; +import injectionKeys from "./injectionKeys"; /** * RemixIcon by remixicon.com diff --git a/src/ui/src/renderer/ChildlessPlaceholder.vue b/src/ui/src/renderer/ChildlessPlaceholder.vue index 3b15fb475..c90bc4653 100644 --- a/src/ui/src/renderer/ChildlessPlaceholder.vue +++ b/src/ui/src/renderer/ChildlessPlaceholder.vue @@ -1,32 +1,23 @@ + - diff --git a/src/ui/src/renderer/useEvaluator.ts b/src/ui/src/renderer/useEvaluator.ts index ebb39642c..d402efad8 100644 --- a/src/ui/src/renderer/useEvaluator.ts +++ b/src/ui/src/renderer/useEvaluator.ts @@ -111,7 +111,6 @@ export function useEvaluator(wf: Core) { instancePath: InstancePath, ): string { if (template === undefined || template === null) return ""; - const evaluatedTemplate = template.replace( templateRegex, (match, captured) => { diff --git a/src/ui/src/renderer/useFormValueBroker.ts b/src/ui/src/renderer/useFormValueBroker.ts index 8d19dabd7..3d2623973 100644 --- a/src/ui/src/renderer/useFormValueBroker.ts +++ b/src/ui/src/renderer/useFormValueBroker.ts @@ -1,6 +1,6 @@ import { ComponentPublicInstance, computed, Ref, ref, watch } from "vue"; -import { Core, InstancePath } from "../writerTypes"; import { useEvaluator } from "../renderer/useEvaluator"; +import { Core, InstancePath } from "../writerTypes"; /** * @@ -10,14 +10,14 @@ import { useEvaluator } from "../renderer/useEvaluator"; * @param componentId * @returns */ -export function useFormValueBroker( +export function useFormValueBroker( wf: Core, instancePath: InstancePath, emitterEl: Ref, ) { - const formValue: Ref = ref(); + const formValue: Ref = ref(); const isBusy = ref(false); - const queuedEvent: Ref<{ eventValue: any; emitEventType: string }> = + const queuedEvent: Ref<{ eventValue: T; emitEventType: string }> = ref(null); const componentId = instancePath.at(-1).componentId; diff --git a/src/writer/ai.py b/src/writer/ai.py index 5e5e0c5a4..ae9655de2 100644 --- a/src/writer/ai.py +++ b/src/writer/ai.py @@ -1,31 +1,58 @@ import logging -from typing import Generator, Iterable, List, Literal, Optional, TypedDict, Union, cast +from datetime import datetime +from typing import ( + Generator, + Iterable, + List, + Literal, + Optional, + Set, + TypedDict, + Union, + cast, +) +from uuid import uuid4 from httpx import Timeout from writerai import Writer from writerai._exceptions import WriterError +from writerai._response import BinaryAPIResponse from writerai._streaming import Stream from writerai._types import Body, Headers, NotGiven, Query -from writerai.types import Chat, Completion, StreamingData +from writerai.resources import FilesResource, GraphsResource +from writerai.types import ( + Chat, + Completion, + FileDeleteResponse, + GraphDeleteResponse, + GraphRemoveFileFromGraphResponse, + GraphUpdateResponse, + StreamingData, +) +from writerai.types import File as SDKFile +from writerai.types import Graph as SDKGraph from writerai.types.chat_chat_params import Message as WriterAIMessage from writer.core import get_app_process -class ChatOptions(TypedDict, total=False): +class APIOptions(TypedDict, total=False): + extra_headers: Optional[Headers] + extra_query: Optional[Query] + extra_body: Optional[Body] + timeout: Union[float, Timeout, None, NotGiven] + + +class ChatOptions(APIOptions, total=False): model: str max_tokens: Union[int, NotGiven] n: Union[int, NotGiven] stop: Union[List[str], str, NotGiven] temperature: Union[float, NotGiven] top_p: Union[float, NotGiven] - extra_headers: Optional[Headers] - extra_query: Optional[Query] - extra_body: Optional[Body] - timeout: Union[float, Timeout, None, NotGiven] -class CreateOptions(TypedDict, total=False): +class CreateOptions(APIOptions, total=False): model: str best_of: Union[int, NotGiven] max_tokens: Union[int, NotGiven] @@ -33,10 +60,13 @@ class CreateOptions(TypedDict, total=False): stop: Union[List[str], str, NotGiven] temperature: Union[float, NotGiven] top_p: Union[float, NotGiven] - extra_headers: Optional[Headers] - extra_query: Optional[Query] - extra_body: Optional[Body] - timeout: Union[float, Timeout, None, NotGiven] + + +class APIListOptions(APIOptions, total=False): + after: Union[str, NotGiven] + before: Union[str, NotGiven] + limit: Union[int, NotGiven] + order: Union[Literal["asc", "desc"], NotGiven] logger = logging.Logger(__name__) @@ -141,6 +171,510 @@ def acquire_client(cls) -> Writer: return instance.client +class SDKWrapper: + """ + A wrapper class for SDK objects, allowing dynamic access to properties. + + Attributes: + _wrapped (Union[SDKFile, SDKGraph]): The wrapped SDK object. + """ + _wrapped: Union[SDKFile, SDKGraph] + + def _get_property(self, property_name): + """ + Retrieves a property from the wrapped object. + + :param property_name: The name of the property to retrieve. + :type property_name: str + :returns: The value of the requested property. + :raises AttributeError: If the property does not exist. + """ + try: + return getattr(self._wrapped, property_name) + except AttributeError: + raise AttributeError( + f"type object '{self.__class__}' has no attribute {property_name}" + ) from None + + +class Graph(SDKWrapper): + """ + A wrapper class for SDKGraph objects, providing additional functionality. + + Attributes: + _wrapped (writerai.types.Graph): The wrapped SDK Graph object. + stale_ids (set): A set of stale graph IDs that need updates. + """ + _wrapped: SDKGraph + stale_ids: Set[str] = set() + + def __init__( + self, + graph_object: SDKGraph + ): + """ + Initializes the Graph with the given SDKGraph object. + + :param graph_object: The SDKGraph object to wrap. + :type graph_object: writerai.types.Graph + """ + self._wrapped = graph_object + + @staticmethod + def _retrieve_graphs_accessor() -> GraphsResource: + """ + Acquires the graphs accessor from the WriterAIManager singleton instance. + + :returns: The graphs accessor instance. + :rtype: GraphsResource + """ + return WriterAIManager.acquire_client().graphs + + @property + def id(self) -> str: + return self._get_property('id') + + @property + def created_at(self) -> datetime: + return self._get_property('created_at') + + def _fetch_object_updates(self): + """ + Fetches updates for the graph object if it is stale. + """ + if self.id in Graph.stale_ids: + graphs = self._retrieve_graphs_accessor() + fresh_object = graphs.retrieve(self.id) + self._wrapped = fresh_object + Graph.stale_ids.remove(self.id) + + @property + def name(self) -> str: + self._fetch_object_updates() + return self._wrapped.name + + @property + def description(self) -> Optional[str]: + self._fetch_object_updates() + return self._wrapped.description + + @property + def file_status(self): + self._fetch_object_updates() + return self._wrapped.file_status + + def update( + self, + name: Optional[str] = None, + description: Optional[str] = None, + config: Optional[APIOptions] = None + ) -> GraphUpdateResponse: + """ + Updates the graph with the given parameters. + + :param name: The new name for the graph. + :type name: Optional[str] + :param description: The new description for the graph. + :type description: Optional[str] + :param config: Additional configuration options. + :type config: Optional[APIOptions] + :returns: The response from the update operation. + :rtype: GraphUpdateResponse + + The `config` dictionary can include the following keys: + - `extra_headers` (Optional[Headers]): Additional headers for the request. + - `extra_query` (Optional[Query]): Additional query parameters for the request. + - `extra_body` (Optional[Body]): Additional body parameters for the request. + - `timeout` (Union[float, httpx.Timeout, None, NotGiven]): Timeout for the request. + """ + config = config or {} + + # We use the payload dictionary + # to distinguish between None-values + # and NotGiven values + payload = {} + if name: + payload["name"] = name + if description: + payload["description"] = description + graphs = self._retrieve_graphs_accessor() + response = graphs.update(self.id, **payload, **config) + Graph.stale_ids.add(self.id) + return response + + def add_file( + self, + file_id_or_file: Union['File', str], + config: Optional[APIOptions] = None + ) -> 'File': + """ + Adds a file to the graph. + + :param file_id_or_file: The file object or file ID to add. + :type file_id_or_file: Union['File', str] + :param config: Additional configuration options. + :type config: Optional[APIOptions] + :returns: The added file object. + :rtype: File + :raises ValueError: If the input is neither a File object nor a file ID string. + + The `config` dictionary can include the following keys: + - `extra_headers` (Optional[Headers]): Additional headers for the request. + - `extra_query` (Optional[Query]): Additional query parameters for the request. + - `extra_body` (Optional[Body]): Additional body parameters for the request. + - `timeout` (Union[float, httpx.Timeout, None, NotGiven]): Timeout for the request. + """ + config = config or {} + file_id = None + if isinstance(file_id_or_file, File): + file_id = file_id_or_file.id + elif isinstance(file_id_or_file, str): + file_id = file_id_or_file + else: + raise ValueError( + "'Graph.add_file' method accepts either 'File' object" + + f" or ID of file as string; got '{type(file_id_or_file)}'" + ) + graphs = self._retrieve_graphs_accessor() + response = graphs.add_file_to_graph( + graph_id=self.id, + file_id=file_id, + **config + ) + Graph.stale_ids.add(self.id) + return File(response) + + def remove_file( + self, + file_id_or_file: Union['File', str], + config: Optional[APIOptions] = None + ) -> Optional[GraphRemoveFileFromGraphResponse]: + """ + Removes a file from the graph. + + :param file_id_or_file: The file object or file ID to remove. + :type file_id_or_file: Union['File', str] + :param config: Additional configuration options. + :type config: Optional[APIOptions] + :returns: The response from the remove operation. + :rtype: Optional[GraphRemoveFileFromGraphResponse] + :raises ValueError: If the input is neither a File object nor a file ID string. + + The `config` dictionary can include the following keys: + - `extra_headers` (Optional[Headers]): Additional headers for the request. + - `extra_query` (Optional[Query]): Additional query parameters for the request. + - `extra_body` (Optional[Body]): Additional body parameters for the request. + - `timeout` (Union[float, httpx.Timeout, None, NotGiven]): Timeout for the request. + """ + config = config or {} + file_id = None + if isinstance(file_id_or_file, File): + file_id = file_id_or_file.id + elif isinstance(file_id_or_file, str): + file_id = file_id_or_file + else: + raise ValueError( + "'Graph.remove_file' method accepts either 'File' object" + + f" or ID of file as string; got '{type(file_id_or_file)}'" + ) + graphs = self._retrieve_graphs_accessor() + response = graphs.remove_file_from_graph( + graph_id=self.id, + file_id=file_id + ) + Graph.stale_ids.add(self.id) + return response + + +def create_graph( + name: str, + description: Optional[str] = None, + config: Optional[APIOptions] = None + ) -> Graph: + """ + Creates a new graph with the given parameters. + + :param name: The name of the graph. + :type name: str + :param description: The description of the graph. + :type description: Optional[str] + :param config: Additional configuration options. + :type config: Optional[APIOptions] + :returns: The created graph object. + :rtype: Graph + + The `config` dictionary can include the following keys: + - `extra_headers` (Optional[Headers]): Additional headers for the request. + - `extra_query` (Optional[Query]): Additional query parameters for the request. + - `extra_body` (Optional[Body]): Additional body parameters for the request. + - `timeout` (Union[float, httpx.Timeout, None, NotGiven]): Timeout for the request. + """ + config = config or {} + graphs = Graph._retrieve_graphs_accessor() + graph_object = graphs.create(name=name, description=description or NotGiven(), **config) + converted_object = cast(SDKGraph, graph_object) + graph = Graph(converted_object) + return graph + + +def retrieve_graph( + graph_id: str, + config: Optional[APIOptions] = None + ) -> Graph: + """ + Retrieves a graph by its ID. + + :param graph_id: The ID of the graph to retrieve. + :type graph_id: str + :param config: Additional configuration options. + :type config: Optional[APIOptions] + :returns: The retrieved graph object. + :rtype: Graph + + The `config` dictionary can include the following keys: + - `extra_headers` (Optional[Headers]): Additional headers for the request. + - `extra_query` (Optional[Query]): Additional query parameters for the request. + - `extra_body` (Optional[Body]): Additional body parameters for the request. + - `timeout` (Union[float, httpx.Timeout, None, NotGiven]): Timeout for the request. + """ + config = config or {} + graphs = Graph._retrieve_graphs_accessor() + graph_object = graphs.retrieve(graph_id, **config) + graph = Graph(graph_object) + return graph + + +def list_graphs(config: Optional[APIListOptions] = None) -> List[Graph]: + """ + Lists all graphs with the given configuration. + + :param config: Additional configuration options. + :type config: Optional[APIListOptions] + :returns: A list of graph objects. + :rtype: List[Graph] + + The `config` dictionary can include the following keys: + - `extra_headers` (Optional[Headers]): Additional headers for the request. + - `extra_query` (Optional[Query]): Additional query parameters for the request. + - `extra_body` (Optional[Body]): Additional body parameters for the request. + - `timeout` (Union[float, httpx.Timeout, None, NotGiven]): Timeout for the request. + - `after` (Union[str, NotGiven]): Filter to retrieve items created after a specific cursor. + - `before` (Union[str, NotGiven]): Filter to retrieve items created before a specific cursor. + - `limit` (Union[int, NotGiven]): The number of items to retrieve. + - `order` (Union[Literal["asc", "desc"], NotGiven]): The order in which to retrieve items. + """ + config = config or {} + graphs = Graph._retrieve_graphs_accessor() + sdk_graphs = graphs.list(**config) + return [Graph(sdk_graph) for sdk_graph in sdk_graphs] + + +def delete_graph(graph_id_or_graph: Union[Graph, str]) -> GraphDeleteResponse: + """ + Deletes a graph by its ID or object. + + :param graph_id_or_graph: The graph object or graph ID to delete. + :type graph_id_or_graph: Union[Graph, str] + :returns: The response from the delete operation. + :rtype: GraphDeleteResponse + :raises ValueError: If the input is neither a Graph object nor a graph ID string. + """ + graph_id = None + if isinstance(graph_id_or_graph, Graph): + graph_id = graph_id_or_graph.id + elif isinstance(graph_id_or_graph, str): + graph_id = graph_id_or_graph + else: + raise ValueError( + "'delete_graph' method accepts either 'Graph' object" + + f" or ID of graph as string; got '{type(graph_id_or_graph)}'" + ) + graphs = Graph._retrieve_graphs_accessor() + return graphs.delete(graph_id) + + +class File(SDKWrapper): + """ + A wrapper class for SDK File objects, providing additional functionality. + + Attributes: + _wrapped (writerai.types.File): The wrapped SDKFile object. + """ + _wrapped: SDKFile + + def __init__(self, file_object: SDKFile): + """ + Initializes the File with the given SDKFile object. + + :param file_object: The SDKFile object to wrap. + :type file_object: writerai.types.File + """ + self._wrapped = file_object + + @staticmethod + def _retrieve_files_accessor() -> FilesResource: + """ + Acquires the files client from the WriterAIManager singleton instance. + + :returns: The files client instance. + :rtype: FilesResource + """ + return WriterAIManager.acquire_client().files + + @property + def id(self) -> str: + return self._get_property('id') + + @property + def created_at(self) -> datetime: + return self._get_property('created_at') + + @property + def graph_ids(self) -> List[str]: + return self._get_property('graph_ids') + + @property + def name(self) -> str: + return self._get_property('name') + + def download(self) -> BinaryAPIResponse: + """ + Downloads the file content. + + :returns: The response containing the file content. + :rtype: BinaryAPIResponse + """ + files = self._retrieve_files_accessor() + return files.download(self.id) + + +def retrieve_file(file_id: str, config: Optional[APIOptions] = None) -> File: + """ + Retrieves a file by its ID. + + :param file_id: The ID of the file to retrieve. + :type file_id: str + :param config: Additional configuration options. + :type config: Optional[APIOptions] + :returns: The retrieved file object. + :rtype: writerai.types.File + + The `config` dictionary can include the following keys: + - `extra_headers` (Optional[Headers]): Additional headers for the request. + - `extra_query` (Optional[Query]): Additional query parameters for the request. + - `extra_body` (Optional[Body]): Additional body parameters for the request. + - `timeout` (Union[float, httpx.Timeout, None, NotGiven]): Timeout for the request. + """ + config = config or {} + files = File._retrieve_files_accessor() + file_object = files.retrieve(file_id, **config) + file = File(file_object) + return file + + +def list_files(config: Optional[APIListOptions] = None) -> List[File]: + """ + Lists all files with the given configuration. + + :param config: Additional configuration options. + :type config: Optional[APIListOptions] + :returns: A list of file objects. + :rtype: List[File] + + The `config` dictionary can include the following keys: + - `extra_headers` (Optional[Headers]): Additional headers for the request. + - `extra_query` (Optional[Query]): Additional query parameters for the request. + - `extra_body` (Optional[Body]): Additional body parameters for the request. + - `timeout` (Union[float, httpx.Timeout, None, NotGiven]): Timeout for the request. + - `after` (Union[str, NotGiven]): Filter to retrieve items created after a specific cursor. + - `before` (Union[str, NotGiven]): Filter to retrieve items created before a specific cursor. + - `limit` (Union[int, NotGiven]): The number of items to retrieve. + - `order` (Union[Literal["asc", "desc"], NotGiven]): The order in which to retrieve items. + """ + config = config or {} + files = File._retrieve_files_accessor() + sdk_files = files.list(**config) + return [File(sdk_file) for sdk_file in sdk_files] + + +def upload_file( + data: bytes, + type: str, + name: Optional[str] = None, + config: Optional[APIOptions] = None + ) -> File: + """ + Uploads a new file with the given parameters. + + :param data: The file content as bytes. + :type data: bytes + :param type: The MIME type of the file. + :type type: str + :param name: The name of the file. + :type name: Optional[str] + :param config: Additional configuration options. + :type config: Optional[APIOptions] + :returns: The uploaded file object. + :rtype: writerai.types.File + + The `config` dictionary can include the following keys: + - `extra_headers` (Optional[Headers]): Additional headers for the request. + - `extra_query` (Optional[Query]): Additional query parameters for the request. + - `extra_body` (Optional[Body]): Additional body parameters for the request. + - `timeout` (Union[float, httpx.Timeout, None, NotGiven]): Timeout for the request. + """ + config = config or {} + files = File._retrieve_files_accessor() + + file_name = name or f"WF-{type}-{uuid4()}" + content_disposition = f'attachment; filename="{file_name}"' + + # Now calling the upload method with correct types. + sdk_file = files.upload( + content=data, + content_type=type, + content_disposition=content_disposition + ) + return File(sdk_file) + + +def delete_file( + file_id_or_file: Union['File', str], + config: Optional[APIOptions] = None + ) -> FileDeleteResponse: + """ + Deletes a file by its ID or object. + + :param file_id_or_file: The file object or file ID to delete. + :type file_id_or_file: Union['File', str] + :param config: Additional configuration options. + :type config: Optional[APIOptions] + :returns: The response from the delete operation. + :rtype: FileDeleteResponse + :raises ValueError: If the input is neither a File object nor a file ID string. + + The `config` dictionary can include the following keys: + - `extra_headers` (Optional[Headers]): Additional headers for the request. + - `extra_query` (Optional[Query]): Additional query parameters for the request. + - `extra_body` (Optional[Body]): Additional body parameters for the request. + - `timeout` (Union[float, httpx.Timeout, None, NotGiven]): Timeout for the request. + """ + config = config or {} + file_id = None + if isinstance(file_id_or_file, File): + file_id = file_id_or_file.id + elif isinstance(file_id_or_file, str): + file_id = file_id_or_file + else: + raise ValueError( + "'delete_file' method accepts either 'File' object" + + f" or ID of file as string; got '{type(file_id_or_file)}'" + ) + + files = File._retrieve_files_accessor() + return files.delete(file_id, **config) + + class Conversation: """ Manages messages within a conversation flow with an AI system, including message validation, @@ -307,8 +841,7 @@ def complete(self, config: Optional['ChatOptions'] = None) -> 'Conversation.Mess :return: Generated message. :raises RuntimeError: If response data was not properly formatted to retrieve model text. """ - if not config: - config = {'max_tokens': 2048} + config = config or {'max_tokens': 2048} client = WriterAIManager.acquire_client() passed_messages: Iterable[WriterAIMessage] = [self._prepare_message(message) for message in self.messages] @@ -343,8 +876,7 @@ def stream_complete(self, config: Optional['ChatOptions'] = None) -> Generator[d :param config: Optional parameters to pass for processing. :yields: Model response chunks as they arrive from the stream. """ - if not config: - config = {'max_tokens': 2048} + config = config or {'max_tokens': 2048} client = WriterAIManager.acquire_client() passed_messages: Iterable[WriterAIMessage] = [self._prepare_message(message) for message in self.messages] @@ -403,8 +935,7 @@ def complete(initial_text: str, config: Optional['CreateOptions'] = None) -> str :return: The text of the first choice from the completion response. :raises RuntimeError: If response data was not properly formatted to retrieve model text. """ - if not config: - config = {} + config = config or {} client = WriterAIManager.acquire_client() request_model = config.get("model", None) or WriterAIManager.use_completion_model() diff --git a/src/writer/core.py b/src/writer/core.py index c72a755f7..8cb2cf442 100644 --- a/src/writer/core.py +++ b/src/writer/core.py @@ -1053,6 +1053,19 @@ def _transform_date_change(self, ev) -> str: return payload + def _transform_time_change(self, ev) -> str: + payload = ev.payload + + if not isinstance(payload, str): + raise ValueError("Time must be a string.") + try: + time.strptime(payload, '%H:%M') + except ValueError: + raise ValueError( + "Time must be in hh:mm format (in 24-hour format that includes leading zeros).") + + return payload + def _transform_change_page_size(self, ev) -> Optional[int]: try: return int(ev.payload) diff --git a/src/writer/deploy.py b/src/writer/deploy.py index 1f746328c..d09bdf654 100644 --- a/src/writer/deploy.py +++ b/src/writer/deploy.py @@ -15,6 +15,7 @@ WRITER_DEPLOY_URL = os.getenv("WRITER_DEPLOY_URL", "https://api.writer.com/v1/deployment/apps") def deploy(path, token, env): + check_app(token) tar = pack_project(path) upload_package(tar, token, env) @@ -90,6 +91,27 @@ def match(file_path) -> bool: return False return f + +def check_app(token): + url = get_app_url(token) + if url: + print("[WARNING] This token was already used to deploy a different app") + print(f"[WARNING] URL: {url}") + print("[WARNING] If looking to deploy to a different URL, use a different API key. ") + if input("[WARNING] Are you sure you want to overwrite? (y/N)").lower() != "y": + sys.exit(1) + +def get_app_url(token): + with requests.get(WRITER_DEPLOY_URL, params={"lineLimit": 1}, headers={"Authorization": f"Bearer {token}"}) as resp: + try: + resp.raise_for_status() + except Exception as e: + print(e) + print(resp.json()) + return None + data = resp.json() + return data['status']['url'] + def get_logs(token, params): with requests.get(WRITER_DEPLOY_URL, params = params, headers={"Authorization": f"Bearer {token}"}) as resp: try: diff --git a/src/writer/serve.py b/src/writer/serve.py index 312922ce5..f52611344 100644 --- a/src/writer/serve.py +++ b/src/writer/serve.py @@ -62,10 +62,25 @@ def get_asgi_app( user_app_path: str, serve_mode: ServeMode, enable_remote_edit: bool = False, - enable_server_setup: bool = False, + enable_server_setup: bool = True, on_load: Optional[Callable] = None, on_shutdown: Optional[Callable] = None, ) -> WriterFastAPI: + """ + Builds an ASGI server that can be injected into another ASGI application + or an asgi server like uvicorn + + >>> asgi_app = writer.serve.get_asgi_app("app1", "run") + >>> uvicorn.run(asgi_app, host="0.0.0.0", port=5328) + + :param user_app_path: writer application path + :param serve_mode: server mode (run, edit) + :param enable_remote_edit: allow editing from the internet (by default, editing only works locally) + :param enable_server_setup: enables fastapi setup hook on startup, server_setup.py + :param on_load: callback called on loading + :param on_shutdown: callback called at shutdown + :return: ASGI Server + """ global app if serve_mode not in ["run", "edit"]: raise ValueError("""Invalid mode. Must be either "run" or "edit".""") diff --git a/tests/backend/test_ai.py b/tests/backend/test_ai.py index 0828062e2..b569f1a22 100644 --- a/tests/backend/test_ai.py +++ b/tests/backend/test_ai.py @@ -40,11 +40,33 @@ ``` """ +from datetime import datetime from unittest.mock import AsyncMock, MagicMock, patch import httpx import pytest -from writer.ai import Conversation, WriterAIManager, complete, init, stream_complete +from writer.ai import ( + Conversation, + File, + FileDeleteResponse, + Graph, + GraphDeleteResponse, + GraphRemoveFileFromGraphResponse, + SDKFile, + SDKGraph, + WriterAIManager, + complete, + create_graph, + delete_file, + delete_graph, + init, + list_files, + list_graphs, + retrieve_file, + retrieve_graph, + stream_complete, + upload_file, +) from writerai import Writer from writerai._streaming import Stream from writerai.types import Chat, ChatStreamingData, Completion, StreamingData @@ -116,6 +138,73 @@ def fake_response_content(): yield streaming_client +@pytest.fixture +def sdk_graph_mock(): + return SDKGraph( + id="test_graph_id", + created_at=datetime.now(), + file_status={"completed": 0, "failed": 0, "in_progress": 0, "total": 0}, + name="test_graph", + description="A test graph" + ) + + +@pytest.fixture +def sdk_file_mock(): + return SDKFile( + id="test_file_id", + created_at=datetime.now(), + graph_ids=["test_graph_id"], + name="test_file" + ) + + +@pytest.fixture +def mock_graphs_accessor(sdk_file_mock, sdk_graph_mock): + with patch('writer.ai.Graph._retrieve_graphs_accessor') as mock_acquire_client: + mock_accessor = MagicMock() + mock_graph = Graph(sdk_graph_mock) + mock_file = File(sdk_file_mock) + mock_accessor.create.return_value = mock_graph + mock_accessor.add_file_to_graph.return_value = mock_file + mock_accessor.retrieve.return_value = mock_graph + mock_accessor.list.return_value = [mock_graph] + mock_accessor.delete.return_value = GraphDeleteResponse(id="test_file_id", deleted=True) + mock_accessor.remove_file_from_graph.return_value = GraphRemoveFileFromGraphResponse(id="test_file_id", deleted=True) + + mock_acquire_client.return_value = mock_accessor + yield mock_accessor + + +@pytest.fixture +def mock_files_accessor(sdk_file_mock): + with patch('writer.ai.File._retrieve_files_accessor') as mock_acquire_client: + mock_accessor = MagicMock() + mock_file = File(sdk_file_mock) + mock_accessor.retrieve.return_value = mock_file + mock_accessor.list.return_value = [mock_file] + mock_accessor.upload.return_value = mock_file + mock_accessor.delete.return_value = FileDeleteResponse(id="test_delete", deleted=True) + mock_acquire_client.return_value = mock_accessor + yield mock_accessor + + +@pytest.fixture +def created_graphs(): + graphs = [] + yield graphs + for graph in graphs: + delete_graph(graph_id_or_graph=graph.id) + + +@pytest.fixture +def created_files(): + files = [] + yield files + for file in files: + delete_file(file_id_or_file=file.id) + + class FakeAppProcessForAIManager: def __init__(self, token): self.ai_manager = WriterAIManager(token=token) @@ -295,6 +384,92 @@ def test_init_writer_ai_manager(emulate_app_process): assert manager.client.api_key == "fake_token" +def test_create_graph(mock_graphs_accessor): + graph = create_graph(name="test_graph", description="A test graph") + + # As we modified SDK response, we expect this function + # to retrieve mock we prepared earlier + assert graph.id == "test_graph_id" + assert graph.name == "test_graph" + + +def test_retrieve_graph(mock_graphs_accessor): + graph = retrieve_graph(graph_id="test_id") + + # As we modified SDK response, we expect this function + # to retrieve mock we prepared earlier + assert graph.id == "test_graph_id" + assert graph.name == "test_graph" + + +def test_list_graphs(mock_graphs_accessor): + graphs = list_graphs() + + # As we modified SDK response, we expect this function + # to retrieve mock we prepared earlier + assert len(graphs) == 1 + assert graphs[0].id == "test_graph_id" + assert graphs[0].name == "test_graph" + + +def test_delete_graph(mock_graphs_accessor): + response = delete_graph(graph_id_or_graph="test_graph_id") + + # As we modified SDK response, we expect this function + # to retrieve mock we prepared earlier + assert response.deleted is True + + +def test_add_file_to_graph(mock_graphs_accessor, mock_files_accessor): + file = retrieve_file(file_id="test_file_id") + graph = retrieve_graph(graph_id="test_graph_id") + added_file = graph.add_file(file_id_or_file=file) + + # As we modified SDK response, we expect this function + # to retrieve mock we prepared earlier + assert added_file.id == "test_file_id" + assert added_file.name == "test_file" + # Graph update should also trigger addition of its ID to stale_ids set + assert "test_graph_id" in Graph.stale_ids + + +def test_retrieve_file(mock_files_accessor): + file = retrieve_file(file_id="test_file_id") + + # As we modified SDK response, we expect this function + # to retrieve mock we prepared earlier + assert file.id == "test_file_id" + assert file.name == "test_file" + + +def test_list_files(mock_files_accessor): + files = list_files() + + # As we modified SDK response, we expect this function + # to retrieve mock we prepared earlier + assert len(files) == 1 + assert files[0].id == "test_file_id" + assert files[0].name == "test_file" + + +def test_upload_file(mock_files_accessor): + data = b"file_content" + file = upload_file(data=data, type="text/plain", name="uploaded_file") + + # As we modified SDK response, we expect this function + # to retrieve mock we prepared earlier + assert file.id == "test_file_id" + assert file.name == "test_file" + + +def test_delete_file(mock_files_accessor): + response = delete_file(file_id_or_file="test_file_id") + + # As we modified SDK response, we expect this function + # to retrieve mock we prepared earlier + assert response.deleted is True + + @explicit def test_explicit_conversation_complete(emulate_app_process): conversation = Conversation() @@ -341,3 +516,90 @@ async def test_explicit_stream_complete(emulate_app_process): assert isinstance(full_response, str) assert len(full_response) > 0 assert "exercise" in full_response.lower() + + +@explicit +def test_explicit_create_graph(emulate_app_process, created_graphs): + graph = create_graph(name="integration_test_graph", description="Integration test graph") + created_graphs.append(graph) + assert graph.id is not None + assert graph.name == "integration_test_graph" + + +@explicit +def test_explicit_retrieve_graph(emulate_app_process, created_graphs): + created_graph = create_graph(name="integration_test_graph", description="Integration test graph") + created_graphs.append(created_graph) + graph = retrieve_graph(graph_id=created_graph.id) + + assert graph.id == created_graph.id + assert graph.name == created_graph.name + + +@explicit +def test_explicit_list_graphs(emulate_app_process, created_graphs): + # Create a graph to ensure there's at least one graph in the list + graph = create_graph(name="integration_test_graph", description="Integration test graph") + created_graphs.append(graph) + + graphs = list_graphs() + + assert len(graphs) > 0 + assert any(g.id == graph.id for g in graphs) + + +@explicit +def test_explicit_delete_graph(emulate_app_process, created_graphs): + created_graph = create_graph(name="integration_test_graph", description="Integration test graph") + created_graphs.append(created_graph) + response = delete_graph(graph_id_or_graph=created_graph.id) + + # Ensure the graph is removed from created_graphs + created_graphs.remove(created_graph) + + assert response.deleted is True + + +@explicit +def test_explicit_upload_file(emulate_app_process, created_files): + data = b"file_content" + file = upload_file(data=data, type="text/plain", name="integration_uploaded_file") + created_files.append(file) + + assert file.id is not None + assert file.name == "integration_uploaded_file.txt" + + +@explicit +def test_explicit_retrieve_file(emulate_app_process, created_files): + uploaded_file = upload_file(data=b"file_content", type="text/plain", name="integration_uploaded_file") + created_files.append(uploaded_file) + file = retrieve_file(file_id=uploaded_file.id) + + assert file.id == uploaded_file.id + assert file.name == uploaded_file.name + + +@explicit +def test_explicit_list_files(emulate_app_process, created_files): + # Upload a file to ensure there's at least one file in the list + data = b"file_content" + file = upload_file(data=data, type="text/plain", name="integration_uploaded_file") + created_files.append(file) + + files = list_files() + + assert len(files) > 0 + assert any(f.id == file.id for f in files) + + +@explicit +def test_explicit_delete_file(emulate_app_process, created_files): + uploaded_file = upload_file(data=b"file_content", type="text/plain", name="integration_uploaded_file") + created_files.append(uploaded_file) + response = delete_file(file_id_or_file=uploaded_file.id) + + # Ensure the file is removed from created_files + created_files.remove(uploaded_file) + + assert response.deleted is True diff --git a/tests/backend/test_auth.py b/tests/backend/test_auth.py index 6e7aa6f69..7236d0cff 100644 --- a/tests/backend/test_auth.py +++ b/tests/backend/test_auth.py @@ -12,7 +12,7 @@ def test_basicauth_authentication_module_should_ask_user_to_write_basic_auth(sel This test verifies that a user has to authenticate when the basic auth module is active. """ - asgi_app: fastapi.FastAPI = writer.serve.get_asgi_app(test_basicauth_dir, "run", enable_server_setup=True) + asgi_app: fastapi.FastAPI = writer.serve.get_asgi_app(test_basicauth_dir, "run") with fastapi.testclient.TestClient(asgi_app) as client: res = client.get("/api/init") assert res.status_code == 401 @@ -22,7 +22,16 @@ def test_basicauth_authentication_module_should_accept_user_using_authorization( This test verifies that a user can use the application when providing basic auth credentials. """ - asgi_app: fastapi.FastAPI = writer.serve.get_asgi_app(test_basicauth_dir, "run", enable_server_setup=True) + asgi_app: fastapi.FastAPI = writer.serve.get_asgi_app(test_basicauth_dir, "run") with fastapi.testclient.TestClient(asgi_app) as client: res = client.get("/static/file.js", auth=("admin", "admin")) assert res.status_code == 200 + + def test_basicauth_authentication_module_disabled_when_server_setup_hook_is_disabled(self): + """ + This test verifies that a user bypass the authentication when server setup hook is disabled. + """ + asgi_app: fastapi.FastAPI = writer.serve.get_asgi_app(test_basicauth_dir, "run", enable_server_setup=False) + with fastapi.testclient.TestClient(asgi_app) as client: + res = client.get("/api/init") + assert res.status_code == 405 diff --git a/tests/backend/test_core.py b/tests/backend/test_core.py index 434f3bc6e..7122c96a3 100644 --- a/tests/backend/test_core.py +++ b/tests/backend/test_core.py @@ -595,6 +595,23 @@ def test_date_change(self) -> None: self.ed.transform(ev_valid) assert ev_valid.payload == "2019-11-23" + def test_time_change(self) -> None: + ev_invalid = WriterEvent( + type="wf-time-change", + instancePath=self.root_instance_path, + payload="virus" + ) + with pytest.raises(RuntimeError): + self.ed.transform(ev_invalid) + + ev_valid = WriterEvent( + type="wf-time-change", + instancePath=self.root_instance_path, + payload="23:59" + ) + self.ed.transform(ev_valid) + assert ev_valid.payload == "23:59" + class TestFileWrapper(): diff --git a/tests/e2e/presets/state/main.py b/tests/e2e/presets/state/main.py index 5ac7c9ac7..957d50042 100644 --- a/tests/e2e/presets/state/main.py +++ b/tests/e2e/presets/state/main.py @@ -1,6 +1,12 @@ import writer as wf initial_state = wf.init_state({ + "types": { + "none": None, + "string": "Hello, World!", + "integer": 42, + "float": 3.14, + }, "counter": 26, "list": ["A", "B", "C"], "dict": {"a": 1, "b": 2}, diff --git a/tests/e2e/tests/button.spec.ts b/tests/e2e/tests/button.spec.ts index db0e06448..5adb10859 100644 --- a/tests/e2e/tests/button.spec.ts +++ b/tests/e2e/tests/button.spec.ts @@ -26,7 +26,7 @@ test.describe("button", () => { .dragTo(page.locator(".CoreSection .ChildlessPlaceholder")); await page.locator(COMPONENT_LOCATOR).click(); await page - .locator('.BuilderFieldsText[data-key="text"] input') + .locator('.BuilderFieldsText[data-automation-key="text"] input') .fill("Hello, World!"); await expect(page.locator(COMPONENT_LOCATOR)).toContainText( "Hello, World!", diff --git a/tests/e2e/tests/components.spec.ts b/tests/e2e/tests/components.spec.ts index b0cbacae8..2ae9bae2b 100644 --- a/tests/e2e/tests/components.spec.ts +++ b/tests/e2e/tests/components.spec.ts @@ -26,6 +26,7 @@ const mapComponents = { sidebar: {test: 'basic'}, fileinput: {locator: '.component.wf-type-fileinput label'}, dateinput: {locator: '.component.wf-type-dateinput label'}, + timeinput: {locator: '.component.wf-type-timeinput label'}, sliderinput: {locator: '.component.wf-type-sliderinput label'}, numberinput: {locator: '.component.wf-type-numberinput label'}, textinput: {locator: '.component.wf-type-textinput label'}, diff --git a/tests/e2e/tests/image.spec.ts b/tests/e2e/tests/image.spec.ts index dbb8aa1c4..71b255020 100644 --- a/tests/e2e/tests/image.spec.ts +++ b/tests/e2e/tests/image.spec.ts @@ -25,7 +25,7 @@ test.describe("image", () => { .dragTo(page.locator(".CoreSection .ChildlessPlaceholder")); await page.locator(COMPONENT_LOCATOR).click(); await page - .locator('.BuilderFieldsText[data-key="caption"] input') + .locator('.BuilderFieldsText[data-automation-key="caption"] input') .fill("Hello, World!"); await expect(page.locator(COMPONENT_LOCATOR)).toContainText( "Hello, World!", diff --git a/tests/e2e/tests/lowCode.spec.ts b/tests/e2e/tests/lowCode.spec.ts index 64451d88b..fc644aa3c 100644 --- a/tests/e2e/tests/lowCode.spec.ts +++ b/tests/e2e/tests/lowCode.spec.ts @@ -79,8 +79,8 @@ with ui.find('results'): await page.locator(`.results .wf-type-${type}.component`).click({force: true}); for (const [key, value] of Object.entries(props)) { - await expect(page.locator(`.BuilderSettings div[data-key="${key}"] input, .BuilderSettings div[data-key="${key}"] textarea`)).toHaveCount(1); - await expect(page.locator(`.BuilderSettings div[data-key="${key}"] input, .BuilderSettings div[data-key="${key}"] textarea`)).toHaveValue(value); + await expect(page.locator(`.BuilderSettings div[data-automation-key="${key}"] input, .BuilderSettings div[data-automation-key="${key}"] textarea`)).toHaveCount(1); + await expect(page.locator(`.BuilderSettings div[data-automation-key="${key}"] input, .BuilderSettings div[data-automation-key="${key}"] textarea`)).toHaveValue(value); } if (renderError) { diff --git a/tests/e2e/tests/reuse.spec.ts b/tests/e2e/tests/reuse.spec.ts index 7a32a84e0..361d2a6c8 100644 --- a/tests/e2e/tests/reuse.spec.ts +++ b/tests/e2e/tests/reuse.spec.ts @@ -6,7 +6,7 @@ test.describe("Reuse component", () => { const fillSettingsField = async (page: Page, key: string, value: string) => { await page - .locator(`.BuilderFieldsText[data-key="${key}"] input, .BuilderFieldsText[data-key="${key}"] textarea`) + .locator(`.BuilderFieldsText[data-automation-key="${key}"] input, .BuilderFieldsText[data-automation-key="${key}"] textarea`) .fill(value); } diff --git a/tests/e2e/tests/state.spec.ts b/tests/e2e/tests/state.spec.ts index b00a2359a..cdedfa6f1 100644 --- a/tests/e2e/tests/state.spec.ts +++ b/tests/e2e/tests/state.spec.ts @@ -4,7 +4,7 @@ import { test, expect } from "@playwright/test"; const setTextField = async (page, text) => { await page.locator('div.CoreText.component').click(); await page - .locator('.BuilderFieldsText[data-key="text"] textarea') + .locator('.BuilderFieldsText[data-automation-key="text"] .templateInput') .fill(text); } diff --git a/tests/e2e/tests/stateAutocompletion.spec.ts b/tests/e2e/tests/stateAutocompletion.spec.ts new file mode 100644 index 000000000..8ab514c41 --- /dev/null +++ b/tests/e2e/tests/stateAutocompletion.spec.ts @@ -0,0 +1,144 @@ + +import { test, expect } from "@playwright/test"; + +const setTextField = async (page, text) => { + await page.locator('div.CoreText.component').click(); + await page + .locator('.BuilderFieldsText[data-automation-key="text"] .templateInput') + .fill(text); +} + +test.describe("state autocompletion", () => { + let url: string; + test.beforeAll(async ({request}) => { + const response = await request.post(`/preset/state`); + expect(response.ok()).toBeTruthy(); + ({url} = await response.json()); + }); + + test.afterAll(async ({request}) => { + await request.delete(url); + }); + + test.beforeEach(async ({ page }) => { + await page.goto(url); + }); + + test.describe("text", () => { + test("completion", async ({ page }) => { + await setTextField(page, "@{types."); + page.locator('.BuilderFieldsText[data-automation-key="text"] .fieldStateAutocomplete span.prop:text-matches("string")').click(); + await expect(page + .locator('.BuilderFieldsText[data-automation-key="text"] .templateInput')) + .toHaveValue("@{types.string"); + }); + test("counter", async ({ page }) => { + await setTextField(page, "@{counter"); + await expect(page.locator('.BuilderFieldsText[data-automation-key="text"] .fieldStateAutocomplete span.prop')).toContainText(["counter"]); + await expect(page.locator('.BuilderFieldsText[data-automation-key="text"] .fieldStateAutocomplete span.type')).toContainText(["number"]); + }); + + test("types", async ({ page }) => { + await setTextField(page, "@{types."); + await expect(page.locator('.BuilderFieldsText[data-automation-key="text"] .fieldStateAutocomplete span.prop')).toHaveText(["none", "string", "integer", "float"]); + await expect(page.locator('.BuilderFieldsText[data-automation-key="text"] .fieldStateAutocomplete span.type')).toHaveText(["null", "string", "number", "number"]); + }); + + test("deeply nested", async ({ page }) => { + await setTextField(page, "@{nested.c."); + await expect(page.locator('.BuilderFieldsText[data-automation-key="text"] .fieldStateAutocomplete span.prop')).toContainText(["d", "e"]); + await expect(page.locator('.BuilderFieldsText[data-automation-key="text"] .fieldStateAutocomplete span.type')).toContainText(["number", "number"]); + }); + }); + + test.describe("text with dropdown", () => { + test("options should show on focus", async ({ page }) => { + await page.locator('div.CoreText.component').click(); + await page + .locator('.BuilderFieldsText[data-automation-key="useMarkdown"] .templateInput') + .focus(); + await expect(page.locator('.BuilderFieldsText[data-automation-key="useMarkdown"] datalist option[value="yes"]')).toHaveCount(1); + await expect(page.locator('.BuilderFieldsText[data-automation-key="useMarkdown"] datalist option[value="no"]')).toHaveCount(1); + }) + }); + + test.describe("Key-Value", () => { + test("Static List - completion", async ({ page }) => { + const FIELD = `.BuilderFieldsOptions[data-automation-key="options"]`; + await page + .locator(`div.component.button[data-component-type="radioinput"]`) + .dragTo(page.locator(".CorePage")); + + await page.locator('div.CoreRadioInput.component > label').click(); + await page + .locator(`${FIELD} button.chip:text-matches("Static List")`) + .click(); + await page + .locator(`${FIELD} .inputKey .templateInput`) + .fill("@{types."); + await expect(page.locator(`${FIELD} .inputKey .fieldStateAutocomplete span.prop`)).toHaveText(["none", "string", "integer", "float"]); + await expect(page.locator(`${FIELD} .inputKey .fieldStateAutocomplete span.type`)).toHaveText(["null", "string", "number", "number"]); + page.locator(`${FIELD} .inputKey .fieldStateAutocomplete span.prop:text-matches("string")`).click(); + await expect(page + .locator(`${FIELD} .inputKey .templateInput`)) + .toHaveValue("@{types.string"); + await page + .locator(`${FIELD} .inputValue .templateInput`) + .fill("@{types."); + await expect(page.locator(`${FIELD} .inputValue .fieldStateAutocomplete span.prop`)).toHaveText(["none", "string", "integer", "float"]); + await expect(page.locator(`${FIELD} .inputValue .fieldStateAutocomplete span.type`)).toHaveText(["null", "string", "number", "number"]); + page.locator(`${FIELD} .inputValue .fieldStateAutocomplete span.prop:text-matches("string")`).click(); + await expect(page + .locator(`${FIELD} .inputValue .templateInput`)) + .toHaveValue("@{types.string"); + await page.locator('[data-automation-action="delete"]').click(); + }); + + test("JSON - completion", async ({ page }) => { + const FIELD = `.BuilderFieldsOptions[data-automation-key="options"]`; + await page + .locator(`div.component.button[data-component-type="radioinput"]`) + .dragTo(page.locator(".CorePage")); + + await page.locator('div.CoreRadioInput.component > label').click(); + await page + .locator(`${FIELD} button.chip:text-matches("JSON")`) + .click(); + await page + .locator(`${FIELD} .templateInput`) + .fill("@{types."); + await expect(page.locator(`${FIELD} .fieldStateAutocomplete span.prop`)).toHaveText(["none", "string", "integer", "float"]); + await expect(page.locator(`${FIELD} .fieldStateAutocomplete span.type`)).toHaveText(["null", "string", "number", "number"]); + page.locator(`${FIELD} .fieldStateAutocomplete span.prop:text-matches("string")`).click(); + await expect(page + .locator(`${FIELD} .templateInput`)) + .toHaveValue("@{types.string"); + await page.locator('[data-automation-action="delete"]').click(); + }); + }); + + function testFieldType(type, key, componentSelector) { + test(`${type} field - state completion`, async ({ page }) => { + const FIELD = `.${type}[data-automation-key="${key}"]`; + await page.locator(componentSelector).click(); + await page + .locator(`${FIELD} button.chip:text-matches("CSS")`) + .click(); + await page + .locator(`${FIELD} .templateInput`) + .fill("@{types."); + await expect(page.locator(`${FIELD} .fieldStateAutocomplete span.prop`)).toHaveText(["none", "string", "integer", "float"]); + await expect(page.locator(`${FIELD} .fieldStateAutocomplete span.type`)).toHaveText(["null", "string", "number", "number"]); + page.locator(`${FIELD} .fieldStateAutocomplete span.prop:text-matches("string")`).click(); + await expect(page + .locator(`${FIELD} .templateInput`)) + .toHaveValue("@{types.string"); + }); + } + + testFieldType("BuilderFieldsColor", "primaryTextColor", 'div.CoreText.component'); + testFieldType("BuilderFieldsShadow", "buttonShadow", '.BuilderTreeBranch [data-branch-component-type="root"]'); + testFieldType("BuilderFieldsAlign", "contentHAlign", '.BuilderTreeBranch [data-branch-component-type="root"]'); + testFieldType("BuilderFieldsPadding", "contentPadding", '.BuilderTreeBranch [data-branch-component-type="root"]'); + testFieldType("BuilderFieldsWidth", "contentWidth", '.BuilderTreeBranch [data-branch-component-type="root"]'); +}); diff --git a/tests/e2e/tests/undoRedo.spec.ts b/tests/e2e/tests/undoRedo.spec.ts index 4ef88e6c4..072604344 100644 --- a/tests/e2e/tests/undoRedo.spec.ts +++ b/tests/e2e/tests/undoRedo.spec.ts @@ -48,7 +48,7 @@ test.describe('undo and redo', () => { await page.locator(COMPONENT_LOCATOR).click(); await page - .locator('.BuilderFieldsText[data-key="text"] input') + .locator('.BuilderFieldsText[data-automation-key="text"] input') .fill('cool text'); await page.locator("button.undo").click(); await expect(page.locator(COMPONENT_LOCATOR)).toHaveText('Button Text')