├── .eslintrc.json ├── .gitignore ├── .vscode └── settings.json ├── README.md ├── app.py ├── codegen.yml ├── graphql.ts ├── models.py ├── mypy.ini ├── next-env.d.ts ├── next.config.js ├── operation.graphql ├── package-lock.json ├── package.json ├── pages ├── _app.tsx └── index.tsx ├── poetry.lock ├── postcss.config.js ├── public ├── favicon.ico ├── panda.svg └── vercel.svg ├── pyproject.toml ├── schema.graphql ├── styles └── globals.css ├── tailwind.config.js └── tsconfig.json /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env.local 29 | .env.development.local 30 | .env.test.local 31 | .env.production.local 32 | 33 | # vercel 34 | .vercel 35 | 36 | # typescript 37 | *.tsbuildinfo 38 | 39 | # Python 40 | __pycache__ 41 | database.db 42 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "python.linting.flake8Enabled": true, 4 | "python.linting.mypyEnabled": true, 5 | "python.linting.mypyArgs": [ 6 | "--follow-imports=silent", 7 | "--ignore-missing-imports", 8 | "--show-column-numbers", 9 | "--no-pretty", 10 | "--config-file", 11 | "${workspaceFolder}/mypy.ini" 12 | ], 13 | "python.linting.enabled": true, 14 | "python.formatting.provider": "black", 15 | "python.formatting.blackArgs": [ 16 | "--config", 17 | "${workspaceFolder}/pyproject.toml" 18 | ], 19 | "python.sortImports.args": ["--settings=pyproject.toml"], 20 | "python.analysis.typeCheckingMode": "off", 21 | "python.languageServer": "Pylance", 22 | "python.linting.flake8Args": ["--max-line-length=99"], 23 | "[python]": { 24 | "editor.codeActionsOnSave": { 25 | "source.organizeImports": true 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Modern Python Web Stack 2 | 3 | ![image](https://user-images.githubusercontent.com/701/141482559-1992d50a-07f1-42e6-b0f6-bc0bb65ccc9e.png) 4 | 5 | SQLAlchemy now has an asyncio extension. Strawberry is a new-ish GraphQL library based on Python 6 | dataclasses that makes full use of type hints and mypy extensions. Codegen can generate typed React 7 | hooks in TypeScript. This template or reference project shows how all these pieces can be put 8 | together for an awesome typed developer experience. 9 | 10 | This is a mini version of the [Inch](https://tryinch.com) tech stack. The schema is monitored by 11 | [codegen](https://www.graphql-code-generator.com) that creates 12 | [urql](https://github.com/FormidableLabs/urql) TypeScript hooks. The goal was to have strong data 13 | consistency between the backend and frontend. Another benefit is a great VS Code environment that 14 | highlights any potential errors when communicating with the backend. 15 | 16 | ![](https://user-images.githubusercontent.com/701/140308942-264f40fa-f6ac-43cf-88f0-b6c4bfdfe105.mp4) 17 | 18 | ## Getting started 19 | 20 | Install Python and NPM packages 21 | 22 | ```bash 23 | poetry install 24 | npm i 25 | ``` 26 | 27 | Drop and recreate all database tables 28 | 29 | ```bash 30 | poetry run python models.py 31 | ``` 32 | 33 | Run the Python GraphQL backend on port :8000 - Next.js will reverse proxy `/graphql` to here 34 | 35 | ```bash 36 | poetry run uvicorn app:app --reload --host '::' 37 | ``` 38 | 39 | Start the GraphQL server 40 | 41 | ```bash 42 | npm run codegen --watch 43 | ``` 44 | 45 | Run the frontend 46 | 47 | ```bash 48 | npm run dev 49 | ``` 50 | 51 | ## VS Code 52 | 53 | Inside `.vscode/settings.json` you'll see how to have nice VS Code mypy errors, import sorting and 54 | code formatting. Pylance does not yet deal well with declarative type hinted SQLAlchemy models. 55 | However there are pretty good SQLA type stubs and a mypy plugin. That's why in the settings you'll 56 | see `python.analysis.typeCheckingMode` switched off and mypy enabled instead. 57 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import strawberry 4 | from sqlalchemy import select 5 | from starlette.applications import Starlette 6 | from strawberry.asgi import GraphQL 7 | 8 | import models 9 | 10 | 11 | @strawberry.type 12 | class Location: 13 | id: strawberry.ID 14 | name: str 15 | 16 | @classmethod 17 | def marshal(cls, model: models.Location) -> "Location": 18 | return cls(id=strawberry.ID(str(model.id)), name=model.name) 19 | 20 | 21 | @strawberry.type 22 | class Task: 23 | id: strawberry.ID 24 | name: str 25 | location: Optional[Location] = None 26 | 27 | @classmethod 28 | def marshal(cls, model: models.Task) -> "Task": 29 | return cls( 30 | id=strawberry.ID(str(model.id)), 31 | name=model.name, 32 | location=Location.marshal(model.location) if model.location else None, 33 | ) 34 | 35 | 36 | # @strawberry.type 37 | # class LocationNotFound: 38 | # message: str = "Location with this name does not exist" 39 | 40 | 41 | AddTaskResponse = strawberry.union("AddTaskResponse", (Task,)) 42 | 43 | 44 | @strawberry.type 45 | class LocationExists: 46 | message: str = "Location with this name already exist" 47 | 48 | 49 | AddLocationResponse = strawberry.union("AddLocationResponse", (Location, LocationExists)) 50 | 51 | 52 | @strawberry.type 53 | class Mutation: 54 | @strawberry.mutation 55 | async def add_task(self, name: str, location_name: Optional[str]) -> AddTaskResponse: 56 | async with models.get_session() as s: 57 | db_location = None 58 | if location_name: 59 | sql = select(models.Location).where(models.Location.name == location_name) 60 | db_location = (await s.execute(sql)).scalars().first() 61 | # if db_location is None: 62 | # return LocationNotFound() 63 | db_task = models.Task(name=name, location=db_location) 64 | s.add(db_task) 65 | await s.commit() 66 | return Task.marshal(db_task) 67 | 68 | @strawberry.mutation 69 | async def add_location(self, name: str) -> AddLocationResponse: 70 | async with models.get_session() as s: 71 | sql = select(models.Location).where(models.Location.name == name) 72 | existing_db_location = (await s.execute(sql)).first() 73 | if existing_db_location is not None: 74 | return LocationExists() 75 | db_location = models.Location(name=name) 76 | s.add(db_location) 77 | await s.commit() 78 | return Location.marshal(db_location) 79 | 80 | 81 | @strawberry.type 82 | class Query: 83 | @strawberry.field 84 | async def tasks(self) -> list[Task]: 85 | async with models.get_session() as s: 86 | sql = select(models.Task).order_by(models.Task.name) 87 | db_tasks = (await s.execute(sql)).scalars().unique().all() 88 | return [Task.marshal(task) for task in db_tasks] 89 | 90 | @strawberry.field 91 | async def locations(self) -> list[Location]: 92 | async with models.get_session() as s: 93 | sql = select(models.Location).order_by(models.Location.name) 94 | db_locations = (await s.execute(sql)).scalars().unique().all() 95 | return [Location.marshal(loc) for loc in db_locations] 96 | 97 | 98 | schema = strawberry.Schema(query=Query, mutation=Mutation) 99 | graphql_app = GraphQL(schema) 100 | app = Starlette() 101 | app.add_route("/graphql", graphql_app) 102 | -------------------------------------------------------------------------------- /codegen.yml: -------------------------------------------------------------------------------- 1 | schema: http://localhost:8000/graphql 2 | documents: 3 | - operation.graphql 4 | generates: 5 | ./graphql.ts: 6 | config: 7 | withHooks: true 8 | plugins: 9 | - typescript 10 | - typescript-operations 11 | - typescript-urql 12 | -------------------------------------------------------------------------------- /graphql.ts: -------------------------------------------------------------------------------- 1 | import gql from 'graphql-tag'; 2 | import * as Urql from 'urql'; 3 | export type Maybe = T | null; 4 | export type Exact = { [K in keyof T]: T[K] }; 5 | export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; 6 | export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; 7 | export type Omit = Pick>; 8 | /** All built-in and custom scalars, mapped to their actual values */ 9 | export type Scalars = { 10 | ID: string; 11 | String: string; 12 | Boolean: boolean; 13 | Int: number; 14 | Float: number; 15 | }; 16 | 17 | export type AddLocationResponse = Location | LocationExists; 18 | 19 | export type AddTaskResponse = Task; 20 | 21 | export type Location = { 22 | __typename?: 'Location'; 23 | id: Scalars['ID']; 24 | name: Scalars['String']; 25 | }; 26 | 27 | export type LocationExists = { 28 | __typename?: 'LocationExists'; 29 | message: Scalars['String']; 30 | }; 31 | 32 | export type Mutation = { 33 | __typename?: 'Mutation'; 34 | addLocation: AddLocationResponse; 35 | addTask: AddTaskResponse; 36 | }; 37 | 38 | 39 | export type MutationAddLocationArgs = { 40 | name: Scalars['String']; 41 | }; 42 | 43 | 44 | export type MutationAddTaskArgs = { 45 | locationName?: Maybe; 46 | name: Scalars['String']; 47 | }; 48 | 49 | export type Query = { 50 | __typename?: 'Query'; 51 | locations: Array; 52 | tasks: Array; 53 | }; 54 | 55 | export type Task = { 56 | __typename?: 'Task'; 57 | id: Scalars['ID']; 58 | location?: Maybe; 59 | name: Scalars['String']; 60 | }; 61 | 62 | export type TasksQueryVariables = Exact<{ [key: string]: never; }>; 63 | 64 | 65 | export type TasksQuery = { __typename?: 'Query', tasks: Array<{ __typename?: 'Task', id: string, name: string, location?: { __typename?: 'Location', name: string } | null | undefined }> }; 66 | 67 | export type LocationsQueryVariables = Exact<{ [key: string]: never; }>; 68 | 69 | 70 | export type LocationsQuery = { __typename?: 'Query', locations: Array<{ __typename?: 'Location', id: string, name: string }> }; 71 | 72 | export type TaskFieldsFragment = { __typename?: 'Task', id: string, name: string, location?: { __typename?: 'Location', name: string } | null | undefined }; 73 | 74 | export type LocationFieldsFragment = { __typename?: 'Location', id: string, name: string }; 75 | 76 | export type AddTaskMutationVariables = Exact<{ 77 | name: Scalars['String']; 78 | locationName: Scalars['String']; 79 | }>; 80 | 81 | 82 | export type AddTaskMutation = { __typename?: 'Mutation', addTask: { __typename: 'Task', id: string, name: string, location?: { __typename?: 'Location', name: string } | null | undefined } }; 83 | 84 | export type AddLocationMutationVariables = Exact<{ 85 | name: Scalars['String']; 86 | }>; 87 | 88 | 89 | export type AddLocationMutation = { __typename?: 'Mutation', addLocation: { __typename: 'Location', id: string, name: string } | { __typename: 'LocationExists', message: string } }; 90 | 91 | export const TaskFieldsFragmentDoc = gql` 92 | fragment TaskFields on Task { 93 | id 94 | name 95 | location { 96 | name 97 | } 98 | } 99 | `; 100 | export const LocationFieldsFragmentDoc = gql` 101 | fragment LocationFields on Location { 102 | id 103 | name 104 | } 105 | `; 106 | export const TasksDocument = gql` 107 | query Tasks { 108 | tasks { 109 | ...TaskFields 110 | } 111 | } 112 | ${TaskFieldsFragmentDoc}`; 113 | 114 | export function useTasksQuery(options: Omit, 'query'> = {}) { 115 | return Urql.useQuery({ query: TasksDocument, ...options }); 116 | }; 117 | export const LocationsDocument = gql` 118 | query Locations { 119 | locations { 120 | ...LocationFields 121 | } 122 | } 123 | ${LocationFieldsFragmentDoc}`; 124 | 125 | export function useLocationsQuery(options: Omit, 'query'> = {}) { 126 | return Urql.useQuery({ query: LocationsDocument, ...options }); 127 | }; 128 | export const AddTaskDocument = gql` 129 | mutation AddTask($name: String!, $locationName: String!) { 130 | addTask(name: $name, locationName: $locationName) { 131 | __typename 132 | ... on Task { 133 | __typename 134 | ...TaskFields 135 | } 136 | } 137 | } 138 | ${TaskFieldsFragmentDoc}`; 139 | 140 | export function useAddTaskMutation() { 141 | return Urql.useMutation(AddTaskDocument); 142 | }; 143 | export const AddLocationDocument = gql` 144 | mutation AddLocation($name: String!) { 145 | addLocation(name: $name) { 146 | __typename 147 | ... on LocationExists { 148 | __typename 149 | message 150 | } 151 | ... on Location { 152 | __typename 153 | ...LocationFields 154 | } 155 | } 156 | } 157 | ${LocationFieldsFragmentDoc}`; 158 | 159 | export function useAddLocationMutation() { 160 | return Urql.useMutation(AddLocationDocument); 161 | }; -------------------------------------------------------------------------------- /models.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from contextlib import asynccontextmanager 3 | from typing import AsyncGenerator, Optional 4 | 5 | from sqlalchemy import Column, ForeignKey, Integer, String 6 | from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine 7 | from sqlalchemy.ext.declarative import declarative_base 8 | from sqlalchemy.orm import relationship, sessionmaker 9 | 10 | Base = declarative_base() 11 | 12 | 13 | class Location(Base): 14 | __tablename__ = "locations" 15 | id: int = Column(Integer, primary_key=True, index=True) 16 | name: str = Column(String, nullable=False, unique=True) 17 | 18 | tasks: list["Task"] = relationship("Task", lazy="joined", back_populates="location") 19 | 20 | 21 | class Task(Base): 22 | __tablename__ = "tasks" 23 | id: int = Column(Integer, primary_key=True, index=True) 24 | name: str = Column(String, nullable=False) 25 | location_id: Optional[int] = Column(Integer, ForeignKey(Location.id), nullable=True) 26 | 27 | location: Optional[Location] = relationship(Location, lazy="joined", back_populates="tasks") 28 | 29 | 30 | engine = create_async_engine( 31 | "sqlite+aiosqlite:///./database.db", connect_args={"check_same_thread": False} 32 | ) 33 | 34 | async_session = sessionmaker( 35 | bind=engine, 36 | class_=AsyncSession, 37 | expire_on_commit=False, 38 | autocommit=False, 39 | autoflush=False, 40 | ) 41 | 42 | 43 | @asynccontextmanager 44 | async def get_session() -> AsyncGenerator[AsyncSession, None]: 45 | async with async_session() as session: 46 | async with session.begin(): 47 | try: 48 | yield session 49 | finally: 50 | await session.close() 51 | 52 | 53 | async def _async_main(): 54 | async with engine.begin() as conn: 55 | await conn.run_sync(Base.metadata.drop_all) 56 | await conn.run_sync(Base.metadata.create_all) 57 | await engine.dispose() 58 | 59 | 60 | if __name__ == "__main__": 61 | print("Dropping and creating tables") 62 | asyncio.run(_async_main()) 63 | print("Done.") 64 | -------------------------------------------------------------------------------- /mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | plugins = strawberry.ext.mypy_plugin, sqlalchemy.ext.mypy.plugin 3 | -------------------------------------------------------------------------------- /next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | 5 | // NOTE: This file should not be edited 6 | // see https://nextjs.org/docs/basic-features/typescript for more information. 7 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | module.exports = { 3 | reactStrictMode: true, 4 | async rewrites() { 5 | return { 6 | beforeFiles: [ 7 | { 8 | source: "/graphql", 9 | destination: "http://localhost:8000/graphql", 10 | }, 11 | ], 12 | }; 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /operation.graphql: -------------------------------------------------------------------------------- 1 | query Tasks { 2 | tasks { 3 | ...TaskFields 4 | } 5 | } 6 | 7 | query Locations { 8 | locations { 9 | ...LocationFields 10 | } 11 | } 12 | 13 | fragment TaskFields on Task { 14 | id 15 | name 16 | location { 17 | name 18 | } 19 | } 20 | 21 | fragment LocationFields on Location { 22 | id 23 | name 24 | } 25 | 26 | mutation AddTask($name: String!, $locationName: String!) { 27 | addTask(name: $name, locationName: $locationName) { 28 | __typename 29 | # ... on LocationNotFound { 30 | # __typename 31 | # message 32 | # } 33 | ... on Task { 34 | __typename 35 | ...TaskFields 36 | } 37 | } 38 | } 39 | 40 | mutation AddLocation($name: String!) { 41 | addLocation(name: $name) { 42 | __typename 43 | ... on LocationExists { 44 | __typename 45 | message 46 | } 47 | ... on Location { 48 | __typename 49 | ...LocationFields 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "python-ts-graphql-demo", 3 | "private": true, 4 | "scripts": { 5 | "dev": "next dev", 6 | "build": "next build", 7 | "start": "next start", 8 | "lint": "next lint", 9 | "codegen": "graphql-codegen --watch" 10 | }, 11 | "graphql": { 12 | "schema": "schema.graphql", 13 | "documents": "src/**/*.{graphql,js,ts,jsx,tsx}" 14 | }, 15 | "dependencies": { 16 | "@graphql-codegen/cli": "^2.2.2", 17 | "@graphql-codegen/typescript": "^2.3.0", 18 | "@graphql-codegen/typescript-operations": "^2.2.0", 19 | "@graphql-codegen/typescript-urql": "^3.3.0", 20 | "@shopify/react-form": "^1.1.6", 21 | "graphql": "^15.7.2", 22 | "next": "^12.0.1", 23 | "react": "17.0.2", 24 | "react-dom": "17.0.2", 25 | "urql": "^2.0.5" 26 | }, 27 | "devDependencies": { 28 | "@types/node": "16.11.6", 29 | "@types/react": "17.0.34", 30 | "autoprefixer": "^10.4.0", 31 | "eslint": "7", 32 | "eslint-config-next": "12.0.2", 33 | "postcss": "^8.3.11", 34 | "tailwindcss": "^3.0.0-alpha.1", 35 | "typescript": "4.4.4" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import type { AppProps } from "next/app"; 2 | import { cacheExchange, createClient, Provider } from "urql"; 3 | import "../styles/globals.css"; 4 | import "tailwindcss/tailwind.css"; 5 | import { GetTasksDocument } from "../graphql"; 6 | 7 | const client = createClient({ 8 | url: "http://localhost:3000/graphql", 9 | }); 10 | 11 | cacheExchange({ 12 | updates: { 13 | Mutation: { 14 | addTodo(result, _args, cache, _info) { 15 | cache.updateQuery({ query: GetTasksDocument }, (data) => { 16 | data.tasks.push(result.addTask); 17 | return data; 18 | }); 19 | }, 20 | }, 21 | }, 22 | }); 23 | 24 | function MyApp({ Component, pageProps }: AppProps) { 25 | return ( 26 | 27 | 28 | 29 | ); 30 | } 31 | 32 | export default MyApp; 33 | -------------------------------------------------------------------------------- /pages/index.tsx: -------------------------------------------------------------------------------- 1 | import { Field, notEmptyString, useField, useForm } from "@shopify/react-form"; 2 | import type { NextPage } from "next"; 3 | import Head from "next/head"; 4 | import Image from "next/image"; 5 | import { useMemo } from "react"; 6 | import { 7 | useAddLocationMutation, 8 | useAddTaskMutation, 9 | useLocationsQuery, 10 | useTasksQuery, 11 | } from "../graphql"; 12 | 13 | const Pill: React.FC = ({ children }) => ( 14 |
15 | {children} 16 |
17 | ); 18 | 19 | const Input: React.FC<{ 20 | field: Field; 21 | placeholder?: string; 22 | disabled?: boolean; 23 | }> = ({ field, placeholder, disabled = false }) => ( 24 | <> 25 | 35 | {field.error && ( 36 |
{field.error}
37 | )} 38 | 39 | ); 40 | 41 | const Locations: React.FC = () => { 42 | const context = useMemo(() => ({ additionalTypenames: ["Location"] }), []); 43 | const [{ data, fetching }] = useLocationsQuery({ context }); 44 | if (fetching) return
Loading
; 45 | if (data?.locations.length === 0) return
No locations yet
; 46 | return ( 47 |
48 | {data?.locations.map(({ name }, index) => ( 49 | {name} 50 | ))} 51 |
52 | ); 53 | }; 54 | 55 | const Tasks: React.FC = () => { 56 | const context = useMemo(() => ({ additionalTypenames: ["Task"] }), []); 57 | const [{ data, fetching }] = useTasksQuery({ context }); 58 | if (fetching) return
Loading
; 59 | if (data?.tasks.length === 0) return
No tasks yet
; 60 | return ( 61 |
62 | {data?.tasks.map(({ name, location }, index) => ( 63 | 64 | {name} {location && `at ${location.name}`} 65 | 66 | ))} 67 |
68 | ); 69 | }; 70 | 71 | const AddLocation: React.FC = () => { 72 | const [{ fetching }, mutation] = useAddLocationMutation(); 73 | 74 | const { 75 | fields: { name }, 76 | submit, 77 | reset, 78 | } = useForm({ 79 | fields: { 80 | name: useField({ 81 | value: "", 82 | validates: notEmptyString("This field is required"), 83 | }), 84 | }, 85 | onSubmit: async ({ name }) => { 86 | const { data } = await mutation({ name }); 87 | if (data?.addLocation.__typename === "LocationExists") 88 | return { 89 | status: "fail", 90 | errors: [{ message: data.addLocation.message, field: ["name"] }], 91 | }; 92 | reset(); 93 | return { status: "success" }; 94 | }, 95 | }); 96 | 97 | return ( 98 |
99 |
100 |
Locations
101 | 102 |
103 | 104 | 107 |
108 | ); 109 | }; 110 | 111 | const AddTask: React.FC = () => { 112 | const [{ fetching }, mutation] = useAddTaskMutation(); 113 | 114 | const { 115 | fields: { name, locationName }, 116 | submit, 117 | reset, 118 | } = useForm({ 119 | fields: { 120 | name: useField({ 121 | value: "", 122 | validates: notEmptyString("This field is required"), 123 | }), 124 | locationName: useField(""), 125 | }, 126 | makeCleanAfterSubmit: false, 127 | onSubmit: async ({ name, locationName }) => { 128 | const { data } = await mutation({ name, locationName }); 129 | // if (data?.addTask.__typename === "LocationNotFound") 130 | // return { 131 | // status: "fail", 132 | // errors: [{ message: data.addTask.message, field: ["locationName"] }], 133 | // }; 134 | reset(); 135 | return { status: "success" }; 136 | }, 137 | }); 138 | 139 | return ( 140 | <> 141 |
142 |
Tasks
143 | 144 |
145 |
146 |
147 | 148 |
149 |
150 | 155 |
156 | 159 |
160 | 161 | ); 162 | }; 163 | 164 | const Home: NextPage = () => { 165 | return ( 166 |
167 | 168 | Mini Inch 169 | 173 | 174 | 175 | 176 |
177 |

178 |
179 | Mini Inch 180 |
181 |
182 | Panda 183 |
184 |

185 | 186 | 187 |
188 |
189 | ); 190 | }; 191 | 192 | export default Home; 193 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "aiosqlite" 3 | version = "0.17.0" 4 | description = "asyncio bridge to the standard sqlite3 module" 5 | category = "main" 6 | optional = false 7 | python-versions = ">=3.6" 8 | 9 | [package.dependencies] 10 | typing_extensions = ">=3.7.2" 11 | 12 | [[package]] 13 | name = "anyio" 14 | version = "3.3.4" 15 | description = "High level compatibility layer for multiple asynchronous event loop implementations" 16 | category = "main" 17 | optional = false 18 | python-versions = ">=3.6.2" 19 | 20 | [package.dependencies] 21 | idna = ">=2.8" 22 | sniffio = ">=1.1" 23 | 24 | [package.extras] 25 | doc = ["sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"] 26 | test = ["coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "pytest (>=6.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "mock (>=4)", "uvloop (>=0.15)"] 27 | trio = ["trio (>=0.16)"] 28 | 29 | [[package]] 30 | name = "asgiref" 31 | version = "3.4.1" 32 | description = "ASGI specs, helper code, and adapters" 33 | category = "main" 34 | optional = false 35 | python-versions = ">=3.6" 36 | 37 | [package.extras] 38 | tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"] 39 | 40 | [[package]] 41 | name = "bandit" 42 | version = "1.7.0" 43 | description = "Security oriented static analyser for python code." 44 | category = "dev" 45 | optional = false 46 | python-versions = ">=3.5" 47 | 48 | [package.dependencies] 49 | colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""} 50 | GitPython = ">=1.0.1" 51 | PyYAML = ">=5.3.1" 52 | six = ">=1.10.0" 53 | stevedore = ">=1.20.0" 54 | 55 | [[package]] 56 | name = "black" 57 | version = "21.10b0" 58 | description = "The uncompromising code formatter." 59 | category = "dev" 60 | optional = false 61 | python-versions = ">=3.6.2" 62 | 63 | [package.dependencies] 64 | click = ">=7.1.2" 65 | mypy-extensions = ">=0.4.3" 66 | pathspec = ">=0.9.0,<1" 67 | platformdirs = ">=2" 68 | regex = ">=2020.1.8" 69 | tomli = ">=0.2.6,<2.0.0" 70 | typing-extensions = [ 71 | {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}, 72 | {version = "!=3.10.0.1", markers = "python_version >= \"3.10\""}, 73 | ] 74 | 75 | [package.extras] 76 | colorama = ["colorama (>=0.4.3)"] 77 | d = ["aiohttp (>=3.7.4)"] 78 | jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] 79 | python2 = ["typed-ast (>=1.4.3)"] 80 | uvloop = ["uvloop (>=0.15.2)"] 81 | 82 | [[package]] 83 | name = "cached-property" 84 | version = "1.5.2" 85 | description = "A decorator for caching properties in classes." 86 | category = "main" 87 | optional = false 88 | python-versions = "*" 89 | 90 | [[package]] 91 | name = "click" 92 | version = "8.0.3" 93 | description = "Composable command line interface toolkit" 94 | category = "main" 95 | optional = false 96 | python-versions = ">=3.6" 97 | 98 | [package.dependencies] 99 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 100 | 101 | [[package]] 102 | name = "colorama" 103 | version = "0.4.4" 104 | description = "Cross-platform colored terminal text." 105 | category = "main" 106 | optional = false 107 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 108 | 109 | [[package]] 110 | name = "flake8" 111 | version = "4.0.1" 112 | description = "the modular source code checker: pep8 pyflakes and co" 113 | category = "dev" 114 | optional = false 115 | python-versions = ">=3.6" 116 | 117 | [package.dependencies] 118 | mccabe = ">=0.6.0,<0.7.0" 119 | pycodestyle = ">=2.8.0,<2.9.0" 120 | pyflakes = ">=2.4.0,<2.5.0" 121 | 122 | [[package]] 123 | name = "gitdb" 124 | version = "4.0.9" 125 | description = "Git Object Database" 126 | category = "dev" 127 | optional = false 128 | python-versions = ">=3.6" 129 | 130 | [package.dependencies] 131 | smmap = ">=3.0.1,<6" 132 | 133 | [[package]] 134 | name = "gitpython" 135 | version = "3.1.24" 136 | description = "GitPython is a python library used to interact with Git repositories" 137 | category = "dev" 138 | optional = false 139 | python-versions = ">=3.7" 140 | 141 | [package.dependencies] 142 | gitdb = ">=4.0.1,<5" 143 | typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.10\""} 144 | 145 | [[package]] 146 | name = "graphql-core" 147 | version = "3.1.6" 148 | description = "GraphQL implementation for Python, a port of GraphQL.js, the JavaScript reference implementation for GraphQL." 149 | category = "main" 150 | optional = false 151 | python-versions = ">=3.6,<4" 152 | 153 | [[package]] 154 | name = "greenlet" 155 | version = "1.1.2" 156 | description = "Lightweight in-process concurrent programming" 157 | category = "main" 158 | optional = false 159 | python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" 160 | 161 | [package.extras] 162 | docs = ["sphinx"] 163 | 164 | [[package]] 165 | name = "h11" 166 | version = "0.12.0" 167 | description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" 168 | category = "main" 169 | optional = false 170 | python-versions = ">=3.6" 171 | 172 | [[package]] 173 | name = "idna" 174 | version = "3.3" 175 | description = "Internationalized Domain Names in Applications (IDNA)" 176 | category = "main" 177 | optional = false 178 | python-versions = ">=3.5" 179 | 180 | [[package]] 181 | name = "isort" 182 | version = "5.10.0" 183 | description = "A Python utility / library to sort Python imports." 184 | category = "dev" 185 | optional = false 186 | python-versions = ">=3.6.1,<4.0" 187 | 188 | [package.extras] 189 | pipfile_deprecated_finder = ["pipreqs", "requirementslib"] 190 | requirements_deprecated_finder = ["pipreqs", "pip-api"] 191 | colors = ["colorama (>=0.4.3,<0.5.0)"] 192 | plugins = ["setuptools"] 193 | 194 | [[package]] 195 | name = "mccabe" 196 | version = "0.6.1" 197 | description = "McCabe checker, plugin for flake8" 198 | category = "dev" 199 | optional = false 200 | python-versions = "*" 201 | 202 | [[package]] 203 | name = "mypy" 204 | version = "0.910" 205 | description = "Optional static typing for Python" 206 | category = "dev" 207 | optional = false 208 | python-versions = ">=3.5" 209 | 210 | [package.dependencies] 211 | mypy-extensions = ">=0.4.3,<0.5.0" 212 | toml = "*" 213 | typing-extensions = ">=3.7.4" 214 | 215 | [package.extras] 216 | dmypy = ["psutil (>=4.0)"] 217 | python2 = ["typed-ast (>=1.4.0,<1.5.0)"] 218 | 219 | [[package]] 220 | name = "mypy-extensions" 221 | version = "0.4.3" 222 | description = "Experimental type system extensions for programs checked with the mypy typechecker." 223 | category = "dev" 224 | optional = false 225 | python-versions = "*" 226 | 227 | [[package]] 228 | name = "pathspec" 229 | version = "0.9.0" 230 | description = "Utility library for gitignore style pattern matching of file paths." 231 | category = "dev" 232 | optional = false 233 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" 234 | 235 | [[package]] 236 | name = "pbr" 237 | version = "5.6.0" 238 | description = "Python Build Reasonableness" 239 | category = "dev" 240 | optional = false 241 | python-versions = ">=2.6" 242 | 243 | [[package]] 244 | name = "platformdirs" 245 | version = "2.4.0" 246 | description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 247 | category = "dev" 248 | optional = false 249 | python-versions = ">=3.6" 250 | 251 | [package.extras] 252 | docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] 253 | test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] 254 | 255 | [[package]] 256 | name = "pycodestyle" 257 | version = "2.8.0" 258 | description = "Python style guide checker" 259 | category = "dev" 260 | optional = false 261 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 262 | 263 | [[package]] 264 | name = "pyflakes" 265 | version = "2.4.0" 266 | description = "passive checker of Python programs" 267 | category = "dev" 268 | optional = false 269 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 270 | 271 | [[package]] 272 | name = "pygments" 273 | version = "2.10.0" 274 | description = "Pygments is a syntax highlighting package written in Python." 275 | category = "main" 276 | optional = false 277 | python-versions = ">=3.5" 278 | 279 | [[package]] 280 | name = "python-dateutil" 281 | version = "2.8.2" 282 | description = "Extensions to the standard Python datetime module" 283 | category = "main" 284 | optional = false 285 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" 286 | 287 | [package.dependencies] 288 | six = ">=1.5" 289 | 290 | [[package]] 291 | name = "python-multipart" 292 | version = "0.0.5" 293 | description = "A streaming multipart parser for Python" 294 | category = "main" 295 | optional = false 296 | python-versions = "*" 297 | 298 | [package.dependencies] 299 | six = ">=1.4.0" 300 | 301 | [[package]] 302 | name = "pyyaml" 303 | version = "6.0" 304 | description = "YAML parser and emitter for Python" 305 | category = "dev" 306 | optional = false 307 | python-versions = ">=3.6" 308 | 309 | [[package]] 310 | name = "regex" 311 | version = "2021.11.2" 312 | description = "Alternative regular expression module, to replace re." 313 | category = "dev" 314 | optional = false 315 | python-versions = "*" 316 | 317 | [[package]] 318 | name = "sentinel" 319 | version = "0.3.0" 320 | description = "Create sentinel objects, akin to None, NotImplemented, Ellipsis" 321 | category = "main" 322 | optional = false 323 | python-versions = ">=3.6,<4.0" 324 | 325 | [package.extras] 326 | varname = ["varname (>=0.1)"] 327 | 328 | [[package]] 329 | name = "six" 330 | version = "1.16.0" 331 | description = "Python 2 and 3 compatibility utilities" 332 | category = "main" 333 | optional = false 334 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 335 | 336 | [[package]] 337 | name = "smmap" 338 | version = "5.0.0" 339 | description = "A pure Python implementation of a sliding window memory map manager" 340 | category = "dev" 341 | optional = false 342 | python-versions = ">=3.6" 343 | 344 | [[package]] 345 | name = "sniffio" 346 | version = "1.2.0" 347 | description = "Sniff out which async library your code is running under" 348 | category = "main" 349 | optional = false 350 | python-versions = ">=3.5" 351 | 352 | [[package]] 353 | name = "sqlalchemy" 354 | version = "1.4.26" 355 | description = "Database Abstraction Library" 356 | category = "main" 357 | optional = false 358 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" 359 | 360 | [package.dependencies] 361 | greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} 362 | 363 | [package.extras] 364 | aiomysql = ["greenlet (!=0.4.17)", "aiomysql"] 365 | aiosqlite = ["typing_extensions (!=3.10.0.1)", "greenlet (!=0.4.17)", "aiosqlite"] 366 | asyncio = ["greenlet (!=0.4.17)"] 367 | asyncmy = ["greenlet (!=0.4.17)", "asyncmy (>=0.2.3)"] 368 | mariadb_connector = ["mariadb (>=1.0.1)"] 369 | mssql = ["pyodbc"] 370 | mssql_pymssql = ["pymssql"] 371 | mssql_pyodbc = ["pyodbc"] 372 | mypy = ["sqlalchemy2-stubs", "mypy (>=0.910)"] 373 | mysql = ["mysqlclient (>=1.4.0,<2)", "mysqlclient (>=1.4.0)"] 374 | mysql_connector = ["mysql-connector-python"] 375 | oracle = ["cx_oracle (>=7,<8)", "cx_oracle (>=7)"] 376 | postgresql = ["psycopg2 (>=2.7)"] 377 | postgresql_asyncpg = ["greenlet (!=0.4.17)", "asyncpg"] 378 | postgresql_pg8000 = ["pg8000 (>=1.16.6)"] 379 | postgresql_psycopg2binary = ["psycopg2-binary"] 380 | postgresql_psycopg2cffi = ["psycopg2cffi"] 381 | pymysql = ["pymysql (<1)", "pymysql"] 382 | sqlcipher = ["sqlcipher3-binary"] 383 | 384 | [[package]] 385 | name = "sqlalchemy2-stubs" 386 | version = "0.0.2a19" 387 | description = "Typing Stubs for SQLAlchemy 1.4" 388 | category = "dev" 389 | optional = false 390 | python-versions = ">=3.6" 391 | 392 | [package.dependencies] 393 | typing-extensions = ">=3.7.4" 394 | 395 | [[package]] 396 | name = "starlette" 397 | version = "0.16.0" 398 | description = "The little ASGI library that shines." 399 | category = "main" 400 | optional = false 401 | python-versions = ">=3.6" 402 | 403 | [package.dependencies] 404 | anyio = ">=3.0.0,<4" 405 | 406 | [package.extras] 407 | full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests", "graphene"] 408 | 409 | [[package]] 410 | name = "stevedore" 411 | version = "3.5.0" 412 | description = "Manage dynamic plugins for Python applications" 413 | category = "dev" 414 | optional = false 415 | python-versions = ">=3.6" 416 | 417 | [package.dependencies] 418 | pbr = ">=2.0.0,<2.1.0 || >2.1.0" 419 | 420 | [[package]] 421 | name = "strawberry-graphql" 422 | version = "0.85.1" 423 | description = "A library for creating GraphQL APIs" 424 | category = "main" 425 | optional = false 426 | python-versions = ">=3.7,<4.0" 427 | 428 | [package.dependencies] 429 | cached-property = ">=1.5.2,<2.0.0" 430 | click = ">=7.0,<9.0" 431 | graphql-core = ">=3.1.0,<3.2.0" 432 | pygments = ">=2.3,<3.0" 433 | python-dateutil = ">=2.7.0,<3.0.0" 434 | python-multipart = ">=0.0.5,<0.0.6" 435 | sentinel = ">=0.3.0,<0.4.0" 436 | typing_extensions = ">=3.7.4,<4.0.0" 437 | 438 | [package.extras] 439 | asgi = ["starlette (>=0.13.6,<0.17.0)"] 440 | debug-server = ["starlette (>=0.13.6,<0.17.0)", "uvicorn (>=0.11.6,<0.16.0)"] 441 | django = ["django (>=2,<4)", "asgiref (>=3.2,<4.0)"] 442 | flask = ["flask (>=1.1,<2.0)"] 443 | opentelemetry = ["opentelemetry-api (<2)", "opentelemetry-sdk (<2)"] 444 | pydantic = ["pydantic (<2)"] 445 | sanic = ["sanic (>=20.12.2,<22.0.0)"] 446 | aiohttp = ["aiohttp (>=3.7.4.post0,<4.0.0)"] 447 | fastapi = ["fastapi (>=0.65.2)"] 448 | 449 | [[package]] 450 | name = "toml" 451 | version = "0.10.2" 452 | description = "Python Library for Tom's Obvious, Minimal Language" 453 | category = "dev" 454 | optional = false 455 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 456 | 457 | [[package]] 458 | name = "tomli" 459 | version = "1.2.2" 460 | description = "A lil' TOML parser" 461 | category = "dev" 462 | optional = false 463 | python-versions = ">=3.6" 464 | 465 | [[package]] 466 | name = "typing-extensions" 467 | version = "3.10.0.2" 468 | description = "Backported and Experimental Type Hints for Python 3.5+" 469 | category = "main" 470 | optional = false 471 | python-versions = "*" 472 | 473 | [[package]] 474 | name = "uvicorn" 475 | version = "0.15.0" 476 | description = "The lightning-fast ASGI server." 477 | category = "main" 478 | optional = false 479 | python-versions = "*" 480 | 481 | [package.dependencies] 482 | asgiref = ">=3.4.0" 483 | click = ">=7.0" 484 | h11 = ">=0.8" 485 | 486 | [package.extras] 487 | standard = ["websockets (>=9.1)", "httptools (>=0.2.0,<0.3.0)", "watchgod (>=0.6)", "python-dotenv (>=0.13)", "PyYAML (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "colorama (>=0.4)"] 488 | 489 | [metadata] 490 | lock-version = "1.1" 491 | python-versions = "^3.9" 492 | content-hash = "0da767ccce07ef39e21726003d8366b0d637bf8366e0353d353be3f43cd4fbf5" 493 | 494 | [metadata.files] 495 | aiosqlite = [ 496 | {file = "aiosqlite-0.17.0-py3-none-any.whl", hash = "sha256:6c49dc6d3405929b1d08eeccc72306d3677503cc5e5e43771efc1e00232e8231"}, 497 | {file = "aiosqlite-0.17.0.tar.gz", hash = "sha256:f0e6acc24bc4864149267ac82fb46dfb3be4455f99fe21df82609cc6e6baee51"}, 498 | ] 499 | anyio = [ 500 | {file = "anyio-3.3.4-py3-none-any.whl", hash = "sha256:4fd09a25ab7fa01d34512b7249e366cd10358cdafc95022c7ff8c8f8a5026d66"}, 501 | {file = "anyio-3.3.4.tar.gz", hash = "sha256:67da67b5b21f96b9d3d65daa6ea99f5d5282cb09f50eb4456f8fb51dffefc3ff"}, 502 | ] 503 | asgiref = [ 504 | {file = "asgiref-3.4.1-py3-none-any.whl", hash = "sha256:ffc141aa908e6f175673e7b1b3b7af4fdb0ecb738fc5c8b88f69f055c2415214"}, 505 | {file = "asgiref-3.4.1.tar.gz", hash = "sha256:4ef1ab46b484e3c706329cedeff284a5d40824200638503f5768edb6de7d58e9"}, 506 | ] 507 | bandit = [ 508 | {file = "bandit-1.7.0-py3-none-any.whl", hash = "sha256:216be4d044209fa06cf2a3e51b319769a51be8318140659719aa7a115c35ed07"}, 509 | {file = "bandit-1.7.0.tar.gz", hash = "sha256:8a4c7415254d75df8ff3c3b15cfe9042ecee628a1e40b44c15a98890fbfc2608"}, 510 | ] 511 | black = [ 512 | {file = "black-21.10b0-py3-none-any.whl", hash = "sha256:6eb7448da9143ee65b856a5f3676b7dda98ad9abe0f87fce8c59291f15e82a5b"}, 513 | {file = "black-21.10b0.tar.gz", hash = "sha256:a9952229092e325fe5f3dae56d81f639b23f7131eb840781947e4b2886030f33"}, 514 | ] 515 | cached-property = [ 516 | {file = "cached-property-1.5.2.tar.gz", hash = "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130"}, 517 | {file = "cached_property-1.5.2-py2.py3-none-any.whl", hash = "sha256:df4f613cf7ad9a588cc381aaf4a512d26265ecebd5eb9e1ba12f1319eb85a6a0"}, 518 | ] 519 | click = [ 520 | {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"}, 521 | {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"}, 522 | ] 523 | colorama = [ 524 | {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, 525 | {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, 526 | ] 527 | flake8 = [ 528 | {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, 529 | {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, 530 | ] 531 | gitdb = [ 532 | {file = "gitdb-4.0.9-py3-none-any.whl", hash = "sha256:8033ad4e853066ba6ca92050b9df2f89301b8fc8bf7e9324d412a63f8bf1a8fd"}, 533 | {file = "gitdb-4.0.9.tar.gz", hash = "sha256:bac2fd45c0a1c9cf619e63a90d62bdc63892ef92387424b855792a6cabe789aa"}, 534 | ] 535 | gitpython = [ 536 | {file = "GitPython-3.1.24-py3-none-any.whl", hash = "sha256:dc0a7f2f697657acc8d7f89033e8b1ea94dd90356b2983bca89dc8d2ab3cc647"}, 537 | {file = "GitPython-3.1.24.tar.gz", hash = "sha256:df83fdf5e684fef7c6ee2c02fc68a5ceb7e7e759d08b694088d0cacb4eba59e5"}, 538 | ] 539 | graphql-core = [ 540 | {file = "graphql-core-3.1.6.tar.gz", hash = "sha256:e65975b6a13878f9113a1fa5320760585b522d139944e005936b1b8358d0651a"}, 541 | {file = "graphql_core-3.1.6-py3-none-any.whl", hash = "sha256:c78d09596d347e1cffd266c5384abfedf43ed1eae08729773bebb3d527fe5a14"}, 542 | ] 543 | greenlet = [ 544 | {file = "greenlet-1.1.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:58df5c2a0e293bf665a51f8a100d3e9956febfbf1d9aaf8c0677cf70218910c6"}, 545 | {file = "greenlet-1.1.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:aec52725173bd3a7b56fe91bc56eccb26fbdff1386ef123abb63c84c5b43b63a"}, 546 | {file = "greenlet-1.1.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:833e1551925ed51e6b44c800e71e77dacd7e49181fdc9ac9a0bf3714d515785d"}, 547 | {file = "greenlet-1.1.2-cp27-cp27m-win32.whl", hash = "sha256:aa5b467f15e78b82257319aebc78dd2915e4c1436c3c0d1ad6f53e47ba6e2713"}, 548 | {file = "greenlet-1.1.2-cp27-cp27m-win_amd64.whl", hash = "sha256:40b951f601af999a8bf2ce8c71e8aaa4e8c6f78ff8afae7b808aae2dc50d4c40"}, 549 | {file = "greenlet-1.1.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:95e69877983ea39b7303570fa6760f81a3eec23d0e3ab2021b7144b94d06202d"}, 550 | {file = "greenlet-1.1.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:356b3576ad078c89a6107caa9c50cc14e98e3a6c4874a37c3e0273e4baf33de8"}, 551 | {file = "greenlet-1.1.2-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:8639cadfda96737427330a094476d4c7a56ac03de7265622fcf4cfe57c8ae18d"}, 552 | {file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e5306482182170ade15c4b0d8386ded995a07d7cc2ca8f27958d34d6736497"}, 553 | {file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6a36bb9474218c7a5b27ae476035497a6990e21d04c279884eb10d9b290f1b1"}, 554 | {file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abb7a75ed8b968f3061327c433a0fbd17b729947b400747c334a9c29a9af6c58"}, 555 | {file = "greenlet-1.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:14d4f3cd4e8b524ae9b8aa567858beed70c392fdec26dbdb0a8a418392e71708"}, 556 | {file = "greenlet-1.1.2-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:17ff94e7a83aa8671a25bf5b59326ec26da379ace2ebc4411d690d80a7fbcf23"}, 557 | {file = "greenlet-1.1.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9f3cba480d3deb69f6ee2c1825060177a22c7826431458c697df88e6aeb3caee"}, 558 | {file = "greenlet-1.1.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:fa877ca7f6b48054f847b61d6fa7bed5cebb663ebc55e018fda12db09dcc664c"}, 559 | {file = "greenlet-1.1.2-cp35-cp35m-win32.whl", hash = "sha256:7cbd7574ce8e138bda9df4efc6bf2ab8572c9aff640d8ecfece1b006b68da963"}, 560 | {file = "greenlet-1.1.2-cp35-cp35m-win_amd64.whl", hash = "sha256:903bbd302a2378f984aef528f76d4c9b1748f318fe1294961c072bdc7f2ffa3e"}, 561 | {file = "greenlet-1.1.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:049fe7579230e44daef03a259faa24511d10ebfa44f69411d99e6a184fe68073"}, 562 | {file = "greenlet-1.1.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:dd0b1e9e891f69e7675ba5c92e28b90eaa045f6ab134ffe70b52e948aa175b3c"}, 563 | {file = "greenlet-1.1.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:7418b6bfc7fe3331541b84bb2141c9baf1ec7132a7ecd9f375912eca810e714e"}, 564 | {file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9d29ca8a77117315101425ec7ec2a47a22ccf59f5593378fc4077ac5b754fce"}, 565 | {file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21915eb821a6b3d9d8eefdaf57d6c345b970ad722f856cd71739493ce003ad08"}, 566 | {file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eff9d20417ff9dcb0d25e2defc2574d10b491bf2e693b4e491914738b7908168"}, 567 | {file = "greenlet-1.1.2-cp36-cp36m-win32.whl", hash = "sha256:32ca72bbc673adbcfecb935bb3fb1b74e663d10a4b241aaa2f5a75fe1d1f90aa"}, 568 | {file = "greenlet-1.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:f0214eb2a23b85528310dad848ad2ac58e735612929c8072f6093f3585fd342d"}, 569 | {file = "greenlet-1.1.2-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:b92e29e58bef6d9cfd340c72b04d74c4b4e9f70c9fa7c78b674d1fec18896dc4"}, 570 | {file = "greenlet-1.1.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fdcec0b8399108577ec290f55551d926d9a1fa6cad45882093a7a07ac5ec147b"}, 571 | {file = "greenlet-1.1.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:93f81b134a165cc17123626ab8da2e30c0455441d4ab5576eed73a64c025b25c"}, 572 | {file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e12bdc622676ce47ae9abbf455c189e442afdde8818d9da983085df6312e7a1"}, 573 | {file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c790abda465726cfb8bb08bd4ca9a5d0a7bd77c7ac1ca1b839ad823b948ea28"}, 574 | {file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f276df9830dba7a333544bd41070e8175762a7ac20350786b322b714b0e654f5"}, 575 | {file = "greenlet-1.1.2-cp37-cp37m-win32.whl", hash = "sha256:64e6175c2e53195278d7388c454e0b30997573f3f4bd63697f88d855f7a6a1fc"}, 576 | {file = "greenlet-1.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b11548073a2213d950c3f671aa88e6f83cda6e2fb97a8b6317b1b5b33d850e06"}, 577 | {file = "greenlet-1.1.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:9633b3034d3d901f0a46b7939f8c4d64427dfba6bbc5a36b1a67364cf148a1b0"}, 578 | {file = "greenlet-1.1.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:eb6ea6da4c787111adf40f697b4e58732ee0942b5d3bd8f435277643329ba627"}, 579 | {file = "greenlet-1.1.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:f3acda1924472472ddd60c29e5b9db0cec629fbe3c5c5accb74d6d6d14773478"}, 580 | {file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e859fcb4cbe93504ea18008d1df98dee4f7766db66c435e4882ab35cf70cac43"}, 581 | {file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00e44c8afdbe5467e4f7b5851be223be68adb4272f44696ee71fe46b7036a711"}, 582 | {file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec8c433b3ab0419100bd45b47c9c8551248a5aee30ca5e9d399a0b57ac04651b"}, 583 | {file = "greenlet-1.1.2-cp38-cp38-win32.whl", hash = "sha256:288c6a76705dc54fba69fbcb59904ae4ad768b4c768839b8ca5fdadec6dd8cfd"}, 584 | {file = "greenlet-1.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:8d2f1fb53a421b410751887eb4ff21386d119ef9cde3797bf5e7ed49fb51a3b3"}, 585 | {file = "greenlet-1.1.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:166eac03e48784a6a6e0e5f041cfebb1ab400b394db188c48b3a84737f505b67"}, 586 | {file = "greenlet-1.1.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:572e1787d1460da79590bf44304abbc0a2da944ea64ec549188fa84d89bba7ab"}, 587 | {file = "greenlet-1.1.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:be5f425ff1f5f4b3c1e33ad64ab994eed12fc284a6ea71c5243fd564502ecbe5"}, 588 | {file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1692f7d6bc45e3200844be0dba153612103db241691088626a33ff1f24a0d88"}, 589 | {file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7227b47e73dedaa513cdebb98469705ef0d66eb5a1250144468e9c3097d6b59b"}, 590 | {file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ff61ff178250f9bb3cd89752df0f1dd0e27316a8bd1465351652b1b4a4cdfd3"}, 591 | {file = "greenlet-1.1.2-cp39-cp39-win32.whl", hash = "sha256:f70a9e237bb792c7cc7e44c531fd48f5897961701cdaa06cf22fc14965c496cf"}, 592 | {file = "greenlet-1.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:013d61294b6cd8fe3242932c1c5e36e5d1db2c8afb58606c5a67efce62c1f5fd"}, 593 | {file = "greenlet-1.1.2.tar.gz", hash = "sha256:e30f5ea4ae2346e62cedde8794a56858a67b878dd79f7df76a0767e356b1744a"}, 594 | ] 595 | h11 = [ 596 | {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"}, 597 | {file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"}, 598 | ] 599 | idna = [ 600 | {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, 601 | {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, 602 | ] 603 | isort = [ 604 | {file = "isort-5.10.0-py3-none-any.whl", hash = "sha256:1a18ccace2ed8910bd9458b74a3ecbafd7b2f581301b0ab65cfdd4338272d76f"}, 605 | {file = "isort-5.10.0.tar.gz", hash = "sha256:e52ff6d38012b131628cf0f26c51e7bd3a7c81592eefe3ac71411e692f1b9345"}, 606 | ] 607 | mccabe = [ 608 | {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, 609 | {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, 610 | ] 611 | mypy = [ 612 | {file = "mypy-0.910-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:a155d80ea6cee511a3694b108c4494a39f42de11ee4e61e72bc424c490e46457"}, 613 | {file = "mypy-0.910-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b94e4b785e304a04ea0828759172a15add27088520dc7e49ceade7834275bedb"}, 614 | {file = "mypy-0.910-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:088cd9c7904b4ad80bec811053272986611b84221835e079be5bcad029e79dd9"}, 615 | {file = "mypy-0.910-cp35-cp35m-win_amd64.whl", hash = "sha256:adaeee09bfde366d2c13fe6093a7df5df83c9a2ba98638c7d76b010694db760e"}, 616 | {file = "mypy-0.910-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ecd2c3fe726758037234c93df7e98deb257fd15c24c9180dacf1ef829da5f921"}, 617 | {file = "mypy-0.910-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d9dd839eb0dc1bbe866a288ba3c1afc33a202015d2ad83b31e875b5905a079b6"}, 618 | {file = "mypy-0.910-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:3e382b29f8e0ccf19a2df2b29a167591245df90c0b5a2542249873b5c1d78212"}, 619 | {file = "mypy-0.910-cp36-cp36m-win_amd64.whl", hash = "sha256:53fd2eb27a8ee2892614370896956af2ff61254c275aaee4c230ae771cadd885"}, 620 | {file = "mypy-0.910-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b6fb13123aeef4a3abbcfd7e71773ff3ff1526a7d3dc538f3929a49b42be03f0"}, 621 | {file = "mypy-0.910-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e4dab234478e3bd3ce83bac4193b2ecd9cf94e720ddd95ce69840273bf44f6de"}, 622 | {file = "mypy-0.910-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:7df1ead20c81371ccd6091fa3e2878559b5c4d4caadaf1a484cf88d93ca06703"}, 623 | {file = "mypy-0.910-cp37-cp37m-win_amd64.whl", hash = "sha256:0aadfb2d3935988ec3815952e44058a3100499f5be5b28c34ac9d79f002a4a9a"}, 624 | {file = "mypy-0.910-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ec4e0cd079db280b6bdabdc807047ff3e199f334050db5cbb91ba3e959a67504"}, 625 | {file = "mypy-0.910-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:119bed3832d961f3a880787bf621634ba042cb8dc850a7429f643508eeac97b9"}, 626 | {file = "mypy-0.910-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:866c41f28cee548475f146aa4d39a51cf3b6a84246969f3759cb3e9c742fc072"}, 627 | {file = "mypy-0.910-cp38-cp38-win_amd64.whl", hash = "sha256:ceb6e0a6e27fb364fb3853389607cf7eb3a126ad335790fa1e14ed02fba50811"}, 628 | {file = "mypy-0.910-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1a85e280d4d217150ce8cb1a6dddffd14e753a4e0c3cf90baabb32cefa41b59e"}, 629 | {file = "mypy-0.910-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:42c266ced41b65ed40a282c575705325fa7991af370036d3f134518336636f5b"}, 630 | {file = "mypy-0.910-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:3c4b8ca36877fc75339253721f69603a9c7fdb5d4d5a95a1a1b899d8b86a4de2"}, 631 | {file = "mypy-0.910-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:c0df2d30ed496a08de5daed2a9ea807d07c21ae0ab23acf541ab88c24b26ab97"}, 632 | {file = "mypy-0.910-cp39-cp39-win_amd64.whl", hash = "sha256:c6c2602dffb74867498f86e6129fd52a2770c48b7cd3ece77ada4fa38f94eba8"}, 633 | {file = "mypy-0.910-py3-none-any.whl", hash = "sha256:ef565033fa5a958e62796867b1df10c40263ea9ded87164d67572834e57a174d"}, 634 | {file = "mypy-0.910.tar.gz", hash = "sha256:704098302473cb31a218f1775a873b376b30b4c18229421e9e9dc8916fd16150"}, 635 | ] 636 | mypy-extensions = [ 637 | {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, 638 | {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, 639 | ] 640 | pathspec = [ 641 | {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, 642 | {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, 643 | ] 644 | pbr = [ 645 | {file = "pbr-5.6.0-py2.py3-none-any.whl", hash = "sha256:c68c661ac5cc81058ac94247278eeda6d2e6aecb3e227b0387c30d277e7ef8d4"}, 646 | {file = "pbr-5.6.0.tar.gz", hash = "sha256:42df03e7797b796625b1029c0400279c7c34fd7df24a7d7818a1abb5b38710dd"}, 647 | ] 648 | platformdirs = [ 649 | {file = "platformdirs-2.4.0-py3-none-any.whl", hash = "sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d"}, 650 | {file = "platformdirs-2.4.0.tar.gz", hash = "sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2"}, 651 | ] 652 | pycodestyle = [ 653 | {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"}, 654 | {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"}, 655 | ] 656 | pyflakes = [ 657 | {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"}, 658 | {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"}, 659 | ] 660 | pygments = [ 661 | {file = "Pygments-2.10.0-py3-none-any.whl", hash = "sha256:b8e67fe6af78f492b3c4b3e2970c0624cbf08beb1e493b2c99b9fa1b67a20380"}, 662 | {file = "Pygments-2.10.0.tar.gz", hash = "sha256:f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6"}, 663 | ] 664 | python-dateutil = [ 665 | {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, 666 | {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, 667 | ] 668 | python-multipart = [ 669 | {file = "python-multipart-0.0.5.tar.gz", hash = "sha256:f7bb5f611fc600d15fa47b3974c8aa16e93724513b49b5f95c81e6624c83fa43"}, 670 | ] 671 | pyyaml = [ 672 | {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, 673 | {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, 674 | {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, 675 | {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, 676 | {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, 677 | {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, 678 | {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, 679 | {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, 680 | {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, 681 | {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, 682 | {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, 683 | {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, 684 | {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, 685 | {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, 686 | {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, 687 | {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, 688 | {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, 689 | {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, 690 | {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, 691 | {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, 692 | {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, 693 | {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, 694 | {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, 695 | {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, 696 | {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, 697 | {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, 698 | {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, 699 | {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, 700 | {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, 701 | {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, 702 | {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, 703 | {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, 704 | {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, 705 | ] 706 | regex = [ 707 | {file = "regex-2021.11.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:897c539f0f3b2c3a715be651322bef2167de1cdc276b3f370ae81a3bda62df71"}, 708 | {file = "regex-2021.11.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:886f459db10c0f9d17c87d6594e77be915f18d343ee138e68d259eb385f044a8"}, 709 | {file = "regex-2021.11.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:075b0fdbaea81afcac5a39a0d1bb91de887dd0d93bf692a5dd69c430e7fc58cb"}, 710 | {file = "regex-2021.11.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6238d30dcff141de076344cf7f52468de61729c2f70d776fce12f55fe8df790"}, 711 | {file = "regex-2021.11.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7fab29411d75c2eb48070020a40f80255936d7c31357b086e5931c107d48306e"}, 712 | {file = "regex-2021.11.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0148988af0182a0a4e5020e7c168014f2c55a16d11179610f7883dd48ac0ebe"}, 713 | {file = "regex-2021.11.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be30cd315db0168063a1755fa20a31119da91afa51da2907553493516e165640"}, 714 | {file = "regex-2021.11.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e9cec3a62d146e8e122d159ab93ac32c988e2ec0dcb1e18e9e53ff2da4fbd30c"}, 715 | {file = "regex-2021.11.2-cp310-cp310-win32.whl", hash = "sha256:41c66bd6750237a8ed23028a6c9173dc0c92dc24c473e771d3bfb9ee817700c3"}, 716 | {file = "regex-2021.11.2-cp310-cp310-win_amd64.whl", hash = "sha256:0075fe4e2c2720a685fef0f863edd67740ff78c342cf20b2a79bc19388edf5db"}, 717 | {file = "regex-2021.11.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0ed3465acf8c7c10aa2e0f3d9671da410ead63b38a77283ef464cbb64275df58"}, 718 | {file = "regex-2021.11.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab1fea8832976ad0bebb11f652b692c328043057d35e9ebc78ab0a7a30cf9a70"}, 719 | {file = "regex-2021.11.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cb1e44d860345ab5d4f533b6c37565a22f403277f44c4d2d5e06c325da959883"}, 720 | {file = "regex-2021.11.2-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9486ebda015913909bc28763c6b92fcc3b5e5a67dee4674bceed112109f5dfb8"}, 721 | {file = "regex-2021.11.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20605bfad484e1341b2cbfea0708e4b211d233716604846baa54b94821f487cb"}, 722 | {file = "regex-2021.11.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f20f9f430c33597887ba9bd76635476928e76cad2981643ca8be277b8e97aa96"}, 723 | {file = "regex-2021.11.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1d85ca137756d62c8138c971453cafe64741adad1f6a7e63a22a5a8abdbd19fa"}, 724 | {file = "regex-2021.11.2-cp36-cp36m-win32.whl", hash = "sha256:af23b9ca9a874ef0ec20e44467b8edd556c37b0f46f93abfa93752ea7c0e8d1e"}, 725 | {file = "regex-2021.11.2-cp36-cp36m-win_amd64.whl", hash = "sha256:070336382ca92c16c45b4066c4ba9fa83fb0bd13d5553a82e07d344df8d58a84"}, 726 | {file = "regex-2021.11.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ef4e53e2fdc997d91f5b682f81f7dc9661db9a437acce28745d765d251902d85"}, 727 | {file = "regex-2021.11.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35ed5714467fc606551db26f80ee5d6aa1f01185586a7bccd96f179c4b974a11"}, 728 | {file = "regex-2021.11.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee36d5113b6506b97f45f2e8447cb9af146e60e3f527d93013d19f6d0405f3b"}, 729 | {file = "regex-2021.11.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4fba661a4966adbd2c3c08d3caad6822ecb6878f5456588e2475ae23a6e47929"}, 730 | {file = "regex-2021.11.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77f9d16f7970791f17ecce7e7f101548314ed1ee2583d4268601f30af3170856"}, 731 | {file = "regex-2021.11.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6a28e87ba69f3a4f30d775b179aac55be1ce59f55799328a0d9b6df8f16b39d"}, 732 | {file = "regex-2021.11.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9267e4fba27e6dd1008c4f2983cc548c98b4be4444e3e342db11296c0f45512f"}, 733 | {file = "regex-2021.11.2-cp37-cp37m-win32.whl", hash = "sha256:d4bfe3bc3976ccaeb4ae32f51e631964e2f0e85b2b752721b7a02de5ce3b7f27"}, 734 | {file = "regex-2021.11.2-cp37-cp37m-win_amd64.whl", hash = "sha256:2bb7cae741de1aa03e3dd3a7d98c304871eb155921ca1f0d7cc11f5aade913fd"}, 735 | {file = "regex-2021.11.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:23f93e74409c210de4de270d4bf88fb8ab736a7400f74210df63a93728cf70d6"}, 736 | {file = "regex-2021.11.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d8ee91e1c295beb5c132ebd78616814de26fedba6aa8687ea460c7f5eb289b72"}, 737 | {file = "regex-2021.11.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e3ff69ab203b54ce5c480c3ccbe959394ea5beef6bd5ad1785457df7acea92e"}, 738 | {file = "regex-2021.11.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e3c00cb5c71da655e1e5161481455479b613d500dd1bd252aa01df4f037c641f"}, 739 | {file = "regex-2021.11.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4abf35e16f4b639daaf05a2602c1b1d47370e01babf9821306aa138924e3fe92"}, 740 | {file = "regex-2021.11.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb11c982a849dc22782210b01d0c1b98eb3696ce655d58a54180774e4880ac66"}, 741 | {file = "regex-2021.11.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e3755e0f070bc31567dfe447a02011bfa8444239b3e9e5cca6773a22133839"}, 742 | {file = "regex-2021.11.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0621c90f28d17260b41838b22c81a79ff436141b322960eb49c7b3f91d1cbab6"}, 743 | {file = "regex-2021.11.2-cp38-cp38-win32.whl", hash = "sha256:8fbe1768feafd3d0156556677b8ff234c7bf94a8110e906b2d73506f577a3269"}, 744 | {file = "regex-2021.11.2-cp38-cp38-win_amd64.whl", hash = "sha256:f9ee98d658a146cb6507be720a0ce1b44f2abef8fb43c2859791d91aace17cd5"}, 745 | {file = "regex-2021.11.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b3794cea825f101fe0df9af8a00f9fad8e119c91e39a28636b95ee2b45b6c2e5"}, 746 | {file = "regex-2021.11.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3576e173e7b4f88f683b4de7db0c2af1b209bb48b2bf1c827a6f3564fad59a97"}, 747 | {file = "regex-2021.11.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48b4f4810117a9072a5aa70f7fea5f86fa9efbe9a798312e0a05044bd707cc33"}, 748 | {file = "regex-2021.11.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f5930d334c2f607711d54761956aedf8137f83f1b764b9640be21d25a976f3a4"}, 749 | {file = "regex-2021.11.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:956187ff49db7014ceb31e88fcacf4cf63371e6e44d209cf8816cd4a2d61e11a"}, 750 | {file = "regex-2021.11.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17e095f7f96a4b9f24b93c2c915f31a5201a6316618d919b0593afb070a5270e"}, 751 | {file = "regex-2021.11.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a56735c35a3704603d9d7b243ee06139f0837bcac2171d9ba1d638ce1df0742a"}, 752 | {file = "regex-2021.11.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:adf35d88d9cffc202e6046e4c32e1e11a1d0238b2fcf095c94f109e510ececea"}, 753 | {file = "regex-2021.11.2-cp39-cp39-win32.whl", hash = "sha256:30fe317332de0e50195665bc61a27d46e903d682f94042c36b3f88cb84bd7958"}, 754 | {file = "regex-2021.11.2-cp39-cp39-win_amd64.whl", hash = "sha256:85289c25f658e3260b00178757c87f033f3d4b3e40aa4abdd4dc875ff11a94fb"}, 755 | {file = "regex-2021.11.2.tar.gz", hash = "sha256:5e85dcfc5d0f374955015ae12c08365b565c6f1eaf36dd182476a4d8e5a1cdb7"}, 756 | ] 757 | sentinel = [ 758 | {file = "sentinel-0.3.0-py3-none-any.whl", hash = "sha256:bd8710dd26752039c668604f6be2aaf741b56f7811c5924a4dcdfd74359244f3"}, 759 | {file = "sentinel-0.3.0.tar.gz", hash = "sha256:f28143aa4716dbc8f6193f5682176a3c33cd26aaae05d9ecf66c186a9887cc2d"}, 760 | ] 761 | six = [ 762 | {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, 763 | {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, 764 | ] 765 | smmap = [ 766 | {file = "smmap-5.0.0-py3-none-any.whl", hash = "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94"}, 767 | {file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"}, 768 | ] 769 | sniffio = [ 770 | {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"}, 771 | {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"}, 772 | ] 773 | sqlalchemy = [ 774 | {file = "SQLAlchemy-1.4.26-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:c2f2114b0968a280f94deeeaa31cfbac9175e6ac7bd3058b3ce6e054ecd762b3"}, 775 | {file = "SQLAlchemy-1.4.26-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:91efbda4e6d311812f23996242bad7665c1392209554f8a31ec6db757456db5c"}, 776 | {file = "SQLAlchemy-1.4.26-cp27-cp27m-win32.whl", hash = "sha256:de996756d894a2d52c132742e3b6d64ecd37e0919ddadf4dc3981818777c7e67"}, 777 | {file = "SQLAlchemy-1.4.26-cp27-cp27m-win_amd64.whl", hash = "sha256:463ef692259ff8189be42223e433542347ae17e33f91c1013e9c5c64e2798088"}, 778 | {file = "SQLAlchemy-1.4.26-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c757ba1279b85b3460e72e8b92239dae6f8b060a75fb24b3d9be984dd78cfa55"}, 779 | {file = "SQLAlchemy-1.4.26-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:c24c01dcd03426a5fe5ee7af735906bec6084977b9027a3605d11d949a565c01"}, 780 | {file = "SQLAlchemy-1.4.26-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c46f013ff31b80cbe36410281675e1fb4eaf3e25c284fd8a69981c73f6fa4cb4"}, 781 | {file = "SQLAlchemy-1.4.26-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fb2aa74a6e3c2cebea38dd21633671841fbe70ea486053cba33d68e3e22ccc0a"}, 782 | {file = "SQLAlchemy-1.4.26-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad7e403fc1e3cb76e802872694e30d6ca6129b9bc6ad4e7caa48ca35f8a144f8"}, 783 | {file = "SQLAlchemy-1.4.26-cp310-cp310-win32.whl", hash = "sha256:7ef421c3887b39c6f352e5022a53ac18de8387de331130481cb956b2d029cad6"}, 784 | {file = "SQLAlchemy-1.4.26-cp310-cp310-win_amd64.whl", hash = "sha256:908fad32c53b17aad12d722379150c3c5317c422437e44032256a77df1746292"}, 785 | {file = "SQLAlchemy-1.4.26-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:1ef37c9ec2015ce2f0dc1084514e197f2f199d3dc3514190db7620b78e6004c8"}, 786 | {file = "SQLAlchemy-1.4.26-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:090536fd23bf49077ee94ff97142bc5ee8bad24294c3d7c8d5284267c885dde7"}, 787 | {file = "SQLAlchemy-1.4.26-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e700d48056475d077f867e6a36e58546de71bdb6fdc3d34b879e3240827fefab"}, 788 | {file = "SQLAlchemy-1.4.26-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:295b90efef1278f27fe27d94a45460ae3c17f5c5c2b32c163e29c359740a1599"}, 789 | {file = "SQLAlchemy-1.4.26-cp36-cp36m-win32.whl", hash = "sha256:cc6b21f19bc9d4cd77cbcba5f3b260436ce033f1053cea225b6efea2603d201e"}, 790 | {file = "SQLAlchemy-1.4.26-cp36-cp36m-win_amd64.whl", hash = "sha256:ba84026e84379326bbf2f0c50792f2ae56ab9c01937df5597b6893810b8ca369"}, 791 | {file = "SQLAlchemy-1.4.26-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:f1e97c5f36b94542f72917b62f3a2f92be914b2cf33b80fa69cede7529241d2a"}, 792 | {file = "SQLAlchemy-1.4.26-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c185c928e2638af9bae13acc3f70e0096eac76471a1101a10f96b80666b8270"}, 793 | {file = "SQLAlchemy-1.4.26-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bca660b76672e15d70a7dba5e703e1ce451a0257b6bd2028e62b0487885e8ae9"}, 794 | {file = "SQLAlchemy-1.4.26-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff8f91a7b1c4a1c7772caa9efe640f2768828897044748f2458b708f1026e2d4"}, 795 | {file = "SQLAlchemy-1.4.26-cp37-cp37m-win32.whl", hash = "sha256:a95bf9c725012dcd7ea3cac16bf647054e0d62b31d67467d228338e6a163e4ff"}, 796 | {file = "SQLAlchemy-1.4.26-cp37-cp37m-win_amd64.whl", hash = "sha256:07ac4461a1116b317519ddf6f34bcb00b011b5c1370ebeaaf56595504ffc7e84"}, 797 | {file = "SQLAlchemy-1.4.26-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:5039faa365e7522a8eb4736a54afd24a7e75dcc33b81ab2f0e6c456140f1ad64"}, 798 | {file = "SQLAlchemy-1.4.26-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7e8ef103eaa72a857746fd57dda5b8b5961e8e82a528a3f8b7e2884d8506f0b7"}, 799 | {file = "SQLAlchemy-1.4.26-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:31f4426cfad19b5a50d07153146b2bcb372a279975d5fa39f98883c0ef0f3313"}, 800 | {file = "SQLAlchemy-1.4.26-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2feb028dc75e13ba93456a42ac042b255bf94dbd692bf80b47b22653bb25ccf8"}, 801 | {file = "SQLAlchemy-1.4.26-cp38-cp38-win32.whl", hash = "sha256:2ce42ad1f59eb85c55c44fb505f8854081ee23748f76b62a7f569cfa9b6d0604"}, 802 | {file = "SQLAlchemy-1.4.26-cp38-cp38-win_amd64.whl", hash = "sha256:dbf588ab09e522ac2cbd010919a592c6aae2f15ccc3cd9a96d01c42fbc13f63e"}, 803 | {file = "SQLAlchemy-1.4.26-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:a6506c17b0b6016656783232d0bdd03fd333f1f654d51a14d93223f953903646"}, 804 | {file = "SQLAlchemy-1.4.26-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a882dedb9dfa6f33524953c3e3d72bcf518a5defd6d5863150a821928b19ad3"}, 805 | {file = "SQLAlchemy-1.4.26-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1dee515578d04bc80c4f9a8c8cfe93f455db725059e885f1b1da174d91c4d077"}, 806 | {file = "SQLAlchemy-1.4.26-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c0c5f54560a92691d54b0768d67b4d3159e514b426cfcb1258af8c195577e8f"}, 807 | {file = "SQLAlchemy-1.4.26-cp39-cp39-win32.whl", hash = "sha256:b86f762cee3709722ab4691981958cbec475ea43406a6916a7ec375db9cbd9e9"}, 808 | {file = "SQLAlchemy-1.4.26-cp39-cp39-win_amd64.whl", hash = "sha256:5c6774b34782116ad9bdec61c2dbce9faaca4b166a0bc8e7b03c2b870b121d94"}, 809 | {file = "SQLAlchemy-1.4.26.tar.gz", hash = "sha256:6bc7f9d7d90ef55e8c6db1308a8619cd8f40e24a34f759119b95e7284dca351a"}, 810 | ] 811 | sqlalchemy2-stubs = [ 812 | {file = "sqlalchemy2-stubs-0.0.2a19.tar.gz", hash = "sha256:2117c48ce5acfe33bf9c9bfce2a981632d931949e68fa313aa5c2a3bc980ca7a"}, 813 | {file = "sqlalchemy2_stubs-0.0.2a19-py3-none-any.whl", hash = "sha256:aac7dca77a2c49e5f0934976421d5e25ae4dc5e27db48c01e055f81caa1e3ead"}, 814 | ] 815 | starlette = [ 816 | {file = "starlette-0.16.0-py3-none-any.whl", hash = "sha256:38eb24bf705a2c317e15868e384c1b8a12ca396e5a3c3a003db7e667c43f939f"}, 817 | {file = "starlette-0.16.0.tar.gz", hash = "sha256:e1904b5d0007aee24bdd3c43994be9b3b729f4f58e740200de1d623f8c3a8870"}, 818 | ] 819 | stevedore = [ 820 | {file = "stevedore-3.5.0-py3-none-any.whl", hash = "sha256:a547de73308fd7e90075bb4d301405bebf705292fa90a90fc3bcf9133f58616c"}, 821 | {file = "stevedore-3.5.0.tar.gz", hash = "sha256:f40253887d8712eaa2bb0ea3830374416736dc8ec0e22f5a65092c1174c44335"}, 822 | ] 823 | strawberry-graphql = [ 824 | {file = "strawberry-graphql-0.85.1.tar.gz", hash = "sha256:2707bed7ca8b784093b05ab345f4143453467acf21ee86a768a8dfb65d12d9ab"}, 825 | {file = "strawberry_graphql-0.85.1-py3-none-any.whl", hash = "sha256:e92e4fb43beaa130cd3475b41d26fa913b7469cc624d5e53dba136c87fde7f43"}, 826 | ] 827 | toml = [ 828 | {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, 829 | {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, 830 | ] 831 | tomli = [ 832 | {file = "tomli-1.2.2-py3-none-any.whl", hash = "sha256:f04066f68f5554911363063a30b108d2b5a5b1a010aa8b6132af78489fe3aade"}, 833 | {file = "tomli-1.2.2.tar.gz", hash = "sha256:c6ce0015eb38820eaf32b5db832dbc26deb3dd427bd5f6556cf0acac2c214fee"}, 834 | ] 835 | typing-extensions = [ 836 | {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, 837 | {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, 838 | {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, 839 | ] 840 | uvicorn = [ 841 | {file = "uvicorn-0.15.0-py3-none-any.whl", hash = "sha256:17f898c64c71a2640514d4089da2689e5db1ce5d4086c2d53699bf99513421c1"}, 842 | {file = "uvicorn-0.15.0.tar.gz", hash = "sha256:d9a3c0dd1ca86728d3e235182683b4cf94cd53a867c288eaeca80ee781b2caff"}, 843 | ] 844 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jokull/python-ts-graphql-demo/52d4fb5a9bf2143c7585fadc43bbaa574e59e3db/public/favicon.ico -------------------------------------------------------------------------------- /public/panda.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "python-ts-graphql-demo" 3 | version = "0.1.0" 4 | description = "" 5 | authors = ["Jökull Sólberg Auðunsson "] 6 | 7 | [tool.poetry.dependencies] 8 | python = "^3.9" 9 | SQLAlchemy = {version = "^1.4.26", extras = ["asyncio"]} 10 | strawberry-graphql = "^0.85.1" 11 | starlette = "^0.16.0" 12 | uvicorn = "^0.15.0" 13 | aiosqlite = "^0.17.0" 14 | greenlet = "^1.1.2" 15 | 16 | [tool.poetry.dev-dependencies] 17 | black = "^21.10b0" 18 | flake8 = "^4.0.1" 19 | isort = "^5.10.0" 20 | bandit = "^1.7.0" 21 | sqlalchemy2-stubs = "^0.0.2-alpha.19" 22 | mypy = "^0.910" 23 | 24 | [build-system] 25 | requires = ["poetry-core>=1.0.0"] 26 | build-backend = "poetry.core.masonry.api" 27 | 28 | [tool.black] 29 | line-length = 99 30 | 31 | [tool.isort] 32 | profile = "black" 33 | 34 | [tool.flake8] 35 | max-line-length = 99 36 | 37 | [tool.mypy] 38 | plugins = "strawberry.ext.mypy_plugin,sqlalchemy.ext.mypy.plugin" 39 | implicit_reexport = false 40 | -------------------------------------------------------------------------------- /schema.graphql: -------------------------------------------------------------------------------- 1 | union AddLocationResponse = Task | LocationExists 2 | 3 | union AddTaskResponse = Task | LocationNotFound 4 | 5 | type Location { 6 | name: String! 7 | } 8 | 9 | type LocationExists { 10 | message: String! 11 | } 12 | 13 | type LocationNotFound { 14 | message: String! 15 | } 16 | 17 | type Mutation { 18 | addTask(name: String!, locationName: String!): AddTaskResponse! 19 | addLocation(name: String!): AddLocationResponse! 20 | } 21 | 22 | type Query { 23 | tasks: [Task!]! 24 | } 25 | 26 | type Task { 27 | name: String! 28 | location: Location 29 | } 30 | -------------------------------------------------------------------------------- /styles/globals.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | padding: 0; 4 | margin: 0; 5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 7 | } 8 | 9 | a { 10 | color: inherit; 11 | text-decoration: none; 12 | } 13 | 14 | * { 15 | box-sizing: border-box; 16 | } 17 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: ["./pages/**/*.tsx"], 3 | theme: { 4 | extend: {}, 5 | }, 6 | plugins: [], 7 | }; 8 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true 17 | }, 18 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 19 | "exclude": ["node_modules"] 20 | } 21 | --------------------------------------------------------------------------------