diff --git a/.gitignore b/.gitignore index 5669fa6f..a3619ea8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,10 @@ -# Python -__pycache__/ *.py[cod] -*$py.class -*.so +__pycache__/ +.pytest_cache/ +.coverage +htmlcov/ + +# Distribution / packaging .Python build/ develop-eggs/ @@ -20,7 +22,12 @@ wheels/ .installed.cfg *.egg -# Virtual Environment +# Installer artifacts +installer/build/ +installer/dist/ +rw.*.dmg # Temporary disk images + +# Virtual environments .env .venv env/ @@ -30,13 +37,8 @@ ENV/ # IDE .idea/ .vscode/ +*.swp +*.swo -# Project specific -projects/*.db -projects/*.db-journal -/.coverage - -**/.DS_Store - -*.log -/.coverage.* +# macOS +.DS_Store diff --git a/Makefile b/Makefile index b04b36f2..fc099fab 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: install test lint clean format type-check +.PHONY: install test lint clean format type-check installer install: pip install -e ".[dev]" @@ -15,7 +15,13 @@ type-check: clean: find . -type f -name '*.pyc' -delete find . -type d -name '__pycache__' -exec rm -r {} + + rm -rf installer/build/ + rm -rf installer/dist/ + rm -f rw.*.dmg rm -rf dist + rm -rf installer/build + rm -rf installer/dist + rm .coverage.* format: uv run ruff format . @@ -23,3 +29,10 @@ format: # run inspector tool run-dev: uv run mcp dev src/basic_memory/mcp/main.py + +# Build app installer +installer: + cd installer && uv run python setup.py bdist_mac + +update-deps: + uv lock f--upgrade diff --git a/installer/README.md b/installer/README.md new file mode 100644 index 00000000..f5fcb65e --- /dev/null +++ b/installer/README.md @@ -0,0 +1,18 @@ +# Basic Memory Installer + +This directory contains the macOS installer for Basic Memory. + +## Building the Installer + +Build the installer: +```bash +cd installer +python setup.py build +``` + +The installer app will be created in `installer/build/Basic Memory Installer` + +## Development + +- `installer.py` - Main installation script +- `setup.py` - py2app configuration for building the macOS app diff --git a/installer/installer.py b/installer/installer.py new file mode 100644 index 00000000..d798ea0c --- /dev/null +++ b/installer/installer.py @@ -0,0 +1,51 @@ +import json +import os +import subprocess +from pathlib import Path + +def ensure_uv_installed(): + """Check if uv is installed, install if not.""" + try: + subprocess.run(['uv', '--version'], capture_output=True, check=True) + except (subprocess.CalledProcessError, FileNotFoundError): + print("Installing uv package manager...") + subprocess.run(['curl', '-LsSf', 'https://github.com/astral-sh/uv/releases/download/0.1.23/uv-installer.sh', '|', 'sh'], shell=True) + +def update_claude_config(): + """Update Claude Desktop config to include basic-memory.""" + config_path = Path.home() / 'Library/Application Support/Claude/claude_desktop_config.json' + config_path.parent.mkdir(parents=True, exist_ok=True) + + # Load existing config or create new + if config_path.exists(): + config = json.loads(config_path.read_text()) + else: + config = {"mcpServers": {}} + + # Add/update basic-memory config + config['mcpServers']['basic-memory'] = { + "command": "uvx", + "args": ["basic-memory"] + } + + # Write back config + config_path.write_text(json.dumps(config, indent=2)) + +def print_completion_message(): + """Show completion message with helpful tips.""" + print("\nInstallation complete! Basic Memory is now available in Claude Desktop.") + print("Please restart Claude Desktop for changes to take effect.") + print("\nQuick Start:") + print("1. You can run sync directly using: uvx basic-memory sync") + print("2. Optionally, install globally with: uv pip install basic-memory") + print("\nBuilt with ♥️ by Basic Machines.") + +def main(): + print("Welcome to Basic Memory installer") + ensure_uv_installed() + print("Configuring Claude Desktop...") + update_claude_config() + print_completion_message() + +if __name__ == '__main__': + main() diff --git a/installer/setup.py b/installer/setup.py new file mode 100644 index 00000000..02f0639b --- /dev/null +++ b/installer/setup.py @@ -0,0 +1,16 @@ +from cx_Freeze import setup, Executable + +executables = [ + Executable( + "installer.py", + target_name="Basic Memory Installer", + base="gui" + ) +] + +setup( + name="basic-memory", + version=open("../pyproject.toml").read().split('version = "', 1)[1].split('"', 1)[0], + description="Basic Memory", + executables=executables, +) diff --git a/pyproject.toml b/pyproject.toml index deb9b5a7..0711bd92 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,8 +28,11 @@ dependencies = [ "watchfiles>=1.0.4", "fastapi[standard]>=0.115.8", "alembic>=1.14.1", + "rumps>=0.4.0", + "qasync>=0.27.1", ] + [project.urls] Homepage = "https://github.com/basicmachines-co/basic-memory" Repository = "https://github.com/basicmachines-co/basic-memory" @@ -62,9 +65,15 @@ dev-dependencies = [ "pytest-mock>=3.12.0", "pytest-asyncio>=0.24.0", "ruff>=0.1.6", + "pytest>=8.3.4", + "pytest-cov>=4.1.0", + "pytest-mock>=3.12.0", + "pytest-asyncio>=0.24.0", + "ruff>=0.1.6", + "cx-freeze>=7.2.10", + "pyqt6>=6.8.1", ] - [tool.pyright] include = ["src/"] exclude = ["**/__pycache__"] diff --git a/scripts/install.sh b/scripts/install.sh new file mode 100755 index 00000000..c2931d0a --- /dev/null +++ b/scripts/install.sh @@ -0,0 +1,36 @@ +#!/bin/bash +set -e + +echo "Welcome to Basic Memory installer" + +# 1. Install uv if not present +if ! command -v uv &> /dev/null; then + echo "Installing uv package manager..." + curl -LsSf https://github.com/astral-sh/uv/releases/download/0.1.23/uv-installer.sh | sh +fi + +# 2. Configure Claude Desktop +echo "Configuring Claude Desktop..." +CONFIG_FILE="$HOME/Library/Application Support/Claude/claude_desktop_config.json" + +# Create config directory if it doesn't exist +mkdir -p "$(dirname "$CONFIG_FILE")" + +# If config file doesn't exist, create it with initial structure +if [ ! -f "$CONFIG_FILE" ]; then + echo '{"mcpServers": {}}' > "$CONFIG_FILE" +fi + +# Add/update the basic-memory config using jq +jq '.mcpServers."basic-memory" = { + "command": "uvx", + "args": ["basic-memory"] +}' "$CONFIG_FILE" > "$CONFIG_FILE.tmp" && mv "$CONFIG_FILE.tmp" "$CONFIG_FILE" + +echo "Installation complete! Basic Memory is now available in Claude Desktop." +echo "Please restart Claude Desktop for changes to take effect." + +echo -e "\nQuick Start:" +echo "1. You can run sync directly using: uvx basic-memory sync" +echo "2. Optionally, install globally with: uv pip install basic-memory" +echo -e "\nBuilt with ♥️ by Basic Machines." \ No newline at end of file diff --git a/src/basic_memory/cli/commands/sync.py b/src/basic_memory/cli/commands/sync.py index 9b0101c3..20e352f9 100644 --- a/src/basic_memory/cli/commands/sync.py +++ b/src/basic_memory/cli/commands/sync.py @@ -97,51 +97,7 @@ def group_issues_by_directory(issues: List[ValidationIssue]) -> Dict[str, List[V return dict(grouped) -def display_validation_errors(issues: List[ValidationIssue]): - """Display validation errors in a rich, organized format.""" - # Create header - console.print() - console.print( - Panel("[red bold]Error:[/red bold] Invalid frontmatter in knowledge files", expand=False) - ) - console.print() - # Group issues by directory - grouped_issues = group_issues_by_directory(issues) - - # Create tree structure - tree = Tree("Knowledge Files") - for dir_name, dir_issues in sorted(grouped_issues.items()): - # Create branch for directory - branch = tree.add( - f"[bold blue]{dir_name}/[/bold blue] ([yellow]{len(dir_issues)} files[/yellow])" - ) - - # Add each file issue - for issue in sorted(dir_issues, key=lambda x: x.file_path): - file_name = Path(issue.file_path).name - branch.add( - Text.assemble(("└─ ", "dim"), (file_name, "yellow"), ": ", (issue.error, "red")) - ) - - # Display tree - console.print(Padding(tree, (1, 2))) - - # Add help text - console.print() - console.print( - Panel( - Text.assemble( - ("To fix:", "bold"), - "\n1. Add required frontmatter fields to each file", - "\n2. Run ", - ("basic-memory sync", "bold cyan"), - " again", - ), - expand=False, - ) - ) - console.print() def display_sync_summary(knowledge: SyncReport): diff --git a/src/basic_memory/schemas/__init__.py b/src/basic_memory/schemas/__init__.py index 77f59103..19b88de8 100644 --- a/src/basic_memory/schemas/__init__.py +++ b/src/basic_memory/schemas/__init__.py @@ -24,7 +24,6 @@ from basic_memory.schemas.request import ( SearchNodesRequest, GetEntitiesRequest, CreateRelationsRequest, - UpdateEntityRequest, ) # Response models @@ -57,7 +56,6 @@ __all__ = [ "SearchNodesRequest", "GetEntitiesRequest", "CreateRelationsRequest", - "UpdateEntityRequest", # Responses "SQLAlchemyModel", "ObservationResponse", diff --git a/src/basic_memory/schemas/request.py b/src/basic_memory/schemas/request.py index b66113f8..ba2d3df4 100644 --- a/src/basic_memory/schemas/request.py +++ b/src/basic_memory/schemas/request.py @@ -58,15 +58,3 @@ class GetEntitiesRequest(BaseModel): class CreateRelationsRequest(BaseModel): relations: List[Relation] - -## update - - -# TODO remove UpdateEntityRequest -class UpdateEntityRequest(BaseModel): - """Request to update an existing entity.""" - - title: Optional[str] = None - entity_type: Optional[EntityType] = None - content: Optional[str] = None - entity_metadata: Optional[Dict[str, Any]] = None diff --git a/src/basic_memory/services/search_service.py b/src/basic_memory/services/search_service.py index d3d14d86..99037107 100644 --- a/src/basic_memory/services/search_service.py +++ b/src/basic_memory/services/search_service.py @@ -149,7 +149,6 @@ class SearchService: title_variants = self._generate_variants(entity.title) content_parts.extend(title_variants) - # TODO should we do something to content on indexing? content = await self.file_service.read_entity_content(entity) if content: content_parts.append(content) diff --git a/src/basic_memory/sync/__init__.py b/src/basic_memory/sync/__init__.py index 1d908cdb..58874bb8 100644 --- a/src/basic_memory/sync/__init__.py +++ b/src/basic_memory/sync/__init__.py @@ -1,4 +1,6 @@ from .file_change_scanner import FileChangeScanner from .sync_service import SyncService +from .watch_service import WatchService + +__all__ = ["SyncService", "FileChangeScanner", "WatchService"] -__all__ = ["SyncService", "FileChangeScanner"] diff --git a/src/basic_memory/sync/watch_service.py b/src/basic_memory/sync/watch_service.py index d0011c3d..d270ae40 100644 --- a/src/basic_memory/sync/watch_service.py +++ b/src/basic_memory/sync/watch_service.py @@ -130,13 +130,36 @@ class WatchService: return table - async def run(self): + async def run(self, console_status: bool = False): # pragma: no cover """Watch for file changes and sync them""" + logger.info("Watching for sync changes") self.state.running = True self.state.start_time = datetime.now() await self.write_status() - with Live(self.generate_table(), refresh_per_second=4, console=self.console) as live: + if console_status: + with Live(self.generate_table(), refresh_per_second=4, console=self.console) as live: + try: + async for changes in awatch( + self.config.home, + watch_filter=self.filter_changes, + debounce=self.config.sync_delay, + recursive=True, + ): + # Process changes + await self.handle_changes(self.config.home) + # Update display + live.update(self.generate_table()) + + except Exception as e: + self.state.record_error(str(e)) + await self.write_status() + raise + finally: + self.state.running = False + await self.write_status() + + else: try: async for changes in awatch( self.config.home, @@ -145,11 +168,10 @@ class WatchService: recursive=True, ): # Process changes - await self.handle_changes(self.config.home) # pragma: no cover + await self.handle_changes(self.config.home) # Update display - live.update(self.generate_table()) # pragma: no cover - except Exception as e: # pragma: no cover + except Exception as e: self.state.record_error(str(e)) await self.write_status() raise diff --git a/src/basic_memory/ui/menubar/__init__.py b/src/basic_memory/ui/menubar/__init__.py new file mode 100644 index 00000000..d16b6be1 --- /dev/null +++ b/src/basic_memory/ui/menubar/__init__.py @@ -0,0 +1,4 @@ +"""Basic Memory menubar application package.""" +from .app import BasicMemoryApp, main + +__all__ = ["BasicMemoryApp", "main"] diff --git a/src/basic_memory/ui/menubar/app.py b/src/basic_memory/ui/menubar/app.py new file mode 100644 index 00000000..6771a895 --- /dev/null +++ b/src/basic_memory/ui/menubar/app.py @@ -0,0 +1,189 @@ +"""Basic Memory menubar app - process manager for sync service.""" +import os +import sys +import subprocess +from PyQt6.QtWidgets import QApplication, QSystemTrayIcon, QMenu, QStyle, QMainWindow, QTextEdit +from PyQt6.QtCore import QTimer +from loguru import logger + +from basic_memory.config import config + + +class StatusWindow(QMainWindow): + """Window to show sync process output.""" + def __init__(self): + super().__init__() + self.setWindowTitle("Basic Memory Status") + self.resize(800, 400) + + # Create terminal-like text display + self.text_display = QTextEdit() + self.text_display.setReadOnly(True) + self.text_display.setStyleSheet(""" + QTextEdit { + background-color: #1e1e1e; + color: #ffffff; + font-family: Menlo, Monaco, 'Courier New', monospace; + font-size: 12px; + padding: 8px; + } + """) + self.setCentralWidget(self.text_display) + + # Update timer for reading process output + self.update_timer = QTimer() + self.update_timer.timeout.connect(self.update_output) + self.update_timer.start(100) # Check output every 100ms + + def set_process(self, process): + """Set the process to monitor.""" + self.process = process + self.text_display.clear() + + def update_output(self): + """Read and display new output from process.""" + if hasattr(self, 'process') and self.process: + while True: + line = self.process.stdout.readline() + if not line: + break + self.text_display.append(line.strip()) + +class BasicMemoryTray(QSystemTrayIcon): + """System tray icon for managing Basic Memory sync.""" + def __init__(self): + super().__init__() + + # Set icon + self.setIcon(QApplication.style().standardIcon(QStyle.StandardPixmap.SP_ComputerIcon)) + + # Create menu + menu = QMenu() + self.status_item = menu.addAction("Status: Idle") + self.status_item.setEnabled(False) + + menu.addSeparator() + self.sync_action = menu.addAction("Start Sync") + self.sync_action.triggered.connect(self.toggle_sync) + + menu.addAction("Show Status").triggered.connect(self.show_status) + + menu.addSeparator() + menu.addAction("Quit").triggered.connect(self.cleanup_and_quit) + + self.setContextMenu(menu) + self.show() + + # Initialize state + self.process = None + self.status_window = None + + # Update timer for status + self.status_timer = QTimer() + self.status_timer.timeout.connect(self.check_process) + self.status_timer.start(1000) # Check every second + + logger.info("Basic Memory tray initialized") + + def show_status(self): + """Show status window.""" + if not self.status_window: + self.status_window = StatusWindow() + if self.process: + self.status_window.set_process(self.process) + self.status_window.show() + self.status_window.raise_() + + def toggle_sync(self): + """Start or stop sync process.""" + if not self.process: + self.start_sync() + else: + self.stop_sync() + + def start_sync(self): + """Start the sync subprocess.""" + logger.info("Starting sync process") + try: + self.process = subprocess.Popen( + ['uvx', ' --directory', '/Users/phernandez/dev/basicmachines/basic-memory', 'basic-memory', 'sync', '--watch'], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + bufsize=1 # Line buffered + ) + self.sync_action.setText("Stop Sync") + if self.status_window: + self.status_window.set_process(self.process) + except Exception as e: + logger.exception("Failed to start sync process") + self.status_item.setText(f"Status: Error - {str(e)}") + + def stop_sync(self): + """Stop the sync subprocess.""" + logger.info("Stopping sync process") + if self.process: + self.process.terminate() + try: + self.process.wait(timeout=2) # Wait up to 2 seconds + except subprocess.TimeoutExpired: + self.process.kill() # Force kill if it doesn't terminate + self.process = None + self.sync_action.setText("Start Sync") + + def check_process(self): + """Check sync process status.""" + if self.process: + if self.process.poll() is not None: # Process has ended + self.process = None + self.sync_action.setText("Start Sync") + self.status_item.setText("Status: Idle") + else: + self.status_item.setText("Status: Running") + else: + self.status_item.setText("Status: Idle") + + def cleanup_and_quit(self): + """Clean up before quitting.""" + logger.info("Cleaning up...") + if self.status_window: + self.status_window.close() + self.stop_sync() + QApplication.instance().quit() + +def ensure_single_instance(): + """Ensure only one instance of the menubar app is running.""" + pid_file = config.home / ".basic-memory" / "menubar.pid" + pid_file.parent.mkdir(parents=True, exist_ok=True) + + if pid_file.exists(): + try: + pid = int(pid_file.read_text()) + os.kill(pid, 0) # Check if process exists + logger.error(f"Basic Memory menubar is already running (PID: {pid})") + sys.exit(1) + except (OSError, ValueError): + # Process not running or invalid PID + pass + + # Write current PID + pid = str(os.getpid()) + pid_file.write_text(pid) + logger.debug(f"PID {pid} written to file {pid_file}") + return pid_file + +def main(): + """Run the menubar app.""" + # Ensure single instance + pid_file = ensure_single_instance() + + try: + app = QApplication(sys.argv) + tray = BasicMemoryTray() + app.exec() + finally: + # Clean up PID file + pid_file.unlink(missing_ok=True) + +if __name__ == "__main__": + main() diff --git a/tests/api/test_knowledge_router.py b/tests/api/test_knowledge_router.py index dea6ebc6..91e3134c 100644 --- a/tests/api/test_knowledge_router.py +++ b/tests/api/test_knowledge_router.py @@ -77,8 +77,6 @@ async def test_create_entity_observations_relations(client: AsyncClient, file_se assert entity.relations[0].from_id == "test/test-entity" assert entity.relations[0].to_id is None - # TODO Relation.to_id should be name from link - # Verify file has new content but preserved metadata file_path = file_service.get_entity_path(entity) file_content, _ = await file_service.read_file(file_path) diff --git a/tests/cli/test_sync.py b/tests/cli/test_sync.py index 161447ad..e2ae357a 100644 --- a/tests/cli/test_sync.py +++ b/tests/cli/test_sync.py @@ -6,7 +6,6 @@ from typer.testing import CliRunner from basic_memory.cli.app import app from basic_memory.cli.commands.sync import ( - display_validation_errors, display_sync_summary, display_detailed_sync_results, run_sync, @@ -36,17 +35,6 @@ def test_group_issues_by_directory(): assert grouped["dir2"][0].error == "error3" -def test_display_validation_errors(): - """Test displaying validation errors.""" - issues = [ - ValidationIssue("dir1/file1.md", "Missing title"), - ValidationIssue("dir1/file2.md", "Invalid date"), - ValidationIssue("dir2/file3.md", "Missing tags"), - ] - - # Just verify it runs without error - display_validation_errors(issues) - def test_display_sync_summary_no_changes(): """Test displaying sync summary with no changes.""" diff --git a/uv.lock b/uv.lock index b5c72f29..36394bc8 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,14 @@ version = 1 requires-python = ">=3.12.1" +resolution-markers = [ + "(platform_machine != 'aarch64' and platform_machine != 'armv7l' and platform_machine != 'i686' and platform_machine != 'ppc64le' and platform_machine != 's390x' and platform_machine != 'x86_64') or (platform_machine == 'aarch64' and sys_platform != 'linux') or (platform_machine == 'armv7l' and sys_platform != 'linux') or (platform_machine == 'i686' and sys_platform != 'linux') or (platform_machine == 'ppc64le' and sys_platform != 'linux') or (platform_machine == 's390x' and sys_platform != 'linux') or (platform_machine == 'x86_64' and sys_platform != 'linux')", + "platform_machine == 'x86_64' and sys_platform == 'linux'", + "platform_machine == 'i686' and sys_platform == 'linux'", + "platform_machine == 'aarch64' and sys_platform == 'linux'", + "platform_machine == 'armv7l' and sys_platform == 'linux'", + "platform_machine == 'ppc64le' and sys_platform == 'linux'", + "platform_machine == 's390x' and sys_platform == 'linux'", +] [[package]] name = "aiosqlite" @@ -43,7 +52,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "sniffio" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "typing-extensions", marker = "python_full_version < '3.13' and python_full_version >= '3.12.1'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a3/73/199a98fc2dae33535d6b8e8e6ec01f8c1d76c9adb096c6b7d64823038cde/anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a", size = 181126 } wheels = [ @@ -78,7 +87,9 @@ dependencies = [ { name = "pyright" }, { name = "python-frontmatter" }, { name = "pyyaml" }, + { name = "qasync" }, { name = "rich" }, + { name = "rumps" }, { name = "sqlalchemy" }, { name = "typer" }, { name = "unidecode" }, @@ -87,8 +98,10 @@ dependencies = [ [package.dev-dependencies] dev = [ + { name = "cx-freeze" }, { name = "gevent" }, { name = "icecream" }, + { name = "pyqt6" }, { name = "pytest" }, { name = "pytest-asyncio" }, { name = "pytest-cov" }, @@ -112,7 +125,9 @@ requires-dist = [ { name = "pyright", specifier = ">=1.1.390" }, { name = "python-frontmatter", specifier = ">=1.1.0" }, { name = "pyyaml", specifier = ">=6.0.1" }, + { name = "qasync", specifier = ">=0.27.1" }, { name = "rich", specifier = ">=13.9.4" }, + { name = "rumps", specifier = ">=0.4.0" }, { name = "sqlalchemy", specifier = ">=2.0.0" }, { name = "typer", specifier = ">=0.9.0" }, { name = "unidecode", specifier = ">=1.3.8" }, @@ -121,8 +136,10 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ + { name = "cx-freeze", specifier = ">=7.2.10" }, { name = "gevent", specifier = ">=24.11.1" }, { name = "icecream", specifier = ">=2.1.3" }, + { name = "pyqt6", specifier = ">=6.8.1" }, { name = "pytest", specifier = ">=8.3.4" }, { name = "pytest-asyncio", specifier = ">=0.24.0" }, { name = "pytest-cov", specifier = ">=4.1.0" }, @@ -144,7 +161,7 @@ name = "cffi" version = "1.17.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pycparser" }, + { name = "pycparser", marker = "(platform_machine != 'aarch64' and platform_machine != 'armv7l' and platform_machine != 'i686' and platform_machine != 'ppc64le' and platform_machine != 's390x' and platform_machine != 'x86_64') or (platform_machine == 'aarch64' and sys_platform != 'linux') or (platform_machine == 'armv7l' and sys_platform != 'linux') or (platform_machine == 'i686' and sys_platform != 'linux') or (platform_machine == 'ppc64le' and sys_platform != 'linux') or (platform_machine == 's390x' and sys_platform != 'linux') or (platform_machine == 'x86_64' and sys_platform != 'linux')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 } wheels = [ @@ -214,6 +231,43 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fb/b2/f655700e1024dec98b10ebaafd0cedbc25e40e4abe62a3c8e2ceef4f8f0a/coverage-7.6.12-py3-none-any.whl", hash = "sha256:eb8668cfbc279a536c633137deeb9435d2962caec279c3f8cf8b91fff6ff8953", size = 200552 }, ] +[[package]] +name = "cx-freeze" +version = "7.2.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cx-logging", marker = "sys_platform == 'win32'" }, + { name = "dmgbuild", marker = "sys_platform == 'darwin'" }, + { name = "filelock", marker = "sys_platform == 'linux'" }, + { name = "lief", marker = "sys_platform == 'win32'" }, + { name = "packaging" }, + { name = "patchelf", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'armv7l' and sys_platform == 'linux') or (platform_machine == 'i686' and sys_platform == 'linux') or (platform_machine == 'ppc64le' and sys_platform == 'linux') or (platform_machine == 's390x' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d4/c3/9f05155f7e0f55041add55cedc8724e9d36418c11c2e29131056fbce8e5e/cx_freeze-7.2.10.tar.gz", hash = "sha256:16a6eb37db7d158d0eb4bba8b93a135b6c85ea4bf2c4176c437bc34f01067e61", size = 3146042 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e2/9a/0f4084aa728a67974574eac2f1db3a032671536f68a935f340caa31b8667/cx_Freeze-7.2.10-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4a908dcad86888b741aa2051a65693d8662999a8abf9b7cf3285ef4ccfddad43", size = 21397503 }, + { url = "https://files.pythonhosted.org/packages/f6/ba/1a66ed666e128152ee9d43b6aa952db823de9918fc7c864373c1000816a4/cx_Freeze-7.2.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:416460e7f3312b1e2010ce5cb35e0449ff5a6e75b3536adddf83fd9b10d13a88", size = 12649925 }, + { url = "https://files.pythonhosted.org/packages/bf/29/e0b3fa58394bfc6bc3ce1776e77788e6c8a856fd850974924791b4d5e661/cx_Freeze-7.2.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:851a0d919a732d17e1db145c72d69b5560ab1578387e18915a9e9f0be1bc50fd", size = 13949452 }, + { url = "https://files.pythonhosted.org/packages/3c/bd/c237c1b0c48cf5fe2103dedad42a3d36c0ef6c44ab86265f8480d13b3c6f/cx_Freeze-7.2.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e251c74b2551668ae890d4c7a2fbb73a6c9b692de4096ddd9867322873e11b2b", size = 12787091 }, + { url = "https://files.pythonhosted.org/packages/8f/66/fae7d0992e72290a08494fa7c5826f00b5130e63747a434993a140746e07/cx_Freeze-7.2.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a7f5d65830cb3b0d24590e4526995baf01beeb2517c41838d597c5a2e4ca76d7", size = 13766813 }, + { url = "https://files.pythonhosted.org/packages/f1/78/c123ec526b57531851d9d9c3338aa2df41b396fe3d23b7a2737bf1ef1a63/cx_Freeze-7.2.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d00914208a2953125398d192d1c332eea2bfb4f210a1507efe5188fec18fb8e3", size = 13315368 }, + { url = "https://files.pythonhosted.org/packages/ac/6c/4a3ef0c1991805505b2ea69fd09e1fd694138b011d2c62808ab5d4548b16/cx_Freeze-7.2.10-cp312-cp312-win32.whl", hash = "sha256:c0af82ba512323a1036a42c2e863ea56e12764c8c9f0764303df1fa3e29b9d4a", size = 2136880 }, + { url = "https://files.pythonhosted.org/packages/06/4c/d1c81cb9cf6b0a68837d7ee44a98a3269bafbc259cb8b3b96c22ac1e235e/cx_Freeze-7.2.10-cp312-cp312-win_amd64.whl", hash = "sha256:15b7dafc5eb2b5f6c118eaeed25b0fb0f3a9022e779958e5f9cd1ebf9f77c737", size = 2139867 }, +] + +[[package]] +name = "cx-logging" +version = "3.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/69/50b0c38e26658072b0221f1ea243c47dd56a9f3f50e5754aa5a39189145c/cx_logging-3.2.1.tar.gz", hash = "sha256:812665ae5012680a6fe47095c3772bce638e47cf05b2c3483db3bdbe6b06da44", size = 26966 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/9b/d8babcfafa7233b862b310a6fe630fc5e6ced02453ca4e60b0c819afbaff/cx_Logging-3.2.1-cp312-cp312-win32.whl", hash = "sha256:3f3de06cf09d5986b39e930c213567c340b3237dfce03d8d3bf6099475eaa02e", size = 22869 }, + { url = "https://files.pythonhosted.org/packages/5c/52/b6bd4f4d51eb4f3523da182cdf5969a560e35f4ef178f34841ba6795addc/cx_Logging-3.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:3452add0544db6ff29116b72a4c48761aaffa9b638728330433853c0c4ad2ea1", size = 26911 }, + { url = "https://files.pythonhosted.org/packages/e1/78/0ce28b89aedf369b02bb5cb763324e799844144386fba75c03128ea9e2ff/cx_Logging-3.2.1-cp313-cp313-win32.whl", hash = "sha256:330a29030bdca8795c99b678b4f6d87a75fb606eed1da206fdd9fa579a33dc21", size = 22874 }, + { url = "https://files.pythonhosted.org/packages/cb/23/dab5f561888951ec02843f087f34a59c791e8ac6423c25a412eb49300633/cx_Logging-3.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:e14748b031522a95aa2db4adfc5f2be5f96f4d0fe687da591114f73a09e66926", size = 26916 }, +] + [[package]] name = "dateparser" version = "1.2.1" @@ -229,6 +283,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cf/0a/981c438c4cd84147c781e4e96c1d72df03775deb1bc76c5a6ee8afa89c62/dateparser-1.2.1-py3-none-any.whl", hash = "sha256:bdcac262a467e6260030040748ad7c10d6bacd4f3b9cdb4cfd2251939174508c", size = 295658 }, ] +[[package]] +name = "dmgbuild" +version = "1.6.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ds-store", marker = "(platform_machine != 'aarch64' and platform_machine != 'armv7l' and platform_machine != 'i686' and platform_machine != 'ppc64le' and platform_machine != 's390x' and platform_machine != 'x86_64') or (platform_machine == 'aarch64' and sys_platform != 'linux') or (platform_machine == 'armv7l' and sys_platform != 'linux') or (platform_machine == 'i686' and sys_platform != 'linux') or (platform_machine == 'ppc64le' and sys_platform != 'linux') or (platform_machine == 's390x' and sys_platform != 'linux') or (platform_machine == 'x86_64' and sys_platform != 'linux')" }, + { name = "mac-alias", marker = "(platform_machine != 'aarch64' and platform_machine != 'armv7l' and platform_machine != 'i686' and platform_machine != 'ppc64le' and platform_machine != 's390x' and platform_machine != 'x86_64') or (platform_machine == 'aarch64' and sys_platform != 'linux') or (platform_machine == 'armv7l' and sys_platform != 'linux') or (platform_machine == 'i686' and sys_platform != 'linux') or (platform_machine == 'ppc64le' and sys_platform != 'linux') or (platform_machine == 's390x' and sys_platform != 'linux') or (platform_machine == 'x86_64' and sys_platform != 'linux')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/17/89c089f4263b6c7f40a69355dd74f2cf5b5a58c4f7db79f76ed3d9e1ca5b/dmgbuild-1.6.4.tar.gz", hash = "sha256:adacada75ee517398d014e3fb250b004a2225f01e54832df52d38b9cd1530b74", size = 36824 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a1/c5/71ecb2f6a95082aa6a7227a92054024e29caba133a7a86094ce32fd03c1f/dmgbuild-1.6.4-py3-none-any.whl", hash = "sha256:53a2f0a9e65111314fce7ecfb6637d08bc3186fa99e719abc9a5af2b484a7d65", size = 34900 }, +] + [[package]] name = "dnspython" version = "2.7.0" @@ -238,6 +305,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632 }, ] +[[package]] +name = "ds-store" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mac-alias", marker = "(platform_machine != 'aarch64' and platform_machine != 'armv7l' and platform_machine != 'i686' and platform_machine != 'ppc64le' and platform_machine != 's390x' and platform_machine != 'x86_64') or (platform_machine == 'aarch64' and sys_platform != 'linux') or (platform_machine == 'armv7l' and sys_platform != 'linux') or (platform_machine == 'i686' and sys_platform != 'linux') or (platform_machine == 'ppc64le' and sys_platform != 'linux') or (platform_machine == 's390x' and sys_platform != 'linux') or (platform_machine == 'x86_64' and sys_platform != 'linux')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7c/36/902259bf7ddb142dd91cf7a9794aa15e1a8ab985974f90375e5d3463b441/ds_store-1.3.1.tar.gz", hash = "sha256:c27d413caf13c19acb85d75da4752673f1f38267f9eb6ba81b3b5aa99c2d207c", size = 27052 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/bf/b1c10362a0d670ee8ae086d92c3ab795fca2a927e4ff25e7cd15224d3863/ds_store-1.3.1-py3-none-any.whl", hash = "sha256:fbacbb0bd5193ab3e66e5a47fff63619f15e374ffbec8ae29744251a6c8f05b5", size = 16268 }, +] + [[package]] name = "email-validator" version = "2.2.0" @@ -303,6 +382,15 @@ standard = [ { name = "uvicorn", extra = ["standard"] }, ] +[[package]] +name = "filelock" +version = "3.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/9c/0b15fb47b464e1b663b1acd1253a062aa5feecb07d4e597daea542ebd2b5/filelock-3.17.0.tar.gz", hash = "sha256:ee4e77401ef576ebb38cd7f13b9b28893194acc20a8e68e18730ba9c0e54660e", size = 18027 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/89/ec/00d68c4ddfedfe64159999e5f8a98fb8442729a63e2077eb9dcd89623d27/filelock-3.17.0-py3-none-any.whl", hash = "sha256:533dc2f7ba78dc2f0f531fc6c4940addf7b70a481e269a5a3b93be94ffbe8338", size = 16164 }, +] + [[package]] name = "gevent" version = "24.11.1" @@ -479,6 +567,17 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bd/0f/2ba5fbcd631e3e88689309dbe978c5769e883e4b84ebfe7da30b43275c5a/jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb", size = 134596 }, ] +[[package]] +name = "lief" +version = "0.16.3" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d8/c6/2b8eab0b1c061d2a0a29642cbef91b9b36148e86f3fce99200ede5e8e788/lief-0.16.3-cp312-cp312-win32.whl", hash = "sha256:e7ba797829584c5cc1c8a736b2f1587f09b1f3030239c968c7664649fb79ae15", size = 3042391 }, + { url = "https://files.pythonhosted.org/packages/76/4e/7bb9efe6bbe804449c150295fa597c7e10fd7264c5a5205c38f9b3bd9942/lief-0.16.3-cp312-cp312-win_amd64.whl", hash = "sha256:70c1f5f66bd4eeead2853a7a80d941b4dd03e3791c68c5351b0d39c78cfa9afe", size = 3167314 }, + { url = "https://files.pythonhosted.org/packages/57/9a/be854d274352a2ce406691fb6c80c82b4a6adf0fdb6978734e4c082326b7/lief-0.16.3-cp313-cp313-win32.whl", hash = "sha256:aefbe78b06d9e89387ab8fc069d1cb34252f5916cf35eaa21088b21b74b99d08", size = 3042393 }, + { url = "https://files.pythonhosted.org/packages/51/be/34b8864d0976258f29a5e3d7bedb2785fd56409cf866813458bfd32d2a6b/lief-0.16.3-cp313-cp313-win_amd64.whl", hash = "sha256:52dc05445d8019b61a9ab8c6eb9d6238c4346ac692dcecca76d5f329a999216e", size = 3167188 }, +] + [[package]] name = "loguru" version = "0.7.3" @@ -492,6 +591,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl", hash = "sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c", size = 61595 }, ] +[[package]] +name = "mac-alias" +version = "2.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ea/a3/83b50f620d318a98363dc7e701fb94856eaaecc472e23a89ac625697b3ea/mac_alias-2.2.2.tar.gz", hash = "sha256:c99c728eb512e955c11f1a6203a0ffa8883b26549e8afe68804031aa5da856b7", size = 34073 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/a1/4136777ed6a56df83e7c748ad28892f0672cbbcdc3b3d15a57df6ba72443/mac_alias-2.2.2-py3-none-any.whl", hash = "sha256:504ab8ac546f35bbd75ad014d6ad977c426660aa721f2cd3acf3dc2f664141bd", size = 21220 }, +] + [[package]] name = "mako" version = "1.3.9" @@ -600,6 +708,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, ] +[[package]] +name = "patchelf" +version = "0.17.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/ec/ac383eb82792e092d8037649b382cf78a7b79c2ce4e5b861f61519b9b14e/patchelf-0.17.2.1.tar.gz", hash = "sha256:a6eb0dd452ce4127d0d5e1eb26515e39186fa609364274bc1b0b77539cfa7031", size = 167484 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/09/b7ec52d01ad2936c967e929fd076b0a2e4f94ce950c9440e38f98c67675e/patchelf-0.17.2.1-py2.py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:fc329da0e8f628bd836dfb8eaf523547e342351fa8f739bf2b3fe4a6db5a297c", size = 421930 }, + { url = "https://files.pythonhosted.org/packages/69/47/e02357d1075cdf4b56be39a6c218a5a2b0bd3896011120ae3765190ab527/patchelf-0.17.2.1-py2.py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:ccb266a94edf016efe80151172c26cff8c2ec120a57a1665d257b0442784195d", size = 381147 }, + { url = "https://files.pythonhosted.org/packages/92/78/3f4e19d6ba7acf1e01db6d82d23e0435a76466187644ce0dbcf6bd621317/patchelf-0.17.2.1-py2.py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.musllinux_1_1_ppc64le.whl", hash = "sha256:f47b5bdd6885cfb20abdd14c707d26eb6f499a7f52e911865548d4aa43385502", size = 488526 }, + { url = "https://files.pythonhosted.org/packages/08/d3/adedfbcff489605a0e907f390006ef7d59a3ac56a9e2dbe721ddbbb1e58e/patchelf-0.17.2.1-py2.py3-none-manylinux_2_17_s390x.manylinux2014_s390x.musllinux_1_1_s390x.whl", hash = "sha256:a9e6ebb0874a11f7ed56d2380bfaa95f00612b23b15f896583da30c2059fcfa8", size = 470060 }, + { url = "https://files.pythonhosted.org/packages/c6/9b/33e54d5916863904609e40b53206e5a49cf649b71f7f787eddcbc27a9f5c/patchelf-0.17.2.1-py2.py3-none-manylinux_2_5_i686.manylinux1_i686.musllinux_1_1_i686.whl", hash = "sha256:3c8d58f0e4c1929b1c7c45ba8da5a84a8f1aa6a82a46e1cfb2e44a4d40f350e5", size = 499565 }, + { url = "https://files.pythonhosted.org/packages/c6/73/c3105c973dd2afcdc5d946ee211d5c4ecdf9d27bb54ae835b144e706e86d/patchelf-0.17.2.1-py2.py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.musllinux_1_1_x86_64.whl", hash = "sha256:d1a9bc0d4fd80c038523ebdc451a1cce75237cfcc52dbd1aca224578001d5927", size = 425709 }, +] + [[package]] name = "pluggy" version = "1.5.0" @@ -637,7 +759,7 @@ email = [ { name = "email-validator" }, ] timezone = [ - { name = "tzdata", marker = "platform_system == 'Windows'" }, + { name = "tzdata", marker = "platform_system == 'Windows' and python_full_version >= '3.12.1'" }, ] [[package]] @@ -701,6 +823,79 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, ] +[[package]] +name = "pyobjc-core" +version = "11.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/94/a111239b98260869780a5767e5d74bfd3a8c13a40457f479c28dcd91f89d/pyobjc_core-11.0.tar.gz", hash = "sha256:63bced211cb8a8fb5c8ff46473603da30e51112861bd02c438fbbbc8578d9a70", size = 994931 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/ce/bf3ff9a9347721a398c3dfb83e29b43fb166b7ef590f3f7b7ddcd283df39/pyobjc_core-11.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a03061d4955c62ddd7754224a80cdadfdf17b6b5f60df1d9169a3b1b02923f0b", size = 739750 }, + { url = "https://files.pythonhosted.org/packages/72/16/0c468e73dbecb821e3da8819236fe832dfc53eb5f66a11775b055a7589ea/pyobjc_core-11.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c338c1deb7ab2e9436d4175d1127da2eeed4a1b564b3d83b9f3ae4844ba97e86", size = 743900 }, + { url = "https://files.pythonhosted.org/packages/f3/88/cecec88fd51f62a6cd7775cc4fb6bfde16652f97df88d28c84fb77ca0c18/pyobjc_core-11.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b4e9dc4296110f251a4033ff3f40320b35873ea7f876bd29a1c9705bb5e08c59", size = 791905 }, +] + +[[package]] +name = "pyobjc-framework-cocoa" +version = "11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyobjc-core" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c5/32/53809096ad5fc3e7a2c5ddea642590a5f2cb5b81d0ad6ea67fdb2263d9f9/pyobjc_framework_cocoa-11.0.tar.gz", hash = "sha256:00346a8cb81ad7b017b32ff7bf596000f9faa905807b1bd234644ebd47f692c5", size = 6173848 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/8d/0e2558447c26b3ba64f7c9776a5a6c9d2ae8abf9d34308b174ae0934402e/pyobjc_framework_Cocoa-11.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:280a577b83c68175a28b2b7138d1d2d3111f2b2b66c30e86f81a19c2b02eae71", size = 385811 }, + { url = "https://files.pythonhosted.org/packages/1d/a5/609281a7e89efefbef9db1d8fe66bc0458c3b4e74e2227c644f9c18926fa/pyobjc_framework_Cocoa-11.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:15b2bd977ed340074f930f1330f03d42912d5882b697d78bd06f8ebe263ef92e", size = 385889 }, + { url = "https://files.pythonhosted.org/packages/93/f6/2d5a863673ef7b85a3cba875c43e6c495fb1307427a6801001ae94bb5e54/pyobjc_framework_Cocoa-11.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:5750001db544e67f2b66f02067d8f0da96bb2ef71732bde104f01b8628f9d7ea", size = 389831 }, +] + +[[package]] +name = "pyqt6" +version = "6.8.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyqt6-qt6" }, + { name = "pyqt6-sip" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ce/bf/ff284a136b39cb1873c18e4fca4a40a8847c84a1910c5fb38c6a77868968/pyqt6-6.8.1.tar.gz", hash = "sha256:91d937d6166274fafd70f4dee11a8da6dbfdb0da53de05f5d62361ddf775e256", size = 1064723 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/09/da/70971b3d7f53a68644ea32544d3786dfbbb162d18572ac1defcf5a6481d5/PyQt6-6.8.1-cp39-abi3-macosx_10_14_universal2.whl", hash = "sha256:0425f9eebdd5d4e57ab36424c9382f2ea06670c3c550fa0028c2b19bd0a1d7bd", size = 12213924 }, + { url = "https://files.pythonhosted.org/packages/be/25/a4392c323a0fb97eb5f449b7594f37e93d9794b900756b43cd65772def77/PyQt6-6.8.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:36bf48e3df3a6ff536e703315d155480ef4e260396eb5469eb7a875bc5bb7ab4", size = 8238120 }, + { url = "https://files.pythonhosted.org/packages/de/a3/e528b4cc3394f2ae15b531c17f27b53de756a8c0404dfa9c184502367c48/PyQt6-6.8.1-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:2eac2267a34828b8db7660dd3cc3b3b5fd76a92e61ad45471565b01221cb558b", size = 8173996 }, + { url = "https://files.pythonhosted.org/packages/f2/69/11404cfcb916bd7207805c21432ecab0401779361d48b67f28ae9337f70d/PyQt6-6.8.1-cp39-abi3-win_amd64.whl", hash = "sha256:70bad7b890a8f9e9e5fb9598c544b832d9d9d99a9519e0009cb29c1e15e96632", size = 6723466 }, + { url = "https://files.pythonhosted.org/packages/00/2a/21a555aea9bc8abc4f09017b922dbdf509c421f70506d4c83d2e8f4315b2/PyQt6-6.8.1-cp39-abi3-win_arm64.whl", hash = "sha256:a40f878e8e5eeeb0bba995152d07eeef9375ea0116df0f4aad0a6b97c8ad1175", size = 5463379 }, +] + +[[package]] +name = "pyqt6-qt6" +version = "6.8.2" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/a4/3d764e05955382b3dc7227cbfde090700edd63431147f1c66d428ccac45c/PyQt6_Qt6-6.8.2-py3-none-macosx_10_14_x86_64.whl", hash = "sha256:470dd4211fe5a67b0565e0202e7aa67816e5dcf7d713528b88327adaebd0934e", size = 66121240 }, + { url = "https://files.pythonhosted.org/packages/d6/b3/6d4f8257b46554fb2c89b33a6773a3f05ed961b3cd83828caee5dc79899f/PyQt6_Qt6-6.8.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:40cda901a3e1617e79225c354fe9d89b80249f0a6c6aaa18b40938e05bbf7d1f", size = 60286219 }, + { url = "https://files.pythonhosted.org/packages/92/95/0036435b9e2cbd22e08f14eec2362c32fc641660c6e4aea6f59d165cb5fc/PyQt6_Qt6-6.8.2-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:fb6d0acdd7d43c33fb8b9d2dd7922d381cdedd00da316049fbe01fc1973e6f05", size = 81263397 }, + { url = "https://files.pythonhosted.org/packages/6e/fb/c01dde044eca1542d88cac72fc99369af76a981cc2f52790236efa566e01/PyQt6_Qt6-6.8.2-py3-none-manylinux_2_39_aarch64.whl", hash = "sha256:5970c85d22cbe5c476418994549161b23ed938e25b04fc4ca8fabf6dcac7b03f", size = 79832921 }, + { url = "https://files.pythonhosted.org/packages/1a/f7/31f03a9f5e6c7cc23ceb2bd0d9c2df0518837f7af0e693e15b6e0881b8b0/PyQt6_Qt6-6.8.2-py3-none-win_amd64.whl", hash = "sha256:28e2bb641f05b01e498503c3ef01c8a919d6e0e96b50230301c0baac2b7d1433", size = 71934164 }, + { url = "https://files.pythonhosted.org/packages/00/c9/102c9537795ca11c12120ec9d5f554d9437787f52d8e23fbc8269e6a2699/PyQt6_Qt6-6.8.2-py3-none-win_arm64.whl", hash = "sha256:912afdddd0dfc666ce1c16bc4695e2acd680db72343e4f7a2b7c053a0146b4bc", size = 48120018 }, +] + +[[package]] +name = "pyqt6-sip" +version = "13.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/90/18/0405c54acba0c8e276dd6f0601890e6e735198218d031a6646104870fe22/pyqt6_sip-13.10.0.tar.gz", hash = "sha256:d6daa95a0bd315d9ec523b549e0ce97455f61ded65d5eafecd83ed2aa4ae5350", size = 92464 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/81/66d9bdacb790592a0641378749a047f12e3b254cdc2cb51f7ed636cf01d2/PyQt6_sip-13.10.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:48791db2914fc39c3218519a02d2a5fd3fcd354a1be3141a57bf2880701486f2", size = 112334 }, + { url = "https://files.pythonhosted.org/packages/26/2c/4796c209009a018e0d4a5c406d5a519234c5a378f370dc679d0ad5f455b2/PyQt6_sip-13.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:466d6b4791973c9fcbdc2e0087ed194b9ea802a8c3948867a849498f0841c70c", size = 322334 }, + { url = "https://files.pythonhosted.org/packages/99/34/2ec54bd475f0a811df1d32be485f2344cf9e8b388ce7adb26b46ce5552d4/PyQt6_sip-13.10.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ae15358941f127cd3d1ab09c1ebd45c4dabb0b2e91587b9eebde0279d0039c54", size = 303798 }, + { url = "https://files.pythonhosted.org/packages/0c/e4/82099bb4ab8bc152b5718541e93c0b3adf7566c0f307c9e58e2368b8c517/PyQt6_sip-13.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:ad573184fa8b00041944e5a17d150ab0d08db2d2189e39c9373574ebab3f2e58", size = 53569 }, + { url = "https://files.pythonhosted.org/packages/e3/09/90e0378887a3cb9664da77061229cf8e97e6ec25a5611b7dbc9cc3e02c78/PyQt6_sip-13.10.0-cp312-cp312-win_arm64.whl", hash = "sha256:2d579d810d0047d40bde9c6aef281d6ed218db93c9496ebc9e55b9e6f27a229d", size = 45430 }, + { url = "https://files.pythonhosted.org/packages/6b/0c/8d1de48b45b565a46bf4757341f13f9b1853a7d2e6b023700f0af2c213ab/PyQt6_sip-13.10.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7b6e250c2e7c14702a623f2cc1479d7fb8db2b6eee9697cac10d06fe79c281bb", size = 112343 }, + { url = "https://files.pythonhosted.org/packages/af/13/e2cc2b667a9f5d44c2d0e18fa6e1066fca3f4521dcb301f4b5374caeb33e/PyQt6_sip-13.10.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fcb30756568f8cd59290f9ef2ae5ee3e72ff9cdd61a6f80c9e3d3b95ae676be", size = 322527 }, + { url = "https://files.pythonhosted.org/packages/20/1a/5c6fcae85edb65cf236c9dc6d23b279b5316e94cdca1abdee6d0a217ddbb/PyQt6_sip-13.10.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:757ac52c92b2ef0b56ecc7cd763b55a62d3c14271d7ea8d03315af85a70090ff", size = 303407 }, + { url = "https://files.pythonhosted.org/packages/b9/db/6924ec985be7d746772806b96ab81d24263ef72f0249f0573a82adaed75e/PyQt6_sip-13.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:571900c44a3e38738d696234d94fe2043972b9de0633505451c99e2922cb6a34", size = 53580 }, + { url = "https://files.pythonhosted.org/packages/77/c3/9e44729b582ee7f1d45160e8c292723156889f3e38ce6574f88d5ab8fa02/PyQt6_sip-13.10.0-cp313-cp313-win_arm64.whl", hash = "sha256:39cba2cc71cf80a99b4dc8147b43508d4716e128f9fb99f5eb5860a37f082282", size = 45446 }, +] + [[package]] name = "pyright" version = "1.1.394" @@ -843,6 +1038,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 }, ] +[[package]] +name = "qasync" +version = "0.27.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1c/e0/7c7c973f52e1765d6ddfc41e9272294f65d5d52b8f5f5eae92adf411ad46/qasync-0.27.1.tar.gz", hash = "sha256:8dc768fd1ee5de1044c7c305eccf2d39d24d87803ea71189d4024fb475f4985f", size = 14287 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/06/bc628aa2981bcfd452a08ee435b812fd3eee4ada8acb8a76c4a09d1a5a77/qasync-0.27.1-py3-none-any.whl", hash = "sha256:5d57335723bc7d9b328dadd8cb2ed7978640e4bf2da184889ce50ee3ad2602c7", size = 14866 }, +] + [[package]] name = "regex" version = "2024.11.6" @@ -933,6 +1137,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e8/a8/d71f44b93e3aa86ae232af1f2126ca7b95c0f515ec135462b3e1f351441c/ruff-0.9.6-py3-none-win_arm64.whl", hash = "sha256:0e2bb706a2be7ddfea4a4af918562fdc1bcb16df255e5fa595bbd800ce322a5a", size = 10177499 }, ] +[[package]] +name = "rumps" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyobjc-framework-cocoa" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b2/e2/2e6a47951290bd1a2831dcc50aec4b25d104c0cf00e8b7868cbd29cf3bfe/rumps-0.4.0.tar.gz", hash = "sha256:17fb33c21b54b1e25db0d71d1d793dc19dc3c0b7d8c79dc6d833d0cffc8b1596", size = 39257 } + [[package]] name = "setuptools" version = "75.8.0" @@ -974,7 +1187,7 @@ name = "sqlalchemy" version = "2.0.38" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "greenlet", marker = "(python_full_version < '3.14' and platform_machine == 'AMD64') or (python_full_version < '3.14' and platform_machine == 'WIN32') or (python_full_version < '3.14' and platform_machine == 'aarch64') or (python_full_version < '3.14' and platform_machine == 'amd64') or (python_full_version < '3.14' and platform_machine == 'ppc64le') or (python_full_version < '3.14' and platform_machine == 'win32') or (python_full_version < '3.14' and platform_machine == 'x86_64')" }, + { name = "greenlet", marker = "(python_full_version < '3.14' and platform_machine == 'AMD64' and python_full_version >= '3.12.1') or (python_full_version < '3.14' and platform_machine == 'WIN32' and python_full_version >= '3.12.1') or (python_full_version < '3.14' and platform_machine == 'aarch64' and python_full_version >= '3.12.1') or (python_full_version < '3.14' and platform_machine == 'amd64' and python_full_version >= '3.12.1') or (python_full_version < '3.14' and platform_machine == 'ppc64le' and python_full_version >= '3.12.1') or (python_full_version < '3.14' and platform_machine == 'win32' and python_full_version >= '3.12.1') or (python_full_version < '3.14' and platform_machine == 'x86_64' and python_full_version >= '3.12.1')" }, { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e4/08/9a90962ea72acd532bda71249a626344d855c4032603924b1b547694b837/sqlalchemy-2.0.38.tar.gz", hash = "sha256:e5a4d82bdb4bf1ac1285a68eab02d253ab73355d9f0fe725a97e1e0fa689decb", size = 9634782 }