diff --git a/Makefile b/Makefile index 28ea5b691c..160f1c2aa2 100644 --- a/Makefile +++ b/Makefile @@ -28,9 +28,9 @@ clean: rm -f buzz/whisper_cpp.py rm -rf dist/* || true -COVERAGE_THRESHOLD := 76 +COVERAGE_THRESHOLD := 77 ifeq ($(UNAME_S),Linux) - COVERAGE_THRESHOLD := 71 + COVERAGE_THRESHOLD := 72 endif test: buzz/whisper_cpp.py translation_mo diff --git a/buzz/buzz.py b/buzz/buzz.py index e56ffeb67f..3e5b2ebc10 100644 --- a/buzz/buzz.py +++ b/buzz/buzz.py @@ -6,7 +6,7 @@ import sys from typing import TextIO -from appdirs import user_log_dir +from platformdirs import user_log_dir # Check for segfaults if not running in frozen mode if getattr(sys, "frozen", False) is False: @@ -57,7 +57,14 @@ def main(): from buzz.cli import parse_command_line from buzz.widgets.application import Application + from buzz.db.dao.transcription_dao import TranscriptionDAO + from buzz.db.dao.transcription_segment_dao import TranscriptionSegmentDAO + from buzz.db.service.transcription_service import TranscriptionService + from buzz.db.db import setup_app_db - app = Application() + db = setup_app_db() + app = Application( + TranscriptionService(TranscriptionDAO(db), TranscriptionSegmentDAO(db)) + ) parse_command_line(app) sys.exit(app.exec()) diff --git a/buzz/db/__init__.py b/buzz/db/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/buzz/db/dao/__init__.py b/buzz/db/dao/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/buzz/db/dao/dao.py b/buzz/db/dao/dao.py new file mode 100644 index 0000000000..16a6548567 --- /dev/null +++ b/buzz/db/dao/dao.py @@ -0,0 +1,53 @@ +# Adapted from https://github.com/zhiyiYo/Groove +from abc import ABC +from typing import TypeVar, Generic, Any, Type + +from PyQt6.QtSql import QSqlDatabase, QSqlQuery, QSqlRecord + +from buzz.db.entity.entity import Entity + +T = TypeVar("T", bound=Entity) + + +class DAO(ABC, Generic[T]): + entity: Type[T] + + def __init__(self, table: str, db: QSqlDatabase): + self.db = db + self.table = table + + def insert(self, record: T): + query = self._create_query() + keys = record.__dict__.keys() + query.prepare( + f""" + INSERT INTO {self.table} ({", ".join(keys)}) + VALUES ({", ".join([f":{key}" for key in keys])}) + """ + ) + for key, value in record.__dict__.items(): + query.bindValue(f":{key}", value) + if not query.exec(): + raise Exception(query.lastError().text()) + + def find_by_id(self, id: Any) -> T | None: + query = self._create_query() + query.prepare(f"SELECT * FROM {self.table} WHERE id = :id") + query.bindValue(":id", id) + return self._execute(query) + + def to_entity(self, record: QSqlRecord) -> T: + entity = self.entity() + for i in range(record.count()): + setattr(entity, record.fieldName(i), record.value(i)) + return entity + + def _execute(self, query: QSqlQuery) -> T | None: + if not query.exec(): + raise Exception(query.lastError().text()) + if not query.first(): + return None + return self.to_entity(query.record()) + + def _create_query(self): + return QSqlQuery(self.db) diff --git a/buzz/db/dao/transcription_dao.py b/buzz/db/dao/transcription_dao.py new file mode 100644 index 0000000000..c8f2ed85d5 --- /dev/null +++ b/buzz/db/dao/transcription_dao.py @@ -0,0 +1,159 @@ +from datetime import datetime +from uuid import UUID + +from PyQt6.QtSql import QSqlDatabase + +from buzz.db.dao.dao import DAO +from buzz.db.entity.transcription import Transcription +from buzz.transcriber.transcriber import FileTranscriptionTask + + +class TranscriptionDAO(DAO[Transcription]): + entity = Transcription + + def __init__(self, db: QSqlDatabase): + super().__init__("transcription", db) + + def create_transcription(self, task: FileTranscriptionTask): + query = self._create_query() + query.prepare( + """ + INSERT INTO transcription ( + id, + export_formats, + file, + output_folder, + language, + model_type, + source, + status, + task, + time_queued, + url, + whisper_model_size + ) VALUES ( + :id, + :export_formats, + :file, + :output_folder, + :language, + :model_type, + :source, + :status, + :task, + :time_queued, + :url, + :whisper_model_size + ) + """ + ) + query.bindValue(":id", str(task.uid)) + query.bindValue( + ":export_formats", + ", ".join( + [ + output_format.value + for output_format in task.file_transcription_options.output_formats + ] + ), + ) + query.bindValue(":file", task.file_path) + query.bindValue(":output_folder", task.output_directory) + query.bindValue(":language", task.transcription_options.language) + query.bindValue( + ":model_type", task.transcription_options.model.model_type.value + ) + query.bindValue(":source", task.source.value) + query.bindValue(":status", FileTranscriptionTask.Status.QUEUED.value) + query.bindValue(":task", task.transcription_options.task.value) + query.bindValue(":time_queued", datetime.now().isoformat()) + query.bindValue(":url", task.url) + query.bindValue( + ":whisper_model_size", + task.transcription_options.model.whisper_model_size.value + if task.transcription_options.model.whisper_model_size + else None, + ) + if not query.exec(): + raise Exception(query.lastError().text()) + + def update_transcription_as_started(self, id: UUID): + query = self._create_query() + query.prepare( + """ + UPDATE transcription + SET status = :status, time_started = :time_started + WHERE id = :id + """ + ) + + query.bindValue(":id", str(id)) + query.bindValue(":status", FileTranscriptionTask.Status.IN_PROGRESS.value) + query.bindValue(":time_started", datetime.now().isoformat()) + if not query.exec(): + raise Exception(query.lastError().text()) + + def update_transcription_as_failed(self, id: UUID, error: str): + query = self._create_query() + query.prepare( + """ + UPDATE transcription + SET status = :status, time_ended = :time_ended, error_message = :error_message + WHERE id = :id + """ + ) + + query.bindValue(":id", str(id)) + query.bindValue(":status", FileTranscriptionTask.Status.FAILED.value) + query.bindValue(":time_ended", datetime.now().isoformat()) + query.bindValue(":error_message", error) + if not query.exec(): + raise Exception(query.lastError().text()) + + def update_transcription_as_canceled(self, id: UUID): + query = self._create_query() + query.prepare( + """ + UPDATE transcription + SET status = :status, time_ended = :time_ended + WHERE id = :id + """ + ) + + query.bindValue(":id", str(id)) + query.bindValue(":status", FileTranscriptionTask.Status.CANCELED.value) + query.bindValue(":time_ended", datetime.now().isoformat()) + if not query.exec(): + raise Exception(query.lastError().text()) + + def update_transcription_progress(self, id: UUID, progress: float): + query = self._create_query() + query.prepare( + """ + UPDATE transcription + SET status = :status, progress = :progress + WHERE id = :id + """ + ) + + query.bindValue(":id", str(id)) + query.bindValue(":status", FileTranscriptionTask.Status.IN_PROGRESS.value) + query.bindValue(":progress", progress) + if not query.exec(): + raise Exception(query.lastError().text()) + + def update_transcription_as_completed(self, id: UUID): + query = self._create_query() + query.prepare( + """ + UPDATE transcription + SET status = :status, time_ended = :time_ended + WHERE id = :id + """ + ) + + query.bindValue(":id", str(id)) + query.bindValue(":status", FileTranscriptionTask.Status.COMPLETED.value) + query.bindValue(":time_ended", datetime.now().isoformat()) + if not query.exec(): + raise Exception(query.lastError().text()) diff --git a/buzz/db/dao/transcription_segment_dao.py b/buzz/db/dao/transcription_segment_dao.py new file mode 100644 index 0000000000..fa2c6ef562 --- /dev/null +++ b/buzz/db/dao/transcription_segment_dao.py @@ -0,0 +1,11 @@ +from PyQt6.QtSql import QSqlDatabase + +from buzz.db.dao.dao import DAO +from buzz.db.entity.transcription_segment import TranscriptionSegment + + +class TranscriptionSegmentDAO(DAO[TranscriptionSegment]): + entity = TranscriptionSegment + + def __init__(self, db: QSqlDatabase): + super().__init__("transcription_segment", db) diff --git a/buzz/db/db.py b/buzz/db/db.py new file mode 100644 index 0000000000..1e9e6ceb16 --- /dev/null +++ b/buzz/db/db.py @@ -0,0 +1,39 @@ +import logging +import os +import sqlite3 +import tempfile + +from PyQt6.QtSql import QSqlDatabase +from platformdirs import user_data_dir + +from buzz.db.helpers import ( + run_sqlite_migrations, + copy_transcriptions_from_json_to_sqlite, + mark_in_progress_and_queued_transcriptions_as_canceled, +) + +APP_DB_PATH = os.path.join(user_data_dir("Buzz"), "Buzz.sqlite") + + +def setup_app_db() -> QSqlDatabase: + return _setup_db(APP_DB_PATH) + + +def setup_test_db() -> QSqlDatabase: + return _setup_db(tempfile.mktemp()) + + +def _setup_db(path: str) -> QSqlDatabase: + # Run migrations + db = sqlite3.connect(path) + run_sqlite_migrations(db) + copy_transcriptions_from_json_to_sqlite(db) + mark_in_progress_and_queued_transcriptions_as_canceled(db) + db.close() + + db = QSqlDatabase.addDatabase("QSQLITE") + db.setDatabaseName(path) + if not db.open(): + raise RuntimeError(f"Failed to open database connection: {db.databaseName()}") + logging.debug("Database connection opened: %s", db.databaseName()) + return db diff --git a/buzz/db/entity/__init__.py b/buzz/db/entity/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/buzz/db/entity/entity.py b/buzz/db/entity/entity.py new file mode 100644 index 0000000000..9ad32f01f1 --- /dev/null +++ b/buzz/db/entity/entity.py @@ -0,0 +1,12 @@ +from abc import ABC + +from PyQt6.QtSql import QSqlRecord + + +class Entity(ABC): + @classmethod + def from_record(cls, record: QSqlRecord): + entity = cls() + for i in range(record.count()): + setattr(entity, record.fieldName(i), record.value(i)) + return entity diff --git a/buzz/db/entity/transcription.py b/buzz/db/entity/transcription.py new file mode 100644 index 0000000000..d4d3731f78 --- /dev/null +++ b/buzz/db/entity/transcription.py @@ -0,0 +1,54 @@ +import datetime +import os +import uuid +from dataclasses import dataclass, field + +from buzz.db.entity.entity import Entity +from buzz.model_loader import ModelType +from buzz.settings.settings import Settings +from buzz.transcriber.transcriber import OutputFormat, Task, FileTranscriptionTask + + +@dataclass +class Transcription(Entity): + status: str = FileTranscriptionTask.Status.QUEUED.value + task: str = Task.TRANSCRIBE.value + model_type: str = ModelType.WHISPER.value + whisper_model_size: str | None = None + language: str | None = None + id: str = field(default_factory=lambda: str(uuid.uuid4())) + error_message: str | None = None + file: str | None = None + time_queued: str = datetime.datetime.now().isoformat() + + @property + def id_as_uuid(self): + return uuid.UUID(hex=self.id) + + @property + def status_as_status(self): + return FileTranscriptionTask.Status(self.status) + + def get_output_file_path( + self, + output_format: OutputFormat, + output_directory: str | None = None, + ): + input_file_name = os.path.splitext(os.path.basename(self.file))[0] + + date_time_now = datetime.datetime.now().strftime("%d-%b-%Y %H-%M-%S") + + export_file_name_template = Settings().get_default_export_file_template() + + output_file_name = ( + export_file_name_template.replace("{{ input_file_name }}", input_file_name) + .replace("{{ task }}", self.task) + .replace("{{ language }}", self.language or "") + .replace("{{ model_type }}", self.model_type) + .replace("{{ model_size }}", self.whisper_model_size or "") + .replace("{{ date_time }}", date_time_now) + + f".{output_format.value}" + ) + + output_directory = output_directory or os.path.dirname(self.file) + return os.path.join(output_directory, output_file_name) diff --git a/buzz/db/entity/transcription_segment.py b/buzz/db/entity/transcription_segment.py new file mode 100644 index 0000000000..539ee46e3b --- /dev/null +++ b/buzz/db/entity/transcription_segment.py @@ -0,0 +1,11 @@ +from dataclasses import dataclass + +from buzz.db.entity.entity import Entity + + +@dataclass +class TranscriptionSegment(Entity): + start_time: int + end_time: int + text: str + transcription_id: str diff --git a/buzz/db/helpers.py b/buzz/db/helpers.py new file mode 100644 index 0000000000..59842c3fff --- /dev/null +++ b/buzz/db/helpers.py @@ -0,0 +1,84 @@ +import os +from datetime import datetime +from sqlite3 import Connection + +from buzz.cache import TasksCache +from buzz.db.migrator import dumb_migrate_db + + +def copy_transcriptions_from_json_to_sqlite(conn: Connection): + cache = TasksCache() + if os.path.exists(cache.tasks_list_file_path): + tasks = cache.load() + cursor = conn.cursor() + for task in tasks: + cursor.execute( + """ + INSERT INTO transcription (id, error_message, export_formats, file, output_folder, progress, language, model_type, source, status, task, time_ended, time_queued, time_started, url, whisper_model_size) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + RETURNING id; + """, + ( + str(task.uid), + task.error, + ", ".join( + [ + format.value + for format in task.file_transcription_options.output_formats + ] + ), + task.file_path, + task.output_directory, + task.fraction_completed, + task.transcription_options.language, + task.transcription_options.model.model_type.value, + task.source.value, + task.status.value, + task.transcription_options.task.value, + task.completed_at, + task.queued_at, + task.started_at, + task.url, + task.transcription_options.model.whisper_model_size.value + if task.transcription_options.model.whisper_model_size + else None, + ), + ) + transcription_id = cursor.fetchone()[0] + + for segment in task.segments: + cursor.execute( + """ + INSERT INTO transcription_segment (end_time, start_time, text, transcription_id) + VALUES (?, ?, ?, ?); + """, + ( + segment.end, + segment.start, + segment.text, + transcription_id, + ), + ) + # os.remove(cache.tasks_list_file_path) + conn.commit() + + +def run_sqlite_migrations(db: Connection): + schema_path = os.path.join(os.path.dirname(__file__), "schema.sql") + + with open(schema_path) as schema_file: + schema = schema_file.read() + dumb_migrate_db(db=db, schema=schema) + + +def mark_in_progress_and_queued_transcriptions_as_canceled(conn: Connection): + cursor = conn.cursor() + cursor.execute( + """ + UPDATE transcription + SET status = 'canceled', time_ended = ? + WHERE status = 'in_progress' OR status = 'queued'; + """, + (datetime.now().isoformat(),), + ) + conn.commit() diff --git a/buzz/db/migrator.py b/buzz/db/migrator.py new file mode 100644 index 0000000000..0fa6b0438f --- /dev/null +++ b/buzz/db/migrator.py @@ -0,0 +1,284 @@ +# coding: utf-8 +# https://gist.github.com/simonw/664b4b0851c1899dc55e1fb655181037 + +"""Simple declarative schema migration for SQLite. +See . +Author: William Manley . +Copyright © 2019-2022 Stb-tester.com Ltd. +License: MIT. +""" + +import logging +import re +import sqlite3 +from textwrap import dedent + + +def dumb_migrate_db(db, schema, allow_deletions=False): + """ + Migrates a database to the new schema given by the SQL text `schema` + preserving the data. We create any table that exists in schema, delete any + old table that is no longer used and add/remove columns and indices as + necessary. + Under this scheme there are a set of changes that we can make to the schema + and this script will handle it fine: + 1. Adding a new table + 2. Adding, deleting or modifying an index + 3. Adding a column to an existing table as long as the new column can be + NULL or has a DEFAULT value specified. + 4. Changing a column to remove NULL or DEFAULT as long as all values in the + database are not NULL + 5. Changing the type of a column + 6. Changing the user_version + In addition this function is capable of: + 1. Deleting tables + 2. Deleting columns from tables + But only if allow_deletions=True. If the new schema requires a column/table + to be deleted and allow_deletions=False this function will raise + `RuntimeError`. + Note: When this function is called a transaction must not be held open on + db. A transaction will be used internally. If you wish to perform + additional migration steps as part of a migration use DBMigrator directly. + Any internally generated rowid columns by SQLite may change values by this + migration. + """ + with DBMigrator(db, schema, allow_deletions) as migrator: + migrator.migrate() + return bool(migrator.n_changes) + + +class DBMigrator: + def __init__(self, db, schema, allow_deletions=False): + self.db = db + self.schema = schema + self.allow_deletions = allow_deletions + + self.pristine = sqlite3.connect(":memory:") + self.pristine.executescript(schema) + self.n_changes = 0 + + self.orig_foreign_keys = None + + def log_execute(self, msg, sql, args=None): + # It's important to log any changes we're making to the database for + # forensics later + msg_tmpl = "Database migration: %s with SQL:\n%s" + msg_argv = (msg, _left_pad(dedent(sql))) + if args: + msg_tmpl += " args = %r" + msg_argv += (args,) + else: + args = [] + logging.info(msg_tmpl, *msg_argv) + self.db.execute(sql, args) + self.n_changes += 1 + + def __enter__(self): + self.orig_foreign_keys = self.db.execute("PRAGMA foreign_keys").fetchone()[0] + if self.orig_foreign_keys: + self.log_execute( + "Disable foreign keys temporarily for migration", + "PRAGMA foreign_keys = OFF", + ) + # This doesn't count as a change because we'll undo it at the end + self.n_changes = 0 + + self.db.__enter__() + self.db.execute("BEGIN") + return self + + def __exit__(self, exc_type, exc_value, exc_tb): + self.db.__exit__(exc_type, exc_value, exc_tb) + if exc_value is None: + # The SQLite docs say: + # + # > This pragma is a no-op within a transaction; foreign key + # > constraint enforcement may only be enabled or disabled when + # > there is no pending BEGIN or SAVEPOINT. + old_changes = self.n_changes + new_val = self._migrate_pragma("foreign_keys") + if new_val == self.orig_foreign_keys: + self.n_changes = old_changes + + # SQLite docs say: + # + # > A VACUUM will fail if there is an open transaction on the database + # > connection that is attempting to run the VACUUM. + if self.n_changes: + self.db.execute("VACUUM") + else: + if self.orig_foreign_keys: + self.log_execute( + "Re-enable foreign keys after migration", "PRAGMA foreign_keys = ON" + ) + + def migrate(self): + # In CI the database schema may be changing all the time. This checks + # the current db and if it doesn't match database.sql we will + # modify it so it does match where possible. + pristine_tables = dict( + self.pristine.execute( + """\ + SELECT name, sql FROM sqlite_master + WHERE type = \"table\" AND name != \"sqlite_sequence\"""" + ).fetchall() + ) + pristine_indices = dict( + self.pristine.execute( + """\ + SELECT name, sql FROM sqlite_master + WHERE type = \"index\"""" + ).fetchall() + ) + + tables = dict( + self.db.execute( + """\ + SELECT name, sql FROM sqlite_master + WHERE type = \"table\" AND name != \"sqlite_sequence\"""" + ).fetchall() + ) + + new_tables = set(pristine_tables.keys()) - set(tables.keys()) + removed_tables = set(tables.keys()) - set(pristine_tables.keys()) + if removed_tables and not self.allow_deletions: + raise RuntimeError( + "Database migration: Refusing to delete tables %r" % removed_tables + ) + + modified_tables = set( + name + for name, sql in pristine_tables.items() + if normalise_sql(tables.get(name, "")) != normalise_sql(sql) + ) + + # This PRAGMA is automatically disabled when the db is committed + self.db.execute("PRAGMA defer_foreign_keys = TRUE") + + # New and removed tables are easy: + for tbl_name in new_tables: + self.log_execute("Create table %s" % tbl_name, pristine_tables[tbl_name]) + for tbl_name in removed_tables: + self.log_execute("Drop table %s" % tbl_name, "DROP TABLE %s" % tbl_name) + + for tbl_name in modified_tables: + # The SQLite documentation insists that we create the new table and + # rename it over the old rather than moving the old out of the way + # and then creating the new + create_table_sql = pristine_tables[tbl_name] + create_table_sql = re.sub( + r"\b%s\b" % re.escape(tbl_name), + tbl_name + "_migration_new", + create_table_sql, + ) + self.log_execute( + "Columns change: Create table %s with updated schema" % tbl_name, + create_table_sql, + ) + + cols = set( + [x[1] for x in self.db.execute("PRAGMA table_info(%s)" % tbl_name)] + ) + pristine_cols = set( + [ + x[1] + for x in self.pristine.execute("PRAGMA table_info(%s)" % tbl_name) + ] + ) + + removed_columns = cols - pristine_cols + if not self.allow_deletions and removed_columns: + logging.warning( + "Database migration: Refusing to remove columns %r from " + "table %s. Current cols are %r attempting migration to %r", + removed_columns, + tbl_name, + cols, + pristine_cols, + ) + raise RuntimeError( + "Database migration: Refusing to remove columns %r from " + "table %s" % (removed_columns, tbl_name) + ) + + logging.info("cols: %s, pristine_cols: %s", cols, pristine_cols) + self.log_execute( + "Migrate data for table %s" % tbl_name, + """\ + INSERT INTO {tbl_name}_migration_new ({common}) + SELECT {common} FROM {tbl_name}""".format( + tbl_name=tbl_name, + common=", ".join(cols.intersection(pristine_cols)), + ), + ) + + # Don't need the old table any more + self.log_execute( + "Drop old table %s now data has been migrated" % tbl_name, + "DROP TABLE %s" % tbl_name, + ) + + self.log_execute( + "Columns change: Move new table %s over old" % tbl_name, + "ALTER TABLE %s_migration_new RENAME TO %s" % (tbl_name, tbl_name), + ) + + # Migrate the indices + indices = dict( + self.db.execute( + """\ + SELECT name, sql FROM sqlite_master + WHERE type = \"index\"""" + ).fetchall() + ) + for name in set(indices.keys()) - set(pristine_indices.keys()): + self.log_execute( + "Dropping obsolete index %s" % name, "DROP INDEX %s" % name + ) + for name, sql in pristine_indices.items(): + if name not in indices: + self.log_execute("Creating new index %s" % name, sql) + elif sql != indices[name]: + self.log_execute( + "Index %s changed: Dropping old version" % name, + "DROP INDEX %s" % name, + ) + self.log_execute( + "Index %s changed: Creating updated version in its place" % name, + sql, + ) + + self._migrate_pragma("user_version") + + if self.pristine.execute("PRAGMA foreign_keys").fetchone()[0]: + if self.db.execute("PRAGMA foreign_key_check").fetchall(): + raise RuntimeError("Database migration: Would fail foreign_key_check") + + def _migrate_pragma(self, pragma): + pristine_val = self.pristine.execute("PRAGMA %s" % pragma).fetchone()[0] + val = self.db.execute("PRAGMA %s" % pragma).fetchone()[0] + + if val != pristine_val: + self.log_execute( + "Set %s to %i from %i" % (pragma, pristine_val, val), + "PRAGMA %s = %i" % (pragma, pristine_val), + ) + + return pristine_val + + +def _left_pad(text, indent=" "): + """Maybe I can find a package in pypi for this?""" + return "\n".join(indent + line for line in text.split("\n")) + + +def normalise_sql(sql): + # Remove comments: + sql = re.sub(r"--[^\n]*\n", "", sql) + # Normalise whitespace: + sql = re.sub(r"\s+", " ", sql) + sql = re.sub(r" *([(),]) *", r"\1", sql) + # Remove unnecessary quotes + sql = re.sub(r'"(\w+)"', r"\1", sql) + + return sql.strip() diff --git a/buzz/db/schema.sql b/buzz/db/schema.sql new file mode 100644 index 0000000000..7bac73e6ec --- /dev/null +++ b/buzz/db/schema.sql @@ -0,0 +1,28 @@ +CREATE TABLE transcription ( + id TEXT PRIMARY KEY, + error_message TEXT, + export_formats TEXT, + file TEXT, + output_folder TEXT, + progress DOUBLE PRECISION DEFAULT 0.0, + language TEXT, + model_type TEXT, + source TEXT, + status TEXT, + task TEXT, + time_ended TIMESTAMP, + time_queued TIMESTAMP NOT NULL, + time_started TIMESTAMP, + url TEXT, + whisper_model_size TEXT +); + +CREATE TABLE transcription_segment ( + id INTEGER PRIMARY KEY, + end_time INT DEFAULT 0, + start_time INT DEFAULT 0, + text TEXT NOT NULL, + transcription_id TEXT, + FOREIGN KEY (transcription_id) REFERENCES transcription(id) ON DELETE CASCADE +); +CREATE INDEX idx_transcription_id ON transcription_segment(transcription_id); diff --git a/buzz/db/service/__init__.py b/buzz/db/service/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/buzz/db/service/transcription_service.py b/buzz/db/service/transcription_service.py new file mode 100644 index 0000000000..0b9c90cf89 --- /dev/null +++ b/buzz/db/service/transcription_service.py @@ -0,0 +1,44 @@ +from typing import List +from uuid import UUID + +from buzz.db.dao.transcription_dao import TranscriptionDAO +from buzz.db.dao.transcription_segment_dao import TranscriptionSegmentDAO +from buzz.db.entity.transcription_segment import TranscriptionSegment +from buzz.transcriber.transcriber import Segment + + +class TranscriptionService: + def __init__( + self, + transcription_dao: TranscriptionDAO, + transcription_segment_dao: TranscriptionSegmentDAO, + ): + self.transcription_dao = transcription_dao + self.transcription_segment_dao = transcription_segment_dao + + def create_transcription(self, task): + self.transcription_dao.create_transcription(task) + + def update_transcription_as_started(self, id: UUID): + self.transcription_dao.update_transcription_as_started(id) + + def update_transcription_as_failed(self, id: UUID, error: str): + self.transcription_dao.update_transcription_as_failed(id, error) + + def update_transcription_as_canceled(self, id: UUID): + self.transcription_dao.update_transcription_as_canceled(id) + + def update_transcription_progress(self, id: UUID, progress: float): + self.transcription_dao.update_transcription_progress(id, progress) + + def update_transcription_as_completed(self, id: UUID, segments: List[Segment]): + self.transcription_dao.update_transcription_as_completed(id) + for segment in segments: + self.transcription_segment_dao.insert( + TranscriptionSegment( + start_time=segment.start, + end_time=segment.end, + text=segment.text, + transcription_id=str(id), + ) + ) diff --git a/buzz/file_transcriber_queue_worker.py b/buzz/file_transcriber_queue_worker.py index c18c7f973e..03ac37c6f1 100644 --- a/buzz/file_transcriber_queue_worker.py +++ b/buzz/file_transcriber_queue_worker.py @@ -1,8 +1,8 @@ -import datetime import logging import multiprocessing import queue -from typing import Optional, Tuple, List +from typing import Optional, Tuple, List, Set +from uuid import UUID from PyQt6.QtCore import QObject, QThread, pyqtSignal, pyqtSlot @@ -21,13 +21,19 @@ class FileTranscriberQueueWorker(QObject): current_task: Optional[FileTranscriptionTask] = None current_transcriber: Optional[FileTranscriber] = None current_transcriber_thread: Optional[QThread] = None - task_updated = pyqtSignal(FileTranscriptionTask) + + task_started = pyqtSignal(FileTranscriptionTask) + task_progress = pyqtSignal(FileTranscriptionTask, float) + task_download_progress = pyqtSignal(FileTranscriptionTask, float) + task_completed = pyqtSignal(FileTranscriptionTask, list) + task_error = pyqtSignal(FileTranscriptionTask, str) + completed = pyqtSignal() def __init__(self, parent: Optional[QObject] = None): super().__init__(parent) self.tasks_queue = queue.Queue() - self.canceled_tasks = set() + self.canceled_tasks: Set[UUID] = set() @pyqtSlot() def run(self): @@ -42,7 +48,7 @@ def run(self): self.completed.emit() return - if self.current_task.id in self.canceled_tasks: + if self.current_task.uid in self.canceled_tasks: continue break @@ -91,53 +97,41 @@ def run(self): self.current_transcriber.error.connect(self.run) self.current_transcriber.completed.connect(self.run) - self.current_task.started_at = datetime.datetime.now() + self.task_started.emit(self.current_task) self.current_transcriber_thread.start() def add_task(self, task: FileTranscriptionTask): - if task.queued_at is None: - task.queued_at = datetime.datetime.now() - self.tasks_queue.put(task) - task.status = FileTranscriptionTask.Status.QUEUED - self.task_updated.emit(task) - def cancel_task(self, task_id: int): + def cancel_task(self, task_id: UUID): self.canceled_tasks.add(task_id) - if self.current_task.id == task_id: + if self.current_task.uid == task_id: if self.current_transcriber is not None: self.current_transcriber.stop() def on_task_error(self, error: str): if ( self.current_task is not None - and self.current_task.id not in self.canceled_tasks + and self.current_task.uid not in self.canceled_tasks ): self.current_task.status = FileTranscriptionTask.Status.FAILED self.current_task.error = error - self.task_updated.emit(self.current_task) + self.task_error.emit(self.current_task, error) @pyqtSlot(tuple) def on_task_progress(self, progress: Tuple[int, int]): if self.current_task is not None: - self.current_task.status = FileTranscriptionTask.Status.IN_PROGRESS - self.current_task.fraction_completed = progress[0] / progress[1] - self.task_updated.emit(self.current_task) + self.task_progress.emit(self.current_task, progress[0] / progress[1]) def on_task_download_progress(self, fraction_downloaded: float): if self.current_task is not None: - self.current_task.status = FileTranscriptionTask.Status.IN_PROGRESS - self.current_task.fraction_downloaded = fraction_downloaded - self.task_updated.emit(self.current_task) + self.task_download_progress.emit(self.current_task, fraction_downloaded) @pyqtSlot(list) def on_task_completed(self, segments: List[Segment]): if self.current_task is not None: - self.current_task.status = FileTranscriptionTask.Status.COMPLETED - self.current_task.segments = segments - self.current_task.completed_at = datetime.datetime.now() - self.task_updated.emit(self.current_task) + self.task_completed.emit(self.current_task, segments) def stop(self): self.tasks_queue.put(None) diff --git a/buzz/transcriber/file_transcriber.py b/buzz/transcriber/file_transcriber.py index aef7ce4bc4..c9e8c86754 100644 --- a/buzz/transcriber/file_transcriber.py +++ b/buzz/transcriber/file_transcriber.py @@ -68,7 +68,12 @@ def run(self): output_format ) in self.transcription_task.file_transcription_options.output_formats: default_path = get_output_file_path( - task=self.transcription_task, output_format=output_format + file_path=self.transcription_task.file_path, + output_format=output_format, + language=self.transcription_task.transcription_options.language, + output_directory=self.transcription_task.output_directory, + model=self.transcription_task.transcription_options.model, + task=self.transcription_task.transcription_options.task, ) write_output( diff --git a/buzz/transcriber/transcriber.py b/buzz/transcriber/transcriber.py index ae3e1b9f2c..e8cb190f3c 100644 --- a/buzz/transcriber/transcriber.py +++ b/buzz/transcriber/transcriber.py @@ -1,6 +1,7 @@ import datetime import enum import os +import uuid from dataclasses import dataclass, field from random import randint from typing import List, Optional, Tuple, Set @@ -174,7 +175,9 @@ class Source(enum.Enum): transcription_options: TranscriptionOptions file_transcription_options: FileTranscriptionOptions model_path: str + # deprecated: use uid id: int = field(default_factory=lambda: randint(0, 100_000_000)) + uid: uuid.UUID = field(default_factory=uuid.uuid4) segments: List[Segment] = field(default_factory=list) status: Optional[Status] = None fraction_completed = 0.0 @@ -188,38 +191,6 @@ class Source(enum.Enum): url: Optional[str] = None fraction_downloaded: float = 0.0 - def status_text(self) -> str: - match self.status: - case FileTranscriptionTask.Status.IN_PROGRESS: - if self.fraction_downloaded > 0 and self.fraction_completed == 0: - return f'{_("Downloading")} ({self.fraction_downloaded :.0%})' - return f'{_("In Progress")} ({self.fraction_completed :.0%})' - case FileTranscriptionTask.Status.COMPLETED: - status = _("Completed") - if self.started_at is not None and self.completed_at is not None: - status += f" ({self.format_timedelta(self.completed_at - self.started_at)})" - return status - case FileTranscriptionTask.Status.FAILED: - return f'{_("Failed")} ({self.error})' - case FileTranscriptionTask.Status.CANCELED: - return _("Canceled") - case FileTranscriptionTask.Status.QUEUED: - return _("Queued") - case _: - return "" - - @staticmethod - def format_timedelta(delta: datetime.timedelta): - mm, ss = divmod(delta.seconds, 60) - result = f"{ss}s" - if mm == 0: - return result - hh, mm = divmod(mm, 60) - result = f"{mm}m {result}" - if hh == 0: - return result - return f"{hh}h {result}" - class OutputFormat(enum.Enum): TXT = "txt" @@ -236,11 +207,15 @@ class Stopped(Exception): def get_output_file_path( - task: FileTranscriptionTask, + file_path: str, + task: Task, + language: Optional[str], + model: TranscriptionModel, output_format: OutputFormat, + output_directory: str | None = None, export_file_name_template: str | None = None, ): - input_file_name = os.path.splitext(os.path.basename(task.file_path))[0] + input_file_name = os.path.splitext(os.path.basename(file_path))[0] date_time_now = datetime.datetime.now().strftime("%d-%b-%Y %H-%M-%S") export_file_name_template = ( @@ -251,18 +226,18 @@ def get_output_file_path( output_file_name = ( export_file_name_template.replace("{{ input_file_name }}", input_file_name) - .replace("{{ task }}", task.transcription_options.task.value) - .replace("{{ language }}", task.transcription_options.language or "") - .replace("{{ model_type }}", task.transcription_options.model.model_type.value) + .replace("{{ task }}", task.value) + .replace("{{ language }}", language or "") + .replace("{{ model_type }}", model.model_type.value) .replace( "{{ model_size }}", - task.transcription_options.model.whisper_model_size.value - if task.transcription_options.model.whisper_model_size is not None + model.whisper_model_size.value + if model.whisper_model_size is not None else "", ) .replace("{{ date_time }}", date_time_now) + f".{output_format.value}" ) - output_directory = task.output_directory or os.path.dirname(task.file_path) + output_directory = output_directory or os.path.dirname(file_path) return os.path.join(output_directory, output_file_name) diff --git a/buzz/widgets/application.py b/buzz/widgets/application.py index 80ba3b0506..3b9525eb2e 100644 --- a/buzz/widgets/application.py +++ b/buzz/widgets/application.py @@ -3,6 +3,7 @@ from PyQt6.QtWidgets import QApplication from buzz.__version__ import VERSION +from buzz.db.service.transcription_service import TranscriptionService from buzz.settings.settings import APP_NAME from buzz.transcriber.transcriber import FileTranscriptionTask from buzz.widgets.main_window import MainWindow @@ -11,7 +12,7 @@ class Application(QApplication): window: MainWindow - def __init__(self) -> None: + def __init__(self, transcription_service: TranscriptionService) -> None: super().__init__(sys.argv) self.setApplicationName(APP_NAME) @@ -20,7 +21,7 @@ def __init__(self) -> None: if sys.platform == "darwin": self.setStyle("Fusion") - self.window = MainWindow() + self.window = MainWindow(transcription_service) self.window.show() def add_task(self, task: FileTranscriptionTask): diff --git a/buzz/widgets/main_window.py b/buzz/widgets/main_window.py index 1f20e51241..34fd2d4ce1 100644 --- a/buzz/widgets/main_window.py +++ b/buzz/widgets/main_window.py @@ -1,4 +1,5 @@ -from typing import Dict, Tuple, List, Optional +import logging +from typing import Tuple, List, Optional from PyQt6 import QtGui from PyQt6.QtCore import ( @@ -13,7 +14,8 @@ QFileDialog, ) -from buzz.cache import TasksCache +from buzz.db.entity.transcription import Transcription +from buzz.db.service.transcription_service import TranscriptionService from buzz.file_transcriber_queue_worker import FileTranscriberQueueWorker from buzz.locale import _ from buzz.settings.settings import APP_NAME, Settings @@ -24,6 +26,7 @@ TranscriptionOptions, FileTranscriptionOptions, SUPPORTED_AUDIO_FORMATS, + Segment, ) from buzz.widgets.icon import BUZZ_ICON_PATH from buzz.widgets.import_url_dialog import ImportURLDialog @@ -34,7 +37,9 @@ from buzz.widgets.transcription_task_folder_watcher import ( TranscriptionTaskFolderWatcher, ) -from buzz.widgets.transcription_tasks_table_widget import TranscriptionTasksTableWidget +from buzz.widgets.transcription_tasks_table_widget import ( + TranscriptionTasksTableWidget, +) from buzz.widgets.transcription_viewer.transcription_viewer_widget import ( TranscriptionViewerWidget, ) @@ -42,9 +47,8 @@ class MainWindow(QMainWindow): table_widget: TranscriptionTasksTableWidget - tasks: Dict[int, "FileTranscriptionTask"] - def __init__(self, tasks_cache=TasksCache()): + def __init__(self, transcription_service: TranscriptionService): super().__init__(flags=Qt.WindowType.Window) self.setWindowTitle(APP_NAME) @@ -53,14 +57,12 @@ def __init__(self, tasks_cache=TasksCache()): self.setAcceptDrops(True) - self.tasks_cache = tasks_cache - self.settings = Settings() self.shortcut_settings = ShortcutSettings(settings=self.settings) self.shortcuts = self.shortcut_settings.load() - self.tasks = {} + self.transcription_service = transcription_service self.toolbar = MainWindowToolbar(shortcuts=self.shortcuts, parent=self) self.toolbar.new_transcription_action_triggered.connect( @@ -100,7 +102,9 @@ def __init__(self, tasks_cache=TasksCache()): self.table_widget = TranscriptionTasksTableWidget(self) self.table_widget.doubleClicked.connect(self.on_table_double_clicked) self.table_widget.return_clicked.connect(self.open_transcript_viewer) - self.table_widget.itemSelectionChanged.connect(self.on_table_selection_changed) + self.table_widget.selectionModel().selectionChanged.connect( + self.on_table_selection_changed + ) self.setCentralWidget(self.table_widget) @@ -110,19 +114,24 @@ def __init__(self, tasks_cache=TasksCache()): self.transcriber_worker = FileTranscriberQueueWorker() self.transcriber_worker.moveToThread(self.transcriber_thread) - self.transcriber_worker.task_updated.connect(self.update_task_table_row) + self.transcriber_worker.task_started.connect(self.on_task_started) + self.transcriber_worker.task_progress.connect(self.on_task_progress) + self.transcriber_worker.task_download_progress.connect( + self.on_task_download_progress + ) + self.transcriber_worker.task_error.connect(self.on_task_error) + self.transcriber_worker.task_completed.connect(self.on_task_completed) + self.transcriber_worker.completed.connect(self.transcriber_thread.quit) self.transcriber_thread.started.connect(self.transcriber_worker.run) self.transcriber_thread.start() - self.load_tasks_from_cache() - self.load_geometry() self.folder_watcher = TranscriptionTaskFolderWatcher( - tasks=self.tasks, + tasks={}, preferences=self.preferences.folder_watch, ) self.folder_watcher.task_found.connect(self.add_task) @@ -181,21 +190,6 @@ def on_file_transcriber_triggered( ) self.add_task(task) - def upsert_task_in_table(self, task: FileTranscriptionTask): - self.table_widget.upsert_task(task) - self.tasks[task.id] = task - - def update_task_table_row(self, task: FileTranscriptionTask): - self.upsert_task_in_table(task=task) - self.on_tasks_changed() - - @staticmethod - def task_completed_or_errored(task: FileTranscriptionTask): - return ( - task.status == FileTranscriptionTask.Status.COMPLETED - or task.status == FileTranscriptionTask.Status.FAILED - ) - def on_clear_history_action_triggered(self): selected_rows = self.table_widget.selectionModel().selectedRows() if len(selected_rows) == 0: @@ -210,25 +204,18 @@ def on_clear_history_action_triggered(self): ), ) if reply == QMessageBox.StandardButton.Yes: - task_ids = [ - TranscriptionTasksTableWidget.find_task_id(selected_row) - for selected_row in selected_rows - ] - for task_id in task_ids: - self.table_widget.clear_task(task_id) - self.tasks.pop(task_id) - self.on_tasks_changed() + self.table_widget.delete_transcriptions(selected_rows) def on_stop_transcription_action_triggered(self): - selected_rows = self.table_widget.selectionModel().selectedRows() - for selected_row in selected_rows: - task_id = TranscriptionTasksTableWidget.find_task_id(selected_row) - task = self.tasks[task_id] - - task.status = FileTranscriptionTask.Status.CANCELED - self.on_tasks_changed() - self.transcriber_worker.cancel_task(task_id) - self.table_widget.upsert_task(task) + selected_transcriptions = self.table_widget.selected_transcriptions() + for transcription in selected_transcriptions: + transcription_id = transcription.id_as_uuid + self.transcriber_worker.cancel_task(transcription_id) + self.transcription_service.update_transcription_as_canceled( + transcription_id + ) + self.table_widget.refresh_row(transcription_id) + self.on_table_selection_changed() def on_new_transcription_action_triggered(self): (file_paths, __) = QFileDialog.getOpenFileNames( @@ -266,8 +253,8 @@ def on_openai_access_token_changed(access_token: str): def open_transcript_viewer(self): selected_rows = self.table_widget.selectionModel().selectedRows() for selected_row in selected_rows: - task_id = TranscriptionTasksTableWidget.find_task_id(selected_row) - self.open_transcription_viewer(task_id) + transcription = self.table_widget.transcription(selected_row) + self.open_transcription_viewer(transcription) def on_table_selection_changed(self): self.toolbar.set_open_transcript_action_enabled( @@ -281,7 +268,20 @@ def on_table_selection_changed(self): ) def should_enable_open_transcript_action(self): - return self.selected_tasks_have_status([FileTranscriptionTask.Status.COMPLETED]) + selected_transcriptions = self.table_widget.selected_transcriptions() + if len(selected_transcriptions) == 0: + return False + return all( + MainWindow.can_open_transcript(transcription) + for transcription in selected_transcriptions + ) + + @staticmethod + def can_open_transcript(transcription: Transcription) -> bool: + return ( + FileTranscriptionTask.Status(transcription.status) + == FileTranscriptionTask.Status.COMPLETED + ) def should_enable_stop_transcription_action(self): return self.selected_tasks_have_status( @@ -301,63 +301,56 @@ def should_enable_clear_history_action(self): ) def selected_tasks_have_status(self, statuses: List[FileTranscriptionTask.Status]): - selected_rows = self.table_widget.selectionModel().selectedRows() - if len(selected_rows) == 0: + transcriptions = self.table_widget.selected_transcriptions() + if len(transcriptions) == 0: return False + return all( [ - self.tasks[ - TranscriptionTasksTableWidget.find_task_id(selected_row) - ].status - in statuses - for selected_row in selected_rows + transcription.status_as_status in statuses + for transcription in transcriptions ] ) def on_table_double_clicked(self, index: QModelIndex): - task_id = TranscriptionTasksTableWidget.find_task_id(index) - self.open_transcription_viewer(task_id) - - def open_transcription_viewer(self, task_id: int): - task = self.tasks[task_id] - if task.status != FileTranscriptionTask.Status.COMPLETED: + transcription = self.table_widget.transcription(index) + if not MainWindow.can_open_transcript(transcription): return + self.open_transcription_viewer(transcription) + def open_transcription_viewer(self, transcription: Transcription): transcription_viewer_widget = TranscriptionViewerWidget( - transcription_task=task, parent=self, flags=Qt.WindowType.Window + transcription=transcription, parent=self, flags=Qt.WindowType.Window ) - transcription_viewer_widget.task_changed.connect(self.on_tasks_changed) transcription_viewer_widget.show() def add_task(self, task: FileTranscriptionTask): + self.transcription_service.create_transcription(task) + self.table_widget.refresh_all() self.transcriber_worker.add_task(task) - def load_tasks_from_cache(self): - tasks = self.tasks_cache.load() - for task in tasks: - if ( - task.status == FileTranscriptionTask.Status.QUEUED - or task.status == FileTranscriptionTask.Status.IN_PROGRESS - ): - task.status = None - self.add_task(task) - else: - self.upsert_task_in_table(task=task) + def on_task_started(self, task: FileTranscriptionTask): + self.transcription_service.update_transcription_as_started(task.uid) + self.table_widget.refresh_row(task.uid) - def save_tasks_to_cache(self): - self.tasks_cache.save(list(self.tasks.values())) + def on_task_progress(self, task: FileTranscriptionTask, progress: float): + self.transcription_service.update_transcription_progress(task.uid, progress) + self.table_widget.refresh_row(task.uid) - def on_tasks_changed(self): - self.toolbar.set_open_transcript_action_enabled( - self.should_enable_open_transcript_action() - ) - self.toolbar.set_stop_transcription_action_enabled( - self.should_enable_stop_transcription_action() - ) - self.toolbar.set_clear_history_action_enabled( - self.should_enable_clear_history_action() - ) - self.save_tasks_to_cache() + def on_task_download_progress( + self, task: FileTranscriptionTask, fraction_downloaded: float + ): + # TODO: Save download progress in the database + pass + + def on_task_completed(self, task: FileTranscriptionTask, segments: List[Segment]): + self.transcription_service.update_transcription_as_completed(task.uid, segments) + self.table_widget.refresh_row(task.uid) + + def on_task_error(self, task: FileTranscriptionTask, error: str): + logging.debug("FAILED!!!!") + self.transcription_service.update_transcription_as_failed(task.uid, error) + self.table_widget.refresh_row(task.uid) def on_shortcuts_changed(self, shortcuts: dict): self.shortcuts = shortcuts @@ -374,7 +367,6 @@ def closeEvent(self, event: QtGui.QCloseEvent) -> None: self.transcriber_worker.stop() self.transcriber_thread.quit() self.transcriber_thread.wait() - self.save_tasks_to_cache() self.shortcut_settings.save(shortcuts=self.shortcuts) super().closeEvent(event) diff --git a/buzz/widgets/record_delegate.py b/buzz/widgets/record_delegate.py new file mode 100644 index 0000000000..4a021dd51e --- /dev/null +++ b/buzz/widgets/record_delegate.py @@ -0,0 +1,15 @@ +from typing import Callable + +from PyQt6.QtSql import QSqlRecord, QSqlTableModel +from PyQt6.QtWidgets import QStyledItemDelegate + + +class RecordDelegate(QStyledItemDelegate): + def __init__(self, text_getter: Callable[[QSqlRecord], str]): + super().__init__() + self.callback = text_getter + + def initStyleOption(self, option, index): + super().initStyleOption(option, index) + model: QSqlTableModel = index.model() + option.text = self.callback(model.record(index.row())) diff --git a/buzz/widgets/transcription_record.py b/buzz/widgets/transcription_record.py new file mode 100644 index 0000000000..bfa3c4ae02 --- /dev/null +++ b/buzz/widgets/transcription_record.py @@ -0,0 +1,25 @@ +from uuid import UUID + +from PyQt6.QtSql import QSqlRecord + +from buzz.model_loader import TranscriptionModel, ModelType, WhisperModelSize +from buzz.transcriber.transcriber import Task + + +class TranscriptionRecord: + @staticmethod + def id(record: QSqlRecord) -> UUID: + return UUID(hex=record.value("id")) + + @staticmethod + def model(record: QSqlRecord) -> TranscriptionModel: + return TranscriptionModel( + model_type=ModelType(record.value("model_type")), + whisper_model_size=WhisperModelSize(record.value("whisper_model_size")) + if record.value("whisper_model_size") + else None, + ) + + @staticmethod + def task(record: QSqlRecord) -> Task: + return Task(record.value("task")) diff --git a/buzz/widgets/transcription_task_folder_watcher.py b/buzz/widgets/transcription_task_folder_watcher.py index dffb6f7070..d230db0ac4 100644 --- a/buzz/widgets/transcription_task_folder_watcher.py +++ b/buzz/widgets/transcription_task_folder_watcher.py @@ -15,6 +15,7 @@ class TranscriptionTaskFolderWatcher(QFileSystemWatcher): preferences: FolderWatchPreferences task_found = pyqtSignal(FileTranscriptionTask) + # TODO: query db instead of passing tasks def __init__( self, tasks: Dict[int, FileTranscriptionTask], diff --git a/buzz/widgets/transcription_tasks_table_widget.py b/buzz/widgets/transcription_tasks_table_widget.py index b069a0850f..e9b506397a 100644 --- a/buzz/widgets/transcription_tasks_table_widget.py +++ b/buzz/widgets/transcription_tasks_table_widget.py @@ -1,147 +1,203 @@ import enum import os from dataclasses import dataclass +from datetime import datetime, timedelta from enum import auto -from typing import Optional, Callable +from typing import Optional, List +from uuid import UUID from PyQt6 import QtGui -from PyQt6.QtCore import pyqtSignal, Qt, QModelIndex +from PyQt6.QtCore import Qt +from PyQt6.QtCore import pyqtSignal, QModelIndex +from PyQt6.QtSql import QSqlTableModel, QSqlRecord from PyQt6.QtWidgets import ( - QTableWidget, QWidget, - QAbstractItemView, - QTableWidgetItem, QMenu, + QTableView, + QAbstractItemView, + QStyledItemDelegate, ) +from buzz.db.entity.transcription import Transcription from buzz.locale import _ from buzz.settings.settings import Settings -from buzz.transcriber.transcriber import FileTranscriptionTask, humanize_language +from buzz.transcriber.transcriber import FileTranscriptionTask +from buzz.widgets.record_delegate import RecordDelegate +from buzz.widgets.transcription_record import TranscriptionRecord + + +class Column(enum.Enum): + ID = 0 + ERROR_MESSAGE = auto() + EXPORT_FORMATS = auto() + FILE = auto() + OUTPUT_FOLDER = auto() + PROGRESS = auto() + LANGUAGE = auto() + MODEL_TYPE = auto() + SOURCE = auto() + STATUS = auto() + TASK = auto() + TIME_ENDED = auto() + TIME_QUEUED = auto() + TIME_STARTED = auto() + URL = auto() + WHISPER_MODEL_SIZE = auto() @dataclass -class TableColDef: +class ColDef: id: str header: str - column_index: int - value_getter: Callable[[FileTranscriptionTask], str] + column: Column width: Optional[int] = None - hidden: bool = False + delegate: Optional[QStyledItemDelegate] = None hidden_toggleable: bool = True -class TranscriptionTasksTableWidget(QTableWidget): - class Column(enum.Enum): - TASK_ID = 0 - FILE_NAME = auto() - MODEL = auto() - TASK = auto() - STATUS = auto() - DATE_ADDED = auto() - DATE_COMPLETED = auto() +def format_record_status_text(record: QSqlRecord) -> str: + status = FileTranscriptionTask.Status(record.value("status")) + match status: + case FileTranscriptionTask.Status.IN_PROGRESS: + return f'{_("In Progress")} ({record.value("progress") :.0%})' + case FileTranscriptionTask.Status.COMPLETED: + status = _("Completed") + started_at = record.value("time_started") + completed_at = record.value("time_ended") + if started_at != "" and completed_at != "": + status += f" ({TranscriptionTasksTableWidget.format_timedelta(datetime.fromisoformat(completed_at) - datetime.fromisoformat(started_at))})" + return status + case FileTranscriptionTask.Status.FAILED: + return f'{_("Failed")} ({record.value("error_message")})' + case FileTranscriptionTask.Status.CANCELED: + return _("Canceled") + case FileTranscriptionTask.Status.QUEUED: + return _("Queued") + case _: + return "" + +column_definitions = [ + ColDef( + id="file_name", + header="File Name / URL", + column=Column.FILE, + width=400, + delegate=RecordDelegate( + text_getter=lambda record: record.value("url") + if record.value("url") != "" + else os.path.basename(record.value("file")) + ), + hidden_toggleable=False, + ), + ColDef( + id="model", + header="Model", + column=Column.MODEL_TYPE, + width=180, + delegate=RecordDelegate( + text_getter=lambda record: str(TranscriptionRecord.model(record)) + ), + ), + ColDef( + id="task", + header="Task", + column=Column.SOURCE, + width=120, + delegate=RecordDelegate( + text_getter=lambda record: record.value("task").capitalize() + ), + ), + ColDef( + id="status", + header="Status", + column=Column.STATUS, + width=180, + delegate=RecordDelegate(text_getter=format_record_status_text), + hidden_toggleable=False, + ), + ColDef( + id="date_added", + header="Date Added", + column=Column.TIME_QUEUED, + width=180, + delegate=RecordDelegate( + text_getter=lambda record: datetime.fromisoformat( + record.value("time_queued") + ).strftime("%Y-%m-%d %H:%M:%S") + ), + ), + ColDef( + id="date_completed", + header="Date Completed", + column=Column.TIME_ENDED, + width=180, + delegate=RecordDelegate( + text_getter=lambda record: datetime.fromisoformat( + record.value("time_ended") + ).strftime("%Y-%m-%d %H:%M:%S") + if record.value("time_ended") != "" + else "" + ), + ), +] + + +class TranscriptionTasksTableWidget(QTableView): return_clicked = pyqtSignal() def __init__(self, parent: Optional[QWidget] = None): super().__init__(parent) - self.setRowCount(0) - self.setAlternatingRowColors(True) + self._model = QSqlTableModel() + self._model.setTable("transcription") + self._model.setEditStrategy(QSqlTableModel.EditStrategy.OnManualSubmit) + self._model.setSort(Column.TIME_QUEUED.value, Qt.SortOrder.DescendingOrder) + + self.setModel(self._model) + + for i in range(self.model().columnCount()): + self.hideColumn(i) + self.settings = Settings() - self.column_definitions = [ - TableColDef( - id="id", - header=_("ID"), - column_index=self.Column.TASK_ID.value, - value_getter=lambda task: str(task.id), - width=0, - hidden=True, - hidden_toggleable=False, - ), - TableColDef( - id="file_name", - header=_("File Name/URL"), - column_index=self.Column.FILE_NAME.value, - value_getter=lambda task: task.url - if task.url is not None - else os.path.basename(task.file_path), - width=300, - hidden_toggleable=False, - ), - TableColDef( - id="model", - header=_("Model"), - column_index=self.Column.MODEL.value, - value_getter=lambda task: str(task.transcription_options.model), - width=180, - hidden=True, - ), - TableColDef( - id="task", - header=_("Task"), - column_index=self.Column.TASK.value, - value_getter=lambda task: self.get_task_label(task), - width=120, - hidden=True, - ), - TableColDef( - id="status", - header=_("Status"), - column_index=self.Column.STATUS.value, - value_getter=lambda task: task.status_text(), - width=180, - hidden_toggleable=False, - ), - TableColDef( - id="date_added", - header=_("Date Added"), - column_index=self.Column.DATE_ADDED.value, - value_getter=lambda task: task.queued_at.strftime("%Y-%m-%d %H:%M:%S") - if task.queued_at is not None - else "", - width=180, - hidden=True, - ), - TableColDef( - id="date_completed", - header=_("Date Completed"), - column_index=self.Column.DATE_COMPLETED.value, - value_getter=lambda task: task.completed_at.strftime( - "%Y-%m-%d %H:%M:%S" - ) - if task.completed_at is not None - else "", - width=180, - hidden=True, - ), - ] - - self.setColumnCount(len(self.column_definitions)) - self.verticalHeader().hide() - self.setHorizontalHeaderLabels( - [definition.header for definition in self.column_definitions] + self.settings.begin_group( + Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_VISIBILITY ) - for definition in self.column_definitions: - if definition.width is not None: - self.setColumnWidth(definition.column_index, definition.width) - self.load_column_visibility() + for definition in column_definitions: + self.model().setHeaderData( + definition.column.value, + Qt.Orientation.Horizontal, + definition.header, + ) - self.horizontalHeader().setMinimumSectionSize(180) + visible = self.settings.settings.value(definition.id, True) + self.setColumnHidden(definition.column.value, not visible) + if definition.width is not None: + self.setColumnWidth(definition.column.value, definition.width) + if definition.delegate is not None: + self.setItemDelegateForColumn( + definition.column.value, definition.delegate + ) + self.settings.end_group() + self.model().select() + self.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers) self.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows) + self.verticalHeader().hide() + self.setAlternatingRowColors(True) def contextMenuEvent(self, event): menu = QMenu(self) - for definition in self.column_definitions: + for definition in column_definitions: if not definition.hidden_toggleable: continue action = menu.addAction(definition.header) action.setCheckable(True) - action.setChecked(not self.isColumnHidden(definition.column_index)) + action.setChecked(not self.isColumnHidden(definition.column.value)) action.toggled.connect( lambda checked, - column_index=definition.column_index: self.on_column_checked( + column_index=definition.column.value: self.on_column_checked( column_index, checked ) ) @@ -155,66 +211,47 @@ def save_column_visibility(self): self.settings.begin_group( Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_VISIBILITY ) - for definition in self.column_definitions: + for definition in column_definitions: self.settings.settings.setValue( - definition.id, not self.isColumnHidden(definition.column_index) + definition.id, not self.isColumnHidden(definition.column.value) ) self.settings.end_group() - def load_column_visibility(self): - self.settings.begin_group( - Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_VISIBILITY - ) - for definition in self.column_definitions: - visible = self.settings.settings.value(definition.id, not definition.hidden) - self.setColumnHidden(definition.column_index, not visible) - self.settings.end_group() - - def upsert_task(self, task: FileTranscriptionTask): - task_row_index = self.task_row_index(task.id) - if task_row_index is None: - self.insertRow(self.rowCount()) - - row_index = self.rowCount() - 1 - for definition in self.column_definitions: - item = QTableWidgetItem(definition.value_getter(task)) - item.setFlags(item.flags() & ~Qt.ItemFlag.ItemIsEditable) - self.setItem(row_index, definition.column_index, item) - else: - for definition in self.column_definitions: - item = self.item(task_row_index, definition.column_index) - item.setText(definition.value_getter(task)) - - @staticmethod - def get_task_label(task: FileTranscriptionTask) -> str: - value = task.transcription_options.task.value.capitalize() - if task.transcription_options.language is not None: - value += f" ({humanize_language(task.transcription_options.language)})" - return value - - def clear_task(self, task_id: int): - task_row_index = self.task_row_index(task_id) - if task_row_index is not None: - self.removeRow(task_row_index) - - def task_row_index(self, task_id: int) -> int | None: - table_items_matching_task_id = [ - item - for item in self.findItems(str(task_id), Qt.MatchFlag.MatchExactly) - if item.column() == self.Column.TASK_ID.value - ] - if len(table_items_matching_task_id) == 0: - return None - return table_items_matching_task_id[0].row() - - @staticmethod - def find_task_id(index: QModelIndex): - sibling_index = index.siblingAtColumn( - TranscriptionTasksTableWidget.Column.TASK_ID.value - ).data() - return int(sibling_index) if sibling_index is not None else None - def keyPressEvent(self, event: QtGui.QKeyEvent) -> None: if event.key() == Qt.Key.Key_Return: self.return_clicked.emit() super().keyPressEvent(event) + + def selected_transcriptions(self) -> List[Transcription]: + selected = self.selectionModel().selectedRows() + return [self.transcription(row) for row in selected] + + def delete_transcriptions(self, rows: List[QModelIndex]): + for row in rows: + self.model().removeRow(row.row()) + self.model().submitAll() + + def transcription(self, index: QModelIndex) -> Transcription: + return Transcription.from_record(self.model().record(index.row())) + + def refresh_all(self): + self.model().select() + + def refresh_row(self, id: UUID): + for i in range(self.model().rowCount()): + record = self.model().record(i) + if record.value("id") == str(id): + self.model().selectRow(i) + return + + @staticmethod + def format_timedelta(delta: timedelta): + mm, ss = divmod(delta.seconds, 60) + result = f"{ss}s" + if mm == 0: + return result + hh, mm = divmod(mm, 60) + result = f"{mm}m {result}" + if hh == 0: + return result + return f"{hh}h {result}" diff --git a/buzz/widgets/transcription_viewer/export_transcription_button.py b/buzz/widgets/transcription_viewer/export_transcription_button.py index 50b7931004..aaf1a7c64f 100644 --- a/buzz/widgets/transcription_viewer/export_transcription_button.py +++ b/buzz/widgets/transcription_viewer/export_transcription_button.py @@ -1,20 +1,18 @@ +from PyQt6.QtCore import pyqtSignal from PyQt6.QtGui import QAction -from PyQt6.QtWidgets import QPushButton, QWidget, QMenu, QFileDialog +from PyQt6.QtWidgets import QPushButton, QWidget, QMenu -from buzz.locale import _ -from buzz.transcriber.file_transcriber import write_output from buzz.transcriber.transcriber import ( - FileTranscriptionTask, OutputFormat, - get_output_file_path, ) from buzz.widgets.icon import FileDownloadIcon class ExportTranscriptionButton(QPushButton): - def __init__(self, transcription_task: FileTranscriptionTask, parent: QWidget): + on_export_triggered = pyqtSignal(OutputFormat) + + def __init__(self, parent: QWidget): super().__init__(parent) - self.transcription_task = transcription_task export_button_menu = QMenu() actions = [ @@ -29,23 +27,4 @@ def __init__(self, transcription_task: FileTranscriptionTask, parent: QWidget): def on_menu_triggered(self, action: QAction): output_format = OutputFormat[action.text()] - - default_path = get_output_file_path( - task=self.transcription_task, output_format=output_format - ) - - (output_file_path, nil) = QFileDialog.getSaveFileName( - self, - _("Save File"), - default_path, - _("Text files") + f" (*.{output_format.value})", - ) - - if output_file_path == "": - return - - write_output( - path=output_file_path, - segments=self.transcription_task.segments, - output_format=output_format, - ) + self.on_export_triggered.emit(output_format) diff --git a/buzz/widgets/transcription_viewer/transcription_segments_editor_widget.py b/buzz/widgets/transcription_viewer/transcription_segments_editor_widget.py index 79acc43afd..e35f21a011 100644 --- a/buzz/widgets/transcription_viewer/transcription_segments_editor_widget.py +++ b/buzz/widgets/transcription_viewer/transcription_segments_editor_widget.py @@ -1,72 +1,105 @@ import enum -from typing import List, Optional - -from PyQt6.QtCore import Qt, pyqtSignal -from PyQt6.QtWidgets import QTableWidget, QWidget, QHeaderView, QTableWidgetItem +from dataclasses import dataclass +from typing import Optional +from uuid import UUID + +from PyQt6.QtCore import pyqtSignal, Qt, QModelIndex, QItemSelection +from PyQt6.QtSql import QSqlTableModel, QSqlRecord +from PyQt6.QtWidgets import ( + QWidget, + QTableView, + QStyledItemDelegate, + QAbstractItemView, +) from buzz.locale import _ from buzz.transcriber.file_transcriber import to_timestamp -from buzz.transcriber.transcriber import Segment -class TranscriptionSegmentsEditorWidget(QTableWidget): - segment_text_changed = pyqtSignal(tuple) - segment_index_selected = pyqtSignal(int) +class Column(enum.Enum): + ID = 0 + END = enum.auto() + START = enum.auto() + TEXT = enum.auto() + TRANSCRIPTION_ID = enum.auto() + + +@dataclass +class ColDef: + id: str + header: str + column: Column + delegate: Optional[QStyledItemDelegate] = None + + +class TimeStampDelegate(QStyledItemDelegate): + def displayText(self, value, locale): + return to_timestamp(value) + + +class TranscriptionSegmentModel(QSqlTableModel): + def __init__(self, transcription_id: UUID): + super().__init__() + self.setTable("transcription_segment") + self.setEditStrategy(QSqlTableModel.EditStrategy.OnFieldChange) + self.setFilter(f"transcription_id = '{transcription_id}'") - class Column(enum.Enum): - START = 0 - END = enum.auto() - TEXT = enum.auto() + def flags(self, index: QModelIndex): + flags = super().flags(index) + if index.column() in (Column.START.value, Column.END.value): + flags &= ~Qt.ItemFlag.ItemIsEditable + return flags - def __init__(self, segments: List[Segment], parent: Optional[QWidget]): + +class TranscriptionSegmentsEditorWidget(QTableView): + segment_selected = pyqtSignal(QSqlRecord) + + def __init__(self, transcription_id: UUID, parent: Optional[QWidget]): super().__init__(parent) - self.segments = segments + model = TranscriptionSegmentModel(transcription_id=transcription_id) + self.setModel(model) - self.setAlternatingRowColors(True) + timestamp_delegate = TimeStampDelegate() - self.setColumnCount(3) + self.column_definitions: list[ColDef] = [ + ColDef("start", _("Start"), Column.START, delegate=timestamp_delegate), + ColDef("end", _("End"), Column.END, delegate=timestamp_delegate), + ColDef("text", _("Text"), Column.TEXT), + ] - self.verticalHeader().hide() - self.setHorizontalHeaderLabels([_("Start"), _("End"), _("Text")]) - self.horizontalHeader().setSectionResizeMode( - 2, QHeaderView.ResizeMode.ResizeToContents - ) - self.setSelectionMode(QTableWidget.SelectionMode.SingleSelection) - - for segment in segments: - row_index = self.rowCount() - self.insertRow(row_index) - - start_item = QTableWidgetItem(to_timestamp(segment.start)) - start_item.setFlags( - start_item.flags() - & ~Qt.ItemFlag.ItemIsEditable - & ~Qt.ItemFlag.ItemIsSelectable - ) - self.setItem(row_index, self.Column.START.value, start_item) + for i in range(model.columnCount()): + self.hideColumn(i) - end_item = QTableWidgetItem(to_timestamp(segment.end)) - end_item.setFlags( - end_item.flags() - & ~Qt.ItemFlag.ItemIsEditable - & ~Qt.ItemFlag.ItemIsSelectable + for definition in self.column_definitions: + model.setHeaderData( + definition.column.value, + Qt.Orientation.Horizontal, + definition.header, ) - self.setItem(row_index, self.Column.END.value, end_item) + self.showColumn(definition.column.value) + if definition.delegate is not None: + self.setItemDelegateForColumn( + definition.column.value, definition.delegate + ) - text_item = QTableWidgetItem(segment.text) - self.setItem(row_index, self.Column.TEXT.value, text_item) + self.setAlternatingRowColors(True) + self.verticalHeader().hide() + self.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows) + self.setSelectionMode(QTableView.SelectionMode.SingleSelection) + self.selectionModel().selectionChanged.connect(self.on_selection_changed) + model.select() - self.itemChanged.connect(self.on_item_changed) - self.itemSelectionChanged.connect(self.on_item_selection_changed) + self.resizeColumnsToContents() - def on_item_changed(self, item: QTableWidgetItem): - if item.column() == self.Column.TEXT.value: - self.segment_text_changed.emit((item.row(), item.text())) + def on_selection_changed( + self, selected: QItemSelection, _deselected: QItemSelection + ): + if selected.indexes(): + self.segment_selected.emit(self.segment(selected.indexes()[0])) - def set_segment_text(self, index: int, text: str): - self.item(index, self.Column.TEXT.value).setText(text) + def segment(self, index: QModelIndex) -> QSqlRecord: + return self.model().record(index.row()) - def on_item_selection_changed(self): - ranges = self.selectedRanges() - self.segment_index_selected.emit(ranges[0].topRow() if len(ranges) > 0 else -1) + def segments(self) -> list[QSqlRecord]: + return [self.model().record(i) for i in range(self.model().rowCount())] diff --git a/buzz/widgets/transcription_viewer/transcription_viewer_widget.py b/buzz/widgets/transcription_viewer/transcription_viewer_widget.py index 0f1c8bd346..e98b24dfe0 100644 --- a/buzz/widgets/transcription_viewer/transcription_viewer_widget.py +++ b/buzz/widgets/transcription_viewer/transcription_viewer_widget.py @@ -1,25 +1,24 @@ import platform -from typing import List, Optional +from typing import Optional +from uuid import UUID -from PyQt6.QtCore import Qt, pyqtSignal -from PyQt6.QtGui import QUndoCommand, QUndoStack, QKeySequence +from PyQt6.QtCore import Qt +from PyQt6.QtMultimedia import QMediaPlayer +from PyQt6.QtSql import QSqlRecord from PyQt6.QtWidgets import ( QWidget, QHBoxLayout, QLabel, QGridLayout, + QFileDialog, ) -from buzz.action import Action +from buzz.db.entity.transcription import Transcription from buzz.locale import _ from buzz.paths import file_path_as_title -from buzz.transcriber.transcriber import ( - FileTranscriptionTask, - Segment, -) +from buzz.transcriber.file_transcriber import write_output +from buzz.transcriber.transcriber import OutputFormat, Segment from buzz.widgets.audio_player import AudioPlayer -from buzz.widgets.icon import UndoIcon, RedoIcon -from buzz.widgets.toolbar import ToolBar from buzz.widgets.transcription_viewer.export_transcription_button import ( ExportTranscriptionButton, ) @@ -28,84 +27,31 @@ ) -class ChangeSegmentTextCommand(QUndoCommand): - def __init__( - self, - table_widget: TranscriptionSegmentsEditorWidget, - segments: List[Segment], - segment_index: int, - segment_text: str, - task_changed: pyqtSignal, - ): - super().__init__() - - self.table_widget = table_widget - self.segments = segments - self.segment_index = segment_index - self.segment_text = segment_text - self.task_changed = task_changed - - self.previous_segment_text = self.segments[self.segment_index].text - - def undo(self) -> None: - self.set_segment_text(self.previous_segment_text) - - def redo(self) -> None: - self.set_segment_text(self.segment_text) - - def set_segment_text(self, text: str): - # block signals before setting text so it doesn't re-trigger a new UndoCommand - self.table_widget.blockSignals(True) - self.table_widget.set_segment_text(self.segment_index, text) - self.table_widget.blockSignals(False) - self.segments[self.segment_index].text = text - self.task_changed.emit() - - class TranscriptionViewerWidget(QWidget): - transcription_task: FileTranscriptionTask - task_changed = pyqtSignal() + transcription: Transcription def __init__( self, - transcription_task: FileTranscriptionTask, - open_transcription_output=True, + transcription: Transcription, parent: Optional["QWidget"] = None, flags: Qt.WindowType = Qt.WindowType.Widget, ) -> None: super().__init__(parent, flags) - self.transcription_task = transcription_task - self.open_transcription_output = open_transcription_output + self.transcription = transcription self.setMinimumWidth(800) self.setMinimumHeight(500) - self.setWindowTitle(file_path_as_title(transcription_task.file_path)) - - self.undo_stack = QUndoStack() - - undo_action = self.undo_stack.createUndoAction(self, _("Undo")) - undo_action.setShortcuts(QKeySequence.StandardKey.Undo) - undo_action.setIcon(UndoIcon(parent=self)) - undo_action.setToolTip(Action.get_tooltip(undo_action)) - - redo_action = self.undo_stack.createRedoAction(self, _("Redo")) - redo_action.setShortcuts(QKeySequence.StandardKey.Redo) - redo_action.setIcon(RedoIcon(parent=self)) - redo_action.setToolTip(Action.get_tooltip(redo_action)) - - toolbar = ToolBar() - toolbar.addActions([undo_action, redo_action]) + self.setWindowTitle(file_path_as_title(transcription.file)) self.table_widget = TranscriptionSegmentsEditorWidget( - segments=transcription_task.segments, parent=self + transcription_id=UUID(hex=transcription.id), parent=self ) - self.table_widget.segment_text_changed.connect(self.on_segment_text_changed) - self.table_widget.segment_index_selected.connect(self.on_segment_index_selected) + self.table_widget.segment_selected.connect(self.on_segment_selected) self.audio_player: Optional[AudioPlayer] = None if platform.system() != "Linux": - self.audio_player = AudioPlayer(file_path=transcription_task.file_path) + self.audio_player = AudioPlayer(file_path=transcription.file) self.audio_player.position_ms_changed.connect( self.on_audio_player_position_ms_changed ) @@ -118,12 +64,10 @@ def __init__( buttons_layout = QHBoxLayout() buttons_layout.addStretch() - export_button = ExportTranscriptionButton( - transcription_task=transcription_task, parent=self - ) + export_button = ExportTranscriptionButton(parent=self) + export_button.on_export_triggered.connect(self.on_export_triggered) layout = QGridLayout(self) - layout.setMenuBar(toolbar) layout.addWidget(self.table_widget, 0, 0, 1, 2) if self.audio_player is not None: @@ -133,33 +77,56 @@ def __init__( self.setLayout(layout) - def on_segment_text_changed(self, event: tuple): - segment_index, segment_text = event - self.undo_stack.push( - ChangeSegmentTextCommand( - table_widget=self.table_widget, - segments=self.transcription_task.segments, - segment_index=segment_index, - segment_text=segment_text, - task_changed=self.task_changed, + def on_export_triggered(self, output_format: OutputFormat) -> None: + default_path = self.transcription.get_output_file_path( + output_format=output_format + ) + + (output_file_path, nil) = QFileDialog.getSaveFileName( + self, + _("Save File"), + default_path, + _("Text files") + f" (*.{output_format.value})", + ) + + if output_file_path == "": + return + + segments = [ + Segment( + start=segment.value("start_time"), + end=segment.value("end_time"), + text=segment.value("text"), ) + for segment in self.table_widget.segments() + ] + + write_output( + path=output_file_path, + segments=segments, + output_format=output_format, ) - def on_segment_index_selected(self, index: int): - selected_segment = self.transcription_task.segments[index] - if self.audio_player is not None: - self.audio_player.set_range((selected_segment.start, selected_segment.end)) + def on_segment_selected(self, segment: QSqlRecord): + if self.audio_player is not None and ( + self.audio_player.media_player.playbackState() + == QMediaPlayer.PlaybackState.PlayingState + ): + self.audio_player.set_range( + (segment.value("start_time"), segment.value("end_time")) + ) def on_audio_player_position_ms_changed(self, position_ms: int) -> None: - current_segment_index: Optional[int] = next( + segments = self.table_widget.segments() + current_segment = next( ( - i - for i, segment in enumerate(self.transcription_task.segments) - if segment.start <= position_ms < segment.end + segment + for segment in segments + if segment.value("start_time") + <= position_ms + < segment.value("end_time") ), None, ) - if current_segment_index is not None: - self.current_segment_label.setText( - self.transcription_task.segments[current_segment_index].text - ) + if current_segment is not None: + self.current_segment_label.setText(current_segment.value("text")) diff --git a/poetry.lock b/poetry.lock index 2f201efcfa..df7ebfb3b1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -24,13 +24,13 @@ files = [ [[package]] name = "anyio" -version = "4.2.0" +version = "4.3.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.8" files = [ - { file = "anyio-4.2.0-py3-none-any.whl", hash = "sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee" }, - { file = "anyio-4.2.0.tar.gz", hash = "sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f" }, + { file = "anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8" }, + { file = "anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6" }, ] [package.dependencies] @@ -44,17 +44,6 @@ doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphin test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] trio = ["trio (>=0.23)"] -[[package]] -name = "appdirs" -version = "1.4.4" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -optional = false -python-versions = "*" -files = [ - { file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128" }, - { file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41" }, -] - [[package]] name = "astroid" version = "2.15.8" @@ -272,13 +261,13 @@ cffi = ">=1.0.0" [[package]] name = "certifi" -version = "2023.11.17" +version = "2024.2.2" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - { file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474" }, - { file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1" }, + { file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" }, + { file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f" }, ] [[package]] @@ -457,28 +446,28 @@ files = [ [[package]] name = "cmake" -version = "3.28.1" +version = "3.28.3" description = "CMake is an open-source, cross-platform family of tools designed to build, test and package software" optional = false python-versions = "*" files = [ - { file = "cmake-3.28.1-py2.py3-none-macosx_10_10_universal2.macosx_10_10_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:9c77c47afef821c0044ba73d182c386ab02e92e6bda5296e553c12455a083f29" }, - { file = "cmake-3.28.1-py2.py3-none-manylinux2010_i686.manylinux_2_12_i686.whl", hash = "sha256:6a9549755d1178426502753d48949edae9bb0c66f15a07f09904783125beb0e3" }, - { file = "cmake-3.28.1-py2.py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:d0978cdd08c0ebc76f4f8543aba1381a41580dcb9c3bcffb536c41337b75aea1" }, - { file = "cmake-3.28.1-py2.py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:96d506c417d63bbcff19b3e9eaa69fe546456a0ddeffe914bcbb23cceee6818e" }, - { file = "cmake-3.28.1-py2.py3-none-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:74c9878c504ccc6ddd5b0914cbe3b86417a36a2c2dfc486040bfdfe63fbbb1ac" }, - { file = "cmake-3.28.1-py2.py3-none-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:64d4642c48486bb4320540781a2266c2060929d1e236d6eb2b2c96273e75e958" }, - { file = "cmake-3.28.1-py2.py3-none-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:363bd0124d71d7e3d9b1ac9bd1dce1d80ba90f48b264c3bf9dbfcfda875cafc9" }, - { file = "cmake-3.28.1-py2.py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1be8f351271f8bcbe32288066e5add642d7c32f2f8fec3f135949c2cb13dfac2" }, - { file = "cmake-3.28.1-py2.py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:3ed193134a4937bad8de2b4f62faebc8c1a4049cd37dad9767db7e7d91a08b52" }, - { file = "cmake-3.28.1-py2.py3-none-musllinux_1_1_i686.whl", hash = "sha256:6ffb1fdb0b0f7f11271d82b5892c2edc109d561e186f882def095970403e2110" }, - { file = "cmake-3.28.1-py2.py3-none-musllinux_1_1_ppc64le.whl", hash = "sha256:9ea12ebe4b8266f04d6619ed64860bd6e687522f02caf3131515dd39d614ef00" }, - { file = "cmake-3.28.1-py2.py3-none-musllinux_1_1_s390x.whl", hash = "sha256:2ad22d897d2ed38544e5ef26ee21c4dccc38e938660cd07497fd6bdba0993ea6" }, - { file = "cmake-3.28.1-py2.py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:379a730b274f39e5858ef2107861b2727918493347b0ccdd5f62bcbb6a8450d9" }, - { file = "cmake-3.28.1-py2.py3-none-win32.whl", hash = "sha256:c82bc0eb1495cf518cb4f355b8a73e584e67d53453406c0498bacc454cf6c404" }, - { file = "cmake-3.28.1-py2.py3-none-win_amd64.whl", hash = "sha256:bb03ed4753185d0c70c0bc3212e5533e20eb2c17fa0ca1e7603b702c6d0db8cf" }, - { file = "cmake-3.28.1-py2.py3-none-win_arm64.whl", hash = "sha256:40f0671c05ef7eec27c4f53c63630b0b621e40f80ab38607d3a0e3a1f2c9242a" }, - { file = "cmake-3.28.1.tar.gz", hash = "sha256:0d4051d101d151d8387156c463aa45c8cd0e164f870e0ac0c8c91d3ff08528e1" }, + { file = "cmake-3.28.3-py2.py3-none-macosx_10_10_universal2.macosx_10_10_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:f27187ae016b089d1c1fca6a24b3af58f9d79471097eaa3b7a7a7623ad12ea89" }, + { file = "cmake-3.28.3-py2.py3-none-manylinux2010_i686.manylinux_2_12_i686.whl", hash = "sha256:f5573c453f7a6c213c82741c173d174b5c6b576eea5cc00e2a8a5a30c40244b3" }, + { file = "cmake-3.28.3-py2.py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:35b14086257dc7ce8e83c19d2d20f7953d584fa3c9d1904211d8498fe1134ecc" }, + { file = "cmake-3.28.3-py2.py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:795c4c7f0ad16cc6553085502a76aa7fcf36fd2f4c8420542d1c7f3be6f9de1e" }, + { file = "cmake-3.28.3-py2.py3-none-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:2b811a7c97b2b31a56397baeb5ca93119fa4d215846851059748427c67f14a58" }, + { file = "cmake-3.28.3-py2.py3-none-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:8415ed1a9335eb30b0e435c38bcaeb8fd9ae900a9594fe500f3bcba744be1dc7" }, + { file = "cmake-3.28.3-py2.py3-none-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:2745d4362ac23f2f979e71d44759af740c3890429cb8a7e2fd449a30a901632f" }, + { file = "cmake-3.28.3-py2.py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d3bc42bf54ea3d64e5d81eb31275076817507cf4a6aa07a49ffc01985cae1f09" }, + { file = "cmake-3.28.3-py2.py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:de10be2f470c41a3628e27157168f017ade2f14065588497e00f4582bc5eec07" }, + { file = "cmake-3.28.3-py2.py3-none-musllinux_1_1_i686.whl", hash = "sha256:5e4972e455fc24509561873cb06c9d9394852d77adde1cf970b859ad14a2a66f" }, + { file = "cmake-3.28.3-py2.py3-none-musllinux_1_1_ppc64le.whl", hash = "sha256:ea338ae68e0c5626f7c21f89b765eb0e81f7b497e977503a3bcce569984dc8a7" }, + { file = "cmake-3.28.3-py2.py3-none-musllinux_1_1_s390x.whl", hash = "sha256:c6415d382933854d2b5508c4d2218cfb1a8cb90f5f78b4e97183f80089868eea" }, + { file = "cmake-3.28.3-py2.py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:cc67c5e5df8db0be57d25b81f7dc76e0ec79215f914e585a8045589a380bcd3c" }, + { file = "cmake-3.28.3-py2.py3-none-win32.whl", hash = "sha256:29d127e5ef256d389feac0884e918612b89eb3a8febff1acf83bb27bc65042ab" }, + { file = "cmake-3.28.3-py2.py3-none-win_amd64.whl", hash = "sha256:f6fc9755979d17970ca6d9688fb5cdd3702c9eaa7ac1ee97074e3d39d3400970" }, + { file = "cmake-3.28.3-py2.py3-none-win_arm64.whl", hash = "sha256:4b1b413cf7683d54ec2a0f3b17a4d7c6979eb469270439c0e7a082256c78ab96" }, + { file = "cmake-3.28.3.tar.gz", hash = "sha256:a8092815c739da7d6775c26ec30c2645f0fca9527a29e36a682faec7d39cde89" }, ] [package.extras] @@ -514,63 +503,63 @@ cron = ["capturer (>=2.4)"] [[package]] name = "coverage" -version = "7.4.0" +version = "7.4.3" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - { file = "coverage-7.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36b0ea8ab20d6a7564e89cb6135920bc9188fb5f1f7152e94e8300b7b189441a" }, - { file = "coverage-7.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0676cd0ba581e514b7f726495ea75aba3eb20899d824636c6f59b0ed2f88c471" }, - { file = "coverage-7.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0ca5c71a5a1765a0f8f88022c52b6b8be740e512980362f7fdbb03725a0d6b9" }, - { file = "coverage-7.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7c97726520f784239f6c62506bc70e48d01ae71e9da128259d61ca5e9788516" }, - { file = "coverage-7.4.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:815ac2d0f3398a14286dc2cea223a6f338109f9ecf39a71160cd1628786bc6f5" }, - { file = "coverage-7.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:80b5ee39b7f0131ebec7968baa9b2309eddb35b8403d1869e08f024efd883566" }, - { file = "coverage-7.4.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5b2ccb7548a0b65974860a78c9ffe1173cfb5877460e5a229238d985565574ae" }, - { file = "coverage-7.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:995ea5c48c4ebfd898eacb098164b3cc826ba273b3049e4a889658548e321b43" }, - { file = "coverage-7.4.0-cp310-cp310-win32.whl", hash = "sha256:79287fd95585ed36e83182794a57a46aeae0b64ca53929d1176db56aacc83451" }, - { file = "coverage-7.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:5b14b4f8760006bfdb6e08667af7bc2d8d9bfdb648351915315ea17645347137" }, - { file = "coverage-7.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:04387a4a6ecb330c1878907ce0dc04078ea72a869263e53c72a1ba5bbdf380ca" }, - { file = "coverage-7.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ea81d8f9691bb53f4fb4db603203029643caffc82bf998ab5b59ca05560f4c06" }, - { file = "coverage-7.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74775198b702868ec2d058cb92720a3c5a9177296f75bd97317c787daf711505" }, - { file = "coverage-7.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76f03940f9973bfaee8cfba70ac991825611b9aac047e5c80d499a44079ec0bc" }, - { file = "coverage-7.4.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:485e9f897cf4856a65a57c7f6ea3dc0d4e6c076c87311d4bc003f82cfe199d25" }, - { file = "coverage-7.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6ae8c9d301207e6856865867d762a4b6fd379c714fcc0607a84b92ee63feff70" }, - { file = "coverage-7.4.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bf477c355274a72435ceb140dc42de0dc1e1e0bf6e97195be30487d8eaaf1a09" }, - { file = "coverage-7.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:83c2dda2666fe32332f8e87481eed056c8b4d163fe18ecc690b02802d36a4d26" }, - { file = "coverage-7.4.0-cp311-cp311-win32.whl", hash = "sha256:697d1317e5290a313ef0d369650cfee1a114abb6021fa239ca12b4849ebbd614" }, - { file = "coverage-7.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:26776ff6c711d9d835557ee453082025d871e30b3fd6c27fcef14733f67f0590" }, - { file = "coverage-7.4.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:13eaf476ec3e883fe3e5fe3707caeb88268a06284484a3daf8250259ef1ba143" }, - { file = "coverage-7.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846f52f46e212affb5bcf131c952fb4075b55aae6b61adc9856222df89cbe3e2" }, - { file = "coverage-7.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26f66da8695719ccf90e794ed567a1549bb2644a706b41e9f6eae6816b398c4a" }, - { file = "coverage-7.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:164fdcc3246c69a6526a59b744b62e303039a81e42cfbbdc171c91a8cc2f9446" }, - { file = "coverage-7.4.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:316543f71025a6565677d84bc4df2114e9b6a615aa39fb165d697dba06a54af9" }, - { file = "coverage-7.4.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bb1de682da0b824411e00a0d4da5a784ec6496b6850fdf8c865c1d68c0e318dd" }, - { file = "coverage-7.4.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:0e8d06778e8fbffccfe96331a3946237f87b1e1d359d7fbe8b06b96c95a5407a" }, - { file = "coverage-7.4.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a56de34db7b7ff77056a37aedded01b2b98b508227d2d0979d373a9b5d353daa" }, - { file = "coverage-7.4.0-cp312-cp312-win32.whl", hash = "sha256:51456e6fa099a8d9d91497202d9563a320513fcf59f33991b0661a4a6f2ad450" }, - { file = "coverage-7.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:cd3c1e4cb2ff0083758f09be0f77402e1bdf704adb7f89108007300a6da587d0" }, - { file = "coverage-7.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e9d1bf53c4c8de58d22e0e956a79a5b37f754ed1ffdbf1a260d9dcfa2d8a325e" }, - { file = "coverage-7.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:109f5985182b6b81fe33323ab4707011875198c41964f014579cf82cebf2bb85" }, - { file = "coverage-7.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cc9d4bc55de8003663ec94c2f215d12d42ceea128da8f0f4036235a119c88ac" }, - { file = "coverage-7.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc6d65b21c219ec2072c1293c505cf36e4e913a3f936d80028993dd73c7906b1" }, - { file = "coverage-7.4.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a10a4920def78bbfff4eff8a05c51be03e42f1c3735be42d851f199144897ba" }, - { file = "coverage-7.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b8e99f06160602bc64da35158bb76c73522a4010f0649be44a4e167ff8555952" }, - { file = "coverage-7.4.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7d360587e64d006402b7116623cebf9d48893329ef035278969fa3bbf75b697e" }, - { file = "coverage-7.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:29f3abe810930311c0b5d1a7140f6395369c3db1be68345638c33eec07535105" }, - { file = "coverage-7.4.0-cp38-cp38-win32.whl", hash = "sha256:5040148f4ec43644702e7b16ca864c5314ccb8ee0751ef617d49aa0e2d6bf4f2" }, - { file = "coverage-7.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:9864463c1c2f9cb3b5db2cf1ff475eed2f0b4285c2aaf4d357b69959941aa555" }, - { file = "coverage-7.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:936d38794044b26c99d3dd004d8af0035ac535b92090f7f2bb5aa9c8e2f5cd42" }, - { file = "coverage-7.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:799c8f873794a08cdf216aa5d0531c6a3747793b70c53f70e98259720a6fe2d7" }, - { file = "coverage-7.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7defbb9737274023e2d7af02cac77043c86ce88a907c58f42b580a97d5bcca9" }, - { file = "coverage-7.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a1526d265743fb49363974b7aa8d5899ff64ee07df47dd8d3e37dcc0818f09ed" }, - { file = "coverage-7.4.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf635a52fc1ea401baf88843ae8708591aa4adff875e5c23220de43b1ccf575c" }, - { file = "coverage-7.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:756ded44f47f330666843b5781be126ab57bb57c22adbb07d83f6b519783b870" }, - { file = "coverage-7.4.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0eb3c2f32dabe3a4aaf6441dde94f35687224dfd7eb2a7f47f3fd9428e421058" }, - { file = "coverage-7.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bfd5db349d15c08311702611f3dccbef4b4e2ec148fcc636cf8739519b4a5c0f" }, - { file = "coverage-7.4.0-cp39-cp39-win32.whl", hash = "sha256:53d7d9158ee03956e0eadac38dfa1ec8068431ef8058fe6447043db1fb40d932" }, - { file = "coverage-7.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:cfd2a8b6b0d8e66e944d47cdec2f47c48fef2ba2f2dff5a9a75757f64172857e" }, - { file = "coverage-7.4.0-pp38.pp39.pp310-none-any.whl", hash = "sha256:c530833afc4707fe48524a44844493f36d8727f04dcce91fb978c414a8556cc6" }, - { file = "coverage-7.4.0.tar.gz", hash = "sha256:707c0f58cb1712b8809ece32b68996ee1e609f71bd14615bd8f87a1293cb610e" }, + { file = "coverage-7.4.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8580b827d4746d47294c0e0b92854c85a92c2227927433998f0d3320ae8a71b6" }, + { file = "coverage-7.4.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:718187eeb9849fc6cc23e0d9b092bc2348821c5e1a901c9f8975df0bc785bfd4" }, + { file = "coverage-7.4.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:767b35c3a246bcb55b8044fd3a43b8cd553dd1f9f2c1eeb87a302b1f8daa0524" }, + { file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae7f19afe0cce50039e2c782bff379c7e347cba335429678450b8fe81c4ef96d" }, + { file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba3a8aaed13770e970b3df46980cb068d1c24af1a1968b7818b69af8c4347efb" }, + { file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ee866acc0861caebb4f2ab79f0b94dbfbdbfadc19f82e6e9c93930f74e11d7a0" }, + { file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:506edb1dd49e13a2d4cac6a5173317b82a23c9d6e8df63efb4f0380de0fbccbc" }, + { file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd6545d97c98a192c5ac995d21c894b581f1fd14cf389be90724d21808b657e2" }, + { file = "coverage-7.4.3-cp310-cp310-win32.whl", hash = "sha256:f6a09b360d67e589236a44f0c39218a8efba2593b6abdccc300a8862cffc2f94" }, + { file = "coverage-7.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:18d90523ce7553dd0b7e23cbb28865db23cddfd683a38fb224115f7826de78d0" }, + { file = "coverage-7.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cbbe5e739d45a52f3200a771c6d2c7acf89eb2524890a4a3aa1a7fa0695d2a47" }, + { file = "coverage-7.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:489763b2d037b164846ebac0cbd368b8a4ca56385c4090807ff9fad817de4113" }, + { file = "coverage-7.4.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:451f433ad901b3bb00184d83fd83d135fb682d780b38af7944c9faeecb1e0bfe" }, + { file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fcc66e222cf4c719fe7722a403888b1f5e1682d1679bd780e2b26c18bb648cdc" }, + { file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3ec74cfef2d985e145baae90d9b1b32f85e1741b04cd967aaf9cfa84c1334f3" }, + { file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:abbbd8093c5229c72d4c2926afaee0e6e3140de69d5dcd918b2921f2f0c8baba" }, + { file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:35eb581efdacf7b7422af677b92170da4ef34500467381e805944a3201df2079" }, + { file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8249b1c7334be8f8c3abcaaa996e1e4927b0e5a23b65f5bf6cfe3180d8ca7840" }, + { file = "coverage-7.4.3-cp311-cp311-win32.whl", hash = "sha256:cf30900aa1ba595312ae41978b95e256e419d8a823af79ce670835409fc02ad3" }, + { file = "coverage-7.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:18c7320695c949de11a351742ee001849912fd57e62a706d83dfc1581897fa2e" }, + { file = "coverage-7.4.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b51bfc348925e92a9bd9b2e48dad13431b57011fd1038f08316e6bf1df107d10" }, + { file = "coverage-7.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d6cdecaedea1ea9e033d8adf6a0ab11107b49571bbb9737175444cea6eb72328" }, + { file = "coverage-7.4.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b2eccb883368f9e972e216c7b4c7c06cabda925b5f06dde0650281cb7666a30" }, + { file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c00cdc8fa4e50e1cc1f941a7f2e3e0f26cb2a1233c9696f26963ff58445bac7" }, + { file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9a4a8dd3dcf4cbd3165737358e4d7dfbd9d59902ad11e3b15eebb6393b0446e" }, + { file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:062b0a75d9261e2f9c6d071753f7eef0fc9caf3a2c82d36d76667ba7b6470003" }, + { file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ebe7c9e67a2d15fa97b77ea6571ce5e1e1f6b0db71d1d5e96f8d2bf134303c1d" }, + { file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c0a120238dd71c68484f02562f6d446d736adcc6ca0993712289b102705a9a3a" }, + { file = "coverage-7.4.3-cp312-cp312-win32.whl", hash = "sha256:37389611ba54fd6d278fde86eb2c013c8e50232e38f5c68235d09d0a3f8aa352" }, + { file = "coverage-7.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:d25b937a5d9ffa857d41be042b4238dd61db888533b53bc76dc082cb5a15e914" }, + { file = "coverage-7.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:28ca2098939eabab044ad68850aac8f8db6bf0b29bc7f2887d05889b17346454" }, + { file = "coverage-7.4.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:280459f0a03cecbe8800786cdc23067a8fc64c0bd51dc614008d9c36e1659d7e" }, + { file = "coverage-7.4.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c0cdedd3500e0511eac1517bf560149764b7d8e65cb800d8bf1c63ebf39edd2" }, + { file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a9babb9466fe1da12417a4aed923e90124a534736de6201794a3aea9d98484e" }, + { file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dec9de46a33cf2dd87a5254af095a409ea3bf952d85ad339751e7de6d962cde6" }, + { file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:16bae383a9cc5abab9bb05c10a3e5a52e0a788325dc9ba8499e821885928968c" }, + { file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2c854ce44e1ee31bda4e318af1dbcfc929026d12c5ed030095ad98197eeeaed0" }, + { file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ce8c50520f57ec57aa21a63ea4f325c7b657386b3f02ccaedeccf9ebe27686e1" }, + { file = "coverage-7.4.3-cp38-cp38-win32.whl", hash = "sha256:708a3369dcf055c00ddeeaa2b20f0dd1ce664eeabde6623e516c5228b753654f" }, + { file = "coverage-7.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:1bf25fbca0c8d121a3e92a2a0555c7e5bc981aee5c3fdaf4bb7809f410f696b9" }, + { file = "coverage-7.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b253094dbe1b431d3a4ac2f053b6d7ede2664ac559705a704f621742e034f1f" }, + { file = "coverage-7.4.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:77fbfc5720cceac9c200054b9fab50cb2a7d79660609200ab83f5db96162d20c" }, + { file = "coverage-7.4.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6679060424faa9c11808598504c3ab472de4531c571ab2befa32f4971835788e" }, + { file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4af154d617c875b52651dd8dd17a31270c495082f3d55f6128e7629658d63765" }, + { file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8640f1fde5e1b8e3439fe482cdc2b0bb6c329f4bb161927c28d2e8879c6029ee" }, + { file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:69b9f6f66c0af29642e73a520b6fed25ff9fd69a25975ebe6acb297234eda501" }, + { file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0842571634f39016a6c03e9d4aba502be652a6e4455fadb73cd3a3a49173e38f" }, + { file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a78ed23b08e8ab524551f52953a8a05d61c3a760781762aac49f8de6eede8c45" }, + { file = "coverage-7.4.3-cp39-cp39-win32.whl", hash = "sha256:c0524de3ff096e15fcbfe8f056fdb4ea0bf497d584454f344d59fce069d3e6e9" }, + { file = "coverage-7.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:0209a6369ccce576b43bb227dc8322d8ef9e323d089c6f3f26a597b09cb4d2aa" }, + { file = "coverage-7.4.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:7cbde573904625509a3f37b6fecea974e363460b556a627c60dc2f47e2fffa51" }, + { file = "coverage-7.4.3.tar.gz", hash = "sha256:276f6077a5c61447a48d133ed13e759c09e62aff0dc84274a68dc18660104d52" }, ] [package.dependencies] @@ -581,81 +570,90 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "41.0.7" +version = "42.0.5" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - { file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:3c78451b78313fa81607fa1b3f1ae0a5ddd8014c38a02d9db0616133987b9cdf" }, - { file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:928258ba5d6f8ae644e764d0f996d61a8777559f72dfeb2eea7e2fe0ad6e782d" }, - { file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a1b41bc97f1ad230a41657d9155113c7521953869ae57ac39ac7f1bb471469a" }, - { file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:841df4caa01008bad253bce2a6f7b47f86dc9f08df4b433c404def869f590a15" }, - { file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5429ec739a29df2e29e15d082f1d9ad683701f0ec7709ca479b3ff2708dae65a" }, - { file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:43f2552a2378b44869fe8827aa19e69512e3245a219104438692385b0ee119d1" }, - { file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:af03b32695b24d85a75d40e1ba39ffe7db7ffcb099fe507b39fd41a565f1b157" }, - { file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:49f0805fc0b2ac8d4882dd52f4a3b935b210935d500b6b805f321addc8177406" }, - { file = "cryptography-41.0.7-cp37-abi3-win32.whl", hash = "sha256:f983596065a18a2183e7f79ab3fd4c475205b839e02cbc0efbbf9666c4b3083d" }, - { file = "cryptography-41.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:90452ba79b8788fa380dfb587cca692976ef4e757b194b093d845e8d99f612f2" }, - { file = "cryptography-41.0.7-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:079b85658ea2f59c4f43b70f8119a52414cdb7be34da5d019a77bf96d473b960" }, - { file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:b640981bf64a3e978a56167594a0e97db71c89a479da8e175d8bb5be5178c003" }, - { file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e3114da6d7f95d2dee7d3f4eec16dacff819740bbab931aff8648cb13c5ff5e7" }, - { file = "cryptography-41.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d5ec85080cce7b0513cfd233914eb8b7bbd0633f1d1703aa28d1dd5a72f678ec" }, - { file = "cryptography-41.0.7-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7a698cb1dac82c35fcf8fe3417a3aaba97de16a01ac914b89a0889d364d2f6be" }, - { file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:37a138589b12069efb424220bf78eac59ca68b95696fc622b6ccc1c0a197204a" }, - { file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:68a2dec79deebc5d26d617bfdf6e8aab065a4f34934b22d3b5010df3ba36612c" }, - { file = "cryptography-41.0.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:09616eeaef406f99046553b8a40fbf8b1e70795a91885ba4c96a70793de5504a" }, - { file = "cryptography-41.0.7-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48a0476626da912a44cc078f9893f292f0b3e4c739caf289268168d8f4702a39" }, - { file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c7f3201ec47d5207841402594f1d7950879ef890c0c495052fa62f58283fde1a" }, - { file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c5ca78485a255e03c32b513f8c2bc39fedb7f5c5f8535545bdc223a03b24f248" }, - { file = "cryptography-41.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d6c391c021ab1f7a82da5d8d0b3cee2f4b2c455ec86c8aebbc84837a631ff309" }, - { file = "cryptography-41.0.7.tar.gz", hash = "sha256:13f93ce9bea8016c253b34afc6bd6a75993e5c40672ed5405a9c832f0d4a00bc" }, + { file = "cryptography-42.0.5-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:a30596bae9403a342c978fb47d9b0ee277699fa53bbafad14706af51fe543d16" }, + { file = "cryptography-42.0.5-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:b7ffe927ee6531c78f81aa17e684e2ff617daeba7f189f911065b2ea2d526dec" }, + { file = "cryptography-42.0.5-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2424ff4c4ac7f6b8177b53c17ed5d8fa74ae5955656867f5a8affaca36a27abb" }, + { file = "cryptography-42.0.5-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:329906dcc7b20ff3cad13c069a78124ed8247adcac44b10bea1130e36caae0b4" }, + { file = "cryptography-42.0.5-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:b03c2ae5d2f0fc05f9a2c0c997e1bc18c8229f392234e8a0194f202169ccd278" }, + { file = "cryptography-42.0.5-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f8837fe1d6ac4a8052a9a8ddab256bc006242696f03368a4009be7ee3075cdb7" }, + { file = "cryptography-42.0.5-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:0270572b8bd2c833c3981724b8ee9747b3ec96f699a9665470018594301439ee" }, + { file = "cryptography-42.0.5-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:b8cac287fafc4ad485b8a9b67d0ee80c66bf3574f655d3b97ef2e1082360faf1" }, + { file = "cryptography-42.0.5-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:16a48c23a62a2f4a285699dba2e4ff2d1cff3115b9df052cdd976a18856d8e3d" }, + { file = "cryptography-42.0.5-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2bce03af1ce5a5567ab89bd90d11e7bbdff56b8af3acbbec1faded8f44cb06da" }, + { file = "cryptography-42.0.5-cp37-abi3-win32.whl", hash = "sha256:b6cd2203306b63e41acdf39aa93b86fb566049aeb6dc489b70e34bcd07adca74" }, + { file = "cryptography-42.0.5-cp37-abi3-win_amd64.whl", hash = "sha256:98d8dc6d012b82287f2c3d26ce1d2dd130ec200c8679b6213b3c73c08b2b7940" }, + { file = "cryptography-42.0.5-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:5e6275c09d2badf57aea3afa80d975444f4be8d3bc58f7f80d2a484c6f9485c8" }, + { file = "cryptography-42.0.5-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4985a790f921508f36f81831817cbc03b102d643b5fcb81cd33df3fa291a1a1" }, + { file = "cryptography-42.0.5-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cde5f38e614f55e28d831754e8a3bacf9ace5d1566235e39d91b35502d6936e" }, + { file = "cryptography-42.0.5-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:7367d7b2eca6513681127ebad53b2582911d1736dc2ffc19f2c3ae49997496bc" }, + { file = "cryptography-42.0.5-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cd2030f6650c089aeb304cf093f3244d34745ce0cfcc39f20c6fbfe030102e2a" }, + { file = "cryptography-42.0.5-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a2913c5375154b6ef2e91c10b5720ea6e21007412f6437504ffea2109b5a33d7" }, + { file = "cryptography-42.0.5-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:c41fb5e6a5fe9ebcd58ca3abfeb51dffb5d83d6775405305bfa8715b76521922" }, + { file = "cryptography-42.0.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3eaafe47ec0d0ffcc9349e1708be2aaea4c6dd4978d76bf6eb0cb2c13636c6fc" }, + { file = "cryptography-42.0.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1b95b98b0d2af784078fa69f637135e3c317091b615cd0905f8b8a087e86fa30" }, + { file = "cryptography-42.0.5-cp39-abi3-win32.whl", hash = "sha256:1f71c10d1e88467126f0efd484bd44bca5e14c664ec2ede64c32f20875c0d413" }, + { file = "cryptography-42.0.5-cp39-abi3-win_amd64.whl", hash = "sha256:a011a644f6d7d03736214d38832e030d8268bcff4a41f728e6030325fea3e400" }, + { file = "cryptography-42.0.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9481ffe3cf013b71b2428b905c4f7a9a4f76ec03065b05ff499bb5682a8d9ad8" }, + { file = "cryptography-42.0.5-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:ba334e6e4b1d92442b75ddacc615c5476d4ad55cc29b15d590cc6b86efa487e2" }, + { file = "cryptography-42.0.5-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:ba3e4a42397c25b7ff88cdec6e2a16c2be18720f317506ee25210f6d31925f9c" }, + { file = "cryptography-42.0.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:111a0d8553afcf8eb02a4fea6ca4f59d48ddb34497aa8706a6cf536f1a5ec576" }, + { file = "cryptography-42.0.5-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cd65d75953847815962c84a4654a84850b2bb4aed3f26fadcc1c13892e1e29f6" }, + { file = "cryptography-42.0.5-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:e807b3188f9eb0eaa7bbb579b462c5ace579f1cedb28107ce8b48a9f7ad3679e" }, + { file = "cryptography-42.0.5-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f12764b8fffc7a123f641d7d049d382b73f96a34117e0b637b80643169cec8ac" }, + { file = "cryptography-42.0.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:37dd623507659e08be98eec89323469e8c7b4c1407c85112634ae3dbdb926fdd" }, + { file = "cryptography-42.0.5.tar.gz", hash = "sha256:6fe07eec95dfd477eb9530aef5bead34fec819b3aaf6c5bd6d20565da607bfe1" }, ] [package.dependencies] -cffi = ">=1.12" +cffi = { version = ">=1.12", markers = "platform_python_implementation != \"PyPy\"" } [package.extras] docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] -docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] +docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"] nox = ["nox"] -pep8test = ["black", "check-sdist", "mypy", "ruff"] +pep8test = ["check-sdist", "click", "mypy", "ruff"] sdist = ["build"] ssh = ["bcrypt (>=3.1.5)"] -test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test = ["certifi", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] [[package]] name = "ctranslate2" -version = "3.23.0" +version = "3.24.0" description = "Fast inference engine for Transformer models" optional = false python-versions = ">=3.8" files = [ - { file = "ctranslate2-3.23.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f42013c51599efce30303286022095b084143d5bd45537e1acb36c032c4f683c" }, - { file = "ctranslate2-3.23.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e055981ba85a7a27a125749eee20e1dfa0740af9dd1f771eab5ef8e7af3d6ed7" }, - { file = "ctranslate2-3.23.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b211cd1cc22356c94ae260a11d9274eaed2f331bae91bbe502542edabc9c0bea" }, - { file = "ctranslate2-3.23.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87648abc1026ec9e1657ed88b8407db057c570ecc2ae5dbd321ddec1a21272c6" }, - { file = "ctranslate2-3.23.0-cp310-cp310-win_amd64.whl", hash = "sha256:8d55b4689e866f62095cfed7c79f3ece75a4cba9a193df96129f83f33d049ccc" }, - { file = "ctranslate2-3.23.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc8e7a8900a9911854d4c820badbdff9ffde94e6d853f27f82a282f01f6c61a1" }, - { file = "ctranslate2-3.23.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b974d63c769e2246eb8384613a3a38417c8a47c00db78a972d3435d3fb92d54b" }, - { file = "ctranslate2-3.23.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f9f2554810157ca8a7dcb6da76aa326e0ea7424c8c62cec743d601dae45f051" }, - { file = "ctranslate2-3.23.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf8a0d3085297373208f6e703e096bfd3b19ec80bf133e006fdcd7e88996b11b" }, - { file = "ctranslate2-3.23.0-cp311-cp311-win_amd64.whl", hash = "sha256:9999956b88cdff4d102868b90c5526af3910010db0acd1bdeb3a1b4c1380800d" }, - { file = "ctranslate2-3.23.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a4bea2124f8ad6e3b218612bc40323922001720d2939653ca69a497583f566eb" }, - { file = "ctranslate2-3.23.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:517c40e1d19efd08572549249146af493812e76e05c08d5b5bab5baff09d6403" }, - { file = "ctranslate2-3.23.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71d77e3249ea3e93f72941fb2da118e9b07aab3da3dc339ed17b97a3a10116b9" }, - { file = "ctranslate2-3.23.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46ec9a53ebc1f286d6407694311e9c83b48c42c0a6dff4975610d7d708cbab37" }, - { file = "ctranslate2-3.23.0-cp312-cp312-win_amd64.whl", hash = "sha256:14db7daeee240c71c41e8021d431a865bb25a1f7ec0d1b37a0dd8cc0ecd64cc0" }, - { file = "ctranslate2-3.23.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:aecc6e3944619a72c873d76ef658a44b1b998ecfe4678b1f7fb4190c2fdb3a11" }, - { file = "ctranslate2-3.23.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8603950fb1816e0943b6713dabe0b4e651fbc65addc88fb185dce2bd6d29522f" }, - { file = "ctranslate2-3.23.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a4c465b65697499bb992a2fd00d9957dc5e6baa479c76dc2a5fb2912c2eb28d" }, - { file = "ctranslate2-3.23.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f16d6e283c4b490fc8b847c49d813c541b780c2738243e34b12db96879f3385" }, - { file = "ctranslate2-3.23.0-cp38-cp38-win_amd64.whl", hash = "sha256:bca8e286b0156208656eafedec73896b40318a0be9b925fca7d6bc8dd665827c" }, - { file = "ctranslate2-3.23.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f37424b57f6dc0ebeca513632d10d15608631b2f9ee7410537b8ca96a73e2c30" }, - { file = "ctranslate2-3.23.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:deaa43c1b47e20f2a79f1df699f41de62a881cc860889e027040d14b9b140db6" }, - { file = "ctranslate2-3.23.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c38bdb154e149e954f63aff4d3291d4c8abd7799b2729c5aed533069f8c299b1" }, - { file = "ctranslate2-3.23.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b82e0dfa2ab179f185d0052ee5b1390cc2f7f905f8d9bfbaf736eefc8e5ed182" }, - { file = "ctranslate2-3.23.0-cp39-cp39-win_amd64.whl", hash = "sha256:720d324f4fe2a56148f7a81248d6a703720685462b96d09c6f8c3ae1615f2f24" }, + { file = "ctranslate2-3.24.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1d31fecdc502ea4759313121bd39a6a3e3cd3cbe7e255e133170b040b0d07e61" }, + { file = "ctranslate2-3.24.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf8a85f6b4be1789330ae6d04b954a72a418a097d4bb1d42f0a071d29427a27d" }, + { file = "ctranslate2-3.24.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c25de97fa3ad814845628b8f9fda9931a4e0c8f85731d67eb06a14b21eb0b95" }, + { file = "ctranslate2-3.24.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f66ccf4786be75e5c5244c5f2e4b004bb43dfe8195cf4255233f711099b3d17" }, + { file = "ctranslate2-3.24.0-cp310-cp310-win_amd64.whl", hash = "sha256:d972c229613220d33eb5faabb35c1e063eab885da6264c693aa01d53ad9c5af2" }, + { file = "ctranslate2-3.24.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5407bc1ea857030b86b3d29ecd60cf29949aabfd918c08ea334c9ae5360caeab" }, + { file = "ctranslate2-3.24.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a7c1498dcd42b01743969f3aaef5165d4969d80e969c9571fe9aa78c33c2f89b" }, + { file = "ctranslate2-3.24.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c950c4a832a88109b63995566849debceb3226573047764998ffd8b60c9f635" }, + { file = "ctranslate2-3.24.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17f8a67684404a776cd2961ff98a6aa0b2fe0ec0488b58d903df3ae1cb6136f3" }, + { file = "ctranslate2-3.24.0-cp311-cp311-win_amd64.whl", hash = "sha256:bb54d91826c3de21fda5784661e732fdfb4da6d877e8495b87b2bb7ed6f88123" }, + { file = "ctranslate2-3.24.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1c91a2c7cccb84facd3316496660c89e7116840aee6dd3be1111721f377e07a6" }, + { file = "ctranslate2-3.24.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f564d0b678e29413c3446380faa4568fd346597bb13e4436fa479cce1a151fd" }, + { file = "ctranslate2-3.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0206b791feed6450e172683c117213ed8a1279b9e8067012475f48fcc18df8b8" }, + { file = "ctranslate2-3.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba272a681974f7405f5c16e99303746fdb27c9c2cab4a65f17bfe9408fe22418" }, + { file = "ctranslate2-3.24.0-cp312-cp312-win_amd64.whl", hash = "sha256:8608d290b651b7c9dd007806493d56744697fbfaf1f4e89082805bb0f8179357" }, + { file = "ctranslate2-3.24.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:79d4048c30f81d6fa4b657f0b5d064e1e9470994b055caef1890e13ef9d97703" }, + { file = "ctranslate2-3.24.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bab89046323c61f3ad3ab7b03523ecb32d7ead43df9bd2441daf75613fce8cc4" }, + { file = "ctranslate2-3.24.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f6152b7850fde769444b31d47be464b628fb08927a0d90b2f12582b415dd69a" }, + { file = "ctranslate2-3.24.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c8bab6f09d395851e626f276ccdcb89153c4e6c11ff0d1f4fce3513d3b1da0b" }, + { file = "ctranslate2-3.24.0-cp38-cp38-win_amd64.whl", hash = "sha256:1649f92a65f760f010ebad79b6351063357d3d5c10d4690d664f02ad0166f215" }, + { file = "ctranslate2-3.24.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cd63fbd3e689e815aef33cb3a7813cfa83f8da3f33b5af4c3c7663247c524870" }, + { file = "ctranslate2-3.24.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c91879cd905aa26882708f833e8d3ac24e3622529b62aef5958fa1db4e84bb13" }, + { file = "ctranslate2-3.24.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8ee1541b9ce69c5eebe0f62f34b96c221fa2aed9606b3d824441f8496091b03" }, + { file = "ctranslate2-3.24.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40675f49bc433b3fb00594806b8e9eb83b78782f17f5a5d08caf360c441fcccc" }, + { file = "ctranslate2-3.24.0-cp39-cp39-win_amd64.whl", hash = "sha256:db3cc618b42462b5dc199e60f2f705da0c95c0523c5221059d35e64818b23644" }, ] [package.dependencies] @@ -691,17 +689,18 @@ typing-inspect = ">=0.4.0,<1" [[package]] name = "dill" -version = "0.3.7" +version = "0.3.8" description = "serialize all of Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - { file = "dill-0.3.7-py3-none-any.whl", hash = "sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e" }, - { file = "dill-0.3.7.tar.gz", hash = "sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03" }, + { file = "dill-0.3.8-py3-none-any.whl", hash = "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7" }, + { file = "dill-0.3.8.tar.gz", hash = "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca" }, ] [package.extras] graph = ["objgraph (>=1.7.2)"] +profile = ["gprof2dot (>=2022.7.29)"] [[package]] name = "distlib" @@ -741,18 +740,19 @@ test = ["pytest (>=6)"] [[package]] name = "faster-whisper" -version = "0.10.0" +version = "0.10.1" description = "Faster Whisper transcription with CTranslate2" optional = false python-versions = ">=3.8" files = [ - { file = "faster-whisper-0.10.0.tar.gz", hash = "sha256:591809328b93c8e4594d52097ec6352a270a81fbb7b956254967f28700f7e4da" }, + { file = "faster-whisper-0.10.1.tar.gz", hash = "sha256:48efa06023a2676eaa98254ebfd66ef76fe630918ccf2d02f8d58654ae292675" }, + { file = "faster_whisper-0.10.1-py3-none-any.whl", hash = "sha256:27935ef45598ed53ae954d42e6c696852b4f675daf080cd8d958238136309ff8" }, ] [package.dependencies] av = "==10.*" ctranslate2 = ">=3.22,<4" -huggingface_hub = ">=0.13" +huggingface-hub = ">=0.13" onnxruntime = ">=1.14,<2" tokenizers = ">=0.13,<0.16" @@ -795,24 +795,24 @@ typing = ["typing-extensions (>=4.8)"] [[package]] name = "flatbuffers" -version = "23.5.26" +version = "24.3.7" description = "The FlatBuffers serialization format for Python" optional = false python-versions = "*" files = [ - { file = "flatbuffers-23.5.26-py2.py3-none-any.whl", hash = "sha256:c0ff356da363087b915fde4b8b45bdda73432fc17cddb3c8157472eab1422ad1" }, - { file = "flatbuffers-23.5.26.tar.gz", hash = "sha256:9ea1144cac05ce5d86e2859f431c6cd5e66cd9c78c558317c7955fb8d4c78d89" }, + { file = "flatbuffers-24.3.7-py2.py3-none-any.whl", hash = "sha256:80c4f5dcad0ee76b7e349671a0d657f2fbba927a0244f88dd3f5ed6a3694e1fc" }, + { file = "flatbuffers-24.3.7.tar.gz", hash = "sha256:0895c22b9a6019ff2f4de2e5e2f7cd15914043e6e7033a94c0c6369422690f22" }, ] [[package]] name = "fsspec" -version = "2023.12.2" +version = "2024.2.0" description = "File-system specification" optional = false python-versions = ">=3.8" files = [ - { file = "fsspec-2023.12.2-py3-none-any.whl", hash = "sha256:d800d87f72189a745fa3d6b033b9dc4a34ad069f60ca60b943a63599f5501960" }, - { file = "fsspec-2023.12.2.tar.gz", hash = "sha256:8548d39e8810b59c38014934f6b31e57f40c1b20f911f4cc2b85389c7e9bf0cb" }, + { file = "fsspec-2024.2.0-py3-none-any.whl", hash = "sha256:817f969556fa5916bc682e02ca2045f96ff7f586d45110fcb76022063ad2c7d8" }, + { file = "fsspec-2024.2.0.tar.gz", hash = "sha256:b6ad1a679f760dda52b1168c859d01b7b80648ea6f7f7c7f5a8a91dc3f3ecb84" }, ] [package.extras] @@ -830,7 +830,7 @@ github = ["requests"] gs = ["gcsfs"] gui = ["panel"] hdfs = ["pyarrow (>=1)"] -http = ["aiohttp (!=4.0.0a0,!=4.0.0a1)", "requests"] +http = ["aiohttp (!=4.0.0a0,!=4.0.0a1)"] libarchive = ["libarchive-c"] oci = ["ocifs"] s3 = ["s3fs"] @@ -841,12 +841,13 @@ tqdm = ["tqdm"] [[package]] name = "future" -version = "0.18.3" +version = "1.0.0" description = "Clean single-source support for Python 3 and 2" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" files = [ - { file = "future-0.18.3.tar.gz", hash = "sha256:34a17436ed1e96697a86f9de3d15a3b0be01d8bc8de9c1dffd59fb8234ed5307" }, + { file = "future-1.0.0-py3-none-any.whl", hash = "sha256:929292d34f5872e70396626ef385ec22355a1fae8ad29e1a734c3e43f9fbc216" }, + { file = "future-1.0.0.tar.gz", hash = "sha256:bd2968309307861edae1458a4f8a4f3598c03be43b97521076aebf5d94c07b05" }, ] [[package]] @@ -862,13 +863,13 @@ files = [ [[package]] name = "httpcore" -version = "1.0.2" +version = "1.0.4" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" files = [ - { file = "httpcore-1.0.2-py3-none-any.whl", hash = "sha256:096cc05bca73b8e459a1fc3dcf585148f63e534eae4339559c9b8a8d6399acc7" }, - { file = "httpcore-1.0.2.tar.gz", hash = "sha256:9fc092e4799b26174648e54b74ed5f683132a464e95643b226e00c2ed2fa6535" }, + { file = "httpcore-1.0.4-py3-none-any.whl", hash = "sha256:ac418c1db41bade2ad53ae2f3834a3a0f5ae76b56cf5aa497d2d033384fc7d73" }, + { file = "httpcore-1.0.4.tar.gz", hash = "sha256:cb2839ccfcba0d2d3c1131d3c3e26dfc327326fbe7a5dc0dbfe9f6c9151bb022" }, ] [package.dependencies] @@ -879,17 +880,17 @@ h11 = ">=0.13,<0.15" asyncio = ["anyio (>=4.0,<5.0)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<0.23.0)"] +trio = ["trio (>=0.22.0,<0.25.0)"] [[package]] name = "httpx" -version = "0.26.0" +version = "0.27.0" description = "The next generation HTTP client." optional = false python-versions = ">=3.8" files = [ - { file = "httpx-0.26.0-py3-none-any.whl", hash = "sha256:8915f5a3627c4d47b73e8202457cb28f1266982d1159bd5779d86a80c0eab1cd" }, - { file = "httpx-0.26.0.tar.gz", hash = "sha256:451b55c30d5185ea6b23c2c793abf9bb237d2a7dfb901ced6ff69ad37ec1dfaf" }, + { file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5" }, + { file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5" }, ] [package.dependencies] @@ -907,13 +908,13 @@ socks = ["socksio (==1.*)"] [[package]] name = "huggingface-hub" -version = "0.20.2" +version = "0.21.4" description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub" optional = false python-versions = ">=3.8.0" files = [ - { file = "huggingface_hub-0.20.2-py3-none-any.whl", hash = "sha256:53752eda2239d30a470c307a61cf9adcf136bc77b0a734338c7d04941af560d8" }, - { file = "huggingface_hub-0.20.2.tar.gz", hash = "sha256:215c5fceff631030c7a3d19ba7b588921c908b3f21eef31d160ebc245b200ff6" }, + { file = "huggingface_hub-0.21.4-py3-none-any.whl", hash = "sha256:df37c2c37fc6c82163cdd8a67ede261687d80d1e262526d6c0ce73b6b3630a7b" }, + { file = "huggingface_hub-0.21.4.tar.gz", hash = "sha256:e1f4968c93726565a80edf6dc309763c7b546d0cfe79aa221206034d50155531" }, ] [package.dependencies] @@ -930,11 +931,12 @@ all = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi", cli = ["InquirerPy (==0.3.4)"] dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi", "mypy (==1.5.1)", "numpy", "pydantic (>1.1,<2.0)", "pydantic (>1.1,<3.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.1.3)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] fastai = ["fastai (>=2.4)", "fastcore (>=1.3.27)", "toml"] +hf-transfer = ["hf-transfer (>=0.1.4)"] inference = ["aiohttp", "pydantic (>1.1,<2.0)", "pydantic (>1.1,<3.0)"] quality = ["mypy (==1.5.1)", "ruff (>=0.1.3)"] tensorflow = ["graphviz", "pydot", "tensorflow"] testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi", "numpy", "pydantic (>1.1,<2.0)", "pydantic (>1.1,<3.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"] -torch = ["torch"] +torch = ["safetensors", "torch"] typing = ["types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)"] [[package]] @@ -967,13 +969,13 @@ tests = ["freezegun", "pytest", "pytest-cov"] [[package]] name = "identify" -version = "2.5.33" +version = "2.5.35" description = "File identification library for Python" optional = false python-versions = ">=3.8" files = [ - { file = "identify-2.5.33-py2.py3-none-any.whl", hash = "sha256:d40ce5fcd762817627670da8a7d8d8e65f24342d14539c59488dc603bf662e34" }, - { file = "identify-2.5.33.tar.gz", hash = "sha256:161558f9fe4559e1557e1bff323e8631f6a0e4837f7497767c1782832f16b62d" }, + { file = "identify-2.5.35-py2.py3-none-any.whl", hash = "sha256:c4de0081837b211594f8e877a6b4fad7ca32bbfc1a9307fdd61c28bfe923f13e" }, + { file = "identify-2.5.35.tar.gz", hash = "sha256:10a7ca245cfcd756a554a7288159f72ff105ad233c7c4b9c6f0f4d108f5f6791" }, ] [package.extras] @@ -992,22 +994,22 @@ files = [ [[package]] name = "importlib-metadata" -version = "7.0.1" +version = "7.0.2" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - { file = "importlib_metadata-7.0.1-py3-none-any.whl", hash = "sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e" }, - { file = "importlib_metadata-7.0.1.tar.gz", hash = "sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc" }, + { file = "importlib_metadata-7.0.2-py3-none-any.whl", hash = "sha256:f4bc4c0c070c490abf4ce96d715f68e95923320370efb66143df00199bb6c100" }, + { file = "importlib_metadata-7.0.2.tar.gz", hash = "sha256:198f568f3230878cb1b44fbd7975f87906c22336dba2e4a7f05278c281fbd792" }, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] [[package]] name = "iniconfig" @@ -1036,21 +1038,21 @@ colors = ["colorama (>=0.4.6)"] [[package]] name = "jaraco-classes" -version = "3.3.0" +version = "3.3.1" description = "Utility functions for Python class constructs" optional = false python-versions = ">=3.8" files = [ - { file = "jaraco.classes-3.3.0-py3-none-any.whl", hash = "sha256:10afa92b6743f25c0cf5f37c6bb6e18e2c5bb84a16527ccfc0040ea377e7aaeb" }, - { file = "jaraco.classes-3.3.0.tar.gz", hash = "sha256:c063dd08e89217cee02c8d5e5ec560f2c8ce6cdc2fcdc2e68f7b2e5547ed3621" }, + { file = "jaraco.classes-3.3.1-py3-none-any.whl", hash = "sha256:86b534de565381f6b3c1c830d13f931d7be1a75f0081c57dff615578676e2206" }, + { file = "jaraco.classes-3.3.1.tar.gz", hash = "sha256:cb28a5ebda8bc47d8c8015307d93163464f9f2b91ab4006e09ff0ce07e8bfb30" }, ] [package.dependencies] more-itertools = "*" [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [[package]] name = "jeepney" @@ -1138,35 +1140,32 @@ files = [ [[package]] name = "llvmlite" -version = "0.41.1" +version = "0.42.0" description = "lightweight wrapper around basic LLVM functionality" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - { file = "llvmlite-0.41.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c1e1029d47ee66d3a0c4d6088641882f75b93db82bd0e6178f7bd744ebce42b9" }, - { file = "llvmlite-0.41.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:150d0bc275a8ac664a705135e639178883293cf08c1a38de3bbaa2f693a0a867" }, - { file = "llvmlite-0.41.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1eee5cf17ec2b4198b509272cf300ee6577229d237c98cc6e63861b08463ddc6" }, - { file = "llvmlite-0.41.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dd0338da625346538f1173a17cabf21d1e315cf387ca21b294ff209d176e244" }, - { file = "llvmlite-0.41.1-cp310-cp310-win32.whl", hash = "sha256:fa1469901a2e100c17eb8fe2678e34bd4255a3576d1a543421356e9c14d6e2ae" }, - { file = "llvmlite-0.41.1-cp310-cp310-win_amd64.whl", hash = "sha256:2b76acee82ea0e9304be6be9d4b3840208d050ea0dcad75b1635fa06e949a0ae" }, - { file = "llvmlite-0.41.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:210e458723436b2469d61b54b453474e09e12a94453c97ea3fbb0742ba5a83d8" }, - { file = "llvmlite-0.41.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:855f280e781d49e0640aef4c4af586831ade8f1a6c4df483fb901cbe1a48d127" }, - { file = "llvmlite-0.41.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b67340c62c93a11fae482910dc29163a50dff3dfa88bc874872d28ee604a83be" }, - { file = "llvmlite-0.41.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2181bb63ef3c607e6403813421b46982c3ac6bfc1f11fa16a13eaafb46f578e6" }, - { file = "llvmlite-0.41.1-cp311-cp311-win_amd64.whl", hash = "sha256:9564c19b31a0434f01d2025b06b44c7ed422f51e719ab5d24ff03b7560066c9a" }, - { file = "llvmlite-0.41.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5940bc901fb0325970415dbede82c0b7f3e35c2d5fd1d5e0047134c2c46b3281" }, - { file = "llvmlite-0.41.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8b0a9a47c28f67a269bb62f6256e63cef28d3c5f13cbae4fab587c3ad506778b" }, - { file = "llvmlite-0.41.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8afdfa6da33f0b4226af8e64cfc2b28986e005528fbf944d0a24a72acfc9432" }, - { file = "llvmlite-0.41.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8454c1133ef701e8c050a59edd85d238ee18bb9a0eb95faf2fca8b909ee3c89a" }, - { file = "llvmlite-0.41.1-cp38-cp38-win32.whl", hash = "sha256:2d92c51e6e9394d503033ffe3292f5bef1566ab73029ec853861f60ad5c925d0" }, - { file = "llvmlite-0.41.1-cp38-cp38-win_amd64.whl", hash = "sha256:df75594e5a4702b032684d5481db3af990b69c249ccb1d32687b8501f0689432" }, - { file = "llvmlite-0.41.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:04725975e5b2af416d685ea0769f4ecc33f97be541e301054c9f741003085802" }, - { file = "llvmlite-0.41.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bf14aa0eb22b58c231243dccf7e7f42f7beec48970f2549b3a6acc737d1a4ba4" }, - { file = "llvmlite-0.41.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92c32356f669e036eb01016e883b22add883c60739bc1ebee3a1cc0249a50828" }, - { file = "llvmlite-0.41.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24091a6b31242bcdd56ae2dbea40007f462260bc9bdf947953acc39dffd54f8f" }, - { file = "llvmlite-0.41.1-cp39-cp39-win32.whl", hash = "sha256:880cb57ca49e862e1cd077104375b9d1dfdc0622596dfa22105f470d7bacb309" }, - { file = "llvmlite-0.41.1-cp39-cp39-win_amd64.whl", hash = "sha256:92f093986ab92e71c9ffe334c002f96defc7986efda18397d0f08534f3ebdc4d" }, - { file = "llvmlite-0.41.1.tar.gz", hash = "sha256:f19f767a018e6ec89608e1f6b13348fa2fcde657151137cb64e56d48598a92db" }, + { file = "llvmlite-0.42.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3366938e1bf63d26c34fbfb4c8e8d2ded57d11e0567d5bb243d89aab1eb56098" }, + { file = "llvmlite-0.42.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c35da49666a21185d21b551fc3caf46a935d54d66969d32d72af109b5e7d2b6f" }, + { file = "llvmlite-0.42.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70f44ccc3c6220bd23e0ba698a63ec2a7d3205da0d848804807f37fc243e3f77" }, + { file = "llvmlite-0.42.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:763f8d8717a9073b9e0246998de89929071d15b47f254c10eef2310b9aac033d" }, + { file = "llvmlite-0.42.0-cp310-cp310-win_amd64.whl", hash = "sha256:8d90edf400b4ceb3a0e776b6c6e4656d05c7187c439587e06f86afceb66d2be5" }, + { file = "llvmlite-0.42.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ae511caed28beaf1252dbaf5f40e663f533b79ceb408c874c01754cafabb9cbf" }, + { file = "llvmlite-0.42.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81e674c2fe85576e6c4474e8c7e7aba7901ac0196e864fe7985492b737dbab65" }, + { file = "llvmlite-0.42.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb3975787f13eb97629052edb5017f6c170eebc1c14a0433e8089e5db43bcce6" }, + { file = "llvmlite-0.42.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5bece0cdf77f22379f19b1959ccd7aee518afa4afbd3656c6365865f84903f9" }, + { file = "llvmlite-0.42.0-cp311-cp311-win_amd64.whl", hash = "sha256:7e0c4c11c8c2aa9b0701f91b799cb9134a6a6de51444eff5a9087fc7c1384275" }, + { file = "llvmlite-0.42.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:08fa9ab02b0d0179c688a4216b8939138266519aaa0aa94f1195a8542faedb56" }, + { file = "llvmlite-0.42.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b2fce7d355068494d1e42202c7aff25d50c462584233013eb4470c33b995e3ee" }, + { file = "llvmlite-0.42.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebe66a86dc44634b59a3bc860c7b20d26d9aaffcd30364ebe8ba79161a9121f4" }, + { file = "llvmlite-0.42.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d47494552559e00d81bfb836cf1c4d5a5062e54102cc5767d5aa1e77ccd2505c" }, + { file = "llvmlite-0.42.0-cp312-cp312-win_amd64.whl", hash = "sha256:05cb7e9b6ce69165ce4d1b994fbdedca0c62492e537b0cc86141b6e2c78d5888" }, + { file = "llvmlite-0.42.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bdd3888544538a94d7ec99e7c62a0cdd8833609c85f0c23fcb6c5c591aec60ad" }, + { file = "llvmlite-0.42.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d0936c2067a67fb8816c908d5457d63eba3e2b17e515c5fe00e5ee2bace06040" }, + { file = "llvmlite-0.42.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a78ab89f1924fc11482209f6799a7a3fc74ddc80425a7a3e0e8174af0e9e2301" }, + { file = "llvmlite-0.42.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7599b65c7af7abbc978dbf345712c60fd596aa5670496561cc10e8a71cebfb2" }, + { file = "llvmlite-0.42.0-cp39-cp39-win_amd64.whl", hash = "sha256:43d65cc4e206c2e902c1004dd5418417c4efa6c1d04df05c6c5675a27e8ca90e" }, + { file = "llvmlite-0.42.0.tar.gz", hash = "sha256:f92b09243c0cc3f457da8b983f67bd8e1295d0f5b3746c7a1861d7a99403854a" }, ] [[package]] @@ -1185,22 +1184,21 @@ altgraph = ">=0.17" [[package]] name = "marshmallow" -version = "3.20.1" +version = "3.21.1" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." optional = false python-versions = ">=3.8" files = [ - { file = "marshmallow-3.20.1-py3-none-any.whl", hash = "sha256:684939db93e80ad3561392f47be0230743131560a41c5110684c16e21ade0a5c" }, - { file = "marshmallow-3.20.1.tar.gz", hash = "sha256:5d2371bbe42000f2b3fb5eaa065224df7d8f8597bc19a1bbfa5bfe7fba8da889" }, + { file = "marshmallow-3.21.1-py3-none-any.whl", hash = "sha256:f085493f79efb0644f270a9bf2892843142d80d7174bbbd2f3713f2a589dc633" }, + { file = "marshmallow-3.21.1.tar.gz", hash = "sha256:4e65e9e0d80fc9e609574b9983cf32579f305c718afb30d7233ab818571768c3" }, ] [package.dependencies] packaging = ">=17.0" [package.extras] -dev = ["flake8 (==6.0.0)", "flake8-bugbear (==23.7.10)", "mypy (==1.4.1)", "pre-commit (>=2.4,<4.0)", "pytest", "pytz", "simplejson", "tox"] -docs = ["alabaster (==0.7.13)", "autodocsumm (==0.2.11)", "sphinx (==7.0.1)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"] -lint = ["flake8 (==6.0.0)", "flake8-bugbear (==23.7.10)", "mypy (==1.4.1)", "pre-commit (>=2.4,<4.0)"] +dev = ["marshmallow[tests]", "pre-commit (>=3.5,<4.0)", "tox"] +docs = ["alabaster (==0.7.16)", "autodocsumm (==0.2.12)", "sphinx (==7.2.6)", "sphinx-issues (==4.0.0)", "sphinx-version-warning (==1.1.2)"] tests = ["pytest", "pytz", "simplejson"] [[package]] @@ -1216,13 +1214,13 @@ files = [ [[package]] name = "more-itertools" -version = "10.1.0" +version = "10.2.0" description = "More routines for operating on iterables, beyond itertools" optional = false python-versions = ">=3.8" files = [ - { file = "more-itertools-10.1.0.tar.gz", hash = "sha256:626c369fa0eb37bac0291bce8259b332fd59ac792fa5497b59837309cd5b114a" }, - { file = "more_itertools-10.1.0-py3-none-any.whl", hash = "sha256:64e0735fcfdc6f3464ea133afe8ea4483b1c5fe3a3d69852e6503b43a0b222e6" }, + { file = "more-itertools-10.2.0.tar.gz", hash = "sha256:8fccb480c43d3e99a00087634c06dd02b0d50fbf088b380de5a41a015ec239e1" }, + { file = "more_itertools-10.2.0-py3-none-any.whl", hash = "sha256:686b06abe565edfab151cb8fd385a05651e1fdf8f0a14191e4439283421f8684" }, ] [[package]] @@ -1280,114 +1278,115 @@ setuptools = "*" [[package]] name = "numba" -version = "0.58.1" +version = "0.59.0" description = "compiling Python code using LLVM" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - { file = "numba-0.58.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:07f2fa7e7144aa6f275f27260e73ce0d808d3c62b30cff8906ad1dec12d87bbe" }, - { file = "numba-0.58.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7bf1ddd4f7b9c2306de0384bf3854cac3edd7b4d8dffae2ec1b925e4c436233f" }, - { file = "numba-0.58.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bc2d904d0319d7a5857bd65062340bed627f5bfe9ae4a495aef342f072880d50" }, - { file = "numba-0.58.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4e79b6cc0d2bf064a955934a2e02bf676bc7995ab2db929dbbc62e4c16551be6" }, - { file = "numba-0.58.1-cp310-cp310-win_amd64.whl", hash = "sha256:81fe5b51532478149b5081311b0fd4206959174e660c372b94ed5364cfb37c82" }, - { file = "numba-0.58.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bcecd3fb9df36554b342140a4d77d938a549be635d64caf8bd9ef6c47a47f8aa" }, - { file = "numba-0.58.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a1eaa744f518bbd60e1f7ccddfb8002b3d06bd865b94a5d7eac25028efe0e0ff" }, - { file = "numba-0.58.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bf68df9c307fb0aa81cacd33faccd6e419496fdc621e83f1efce35cdc5e79cac" }, - { file = "numba-0.58.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:55a01e1881120e86d54efdff1be08381886fe9f04fc3006af309c602a72bc44d" }, - { file = "numba-0.58.1-cp311-cp311-win_amd64.whl", hash = "sha256:811305d5dc40ae43c3ace5b192c670c358a89a4d2ae4f86d1665003798ea7a1a" }, - { file = "numba-0.58.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ea5bfcf7d641d351c6a80e8e1826eb4a145d619870016eeaf20bbd71ef5caa22" }, - { file = "numba-0.58.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e63d6aacaae1ba4ef3695f1c2122b30fa3d8ba039c8f517784668075856d79e2" }, - { file = "numba-0.58.1-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6fe7a9d8e3bd996fbe5eac0683227ccef26cba98dae6e5cee2c1894d4b9f16c1" }, - { file = "numba-0.58.1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:898af055b03f09d33a587e9425500e5be84fc90cd2f80b3fb71c6a4a17a7e354" }, - { file = "numba-0.58.1-cp38-cp38-win_amd64.whl", hash = "sha256:d3e2fe81fe9a59fcd99cc572002101119059d64d31eb6324995ee8b0f144a306" }, - { file = "numba-0.58.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c765aef472a9406a97ea9782116335ad4f9ef5c9f93fc05fd44aab0db486954" }, - { file = "numba-0.58.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9e9356e943617f5e35a74bf56ff6e7cc83e6b1865d5e13cee535d79bf2cae954" }, - { file = "numba-0.58.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:240e7a1ae80eb6b14061dc91263b99dc8d6af9ea45d310751b780888097c1aaa" }, - { file = "numba-0.58.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:45698b995914003f890ad839cfc909eeb9c74921849c712a05405d1a79c50f68" }, - { file = "numba-0.58.1-cp39-cp39-win_amd64.whl", hash = "sha256:bd3dda77955be03ff366eebbfdb39919ce7c2620d86c906203bed92124989032" }, - { file = "numba-0.58.1.tar.gz", hash = "sha256:487ded0633efccd9ca3a46364b40006dbdaca0f95e99b8b83e778d1195ebcbaa" }, + { file = "numba-0.59.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8d061d800473fb8fef76a455221f4ad649a53f5e0f96e3f6c8b8553ee6fa98fa" }, + { file = "numba-0.59.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c086a434e7d3891ce5dfd3d1e7ee8102ac1e733962098578b507864120559ceb" }, + { file = "numba-0.59.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9e20736bf62e61f8353fb71b0d3a1efba636c7a303d511600fc57648b55823ed" }, + { file = "numba-0.59.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e86e6786aec31d2002122199486e10bbc0dc40f78d76364cded375912b13614c" }, + { file = "numba-0.59.0-cp310-cp310-win_amd64.whl", hash = "sha256:0307ee91b24500bb7e64d8a109848baf3a3905df48ce142b8ac60aaa406a0400" }, + { file = "numba-0.59.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d540f69a8245fb714419c2209e9af6104e568eb97623adc8943642e61f5d6d8e" }, + { file = "numba-0.59.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1192d6b2906bf3ff72b1d97458724d98860ab86a91abdd4cfd9328432b661e31" }, + { file = "numba-0.59.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:90efb436d3413809fcd15298c6d395cb7d98184350472588356ccf19db9e37c8" }, + { file = "numba-0.59.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cd3dac45e25d927dcb65d44fb3a973994f5add2b15add13337844afe669dd1ba" }, + { file = "numba-0.59.0-cp311-cp311-win_amd64.whl", hash = "sha256:753dc601a159861808cc3207bad5c17724d3b69552fd22768fddbf302a817a4c" }, + { file = "numba-0.59.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ce62bc0e6dd5264e7ff7f34f41786889fa81a6b860662f824aa7532537a7bee0" }, + { file = "numba-0.59.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8cbef55b73741b5eea2dbaf1b0590b14977ca95a13a07d200b794f8f6833a01c" }, + { file = "numba-0.59.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:70d26ba589f764be45ea8c272caa467dbe882b9676f6749fe6f42678091f5f21" }, + { file = "numba-0.59.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e125f7d69968118c28ec0eed9fbedd75440e64214b8d2eac033c22c04db48492" }, + { file = "numba-0.59.0-cp312-cp312-win_amd64.whl", hash = "sha256:4981659220b61a03c1e557654027d271f56f3087448967a55c79a0e5f926de62" }, + { file = "numba-0.59.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe4d7562d1eed754a7511ed7ba962067f198f86909741c5c6e18c4f1819b1f47" }, + { file = "numba-0.59.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6feb1504bb432280f900deaf4b1dadcee68812209500ed3f81c375cbceab24dc" }, + { file = "numba-0.59.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:944faad25ee23ea9dda582bfb0189fb9f4fc232359a80ab2a028b94c14ce2b1d" }, + { file = "numba-0.59.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5516a469514bfae52a9d7989db4940653a5cbfac106f44cb9c50133b7ad6224b" }, + { file = "numba-0.59.0-cp39-cp39-win_amd64.whl", hash = "sha256:32bd0a41525ec0b1b853da244808f4e5333867df3c43c30c33f89cf20b9c2b63" }, + { file = "numba-0.59.0.tar.gz", hash = "sha256:12b9b064a3e4ad00e2371fc5212ef0396c80f41caec9b5ec391c8b04b6eaf2a8" }, ] [package.dependencies] -llvmlite = "==0.41.*" +llvmlite = "==0.42.*" numpy = ">=1.22,<1.27" [[package]] name = "numpy" -version = "1.26.3" +version = "1.26.4" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.9" files = [ - { file = "numpy-1.26.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:806dd64230dbbfaca8a27faa64e2f414bf1c6622ab78cc4264f7f5f028fee3bf" }, - { file = "numpy-1.26.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02f98011ba4ab17f46f80f7f8f1c291ee7d855fcef0a5a98db80767a468c85cd" }, - { file = "numpy-1.26.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d45b3ec2faed4baca41c76617fcdcfa4f684ff7a151ce6fc78ad3b6e85af0a6" }, - { file = "numpy-1.26.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdd2b45bf079d9ad90377048e2747a0c82351989a2165821f0c96831b4a2a54b" }, - { file = "numpy-1.26.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:211ddd1e94817ed2d175b60b6374120244a4dd2287f4ece45d49228b4d529178" }, - { file = "numpy-1.26.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b1240f767f69d7c4c8a29adde2310b871153df9b26b5cb2b54a561ac85146485" }, - { file = "numpy-1.26.3-cp310-cp310-win32.whl", hash = "sha256:21a9484e75ad018974a2fdaa216524d64ed4212e418e0a551a2d83403b0531d3" }, - { file = "numpy-1.26.3-cp310-cp310-win_amd64.whl", hash = "sha256:9e1591f6ae98bcfac2a4bbf9221c0b92ab49762228f38287f6eeb5f3f55905ce" }, - { file = "numpy-1.26.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b831295e5472954104ecb46cd98c08b98b49c69fdb7040483aff799a755a7374" }, - { file = "numpy-1.26.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9e87562b91f68dd8b1c39149d0323b42e0082db7ddb8e934ab4c292094d575d6" }, - { file = "numpy-1.26.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c66d6fec467e8c0f975818c1796d25c53521124b7cfb760114be0abad53a0a2" }, - { file = "numpy-1.26.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f25e2811a9c932e43943a2615e65fc487a0b6b49218899e62e426e7f0a57eeda" }, - { file = "numpy-1.26.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:af36e0aa45e25c9f57bf684b1175e59ea05d9a7d3e8e87b7ae1a1da246f2767e" }, - { file = "numpy-1.26.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:51c7f1b344f302067b02e0f5b5d2daa9ed4a721cf49f070280ac202738ea7f00" }, - { file = "numpy-1.26.3-cp311-cp311-win32.whl", hash = "sha256:7ca4f24341df071877849eb2034948459ce3a07915c2734f1abb4018d9c49d7b" }, - { file = "numpy-1.26.3-cp311-cp311-win_amd64.whl", hash = "sha256:39763aee6dfdd4878032361b30b2b12593fb445ddb66bbac802e2113eb8a6ac4" }, - { file = "numpy-1.26.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a7081fd19a6d573e1a05e600c82a1c421011db7935ed0d5c483e9dd96b99cf13" }, - { file = "numpy-1.26.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12c70ac274b32bc00c7f61b515126c9205323703abb99cd41836e8125ea0043e" }, - { file = "numpy-1.26.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f784e13e598e9594750b2ef6729bcd5a47f6cfe4a12cca13def35e06d8163e3" }, - { file = "numpy-1.26.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f24750ef94d56ce6e33e4019a8a4d68cfdb1ef661a52cdaee628a56d2437419" }, - { file = "numpy-1.26.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:77810ef29e0fb1d289d225cabb9ee6cf4d11978a00bb99f7f8ec2132a84e0166" }, - { file = "numpy-1.26.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8ed07a90f5450d99dad60d3799f9c03c6566709bd53b497eb9ccad9a55867f36" }, - { file = "numpy-1.26.3-cp312-cp312-win32.whl", hash = "sha256:f73497e8c38295aaa4741bdfa4fda1a5aedda5473074369eca10626835445511" }, - { file = "numpy-1.26.3-cp312-cp312-win_amd64.whl", hash = "sha256:da4b0c6c699a0ad73c810736303f7fbae483bcb012e38d7eb06a5e3b432c981b" }, - { file = "numpy-1.26.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1666f634cb3c80ccbd77ec97bc17337718f56d6658acf5d3b906ca03e90ce87f" }, - { file = "numpy-1.26.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:18c3319a7d39b2c6a9e3bb75aab2304ab79a811ac0168a671a62e6346c29b03f" }, - { file = "numpy-1.26.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b7e807d6888da0db6e7e75838444d62495e2b588b99e90dd80c3459594e857b" }, - { file = "numpy-1.26.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4d362e17bcb0011738c2d83e0a65ea8ce627057b2fdda37678f4374a382a137" }, - { file = "numpy-1.26.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b8c275f0ae90069496068c714387b4a0eba5d531aace269559ff2b43655edd58" }, - { file = "numpy-1.26.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cc0743f0302b94f397a4a65a660d4cd24267439eb16493fb3caad2e4389bccbb" }, - { file = "numpy-1.26.3-cp39-cp39-win32.whl", hash = "sha256:9bc6d1a7f8cedd519c4b7b1156d98e051b726bf160715b769106661d567b3f03" }, - { file = "numpy-1.26.3-cp39-cp39-win_amd64.whl", hash = "sha256:867e3644e208c8922a3be26fc6bbf112a035f50f0a86497f98f228c50c607bb2" }, - { file = "numpy-1.26.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3c67423b3703f8fbd90f5adaa37f85b5794d3366948efe9a5190a5f3a83fc34e" }, - { file = "numpy-1.26.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46f47ee566d98849323f01b349d58f2557f02167ee301e5e28809a8c0e27a2d0" }, - { file = "numpy-1.26.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a8474703bffc65ca15853d5fd4d06b18138ae90c17c8d12169968e998e448bb5" }, - { file = "numpy-1.26.3.tar.gz", hash = "sha256:697df43e2b6310ecc9d95f05d5ef20eacc09c7c4ecc9da3f235d39e71b7da1e4" }, + { file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0" }, + { file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a" }, + { file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4" }, + { file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f" }, + { file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a" }, + { file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2" }, + { file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07" }, + { file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5" }, + { file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71" }, + { file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef" }, + { file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e" }, + { file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5" }, + { file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a" }, + { file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a" }, + { file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20" }, + { file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2" }, + { file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218" }, + { file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b" }, + { file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b" }, + { file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed" }, + { file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a" }, + { file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0" }, + { file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110" }, + { file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818" }, + { file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c" }, + { file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be" }, + { file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764" }, + { file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3" }, + { file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd" }, + { file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c" }, + { file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6" }, + { file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea" }, + { file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30" }, + { file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c" }, + { file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0" }, + { file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010" }, ] [[package]] name = "onnxruntime" -version = "1.16.3" +version = "1.17.1" description = "ONNX Runtime is a runtime accelerator for Machine Learning models" optional = false python-versions = "*" files = [ - { file = "onnxruntime-1.16.3-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:3bc41f323ac77acfed190be8ffdc47a6a75e4beeb3473fbf55eeb075ccca8df2" }, - { file = "onnxruntime-1.16.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:212741b519ee61a4822c79c47147d63a8b0ffde25cd33988d3d7be9fbd51005d" }, - { file = "onnxruntime-1.16.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f91f5497fe3df4ceee2f9e66c6148d9bfeb320cd6a71df361c66c5b8bac985a" }, - { file = "onnxruntime-1.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef2b1fc269cabd27f129fb9058917d6fdc89b188c49ed8700f300b945c81f889" }, - { file = "onnxruntime-1.16.3-cp310-cp310-win32.whl", hash = "sha256:f36b56a593b49a3c430be008c2aea6658d91a3030115729609ec1d5ffbaab1b6" }, - { file = "onnxruntime-1.16.3-cp310-cp310-win_amd64.whl", hash = "sha256:3c467eaa3d2429c026b10c3d17b78b7f311f718ef9d2a0d6938e5c3c2611b0cf" }, - { file = "onnxruntime-1.16.3-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:a225bb683991001d111f75323d355b3590e75e16b5e0f07a0401e741a0143ea1" }, - { file = "onnxruntime-1.16.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9aded21fe3d898edd86be8aa2eb995aa375e800ad3dfe4be9f618a20b8ee3630" }, - { file = "onnxruntime-1.16.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00cccc37a5195c8fca5011b9690b349db435986bd508eb44c9fce432da9228a4" }, - { file = "onnxruntime-1.16.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e253e572021563226a86f1c024f8f70cdae28f2fb1cc8c3a9221e8b1ce37db5" }, - { file = "onnxruntime-1.16.3-cp311-cp311-win32.whl", hash = "sha256:a82a8f0b4c978d08f9f5c7a6019ae51151bced9fd91e5aaa0c20a9e4ac7a60b6" }, - { file = "onnxruntime-1.16.3-cp311-cp311-win_amd64.whl", hash = "sha256:78d81d9af457a1dc90db9a7da0d09f3ccb1288ea1236c6ab19f0ca61f3eee2d3" }, - { file = "onnxruntime-1.16.3-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:04ebcd29c20473596a1412e471524b2fb88d55e6301c40b98dd2407b5911595f" }, - { file = "onnxruntime-1.16.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9996bab0f202a6435ab867bc55598f15210d0b72794d5de83712b53d564084ae" }, - { file = "onnxruntime-1.16.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b8f5083f903408238883821dd8c775f8120cb4a604166dbdabe97f4715256d5" }, - { file = "onnxruntime-1.16.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c2dcf1b70f8434abb1116fe0975c00e740722aaf321997195ea3618cc00558e" }, - { file = "onnxruntime-1.16.3-cp38-cp38-win32.whl", hash = "sha256:d4a0151e1accd04da6711f6fd89024509602f82c65a754498e960b032359b02d" }, - { file = "onnxruntime-1.16.3-cp38-cp38-win_amd64.whl", hash = "sha256:e8aa5bba78afbd4d8a2654b14ec7462ff3ce4a6aad312a3c2d2c2b65009f2541" }, - { file = "onnxruntime-1.16.3-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:6829dc2a79d48c911fedaf4c0f01e03c86297d32718a3fdee7a282766dfd282a" }, - { file = "onnxruntime-1.16.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:76f876c53bfa912c6c242fc38213a6f13f47612d4360bc9d599bd23753e53161" }, - { file = "onnxruntime-1.16.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4137e5d443e2dccebe5e156a47f1d6d66f8077b03587c35f11ee0c7eda98b533" }, - { file = "onnxruntime-1.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c56695c1a343c7c008b647fff3df44da63741fbe7b6003ef576758640719be7b" }, - { file = "onnxruntime-1.16.3-cp39-cp39-win32.whl", hash = "sha256:985a029798744ce4743fcf8442240fed35c8e4d4d30ec7d0c2cdf1388cd44408" }, - { file = "onnxruntime-1.16.3-cp39-cp39-win_amd64.whl", hash = "sha256:28ff758b17ce3ca6bcad3d936ec53bd7f5482e7630a13f6dcae518eba8f71d85" }, + { file = "onnxruntime-1.17.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:d43ac17ac4fa3c9096ad3c0e5255bb41fd134560212dc124e7f52c3159af5d21" }, + { file = "onnxruntime-1.17.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:55b5e92a4c76a23981c998078b9bf6145e4fb0b016321a8274b1607bd3c6bd35" }, + { file = "onnxruntime-1.17.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ebbcd2bc3a066cf54e6f18c75708eb4d309ef42be54606d22e5bdd78afc5b0d7" }, + { file = "onnxruntime-1.17.1-cp310-cp310-win32.whl", hash = "sha256:5e3716b5eec9092e29a8d17aab55e737480487deabfca7eac3cd3ed952b6ada9" }, + { file = "onnxruntime-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:fbb98cced6782ae1bb799cc74ddcbbeeae8819f3ad1d942a74d88e72b6511337" }, + { file = "onnxruntime-1.17.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:36fd6f87a1ecad87e9c652e42407a50fb305374f9a31d71293eb231caae18784" }, + { file = "onnxruntime-1.17.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99a8bddeb538edabc524d468edb60ad4722cff8a49d66f4e280c39eace70500b" }, + { file = "onnxruntime-1.17.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd7fddb4311deb5a7d3390cd8e9b3912d4d963efbe4dfe075edbaf18d01c024e" }, + { file = "onnxruntime-1.17.1-cp311-cp311-win32.whl", hash = "sha256:606a7cbfb6680202b0e4f1890881041ffc3ac6e41760a25763bd9fe146f0b335" }, + { file = "onnxruntime-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:53e4e06c0a541696ebdf96085fd9390304b7b04b748a19e02cf3b35c869a1e76" }, + { file = "onnxruntime-1.17.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:40f08e378e0f85929712a2b2c9b9a9cc400a90c8a8ca741d1d92c00abec60843" }, + { file = "onnxruntime-1.17.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac79da6d3e1bb4590f1dad4bb3c2979d7228555f92bb39820889af8b8e6bd472" }, + { file = "onnxruntime-1.17.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ae9ba47dc099004e3781f2d0814ad710a13c868c739ab086fc697524061695ea" }, + { file = "onnxruntime-1.17.1-cp312-cp312-win32.whl", hash = "sha256:2dff1a24354220ac30e4a4ce2fb1df38cb1ea59f7dac2c116238d63fe7f4c5ff" }, + { file = "onnxruntime-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:6226a5201ab8cafb15e12e72ff2a4fc8f50654e8fa5737c6f0bd57c5ff66827e" }, + { file = "onnxruntime-1.17.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:cd0c07c0d1dfb8629e820b05fda5739e4835b3b82faf43753d2998edf2cf00aa" }, + { file = "onnxruntime-1.17.1-cp38-cp38-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:617ebdf49184efa1ba6e4467e602fbfa029ed52c92f13ce3c9f417d303006381" }, + { file = "onnxruntime-1.17.1-cp38-cp38-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9dae9071e3facdf2920769dceee03b71c684b6439021defa45b830d05e148924" }, + { file = "onnxruntime-1.17.1-cp38-cp38-win32.whl", hash = "sha256:835d38fa1064841679433b1aa8138b5e1218ddf0cfa7a3ae0d056d8fd9cec713" }, + { file = "onnxruntime-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:96621e0c555c2453bf607606d08af3f70fbf6f315230c28ddea91754e17ad4e6" }, + { file = "onnxruntime-1.17.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:7a9539935fb2d78ebf2cf2693cad02d9930b0fb23cdd5cf37a7df813e977674d" }, + { file = "onnxruntime-1.17.1-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:45c6a384e9d9a29c78afff62032a46a993c477b280247a7e335df09372aedbe9" }, + { file = "onnxruntime-1.17.1-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4e19f966450f16863a1d6182a685ca33ae04d7772a76132303852d05b95411ea" }, + { file = "onnxruntime-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e2ae712d64a42aac29ed7a40a426cb1e624a08cfe9273dcfe681614aa65b07dc" }, + { file = "onnxruntime-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:f7e9f7fb049825cdddf4a923cfc7c649d84d63c0134315f8e0aa9e0c3004672c" }, ] [package.dependencies] @@ -1400,13 +1399,13 @@ sympy = "*" [[package]] name = "openai" -version = "1.6.1" +version = "1.14.0" description = "The official Python library for the openai API" optional = false python-versions = ">=3.7.1" files = [ - { file = "openai-1.6.1-py3-none-any.whl", hash = "sha256:bc9f774838d67ac29fb24cdeb2d58faf57de8b311085dcd1348f7aa02a96c7ee" }, - { file = "openai-1.6.1.tar.gz", hash = "sha256:d553ca9dbf9486b08e75b09e8671e4f638462aaadccfced632bf490fc3d75fa2" }, + { file = "openai-1.14.0-py3-none-any.whl", hash = "sha256:5c9fd3a59f5cbdb4020733ddf79a22f6b7a36d561968cb3f3dd255cdd263d9fe" }, + { file = "openai-1.14.0.tar.gz", hash = "sha256:e287057adf0ec3315abc32ddcc968d095879abd9b68bf51c0402dab13ab5ae9b" }, ] [package.dependencies] @@ -1438,20 +1437,20 @@ numpy = "*" tiktoken = "*" torch = "*" tqdm = "*" -triton = { version = "2.0.0", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" } +triton = { version = ">=2.0.0,<3", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" } [package.extras] dev = ["black", "flake8", "isort", "pytest", "scipy"] [[package]] name = "packaging" -version = "23.2" +version = "24.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.7" files = [ - { file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" }, - { file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5" }, + { file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5" }, + { file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9" }, ] [[package]] @@ -1482,13 +1481,13 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-co [[package]] name = "pluggy" -version = "1.3.0" +version = "1.4.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" files = [ - { file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7" }, - { file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12" }, + { file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981" }, + { file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be" }, ] [package.extras] @@ -1515,22 +1514,22 @@ virtualenv = ">=20.10.0" [[package]] name = "protobuf" -version = "4.25.1" +version = "5.26.0" description = "" optional = false python-versions = ">=3.8" files = [ - { file = "protobuf-4.25.1-cp310-abi3-win32.whl", hash = "sha256:193f50a6ab78a970c9b4f148e7c750cfde64f59815e86f686c22e26b4fe01ce7" }, - { file = "protobuf-4.25.1-cp310-abi3-win_amd64.whl", hash = "sha256:3497c1af9f2526962f09329fd61a36566305e6c72da2590ae0d7d1322818843b" }, - { file = "protobuf-4.25.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:0bf384e75b92c42830c0a679b0cd4d6e2b36ae0cf3dbb1e1dfdda48a244f4bcd" }, - { file = "protobuf-4.25.1-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:0f881b589ff449bf0b931a711926e9ddaad3b35089cc039ce1af50b21a4ae8cb" }, - { file = "protobuf-4.25.1-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:ca37bf6a6d0046272c152eea90d2e4ef34593aaa32e8873fc14c16440f22d4b7" }, - { file = "protobuf-4.25.1-cp38-cp38-win32.whl", hash = "sha256:abc0525ae2689a8000837729eef7883b9391cd6aa7950249dcf5a4ede230d5dd" }, - { file = "protobuf-4.25.1-cp38-cp38-win_amd64.whl", hash = "sha256:1484f9e692091450e7edf418c939e15bfc8fc68856e36ce399aed6889dae8bb0" }, - { file = "protobuf-4.25.1-cp39-cp39-win32.whl", hash = "sha256:8bdbeaddaac52d15c6dce38c71b03038ef7772b977847eb6d374fc86636fa510" }, - { file = "protobuf-4.25.1-cp39-cp39-win_amd64.whl", hash = "sha256:becc576b7e6b553d22cbdf418686ee4daa443d7217999125c045ad56322dda10" }, - { file = "protobuf-4.25.1-py3-none-any.whl", hash = "sha256:a19731d5e83ae4737bb2a089605e636077ac001d18781b3cf489b9546c7c80d6" }, - { file = "protobuf-4.25.1.tar.gz", hash = "sha256:57d65074b4f5baa4ab5da1605c02be90ac20c8b40fb137d6a8df9f416b0d0ce2" }, + { file = "protobuf-5.26.0-cp310-abi3-win32.whl", hash = "sha256:f9ecc8eb6f18037e0cbf43256db0325d4723f429bca7ef5cd358b7c29d65f628" }, + { file = "protobuf-5.26.0-cp310-abi3-win_amd64.whl", hash = "sha256:dfd29f6eb34107dccf289a93d44fb6b131e68888d090b784b691775ac84e8213" }, + { file = "protobuf-5.26.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:7e47c57303466c867374a17b2b5e99c5a7c8b72a94118e2f28efb599f19b4069" }, + { file = "protobuf-5.26.0-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:e184175276edc222e2d5e314a72521e10049938a9a4961fe4bea9b25d073c03f" }, + { file = "protobuf-5.26.0-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:6ee9d1aa02f951c5ce10bf8c6cfb7604133773038e33f913183c8b5201350600" }, + { file = "protobuf-5.26.0-cp38-cp38-win32.whl", hash = "sha256:2c334550e1cb4efac5c8a3987384bf13a4334abaf5ab59e40479e7b70ecd6b19" }, + { file = "protobuf-5.26.0-cp38-cp38-win_amd64.whl", hash = "sha256:8eef61a90631c21b06b4f492a27e199a269827f046de3bb68b61aa84fcf50905" }, + { file = "protobuf-5.26.0-cp39-cp39-win32.whl", hash = "sha256:ca825f4eecb8c342d2ec581e6a5ad1ad1a47bededaecd768e0d3451ae4aaac2b" }, + { file = "protobuf-5.26.0-cp39-cp39-win_amd64.whl", hash = "sha256:efd4f5894c50bd76cbcfdd668cd941021333861ed0f441c78a83d8254a01cc9f" }, + { file = "protobuf-5.26.0-py3-none-any.whl", hash = "sha256:a49b6c5359bf34fb7bf965bf21abfab4476e4527d822ab5289ee3bf73f291159" }, + { file = "protobuf-5.26.0.tar.gz", hash = "sha256:82f5870d74c99addfe4152777bdf8168244b9cf0ac65f8eccf045ddfa9d80d9b" }, ] [[package]] @@ -1568,59 +1567,59 @@ files = [ [[package]] name = "pycryptodomex" -version = "3.19.1" +version = "3.20.0" description = "Cryptographic library for Python" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ - { file = "pycryptodomex-3.19.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b5c336dc698650283ad06f8c0237a984087d0af9f403ff21d633507335628156" }, - { file = "pycryptodomex-3.19.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:c9cb88ed323be1aa642b3c17cd5caa1a03c3a8fbad092d48ecefe88e328ffae3" }, - { file = "pycryptodomex-3.19.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:0b42e2743893f386dfb58fe24a4c8be5305c3d1c825d5f23d9e63fd0700d1110" }, - { file = "pycryptodomex-3.19.1-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:10c2eed4efdfa084b602ab922e699a0a2ba82053baebfc8afcaf27489def7955" }, - { file = "pycryptodomex-3.19.1-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:e94a7e986b117b72e9472f8eafdd81748dafff30815401f9760f759f1debe9ef" }, - { file = "pycryptodomex-3.19.1-cp27-cp27m-win32.whl", hash = "sha256:23707238b024b36c35dd3428f5af6c1f0c5ef54c21e387a2063633717699b8b2" }, - { file = "pycryptodomex-3.19.1-cp27-cp27m-win_amd64.whl", hash = "sha256:c1ae2fb8d5d6771670436dcc889b293e363c97647a6d31c21eebc12b7b760010" }, - { file = "pycryptodomex-3.19.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:d7a77391fd351ff1bdf8475558ddc6e92950218cb905419ee14aa02f370f1054" }, - { file = "pycryptodomex-3.19.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:c9332b04bf3f838327087b028f690f4ddb9341eb014a0221e79b9c19a77f7555" }, - { file = "pycryptodomex-3.19.1-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:beb5f0664f49b6093da179ee8e27c1d670779f50b9ece0886ce491bb8bd63728" }, - { file = "pycryptodomex-3.19.1-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:d45d0d35a238d838b872598fa865bbfb31aaef9aeeda77c68b04ef79f9a469dc" }, - { file = "pycryptodomex-3.19.1-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:ed3bdda44cc05dd13eee697ab9bea6928531bb7b218e68e66d0d3eb2ebab043e" }, - { file = "pycryptodomex-3.19.1-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ae75eea2e908383fd4c659fdcfe9621a72869e3e3ee73904227e93b7f7b80b54" }, - { file = "pycryptodomex-3.19.1-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:371bbe0be17b4dd8cc0c2f378d75ea33f00d5a39884c09a672016ac40145a5fa" }, - { file = "pycryptodomex-3.19.1-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96000b837bcd8e3bf86b419924a056c978e45027281e4318650c81c25a3ef6cc" }, - { file = "pycryptodomex-3.19.1-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:011e859026ecbd15b8e720e8992361186e582cf726c50bde6ff8c0c05e820ddf" }, - { file = "pycryptodomex-3.19.1-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:76414d39df6b45bcc4f38cf1ba2031e0f4b8e99d1ba3c2eee31ffe1b9f039733" }, - { file = "pycryptodomex-3.19.1-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:1c04cfff163c05d033bf28e3c4429d8222796738c7b6c1638b9d7090b904611e" }, - { file = "pycryptodomex-3.19.1-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:de5a43901e47e7a6938490fc5de3074f6e35c8b481a75b227c0d24d6099bd41d" }, - { file = "pycryptodomex-3.19.1-cp35-abi3-win32.whl", hash = "sha256:f24f49fc6bd706d87048654d6be6c7c967d6836d4879e3a7c439275fab9948ad" }, - { file = "pycryptodomex-3.19.1-cp35-abi3-win_amd64.whl", hash = "sha256:f8b3d9e7c17c1ffc1fa5b11c0bbab8a5df3de8596bb32ad30281b21e5ede4bf5" }, - { file = "pycryptodomex-3.19.1-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:ac562e239d98cfef763866c0aee4586affb0d58c592202f06c87241af99db241" }, - { file = "pycryptodomex-3.19.1-pp27-pypy_73-win32.whl", hash = "sha256:39eb1f82ac3ba3e39d866f38e480e8fa53fcdd22260340f05f54a8188d47d510" }, - { file = "pycryptodomex-3.19.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0bc4b7bfaac56e6dfd62044847443a3d110c7abea7fcb0d68c1aea64ed3a6697" }, - { file = "pycryptodomex-3.19.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dffe067d5fff14dba4d18ff7d459cc2a47576d82dafbff13a8f1199c3353e41" }, - { file = "pycryptodomex-3.19.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aab7941c2ff53eb63cb26252770e4f14386d79ce07baeffbf98a1323c1646545" }, - { file = "pycryptodomex-3.19.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3f3c58971784fba0e014bc3f8aed1197b86719631e1b597d36d7354be5598312" }, - { file = "pycryptodomex-3.19.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5ca98de2e5ac100e57a7116309723360e8f799f722509e376dc396cdf65eec9c" }, - { file = "pycryptodomex-3.19.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8a97b1acd36e9ce9d4067d94a8be99c458f0eb8070828639302a95cfcf0770b" }, - { file = "pycryptodomex-3.19.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62f51a63d73153482729904381dd2de86800b0733a8814ee8f072fa73e5c92fb" }, - { file = "pycryptodomex-3.19.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:9919a1edd2a83c4dfb69f1d8a4c0c5efde7147ef15b07775633372b80c90b5d8" }, - { file = "pycryptodomex-3.19.1.tar.gz", hash = "sha256:0b7154aff2272962355f8941fd514104a88cb29db2d8f43a29af900d6398eb1c" }, + { file = "pycryptodomex-3.20.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:645bd4ca6f543685d643dadf6a856cc382b654cc923460e3a10a49c1b3832aeb" }, + { file = "pycryptodomex-3.20.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ff5c9a67f8a4fba4aed887216e32cbc48f2a6fb2673bb10a99e43be463e15913" }, + { file = "pycryptodomex-3.20.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:8ee606964553c1a0bc74057dd8782a37d1c2bc0f01b83193b6f8bb14523b877b" }, + { file = "pycryptodomex-3.20.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7805830e0c56d88f4d491fa5ac640dfc894c5ec570d1ece6ed1546e9df2e98d6" }, + { file = "pycryptodomex-3.20.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:bc3ee1b4d97081260d92ae813a83de4d2653206967c4a0a017580f8b9548ddbc" }, + { file = "pycryptodomex-3.20.0-cp27-cp27m-win32.whl", hash = "sha256:8af1a451ff9e123d0d8bd5d5e60f8e3315c3a64f3cdd6bc853e26090e195cdc8" }, + { file = "pycryptodomex-3.20.0-cp27-cp27m-win_amd64.whl", hash = "sha256:cbe71b6712429650e3883dc81286edb94c328ffcd24849accac0a4dbcc76958a" }, + { file = "pycryptodomex-3.20.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:76bd15bb65c14900d98835fcd10f59e5e0435077431d3a394b60b15864fddd64" }, + { file = "pycryptodomex-3.20.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:653b29b0819605fe0898829c8ad6400a6ccde096146730c2da54eede9b7b8baa" }, + { file = "pycryptodomex-3.20.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62a5ec91388984909bb5398ea49ee61b68ecb579123694bffa172c3b0a107079" }, + { file = "pycryptodomex-3.20.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:108e5f1c1cd70ffce0b68739c75734437c919d2eaec8e85bffc2c8b4d2794305" }, + { file = "pycryptodomex-3.20.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:59af01efb011b0e8b686ba7758d59cf4a8263f9ad35911bfe3f416cee4f5c08c" }, + { file = "pycryptodomex-3.20.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:82ee7696ed8eb9a82c7037f32ba9b7c59e51dda6f105b39f043b6ef293989cb3" }, + { file = "pycryptodomex-3.20.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91852d4480a4537d169c29a9d104dda44094c78f1f5b67bca76c29a91042b623" }, + { file = "pycryptodomex-3.20.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca649483d5ed251d06daf25957f802e44e6bb6df2e8f218ae71968ff8f8edc4" }, + { file = "pycryptodomex-3.20.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e186342cfcc3aafaad565cbd496060e5a614b441cacc3995ef0091115c1f6c5" }, + { file = "pycryptodomex-3.20.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:25cd61e846aaab76d5791d006497134602a9e451e954833018161befc3b5b9ed" }, + { file = "pycryptodomex-3.20.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:9c682436c359b5ada67e882fec34689726a09c461efd75b6ea77b2403d5665b7" }, + { file = "pycryptodomex-3.20.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:7a7a8f33a1f1fb762ede6cc9cbab8f2a9ba13b196bfaf7bc6f0b39d2ba315a43" }, + { file = "pycryptodomex-3.20.0-cp35-abi3-win32.whl", hash = "sha256:c39778fd0548d78917b61f03c1fa8bfda6cfcf98c767decf360945fe6f97461e" }, + { file = "pycryptodomex-3.20.0-cp35-abi3-win_amd64.whl", hash = "sha256:2a47bcc478741b71273b917232f521fd5704ab4b25d301669879e7273d3586cc" }, + { file = "pycryptodomex-3.20.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:1be97461c439a6af4fe1cf8bf6ca5936d3db252737d2f379cc6b2e394e12a458" }, + { file = "pycryptodomex-3.20.0-pp27-pypy_73-win32.whl", hash = "sha256:19764605feea0df966445d46533729b645033f134baeb3ea26ad518c9fdf212c" }, + { file = "pycryptodomex-3.20.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f2e497413560e03421484189a6b65e33fe800d3bd75590e6d78d4dfdb7accf3b" }, + { file = "pycryptodomex-3.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e48217c7901edd95f9f097feaa0388da215ed14ce2ece803d3f300b4e694abea" }, + { file = "pycryptodomex-3.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d00fe8596e1cc46b44bf3907354e9377aa030ec4cd04afbbf6e899fc1e2a7781" }, + { file = "pycryptodomex-3.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:88afd7a3af7ddddd42c2deda43d53d3dfc016c11327d0915f90ca34ebda91499" }, + { file = "pycryptodomex-3.20.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d3584623e68a5064a04748fb6d76117a21a7cb5eaba20608a41c7d0c61721794" }, + { file = "pycryptodomex-3.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0daad007b685db36d977f9de73f61f8da2a7104e20aca3effd30752fd56f73e1" }, + { file = "pycryptodomex-3.20.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5dcac11031a71348faaed1f403a0debd56bf5404232284cf8c761ff918886ebc" }, + { file = "pycryptodomex-3.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:69138068268127cd605e03438312d8f271135a33140e2742b417d027a0539427" }, + { file = "pycryptodomex-3.20.0.tar.gz", hash = "sha256:7a710b79baddd65b806402e14766c721aee8fb83381769c27920f26476276c1e" }, ] [[package]] name = "pydantic" -version = "2.5.3" +version = "2.6.4" description = "Data validation using Python type hints" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - { file = "pydantic-2.5.3-py3-none-any.whl", hash = "sha256:d0caf5954bee831b6bfe7e338c32b9e30c85dfe080c843680783ac2b631673b4" }, - { file = "pydantic-2.5.3.tar.gz", hash = "sha256:b3ef57c62535b0941697cce638c08900d87fcb67e29cfa99e8a68f747f393f7a" }, + { file = "pydantic-2.6.4-py3-none-any.whl", hash = "sha256:cc46fce86607580867bdc3361ad462bab9c222ef042d3da86f2fb333e1d916c5" }, + { file = "pydantic-2.6.4.tar.gz", hash = "sha256:b1704e0847db01817624a6b86766967f552dd9dbf3afba4004409f908dcc84e6" }, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.14.6" +pydantic-core = "2.16.3" typing-extensions = ">=4.6.1" [package.extras] @@ -1628,116 +1627,90 @@ email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.14.6" +version = "2.16.3" description = "" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - { file = "pydantic_core-2.14.6-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:72f9a942d739f09cd42fffe5dc759928217649f070056f03c70df14f5770acf9" }, - { file = "pydantic_core-2.14.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6a31d98c0d69776c2576dda4b77b8e0c69ad08e8b539c25c7d0ca0dc19a50d6c" }, - { file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5aa90562bc079c6c290f0512b21768967f9968e4cfea84ea4ff5af5d917016e4" }, - { file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:370ffecb5316ed23b667d99ce4debe53ea664b99cc37bfa2af47bc769056d534" }, - { file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f85f3843bdb1fe80e8c206fe6eed7a1caeae897e496542cee499c374a85c6e08" }, - { file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9862bf828112e19685b76ca499b379338fd4c5c269d897e218b2ae8fcb80139d" }, - { file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:036137b5ad0cb0004c75b579445a1efccd072387a36c7f217bb8efd1afbe5245" }, - { file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92879bce89f91f4b2416eba4429c7b5ca22c45ef4a499c39f0c5c69257522c7c" }, - { file = "pydantic_core-2.14.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0c08de15d50fa190d577e8591f0329a643eeaed696d7771760295998aca6bc66" }, - { file = "pydantic_core-2.14.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:36099c69f6b14fc2c49d7996cbf4f87ec4f0e66d1c74aa05228583225a07b590" }, - { file = "pydantic_core-2.14.6-cp310-none-win32.whl", hash = "sha256:7be719e4d2ae6c314f72844ba9d69e38dff342bc360379f7c8537c48e23034b7" }, - { file = "pydantic_core-2.14.6-cp310-none-win_amd64.whl", hash = "sha256:36fa402dcdc8ea7f1b0ddcf0df4254cc6b2e08f8cd80e7010d4c4ae6e86b2a87" }, - { file = "pydantic_core-2.14.6-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:dea7fcd62915fb150cdc373212141a30037e11b761fbced340e9db3379b892d4" }, - { file = "pydantic_core-2.14.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ffff855100bc066ff2cd3aa4a60bc9534661816b110f0243e59503ec2df38421" }, - { file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b027c86c66b8627eb90e57aee1f526df77dc6d8b354ec498be9a757d513b92b" }, - { file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:00b1087dabcee0b0ffd104f9f53d7d3eaddfaa314cdd6726143af6bc713aa27e" }, - { file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:75ec284328b60a4e91010c1acade0c30584f28a1f345bc8f72fe8b9e46ec6a96" }, - { file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e1f4744eea1501404b20b0ac059ff7e3f96a97d3e3f48ce27a139e053bb370b" }, - { file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2602177668f89b38b9f84b7b3435d0a72511ddef45dc14446811759b82235a1" }, - { file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6c8edaea3089bf908dd27da8f5d9e395c5b4dc092dbcce9b65e7156099b4b937" }, - { file = "pydantic_core-2.14.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:478e9e7b360dfec451daafe286998d4a1eeaecf6d69c427b834ae771cad4b622" }, - { file = "pydantic_core-2.14.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b6ca36c12a5120bad343eef193cc0122928c5c7466121da7c20f41160ba00ba2" }, - { file = "pydantic_core-2.14.6-cp311-none-win32.whl", hash = "sha256:2b8719037e570639e6b665a4050add43134d80b687288ba3ade18b22bbb29dd2" }, - { file = "pydantic_core-2.14.6-cp311-none-win_amd64.whl", hash = "sha256:78ee52ecc088c61cce32b2d30a826f929e1708f7b9247dc3b921aec367dc1b23" }, - { file = "pydantic_core-2.14.6-cp311-none-win_arm64.whl", hash = "sha256:a19b794f8fe6569472ff77602437ec4430f9b2b9ec7a1105cfd2232f9ba355e6" }, - { file = "pydantic_core-2.14.6-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:667aa2eac9cd0700af1ddb38b7b1ef246d8cf94c85637cbb03d7757ca4c3fdec" }, - { file = "pydantic_core-2.14.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cdee837710ef6b56ebd20245b83799fce40b265b3b406e51e8ccc5b85b9099b7" }, - { file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c5bcf3414367e29f83fd66f7de64509a8fd2368b1edf4351e862910727d3e51" }, - { file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26a92ae76f75d1915806b77cf459811e772d8f71fd1e4339c99750f0e7f6324f" }, - { file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a983cca5ed1dd9a35e9e42ebf9f278d344603bfcb174ff99a5815f953925140a" }, - { file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cb92f9061657287eded380d7dc455bbf115430b3aa4741bdc662d02977e7d0af" }, - { file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4ace1e220b078c8e48e82c081e35002038657e4b37d403ce940fa679e57113b" }, - { file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef633add81832f4b56d3b4c9408b43d530dfca29e68fb1b797dcb861a2c734cd" }, - { file = "pydantic_core-2.14.6-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7e90d6cc4aad2cc1f5e16ed56e46cebf4877c62403a311af20459c15da76fd91" }, - { file = "pydantic_core-2.14.6-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e8a5ac97ea521d7bde7621d86c30e86b798cdecd985723c4ed737a2aa9e77d0c" }, - { file = "pydantic_core-2.14.6-cp312-none-win32.whl", hash = "sha256:f27207e8ca3e5e021e2402ba942e5b4c629718e665c81b8b306f3c8b1ddbb786" }, - { file = "pydantic_core-2.14.6-cp312-none-win_amd64.whl", hash = "sha256:b3e5fe4538001bb82e2295b8d2a39356a84694c97cb73a566dc36328b9f83b40" }, - { file = "pydantic_core-2.14.6-cp312-none-win_arm64.whl", hash = "sha256:64634ccf9d671c6be242a664a33c4acf12882670b09b3f163cd00a24cffbd74e" }, - { file = "pydantic_core-2.14.6-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:24368e31be2c88bd69340fbfe741b405302993242ccb476c5c3ff48aeee1afe0" }, - { file = "pydantic_core-2.14.6-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:e33b0834f1cf779aa839975f9d8755a7c2420510c0fa1e9fa0497de77cd35d2c" }, - { file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6af4b3f52cc65f8a0bc8b1cd9676f8c21ef3e9132f21fed250f6958bd7223bed" }, - { file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d15687d7d7f40333bd8266f3814c591c2e2cd263fa2116e314f60d82086e353a" }, - { file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:095b707bb287bfd534044166ab767bec70a9bba3175dcdc3371782175c14e43c" }, - { file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94fc0e6621e07d1e91c44e016cc0b189b48db053061cc22d6298a611de8071bb" }, - { file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ce830e480f6774608dedfd4a90c42aac4a7af0a711f1b52f807130c2e434c06" }, - { file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a306cdd2ad3a7d795d8e617a58c3a2ed0f76c8496fb7621b6cd514eb1532cae8" }, - { file = "pydantic_core-2.14.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:2f5fa187bde8524b1e37ba894db13aadd64faa884657473b03a019f625cee9a8" }, - { file = "pydantic_core-2.14.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:438027a975cc213a47c5d70672e0d29776082155cfae540c4e225716586be75e" }, - { file = "pydantic_core-2.14.6-cp37-none-win32.whl", hash = "sha256:f96ae96a060a8072ceff4cfde89d261837b4294a4f28b84a28765470d502ccc6" }, - { file = "pydantic_core-2.14.6-cp37-none-win_amd64.whl", hash = "sha256:e646c0e282e960345314f42f2cea5e0b5f56938c093541ea6dbf11aec2862391" }, - { file = "pydantic_core-2.14.6-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:db453f2da3f59a348f514cfbfeb042393b68720787bbef2b4c6068ea362c8149" }, - { file = "pydantic_core-2.14.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3860c62057acd95cc84044e758e47b18dcd8871a328ebc8ccdefd18b0d26a21b" }, - { file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36026d8f99c58d7044413e1b819a67ca0e0b8ebe0f25e775e6c3d1fabb3c38fb" }, - { file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8ed1af8692bd8d2a29d702f1a2e6065416d76897d726e45a1775b1444f5928a7" }, - { file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:314ccc4264ce7d854941231cf71b592e30d8d368a71e50197c905874feacc8a8" }, - { file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:982487f8931067a32e72d40ab6b47b1628a9c5d344be7f1a4e668fb462d2da42" }, - { file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dbe357bc4ddda078f79d2a36fc1dd0494a7f2fad83a0a684465b6f24b46fe80" }, - { file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2f6ffc6701a0eb28648c845f4945a194dc7ab3c651f535b81793251e1185ac3d" }, - { file = "pydantic_core-2.14.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7f5025db12fc6de7bc1104d826d5aee1d172f9ba6ca936bf6474c2148ac336c1" }, - { file = "pydantic_core-2.14.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dab03ed811ed1c71d700ed08bde8431cf429bbe59e423394f0f4055f1ca0ea60" }, - { file = "pydantic_core-2.14.6-cp38-none-win32.whl", hash = "sha256:dfcbebdb3c4b6f739a91769aea5ed615023f3c88cb70df812849aef634c25fbe" }, - { file = "pydantic_core-2.14.6-cp38-none-win_amd64.whl", hash = "sha256:99b14dbea2fdb563d8b5a57c9badfcd72083f6006caf8e126b491519c7d64ca8" }, - { file = "pydantic_core-2.14.6-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:4ce8299b481bcb68e5c82002b96e411796b844d72b3e92a3fbedfe8e19813eab" }, - { file = "pydantic_core-2.14.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b9a9d92f10772d2a181b5ca339dee066ab7d1c9a34ae2421b2a52556e719756f" }, - { file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd9e98b408384989ea4ab60206b8e100d8687da18b5c813c11e92fd8212a98e0" }, - { file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4f86f1f318e56f5cbb282fe61eb84767aee743ebe32c7c0834690ebea50c0a6b" }, - { file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86ce5fcfc3accf3a07a729779d0b86c5d0309a4764c897d86c11089be61da160" }, - { file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dcf1978be02153c6a31692d4fbcc2a3f1db9da36039ead23173bc256ee3b91b" }, - { file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eedf97be7bc3dbc8addcef4142f4b4164066df0c6f36397ae4aaed3eb187d8ab" }, - { file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5f916acf8afbcab6bacbb376ba7dc61f845367901ecd5e328fc4d4aef2fcab0" }, - { file = "pydantic_core-2.14.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8a14c192c1d724c3acbfb3f10a958c55a2638391319ce8078cb36c02283959b9" }, - { file = "pydantic_core-2.14.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0348b1dc6b76041516e8a854ff95b21c55f5a411c3297d2ca52f5528e49d8411" }, - { file = "pydantic_core-2.14.6-cp39-none-win32.whl", hash = "sha256:de2a0645a923ba57c5527497daf8ec5df69c6eadf869e9cd46e86349146e5975" }, - { file = "pydantic_core-2.14.6-cp39-none-win_amd64.whl", hash = "sha256:aca48506a9c20f68ee61c87f2008f81f8ee99f8d7f0104bff3c47e2d148f89d9" }, - { file = "pydantic_core-2.14.6-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d5c28525c19f5bb1e09511669bb57353d22b94cf8b65f3a8d141c389a55dec95" }, - { file = "pydantic_core-2.14.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:78d0768ee59baa3de0f4adac9e3748b4b1fffc52143caebddfd5ea2961595277" }, - { file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b93785eadaef932e4fe9c6e12ba67beb1b3f1e5495631419c784ab87e975670" }, - { file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a874f21f87c485310944b2b2734cd6d318765bcbb7515eead33af9641816506e" }, - { file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89f4477d915ea43b4ceea6756f63f0288941b6443a2b28c69004fe07fde0d0d" }, - { file = "pydantic_core-2.14.6-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:172de779e2a153d36ee690dbc49c6db568d7b33b18dc56b69a7514aecbcf380d" }, - { file = "pydantic_core-2.14.6-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:dfcebb950aa7e667ec226a442722134539e77c575f6cfaa423f24371bb8d2e94" }, - { file = "pydantic_core-2.14.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:55a23dcd98c858c0db44fc5c04fc7ed81c4b4d33c653a7c45ddaebf6563a2f66" }, - { file = "pydantic_core-2.14.6-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:4241204e4b36ab5ae466ecec5c4c16527a054c69f99bba20f6f75232a6a534e2" }, - { file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e574de99d735b3fc8364cba9912c2bec2da78775eba95cbb225ef7dda6acea24" }, - { file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1302a54f87b5cd8528e4d6d1bf2133b6aa7c6122ff8e9dc5220fbc1e07bffebd" }, - { file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8e81e4b55930e5ffab4a68db1af431629cf2e4066dbdbfef65348b8ab804ea8" }, - { file = "pydantic_core-2.14.6-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c99462ffc538717b3e60151dfaf91125f637e801f5ab008f81c402f1dff0cd0f" }, - { file = "pydantic_core-2.14.6-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e4cf2d5829f6963a5483ec01578ee76d329eb5caf330ecd05b3edd697e7d768a" }, - { file = "pydantic_core-2.14.6-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:cf10b7d58ae4a1f07fccbf4a0a956d705356fea05fb4c70608bb6fa81d103cda" }, - { file = "pydantic_core-2.14.6-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:399ac0891c284fa8eb998bcfa323f2234858f5d2efca3950ae58c8f88830f145" }, - { file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c6a5c79b28003543db3ba67d1df336f253a87d3112dac3a51b94f7d48e4c0e1" }, - { file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:599c87d79cab2a6a2a9df4aefe0455e61e7d2aeede2f8577c1b7c0aec643ee8e" }, - { file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43e166ad47ba900f2542a80d83f9fc65fe99eb63ceec4debec160ae729824052" }, - { file = "pydantic_core-2.14.6-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3a0b5db001b98e1c649dd55afa928e75aa4087e587b9524a4992316fa23c9fba" }, - { file = "pydantic_core-2.14.6-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:747265448cb57a9f37572a488a57d873fd96bf51e5bb7edb52cfb37124516da4" }, - { file = "pydantic_core-2.14.6-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:7ebe3416785f65c28f4f9441e916bfc8a54179c8dea73c23023f7086fa601c5d" }, - { file = "pydantic_core-2.14.6-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:86c963186ca5e50d5c8287b1d1c9d3f8f024cbe343d048c5bd282aec2d8641f2" }, - { file = "pydantic_core-2.14.6-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e0641b506486f0b4cd1500a2a65740243e8670a2549bb02bc4556a83af84ae03" }, - { file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71d72ca5eaaa8d38c8df16b7deb1a2da4f650c41b58bb142f3fb75d5ad4a611f" }, - { file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27e524624eace5c59af499cd97dc18bb201dc6a7a2da24bfc66ef151c69a5f2a" }, - { file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a3dde6cac75e0b0902778978d3b1646ca9f438654395a362cb21d9ad34b24acf" }, - { file = "pydantic_core-2.14.6-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:00646784f6cd993b1e1c0e7b0fdcbccc375d539db95555477771c27555e3c556" }, - { file = "pydantic_core-2.14.6-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:23598acb8ccaa3d1d875ef3b35cb6376535095e9405d91a3d57a8c7db5d29341" }, - { file = "pydantic_core-2.14.6-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7f41533d7e3cf9520065f610b41ac1c76bc2161415955fbcead4981b22c7611e" }, - { file = "pydantic_core-2.14.6.tar.gz", hash = "sha256:1fd0c1d395372843fba13a51c28e3bb9d59bd7aebfeb17358ffaaa1e4dbbe948" }, + { file = "pydantic_core-2.16.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4" }, + { file = "pydantic_core-2.16.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1" }, + { file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45" }, + { file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187" }, + { file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8" }, + { file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec" }, + { file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f" }, + { file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99" }, + { file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979" }, + { file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db" }, + { file = "pydantic_core-2.16.3-cp310-none-win32.whl", hash = "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132" }, + { file = "pydantic_core-2.16.3-cp310-none-win_amd64.whl", hash = "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb" }, + { file = "pydantic_core-2.16.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4" }, + { file = "pydantic_core-2.16.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd" }, + { file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac" }, + { file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda" }, + { file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340" }, + { file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97" }, + { file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e" }, + { file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f" }, + { file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e" }, + { file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba" }, + { file = "pydantic_core-2.16.3-cp311-none-win32.whl", hash = "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721" }, + { file = "pydantic_core-2.16.3-cp311-none-win_amd64.whl", hash = "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df" }, + { file = "pydantic_core-2.16.3-cp311-none-win_arm64.whl", hash = "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9" }, + { file = "pydantic_core-2.16.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff" }, + { file = "pydantic_core-2.16.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975" }, + { file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2" }, + { file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120" }, + { file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053" }, + { file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b" }, + { file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade" }, + { file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e" }, + { file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca" }, + { file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf" }, + { file = "pydantic_core-2.16.3-cp312-none-win32.whl", hash = "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe" }, + { file = "pydantic_core-2.16.3-cp312-none-win_amd64.whl", hash = "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed" }, + { file = "pydantic_core-2.16.3-cp312-none-win_arm64.whl", hash = "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6" }, + { file = "pydantic_core-2.16.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01" }, + { file = "pydantic_core-2.16.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7" }, + { file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48" }, + { file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a" }, + { file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8" }, + { file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d" }, + { file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9" }, + { file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c" }, + { file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8" }, + { file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5" }, + { file = "pydantic_core-2.16.3-cp38-none-win32.whl", hash = "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a" }, + { file = "pydantic_core-2.16.3-cp38-none-win_amd64.whl", hash = "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed" }, + { file = "pydantic_core-2.16.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820" }, + { file = "pydantic_core-2.16.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23" }, + { file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074" }, + { file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805" }, + { file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c" }, + { file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9" }, + { file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256" }, + { file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8" }, + { file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b" }, + { file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972" }, + { file = "pydantic_core-2.16.3-cp39-none-win32.whl", hash = "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2" }, + { file = "pydantic_core-2.16.3-cp39-none-win_amd64.whl", hash = "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf" }, + { file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c" }, + { file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a" }, + { file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241" }, + { file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183" }, + { file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad" }, + { file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a" }, + { file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1" }, + { file = "pydantic_core-2.16.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe" }, + { file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b" }, + { file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f" }, + { file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137" }, + { file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89" }, + { file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a" }, + { file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6" }, + { file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc" }, + { file = "pydantic_core-2.16.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da" }, + { file = "pydantic_core-2.16.3.tar.gz", hash = "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad" }, ] [package.dependencies] @@ -1832,15 +1805,15 @@ PyQt6-sip = ">=13.6,<14" [[package]] name = "pyqt6-qt6" -version = "6.6.1" +version = "6.6.2" description = "The subset of a Qt installation needed by PyQt6." optional = false python-versions = "*" files = [ - { file = "PyQt6_Qt6-6.6.1-py3-none-macosx_10_14_x86_64.whl", hash = "sha256:0409aa09b8dae90d5f00ba2d9761e671dfbc54ab169cff8f4cdfecd7f664fd0f" }, - { file = "PyQt6_Qt6-6.6.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:8dcac0bd9df13d63deafb6a61969b832c34467da4a28d2b7abf78066bfce22e6" }, - { file = "PyQt6_Qt6-6.6.1-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:e7df8851c93886412d890d0ecc62b39f42521861ee7a80982136d65903e1f2c5" }, - { file = "PyQt6_Qt6-6.6.1-py3-none-win_amd64.whl", hash = "sha256:41f1ed3eadc00540c205a0e897ae0e0fffc21b896e575214f7c5b9c86d2037d1" }, + { file = "PyQt6_Qt6-6.6.2-py3-none-macosx_10_14_x86_64.whl", hash = "sha256:7ef446d3ffc678a8586ff6dc9f0d27caf4dff05dea02c353540d2f614386faf9" }, + { file = "PyQt6_Qt6-6.6.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b8363d88623342a72ac17da9127dc12f259bb3148796ea029762aa2d499778d9" }, + { file = "PyQt6_Qt6-6.6.2-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:8d7f674a4ec43ca00191e14945ca4129acbe37a2172ed9d08214ad58b170bc11" }, + { file = "PyQt6_Qt6-6.6.2-py3-none-win_amd64.whl", hash = "sha256:5a41fe9d53b9e29e9ec5c23f3c5949dba160f90ca313ee8b96b8ffe6a5059387" }, ] [[package]] @@ -1946,17 +1919,18 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale [[package]] name = "pytest-qt" -version = "4.3.1" +version = "4.4.0" description = "pytest support for PyQt and PySide applications" optional = false python-versions = ">=3.8" files = [ - { file = "pytest-qt-4.3.1.tar.gz", hash = "sha256:0256041af78082dfc08e22ccf860aaa878d8029557f03f4bfc2007fc291b1e61" }, - { file = "pytest_qt-4.3.1-py3-none-any.whl", hash = "sha256:e1bd043a4e460f184657bc3a0eabf289ad5e88a55a2abf0436d248049a331653" }, + { file = "pytest-qt-4.4.0.tar.gz", hash = "sha256:76896142a940a4285339008d6928a36d4be74afec7e634577e842c9cc5c56844" }, + { file = "pytest_qt-4.4.0-py3-none-any.whl", hash = "sha256:001ed2f8641764b394cf286dc8a4203e40eaf9fff75bf0bfe5103f7f8d0c591d" }, ] [package.dependencies] -pytest = ">=3.0.0" +pluggy = ">=1.1" +pytest = "*" [package.extras] dev = ["pre-commit", "tox"] @@ -2183,28 +2157,28 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "ruff" -version = "0.1.11" +version = "0.1.15" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - { file = "ruff-0.1.11-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:a7f772696b4cdc0a3b2e527fc3c7ccc41cdcb98f5c80fdd4f2b8c50eb1458196" }, - { file = "ruff-0.1.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:934832f6ed9b34a7d5feea58972635c2039c7a3b434fe5ba2ce015064cb6e955" }, - { file = "ruff-0.1.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea0d3e950e394c4b332bcdd112aa566010a9f9c95814844a7468325290aabfd9" }, - { file = "ruff-0.1.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9bd4025b9c5b429a48280785a2b71d479798a69f5c2919e7d274c5f4b32c3607" }, - { file = "ruff-0.1.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1ad00662305dcb1e987f5ec214d31f7d6a062cae3e74c1cbccef15afd96611d" }, - { file = "ruff-0.1.11-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4b077ce83f47dd6bea1991af08b140e8b8339f0ba8cb9b7a484c30ebab18a23f" }, - { file = "ruff-0.1.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4a88efecec23c37b11076fe676e15c6cdb1271a38f2b415e381e87fe4517f18" }, - { file = "ruff-0.1.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b25093dad3b055667730a9b491129c42d45e11cdb7043b702e97125bcec48a1" }, - { file = "ruff-0.1.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:231d8fb11b2cc7c0366a326a66dafc6ad449d7fcdbc268497ee47e1334f66f77" }, - { file = "ruff-0.1.11-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:09c415716884950080921dd6237767e52e227e397e2008e2bed410117679975b" }, - { file = "ruff-0.1.11-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0f58948c6d212a6b8d41cd59e349751018797ce1727f961c2fa755ad6208ba45" }, - { file = "ruff-0.1.11-py3-none-musllinux_1_2_i686.whl", hash = "sha256:190a566c8f766c37074d99640cd9ca3da11d8deae2deae7c9505e68a4a30f740" }, - { file = "ruff-0.1.11-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:6464289bd67b2344d2a5d9158d5eb81025258f169e69a46b741b396ffb0cda95" }, - { file = "ruff-0.1.11-py3-none-win32.whl", hash = "sha256:9b8f397902f92bc2e70fb6bebfa2139008dc72ae5177e66c383fa5426cb0bf2c" }, - { file = "ruff-0.1.11-py3-none-win_amd64.whl", hash = "sha256:eb85ee287b11f901037a6683b2374bb0ec82928c5cbc984f575d0437979c521a" }, - { file = "ruff-0.1.11-py3-none-win_arm64.whl", hash = "sha256:97ce4d752f964ba559c7023a86e5f8e97f026d511e48013987623915431c7ea9" }, - { file = "ruff-0.1.11.tar.gz", hash = "sha256:f9d4d88cb6eeb4dfe20f9f0519bd2eaba8119bde87c3d5065c541dbae2b5a2cb" }, + { file = "ruff-0.1.15-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:5fe8d54df166ecc24106db7dd6a68d44852d14eb0729ea4672bb4d96c320b7df" }, + { file = "ruff-0.1.15-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6f0bfbb53c4b4de117ac4d6ddfd33aa5fc31beeaa21d23c45c6dd249faf9126f" }, + { file = "ruff-0.1.15-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0d432aec35bfc0d800d4f70eba26e23a352386be3a6cf157083d18f6f5881c8" }, + { file = "ruff-0.1.15-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9405fa9ac0e97f35aaddf185a1be194a589424b8713e3b97b762336ec79ff807" }, + { file = "ruff-0.1.15-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c66ec24fe36841636e814b8f90f572a8c0cb0e54d8b5c2d0e300d28a0d7bffec" }, + { file = "ruff-0.1.15-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:6f8ad828f01e8dd32cc58bc28375150171d198491fc901f6f98d2a39ba8e3ff5" }, + { file = "ruff-0.1.15-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86811954eec63e9ea162af0ffa9f8d09088bab51b7438e8b6488b9401863c25e" }, + { file = "ruff-0.1.15-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fd4025ac5e87d9b80e1f300207eb2fd099ff8200fa2320d7dc066a3f4622dc6b" }, + { file = "ruff-0.1.15-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b17b93c02cdb6aeb696effecea1095ac93f3884a49a554a9afa76bb125c114c1" }, + { file = "ruff-0.1.15-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ddb87643be40f034e97e97f5bc2ef7ce39de20e34608f3f829db727a93fb82c5" }, + { file = "ruff-0.1.15-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:abf4822129ed3a5ce54383d5f0e964e7fef74a41e48eb1dfad404151efc130a2" }, + { file = "ruff-0.1.15-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6c629cf64bacfd136c07c78ac10a54578ec9d1bd2a9d395efbee0935868bf852" }, + { file = "ruff-0.1.15-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1bab866aafb53da39c2cadfb8e1c4550ac5340bb40300083eb8967ba25481447" }, + { file = "ruff-0.1.15-py3-none-win32.whl", hash = "sha256:2417e1cb6e2068389b07e6fa74c306b2810fe3ee3476d5b8a96616633f40d14f" }, + { file = "ruff-0.1.15-py3-none-win_amd64.whl", hash = "sha256:3837ac73d869efc4182d9036b1405ef4c73d9b1f88da2413875e34e0d6919587" }, + { file = "ruff-0.1.15-py3-none-win_arm64.whl", hash = "sha256:9a933dfb1c14ec7a33cceb1e49ec4a16b51ce3c20fd42663198746efc0427360" }, + { file = "ruff-0.1.15.tar.gz", hash = "sha256:f6dfa8c1b21c913c326919056c390966648b680966febcb796cc9d1aaab8564e" }, ] [[package]] @@ -2224,19 +2198,19 @@ jeepney = ">=0.6" [[package]] name = "setuptools" -version = "69.0.3" +version = "69.2.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - { file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05" }, - { file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78" }, + { file = "setuptools-69.2.0-py3-none-any.whl", hash = "sha256:c21c49fb1042386df081cb5d86759792ab89efca84cf114889191cd09aacc80c" }, + { file = "setuptools-69.2.0.tar.gz", hash = "sha256:0ff4183f8f42cd8fa3acea16c45205521a4ef28f73c6391d8a25e92893134f2e" }, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" @@ -2251,13 +2225,13 @@ files = [ [[package]] name = "sniffio" -version = "1.3.0" +version = "1.3.1" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" files = [ - { file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384" }, - { file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101" }, + { file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2" }, + { file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" }, ] [[package]] @@ -2309,47 +2283,47 @@ mpmath = ">=0.19" [[package]] name = "tiktoken" -version = "0.5.2" +version = "0.6.0" description = "tiktoken is a fast BPE tokeniser for use with OpenAI's models" optional = false python-versions = ">=3.8" files = [ - { file = "tiktoken-0.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8c4e654282ef05ec1bd06ead22141a9a1687991cef2c6a81bdd1284301abc71d" }, - { file = "tiktoken-0.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7b3134aa24319f42c27718c6967f3c1916a38a715a0fa73d33717ba121231307" }, - { file = "tiktoken-0.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6092e6e77730929c8c6a51bb0d7cfdf1b72b63c4d033d6258d1f2ee81052e9e5" }, - { file = "tiktoken-0.5.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72ad8ae2a747622efae75837abba59be6c15a8f31b4ac3c6156bc56ec7a8e631" }, - { file = "tiktoken-0.5.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:51cba7c8711afa0b885445f0637f0fcc366740798c40b981f08c5f984e02c9d1" }, - { file = "tiktoken-0.5.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3d8c7d2c9313f8e92e987d585ee2ba0f7c40a0de84f4805b093b634f792124f5" }, - { file = "tiktoken-0.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:692eca18c5fd8d1e0dde767f895c17686faaa102f37640e884eecb6854e7cca7" }, - { file = "tiktoken-0.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:138d173abbf1ec75863ad68ca289d4da30caa3245f3c8d4bfb274c4d629a2f77" }, - { file = "tiktoken-0.5.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7388fdd684690973fdc450b47dfd24d7f0cbe658f58a576169baef5ae4658607" }, - { file = "tiktoken-0.5.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a114391790113bcff670c70c24e166a841f7ea8f47ee2fe0e71e08b49d0bf2d4" }, - { file = "tiktoken-0.5.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca96f001e69f6859dd52926d950cfcc610480e920e576183497ab954e645e6ac" }, - { file = "tiktoken-0.5.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:15fed1dd88e30dfadcdd8e53a8927f04e1f6f81ad08a5ca824858a593ab476c7" }, - { file = "tiktoken-0.5.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:93f8e692db5756f7ea8cb0cfca34638316dcf0841fb8469de8ed7f6a015ba0b0" }, - { file = "tiktoken-0.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:bcae1c4c92df2ffc4fe9f475bf8148dbb0ee2404743168bbeb9dcc4b79dc1fdd" }, - { file = "tiktoken-0.5.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b76a1e17d4eb4357d00f0622d9a48ffbb23401dcf36f9716d9bd9c8e79d421aa" }, - { file = "tiktoken-0.5.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:01d8b171bb5df4035580bc26d4f5339a6fd58d06f069091899d4a798ea279d3e" }, - { file = "tiktoken-0.5.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42adf7d4fb1ed8de6e0ff2e794a6a15005f056a0d83d22d1d6755a39bffd9e7f" }, - { file = "tiktoken-0.5.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c3f894dbe0adb44609f3d532b8ea10820d61fdcb288b325a458dfc60fefb7db" }, - { file = "tiktoken-0.5.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:58ccfddb4e62f0df974e8f7e34a667981d9bb553a811256e617731bf1d007d19" }, - { file = "tiktoken-0.5.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58902a8bad2de4268c2a701f1c844d22bfa3cbcc485b10e8e3e28a050179330b" }, - { file = "tiktoken-0.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:5e39257826d0647fcac403d8fa0a474b30d02ec8ffc012cfaf13083e9b5e82c5" }, - { file = "tiktoken-0.5.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8bde3b0fbf09a23072d39c1ede0e0821f759b4fa254a5f00078909158e90ae1f" }, - { file = "tiktoken-0.5.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2ddee082dcf1231ccf3a591d234935e6acf3e82ee28521fe99af9630bc8d2a60" }, - { file = "tiktoken-0.5.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35c057a6a4e777b5966a7540481a75a31429fc1cb4c9da87b71c8b75b5143037" }, - { file = "tiktoken-0.5.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c4a049b87e28f1dc60509f8eb7790bc8d11f9a70d99b9dd18dfdd81a084ffe6" }, - { file = "tiktoken-0.5.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5bf5ce759089f4f6521ea6ed89d8f988f7b396e9f4afb503b945f5c949c6bec2" }, - { file = "tiktoken-0.5.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0c964f554af1a96884e01188f480dad3fc224c4bbcf7af75d4b74c4b74ae0125" }, - { file = "tiktoken-0.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:368dd5726d2e8788e47ea04f32e20f72a2012a8a67af5b0b003d1e059f1d30a3" }, - { file = "tiktoken-0.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a2deef9115b8cd55536c0a02c0203512f8deb2447f41585e6d929a0b878a0dd2" }, - { file = "tiktoken-0.5.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2ed7d380195affbf886e2f8b92b14edfe13f4768ff5fc8de315adba5b773815e" }, - { file = "tiktoken-0.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c76fce01309c8140ffe15eb34ded2bb94789614b7d1d09e206838fc173776a18" }, - { file = "tiktoken-0.5.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60a5654d6a2e2d152637dd9a880b4482267dfc8a86ccf3ab1cec31a8c76bfae8" }, - { file = "tiktoken-0.5.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:41d4d3228e051b779245a8ddd21d4336f8975563e92375662f42d05a19bdff41" }, - { file = "tiktoken-0.5.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a5c1cdec2c92fcde8c17a50814b525ae6a88e8e5b02030dc120b76e11db93f13" }, - { file = "tiktoken-0.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:84ddb36faedb448a50b246e13d1b6ee3437f60b7169b723a4b2abad75e914f3e" }, - { file = "tiktoken-0.5.2.tar.gz", hash = "sha256:f54c581f134a8ea96ce2023ab221d4d4d81ab614efa0b2fbce926387deb56c80" }, + { file = "tiktoken-0.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:277de84ccd8fa12730a6b4067456e5cf72fef6300bea61d506c09e45658d41ac" }, + { file = "tiktoken-0.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c44433f658064463650d61387623735641dcc4b6c999ca30bc0f8ba3fccaf5c" }, + { file = "tiktoken-0.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afb9a2a866ae6eef1995ab656744287a5ac95acc7e0491c33fad54d053288ad3" }, + { file = "tiktoken-0.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c62c05b3109fefca26fedb2820452a050074ad8e5ad9803f4652977778177d9f" }, + { file = "tiktoken-0.6.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0ef917fad0bccda07bfbad835525bbed5f3ab97a8a3e66526e48cdc3e7beacf7" }, + { file = "tiktoken-0.6.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e095131ab6092d0769a2fda85aa260c7c383072daec599ba9d8b149d2a3f4d8b" }, + { file = "tiktoken-0.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:05b344c61779f815038292a19a0c6eb7098b63c8f865ff205abb9ea1b656030e" }, + { file = "tiktoken-0.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cefb9870fb55dca9e450e54dbf61f904aab9180ff6fe568b61f4db9564e78871" }, + { file = "tiktoken-0.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:702950d33d8cabc039845674107d2e6dcabbbb0990ef350f640661368df481bb" }, + { file = "tiktoken-0.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8d49d076058f23254f2aff9af603863c5c5f9ab095bc896bceed04f8f0b013a" }, + { file = "tiktoken-0.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:430bc4e650a2d23a789dc2cdca3b9e5e7eb3cd3935168d97d43518cbb1f9a911" }, + { file = "tiktoken-0.6.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:293cb8669757301a3019a12d6770bd55bec38a4d3ee9978ddbe599d68976aca7" }, + { file = "tiktoken-0.6.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7bd1a288b7903aadc054b0e16ea78e3171f70b670e7372432298c686ebf9dd47" }, + { file = "tiktoken-0.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac76e000183e3b749634968a45c7169b351e99936ef46f0d2353cd0d46c3118d" }, + { file = "tiktoken-0.6.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:17cc8a4a3245ab7d935c83a2db6bb71619099d7284b884f4b2aea4c74f2f83e3" }, + { file = "tiktoken-0.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:284aebcccffe1bba0d6571651317df6a5b376ff6cfed5aeb800c55df44c78177" }, + { file = "tiktoken-0.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c1a3a5d33846f8cd9dd3b7897c1d45722f48625a587f8e6f3d3e85080559be8" }, + { file = "tiktoken-0.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6318b2bb2337f38ee954fd5efa82632c6e5ced1d52a671370fa4b2eff1355e91" }, + { file = "tiktoken-0.6.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1f5f0f2ed67ba16373f9a6013b68da298096b27cd4e1cf276d2d3868b5c7efd1" }, + { file = "tiktoken-0.6.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:75af4c0b16609c2ad02581f3cdcd1fb698c7565091370bf6c0cf8624ffaba6dc" }, + { file = "tiktoken-0.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:45577faf9a9d383b8fd683e313cf6df88b6076c034f0a16da243bb1c139340c3" }, + { file = "tiktoken-0.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7c1492ab90c21ca4d11cef3a236ee31a3e279bb21b3fc5b0e2210588c4209e68" }, + { file = "tiktoken-0.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e2b380c5b7751272015400b26144a2bab4066ebb8daae9c3cd2a92c3b508fe5a" }, + { file = "tiktoken-0.6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9f497598b9f58c99cbc0eb764b4a92272c14d5203fc713dd650b896a03a50ad" }, + { file = "tiktoken-0.6.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e65e8bd6f3f279d80f1e1fbd5f588f036b9a5fa27690b7f0cc07021f1dfa0839" }, + { file = "tiktoken-0.6.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5f1495450a54e564d236769d25bfefbf77727e232d7a8a378f97acddee08c1ae" }, + { file = "tiktoken-0.6.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6c4e4857d99f6fb4670e928250835b21b68c59250520a1941618b5b4194e20c3" }, + { file = "tiktoken-0.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:168d718f07a39b013032741867e789971346df8e89983fe3c0ef3fbd5a0b1cb9" }, + { file = "tiktoken-0.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:47fdcfe11bd55376785a6aea8ad1db967db7f66ea81aed5c43fad497521819a4" }, + { file = "tiktoken-0.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fb7d2ccbf1a7784810aff6b80b4012fb42c6fc37eaa68cb3b553801a5cc2d1fc" }, + { file = "tiktoken-0.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ccb7a111ee76af5d876a729a347f8747d5ad548e1487eeea90eaf58894b3138" }, + { file = "tiktoken-0.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2048e1086b48e3c8c6e2ceeac866561374cd57a84622fa49a6b245ffecb7744" }, + { file = "tiktoken-0.6.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:07f229a5eb250b6403a61200199cecf0aac4aa23c3ecc1c11c1ca002cbb8f159" }, + { file = "tiktoken-0.6.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:432aa3be8436177b0db5a2b3e7cc28fd6c693f783b2f8722539ba16a867d0c6a" }, + { file = "tiktoken-0.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:8bfe8a19c8b5c40d121ee7938cd9c6a278e5b97dc035fd61714b4f0399d2f7a1" }, + { file = "tiktoken-0.6.0.tar.gz", hash = "sha256:ace62a4ede83c75b0374a2ddfa4b76903cf483e9cb06247f566be3bf14e6beed" }, ] [package.dependencies] @@ -2437,13 +2411,13 @@ files = [ [[package]] name = "tomlkit" -version = "0.12.3" +version = "0.12.4" description = "Style preserving TOML library" optional = false python-versions = ">=3.7" files = [ - { file = "tomlkit-0.12.3-py3-none-any.whl", hash = "sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba" }, - { file = "tomlkit-0.12.3.tar.gz", hash = "sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4" }, + { file = "tomlkit-0.12.4-py3-none-any.whl", hash = "sha256:5cd82d48a3dd89dee1f9d64420aa20ae65cfbd00668d6f094d7578a78efbb77b" }, + { file = "tomlkit-0.12.4.tar.gz", hash = "sha256:7ca1cfc12232806517a8515047ba66a19369e71edf2439d0f5824f91032b6cc3" }, ] [[package]] @@ -2480,13 +2454,13 @@ typing-extensions = "*" [[package]] name = "tqdm" -version = "4.66.1" +version = "4.66.2" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" files = [ - { file = "tqdm-4.66.1-py3-none-any.whl", hash = "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386" }, - { file = "tqdm-4.66.1.tar.gz", hash = "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7" }, + { file = "tqdm-4.66.2-py3-none-any.whl", hash = "sha256:1ee4f8a893eb9bef51c6e35730cebf234d5d0b6bd112b0271e10ed7c24a02bd9" }, + { file = "tqdm-4.66.2.tar.gz", hash = "sha256:6cd52cdf0fef0e0f543299cfc96fec90d7b8a7e88745f411ec33eb44d5ed3531" }, ] [package.dependencies] @@ -2564,38 +2538,36 @@ vision = ["Pillow"] [[package]] name = "triton" -version = "2.1.0" +version = "2.2.0" description = "A language and compiler for custom Deep Learning operations" optional = false python-versions = "*" files = [ - { file = "triton-2.1.0-0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:66439923a30d5d48399b08a9eae10370f6c261a5ec864a64983bae63152d39d7" }, - { file = "triton-2.1.0-0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:919b06453f0033ea52c13eaf7833de0e57db3178d23d4e04f9fc71c4f2c32bf8" }, - { file = "triton-2.1.0-0-cp37-cp37m-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ae4bb8a91de790e1866405211c4d618379781188f40d5c4c399766914e84cd94" }, - { file = "triton-2.1.0-0-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:39f6fb6bdccb3e98f3152e3fbea724f1aeae7d749412bbb1fa9c441d474eba26" }, - { file = "triton-2.1.0-0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:21544e522c02005a626c8ad63d39bdff2f31d41069592919ef281e964ed26446" }, - { file = "triton-2.1.0-0-pp37-pypy37_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:143582ca31dd89cd982bd3bf53666bab1c7527d41e185f9e3d8a3051ce1b663b" }, - { file = "triton-2.1.0-0-pp38-pypy38_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:82fc5aeeedf6e36be4e4530cbdcba81a09d65c18e02f52dc298696d45721f3bd" }, - { file = "triton-2.1.0-0-pp39-pypy39_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:81a96d110a738ff63339fc892ded095b31bd0d205e3aace262af8400d40b6fa8" }, + { file = "triton-2.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2294514340cfe4e8f4f9e5c66c702744c4a117d25e618bd08469d0bfed1e2e5" }, + { file = "triton-2.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da58a152bddb62cafa9a857dd2bc1f886dbf9f9c90a2b5da82157cd2b34392b0" }, + { file = "triton-2.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af58716e721460a61886668b205963dc4d1e4ac20508cc3f623aef0d70283d5" }, + { file = "triton-2.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8fe46d3ab94a8103e291bd44c741cc294b91d1d81c1a2888254cbf7ff846dab" }, + { file = "triton-2.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8ce26093e539d727e7cf6f6f0d932b1ab0574dc02567e684377630d86723ace" }, + { file = "triton-2.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:227cc6f357c5efcb357f3867ac2a8e7ecea2298cd4606a8ba1e931d1d5a947df" }, ] [package.dependencies] filelock = "*" [package.extras] -build = ["cmake (>=3.18)", "lit"] -tests = ["autopep8", "flake8", "isort", "numpy", "pytest", "scipy (>=1.7.1)"] -tutorials = ["matplotlib", "pandas", "tabulate"] +build = ["cmake (>=3.20)", "lit"] +tests = ["autopep8", "flake8", "isort", "numpy", "pytest", "scipy (>=1.7.1)", "torch"] +tutorials = ["matplotlib", "pandas", "tabulate", "torch"] [[package]] name = "typing-extensions" -version = "4.9.0" +version = "4.10.0" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - { file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" }, - { file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783" }, + { file = "typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475" }, + { file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb" }, ] [[package]] @@ -2615,29 +2587,30 @@ typing-extensions = ">=3.7.4" [[package]] name = "urllib3" -version = "2.1.0" +version = "2.2.1" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - { file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3" }, - { file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54" }, + { file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d" }, + { file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19" }, ] [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.25.0" +version = "20.25.1" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - { file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3" }, - { file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b" }, + { file = "virtualenv-20.25.1-py3-none-any.whl", hash = "sha256:961c026ac520bac5f69acb8ea063e8a4f071bcc9457b9c1f28f6b085c511583a" }, + { file = "virtualenv-20.25.1.tar.gz", hash = "sha256:e08e13ecdca7a0bd53798f356d5831434afa5b07b93f0abdf0797b7a06ffe197" }, ] [package.dependencies] @@ -2845,20 +2818,20 @@ websockets = ">=12.0" [[package]] name = "zipp" -version = "3.17.0" +version = "3.18.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - { file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31" }, - { file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0" }, + { file = "zipp-3.18.0-py3-none-any.whl", hash = "sha256:c1bb803ed69d2cce2373152797064f7e79bc43f0a3748eb494096a867e0ebf79" }, + { file = "zipp-3.18.0.tar.gz", hash = "sha256:df8d042b02765029a09b157efd8e820451045890acc30f8e37dd2f94a060221f" }, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [metadata] lock-version = "2.0" python-versions = ">=3.9.13,<3.11" -content-hash = "4d011bc97fb3eb123631563b28e3f1e55a1a189a3dcbbb7a29f55460945c5982" +content-hash = "af0faf240d7f659c167f3f644a35ccb17e7c70787be015f2d7276391e38591bb" diff --git a/pyproject.toml b/pyproject.toml index 19790700bf..5fc96e6774 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,6 @@ packages = [ [tool.poetry.dependencies] python = ">=3.9.13,<3.11" sounddevice = "^0.4.5" -appdirs = "^1.4.4" humanize = "^4.4.0" PyQt6 = "^6.4.0" openai = "^1.6.1" diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000000..b2adb2698f --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,40 @@ +import os + +import pytest +from PyQt6.QtSql import QSqlDatabase +from _pytest.fixtures import SubRequest + +from buzz.db.dao.transcription_dao import TranscriptionDAO +from buzz.db.dao.transcription_segment_dao import TranscriptionSegmentDAO +from buzz.db.db import setup_test_db +from buzz.db.service.transcription_service import TranscriptionService + + +@pytest.fixture() +def db() -> QSqlDatabase: + db = setup_test_db() + yield db + db.close() + os.remove(db.databaseName()) + + +@pytest.fixture() +def transcription_dao(db, request: SubRequest) -> TranscriptionDAO: + dao = TranscriptionDAO(db) + if hasattr(request, "param"): + transcriptions = request.param + for transcription in transcriptions: + dao.insert(transcription) + return dao + + +@pytest.fixture() +def transcription_service( + transcription_dao, transcription_segment_dao +) -> TranscriptionService: + return TranscriptionService(transcription_dao, transcription_segment_dao) + + +@pytest.fixture() +def transcription_segment_dao(db) -> TranscriptionSegmentDAO: + return TranscriptionSegmentDAO(db) diff --git a/tests/transcriber/whisper_file_transcriber_test.py b/tests/transcriber/whisper_file_transcriber_test.py index 056652ee1a..5b4d9f2d7b 100644 --- a/tests/transcriber/whisper_file_transcriber_test.py +++ b/tests/transcriber/whisper_file_transcriber_test.py @@ -54,13 +54,15 @@ def test_default_output_file( expected_file_path: str, ): file_path = get_output_file_path( - task=FileTranscriptionTask( - file_path=file_path, - transcription_options=TranscriptionOptions(task=Task.TRANSLATE), - file_transcription_options=FileTranscriptionOptions(file_paths=[]), - model_path="", + file_path=file_path, + language=None, + task=Task.TRANSLATE, + model=TranscriptionModel( + model_type=ModelType.WHISPER, + whisper_model_size=WhisperModelSize.TINY, ), output_format=output_format, + output_directory="", export_file_name_template="{{ input_file_name }}-{{ task }}-{{ language }}-{{ model_type }}-{{ model_size }}", ) assert file_path == expected_file_path @@ -87,15 +89,15 @@ def test_default_output_file_with_date( "{{ input_file_name }} (Translated on {{ date_time }})" ) srt = get_output_file_path( - task=FileTranscriptionTask( - file_path=file_path, - transcription_options=TranscriptionOptions(task=Task.TRANSLATE), - file_transcription_options=FileTranscriptionOptions( - file_paths=[], - ), - model_path="", + file_path=file_path, + language=None, + task=Task.TRANSLATE, + model=TranscriptionModel( + model_type=ModelType.WHISPER, + whisper_model_size=WhisperModelSize.TINY, ), output_format=OutputFormat.TXT, + output_directory="", export_file_name_template=export_file_name_template, ) @@ -103,15 +105,15 @@ def test_default_output_file_with_date( assert srt.endswith(".txt") srt = get_output_file_path( - task=FileTranscriptionTask( - file_path=file_path, - transcription_options=TranscriptionOptions(task=Task.TRANSLATE), - file_transcription_options=FileTranscriptionOptions( - file_paths=[], - ), - model_path="", + file_path=file_path, + language=None, + task=Task.TRANSLATE, + model=TranscriptionModel( + model_type=ModelType.WHISPER, + whisper_model_size=WhisperModelSize.TINY, ), output_format=OutputFormat.SRT, + output_directory="", export_file_name_template=export_file_name_template, ) assert srt.startswith(expected_starts_with) diff --git a/tests/widgets/main_window_test.py b/tests/widgets/main_window_test.py index 3290f0edea..1f0bb769d8 100644 --- a/tests/widgets/main_window_test.py +++ b/tests/widgets/main_window_test.py @@ -6,50 +6,26 @@ from PyQt6.QtCore import QSize, Qt from PyQt6.QtGui import QKeyEvent, QAction from PyQt6.QtWidgets import ( - QTableWidget, QMessageBox, QPushButton, QToolBar, QMenuBar, + QTableView, ) -from _pytest.fixtures import SubRequest from pytestqt.qtbot import QtBot -from buzz.cache import TasksCache -from buzz.transcriber.transcriber import ( - FileTranscriptionTask, - TranscriptionOptions, - FileTranscriptionOptions, -) +from buzz.db.entity.transcription import Transcription +from buzz.db.service.transcription_service import TranscriptionService from buzz.widgets.main_window import MainWindow from buzz.widgets.transcriber.file_transcriber_widget import FileTranscriberWidget from buzz.widgets.transcription_viewer.transcription_viewer_widget import ( TranscriptionViewerWidget, ) -mock_tasks = [ - FileTranscriptionTask( - file_path="", - transcription_options=TranscriptionOptions(), - file_transcription_options=FileTranscriptionOptions(file_paths=[]), - model_path="", - status=FileTranscriptionTask.Status.COMPLETED, - ), - FileTranscriptionTask( - file_path="", - transcription_options=TranscriptionOptions(), - file_transcription_options=FileTranscriptionOptions(file_paths=[]), - model_path="", - status=FileTranscriptionTask.Status.CANCELED, - ), - FileTranscriptionTask( - file_path="", - transcription_options=TranscriptionOptions(), - file_transcription_options=FileTranscriptionOptions(file_paths=[]), - model_path="", - status=FileTranscriptionTask.Status.FAILED, - error="Error", - ), +mock_transcriptions: List[Transcription] = [ + Transcription(status="completed"), + Transcription(status="canceled"), + Transcription(status="failed", error_message="Error"), ] @@ -58,37 +34,41 @@ def get_test_asset(filename: str): class TestMainWindow: - def test_should_set_window_title_and_icon(self, qtbot): - window = MainWindow() + def test_should_set_window_title_and_icon(self, qtbot, transcription_service): + window = MainWindow(transcription_service) qtbot.add_widget(window) assert window.windowTitle() == "Buzz" assert window.windowIcon().pixmap(QSize(64, 64)).isNull() is False window.close() - def test_should_run_file_transcription_task(self, qtbot: QtBot, tasks_cache): - window = MainWindow(tasks_cache=tasks_cache) + def test_should_run_file_transcription_task( + self, qtbot: QtBot, transcription_service + ): + window = MainWindow(transcription_service) - self.import_file_and_start_transcription(window) + self._import_file_and_start_transcription(window) open_transcript_action = self._get_toolbar_action(window, "Open Transcript") assert open_transcript_action.isEnabled() is False - table_widget: QTableWidget = window.findChild(QTableWidget) + table_widget = self._get_tasks_table(window) qtbot.wait_until( - self.get_assert_task_status_callback(table_widget, 0, "Completed"), + self._get_assert_task_status_callback(table_widget, 0, "completed"), timeout=2 * 60 * 1000, ) - table_widget.setCurrentIndex( - table_widget.indexFromItem(table_widget.item(0, 1)) - ) + table_widget.setCurrentIndex(table_widget.model().index(0, 0)) assert open_transcript_action.isEnabled() window.close() + @staticmethod + def _get_tasks_table(window: MainWindow) -> QTableView: + return window.findChild(QTableView) + def test_should_run_url_import_file_transcription_task( - self, qtbot: QtBot, tasks_cache + self, qtbot: QtBot, db, transcription_service ): - window = MainWindow(tasks_cache=tasks_cache) + window = MainWindow(transcription_service) menu: QMenuBar = window.menuBar() file_action = menu.actions()[0] import_url_action: QAction = file_action.menu().actions()[1] @@ -105,24 +85,26 @@ def test_should_run_url_import_file_transcription_task( run_button: QPushButton = file_transcriber_widget.findChild(QPushButton) run_button.click() - table_widget: QTableWidget = window.findChild(QTableWidget) + table_widget = self._get_tasks_table(window) qtbot.wait_until( - self.get_assert_task_status_callback(table_widget, 0, "Completed"), + self._get_assert_task_status_callback(table_widget, 0, "completed"), timeout=2 * 60 * 1000, ) window.close() - def test_should_run_and_cancel_transcription_task(self, qtbot, tasks_cache): - window = MainWindow(tasks_cache=tasks_cache) + def test_should_run_and_cancel_transcription_task( + self, qtbot, db, transcription_service + ): + window = MainWindow(transcription_service) qtbot.add_widget(window) - self.import_file_and_start_transcription(window, long_audio=True) + self._import_file_and_start_transcription(window, long_audio=True) - table_widget: QTableWidget = window.findChild(QTableWidget) + table_widget = self._get_tasks_table(window) qtbot.wait_until( - self.get_assert_task_status_callback(table_widget, 0, "In Progress"), + self._get_assert_task_status_callback(table_widget, 0, "in_progress"), timeout=2 * 60 * 1000, ) @@ -131,7 +113,7 @@ def test_should_run_and_cancel_transcription_task(self, qtbot, tasks_cache): window.toolbar.stop_transcription_action.trigger() qtbot.wait_until( - self.get_assert_task_status_callback(table_widget, 0, "Canceled"), + self._get_assert_task_status_callback(table_widget, 0, "canceled"), timeout=60 * 1000, ) @@ -141,60 +123,72 @@ def test_should_run_and_cancel_transcription_task(self, qtbot, tasks_cache): window.close() - @pytest.mark.parametrize("tasks_cache", [mock_tasks], indirect=True) - def test_should_load_tasks_from_cache(self, qtbot, tasks_cache): - window = MainWindow(tasks_cache=tasks_cache) + @pytest.mark.parametrize("transcription_dao", [mock_transcriptions], indirect=True) + def test_should_load_tasks_from_cache( + self, qtbot, transcription_dao, transcription_segment_dao + ): + window = MainWindow( + TranscriptionService(transcription_dao, transcription_segment_dao) + ) qtbot.add_widget(window) - table_widget: QTableWidget = window.findChild(QTableWidget) - assert table_widget.rowCount() == 3 + table_widget = self._get_tasks_table(window) + assert table_widget.model().rowCount() == 3 - assert table_widget.item(0, 4).text() == "Completed" + assert self._get_status(table_widget, 0) == "completed" table_widget.selectRow(0) assert window.toolbar.open_transcript_action.isEnabled() - assert table_widget.item(1, 4).text() == "Canceled" + assert self._get_status(table_widget, 1) == "canceled" table_widget.selectRow(1) assert window.toolbar.open_transcript_action.isEnabled() is False - assert table_widget.item(2, 4).text() == "Failed (Error)" + assert self._get_status(table_widget, 2) == "failed" table_widget.selectRow(2) assert window.toolbar.open_transcript_action.isEnabled() is False window.close() - @pytest.mark.parametrize("tasks_cache", [mock_tasks], indirect=True) - def test_should_clear_history_with_rows_selected(self, qtbot, tasks_cache): - window = MainWindow(tasks_cache=tasks_cache) + @pytest.mark.parametrize("transcription_dao", [mock_transcriptions], indirect=True) + def test_should_clear_history_with_rows_selected( + self, qtbot, transcription_dao, transcription_segment_dao + ): + window = MainWindow( + TranscriptionService(transcription_dao, transcription_segment_dao) + ) + qtbot.add_widget(window) - table_widget: QTableWidget = window.findChild(QTableWidget) + table_widget = self._get_tasks_table(window) table_widget.selectAll() with patch("PyQt6.QtWidgets.QMessageBox.question") as question_message_box_mock: question_message_box_mock.return_value = QMessageBox.StandardButton.Yes window.toolbar.clear_history_action.trigger() - assert table_widget.rowCount() == 0 + assert table_widget.model().rowCount() == 0 window.close() - @pytest.mark.parametrize("tasks_cache", [mock_tasks], indirect=True) + @pytest.mark.parametrize("transcription_dao", [mock_transcriptions], indirect=True) def test_should_have_clear_history_action_disabled_with_no_rows_selected( - self, qtbot, tasks_cache + self, qtbot, transcription_dao, transcription_segment_dao ): - window = MainWindow(tasks_cache=tasks_cache) + window = MainWindow( + TranscriptionService(transcription_dao, transcription_segment_dao) + ) qtbot.add_widget(window) assert window.toolbar.clear_history_action.isEnabled() is False window.close() - @pytest.mark.parametrize("tasks_cache", [mock_tasks], indirect=True) + @pytest.mark.parametrize("transcription_dao", [mock_transcriptions], indirect=True) def test_should_open_transcription_viewer_when_menu_action_is_clicked( - self, qtbot, tasks_cache + self, qtbot, transcription_dao, transcription_segment_dao ): - window = MainWindow(tasks_cache=tasks_cache) + window = MainWindow( + TranscriptionService(transcription_dao, transcription_segment_dao) + ) qtbot.add_widget(window) - table_widget: QTableWidget = window.findChild(QTableWidget) - + table_widget = self._get_tasks_table(window) table_widget.selectRow(0) window.toolbar.open_transcript_action.trigger() @@ -204,14 +198,16 @@ def test_should_open_transcription_viewer_when_menu_action_is_clicked( window.close() - @pytest.mark.parametrize("tasks_cache", [mock_tasks], indirect=True) + @pytest.mark.parametrize("transcription_dao", [mock_transcriptions], indirect=True) def test_should_open_transcription_viewer_when_return_clicked( - self, qtbot, tasks_cache + self, qtbot, transcription_dao, transcription_segment_dao ): - window = MainWindow(tasks_cache=tasks_cache) + window = MainWindow( + TranscriptionService(transcription_dao, transcription_segment_dao) + ) qtbot.add_widget(window) - table_widget: QTableWidget = window.findChild(QTableWidget) + table_widget = self._get_tasks_table(window) table_widget.selectRow(0) table_widget.keyPressEvent( QKeyEvent( @@ -227,18 +223,20 @@ def test_should_open_transcription_viewer_when_return_clicked( window.close() - @pytest.mark.parametrize("tasks_cache", [mock_tasks], indirect=True) + @pytest.mark.parametrize("transcription_dao", [mock_transcriptions], indirect=True) def test_should_have_open_transcript_action_disabled_with_no_rows_selected( - self, qtbot, tasks_cache + self, qtbot, transcription_dao, transcription_segment_dao ): - window = MainWindow(tasks_cache=tasks_cache) + window = MainWindow( + TranscriptionService(transcription_dao, transcription_segment_dao) + ) qtbot.add_widget(window) assert window.toolbar.open_transcript_action.isEnabled() is False window.close() @staticmethod - def import_file_and_start_transcription( + def _import_file_and_start_transcription( window: MainWindow, long_audio: bool = False ): with patch( @@ -264,34 +262,24 @@ def import_file_and_start_transcription( run_button.click() @staticmethod - def get_assert_task_status_callback( - table_widget: QTableWidget, + def _get_assert_task_status_callback( + table_widget: QTableView, row_index: int, expected_status: str, - long_audio: bool = False, ): def assert_task_status(): - assert table_widget.rowCount() > 0 - assert ( - table_widget.item(row_index, 1).text() == "audio-long.mp3" - if long_audio - else "whisper-french.mp3" + assert table_widget.model().rowCount() > 0 + assert expected_status in TestMainWindow._get_status( + table_widget, row_index ) - assert expected_status in table_widget.item(row_index, 4).text() return assert_task_status + @staticmethod + def _get_status(table_widget: QTableView, row_index: int): + return table_widget.model().index(row_index, 9).data() + @staticmethod def _get_toolbar_action(window: MainWindow, text: str): toolbar: QToolBar = window.findChild(QToolBar) return [action for action in toolbar.actions() if action.text() == text][0] - - -@pytest.fixture() -def tasks_cache(tmp_path, request: SubRequest): - cache = TasksCache(cache_dir=str(tmp_path)) - if hasattr(request, "param"): - tasks: List[FileTranscriptionTask] = request.param - cache.save(tasks) - yield cache - cache.clear() diff --git a/tests/widgets/transcription_tasks_table_widget_test.py b/tests/widgets/transcription_tasks_table_widget_test.py index 99b4bd398c..fd3ca321d5 100644 --- a/tests/widgets/transcription_tasks_table_widget_test.py +++ b/tests/widgets/transcription_tasks_table_widget_test.py @@ -1,115 +1,7 @@ -import datetime - -from pytestqt.qtbot import QtBot - -from buzz.transcriber.transcriber import ( - FileTranscriptionTask, - TranscriptionOptions, - FileTranscriptionOptions, -) from buzz.widgets.transcription_tasks_table_widget import TranscriptionTasksTableWidget class TestTranscriptionTasksTableWidget: - def test_upsert_task(self, qtbot: QtBot): - widget = TranscriptionTasksTableWidget() - qtbot.add_widget(widget) - - task = FileTranscriptionTask( - id=0, - file_path="testdata/whisper-french.mp3", - transcription_options=TranscriptionOptions(), - file_transcription_options=FileTranscriptionOptions( - file_paths=["testdata/whisper-french.mp3"] - ), - model_path="", - status=FileTranscriptionTask.Status.QUEUED, - ) - task.queued_at = datetime.datetime(2023, 4, 12, 0, 0, 0) - task.started_at = datetime.datetime(2023, 4, 12, 0, 0, 5) - - widget.upsert_task(task) - - assert widget.rowCount() == 1 - self.assert_row_text( - widget, 0, "whisper-french.mp3", "Whisper (Tiny)", "Transcribe", "Queued" - ) - - task.status = FileTranscriptionTask.Status.IN_PROGRESS - task.fraction_completed = 0.3524 - widget.upsert_task(task) - - assert widget.rowCount() == 1 - self.assert_row_text( - widget, - 0, - "whisper-french.mp3", - "Whisper (Tiny)", - "Transcribe", - "In Progress (35%)", - ) - - task.status = FileTranscriptionTask.Status.COMPLETED - task.completed_at = datetime.datetime(2023, 4, 12, 0, 0, 10) - widget.upsert_task(task) - - assert widget.rowCount() == 1 - self.assert_row_text( - widget, - 0, - "whisper-french.mp3", - "Whisper (Tiny)", - "Transcribe", - "Completed (5s)", - ) - - def test_upsert_task_no_timings(self, qtbot: QtBot): - widget = TranscriptionTasksTableWidget() - qtbot.add_widget(widget) - - task = FileTranscriptionTask( - id=0, - file_path="testdata/whisper-french.mp3", - transcription_options=TranscriptionOptions(), - file_transcription_options=FileTranscriptionOptions( - file_paths=["testdata/whisper-french.mp3"] - ), - model_path="", - status=FileTranscriptionTask.Status.COMPLETED, - ) - widget.upsert_task(task) - - assert widget.rowCount() == 1 - self.assert_row_text( - widget, 0, "whisper-french.mp3", "Whisper (Tiny)", "Transcribe", "Completed" - ) - - def test_toggle_column_visibility(self, qtbot, reset_settings): + def test_can_create(self, qtbot, reset_settings): widget = TranscriptionTasksTableWidget() qtbot.add_widget(widget) - - assert widget.isColumnHidden(TranscriptionTasksTableWidget.Column.TASK_ID.value) - assert not widget.isColumnHidden( - TranscriptionTasksTableWidget.Column.FILE_NAME.value - ) - assert widget.isColumnHidden(TranscriptionTasksTableWidget.Column.MODEL.value) - assert widget.isColumnHidden(TranscriptionTasksTableWidget.Column.TASK.value) - assert not widget.isColumnHidden( - TranscriptionTasksTableWidget.Column.STATUS.value - ) - - # TODO: open context menu and toggle column visibility - - def assert_row_text( - self, - widget: TranscriptionTasksTableWidget, - row: int, - filename: str, - model: str, - task: str, - status: str, - ): - assert widget.item(row, 1).text() == filename - assert widget.item(row, 2).text() == model - assert widget.item(row, 3).text() == task - assert widget.item(row, 4).text() == status diff --git a/tests/widgets/transcription_viewer_test.py b/tests/widgets/transcription_viewer_test.py index e9bd73f230..aa2ba30b19 100644 --- a/tests/widgets/transcription_viewer_test.py +++ b/tests/widgets/transcription_viewer_test.py @@ -1,16 +1,15 @@ import pathlib +import uuid from unittest.mock import patch import pytest -from PyQt6.QtWidgets import QPushButton, QToolBar +from PyQt6.QtWidgets import QPushButton from pytestqt.qtbot import QtBot -from buzz.transcriber.transcriber import ( - FileTranscriptionTask, - FileTranscriptionOptions, - TranscriptionOptions, - Segment, -) +from buzz.db.entity.transcription import Transcription +from buzz.db.entity.transcription_segment import TranscriptionSegment +from buzz.model_loader import ModelType, WhisperModelSize +from buzz.transcriber.transcriber import Task from buzz.widgets.transcription_viewer.transcription_segments_editor_widget import ( TranscriptionSegmentsEditorWidget, ) @@ -21,22 +20,29 @@ class TestTranscriptionViewerWidget: @pytest.fixture() - def task(self) -> FileTranscriptionTask: - return FileTranscriptionTask( - id=0, - file_path="testdata/whisper-french.mp3", - file_transcription_options=FileTranscriptionOptions( - file_paths=["testdata/whisper-french.mp3"] - ), - transcription_options=TranscriptionOptions(), - segments=[Segment(40, 299, "Bien"), Segment(299, 329, "venue dans")], - model_path="", + def transcription( + self, transcription_dao, transcription_segment_dao + ) -> Transcription: + id = uuid.uuid4() + transcription_dao.insert( + Transcription( + id=str(id), + status="completed", + file="testdata/whisper-french.mp3", + task=Task.TRANSCRIBE.value, + model_type=ModelType.WHISPER.value, + whisper_model_size=WhisperModelSize.SMALL.value, + ) ) - - def test_should_display_segments(self, qtbot: QtBot, task): - widget = TranscriptionViewerWidget( - transcription_task=task, open_transcription_output=False + transcription_segment_dao.insert(TranscriptionSegment(40, 299, "Bien", str(id))) + transcription_segment_dao.insert( + TranscriptionSegment(299, 329, "venue dans", str(id)) ) + + return transcription_dao.find_by_id(str(id)) + + def test_should_display_segments(self, qtbot: QtBot, transcription): + widget = TranscriptionViewerWidget(transcription) qtbot.add_widget(widget) assert widget.windowTitle() == "whisper-french.mp3" @@ -44,37 +50,23 @@ def test_should_display_segments(self, qtbot: QtBot, task): editor = widget.findChild(TranscriptionSegmentsEditorWidget) assert isinstance(editor, TranscriptionSegmentsEditorWidget) - assert editor.item(0, 0).text() == "00:00:00.040" - assert editor.item(0, 1).text() == "00:00:00.299" - assert editor.item(0, 2).text() == "Bien" + assert editor.model().index(0, 1).data() == 299 + assert editor.model().index(0, 2).data() == 40 + assert editor.model().index(0, 3).data() == "Bien" - def test_should_update_segment_text(self, qtbot, task): - widget = TranscriptionViewerWidget( - transcription_task=task, open_transcription_output=False - ) + def test_should_update_segment_text(self, qtbot, transcription): + widget = TranscriptionViewerWidget(transcription) qtbot.add_widget(widget) editor = widget.findChild(TranscriptionSegmentsEditorWidget) assert isinstance(editor, TranscriptionSegmentsEditorWidget) - # Change text - editor.item(0, 2).setText("Biens") - assert task.segments[0].text == "Biens" + editor.model().setData(editor.model().index(0, 3), "Biens") - # Undo - toolbar = widget.findChild(QToolBar) - undo_action, redo_action = toolbar.actions() - - undo_action.trigger() - assert task.segments[0].text == "Bien" - - redo_action.trigger() - assert task.segments[0].text == "Biens" - - def test_should_export_segments(self, tmp_path: pathlib.Path, qtbot: QtBot, task): - widget = TranscriptionViewerWidget( - transcription_task=task, open_transcription_output=False - ) + def test_should_export_segments( + self, tmp_path: pathlib.Path, qtbot: QtBot, transcription + ): + widget = TranscriptionViewerWidget(transcription) qtbot.add_widget(widget) export_button = widget.findChild(QPushButton) @@ -87,5 +79,5 @@ def test_should_export_segments(self, tmp_path: pathlib.Path, qtbot: QtBot, task save_file_name_mock.return_value = (str(output_file_path), "") export_button.menu().actions()[0].trigger() - output_file = open(output_file_path, "r", encoding="utf-8") - assert "Bien\nvenue dans" in output_file.read() + with open(output_file_path, encoding="utf-8") as output_file: + assert "Bien\nvenue dans" in output_file.read()