From e6a4bf4f9f34af49c41bb3cbe8ed69d34023eea2 Mon Sep 17 00:00:00 2001 From: Leo McArdle Date: Wed, 8 Jan 2025 12:05:36 +0000 Subject: [PATCH 1/2] chore(lit): move into separate folder and make tsconfig stricter (#12398) --- client/src/about/index.tsx | 2 +- client/src/community/index.tsx | 2 +- client/src/curriculum/landing.tsx | 2 +- client/src/curriculum/module.tsx | 2 +- .../custom-elements.js => lit/about.js} | 0 .../{ => lit}/community/contributor-list.js | 0 .../{ => lit}/community/contributor-list.scss | 2 +- client/src/{ => lit}/community/types.d.ts | 0 .../curriculum/scrim-inline.global.css | 2 +- .../src/{ => lit}/curriculum/scrim-inline.js | 6 +- .../{ => lit}/curriculum/scrim-inline.scss | 12 +- client/src/lit/globals.d.ts | 14 ++ client/src/lit/modules.d.ts | 12 ++ .../src/{playground => lit/play}/console.js | 0 .../src/{playground => lit/play}/console.scss | 0 .../src/{playground => lit/play}/types.d.ts | 0 client/src/lit/tsconfig.json | 30 +++++ client/src/playground/index.tsx | 4 +- .../plus/collections/frequently-viewed.tsx | 21 +-- client/src/react-app.d.ts | 36 ------ client/src/settings/mdn-worker.tsx | 2 +- client/src/telemetry/glean-context.tsx | 13 +- client/src/user-context.tsx | 4 +- client/tsconfig.json | 8 +- server/react-app.d.ts | 91 ------------- ssr/modules.d.ts | 9 ++ ssr/react-app.d.ts | 122 ------------------ ssr/tsconfig.json | 2 +- 28 files changed, 109 insertions(+), 289 deletions(-) rename client/src/{about/custom-elements.js => lit/about.js} (100%) rename client/src/{ => lit}/community/contributor-list.js (100%) rename client/src/{ => lit}/community/contributor-list.scss (99%) rename client/src/{ => lit}/community/types.d.ts (100%) rename client/src/{ => lit}/curriculum/scrim-inline.global.css (65%) rename client/src/{ => lit}/curriculum/scrim-inline.js (96%) rename client/src/{ => lit}/curriculum/scrim-inline.scss (88%) create mode 100644 client/src/lit/globals.d.ts create mode 100644 client/src/lit/modules.d.ts rename client/src/{playground => lit/play}/console.js (100%) rename client/src/{playground => lit/play}/console.scss (100%) rename client/src/{playground => lit/play}/types.d.ts (100%) create mode 100644 client/src/lit/tsconfig.json delete mode 100644 server/react-app.d.ts create mode 100644 ssr/modules.d.ts delete mode 100644 ssr/react-app.d.ts diff --git a/client/src/about/index.tsx b/client/src/about/index.tsx index 92055d8c82f2..3c5ae1b1785a 100644 --- a/client/src/about/index.tsx +++ b/client/src/about/index.tsx @@ -7,7 +7,7 @@ import { WRITER_MODE } from "../env"; import { Prose } from "../document/ingredients/prose"; import "./index.scss"; -import "./custom-elements"; +import "../lit/about"; import { useGleanClick } from "../telemetry/glean-context"; import { ABOUT } from "../telemetry/constants"; diff --git a/client/src/community/index.tsx b/client/src/community/index.tsx index e2290d123a52..37af5b68c086 100644 --- a/client/src/community/index.tsx +++ b/client/src/community/index.tsx @@ -11,7 +11,7 @@ export function Community(appProps: HydrationData) { const doc = useAboutDoc(appProps); useEffect(() => { - import("./contributor-list"); + import("../lit/community/contributor-list"); }, []); return ( diff --git a/client/src/curriculum/landing.tsx b/client/src/curriculum/landing.tsx index bc3cbd5c96bd..9b60e447a671 100644 --- a/client/src/curriculum/landing.tsx +++ b/client/src/curriculum/landing.tsx @@ -20,7 +20,7 @@ import scrimBg from "../assets/curriculum/landing-scrim.png"; import { useGleanClick } from "../telemetry/glean-context"; import { CURRICULUM } from "../telemetry/constants"; -const ScrimInline = lazy(() => import("./scrim-inline")); +const ScrimInline = lazy(() => import("../lit/curriculum/scrim-inline")); export function CurriculumLanding(appProps: HydrationData) { const doc = useCurriculumDoc(appProps as CurriculumData); diff --git a/client/src/curriculum/module.tsx b/client/src/curriculum/module.tsx index 07cf874ad478..3804dedfbf2b 100644 --- a/client/src/curriculum/module.tsx +++ b/client/src/curriculum/module.tsx @@ -14,7 +14,7 @@ export function CurriculumModule(props: HydrationData) { const doc = useCurriculumDoc(props as CurriculumData); useEffect(() => { - import("./scrim-inline"); + import("../lit/curriculum/scrim-inline"); }, []); return ( diff --git a/client/src/about/custom-elements.js b/client/src/lit/about.js similarity index 100% rename from client/src/about/custom-elements.js rename to client/src/lit/about.js diff --git a/client/src/community/contributor-list.js b/client/src/lit/community/contributor-list.js similarity index 100% rename from client/src/community/contributor-list.js rename to client/src/lit/community/contributor-list.js diff --git a/client/src/community/contributor-list.scss b/client/src/lit/community/contributor-list.scss similarity index 99% rename from client/src/community/contributor-list.scss rename to client/src/lit/community/contributor-list.scss index 232d5e7a6949..e2d6b20c81d6 100644 --- a/client/src/community/contributor-list.scss +++ b/client/src/lit/community/contributor-list.scss @@ -1,4 +1,4 @@ -@use "../ui/vars" as *; +@use "../../ui/vars" as *; * { box-sizing: border-box; diff --git a/client/src/community/types.d.ts b/client/src/lit/community/types.d.ts similarity index 100% rename from client/src/community/types.d.ts rename to client/src/lit/community/types.d.ts diff --git a/client/src/curriculum/scrim-inline.global.css b/client/src/lit/curriculum/scrim-inline.global.css similarity index 65% rename from client/src/curriculum/scrim-inline.global.css rename to client/src/lit/curriculum/scrim-inline.global.css index ac55e7fa316a..716a41ddcec5 100644 --- a/client/src/curriculum/scrim-inline.global.css +++ b/client/src/lit/curriculum/scrim-inline.global.css @@ -4,5 +4,5 @@ font-display: block; src: local("BarlowCondensed-SemiBold"), - url("../assets/fonts/BarlowCondensed-SemiBold.woff2") format("woff2"); + url("../../assets/fonts/BarlowCondensed-SemiBold.woff2") format("woff2"); } diff --git a/client/src/curriculum/scrim-inline.js b/client/src/lit/curriculum/scrim-inline.js similarity index 96% rename from client/src/curriculum/scrim-inline.js rename to client/src/lit/curriculum/scrim-inline.js index 894e7d529599..2340ba55746c 100644 --- a/client/src/curriculum/scrim-inline.js +++ b/client/src/lit/curriculum/scrim-inline.js @@ -4,13 +4,13 @@ import { styleMap } from "lit/directives/style-map.js"; import { ifDefined } from "lit/directives/if-defined.js"; import { createComponent } from "@lit/react"; import React from "react"; -import { CURRICULUM } from "../telemetry/constants.ts"; +import { CURRICULUM } from "../../telemetry/constants.ts"; import "./scrim-inline.global.css"; import styles from "./scrim-inline.scss?css" with { type: "css" }; -import playSvg from "../assets/curriculum/scrim-play.svg?raw"; +import playSvg from "../../assets/curriculum/scrim-play.svg?raw"; -class ScrimInline extends LitElement { +export class ScrimInline extends LitElement { static properties = { url: { type: String }, img: { type: String }, diff --git a/client/src/curriculum/scrim-inline.scss b/client/src/lit/curriculum/scrim-inline.scss similarity index 88% rename from client/src/curriculum/scrim-inline.scss rename to client/src/lit/curriculum/scrim-inline.scss index 6618fb42ac2f..ef70efbe675f 100644 --- a/client/src/curriculum/scrim-inline.scss +++ b/client/src/lit/curriculum/scrim-inline.scss @@ -88,16 +88,16 @@ dialog { .toggle { &.enter { - mask-image: url("../assets/icons/fullscreen-enter.svg"); + mask-image: url("../../assets/icons/fullscreen-enter.svg"); } &.exit { - mask-image: url("../assets/icons/cancel.svg"); + mask-image: url("../../assets/icons/cancel.svg"); } } .external { - mask-image: url("../assets/icons/external.svg"); + mask-image: url("../../assets/icons/external.svg"); mask-size: 75%; } @@ -109,9 +109,9 @@ dialog { .background { background-color: #453c78; - background-image: url("../assets/curriculum/scrimba-logo.svg"), - url("../assets/curriculum/scrim-hexagons.svg"), - url("../assets/curriculum/scrim-bg.png"); + background-image: url("../../assets/curriculum/scrimba-logo.svg"), + url("../../assets/curriculum/scrim-hexagons.svg"), + url("../../assets/curriculum/scrim-bg.png"); background-position: 1.5em 1.5em, right, diff --git a/client/src/lit/globals.d.ts b/client/src/lit/globals.d.ts new file mode 100644 index 000000000000..51d5a73c8baf --- /dev/null +++ b/client/src/lit/globals.d.ts @@ -0,0 +1,14 @@ +import { MDNImageHistory, TeamMember } from "./about"; +import { ContributorList } from "./community/contributor-list"; +import { ScrimInline } from "./curriculum/scrim-inline"; +import { PlayConsole } from "./play/console"; + +declare global { + interface HTMLElementTagNameMap { + "mdn-image-history": MDNImageHistory; + "team-member": TeamMember; + "contributor-list": ContributorList; + "scrim-inline": ScrimInline; + "play-console": PlayConsole; + } +} diff --git a/client/src/lit/modules.d.ts b/client/src/lit/modules.d.ts new file mode 100644 index 000000000000..c5fc9cfff13e --- /dev/null +++ b/client/src/lit/modules.d.ts @@ -0,0 +1,12 @@ +// once https://github.com/microsoft/TypeScript/issues/46135 is fixed +// we'll be able to do something like: +// declare module '*' with {type: 'css'} { +declare module "*?css" { + const sheet: CSSStyleSheet; + export default sheet; +} + +declare module "*?raw" { + const src: string; + export default src; +} diff --git a/client/src/playground/console.js b/client/src/lit/play/console.js similarity index 100% rename from client/src/playground/console.js rename to client/src/lit/play/console.js diff --git a/client/src/playground/console.scss b/client/src/lit/play/console.scss similarity index 100% rename from client/src/playground/console.scss rename to client/src/lit/play/console.scss diff --git a/client/src/playground/types.d.ts b/client/src/lit/play/types.d.ts similarity index 100% rename from client/src/playground/types.d.ts rename to client/src/lit/play/types.d.ts diff --git a/client/src/lit/tsconfig.json b/client/src/lit/tsconfig.json new file mode 100644 index 000000000000..a3708bfbf670 --- /dev/null +++ b/client/src/lit/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "strict": true, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noEmit": true, + "noFallthroughCasesInSwitch": true, + "allowImportingTsExtensions": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["dom", "dom.iterable", "es2021"], + "module": "ESNext", + "moduleResolution": "Node", + "target": "ES2020", + "plugins": [ + { + "name": "ts-lit-plugin", + "strict": true + } + ] + }, + "include": ["**/*"] +} diff --git a/client/src/playground/index.tsx b/client/src/playground/index.tsx index 67d54f06ab42..c023cccf3811 100644 --- a/client/src/playground/index.tsx +++ b/client/src/playground/index.tsx @@ -21,10 +21,10 @@ import { import "./index.scss"; import { PLAYGROUND_BASE_HOST } from "../env"; import { FlagForm, ShareForm } from "./forms"; -import { ReactPlayConsole } from "./console"; +import { ReactPlayConsole } from "../lit/play/console"; import { useGleanClick } from "../telemetry/glean-context"; import { PLAYGROUND } from "../telemetry/constants"; -import type { VConsole } from "./types"; +import type { VConsole } from "../lit/play/types"; const HTML_DEFAULT = ""; const CSS_DEFAULT = ""; diff --git a/client/src/plus/collections/frequently-viewed.tsx b/client/src/plus/collections/frequently-viewed.tsx index 63352fbd817d..6d329e351a7a 100644 --- a/client/src/plus/collections/frequently-viewed.tsx +++ b/client/src/plus/collections/frequently-viewed.tsx @@ -78,8 +78,13 @@ const sortByVisitsThenTimestampsDesc = ( //'Each timestamp represents one visit. The first is the most recent visit. if (first.timestamps.length > second.timestamps.length) return -1; if (first.timestamps.length < second.timestamps.length) return 1; - if (first.timestamps[0] < second.timestamps[0]) return 1; - if (first.timestamps[0] > second.timestamps[0]) return -1; + if ( + typeof first.timestamps[0] !== "undefined" && + typeof second.timestamps[0] !== "undefined" + ) { + if (first.timestamps[0] < second.timestamps[0]) return 1; + if (first.timestamps[0] > second.timestamps[0]) return -1; + } return 0; }; @@ -98,7 +103,7 @@ function getNextFrequentlyViewedSerial( export function useFrequentlyViewed( limit: number = 0, offset: number = 10, - setEnd?: (bool) => void + setEnd?: (bool: boolean) => void ): FrequentlyViewedCollection { const [collection, setCollection] = useState({ article_count: 0, @@ -130,7 +135,7 @@ export function useFrequentlyViewed( ...c, article_count: freqViewed.length, items: paged, - updated_at: freqViewed[0] + updated_at: freqViewed[0]?.timestamps[0] ? new Date(freqViewed[0].timestamps[0]).toISOString() : new Date().toISOString(), }; @@ -208,12 +213,12 @@ export function useIncrementFrequentlyViewed(doc: Doc | undefined) { let frequentlyViewed = getFrequentlyViewed(); - const index = frequentlyViewed.findIndex( + const foundEntry = frequentlyViewed.find( (entry) => entry.url === doc.mdn_url ); - if (index !== -1) { - frequentlyViewed[index].timestamps.unshift(Date.now()); + if (foundEntry) { + foundEntry.timestamps.unshift(Date.now()); } else { const newEntry: FrequentlyViewedEntry = { serial: getNextFrequentlyViewedSerial(frequentlyViewed), @@ -236,7 +241,7 @@ export function useIncrementFrequentlyViewed(doc: Doc | undefined) { }, [user?.isAuthenticated, doc]); } -const filterFrequentlyViewed = (frequentlyViewed) => { +const filterFrequentlyViewed = (frequentlyViewed: FrequentlyViewedEntry[]) => { //1. Remove timestamps older than 30 days. //2. Filter all values with no remaining timestamps return frequentlyViewed diff --git a/client/src/react-app.d.ts b/client/src/react-app.d.ts index 23b53c872707..20002b3e2305 100644 --- a/client/src/react-app.d.ts +++ b/client/src/react-app.d.ts @@ -78,39 +78,3 @@ declare module "*.svg" { const src: string; export default src; } - -declare module "*?raw" { - const src: string; - export default src; -} - -// once https://github.com/microsoft/TypeScript/issues/46135 is fixed -// we'll be able to do something like: -// declare module '*' with {type: 'css'} { -declare module "*?css" { - const sheet: CSSStyleSheet; - export default sheet; -} - -// once https://github.com/microsoft/TypeScript/issues/46135 is fixed -// we'll be able to do something like: -// declare module '*' with {type: 'css'} { -declare module "*?css" { - const sheet: CSSStyleSheet; - export default sheet; -} - -declare module "*.module.css" { - const classes: { readonly [key: string]: string }; - export default classes; -} - -declare module "*.module.scss" { - const classes: { readonly [key: string]: string }; - export default classes; -} - -declare module "*.module.sass" { - const classes: { readonly [key: string]: string }; - export default classes; -} diff --git a/client/src/settings/mdn-worker.tsx b/client/src/settings/mdn-worker.tsx index c2f58230aa4c..602b845f424b 100644 --- a/client/src/settings/mdn-worker.tsx +++ b/client/src/settings/mdn-worker.tsx @@ -35,7 +35,7 @@ export class MDNWorker { this.timeout = setTimeout(() => this.autoUpdate(), 60 * 60 * 1000); } - messageHandler(event) { + messageHandler(event: MessageEvent) { switch (event.data.type) { case "pong": console.log("pong"); diff --git a/client/src/telemetry/glean-context.tsx b/client/src/telemetry/glean-context.tsx index 599d77f09260..caa8acb3b30e 100644 --- a/client/src/telemetry/glean-context.tsx +++ b/client/src/telemetry/glean-context.tsx @@ -78,8 +78,8 @@ function glean(): GleanAnalytics { if (typeof window === "undefined" || !GLEAN_ENABLED) { //SSR return noop. return { - page: (page: PageProps) => () => {}, - click: (element: ElementClickedProps) => {}, + page: () => () => {}, + click: () => {}, }; } const userIsOptedOut = document.cookie @@ -114,8 +114,13 @@ function glean(): GleanAnalytics { if (page.isBaseline) { pageMetric.isBaseline.set(page.isBaseline); } - for (const param in page.utm) { - pageMetric.utm[param].set(page.utm[param]); + for (const param of Object.keys(page.utm) as Array< + keyof typeof page.utm + >) { + const value = page.utm[param]; + if (value) { + pageMetric.utm[param]?.set(value); + } } pageMetric.httpStatus.set(page.httpStatus); if (page.geo) { diff --git a/client/src/user-context.tsx b/client/src/user-context.tsx index d59b371995c2..109b6abe8857 100644 --- a/client/src/user-context.tsx +++ b/client/src/user-context.tsx @@ -121,8 +121,8 @@ function getSessionStorageData() { } } catch (error: any) { console.warn("sessionStorage.getItem didn't work", error.toString()); - return undefined; } + return undefined; } export function cleanupUserData() { @@ -184,7 +184,7 @@ function setNoPlacementFlag(noAds: boolean) { export function UserDataProvider(props: { children: React.ReactNode }) { const { data, error, isLoading, mutate } = useSWR( DISABLE_AUTH ? null : "/api/v1/whoami", - async (url) => { + async (url: string) => { const response = await fetch(url); if (!response.ok) { removeSessionStorageData(); diff --git a/client/tsconfig.json b/client/tsconfig.json index 262b9c47b077..d82d4baedb94 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -19,13 +19,7 @@ "skipLibCheck": true, "sourceMap": true, "strict": true, - "target": "ES2020", - "plugins": [ - { - "name": "ts-lit-plugin", - "strict": true - } - ] + "target": "ES2020" }, "include": ["src"] } diff --git a/server/react-app.d.ts b/server/react-app.d.ts deleted file mode 100644 index 8206136fee8c..000000000000 --- a/server/react-app.d.ts +++ /dev/null @@ -1,91 +0,0 @@ -declare namespace NodeJS { - interface ProcessEnv { - readonly NODE_ENV: "development" | "production" | "test"; - } -} - -declare module "*.avif" { - const src: string; - export default src; -} - -declare module "*.bmp" { - const src: string; - export default src; -} - -declare module "*.gif" { - const src: string; - export default src; -} - -declare module "*.jpg" { - const src: string; - export default src; -} - -declare module "*.jpeg" { - const src: string; - export default src; -} - -declare module "*.mp3" { - const src: string; - export default src; -} - -declare module "*.mp4" { - const src: string; - export default src; -} - -declare module "*.ogg" { - const src: string; - export default src; -} - -declare module "*.png" { - const src: string; - export default src; -} - -declare module "*.webm" { - const src: string; - export default src; -} - -declare module "*.webp" { - const src: string; - export default src; -} - -declare module "*.woff2" { - const src: string; - export default src; -} - -declare module "*.svg" { - import * as React from "react"; - - export const ReactComponent: React.FunctionComponent< - React.SVGProps & { title?: string } - >; - - const src: string; - export default src; -} - -declare module "*.module.css" { - const classes: { readonly [key: string]: string }; - export default classes; -} - -declare module "*.module.scss" { - const classes: { readonly [key: string]: string }; - export default classes; -} - -declare module "*.module.sass" { - const classes: { readonly [key: string]: string }; - export default classes; -} diff --git a/ssr/modules.d.ts b/ssr/modules.d.ts new file mode 100644 index 000000000000..9f24738429e9 --- /dev/null +++ b/ssr/modules.d.ts @@ -0,0 +1,9 @@ +declare module "*?inline" { + const source: string; + export default source; +} + +declare module "*?public" { + const src: string; + export default src; +} diff --git a/ssr/react-app.d.ts b/ssr/react-app.d.ts deleted file mode 100644 index 4822f4144835..000000000000 --- a/ssr/react-app.d.ts +++ /dev/null @@ -1,122 +0,0 @@ -declare namespace NodeJS { - interface ProcessEnv { - readonly NODE_ENV: "development" | "production" | "test"; - } -} - -declare module "*.avif" { - const src: string; - export default src; -} - -declare module "*.bmp" { - const src: string; - export default src; -} - -declare module "*.gif" { - const src: string; - export default src; -} - -declare module "*.jpg" { - const src: string; - export default src; -} - -declare module "*.jpeg" { - const src: string; - export default src; -} - -declare module "*.mp3" { - const src: string; - export default src; -} - -declare module "*.mp4" { - const src: string; - export default src; -} - -declare module "*.ogg" { - const src: string; - export default src; -} - -declare module "*.png" { - const src: string; - export default src; -} - -declare module "*.webm" { - const src: string; - export default src; -} - -declare module "*.webp" { - const src: string; - export default src; -} - -declare module "*.woff2" { - const src: string; - export default src; -} - -declare module "*.svg" { - import * as React from "react"; - - export const ReactComponent: React.FunctionComponent< - React.SVGProps & { title?: string } - >; - - const src: string; - export default src; -} - -declare module "*?raw" { - const src: string; - export default src; -} - -// once https://github.com/microsoft/TypeScript/issues/46135 is fixed -// we'll be able to do something like: -// declare module '*' with {type: 'css'} { -declare module "*?css" { - const sheet: CSSStyleSheet; - export default sheet; -} - -// once https://github.com/microsoft/TypeScript/issues/46135 is fixed -// we'll be able to do something like: -// declare module '*' with {type: 'css'} { -declare module "*?css" { - const sheet: CSSStyleSheet; - export default sheet; -} - -declare module "*.module.css" { - const classes: { readonly [key: string]: string }; - export default classes; -} - -declare module "*.module.scss" { - const classes: { readonly [key: string]: string }; - export default classes; -} - -declare module "*.module.sass" { - const classes: { readonly [key: string]: string }; - export default classes; -} - -declare module "*?inline" { - const source: string; - export default source; -} - -declare module "*?public" { - const src: string; - export default src; -} diff --git a/ssr/tsconfig.json b/ssr/tsconfig.json index bf2c0bd5252e..e86b2592693b 100644 --- a/ssr/tsconfig.json +++ b/ssr/tsconfig.json @@ -1,5 +1,5 @@ { "extends": "../client/tsconfig.json", - "include": ["."], + "include": [".", "../client/**/*.d.ts"], "exclude": ["dist"] } From c3da70bc03e3e3a91aac3aaa678ba56c35b3719f Mon Sep 17 00:00:00 2001 From: Claas Augner <495429+caugner@users.noreply.github.com> Date: Wed, 8 Jan 2025 13:46:20 +0100 Subject: [PATCH 2/2] chore(deps): bump elasticsearch from 7.17.9 to 7.17.12 in /deployer (#12412) --- deployer/poetry.lock | 57 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 6 deletions(-) diff --git a/deployer/poetry.lock b/deployer/poetry.lock index 5f6f185b7826..c6268809a151 100644 --- a/deployer/poetry.lock +++ b/deployer/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.0.0 and should not be changed by hand. [[package]] name = "black" @@ -6,6 +6,7 @@ version = "24.10.0" description = "The uncompromising code formatter." optional = false python-versions = ">=3.9" +groups = ["dev"] files = [ {file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"}, {file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"}, @@ -52,6 +53,7 @@ version = "1.35.92" description = "The AWS SDK for Python" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "boto3-1.35.92-py3-none-any.whl", hash = "sha256:786930d5f1cd13d03db59ff2abbb2b7ffc173fd66646d5d8bee07f316a5f16ca"}, {file = "boto3-1.35.92.tar.gz", hash = "sha256:f7851cb320dcb2a53fc73b4075187ec9b05d51291539601fa238623fdc0e8cd3"}, @@ -71,6 +73,7 @@ version = "1.35.92" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "botocore-1.35.92-py3-none-any.whl", hash = "sha256:f94ae1e056a675bd67c8af98a6858d06e3927d974d6c712ed6e27bb1d11bee1d"}, {file = "botocore-1.35.92.tar.gz", hash = "sha256:caa7d5d857fed5b3d694b89c45f82b9f938f840e90a4eb7bf50aa65da2ba8f82"}, @@ -90,6 +93,7 @@ version = "2024.7.4" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, @@ -101,6 +105,7 @@ version = "1.15.1" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, @@ -177,6 +182,7 @@ version = "3.0.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "charset-normalizer-3.0.1.tar.gz", hash = "sha256:ebea339af930f8ca5d7a699b921106c6e29c617fe9606fa7baa043c1cdae326f"}, {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88600c72ef7587fe1708fd242b385b6ed4b8904976d5da0893e31df8b3480cb6"}, @@ -274,6 +280,7 @@ version = "8.1.8" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, @@ -288,10 +295,12 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main", "dev"] files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +markers = {main = "platform_system == \"Windows\"", dev = "platform_system == \"Windows\" or sys_platform == \"win32\""} [[package]] name = "cryptography" @@ -299,6 +308,7 @@ version = "43.0.1" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"}, {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062"}, @@ -348,6 +358,7 @@ version = "1.2.13" description = "Python @deprecated decorator to deprecate old python classes, functions or methods." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main"] files = [ {file = "Deprecated-1.2.13-py2.py3-none-any.whl", hash = "sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d"}, {file = "Deprecated-1.2.13.tar.gz", hash = "sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d"}, @@ -361,13 +372,14 @@ dev = ["PyTest", "PyTest (<5)", "PyTest-Cov", "PyTest-Cov (<2.6)", "bump2version [[package]] name = "elasticsearch" -version = "7.17.9" +version = "7.17.12" description = "Python client for Elasticsearch" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,<4,>=2.7" +groups = ["main"] files = [ - {file = "elasticsearch-7.17.9-py2.py3-none-any.whl", hash = "sha256:0e2454645dc00517dee4c6de3863411a9c5f1955d013c5fefa29123dadc92f98"}, - {file = "elasticsearch-7.17.9.tar.gz", hash = "sha256:66c4ece2adfe7cc120e2b6a6798a1fd5c777aecf82eec39bb95cef7cfc7ea2b3"}, + {file = "elasticsearch-7.17.12-py2.py3-none-any.whl", hash = "sha256:468fd5eef703c0d9238e29bcaf3a6fe4d6b092f917959fbf41f48f8fea3df2f8"}, + {file = "elasticsearch-7.17.12.tar.gz", hash = "sha256:a1f5733ae8cf1dbf0a78593389f2503c87dd97429976099832bf0626cdfaac8b"}, ] [package.dependencies] @@ -386,6 +398,7 @@ version = "7.4.1" description = "Python client for Elasticsearch" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main"] files = [ {file = "elasticsearch-dsl-7.4.1.tar.gz", hash = "sha256:07ee9c87dc28cc3cae2daa19401e1e18a172174ad9e5ca67938f752e3902a1d5"}, {file = "elasticsearch_dsl-7.4.1-py2.py3-none-any.whl", hash = "sha256:97f79239a252be7c4cce554c29e64695d7ef6a4828372316a5e5ff815e7a7498"}, @@ -405,6 +418,8 @@ version = "1.1.0" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version < \"3.11\"" files = [ {file = "exceptiongroup-1.1.0-py3-none-any.whl", hash = "sha256:327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e"}, {file = "exceptiongroup-1.1.0.tar.gz", hash = "sha256:bcb67d800a4497e1b404c2dd44fca47d3b7a5e5433dbab67f96c1a685cdfdf23"}, @@ -419,6 +434,7 @@ version = "7.1.1" description = "the modular source code checker: pep8 pyflakes and co" optional = false python-versions = ">=3.8.1" +groups = ["dev"] files = [ {file = "flake8-7.1.1-py2.py3-none-any.whl", hash = "sha256:597477df7860daa5aa0fdd84bf5208a043ab96b8e96ab708770ae0364dd03213"}, {file = "flake8-7.1.1.tar.gz", hash = "sha256:049d058491e228e03e67b390f311bbf88fce2dbaa8fa673e7aea87b7198b8d38"}, @@ -435,6 +451,7 @@ version = "3.7" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" +groups = ["main"] files = [ {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, @@ -446,6 +463,7 @@ version = "2.0.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, @@ -457,6 +475,7 @@ version = "1.0.1" description = "JSON Matching Expressions" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, @@ -468,6 +487,7 @@ version = "0.7.0" description = "McCabe checker, plugin for flake8" optional = false python-versions = ">=3.6" +groups = ["dev"] files = [ {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, @@ -479,6 +499,7 @@ version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false python-versions = ">=3.5" +groups = ["dev"] files = [ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, @@ -490,6 +511,7 @@ version = "23.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, @@ -501,6 +523,7 @@ version = "0.11.0" description = "Utility library for gitignore style pattern matching of file paths." optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "pathspec-0.11.0-py3-none-any.whl", hash = "sha256:3a66eb970cbac598f9e5ccb5b2cf58930cd8e3ed86d393d541eaf2d8b1705229"}, {file = "pathspec-0.11.0.tar.gz", hash = "sha256:64d338d4e0914e91c1792321e6907b5a593f1ab1851de7fc269557a21b30ebbc"}, @@ -512,6 +535,7 @@ version = "3.0.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "platformdirs-3.0.0-py3-none-any.whl", hash = "sha256:b1d5eb14f221506f50d6604a561f4c5786d9e80355219694a1b244bcd96f4567"}, {file = "platformdirs-3.0.0.tar.gz", hash = "sha256:8a1228abb1ef82d788f74139988b137e78692984ec7b08eaa6c65f1723af28f9"}, @@ -527,6 +551,7 @@ version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, @@ -542,6 +567,7 @@ version = "2.12.0" description = "Python style guide checker" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pycodestyle-2.12.0-py2.py3-none-any.whl", hash = "sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4"}, {file = "pycodestyle-2.12.0.tar.gz", hash = "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c"}, @@ -553,6 +579,7 @@ version = "2.21" description = "C parser in Python" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main"] files = [ {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, @@ -564,6 +591,7 @@ version = "3.2.0" description = "passive checker of Python programs" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"}, {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, @@ -575,6 +603,7 @@ version = "1.59.1" description = "Use the full Github API v3" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "PyGithub-1.59.1-py3-none-any.whl", hash = "sha256:3d87a822e6c868142f0c2c4bf16cce4696b5a7a4d142a7bd160e1bdf75bc54a9"}, {file = "PyGithub-1.59.1.tar.gz", hash = "sha256:c44e3a121c15bf9d3a5cc98d94c9a047a5132a9b01d22264627f58ade9ddc217"}, @@ -592,6 +621,7 @@ version = "2.6.0" description = "JSON Web Token implementation in Python" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "PyJWT-2.6.0-py3-none-any.whl", hash = "sha256:d83c3d892a77bbb74d3e1a2cfa90afaadb60945205d1095d9221f04466f64c14"}, {file = "PyJWT-2.6.0.tar.gz", hash = "sha256:69285c7e31fc44f68a1feb309e948e0df53259d579295e6cfe2b1792329f05fd"}, @@ -612,6 +642,7 @@ version = "1.5.0" description = "Python binding to the Networking and Cryptography (NaCl) library" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1"}, {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92"}, @@ -638,6 +669,7 @@ version = "8.3.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, @@ -660,6 +692,7 @@ version = "2.8.2" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main"] files = [ {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, @@ -674,6 +707,7 @@ version = "3.8" description = "Strict separation of settings from code." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "python-decouple-3.8.tar.gz", hash = "sha256:ba6e2657d4f376ecc46f77a3a615e058d93ba5e465c01bbe57289bfb7cce680f"}, {file = "python_decouple-3.8-py3-none-any.whl", hash = "sha256:d0d45340815b25f4de59c974b855bb38d03151d81b037d9e3f463b0c9f8cbd66"}, @@ -685,6 +719,7 @@ version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, @@ -706,6 +741,7 @@ version = "0.10.0" description = "An Amazon S3 Transfer Manager" optional = false python-versions = ">= 3.8" +groups = ["main"] files = [ {file = "s3transfer-0.10.0-py3-none-any.whl", hash = "sha256:3cdb40f5cfa6966e812209d0994f2a4709b561c88e90cf00c2696d2df4e56b2e"}, {file = "s3transfer-0.10.0.tar.gz", hash = "sha256:d0c8bbf672d5eebbe4e57945e23b972d963f07d82f661cabf678a5c88831595b"}, @@ -723,6 +759,7 @@ version = "0.3.27" description = "Fast HTML5 parser with CSS selectors." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "selectolax-0.3.27-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:000b11bbf1c730e61ddd59106cabc77b649e5ebfb3d043abfc1d6b618dab8f0a"}, {file = "selectolax-0.3.27-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a975fb54f7180d4b919e084ce54271083fd2960df734ae3045e9c3f557617136"}, @@ -801,6 +838,7 @@ version = "1.16.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +groups = ["main"] files = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, @@ -812,6 +850,8 @@ version = "2.0.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version < \"3.11\"" files = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, @@ -823,6 +863,8 @@ version = "4.7.1" description = "Backported and Experimental Type Hints for Python 3.7+" optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version < \"3.11\"" files = [ {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, @@ -834,6 +876,7 @@ version = "0.7.5" description = "Unified diff parsing/metadata extraction library." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "unidiff-0.7.5-py2.py3-none-any.whl", hash = "sha256:c93bf2265cc1ba2a520e415ab05da587370bc2a3ae9e0414329f54f0c2fc09e8"}, {file = "unidiff-0.7.5.tar.gz", hash = "sha256:2e5f0162052248946b9f0970a40e9e124236bf86c82b70821143a6fc1dea2574"}, @@ -845,6 +888,7 @@ version = "1.26.19" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +groups = ["main"] files = [ {file = "urllib3-1.26.19-py2.py3-none-any.whl", hash = "sha256:37a0344459b199fce0e80b0d3569837ec6b6937435c5244e7fd73fa6006830f3"}, {file = "urllib3-1.26.19.tar.gz", hash = "sha256:3e3d753a8618b86d7de333b4223005f68720bcd6a7d2bcb9fbd2229ec7c1e429"}, @@ -861,6 +905,7 @@ version = "1.14.1" description = "Module for decorators, wrappers and monkey patching." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +groups = ["main"] files = [ {file = "wrapt-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3"}, {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef"}, @@ -939,6 +984,6 @@ files = [ ] [metadata] -lock-version = "2.0" +lock-version = "2.1" python-versions = "^3.10" content-hash = "10ac28b1059d5c45045b784e38db708662205ce99b77ae6d5b76aa65b1a8e7bf"