feat: add interface, plugin list loading, search, keyboard navigation
This commit is contained in:
71
.gitignore
vendored
Normal file
71
.gitignore
vendored
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# OSX useful to ignore
|
||||||
|
*.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
env/
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
*.dist-info/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
|
||||||
|
# IntelliJ Idea family of suites
|
||||||
|
.idea
|
||||||
|
*.iml
|
||||||
|
## File-based project format:
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
## mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# Briefcase log files
|
||||||
|
logs/
|
||||||
|
|
||||||
|
# Briefcase local configuratoin
|
||||||
|
.briefcase/
|
||||||
|
|
||||||
|
# Virtual environments
|
||||||
|
.venv
|
||||||
|
|
||||||
|
# Research and Tests
|
||||||
|
t
|
||||||
8
.mcp.json
Normal file
8
.mcp.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"context7": {
|
||||||
|
"type": "http",
|
||||||
|
"url": "https://mcp.context7.com/mcp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
.pre-commit-config.yaml
Normal file
17
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
repos:
|
||||||
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
|
rev: v0.14.14
|
||||||
|
hooks:
|
||||||
|
- id: ruff-check
|
||||||
|
types_or: [ python, pyi ]
|
||||||
|
args: [ --fix ]
|
||||||
|
- id: ruff-format
|
||||||
|
types_or: [ python, pyi ]
|
||||||
|
|
||||||
|
- repo: local
|
||||||
|
hooks:
|
||||||
|
- id: ty
|
||||||
|
name: ty check
|
||||||
|
entry: uvx ty check
|
||||||
|
language: python
|
||||||
|
types_or: [ python, pyi ]
|
||||||
1
.python-version
Normal file
1
.python-version
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3.13
|
||||||
5
CHANGELOG
Normal file
5
CHANGELOG
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# illogical Release Notes
|
||||||
|
|
||||||
|
## 0.0.1 (25 Jan 2026)
|
||||||
|
|
||||||
|
* Initial release
|
||||||
44
CLAUDE.md
Normal file
44
CLAUDE.md
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
illogical is a macOS Logic Pro plugin manager built with PySide6 and Briefcase.
|
||||||
|
It uses `logic-plugin-manager` for Audio Units management and `pyqt-liquidglass` for UI styling.
|
||||||
|
|
||||||
|
## Development Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Type checking
|
||||||
|
ty check
|
||||||
|
|
||||||
|
# Linting and formatting
|
||||||
|
ruff format
|
||||||
|
ruff check --fix
|
||||||
|
```
|
||||||
|
|
||||||
|
NEVER run briefcase or any run commands by yourself
|
||||||
|
|
||||||
|
## Custom Libraries
|
||||||
|
|
||||||
|
This project uses two custom libraries. **Always fetch their documentation via Context7 before working with them:**
|
||||||
|
|
||||||
|
- `logic-plugin-manager` - Audio Units plugin management
|
||||||
|
- `pyqt-liquidglass` - macOS liquid glass UI effects for Qt
|
||||||
|
|
||||||
|
## Code Principles
|
||||||
|
|
||||||
|
- **Simplicity**: Write simple, straightforward code
|
||||||
|
- **Readability**: Make code easy to understand
|
||||||
|
- **Performance**: Consider performance without sacrificing readability
|
||||||
|
- **Maintainability**: Write code that's easy to update
|
||||||
|
- **Reusability**: Create reusable components and functions
|
||||||
|
- **Less Code = Less Debt**: Minimize code footprint
|
||||||
|
- **NEVER write comments** - code should be self-documenting
|
||||||
|
|
||||||
|
## Context7 Usage
|
||||||
|
|
||||||
|
Use Context7 MCP tools to fetch up-to-date documentation:
|
||||||
|
1. Call `resolve-library-id` with the library name to get its ID
|
||||||
|
2. Call `query-docs` with the library ID and your question
|
||||||
19
LICENSE
Normal file
19
LICENSE
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2026, h
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# illogical
|
||||||
|
|
||||||
|
The sane Logic Pro plugin manager Apple forgot to build
|
||||||
66
pyproject.toml
Normal file
66
pyproject.toml
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
[tool.briefcase]
|
||||||
|
project_name = "illogical"
|
||||||
|
bundle = "com.kotikot.illogical"
|
||||||
|
version = "0.0.1"
|
||||||
|
url = "https://dsp.kotikot.com/illogical"
|
||||||
|
license.file = "LICENSE"
|
||||||
|
author = "h"
|
||||||
|
author_email = "h@kotikot.com"
|
||||||
|
|
||||||
|
[tool.briefcase.app.illogical]
|
||||||
|
formal_name = "illogical"
|
||||||
|
description = "The sane Logic Pro plugin manager Apple forgot to build"
|
||||||
|
long_description = """An advanced, open-source plugin manager for Logic Pro to organize your Audio Units ecosystem."""
|
||||||
|
sources = [
|
||||||
|
"src/illogical",
|
||||||
|
]
|
||||||
|
|
||||||
|
requires = [
|
||||||
|
"PySide6-Essentials~=6.8",
|
||||||
|
"logic-plugin-manager[search]>=1.0.0",
|
||||||
|
"pyqt-liquidglass>=0.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.briefcase.app.illogical.macOS]
|
||||||
|
universal_build = true
|
||||||
|
min_os_version = "12.0"
|
||||||
|
requires = [
|
||||||
|
"std-nslog~=1.0.3",
|
||||||
|
]
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "illogical"
|
||||||
|
version = "0.0.0"
|
||||||
|
requires-python = ">=3.13"
|
||||||
|
dependencies = [
|
||||||
|
"briefcase>=0.3.25",
|
||||||
|
"logic-plugin-manager[search]>=1.0.0",
|
||||||
|
"pyqt-liquidglass>=0.1.0",
|
||||||
|
"PySide6-Essentials~=6.8",
|
||||||
|
]
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["uv_build>=0.9.13,<0.10.0"]
|
||||||
|
build-backend = "uv_build"
|
||||||
|
|
||||||
|
[tool.ruff]
|
||||||
|
target-version = "py313"
|
||||||
|
|
||||||
|
[tool.ruff.lint]
|
||||||
|
select = ["ALL"]
|
||||||
|
ignore = ["CPY", "D1", "D203", "D212", "COM812", "RUF001", "RUF002", "RUF003"]
|
||||||
|
unfixable = ["F401"]
|
||||||
|
|
||||||
|
[tool.ruff.lint.per-file-ignores]
|
||||||
|
"*.lock" = ["ALL"]
|
||||||
|
"docs/*" = ["ALL"]
|
||||||
|
|
||||||
|
[tool.ruff.lint.pydocstyle]
|
||||||
|
convention = "google"
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
docstring-code-format = true
|
||||||
|
skip-magic-trailing-comma = true
|
||||||
|
|
||||||
|
[tool.ruff.lint.isort]
|
||||||
|
split-on-trailing-comma = false
|
||||||
0
src/illogical/__init__.py
Normal file
0
src/illogical/__init__.py
Normal file
4
src/illogical/__main__.py
Normal file
4
src/illogical/__main__.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
from illogical.app import main
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
18
src/illogical/app.py
Normal file
18
src/illogical/app.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import importlib.metadata
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from PySide6.QtWidgets import QApplication
|
||||||
|
|
||||||
|
from illogical.ui.main_window import MainWindow
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
app_module = sys.modules["__main__"].__package__ or "illogical"
|
||||||
|
metadata = importlib.metadata.metadata(app_module)
|
||||||
|
|
||||||
|
QApplication.setApplicationName(metadata["Formal-Name"])
|
||||||
|
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
window = MainWindow()
|
||||||
|
window.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
0
src/illogical/modules/__init__.py
Normal file
0
src/illogical/modules/__init__.py
Normal file
367
src/illogical/modules/models.py
Normal file
367
src/illogical/modules/models.py
Normal file
@@ -0,0 +1,367 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING, ClassVar
|
||||||
|
|
||||||
|
from PySide6.QtCore import (
|
||||||
|
QAbstractItemModel,
|
||||||
|
QAbstractListModel,
|
||||||
|
QAbstractTableModel,
|
||||||
|
QModelIndex,
|
||||||
|
QObject,
|
||||||
|
QSortFilterProxyModel,
|
||||||
|
Qt,
|
||||||
|
)
|
||||||
|
|
||||||
|
from illogical.modules.sf_symbols import sf_symbol
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from logic_plugin_manager import AudioComponent, Logic
|
||||||
|
|
||||||
|
|
||||||
|
COL_NAME = 0
|
||||||
|
COL_CUSTOM_NAME = 1
|
||||||
|
COL_SHORT_NAME = 2
|
||||||
|
COL_TYPE = 3
|
||||||
|
COL_MANUFACTURER = 4
|
||||||
|
COL_VERSION = 5
|
||||||
|
|
||||||
|
|
||||||
|
def _format_version(version: int) -> str:
|
||||||
|
if version <= 0:
|
||||||
|
return ""
|
||||||
|
major = (version >> 16) & 0xFF
|
||||||
|
minor = (version >> 8) & 0xFF
|
||||||
|
patch = version & 0xFF
|
||||||
|
if patch:
|
||||||
|
return f"{major}.{minor}.{patch}"
|
||||||
|
if minor:
|
||||||
|
return f"{major}.{minor}"
|
||||||
|
return str(major)
|
||||||
|
|
||||||
|
|
||||||
|
class PluginTableModel(QAbstractTableModel):
|
||||||
|
COLUMNS: ClassVar[list[str]] = [
|
||||||
|
"Name",
|
||||||
|
"Custom Name",
|
||||||
|
"Short Name",
|
||||||
|
"Type",
|
||||||
|
"Manufacturer",
|
||||||
|
"Version",
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, parent: QObject | None = None) -> None:
|
||||||
|
super().__init__(parent)
|
||||||
|
self._all_plugins: list[AudioComponent] = []
|
||||||
|
self._plugins: list[AudioComponent] = []
|
||||||
|
self._sort_column: int = COL_NAME
|
||||||
|
self._sort_order: Qt.SortOrder = Qt.SortOrder.AscendingOrder
|
||||||
|
|
||||||
|
def set_plugins(self, logic: Logic) -> None:
|
||||||
|
self.beginResetModel()
|
||||||
|
self._all_plugins = list(logic.plugins.all())
|
||||||
|
self._plugins = self._all_plugins.copy()
|
||||||
|
self._apply_sort()
|
||||||
|
self.endResetModel()
|
||||||
|
|
||||||
|
def rowCount(self, parent: QModelIndex | None = None) -> int: # noqa: N802
|
||||||
|
if parent is not None and parent.isValid():
|
||||||
|
return 0
|
||||||
|
return len(self._plugins)
|
||||||
|
|
||||||
|
def columnCount(self, parent: QModelIndex | None = None) -> int: # noqa: N802
|
||||||
|
if parent is not None and parent.isValid():
|
||||||
|
return 0
|
||||||
|
return len(self.COLUMNS)
|
||||||
|
|
||||||
|
def headerData( # noqa: N802
|
||||||
|
self,
|
||||||
|
section: int,
|
||||||
|
orientation: Qt.Orientation,
|
||||||
|
role: int = Qt.ItemDataRole.DisplayRole,
|
||||||
|
) -> str | None:
|
||||||
|
if role != Qt.ItemDataRole.DisplayRole:
|
||||||
|
return None
|
||||||
|
if orientation == Qt.Orientation.Horizontal and 0 <= section < len(
|
||||||
|
self.COLUMNS
|
||||||
|
):
|
||||||
|
return self.COLUMNS[section]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def data( # noqa: PLR0911
|
||||||
|
self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole
|
||||||
|
) -> object:
|
||||||
|
if not index.isValid() or not (0 <= index.row() < len(self._plugins)):
|
||||||
|
return None
|
||||||
|
|
||||||
|
plugin = self._plugins[index.row()]
|
||||||
|
col = index.column()
|
||||||
|
|
||||||
|
if role == Qt.ItemDataRole.DisplayRole:
|
||||||
|
if col == COL_NAME:
|
||||||
|
return plugin.name
|
||||||
|
if col == COL_CUSTOM_NAME:
|
||||||
|
return getattr(plugin, "custom_name", "") or ""
|
||||||
|
if col == COL_SHORT_NAME:
|
||||||
|
return getattr(plugin, "short_name", "") or ""
|
||||||
|
if col == COL_TYPE:
|
||||||
|
return plugin.type_name.display_name
|
||||||
|
if col == COL_MANUFACTURER:
|
||||||
|
return plugin.manufacturer
|
||||||
|
if col == COL_VERSION:
|
||||||
|
version = getattr(plugin, "version", 0) or 0
|
||||||
|
return _format_version(version)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def filter_by_category(self, category: str | None) -> None:
|
||||||
|
self.beginResetModel()
|
||||||
|
if category == "Show All":
|
||||||
|
self._plugins = self._all_plugins.copy()
|
||||||
|
elif category is None:
|
||||||
|
self._plugins = [p for p in self._all_plugins if not p.categories]
|
||||||
|
elif category == "Top Level":
|
||||||
|
self._plugins = [
|
||||||
|
p for p in self._all_plugins if any(c.name == "" for c in p.categories)
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
self._plugins = [
|
||||||
|
p
|
||||||
|
for p in self._all_plugins
|
||||||
|
if any(c.name == category for c in p.categories)
|
||||||
|
]
|
||||||
|
self._apply_sort()
|
||||||
|
self.endResetModel()
|
||||||
|
|
||||||
|
def filter_by_manufacturer(self, manufacturer: str) -> None:
|
||||||
|
self.beginResetModel()
|
||||||
|
self._plugins = [
|
||||||
|
p
|
||||||
|
for p in self._all_plugins
|
||||||
|
if p.manufacturer.lower() == manufacturer.lower()
|
||||||
|
]
|
||||||
|
self._apply_sort()
|
||||||
|
self.endResetModel()
|
||||||
|
|
||||||
|
def filter_by_search_results(self, plugins: list[AudioComponent]) -> None:
|
||||||
|
self.beginResetModel()
|
||||||
|
self._plugins = plugins
|
||||||
|
self.endResetModel()
|
||||||
|
|
||||||
|
def get_plugin(self, row: int) -> AudioComponent | None:
|
||||||
|
if 0 <= row < len(self._plugins):
|
||||||
|
return self._plugins[row]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def sort(
|
||||||
|
self, column: int, order: Qt.SortOrder = Qt.SortOrder.AscendingOrder
|
||||||
|
) -> None:
|
||||||
|
self._sort_column = column
|
||||||
|
self._sort_order = order
|
||||||
|
self.beginResetModel()
|
||||||
|
self._apply_sort()
|
||||||
|
self.endResetModel()
|
||||||
|
|
||||||
|
def _apply_sort(self) -> None:
|
||||||
|
reverse = self._sort_order == Qt.SortOrder.DescendingOrder
|
||||||
|
column = self._sort_column
|
||||||
|
|
||||||
|
def get_sort_value(plugin: AudioComponent) -> str | int:
|
||||||
|
if column == COL_VERSION:
|
||||||
|
return getattr(plugin, "version", 0) or 0
|
||||||
|
values = {
|
||||||
|
COL_NAME: plugin.name,
|
||||||
|
COL_CUSTOM_NAME: getattr(plugin, "custom_name", "") or "",
|
||||||
|
COL_SHORT_NAME: getattr(plugin, "short_name", "") or "",
|
||||||
|
COL_TYPE: plugin.type_code,
|
||||||
|
COL_MANUFACTURER: plugin.manufacturer,
|
||||||
|
}
|
||||||
|
return values.get(column, "").lower()
|
||||||
|
|
||||||
|
self._plugins.sort(key=get_sort_value, reverse=reverse)
|
||||||
|
|
||||||
|
|
||||||
|
class CategoryTreeItem:
|
||||||
|
def __init__(
|
||||||
|
self, name: str, full_path: str, parent: CategoryTreeItem | None = None
|
||||||
|
) -> None:
|
||||||
|
self.name = name
|
||||||
|
self.full_path = full_path
|
||||||
|
self.parent_item = parent
|
||||||
|
self.children: list[CategoryTreeItem] = []
|
||||||
|
|
||||||
|
def append_child(self, child: CategoryTreeItem) -> None:
|
||||||
|
self.children.append(child)
|
||||||
|
|
||||||
|
def child(self, row: int) -> CategoryTreeItem | None:
|
||||||
|
if 0 <= row < len(self.children):
|
||||||
|
return self.children[row]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def child_count(self) -> int:
|
||||||
|
return len(self.children)
|
||||||
|
|
||||||
|
def row(self) -> int:
|
||||||
|
if self.parent_item:
|
||||||
|
return self.parent_item.children.index(self)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
class CategoryTreeModel(QAbstractItemModel):
|
||||||
|
def __init__(self, parent: QObject | None = None) -> None:
|
||||||
|
super().__init__(parent)
|
||||||
|
self._root = CategoryTreeItem("", "")
|
||||||
|
|
||||||
|
def build_from_plugins(self, logic: Logic) -> None:
|
||||||
|
self.beginResetModel()
|
||||||
|
self._root = CategoryTreeItem("", "")
|
||||||
|
|
||||||
|
categories: set[str] = set()
|
||||||
|
for plugin in logic.plugins.all():
|
||||||
|
for cat in plugin.categories:
|
||||||
|
if cat.name != "":
|
||||||
|
categories.add(cat.name)
|
||||||
|
|
||||||
|
category_items: dict[str, CategoryTreeItem] = {}
|
||||||
|
|
||||||
|
top_level_item = CategoryTreeItem("Top Level", "Top Level", self._root)
|
||||||
|
self._root.append_child(top_level_item)
|
||||||
|
|
||||||
|
for cat_path in sorted(categories):
|
||||||
|
parts = cat_path.split(":")
|
||||||
|
current_path = ""
|
||||||
|
parent_item = self._root
|
||||||
|
|
||||||
|
for part in parts:
|
||||||
|
current_path = f"{current_path}:{part}" if current_path else part
|
||||||
|
|
||||||
|
if current_path not in category_items:
|
||||||
|
item = CategoryTreeItem(part, current_path, parent_item)
|
||||||
|
parent_item.append_child(item)
|
||||||
|
category_items[current_path] = item
|
||||||
|
|
||||||
|
parent_item = category_items[current_path]
|
||||||
|
|
||||||
|
self.endResetModel()
|
||||||
|
|
||||||
|
def index(
|
||||||
|
self, row: int, column: int, parent: QModelIndex | None = None
|
||||||
|
) -> QModelIndex:
|
||||||
|
if parent is None:
|
||||||
|
parent = QModelIndex()
|
||||||
|
if not self.hasIndex(row, column, parent):
|
||||||
|
return QModelIndex()
|
||||||
|
|
||||||
|
parent_item = parent.internalPointer() if parent.isValid() else self._root
|
||||||
|
child = parent_item.child(row)
|
||||||
|
|
||||||
|
if child:
|
||||||
|
return self.createIndex(row, column, child)
|
||||||
|
return QModelIndex()
|
||||||
|
|
||||||
|
def parent(self, index: QModelIndex) -> QModelIndex:
|
||||||
|
if not index.isValid():
|
||||||
|
return QModelIndex()
|
||||||
|
|
||||||
|
child_item: CategoryTreeItem = index.internalPointer()
|
||||||
|
parent_item = child_item.parent_item
|
||||||
|
|
||||||
|
if parent_item is None or parent_item == self._root:
|
||||||
|
return QModelIndex()
|
||||||
|
|
||||||
|
return self.createIndex(parent_item.row(), 0, parent_item)
|
||||||
|
|
||||||
|
def rowCount(self, parent: QModelIndex | None = None) -> int: # noqa: N802
|
||||||
|
if parent is None:
|
||||||
|
parent = QModelIndex()
|
||||||
|
if parent.column() > 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
parent_item = parent.internalPointer() if parent.isValid() else self._root
|
||||||
|
return parent_item.child_count()
|
||||||
|
|
||||||
|
def columnCount( # noqa: N802
|
||||||
|
self,
|
||||||
|
parent: QModelIndex | None = None, # noqa: ARG002
|
||||||
|
) -> int:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def data(
|
||||||
|
self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole
|
||||||
|
) -> object:
|
||||||
|
if not index.isValid():
|
||||||
|
return None
|
||||||
|
|
||||||
|
item: CategoryTreeItem = index.internalPointer()
|
||||||
|
|
||||||
|
if role == Qt.ItemDataRole.DisplayRole:
|
||||||
|
return item.name
|
||||||
|
|
||||||
|
if role == Qt.ItemDataRole.UserRole:
|
||||||
|
return item.full_path
|
||||||
|
|
||||||
|
if role == Qt.ItemDataRole.DecorationRole and item.full_path == "Top Level":
|
||||||
|
return sf_symbol("arrow.up", 14)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def index_for_path(self, path: str) -> QModelIndex:
|
||||||
|
def find_in_item(
|
||||||
|
item: CategoryTreeItem, parent_index: QModelIndex
|
||||||
|
) -> QModelIndex:
|
||||||
|
for row, child in enumerate(item.children):
|
||||||
|
if child.full_path == path:
|
||||||
|
return self.index(row, 0, parent_index)
|
||||||
|
result = find_in_item(child, self.index(row, 0, parent_index))
|
||||||
|
if result.isValid():
|
||||||
|
return result
|
||||||
|
return QModelIndex()
|
||||||
|
|
||||||
|
return find_in_item(self._root, QModelIndex())
|
||||||
|
|
||||||
|
|
||||||
|
class ManufacturerListModel(QAbstractListModel):
|
||||||
|
def __init__(self, parent: QObject | None = None) -> None:
|
||||||
|
super().__init__(parent)
|
||||||
|
self._manufacturers: list[str] = []
|
||||||
|
|
||||||
|
def build_from_plugins(self, logic: Logic) -> None:
|
||||||
|
self.beginResetModel()
|
||||||
|
manufacturers: set[str] = set()
|
||||||
|
for plugin in logic.plugins.all():
|
||||||
|
manufacturers.add(plugin.manufacturer)
|
||||||
|
self._manufacturers = sorted(manufacturers, key=str.lower)
|
||||||
|
self.endResetModel()
|
||||||
|
|
||||||
|
def rowCount(self, parent: QModelIndex | None = None) -> int: # noqa: N802
|
||||||
|
if parent is not None and parent.isValid():
|
||||||
|
return 0
|
||||||
|
return len(self._manufacturers)
|
||||||
|
|
||||||
|
def data(
|
||||||
|
self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole
|
||||||
|
) -> object:
|
||||||
|
if not index.isValid() or not (0 <= index.row() < len(self._manufacturers)):
|
||||||
|
return None
|
||||||
|
|
||||||
|
if role in (Qt.ItemDataRole.DisplayRole, Qt.ItemDataRole.UserRole):
|
||||||
|
return self._manufacturers[index.row()]
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class ManufacturerFilterProxy(QSortFilterProxyModel):
|
||||||
|
def __init__(self, parent: QObject | None = None) -> None:
|
||||||
|
super().__init__(parent)
|
||||||
|
self.setFilterCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive)
|
||||||
|
|
||||||
|
def filterAcceptsRow( # noqa: N802
|
||||||
|
self, source_row: int, source_parent: QModelIndex
|
||||||
|
) -> bool:
|
||||||
|
source_model = self.sourceModel()
|
||||||
|
if source_model is None:
|
||||||
|
return False
|
||||||
|
index = source_model.index(source_row, 0, source_parent)
|
||||||
|
manufacturer = index.data(Qt.ItemDataRole.DisplayRole)
|
||||||
|
if manufacturer is None:
|
||||||
|
return False
|
||||||
|
return self.filterRegularExpression().match(manufacturer).hasMatch()
|
||||||
74
src/illogical/modules/plugin_service.py
Normal file
74
src/illogical/modules/plugin_service.py
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from logic_plugin_manager import Logic
|
||||||
|
from PySide6.QtCore import QObject, QThread, Signal
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from logic_plugin_manager import SearchResult
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class PluginWorker(QObject):
|
||||||
|
plugins_loaded = Signal(object)
|
||||||
|
search_results = Signal(list)
|
||||||
|
error_occurred = Signal(str)
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self._logic: Logic | None = None
|
||||||
|
|
||||||
|
def discover_plugins(self) -> None:
|
||||||
|
try:
|
||||||
|
self._logic = Logic()
|
||||||
|
self.plugins_loaded.emit(self._logic)
|
||||||
|
except OSError as e:
|
||||||
|
logger.exception("Plugin discovery failed")
|
||||||
|
self.error_occurred.emit(str(e))
|
||||||
|
|
||||||
|
def search_plugins(self, query: str) -> None:
|
||||||
|
if self._logic is None:
|
||||||
|
self.search_results.emit([])
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
results: list[SearchResult] = self._logic.plugins.search(
|
||||||
|
query, use_fuzzy=True
|
||||||
|
)
|
||||||
|
self.search_results.emit(results)
|
||||||
|
except OSError as e:
|
||||||
|
logger.exception("Plugin search failed")
|
||||||
|
self.error_occurred.emit(str(e))
|
||||||
|
|
||||||
|
|
||||||
|
class PluginService(QObject):
|
||||||
|
plugins_loaded = Signal(object)
|
||||||
|
search_results = Signal(list)
|
||||||
|
loading_started = Signal()
|
||||||
|
error_occurred = Signal(str)
|
||||||
|
|
||||||
|
def __init__(self, parent: QObject | None = None) -> None:
|
||||||
|
super().__init__(parent)
|
||||||
|
self._thread = QThread()
|
||||||
|
self._worker = PluginWorker()
|
||||||
|
self._worker.moveToThread(self._thread)
|
||||||
|
|
||||||
|
self._worker.plugins_loaded.connect(self.plugins_loaded)
|
||||||
|
self._worker.search_results.connect(self.search_results)
|
||||||
|
self._worker.error_occurred.connect(self.error_occurred)
|
||||||
|
|
||||||
|
self._thread.start()
|
||||||
|
|
||||||
|
def start_discovery(self) -> None:
|
||||||
|
self.loading_started.emit()
|
||||||
|
self._worker.discover_plugins()
|
||||||
|
|
||||||
|
def search(self, query: str) -> None:
|
||||||
|
self._worker.search_plugins(query)
|
||||||
|
|
||||||
|
def shutdown(self) -> None:
|
||||||
|
self._thread.quit()
|
||||||
|
self._thread.wait()
|
||||||
93
src/illogical/modules/sf_symbols.py
Normal file
93
src/illogical/modules/sf_symbols.py
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from AppKit import (
|
||||||
|
NSColor, # type: ignore[attr-defined]
|
||||||
|
NSFontWeightRegular, # type: ignore[attr-defined]
|
||||||
|
NSGraphicsContext, # type: ignore[attr-defined]
|
||||||
|
NSImage, # type: ignore[attr-defined]
|
||||||
|
NSImageSymbolConfiguration, # type: ignore[attr-defined]
|
||||||
|
NSImageSymbolScaleMedium, # type: ignore[attr-defined]
|
||||||
|
)
|
||||||
|
from PySide6.QtGui import QIcon, QImage, QPixmap
|
||||||
|
from Quartz import (
|
||||||
|
CGBitmapContextCreate, # type: ignore[attr-defined]
|
||||||
|
CGBitmapContextCreateImage, # type: ignore[attr-defined]
|
||||||
|
CGColorSpaceCreateDeviceRGB, # type: ignore[attr-defined]
|
||||||
|
CGDataProviderCopyData, # type: ignore[attr-defined]
|
||||||
|
CGImageGetDataProvider, # type: ignore[attr-defined]
|
||||||
|
CGImageGetHeight, # type: ignore[attr-defined]
|
||||||
|
CGImageGetWidth, # type: ignore[attr-defined]
|
||||||
|
kCGImageAlphaPremultipliedLast, # type: ignore[attr-defined]
|
||||||
|
)
|
||||||
|
|
||||||
|
_icon_cache: dict[tuple[str, int, tuple[float, ...] | None], QIcon] = {}
|
||||||
|
|
||||||
|
SCALE_FACTOR = 2
|
||||||
|
|
||||||
|
DEFAULT_COLOR = (155.0 / 255.0, 153.0 / 255.0, 158.0 / 255.0, 1.0)
|
||||||
|
|
||||||
|
|
||||||
|
def sf_symbol(
|
||||||
|
name: str, size: int = 16, color: tuple[float, float, float, float] | None = None
|
||||||
|
) -> QIcon:
|
||||||
|
color_key = color if color else None
|
||||||
|
cache_key = (name, size, color_key)
|
||||||
|
if cache_key in _icon_cache:
|
||||||
|
return _icon_cache[cache_key]
|
||||||
|
|
||||||
|
ns_image = NSImage.imageWithSystemSymbolName_accessibilityDescription_(name, None)
|
||||||
|
if ns_image is None:
|
||||||
|
return QIcon()
|
||||||
|
|
||||||
|
size_config = NSImageSymbolConfiguration.configurationWithPointSize_weight_scale_(
|
||||||
|
float(size), NSFontWeightRegular, NSImageSymbolScaleMedium
|
||||||
|
)
|
||||||
|
r, g, b, a = color if color else DEFAULT_COLOR
|
||||||
|
icon_color = NSColor.colorWithSRGBRed_green_blue_alpha_(r, g, b, a)
|
||||||
|
color_config = NSImageSymbolConfiguration.configurationWithHierarchicalColor_(
|
||||||
|
icon_color
|
||||||
|
)
|
||||||
|
config = size_config.configurationByApplyingConfiguration_(color_config)
|
||||||
|
ns_image = ns_image.imageWithSymbolConfiguration_(config)
|
||||||
|
|
||||||
|
img_size = ns_image.size()
|
||||||
|
pixel_width = int(img_size.width * SCALE_FACTOR)
|
||||||
|
pixel_height = int(img_size.height * SCALE_FACTOR)
|
||||||
|
|
||||||
|
color_space = CGColorSpaceCreateDeviceRGB()
|
||||||
|
ctx = CGBitmapContextCreate(
|
||||||
|
None,
|
||||||
|
pixel_width,
|
||||||
|
pixel_height,
|
||||||
|
8,
|
||||||
|
pixel_width * 4,
|
||||||
|
color_space,
|
||||||
|
kCGImageAlphaPremultipliedLast,
|
||||||
|
)
|
||||||
|
|
||||||
|
NSGraphicsContext.saveGraphicsState()
|
||||||
|
ns_ctx = NSGraphicsContext.graphicsContextWithCGContext_flipped_(ctx, False) # noqa: FBT003
|
||||||
|
NSGraphicsContext.setCurrentContext_(ns_ctx)
|
||||||
|
|
||||||
|
ns_image.drawInRect_(((0, 0), (pixel_width, pixel_height)))
|
||||||
|
|
||||||
|
NSGraphicsContext.restoreGraphicsState()
|
||||||
|
|
||||||
|
cg_image = CGBitmapContextCreateImage(ctx)
|
||||||
|
if cg_image is None:
|
||||||
|
return QIcon()
|
||||||
|
|
||||||
|
width = CGImageGetWidth(cg_image)
|
||||||
|
height = CGImageGetHeight(cg_image)
|
||||||
|
data_provider = CGImageGetDataProvider(cg_image)
|
||||||
|
cf_data = CGDataProviderCopyData(data_provider)
|
||||||
|
|
||||||
|
qimage = QImage(
|
||||||
|
bytes(cf_data), width, height, QImage.Format.Format_RGBA8888_Premultiplied
|
||||||
|
).copy()
|
||||||
|
qimage.setDevicePixelRatio(SCALE_FACTOR)
|
||||||
|
|
||||||
|
pixmap = QPixmap.fromImage(qimage)
|
||||||
|
icon = QIcon(pixmap)
|
||||||
|
_icon_cache[cache_key] = icon
|
||||||
|
return icon
|
||||||
2
src/illogical/resources/README
Normal file
2
src/illogical/resources/README
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Put any application resources (e.g., icons and resources) here;
|
||||||
|
they can be referenced in code as "resources/filename".
|
||||||
0
src/illogical/ui/__init__.py
Normal file
0
src/illogical/ui/__init__.py
Normal file
44
src/illogical/ui/loading_overlay.py
Normal file
44
src/illogical/ui/loading_overlay.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING, cast
|
||||||
|
|
||||||
|
from PySide6.QtCore import Qt
|
||||||
|
from PySide6.QtWidgets import QLabel, QProgressBar, QVBoxLayout, QWidget
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from PySide6.QtGui import QResizeEvent, QShowEvent
|
||||||
|
|
||||||
|
|
||||||
|
class LoadingOverlay(QWidget):
|
||||||
|
def __init__(self, parent: QWidget | None = None) -> None:
|
||||||
|
super().__init__(parent)
|
||||||
|
self.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents, on=False)
|
||||||
|
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
layout.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
|
|
||||||
|
self._spinner = QProgressBar()
|
||||||
|
self._spinner.setRange(0, 0)
|
||||||
|
self._spinner.setFixedWidth(200)
|
||||||
|
|
||||||
|
self._label = QLabel("Discovering plugins...")
|
||||||
|
self._label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
|
|
||||||
|
layout.addWidget(self._spinner)
|
||||||
|
layout.addSpacing(12)
|
||||||
|
layout.addWidget(self._label)
|
||||||
|
|
||||||
|
def set_message(self, message: str) -> None:
|
||||||
|
self._label.setText(message)
|
||||||
|
|
||||||
|
def showEvent(self, event: QShowEvent) -> None: # noqa: N802
|
||||||
|
super().showEvent(event)
|
||||||
|
parent = self.parent()
|
||||||
|
if parent is not None:
|
||||||
|
self.resize(cast("QWidget", parent).size())
|
||||||
|
|
||||||
|
def resizeEvent(self, event: QResizeEvent) -> None: # noqa: N802
|
||||||
|
super().resizeEvent(event)
|
||||||
|
parent = self.parent()
|
||||||
|
if parent is not None:
|
||||||
|
self.resize(cast("QWidget", parent).size())
|
||||||
178
src/illogical/ui/main_window.py
Normal file
178
src/illogical/ui/main_window.py
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
import pyqt_liquidglass as glass
|
||||||
|
from PySide6.QtCore import Qt, QTimer
|
||||||
|
from PySide6.QtWidgets import QHBoxLayout, QMainWindow, QSplitter, QWidget
|
||||||
|
|
||||||
|
from illogical.modules.plugin_service import PluginService
|
||||||
|
from illogical.ui.loading_overlay import LoadingOverlay
|
||||||
|
from illogical.ui.plugin_table import PluginTableView
|
||||||
|
from illogical.ui.sidebar import Sidebar
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from logic_plugin_manager import Logic, SearchResult
|
||||||
|
from PySide6.QtGui import QCloseEvent, QKeyEvent, QShowEvent
|
||||||
|
|
||||||
|
|
||||||
|
class MainWindow(QMainWindow):
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.setWindowTitle("illogical")
|
||||||
|
self.resize(1200, 800)
|
||||||
|
self.setMinimumSize(800, 600)
|
||||||
|
|
||||||
|
self._logic: Logic | None = None
|
||||||
|
self._glass_applied = False
|
||||||
|
|
||||||
|
self._setup_ui()
|
||||||
|
self._setup_service()
|
||||||
|
|
||||||
|
glass.prepare_window_for_glass(self)
|
||||||
|
|
||||||
|
def _setup_ui(self) -> None:
|
||||||
|
self._central = QWidget()
|
||||||
|
layout = QHBoxLayout(self._central)
|
||||||
|
layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
layout.setSpacing(0)
|
||||||
|
|
||||||
|
self._splitter = QSplitter(Qt.Orientation.Horizontal)
|
||||||
|
self._splitter.setHandleWidth(1)
|
||||||
|
self._splitter.setStyleSheet("QSplitter::handle { background: transparent; }")
|
||||||
|
|
||||||
|
self._sidebar = Sidebar()
|
||||||
|
self._plugin_table = PluginTableView()
|
||||||
|
|
||||||
|
self._splitter.addWidget(self._sidebar)
|
||||||
|
self._splitter.addWidget(self._plugin_table)
|
||||||
|
self._splitter.setStretchFactor(0, 1)
|
||||||
|
self._splitter.setStretchFactor(1, 4)
|
||||||
|
self._splitter.setCollapsible(0, False) # noqa: FBT003
|
||||||
|
self._splitter.setCollapsible(1, False) # noqa: FBT003
|
||||||
|
|
||||||
|
layout.addWidget(self._splitter)
|
||||||
|
|
||||||
|
self.setCentralWidget(self._central)
|
||||||
|
|
||||||
|
self._loading_overlay = LoadingOverlay(self._central)
|
||||||
|
self._loading_overlay.hide()
|
||||||
|
|
||||||
|
self._sidebar.category_selected.connect(self._on_category_selected)
|
||||||
|
self._sidebar.manufacturer_selected.connect(self._on_manufacturer_selected)
|
||||||
|
self._sidebar.enter_pressed.connect(self._plugin_table.focus_table)
|
||||||
|
self._plugin_table.search_changed.connect(self._on_search_changed)
|
||||||
|
self._plugin_table.plugin_selected.connect(self._on_plugin_selected)
|
||||||
|
|
||||||
|
def _setup_service(self) -> None:
|
||||||
|
self._service = PluginService(self)
|
||||||
|
self._service.loading_started.connect(self._on_loading_started)
|
||||||
|
self._service.plugins_loaded.connect(self._on_plugins_loaded)
|
||||||
|
self._service.search_results.connect(self._on_search_results)
|
||||||
|
self._service.error_occurred.connect(self._on_error)
|
||||||
|
|
||||||
|
def showEvent(self, event: QShowEvent) -> None: # noqa: N802
|
||||||
|
super().showEvent(event)
|
||||||
|
if not self._glass_applied:
|
||||||
|
self._glass_applied = True
|
||||||
|
QTimer.singleShot(0, self._apply_glass)
|
||||||
|
QTimer.singleShot(100, self._service.start_discovery)
|
||||||
|
|
||||||
|
def _apply_glass(self) -> None:
|
||||||
|
glass.setup_traffic_lights_inset(self, x_offset=18, y_offset=12)
|
||||||
|
glass.apply_glass_to_widget(self._sidebar, options=glass.GlassOptions.sidebar())
|
||||||
|
glass.apply_glass_to_widget(
|
||||||
|
self._central, options=glass.GlassOptions(corner_radius=0.0)
|
||||||
|
)
|
||||||
|
|
||||||
|
def _on_loading_started(self) -> None:
|
||||||
|
self._loading_overlay.set_message("Discovering plugins...")
|
||||||
|
self._loading_overlay.show()
|
||||||
|
self._loading_overlay.raise_()
|
||||||
|
|
||||||
|
def _on_plugins_loaded(self, logic: Logic) -> None:
|
||||||
|
self._logic = logic
|
||||||
|
self._sidebar.populate(logic)
|
||||||
|
self._plugin_table.set_plugins(logic)
|
||||||
|
self._loading_overlay.hide()
|
||||||
|
self._plugin_table.focus_table()
|
||||||
|
|
||||||
|
def _on_category_selected(self, category: str | None) -> None:
|
||||||
|
self._plugin_table.clear_search()
|
||||||
|
self._plugin_table.filter_by_category(category)
|
||||||
|
|
||||||
|
def _on_manufacturer_selected(self, manufacturer: str) -> None:
|
||||||
|
self._plugin_table.clear_search()
|
||||||
|
self._plugin_table.filter_by_manufacturer(manufacturer)
|
||||||
|
|
||||||
|
def _on_search_changed(self, query: str) -> None:
|
||||||
|
if not query:
|
||||||
|
self._plugin_table.filter_by_category("Show All")
|
||||||
|
return
|
||||||
|
self._service.search(query)
|
||||||
|
|
||||||
|
def _on_plugin_selected(self, plugin: object) -> None:
|
||||||
|
categories = getattr(plugin, "categories", [])
|
||||||
|
paths = [c.name for c in categories if c.name]
|
||||||
|
if any(c.name == "" for c in categories):
|
||||||
|
paths.append("Top Level")
|
||||||
|
self._sidebar.highlight_categories(paths)
|
||||||
|
|
||||||
|
def _on_search_results(self, results: list[SearchResult]) -> None:
|
||||||
|
plugins = [r.plugin for r in results]
|
||||||
|
self._plugin_table.filter_by_search_results(plugins)
|
||||||
|
|
||||||
|
def _on_error(self, message: str) -> None:
|
||||||
|
self._loading_overlay.set_message(f"Error: {message}")
|
||||||
|
|
||||||
|
def keyPressEvent(self, event: QKeyEvent) -> None: # noqa: N802
|
||||||
|
mods = event.modifiers()
|
||||||
|
key = event.key()
|
||||||
|
|
||||||
|
if mods == Qt.KeyboardModifier.ControlModifier:
|
||||||
|
if key == Qt.Key.Key_F:
|
||||||
|
if self._sidebar.is_manufacturer_mode():
|
||||||
|
self._sidebar.focus_manufacturer_search()
|
||||||
|
else:
|
||||||
|
self._plugin_table.focus_search()
|
||||||
|
event.accept()
|
||||||
|
return
|
||||||
|
if key == Qt.Key.Key_1:
|
||||||
|
self._reset_to_show_all()
|
||||||
|
self._plugin_table.focus_table()
|
||||||
|
event.accept()
|
||||||
|
return
|
||||||
|
if key == Qt.Key.Key_2:
|
||||||
|
self._select_uncategorized()
|
||||||
|
self._plugin_table.focus_table()
|
||||||
|
event.accept()
|
||||||
|
return
|
||||||
|
if key == Qt.Key.Key_3:
|
||||||
|
self._sidebar.focus_category_tree()
|
||||||
|
event.accept()
|
||||||
|
return
|
||||||
|
if key == Qt.Key.Key_4:
|
||||||
|
self._sidebar.focus_manufacturer_list()
|
||||||
|
event.accept()
|
||||||
|
return
|
||||||
|
|
||||||
|
if key == Qt.Key.Key_Escape:
|
||||||
|
self._reset_to_show_all()
|
||||||
|
event.accept()
|
||||||
|
return
|
||||||
|
|
||||||
|
super().keyPressEvent(event)
|
||||||
|
|
||||||
|
def _select_uncategorized(self) -> None:
|
||||||
|
self._plugin_table.clear_search()
|
||||||
|
self._sidebar.clear_manufacturer_search()
|
||||||
|
self._sidebar.select_uncategorized()
|
||||||
|
|
||||||
|
def _reset_to_show_all(self) -> None:
|
||||||
|
self._plugin_table.clear_search()
|
||||||
|
self._sidebar.clear_manufacturer_search()
|
||||||
|
self._sidebar.select_show_all()
|
||||||
|
|
||||||
|
def closeEvent(self, event: QCloseEvent) -> None: # noqa: N802
|
||||||
|
self._service.shutdown()
|
||||||
|
super().closeEvent(event)
|
||||||
214
src/illogical/ui/plugin_table.py
Normal file
214
src/illogical/ui/plugin_table.py
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from PySide6.QtCore import Qt, Signal
|
||||||
|
from PySide6.QtWidgets import (
|
||||||
|
QAbstractItemView,
|
||||||
|
QFrame,
|
||||||
|
QHeaderView,
|
||||||
|
QTableView,
|
||||||
|
QVBoxLayout,
|
||||||
|
QWidget,
|
||||||
|
)
|
||||||
|
|
||||||
|
from illogical.modules.models import (
|
||||||
|
COL_CUSTOM_NAME,
|
||||||
|
COL_MANUFACTURER,
|
||||||
|
COL_NAME,
|
||||||
|
COL_SHORT_NAME,
|
||||||
|
COL_TYPE,
|
||||||
|
COL_VERSION,
|
||||||
|
PluginTableModel,
|
||||||
|
)
|
||||||
|
from illogical.ui.search_bar import SearchBar
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from logic_plugin_manager import AudioComponent, Logic
|
||||||
|
from PySide6.QtCore import QModelIndex
|
||||||
|
from PySide6.QtGui import QKeyEvent, QResizeEvent
|
||||||
|
|
||||||
|
|
||||||
|
KVK_J = 0x26
|
||||||
|
KVK_K = 0x28
|
||||||
|
|
||||||
|
|
||||||
|
class _VimTableView(QTableView):
|
||||||
|
def _select_row(self, row: int) -> None:
|
||||||
|
index = self.model().index(row, 0)
|
||||||
|
self.selectionModel().setCurrentIndex(
|
||||||
|
index,
|
||||||
|
self.selectionModel().SelectionFlag.ClearAndSelect
|
||||||
|
| self.selectionModel().SelectionFlag.Rows,
|
||||||
|
)
|
||||||
|
|
||||||
|
def keyPressEvent(self, event: QKeyEvent) -> None: # noqa: N802
|
||||||
|
vk = event.nativeVirtualKey()
|
||||||
|
key = event.key()
|
||||||
|
|
||||||
|
if vk == KVK_J or key == Qt.Key.Key_Down:
|
||||||
|
current = self.currentIndex()
|
||||||
|
if current.row() < self.model().rowCount() - 1:
|
||||||
|
self._select_row(current.row() + 1)
|
||||||
|
event.accept()
|
||||||
|
return
|
||||||
|
if vk == KVK_K or key == Qt.Key.Key_Up:
|
||||||
|
current = self.currentIndex()
|
||||||
|
if current.row() > 0:
|
||||||
|
self._select_row(current.row() - 1)
|
||||||
|
event.accept()
|
||||||
|
return
|
||||||
|
super().keyPressEvent(event)
|
||||||
|
|
||||||
|
|
||||||
|
class PluginTableView(QWidget):
|
||||||
|
search_changed = Signal(str)
|
||||||
|
plugin_selected = Signal(object)
|
||||||
|
|
||||||
|
def __init__(self, parent: QWidget | None = None) -> None:
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
layout.setContentsMargins(16, 0, 16, 16)
|
||||||
|
layout.setSpacing(12)
|
||||||
|
|
||||||
|
self._search_bar = SearchBar()
|
||||||
|
self._search_bar.search_changed.connect(self.search_changed)
|
||||||
|
self._search_bar.escape_pressed.connect(self._on_search_escape)
|
||||||
|
layout.addWidget(self._search_bar)
|
||||||
|
|
||||||
|
self._model = PluginTableModel()
|
||||||
|
self._table = _VimTableView()
|
||||||
|
self._table.setModel(self._model)
|
||||||
|
self._table.setAlternatingRowColors(True)
|
||||||
|
self._table.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
||||||
|
self._table.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
|
||||||
|
self._table.setShowGrid(False)
|
||||||
|
self._table.verticalHeader().setVisible(False)
|
||||||
|
self._table.horizontalHeader().setStretchLastSection(True)
|
||||||
|
self._table.horizontalHeader().setAttribute(
|
||||||
|
Qt.WidgetAttribute.WA_TranslucentBackground
|
||||||
|
)
|
||||||
|
self._table.horizontalHeader().setSectionResizeMode(
|
||||||
|
QHeaderView.ResizeMode.Interactive
|
||||||
|
)
|
||||||
|
self._table.setFrameShape(QFrame.Shape.NoFrame)
|
||||||
|
self._table.setSortingEnabled(True)
|
||||||
|
self._table.sortByColumn(0, Qt.SortOrder.AscendingOrder)
|
||||||
|
self._table.setStyleSheet("""
|
||||||
|
QTableView {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
QTableView::item {
|
||||||
|
padding: 1px 4px;
|
||||||
|
}
|
||||||
|
QTableView::item:alternate {
|
||||||
|
background: rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
QTableView::item:selected {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
QHeaderView {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
QHeaderView::section {
|
||||||
|
padding: 4px 6px;
|
||||||
|
background: rgba(0, 0, 0, 0.08);
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
QHeaderView::section:first {
|
||||||
|
border-top-left-radius: 14px;
|
||||||
|
border-bottom-left-radius: 14px;
|
||||||
|
}
|
||||||
|
QHeaderView::section:last {
|
||||||
|
border-top-right-radius: 14px;
|
||||||
|
border-bottom-right-radius: 14px;
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
|
||||||
|
layout.addWidget(self._table, 1)
|
||||||
|
|
||||||
|
self._table.selectionModel().currentChanged.connect(self._on_current_changed)
|
||||||
|
|
||||||
|
def _on_current_changed(self, current: QModelIndex, _previous: QModelIndex) -> None:
|
||||||
|
if current.isValid():
|
||||||
|
plugin = self._model.get_plugin(current.row())
|
||||||
|
if plugin:
|
||||||
|
self.plugin_selected.emit(plugin)
|
||||||
|
|
||||||
|
def set_plugins(self, logic: Logic) -> None:
|
||||||
|
self._model.set_plugins(logic)
|
||||||
|
self._resize_columns()
|
||||||
|
|
||||||
|
def filter_by_category(self, category: str | None) -> None:
|
||||||
|
self._model.filter_by_category(category)
|
||||||
|
|
||||||
|
def filter_by_manufacturer(self, manufacturer: str) -> None:
|
||||||
|
self._model.filter_by_manufacturer(manufacturer)
|
||||||
|
|
||||||
|
def filter_by_search_results(self, plugins: list[AudioComponent]) -> None:
|
||||||
|
self._model.filter_by_search_results(plugins)
|
||||||
|
|
||||||
|
def clear_search(self) -> None:
|
||||||
|
self._search_bar.clear()
|
||||||
|
|
||||||
|
def focus_search(self) -> None:
|
||||||
|
self._search_bar.setFocus()
|
||||||
|
self._search_bar.selectAll()
|
||||||
|
|
||||||
|
def focus_table(self) -> None:
|
||||||
|
self._table.setFocus()
|
||||||
|
has_selection = self._table.selectionModel().hasSelection()
|
||||||
|
if not has_selection and self._model.rowCount() > 0:
|
||||||
|
self._table.selectRow(0)
|
||||||
|
|
||||||
|
def _on_search_escape(self) -> None:
|
||||||
|
self._table.setFocus()
|
||||||
|
|
||||||
|
def _resize_columns(self) -> None:
|
||||||
|
header = self._table.horizontalHeader()
|
||||||
|
header.setSectionResizeMode(QHeaderView.ResizeMode.Interactive)
|
||||||
|
header.setStretchLastSection(False)
|
||||||
|
|
||||||
|
self._table.resizeColumnToContents(COL_TYPE)
|
||||||
|
self._table.resizeColumnToContents(COL_MANUFACTURER)
|
||||||
|
self._table.resizeColumnToContents(COL_VERSION)
|
||||||
|
|
||||||
|
padding = 20
|
||||||
|
type_width = header.sectionSize(COL_TYPE) + padding
|
||||||
|
manufacturer_width = header.sectionSize(COL_MANUFACTURER) + padding
|
||||||
|
version_width = header.sectionSize(COL_VERSION) + padding
|
||||||
|
|
||||||
|
header.resizeSection(COL_TYPE, type_width)
|
||||||
|
header.resizeSection(COL_MANUFACTURER, manufacturer_width)
|
||||||
|
header.resizeSection(COL_VERSION, version_width)
|
||||||
|
|
||||||
|
total_width = self._table.viewport().width()
|
||||||
|
fixed_width = type_width + manufacturer_width + version_width
|
||||||
|
remaining = total_width - fixed_width
|
||||||
|
|
||||||
|
header.resizeSection(COL_NAME, int(remaining * 0.5))
|
||||||
|
header.resizeSection(COL_CUSTOM_NAME, int(remaining * 0.25))
|
||||||
|
header.resizeSection(COL_SHORT_NAME, int(remaining * 0.25))
|
||||||
|
|
||||||
|
self._store_proportions()
|
||||||
|
|
||||||
|
def _store_proportions(self) -> None:
|
||||||
|
header = self._table.horizontalHeader()
|
||||||
|
total = self._table.viewport().width()
|
||||||
|
if total > 0:
|
||||||
|
self._column_proportions = [
|
||||||
|
header.sectionSize(i) / total for i in range(self._model.columnCount())
|
||||||
|
]
|
||||||
|
|
||||||
|
def _apply_proportions(self) -> None:
|
||||||
|
if not hasattr(self, "_column_proportions"):
|
||||||
|
return
|
||||||
|
header = self._table.horizontalHeader()
|
||||||
|
total = self._table.viewport().width()
|
||||||
|
for i, prop in enumerate(self._column_proportions):
|
||||||
|
header.resizeSection(i, int(total * prop))
|
||||||
|
|
||||||
|
def resizeEvent(self, event: QResizeEvent) -> None: # noqa: N802
|
||||||
|
super().resizeEvent(event)
|
||||||
|
self._apply_proportions()
|
||||||
65
src/illogical/ui/search_bar.py
Normal file
65
src/illogical/ui/search_bar.py
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from PySide6.QtCore import Qt, QTimer, Signal
|
||||||
|
from PySide6.QtWidgets import QLineEdit, QWidget
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from PySide6.QtGui import QKeyEvent
|
||||||
|
|
||||||
|
from illogical.modules.sf_symbols import sf_symbol
|
||||||
|
|
||||||
|
MIN_SEARCH_LENGTH = 1
|
||||||
|
|
||||||
|
|
||||||
|
class SearchBar(QLineEdit):
|
||||||
|
search_changed = Signal(str)
|
||||||
|
escape_pressed = Signal()
|
||||||
|
|
||||||
|
def __init__(self, parent: QWidget | None = None) -> None:
|
||||||
|
super().__init__(parent)
|
||||||
|
self.setPlaceholderText("Search")
|
||||||
|
self.setClearButtonEnabled(True)
|
||||||
|
|
||||||
|
search_icon = sf_symbol("magnifyingglass", 14)
|
||||||
|
if not search_icon.isNull():
|
||||||
|
self.addAction(search_icon, QLineEdit.ActionPosition.LeadingPosition)
|
||||||
|
|
||||||
|
self.setStyleSheet("""
|
||||||
|
QLineEdit {
|
||||||
|
border: none;
|
||||||
|
border-radius: 14px;
|
||||||
|
padding: 6px 12px 6px 8px;
|
||||||
|
background: #302C33;
|
||||||
|
}
|
||||||
|
QLineEdit:focus {
|
||||||
|
border: 2px solid palette(highlight);
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
|
||||||
|
self._debounce_timer = QTimer(self)
|
||||||
|
self._debounce_timer.setSingleShot(True)
|
||||||
|
self._debounce_timer.setInterval(150)
|
||||||
|
self._debounce_timer.timeout.connect(self._emit_search)
|
||||||
|
|
||||||
|
self.textChanged.connect(self._on_text_changed)
|
||||||
|
|
||||||
|
def _on_text_changed(self, text: str) -> None:
|
||||||
|
self._debounce_timer.stop()
|
||||||
|
if len(text) >= MIN_SEARCH_LENGTH or len(text) == 0:
|
||||||
|
self._debounce_timer.start()
|
||||||
|
|
||||||
|
def _emit_search(self) -> None:
|
||||||
|
self.search_changed.emit(self.text())
|
||||||
|
|
||||||
|
def keyPressEvent(self, event: QKeyEvent) -> None: # noqa: N802
|
||||||
|
if event.key() == Qt.Key.Key_Escape:
|
||||||
|
if self.text():
|
||||||
|
self.clear()
|
||||||
|
else:
|
||||||
|
self.escape_pressed.emit()
|
||||||
|
self.clearFocus()
|
||||||
|
event.accept()
|
||||||
|
return
|
||||||
|
super().keyPressEvent(event)
|
||||||
486
src/illogical/ui/sidebar.py
Normal file
486
src/illogical/ui/sidebar.py
Normal file
@@ -0,0 +1,486 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from AppKit import NSColor # type: ignore[attr-defined]
|
||||||
|
from PySide6.QtCore import QModelIndex, QRect, Qt, Signal
|
||||||
|
from PySide6.QtGui import QFont
|
||||||
|
from PySide6.QtWidgets import (
|
||||||
|
QAbstractItemView,
|
||||||
|
QFrame,
|
||||||
|
QHBoxLayout,
|
||||||
|
QLabel,
|
||||||
|
QListView,
|
||||||
|
QSplitter,
|
||||||
|
QStyle,
|
||||||
|
QStyledItemDelegate,
|
||||||
|
QStyleOptionViewItem,
|
||||||
|
QTreeView,
|
||||||
|
QVBoxLayout,
|
||||||
|
QWidget,
|
||||||
|
)
|
||||||
|
|
||||||
|
from illogical.modules.models import (
|
||||||
|
CategoryTreeModel,
|
||||||
|
ManufacturerFilterProxy,
|
||||||
|
ManufacturerListModel,
|
||||||
|
)
|
||||||
|
from illogical.modules.sf_symbols import sf_symbol
|
||||||
|
from illogical.ui.search_bar import SearchBar
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from logic_plugin_manager import Logic
|
||||||
|
from PySide6.QtGui import QKeyEvent, QMouseEvent, QPainter
|
||||||
|
|
||||||
|
|
||||||
|
KVK_H = 0x04
|
||||||
|
KVK_J = 0x26
|
||||||
|
KVK_K = 0x28
|
||||||
|
KVK_L = 0x25
|
||||||
|
|
||||||
|
|
||||||
|
class _VimTreeView(QTreeView):
|
||||||
|
enter_pressed = Signal()
|
||||||
|
|
||||||
|
def _select_and_activate(self, index: QModelIndex) -> None:
|
||||||
|
self.selectionModel().setCurrentIndex(
|
||||||
|
index, self.selectionModel().SelectionFlag.ClearAndSelect
|
||||||
|
)
|
||||||
|
self.clicked.emit(index)
|
||||||
|
|
||||||
|
def keyPressEvent(self, event: QKeyEvent) -> None: # noqa: N802
|
||||||
|
vk = event.nativeVirtualKey()
|
||||||
|
key = event.key()
|
||||||
|
|
||||||
|
if vk == KVK_J or key == Qt.Key.Key_Down:
|
||||||
|
next_idx = self.indexBelow(self.currentIndex())
|
||||||
|
if next_idx.isValid():
|
||||||
|
self._select_and_activate(next_idx)
|
||||||
|
event.accept()
|
||||||
|
return
|
||||||
|
if vk == KVK_K or key == Qt.Key.Key_Up:
|
||||||
|
prev_idx = self.indexAbove(self.currentIndex())
|
||||||
|
if prev_idx.isValid():
|
||||||
|
self._select_and_activate(prev_idx)
|
||||||
|
event.accept()
|
||||||
|
return
|
||||||
|
if vk == KVK_H or key == Qt.Key.Key_Left:
|
||||||
|
self.collapse(self.currentIndex())
|
||||||
|
event.accept()
|
||||||
|
return
|
||||||
|
if vk == KVK_L or key == Qt.Key.Key_Right:
|
||||||
|
self.expand(self.currentIndex())
|
||||||
|
event.accept()
|
||||||
|
return
|
||||||
|
if key in (Qt.Key.Key_Return, Qt.Key.Key_Enter):
|
||||||
|
self.enter_pressed.emit()
|
||||||
|
event.accept()
|
||||||
|
return
|
||||||
|
super().keyPressEvent(event)
|
||||||
|
|
||||||
|
|
||||||
|
class _VimListView(QListView):
|
||||||
|
enter_pressed = Signal()
|
||||||
|
|
||||||
|
def _select_and_activate(self, index: QModelIndex) -> None:
|
||||||
|
self.selectionModel().setCurrentIndex(
|
||||||
|
index, self.selectionModel().SelectionFlag.ClearAndSelect
|
||||||
|
)
|
||||||
|
self.clicked.emit(index)
|
||||||
|
|
||||||
|
def keyPressEvent(self, event: QKeyEvent) -> None: # noqa: N802
|
||||||
|
vk = event.nativeVirtualKey()
|
||||||
|
key = event.key()
|
||||||
|
|
||||||
|
if vk == KVK_J or key == Qt.Key.Key_Down:
|
||||||
|
current = self.currentIndex()
|
||||||
|
next_idx = self.model().index(current.row() + 1, 0)
|
||||||
|
if next_idx.isValid():
|
||||||
|
self._select_and_activate(next_idx)
|
||||||
|
event.accept()
|
||||||
|
return
|
||||||
|
if vk == KVK_K or key == Qt.Key.Key_Up:
|
||||||
|
current = self.currentIndex()
|
||||||
|
if current.row() > 0:
|
||||||
|
prev_idx = self.model().index(current.row() - 1, 0)
|
||||||
|
self._select_and_activate(prev_idx)
|
||||||
|
event.accept()
|
||||||
|
return
|
||||||
|
if key in (Qt.Key.Key_Return, Qt.Key.Key_Enter):
|
||||||
|
self.enter_pressed.emit()
|
||||||
|
event.accept()
|
||||||
|
return
|
||||||
|
super().keyPressEvent(event)
|
||||||
|
|
||||||
|
|
||||||
|
class _CategoryDelegate(QStyledItemDelegate):
|
||||||
|
def paint(
|
||||||
|
self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex
|
||||||
|
) -> None:
|
||||||
|
full_path = index.data(Qt.ItemDataRole.UserRole)
|
||||||
|
icon = index.data(Qt.ItemDataRole.DecorationRole)
|
||||||
|
|
||||||
|
if full_path == "Top Level" and icon and not icon.isNull():
|
||||||
|
opt = QStyleOptionViewItem(option)
|
||||||
|
self.initStyleOption(opt, index)
|
||||||
|
opt.icon = icon # type: ignore[attr-defined]
|
||||||
|
opt.decorationPosition = QStyleOptionViewItem.Position.Left # type: ignore[attr-defined]
|
||||||
|
|
||||||
|
style = opt.widget.style() if opt.widget else None # type: ignore[attr-defined]
|
||||||
|
if style:
|
||||||
|
icon_rect = QRect(
|
||||||
|
opt.rect.left() - 14, # type: ignore[attr-defined]
|
||||||
|
opt.rect.top() + (opt.rect.height() - 14) // 2, # type: ignore[attr-defined]
|
||||||
|
14,
|
||||||
|
14,
|
||||||
|
)
|
||||||
|
|
||||||
|
opt.icon = type(icon)() # type: ignore[attr-defined]
|
||||||
|
opt.decorationSize = type(opt.decorationSize)(1, 1) # type: ignore[attr-defined]
|
||||||
|
opt.rect.adjust(-5, 0, 0, 0) # type: ignore[attr-defined]
|
||||||
|
style.drawControl(QStyle.ControlElement.CE_ItemViewItem, opt, painter)
|
||||||
|
|
||||||
|
if opt.state & QStyle.StateFlag.State_Selected: # type: ignore[attr-defined]
|
||||||
|
selected_icon = sf_symbol("arrow.up", 14, (1.0, 1.0, 1.0, 1.0))
|
||||||
|
selected_icon.paint(painter, icon_rect)
|
||||||
|
else:
|
||||||
|
icon.paint(painter, icon_rect)
|
||||||
|
return
|
||||||
|
|
||||||
|
super().paint(painter, option, index)
|
||||||
|
|
||||||
|
|
||||||
|
class StickyItem(QWidget):
|
||||||
|
clicked = Signal(str)
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, text: str, icon_name: str, parent: QWidget | None = None
|
||||||
|
) -> None:
|
||||||
|
super().__init__(parent)
|
||||||
|
self._text = text
|
||||||
|
self._icon_name = icon_name
|
||||||
|
self.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||||
|
|
||||||
|
layout = QHBoxLayout(self)
|
||||||
|
layout.setContentsMargins(8, 4, 4, 4)
|
||||||
|
layout.setSpacing(6)
|
||||||
|
|
||||||
|
self._icon_label = QLabel()
|
||||||
|
icon = sf_symbol(icon_name, 16)
|
||||||
|
if not icon.isNull():
|
||||||
|
self._icon_label.setPixmap(icon.pixmap(16, 16))
|
||||||
|
|
||||||
|
self._text_label = QLabel(text)
|
||||||
|
|
||||||
|
layout.addWidget(self._icon_label)
|
||||||
|
layout.addWidget(self._text_label)
|
||||||
|
layout.addStretch()
|
||||||
|
|
||||||
|
def set_selected(self, selected: bool) -> None: # noqa: FBT001
|
||||||
|
if selected:
|
||||||
|
accent = NSColor.controlAccentColor()
|
||||||
|
accent = accent.colorUsingColorSpaceName_("NSCalibratedRGBColorSpace")
|
||||||
|
r, g, b = (
|
||||||
|
accent.redComponent(),
|
||||||
|
accent.greenComponent(),
|
||||||
|
accent.blueComponent(),
|
||||||
|
)
|
||||||
|
self._text_label.setStyleSheet(
|
||||||
|
f"color: rgb({int(r * 255)}, {int(g * 255)}, {int(b * 255)});"
|
||||||
|
)
|
||||||
|
icon = sf_symbol(self._icon_name, 16, (r, g, b, 1.0))
|
||||||
|
if not icon.isNull():
|
||||||
|
self._icon_label.setPixmap(icon.pixmap(16, 16))
|
||||||
|
else:
|
||||||
|
self._text_label.setStyleSheet("")
|
||||||
|
icon = sf_symbol(self._icon_name, 16)
|
||||||
|
if not icon.isNull():
|
||||||
|
self._icon_label.setPixmap(icon.pixmap(16, 16))
|
||||||
|
|
||||||
|
def mousePressEvent(self, event: QMouseEvent) -> None: # noqa: ARG002, N802
|
||||||
|
self.clicked.emit(self._text)
|
||||||
|
|
||||||
|
|
||||||
|
class _SectionHeader(QWidget):
|
||||||
|
def __init__(
|
||||||
|
self, title: str, icon_name: str, parent: QWidget | None = None
|
||||||
|
) -> None:
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
|
layout = QHBoxLayout(self)
|
||||||
|
layout.setContentsMargins(8, 8, 8, 8)
|
||||||
|
layout.setSpacing(8)
|
||||||
|
|
||||||
|
icon_label = QLabel()
|
||||||
|
icon = sf_symbol(icon_name, 16)
|
||||||
|
if not icon.isNull():
|
||||||
|
icon_label.setPixmap(icon.pixmap(16, 16))
|
||||||
|
|
||||||
|
title_label = QLabel(title)
|
||||||
|
title_label.setStyleSheet("font-size: 11px;")
|
||||||
|
|
||||||
|
layout.addWidget(icon_label)
|
||||||
|
layout.addWidget(title_label)
|
||||||
|
layout.addStretch()
|
||||||
|
|
||||||
|
|
||||||
|
class _DraggableHeader(_SectionHeader):
|
||||||
|
dragged = Signal(int)
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, title: str, icon_name: str, parent: QWidget | None = None
|
||||||
|
) -> None:
|
||||||
|
super().__init__(title, icon_name, parent)
|
||||||
|
self.setCursor(Qt.CursorShape.SplitVCursor)
|
||||||
|
self._drag_start: int | None = None
|
||||||
|
|
||||||
|
def mousePressEvent(self, event: QMouseEvent) -> None: # noqa: N802
|
||||||
|
if event.button() == Qt.MouseButton.LeftButton:
|
||||||
|
self._drag_start = event.globalPosition().toPoint().y()
|
||||||
|
|
||||||
|
def mouseMoveEvent(self, event: QMouseEvent) -> None: # noqa: N802
|
||||||
|
if self._drag_start is not None:
|
||||||
|
delta = event.globalPosition().toPoint().y() - self._drag_start
|
||||||
|
self.dragged.emit(delta)
|
||||||
|
self._drag_start = event.globalPosition().toPoint().y()
|
||||||
|
|
||||||
|
def mouseReleaseEvent(self, event: QMouseEvent) -> None: # noqa: ARG002, N802
|
||||||
|
self._drag_start = None
|
||||||
|
|
||||||
|
|
||||||
|
class Sidebar(QWidget):
|
||||||
|
category_selected = Signal(object)
|
||||||
|
manufacturer_selected = Signal(str)
|
||||||
|
enter_pressed = Signal()
|
||||||
|
|
||||||
|
def __init__(self, parent: QWidget | None = None) -> None:
|
||||||
|
super().__init__(parent)
|
||||||
|
self.setMinimumWidth(200)
|
||||||
|
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
layout.setSpacing(0)
|
||||||
|
|
||||||
|
layout.addWidget(self._create_sticky_items())
|
||||||
|
layout.addWidget(self._create_splitter(), 1)
|
||||||
|
|
||||||
|
def _create_sticky_items(self) -> QWidget:
|
||||||
|
container = QWidget()
|
||||||
|
layout = QVBoxLayout(container)
|
||||||
|
layout.setContentsMargins(9, 18, 9, 9)
|
||||||
|
layout.setSpacing(0)
|
||||||
|
|
||||||
|
self._show_all = StickyItem("Show All", "tray.full")
|
||||||
|
self._show_all.clicked.connect(self._on_show_all_clicked)
|
||||||
|
|
||||||
|
self._uncategorized = StickyItem("Uncategorized", "questionmark.folder")
|
||||||
|
self._uncategorized.clicked.connect(self._on_uncategorized_clicked)
|
||||||
|
|
||||||
|
layout.addWidget(self._show_all)
|
||||||
|
layout.addWidget(self._uncategorized)
|
||||||
|
return container
|
||||||
|
|
||||||
|
def _create_splitter(self) -> QWidget:
|
||||||
|
container = QWidget()
|
||||||
|
container_layout = QVBoxLayout(container)
|
||||||
|
container_layout.setContentsMargins(9, 0, 9, 9)
|
||||||
|
container_layout.setSpacing(0)
|
||||||
|
|
||||||
|
splitter = QSplitter(Qt.Orientation.Vertical)
|
||||||
|
splitter.setHandleWidth(1)
|
||||||
|
splitter.setStyleSheet("QSplitter::handle { background: transparent; }")
|
||||||
|
|
||||||
|
splitter.addWidget(self._create_category_section())
|
||||||
|
splitter.addWidget(self._create_manufacturer_section())
|
||||||
|
|
||||||
|
splitter.setStretchFactor(0, 7)
|
||||||
|
splitter.setStretchFactor(1, 3)
|
||||||
|
splitter.setCollapsible(0, False) # noqa: FBT003
|
||||||
|
splitter.setCollapsible(1, False) # noqa: FBT003
|
||||||
|
|
||||||
|
self._splitter = splitter
|
||||||
|
container_layout.addWidget(splitter)
|
||||||
|
return container
|
||||||
|
|
||||||
|
def _create_category_section(self) -> QWidget:
|
||||||
|
section = QWidget()
|
||||||
|
layout = QVBoxLayout(section)
|
||||||
|
layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
layout.setSpacing(0)
|
||||||
|
|
||||||
|
header = _SectionHeader("Category", "folder")
|
||||||
|
layout.addWidget(header)
|
||||||
|
|
||||||
|
tree_container = QWidget()
|
||||||
|
tree_layout = QHBoxLayout(tree_container)
|
||||||
|
tree_layout.setContentsMargins(9, 0, 0, 0)
|
||||||
|
tree_layout.setSpacing(0)
|
||||||
|
|
||||||
|
self._category_model = CategoryTreeModel()
|
||||||
|
self._category_tree = _VimTreeView()
|
||||||
|
self._category_tree.setItemDelegate(_CategoryDelegate(self._category_tree))
|
||||||
|
self._category_tree.setModel(self._category_model)
|
||||||
|
self._category_tree.setHeaderHidden(True)
|
||||||
|
self._category_tree.setIndentation(16)
|
||||||
|
self._category_tree.setFrameShape(QFrame.Shape.NoFrame)
|
||||||
|
self._category_tree.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
|
||||||
|
self._category_tree.viewport().setAutoFillBackground(False)
|
||||||
|
self._category_tree.setStyleSheet("QTreeView::item { padding: 4px 2px; }")
|
||||||
|
self._category_tree.setSelectionMode(
|
||||||
|
QAbstractItemView.SelectionMode.ExtendedSelection
|
||||||
|
)
|
||||||
|
font = self._category_tree.font()
|
||||||
|
font.setWeight(QFont.Weight.Normal)
|
||||||
|
self._category_tree.setFont(font)
|
||||||
|
self._category_tree.clicked.connect(self._on_category_clicked)
|
||||||
|
self._category_tree.enter_pressed.connect(self.enter_pressed)
|
||||||
|
tree_layout.addWidget(self._category_tree)
|
||||||
|
|
||||||
|
layout.addWidget(tree_container, 1)
|
||||||
|
|
||||||
|
return section
|
||||||
|
|
||||||
|
def _create_manufacturer_section(self) -> QWidget:
|
||||||
|
section = QWidget()
|
||||||
|
layout = QVBoxLayout(section)
|
||||||
|
layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
layout.setSpacing(0)
|
||||||
|
|
||||||
|
header = _DraggableHeader("Manufacturer", "list.bullet")
|
||||||
|
header.dragged.connect(self._on_header_dragged)
|
||||||
|
layout.addWidget(header)
|
||||||
|
|
||||||
|
self._manufacturer_search = SearchBar()
|
||||||
|
self._manufacturer_search.setFixedHeight(28)
|
||||||
|
search_container = QWidget()
|
||||||
|
search_layout = QHBoxLayout(search_container)
|
||||||
|
search_layout.setContentsMargins(9, 4, 9, 4)
|
||||||
|
search_layout.addWidget(self._manufacturer_search)
|
||||||
|
layout.addWidget(search_container)
|
||||||
|
|
||||||
|
self._manufacturer_model = ManufacturerListModel()
|
||||||
|
self._manufacturer_proxy = ManufacturerFilterProxy()
|
||||||
|
self._manufacturer_proxy.setSourceModel(self._manufacturer_model)
|
||||||
|
self._manufacturer_list = _VimListView()
|
||||||
|
self._manufacturer_list.setModel(self._manufacturer_proxy)
|
||||||
|
self._manufacturer_list.setFrameShape(QFrame.Shape.NoFrame)
|
||||||
|
self._manufacturer_list.setAttribute(
|
||||||
|
Qt.WidgetAttribute.WA_TranslucentBackground
|
||||||
|
)
|
||||||
|
self._manufacturer_list.viewport().setAutoFillBackground(False)
|
||||||
|
self._manufacturer_list.setStyleSheet("QListView::item { padding: 4px 8px; }")
|
||||||
|
font = self._manufacturer_list.font()
|
||||||
|
font.setWeight(QFont.Weight.Normal)
|
||||||
|
self._manufacturer_list.setFont(font)
|
||||||
|
self._manufacturer_list.clicked.connect(self._on_manufacturer_clicked)
|
||||||
|
self._manufacturer_list.enter_pressed.connect(self.enter_pressed)
|
||||||
|
self._manufacturer_search.search_changed.connect(self._filter_manufacturers)
|
||||||
|
self._manufacturer_search.escape_pressed.connect(
|
||||||
|
self._on_manufacturer_search_escape
|
||||||
|
)
|
||||||
|
layout.addWidget(self._manufacturer_list, 1)
|
||||||
|
|
||||||
|
return section
|
||||||
|
|
||||||
|
def populate(self, logic: Logic) -> None:
|
||||||
|
self._category_model.build_from_plugins(logic)
|
||||||
|
self._manufacturer_model.build_from_plugins(logic)
|
||||||
|
|
||||||
|
def _clear_selections(self) -> None:
|
||||||
|
self._category_tree.clearSelection()
|
||||||
|
self._manufacturer_list.clearSelection()
|
||||||
|
self._uncategorized.set_selected(False)
|
||||||
|
|
||||||
|
def _on_show_all_clicked(self) -> None:
|
||||||
|
self._clear_selections()
|
||||||
|
self.category_selected.emit("Show All")
|
||||||
|
|
||||||
|
def _on_uncategorized_clicked(self) -> None:
|
||||||
|
self._clear_selections()
|
||||||
|
self.category_selected.emit(None)
|
||||||
|
|
||||||
|
def _on_category_clicked(self, index: QModelIndex) -> None:
|
||||||
|
full_path = index.data(Qt.ItemDataRole.UserRole)
|
||||||
|
if full_path:
|
||||||
|
self._manufacturer_list.clearSelection()
|
||||||
|
self.category_selected.emit(full_path)
|
||||||
|
|
||||||
|
def _on_manufacturer_clicked(self, index: QModelIndex) -> None:
|
||||||
|
manufacturer = index.data(Qt.ItemDataRole.DisplayRole)
|
||||||
|
if manufacturer:
|
||||||
|
self._category_tree.clearSelection()
|
||||||
|
self.manufacturer_selected.emit(manufacturer)
|
||||||
|
|
||||||
|
def _filter_manufacturers(self, text: str) -> None:
|
||||||
|
self._manufacturer_proxy.setFilterFixedString(text)
|
||||||
|
|
||||||
|
def _on_manufacturer_search_escape(self) -> None:
|
||||||
|
self._manufacturer_list.setFocus()
|
||||||
|
|
||||||
|
def is_manufacturer_mode(self) -> bool:
|
||||||
|
return (
|
||||||
|
self._manufacturer_search.hasFocus()
|
||||||
|
or self._manufacturer_list.selectionModel().hasSelection()
|
||||||
|
)
|
||||||
|
|
||||||
|
def focus_manufacturer_search(self) -> None:
|
||||||
|
self._manufacturer_search.setFocus()
|
||||||
|
self._manufacturer_search.selectAll()
|
||||||
|
|
||||||
|
def clear_manufacturer_search(self) -> None:
|
||||||
|
self._manufacturer_search.clear()
|
||||||
|
|
||||||
|
def select_show_all(self) -> None:
|
||||||
|
self._clear_selections()
|
||||||
|
self.category_selected.emit("Show All")
|
||||||
|
|
||||||
|
def select_uncategorized(self) -> None:
|
||||||
|
self._clear_selections()
|
||||||
|
self._uncategorized.set_selected(True)
|
||||||
|
self.category_selected.emit(None)
|
||||||
|
|
||||||
|
def focus_category_tree(self) -> None:
|
||||||
|
self._category_tree.setFocus()
|
||||||
|
top_level_index = self._category_model.index_for_path("Top Level")
|
||||||
|
if top_level_index.isValid():
|
||||||
|
self._category_tree.setCurrentIndex(top_level_index)
|
||||||
|
|
||||||
|
def focus_manufacturer_list(self) -> None:
|
||||||
|
self._manufacturer_list.setFocus()
|
||||||
|
if not self._manufacturer_list.selectionModel().hasSelection():
|
||||||
|
first_index = self._manufacturer_proxy.index(0, 0)
|
||||||
|
if first_index.isValid():
|
||||||
|
self._manufacturer_list.setCurrentIndex(first_index)
|
||||||
|
|
||||||
|
def _on_header_dragged(self, delta: int) -> None:
|
||||||
|
sizes = self._splitter.sizes()
|
||||||
|
min_size = 50
|
||||||
|
new_top = max(min_size, sizes[0] + delta)
|
||||||
|
new_bottom = max(min_size, sizes[1] - delta)
|
||||||
|
self._splitter.setSizes([new_top, new_bottom])
|
||||||
|
|
||||||
|
def highlight_categories(self, category_paths: list[str]) -> None:
|
||||||
|
self._category_tree.clearSelection()
|
||||||
|
self._manufacturer_list.clearSelection()
|
||||||
|
self._uncategorized.set_selected(False)
|
||||||
|
|
||||||
|
if not category_paths:
|
||||||
|
self._uncategorized.set_selected(True)
|
||||||
|
return
|
||||||
|
|
||||||
|
selection_model = self._category_tree.selectionModel()
|
||||||
|
|
||||||
|
first_index = None
|
||||||
|
for path in category_paths:
|
||||||
|
index = self._category_model.index_for_path(path)
|
||||||
|
if index.isValid():
|
||||||
|
parent = index.parent()
|
||||||
|
while parent.isValid():
|
||||||
|
self._category_tree.expand(parent)
|
||||||
|
parent = parent.parent()
|
||||||
|
selection_model.select(index, selection_model.SelectionFlag.Select)
|
||||||
|
if first_index is None:
|
||||||
|
first_index = index
|
||||||
|
|
||||||
|
if first_index is not None:
|
||||||
|
self._category_tree.scrollTo(first_index)
|
||||||
11
ty.toml
Normal file
11
ty.toml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[environment]
|
||||||
|
python = ".venv"
|
||||||
|
|
||||||
|
[rules]
|
||||||
|
invalid-method-override = "ignore"
|
||||||
|
|
||||||
|
[[overrides]]
|
||||||
|
include = ["src/illogical/modules/sf_symbols.py", "src/illogical/ui/sidebar.py"]
|
||||||
|
[overrides.rules]
|
||||||
|
unresolved-import = "ignore"
|
||||||
|
unresolved-attribute = "ignore"
|
||||||
781
uv.lock
generated
Normal file
781
uv.lock
generated
Normal file
@@ -0,0 +1,781 @@
|
|||||||
|
version = 1
|
||||||
|
revision = 3
|
||||||
|
requires-python = ">=3.13"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyio"
|
||||||
|
version = "4.12.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "idna" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arrow"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "python-dateutil" },
|
||||||
|
{ name = "tzdata" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/b9/33/032cdc44182491aa708d06a68b62434140d8c50820a087fac7af37703357/arrow-1.4.0.tar.gz", hash = "sha256:ed0cc050e98001b8779e84d461b0098c4ac597e88704a655582b21d116e526d7", size = 152931, upload-time = "2025-10-18T17:46:46.761Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl", hash = "sha256:749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205", size = 68797, upload-time = "2025-10-18T17:46:45.663Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "binaryornot"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "chardet" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/a7/fe/7ebfec74d49f97fc55cd38240c7a7d08134002b1e14be8c3897c0dd5e49b/binaryornot-0.4.4.tar.gz", hash = "sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061", size = 371054, upload-time = "2017-08-03T15:55:25.08Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/24/7e/f7b6f453e6481d1e233540262ccbfcf89adcd43606f44a028d7f5fae5eb2/binaryornot-0.4.4-py2.py3-none-any.whl", hash = "sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4", size = 9006, upload-time = "2017-08-03T15:55:31.23Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "briefcase"
|
||||||
|
version = "0.3.26"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "build" },
|
||||||
|
{ name = "cookiecutter" },
|
||||||
|
{ name = "dmgbuild", marker = "sys_platform == 'darwin'" },
|
||||||
|
{ name = "gitpython" },
|
||||||
|
{ name = "httpx" },
|
||||||
|
{ name = "packaging" },
|
||||||
|
{ name = "pip" },
|
||||||
|
{ name = "platformdirs" },
|
||||||
|
{ name = "psutil" },
|
||||||
|
{ name = "python-dateutil" },
|
||||||
|
{ name = "rich" },
|
||||||
|
{ name = "setuptools" },
|
||||||
|
{ name = "tomli-w" },
|
||||||
|
{ name = "truststore" },
|
||||||
|
{ name = "wheel" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/7a/c6/668fd69fcc982f8673d1324da034e3ef0c5f2eaa14feab25693dddccd563/briefcase-0.3.26.tar.gz", hash = "sha256:ebde1b0e899c5d1107737694f8d6070b60706c4260ce787915b72f29d6c8413d", size = 2608149, upload-time = "2025-12-04T08:06:27.348Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/03/d0/9d1199811cc088f4fb1e9faa8504e620e45e4502ac4ef5357cad369ff87f/briefcase-0.3.26-py3-none-any.whl", hash = "sha256:8c1e8b3c9006f730c9e4983d640cb0b52333c17f605d952b503cb6beae5fec38", size = 265200, upload-time = "2025-12-04T08:06:24.491Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "build"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "colorama", marker = "os_name == 'nt'" },
|
||||||
|
{ name = "packaging" },
|
||||||
|
{ name = "pyproject-hooks" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/42/18/94eaffda7b329535d91f00fe605ab1f1e5cd68b2074d03f255c7d250687d/build-1.4.0.tar.gz", hash = "sha256:f1b91b925aa322be454f8330c6fb48b465da993d1e7e7e6fa35027ec49f3c936", size = 50054, upload-time = "2026-01-08T16:41:47.696Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c5/0d/84a4380f930db0010168e0aa7b7a8fed9ba1835a8fbb1472bc6d0201d529/build-1.4.0-py3-none-any.whl", hash = "sha256:6a07c1b8eb6f2b311b96fcbdbce5dab5fe637ffda0fd83c9cac622e927501596", size = 24141, upload-time = "2026-01-08T16:41:46.453Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "certifi"
|
||||||
|
version = "2026.1.4"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chardet"
|
||||||
|
version = "5.2.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/f7b6ab21ec75897ed80c17d79b15951a719226b9fababf1e40ea74d69079/chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7", size = 2069618, upload-time = "2023-08-01T19:23:02.662Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/38/6f/f5fbc992a329ee4e0f288c1fe0e2ad9485ed064cac731ed2fe47dcc38cbf/chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970", size = 199385, upload-time = "2023-08-01T19:23:00.661Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "charset-normalizer"
|
||||||
|
version = "3.4.4"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "click"
|
||||||
|
version = "8.3.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorama"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cookiecutter"
|
||||||
|
version = "2.6.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "arrow" },
|
||||||
|
{ name = "binaryornot" },
|
||||||
|
{ name = "click" },
|
||||||
|
{ name = "jinja2" },
|
||||||
|
{ name = "python-slugify" },
|
||||||
|
{ name = "pyyaml" },
|
||||||
|
{ name = "requests" },
|
||||||
|
{ name = "rich" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/52/17/9f2cd228eb949a91915acd38d3eecdc9d8893dde353b603f0db7e9f6be55/cookiecutter-2.6.0.tar.gz", hash = "sha256:db21f8169ea4f4fdc2408d48ca44859349de2647fbe494a9d6c3edfc0542c21c", size = 158767, upload-time = "2024-02-21T18:02:41.949Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b6/d9/0137658a353168ffa9d0fc14b812d3834772040858ddd1cb6eeaf09f7a44/cookiecutter-2.6.0-py3-none-any.whl", hash = "sha256:a54a8e37995e4ed963b3e82831072d1ad4b005af736bb17b99c2cbd9d41b6e2d", size = 39177, upload-time = "2024-02-21T18:02:39.569Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dmgbuild"
|
||||||
|
version = "1.6.7"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "ds-store" },
|
||||||
|
{ name = "mac-alias" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/a7/a5/f4dbd63c96902de8f2427a82518aaeedac0006587409294e55a14e45f367/dmgbuild-1.6.7.tar.gz", hash = "sha256:676b17acd448899f6d4a83b2184e0657480444ecb6ac9c4922889efad9e5dbfb", size = 36938, upload-time = "2026-01-15T23:13:43.779Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6c/4a/8812638bba991a55a4b670806ab9cf60207077401893bb308eb1b04f288c/dmgbuild-1.6.7-py3-none-any.whl", hash = "sha256:37ee5771c377beb3203d9164aae8046ffed8531c06edf9227f5788b3c599b1bf", size = 34853, upload-time = "2026-01-15T23:13:41.854Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ds-store"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "mac-alias" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/e9/11/971e423750b219ec3f3a7f27dfb9bd74aef3d3fdfee6cc7df10a0217b5cd/ds_store-1.3.2.tar.gz", hash = "sha256:e4da49df901123481a85b9250945f2aac054a0f0c29352cd2cc858c536cdd364", size = 26574, upload-time = "2025-12-04T00:52:46.178Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/03/83/7135cae57531edc070c73ea92b9129be0714323f5face6e15f415ca8ef52/ds_store-1.3.2-py3-none-any.whl", hash = "sha256:3b37332d9f8c18ff04c385d2933b66a1d84950071364f94bfc5f5a3ab1fb361e", size = 15928, upload-time = "2025-12-04T00:52:44.528Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gitdb"
|
||||||
|
version = "4.0.12"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "smmap" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684, upload-time = "2025-01-02T07:20:46.413Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794, upload-time = "2025-01-02T07:20:43.624Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gitpython"
|
||||||
|
version = "3.1.46"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "gitdb" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/df/b5/59d16470a1f0dfe8c793f9ef56fd3826093fc52b3bd96d6b9d6c26c7e27b/gitpython-3.1.46.tar.gz", hash = "sha256:400124c7d0ef4ea03f7310ac2fbf7151e09ff97f2a3288d64a440c584a29c37f", size = 215371, upload-time = "2026-01-01T15:37:32.073Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6a/09/e21df6aef1e1ffc0c816f0522ddc3f6dcded766c3261813131c78a704470/gitpython-3.1.46-py3-none-any.whl", hash = "sha256:79812ed143d9d25b6d176a10bb511de0f9c67b1fa641d82097b0ab90398a2058", size = 208620, upload-time = "2026-01-01T15:37:30.574Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "h11"
|
||||||
|
version = "0.16.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpcore"
|
||||||
|
version = "1.0.9"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "certifi" },
|
||||||
|
{ name = "h11" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpx"
|
||||||
|
version = "0.28.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "anyio" },
|
||||||
|
{ name = "certifi" },
|
||||||
|
{ name = "httpcore" },
|
||||||
|
{ name = "idna" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "idna"
|
||||||
|
version = "3.11"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "illogical"
|
||||||
|
version = "0.0.0"
|
||||||
|
source = { editable = "." }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "briefcase" },
|
||||||
|
{ name = "logic-plugin-manager", extra = ["search"] },
|
||||||
|
{ name = "pyqt-liquidglass" },
|
||||||
|
{ name = "pyside6-essentials" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.metadata]
|
||||||
|
requires-dist = [
|
||||||
|
{ name = "briefcase", specifier = ">=0.3.25" },
|
||||||
|
{ name = "logic-plugin-manager", extras = ["search"], specifier = ">=1.0.0" },
|
||||||
|
{ name = "pyqt-liquidglass", specifier = ">=0.1.0" },
|
||||||
|
{ name = "pyside6-essentials", specifier = "~=6.8" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jinja2"
|
||||||
|
version = "3.1.6"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "markupsafe" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "logic-plugin-manager"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/36/47/0cdfe1b1e35fb30d9b0b7d1c7b8c133254364da8613131d750af1c83b885/logic_plugin_manager-1.0.0.tar.gz", hash = "sha256:b8364838897c4c3319d3ef69ddbdbaa3fc2d795815d2385dea8f2ca7f25f481f", size = 16174, upload-time = "2025-11-07T16:16:34.245Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0f/3e/df9410cfa94cf75f1196fce9797a64482823b009bdab417fb11de8ef9c70/logic_plugin_manager-1.0.0-py3-none-any.whl", hash = "sha256:b23e0e1469687d97a33de44b7feaea1e470808dff0968e5289b66e07b7dd6607", size = 23149, upload-time = "2025-11-07T16:16:33.411Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.optional-dependencies]
|
||||||
|
search = [
|
||||||
|
{ name = "rapidfuzz" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mac-alias"
|
||||||
|
version = "2.2.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/fb/c9/2c28b2ea968a6bbc4327c0360b746fda3757cb11cf287d00078cf81a27e2/mac_alias-2.2.3.tar.gz", hash = "sha256:1c7fa367687d66979f2ce4d1a8b2716cf1c9fb811741cab3cf3ca356555c2beb", size = 33860, upload-time = "2025-12-04T00:58:13.679Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/13/20/103f4e4a6e8a524ea92eee7d938c6133d0b129aa999a50f8648ad126c728/mac_alias-2.2.3-py3-none-any.whl", hash = "sha256:7362b521d2132ef92f606a37abfed5fcd849ceb2f28b6f9743e014b02af92f0d", size = 21127, upload-time = "2025-12-04T00:58:11.931Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "markdown-it-py"
|
||||||
|
version = "4.0.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "mdurl" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "markupsafe"
|
||||||
|
version = "3.0.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mdurl"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "packaging"
|
||||||
|
version = "26.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pip"
|
||||||
|
version = "25.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/fe/6e/74a3f0179a4a73a53d66ce57fdb4de0080a8baa1de0063de206d6167acc2/pip-25.3.tar.gz", hash = "sha256:8d0538dbbd7babbd207f261ed969c65de439f6bc9e5dbd3b3b9a77f25d95f343", size = 1803014, upload-time = "2025-10-25T00:55:41.394Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/44/3c/d717024885424591d5376220b5e836c2d5293ce2011523c9de23ff7bf068/pip-25.3-py3-none-any.whl", hash = "sha256:9655943313a94722b7774661c21049070f6bbb0a1516bf02f7c8d5d9201514cd", size = 1778622, upload-time = "2025-10-25T00:55:39.247Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "platformdirs"
|
||||||
|
version = "4.5.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "psutil"
|
||||||
|
version = "7.2.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/73/cb/09e5184fb5fc0358d110fc3ca7f6b1d033800734d34cac10f4136cfac10e/psutil-7.2.1.tar.gz", hash = "sha256:f7583aec590485b43ca601dd9cea0dcd65bd7bb21d30ef4ddbf4ea6b5ed1bdd3", size = 490253, upload-time = "2025-12-29T08:26:00.169Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/77/8e/f0c242053a368c2aa89584ecd1b054a18683f13d6e5a318fc9ec36582c94/psutil-7.2.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ba9f33bb525b14c3ea563b2fd521a84d2fa214ec59e3e6a2858f78d0844dd60d", size = 129624, upload-time = "2025-12-29T08:26:04.255Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/26/97/a58a4968f8990617decee234258a2b4fc7cd9e35668387646c1963e69f26/psutil-7.2.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:81442dac7abfc2f4f4385ea9e12ddf5a796721c0f6133260687fec5c3780fa49", size = 130132, upload-time = "2025-12-29T08:26:06.228Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/db/6d/ed44901e830739af5f72a85fa7ec5ff1edea7f81bfbf4875e409007149bd/psutil-7.2.1-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ea46c0d060491051d39f0d2cff4f98d5c72b288289f57a21556cc7d504db37fc", size = 180612, upload-time = "2025-12-29T08:26:08.276Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c7/65/b628f8459bca4efbfae50d4bf3feaab803de9a160b9d5f3bd9295a33f0c2/psutil-7.2.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:35630d5af80d5d0d49cfc4d64c1c13838baf6717a13effb35869a5919b854cdf", size = 183201, upload-time = "2025-12-29T08:26:10.622Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fb/23/851cadc9764edcc18f0effe7d0bf69f727d4cf2442deb4a9f78d4e4f30f2/psutil-7.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:923f8653416604e356073e6e0bccbe7c09990acef442def2f5640dd0faa9689f", size = 139081, upload-time = "2025-12-29T08:26:12.483Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/59/82/d63e8494ec5758029f31c6cb06d7d161175d8281e91d011a4a441c8a43b5/psutil-7.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:cfbe6b40ca48019a51827f20d830887b3107a74a79b01ceb8cc8de4ccb17b672", size = 134767, upload-time = "2025-12-29T08:26:14.528Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/05/c2/5fb764bd61e40e1fe756a44bd4c21827228394c17414ade348e28f83cd79/psutil-7.2.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:494c513ccc53225ae23eec7fe6e1482f1b8a44674241b54561f755a898650679", size = 129716, upload-time = "2025-12-29T08:26:16.017Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c9/d2/935039c20e06f615d9ca6ca0ab756cf8408a19d298ffaa08666bc18dc805/psutil-7.2.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3fce5f92c22b00cdefd1645aa58ab4877a01679e901555067b1bd77039aa589f", size = 130133, upload-time = "2025-12-29T08:26:18.009Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/77/69/19f1eb0e01d24c2b3eacbc2f78d3b5add8a89bf0bb69465bc8d563cc33de/psutil-7.2.1-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93f3f7b0bb07711b49626e7940d6fe52aa9940ad86e8f7e74842e73189712129", size = 181518, upload-time = "2025-12-29T08:26:20.241Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e1/6d/7e18b1b4fa13ad370787626c95887b027656ad4829c156bb6569d02f3262/psutil-7.2.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d34d2ca888208eea2b5c68186841336a7f5e0b990edec929be909353a202768a", size = 184348, upload-time = "2025-12-29T08:26:22.215Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/98/60/1672114392dd879586d60dd97896325df47d9a130ac7401318005aab28ec/psutil-7.2.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2ceae842a78d1603753561132d5ad1b2f8a7979cb0c283f5b52fb4e6e14b1a79", size = 140400, upload-time = "2025-12-29T08:26:23.993Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fb/7b/d0e9d4513c46e46897b46bcfc410d51fc65735837ea57a25170f298326e6/psutil-7.2.1-cp314-cp314t-win_arm64.whl", hash = "sha256:08a2f175e48a898c8eb8eace45ce01777f4785bc744c90aa2cc7f2fa5462a266", size = 135430, upload-time = "2025-12-29T08:26:25.999Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c5/cf/5180eb8c8bdf6a503c6919f1da28328bd1e6b3b1b5b9d5b01ae64f019616/psutil-7.2.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b2e953fcfaedcfbc952b44744f22d16575d3aa78eb4f51ae74165b4e96e55f42", size = 128137, upload-time = "2025-12-29T08:26:27.759Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c5/2c/78e4a789306a92ade5000da4f5de3255202c534acdadc3aac7b5458fadef/psutil-7.2.1-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:05cc68dbb8c174828624062e73078e7e35406f4ca2d0866c272c2410d8ef06d1", size = 128947, upload-time = "2025-12-29T08:26:29.548Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/29/f8/40e01c350ad9a2b3cb4e6adbcc8a83b17ee50dd5792102b6142385937db5/psutil-7.2.1-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e38404ca2bb30ed7267a46c02f06ff842e92da3bb8c5bfdadbd35a5722314d8", size = 154694, upload-time = "2025-12-29T08:26:32.147Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/06/e4/b751cdf839c011a9714a783f120e6a86b7494eb70044d7d81a25a5cd295f/psutil-7.2.1-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab2b98c9fc19f13f59628d94df5cc4cc4844bc572467d113a8b517d634e362c6", size = 156136, upload-time = "2025-12-29T08:26:34.079Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/44/ad/bbf6595a8134ee1e94a4487af3f132cef7fce43aef4a93b49912a48c3af7/psutil-7.2.1-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f78baafb38436d5a128f837fab2d92c276dfb48af01a240b861ae02b2413ada8", size = 148108, upload-time = "2025-12-29T08:26:36.225Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1c/15/dd6fd869753ce82ff64dcbc18356093471a5a5adf4f77ed1f805d473d859/psutil-7.2.1-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:99a4cd17a5fdd1f3d014396502daa70b5ec21bf4ffe38393e152f8e449757d67", size = 147402, upload-time = "2025-12-29T08:26:39.21Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/34/68/d9317542e3f2b180c4306e3f45d3c922d7e86d8ce39f941bb9e2e9d8599e/psutil-7.2.1-cp37-abi3-win_amd64.whl", hash = "sha256:b1b0671619343aa71c20ff9767eced0483e4fc9e1f489d50923738caf6a03c17", size = 136938, upload-time = "2025-12-29T08:26:41.036Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3e/73/2ce007f4198c80fcf2cb24c169884f833fe93fbc03d55d302627b094ee91/psutil-7.2.1-cp37-abi3-win_arm64.whl", hash = "sha256:0d67c1822c355aa6f7314d92018fb4268a76668a536f133599b91edd48759442", size = 133836, upload-time = "2025-12-29T08:26:43.086Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pygments"
|
||||||
|
version = "2.19.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyobjc-core"
|
||||||
|
version = "12.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/b8/b6/d5612eb40be4fd5ef88c259339e6313f46ba67577a95d86c3470b951fce0/pyobjc_core-12.1.tar.gz", hash = "sha256:2bb3903f5387f72422145e1466b3ac3f7f0ef2e9960afa9bcd8961c5cbf8bd21", size = 1000532, upload-time = "2025-11-14T10:08:28.292Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f4/d2/29e5e536adc07bc3d33dd09f3f7cf844bf7b4981820dc2a91dd810f3c782/pyobjc_core-12.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:01c0cf500596f03e21c23aef9b5f326b9fb1f8f118cf0d8b66749b6cf4cbb37a", size = 677370, upload-time = "2025-11-14T09:33:05.273Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1b/f0/4b4ed8924cd04e425f2a07269943018d43949afad1c348c3ed4d9d032787/pyobjc_core-12.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:177aaca84bb369a483e4961186704f64b2697708046745f8167e818d968c88fc", size = 719586, upload-time = "2025-11-14T09:33:53.302Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/25/98/9f4ed07162de69603144ff480be35cd021808faa7f730d082b92f7ebf2b5/pyobjc_core-12.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:844515f5d86395b979d02152576e7dee9cc679acc0b32dc626ef5bda315eaa43", size = 670164, upload-time = "2025-11-14T09:34:37.458Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/62/50/dc076965c96c7f0de25c0a32b7f8aa98133ed244deaeeacfc758783f1f30/pyobjc_core-12.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:453b191df1a4b80e756445b935491b974714456ae2cbae816840bd96f86db882", size = 712204, upload-time = "2025-11-14T09:35:24.148Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyobjc-framework-cocoa"
|
||||||
|
version = "12.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "pyobjc-core" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/02/a3/16ca9a15e77c061a9250afbae2eae26f2e1579eb8ca9462ae2d2c71e1169/pyobjc_framework_cocoa-12.1.tar.gz", hash = "sha256:5556c87db95711b985d5efdaaf01c917ddd41d148b1e52a0c66b1a2e2c5c1640", size = 2772191, upload-time = "2025-11-14T10:13:02.069Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ad/31/0c2e734165abb46215797bd830c4bdcb780b699854b15f2b6240515edcc6/pyobjc_framework_cocoa-12.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5a3dcd491cacc2f5a197142b3c556d8aafa3963011110102a093349017705118", size = 384689, upload-time = "2025-11-14T09:41:41.478Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/23/3b/b9f61be7b9f9b4e0a6db18b3c35c4c4d589f2d04e963e2174d38c6555a92/pyobjc_framework_cocoa-12.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:914b74328c22d8ca261d78c23ef2befc29776e0b85555973927b338c5734ca44", size = 388843, upload-time = "2025-11-14T09:42:05.719Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/59/bb/f777cc9e775fc7dae77b569254570fe46eb842516b3e4fe383ab49eab598/pyobjc_framework_cocoa-12.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:03342a60fc0015bcdf9b93ac0b4f457d3938e9ef761b28df9564c91a14f0129a", size = 384932, upload-time = "2025-11-14T09:42:29.771Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/58/27/b457b7b37089cad692c8aada90119162dfb4c4a16f513b79a8b2b022b33b/pyobjc_framework_cocoa-12.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:6ba1dc1bfa4da42d04e93d2363491275fb2e2be5c20790e561c8a9e09b8cf2cc", size = 388970, upload-time = "2025-11-14T09:42:53.964Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyobjc-framework-quartz"
|
||||||
|
version = "12.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "pyobjc-core" },
|
||||||
|
{ name = "pyobjc-framework-cocoa" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/94/18/cc59f3d4355c9456fc945eae7fe8797003c4da99212dd531ad1b0de8a0c6/pyobjc_framework_quartz-12.1.tar.gz", hash = "sha256:27f782f3513ac88ec9b6c82d9767eef95a5cf4175ce88a1e5a65875fee799608", size = 3159099, upload-time = "2025-11-14T10:21:24.31Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ba/2d/e8f495328101898c16c32ac10e7b14b08ff2c443a756a76fd1271915f097/pyobjc_framework_quartz-12.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:629b7971b1b43a11617f1460cd218bd308dfea247cd4ee3842eb40ca6f588860", size = 219206, upload-time = "2025-11-14T10:00:15.623Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/67/43/b1f0ad3b842ab150a7e6b7d97f6257eab6af241b4c7d14cb8e7fde9214b8/pyobjc_framework_quartz-12.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:53b84e880c358ba1ddcd7e8d5ea0407d760eca58b96f0d344829162cda5f37b3", size = 224317, upload-time = "2025-11-14T10:00:30.703Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4a/00/96249c5c7e5aaca5f688ca18b8d8ad05cd7886ebd639b3c71a6a4cadbe75/pyobjc_framework_quartz-12.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:42d306b07f05ae7d155984503e0fb1b701fecd31dcc5c79fe8ab9790ff7e0de0", size = 219558, upload-time = "2025-11-14T10:00:45.476Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4d/a6/708a55f3ff7a18c403b30a29a11dccfed0410485a7548c60a4b6d4cc0676/pyobjc_framework_quartz-12.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0cc08fddb339b2760df60dea1057453557588908e42bdc62184b6396ce2d6e9a", size = 224580, upload-time = "2025-11-14T10:01:00.091Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyproject-hooks"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/e7/82/28175b2414effca1cdac8dc99f76d660e7a4fb0ceefa4b4ab8f5f6742925/pyproject_hooks-1.2.0.tar.gz", hash = "sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8", size = 19228, upload-time = "2024-09-29T09:24:13.293Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl", hash = "sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913", size = 10216, upload-time = "2024-09-29T09:24:11.978Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyqt-liquidglass"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "pyobjc-framework-cocoa" },
|
||||||
|
{ name = "pyobjc-framework-quartz" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/04/91/5d12e7494138a55e807cb09f5297920ce4d84411eb3156aeb068804a75b7/pyqt_liquidglass-0.1.0.tar.gz", hash = "sha256:2b0b5f7f302b70236f653d0362910b9c94898942b8befeb80fb3822625d86fee", size = 10691, upload-time = "2026-01-19T00:41:21.265Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3e/06/7e3195c45e3cf44fee89ffd18e03e5afbc57632bacdddf7a597bac7fe59a/pyqt_liquidglass-0.1.0-py3-none-any.whl", hash = "sha256:cd41bff4df4ee9b61de454fb220a36ace2f25de804525161f5ab82dd9113ce53", size = 14551, upload-time = "2026-01-19T00:41:20.441Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyside6-essentials"
|
||||||
|
version = "6.10.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "shiboken6" },
|
||||||
|
]
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/b0/c43209fecef79912e9b1c70a1b5172b1edf76caebcc885c58c60a09613b0/pyside6_essentials-6.10.1-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:cd224aff3bb26ff1fca32c050e1c4d0bd9f951a96219d40d5f3d0128485b0bbe", size = 105461499, upload-time = "2025-11-20T09:59:23.733Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5f/8e/b69ba7fa0c701f3f4136b50460441697ec49ee6ea35c229eb2a5ee4b5952/pyside6_essentials-6.10.1-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:e9ccbfb58c03911a0bce1f2198605b02d4b5ca6276bfc0cbcf7c6f6393ffb856", size = 76764617, upload-time = "2025-11-20T09:59:38.831Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bd/83/569d27f4b6c6b9377150fe1a3745d64d02614021bea233636bc936a23423/pyside6_essentials-6.10.1-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:ec8617c9b143b0c19ba1cc5a7e98c538e4143795480cb152aee47802c18dc5d2", size = 75850373, upload-time = "2025-11-20T09:59:56.082Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1e/64/a8df6333de8ccbf3a320e1346ca30d0f314840aff5e3db9b4b66bf38e26c/pyside6_essentials-6.10.1-cp39-abi3-win_amd64.whl", hash = "sha256:9555a48e8f0acf63fc6a23c250808db841b28a66ed6ad89ee0e4df7628752674", size = 74491180, upload-time = "2025-11-20T10:00:11.215Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/67/da/65cc6c6a870d4ea908c59b2f0f9e2cf3bfc6c0710ebf278ed72f69865e4e/pyside6_essentials-6.10.1-cp39-abi3-win_arm64.whl", hash = "sha256:4d1d248644f1778f8ddae5da714ca0f5a150a5e6f602af2765a7d21b876da05c", size = 55190458, upload-time = "2025-11-20T10:00:26.226Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "python-dateutil"
|
||||||
|
version = "2.9.0.post0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "six" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "python-slugify"
|
||||||
|
version = "8.0.4"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "text-unidecode" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/87/c7/5e1547c44e31da50a460df93af11a535ace568ef89d7a811069ead340c4a/python-slugify-8.0.4.tar.gz", hash = "sha256:59202371d1d05b54a9e7720c5e038f928f45daaffe41dd10822f3907b937c856", size = 10921, upload-time = "2024-02-08T18:32:45.488Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a4/62/02da182e544a51a5c3ccf4b03ab79df279f9c60c5e82d5e8bec7ca26ac11/python_slugify-8.0.4-py2.py3-none-any.whl", hash = "sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8", size = 10051, upload-time = "2024-02-08T18:32:43.911Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyyaml"
|
||||||
|
version = "6.0.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rapidfuzz"
|
||||||
|
version = "3.14.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/d3/28/9d808fe62375b9aab5ba92fa9b29371297b067c2790b2d7cda648b1e2f8d/rapidfuzz-3.14.3.tar.gz", hash = "sha256:2491937177868bc4b1e469087601d53f925e8d270ccc21e07404b4b5814b7b5f", size = 57863900, upload-time = "2025-11-01T11:54:52.321Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e4/4f/0d94d09646853bd26978cb3a7541b6233c5760687777fa97da8de0d9a6ac/rapidfuzz-3.14.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dbcb726064b12f356bf10fffdb6db4b6dce5390b23627c08652b3f6e49aa56ae", size = 1939646, upload-time = "2025-11-01T11:53:25.292Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b6/eb/f96aefc00f3bbdbab9c0657363ea8437a207d7545ac1c3789673e05d80bd/rapidfuzz-3.14.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1704fc70d214294e554a2421b473779bcdeef715881c5e927dc0f11e1692a0ff", size = 1385512, upload-time = "2025-11-01T11:53:27.594Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/26/34/71c4f7749c12ee223dba90017a5947e8f03731a7cc9f489b662a8e9e643d/rapidfuzz-3.14.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc65e72790ddfd310c2c8912b45106e3800fefe160b0c2ef4d6b6fec4e826457", size = 1373571, upload-time = "2025-11-01T11:53:29.096Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/32/00/ec8597a64f2be301ce1ee3290d067f49f6a7afb226b67d5f15b56d772ba5/rapidfuzz-3.14.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43e38c1305cffae8472572a0584d4ffc2f130865586a81038ca3965301f7c97c", size = 3156759, upload-time = "2025-11-01T11:53:30.777Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/61/d5/b41eeb4930501cc899d5a9a7b5c9a33d85a670200d7e81658626dcc0ecc0/rapidfuzz-3.14.3-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:e195a77d06c03c98b3fc06b8a28576ba824392ce40de8c708f96ce04849a052e", size = 1222067, upload-time = "2025-11-01T11:53:32.334Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2a/7d/6d9abb4ffd1027c6ed837b425834f3bed8344472eb3a503ab55b3407c721/rapidfuzz-3.14.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1b7ef2f4b8583a744338a18f12c69693c194fb6777c0e9ada98cd4d9e8f09d10", size = 2394775, upload-time = "2025-11-01T11:53:34.24Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/15/ce/4f3ab4c401c5a55364da1ffff8cc879fc97b4e5f4fa96033827da491a973/rapidfuzz-3.14.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a2135b138bcdcb4c3742d417f215ac2d8c2b87bde15b0feede231ae95f09ec41", size = 2526123, upload-time = "2025-11-01T11:53:35.779Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c1/4b/54f804975376a328f57293bd817c12c9036171d15cf7292032e3f5820b2d/rapidfuzz-3.14.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:33a325ed0e8e1aa20c3e75f8ab057a7b248fdea7843c2a19ade0008906c14af0", size = 4262874, upload-time = "2025-11-01T11:53:37.866Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e9/b6/958db27d8a29a50ee6edd45d33debd3ce732e7209183a72f57544cd5fe22/rapidfuzz-3.14.3-cp313-cp313-win32.whl", hash = "sha256:8383b6d0d92f6cd008f3c9216535be215a064b2cc890398a678b56e6d280cb63", size = 1707972, upload-time = "2025-11-01T11:53:39.442Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/07/75/fde1f334b0cec15b5946d9f84d73250fbfcc73c236b4bc1b25129d90876b/rapidfuzz-3.14.3-cp313-cp313-win_amd64.whl", hash = "sha256:e6b5e3036976f0fde888687d91be86d81f9ac5f7b02e218913c38285b756be6c", size = 1537011, upload-time = "2025-11-01T11:53:40.92Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2e/d7/d83fe001ce599dc7ead57ba1debf923dc961b6bdce522b741e6b8c82f55c/rapidfuzz-3.14.3-cp313-cp313-win_arm64.whl", hash = "sha256:7ba009977601d8b0828bfac9a110b195b3e4e79b350dcfa48c11269a9f1918a0", size = 810744, upload-time = "2025-11-01T11:53:42.723Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/92/13/a486369e63ff3c1a58444d16b15c5feb943edd0e6c28a1d7d67cb8946b8f/rapidfuzz-3.14.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a0a28add871425c2fe94358c6300bbeb0bc2ed828ca003420ac6825408f5a424", size = 1967702, upload-time = "2025-11-01T11:53:44.554Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f1/82/efad25e260b7810f01d6b69122685e355bed78c94a12784bac4e0beb2afb/rapidfuzz-3.14.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:010e12e2411a4854b0434f920e72b717c43f8ec48d57e7affe5c42ecfa05dd0e", size = 1410702, upload-time = "2025-11-01T11:53:46.066Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ba/1a/34c977b860cde91082eae4a97ae503f43e0d84d4af301d857679b66f9869/rapidfuzz-3.14.3-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cfc3d57abd83c734d1714ec39c88a34dd69c85474918ebc21296f1e61eb5ca8", size = 1382337, upload-time = "2025-11-01T11:53:47.62Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/88/74/f50ea0e24a5880a9159e8fd256b84d8f4634c2f6b4f98028bdd31891d907/rapidfuzz-3.14.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:89acb8cbb52904f763e5ac238083b9fc193bed8d1f03c80568b20e4cef43a519", size = 3165563, upload-time = "2025-11-01T11:53:49.216Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e8/7a/e744359404d7737049c26099423fc54bcbf303de5d870d07d2fb1410f567/rapidfuzz-3.14.3-cp313-cp313t-manylinux_2_31_armv7l.whl", hash = "sha256:7d9af908c2f371bfb9c985bd134e295038e3031e666e4b2ade1e7cb7f5af2f1a", size = 1214727, upload-time = "2025-11-01T11:53:50.883Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d3/2e/87adfe14ce75768ec6c2b8acd0e05e85e84be4be5e3d283cdae360afc4fe/rapidfuzz-3.14.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:1f1925619627f8798f8c3a391d81071336942e5fe8467bc3c567f982e7ce2897", size = 2403349, upload-time = "2025-11-01T11:53:52.322Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/70/17/6c0b2b2bff9c8b12e12624c07aa22e922b0c72a490f180fa9183d1ef2c75/rapidfuzz-3.14.3-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:152555187360978119e98ce3e8263d70dd0c40c7541193fc302e9b7125cf8f58", size = 2507596, upload-time = "2025-11-01T11:53:53.835Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c3/d1/87852a7cbe4da7b962174c749a47433881a63a817d04f3e385ea9babcd9e/rapidfuzz-3.14.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:52619d25a09546b8db078981ca88939d72caa6b8701edd8b22e16482a38e799f", size = 4273595, upload-time = "2025-11-01T11:53:55.961Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c1/ab/1d0354b7d1771a28fa7fe089bc23acec2bdd3756efa2419f463e3ed80e16/rapidfuzz-3.14.3-cp313-cp313t-win32.whl", hash = "sha256:489ce98a895c98cad284f0a47960c3e264c724cb4cfd47a1430fa091c0c25204", size = 1757773, upload-time = "2025-11-01T11:53:57.628Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0b/0c/71ef356adc29e2bdf74cd284317b34a16b80258fa0e7e242dd92cc1e6d10/rapidfuzz-3.14.3-cp313-cp313t-win_amd64.whl", hash = "sha256:656e52b054d5b5c2524169240e50cfa080b04b1c613c5f90a2465e84888d6f15", size = 1576797, upload-time = "2025-11-01T11:53:59.455Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fe/d2/0e64fc27bb08d4304aa3d11154eb5480bcf5d62d60140a7ee984dc07468a/rapidfuzz-3.14.3-cp313-cp313t-win_arm64.whl", hash = "sha256:c7e40c0a0af02ad6e57e89f62bef8604f55a04ecae90b0ceeda591bbf5923317", size = 829940, upload-time = "2025-11-01T11:54:01.1Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/32/6f/1b88aaeade83abc5418788f9e6b01efefcd1a69d65ded37d89cd1662be41/rapidfuzz-3.14.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:442125473b247227d3f2de807a11da6c08ccf536572d1be943f8e262bae7e4ea", size = 1942086, upload-time = "2025-11-01T11:54:02.592Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a0/2c/b23861347436cb10f46c2bd425489ec462790faaa360a54a7ede5f78de88/rapidfuzz-3.14.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1ec0c8c0c3d4f97ced46b2e191e883f8c82dbbf6d5ebc1842366d7eff13cd5a6", size = 1386993, upload-time = "2025-11-01T11:54:04.12Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/83/86/5d72e2c060aa1fbdc1f7362d938f6b237dff91f5b9fc5dd7cc297e112250/rapidfuzz-3.14.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2dc37bc20272f388b8c3a4eba4febc6e77e50a8f450c472def4751e7678f55e4", size = 1379126, upload-time = "2025-11-01T11:54:05.777Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c9/bc/ef2cee3e4d8b3fc22705ff519f0d487eecc756abdc7c25d53686689d6cf2/rapidfuzz-3.14.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dee362e7e79bae940a5e2b3f6d09c6554db6a4e301cc68343886c08be99844f1", size = 3159304, upload-time = "2025-11-01T11:54:07.351Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a0/36/dc5f2f62bbc7bc90be1f75eeaf49ed9502094bb19290dfb4747317b17f12/rapidfuzz-3.14.3-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:4b39921df948388a863f0e267edf2c36302983459b021ab928d4b801cbe6a421", size = 1218207, upload-time = "2025-11-01T11:54:09.641Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/df/7e/8f4be75c1bc62f47edf2bbbe2370ee482fae655ebcc4718ac3827ead3904/rapidfuzz-3.14.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:beda6aa9bc44d1d81242e7b291b446be352d3451f8217fcb068fc2933927d53b", size = 2401245, upload-time = "2025-11-01T11:54:11.543Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/05/38/f7c92759e1bb188dd05b80d11c630ba59b8d7856657baf454ff56059c2ab/rapidfuzz-3.14.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:6a014ba09657abfcfeed64b7d09407acb29af436d7fc075b23a298a7e4a6b41c", size = 2518308, upload-time = "2025-11-01T11:54:13.134Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c7/ac/85820f70fed5ecb5f1d9a55f1e1e2090ef62985ef41db289b5ac5ec56e28/rapidfuzz-3.14.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:32eeafa3abce138bb725550c0e228fc7eaeec7059aa8093d9cbbec2b58c2371a", size = 4265011, upload-time = "2025-11-01T11:54:15.087Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/46/a9/616930721ea9835c918af7cde22bff17f9db3639b0c1a7f96684be7f5630/rapidfuzz-3.14.3-cp314-cp314-win32.whl", hash = "sha256:adb44d996fc610c7da8c5048775b21db60dd63b1548f078e95858c05c86876a3", size = 1742245, upload-time = "2025-11-01T11:54:17.19Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/06/8a/f2fa5e9635b1ccafda4accf0e38246003f69982d7c81f2faa150014525a4/rapidfuzz-3.14.3-cp314-cp314-win_amd64.whl", hash = "sha256:f3d15d8527e2b293e38ce6e437631af0708df29eafd7c9fc48210854c94472f9", size = 1584856, upload-time = "2025-11-01T11:54:18.764Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ef/97/09e20663917678a6d60d8e0e29796db175b1165e2079830430342d5298be/rapidfuzz-3.14.3-cp314-cp314-win_arm64.whl", hash = "sha256:576e4b9012a67e0bf54fccb69a7b6c94d4e86a9540a62f1a5144977359133583", size = 833490, upload-time = "2025-11-01T11:54:20.753Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/03/1b/6b6084576ba87bf21877c77218a0c97ba98cb285b0c02eaaee3acd7c4513/rapidfuzz-3.14.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:cec3c0da88562727dd5a5a364bd9efeb535400ff0bfb1443156dd139a1dd7b50", size = 1968658, upload-time = "2025-11-01T11:54:22.25Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/38/c0/fb02a0db80d95704b0a6469cc394e8c38501abf7e1c0b2afe3261d1510c2/rapidfuzz-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d1fa009f8b1100e4880868137e7bf0501422898f7674f2adcd85d5a67f041296", size = 1410742, upload-time = "2025-11-01T11:54:23.863Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a4/72/3fbf12819fc6afc8ec75a45204013b40979d068971e535a7f3512b05e765/rapidfuzz-3.14.3-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b86daa7419b5e8b180690efd1fdbac43ff19230803282521c5b5a9c83977655", size = 1382810, upload-time = "2025-11-01T11:54:25.571Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0f/18/0f1991d59bb7eee28922a00f79d83eafa8c7bfb4e8edebf4af2a160e7196/rapidfuzz-3.14.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c7bd1816db05d6c5ffb3a4df0a2b7b56fb8c81ef584d08e37058afa217da91b1", size = 3166349, upload-time = "2025-11-01T11:54:27.195Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0d/f0/baa958b1989c8f88c78bbb329e969440cf330b5a01a982669986495bb980/rapidfuzz-3.14.3-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:33da4bbaf44e9755b0ce192597f3bde7372fe2e381ab305f41b707a95ac57aa7", size = 1214994, upload-time = "2025-11-01T11:54:28.821Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e4/a0/cd12ec71f9b2519a3954febc5740291cceabc64c87bc6433afcb36259f3b/rapidfuzz-3.14.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3fecce764cf5a991ee2195a844196da840aba72029b2612f95ac68a8b74946bf", size = 2403919, upload-time = "2025-11-01T11:54:30.393Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0b/ce/019bd2176c1644098eced4f0595cb4b3ef52e4941ac9a5854f209d0a6e16/rapidfuzz-3.14.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:ecd7453e02cf072258c3a6b8e930230d789d5d46cc849503729f9ce475d0e785", size = 2508346, upload-time = "2025-11-01T11:54:32.048Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/23/f8/be16c68e2c9e6c4f23e8f4adbb7bccc9483200087ed28ff76c5312da9b14/rapidfuzz-3.14.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ea188aa00e9bcae8c8411f006a5f2f06c4607a02f24eab0d8dc58566aa911f35", size = 4274105, upload-time = "2025-11-01T11:54:33.701Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a1/d1/5ab148e03f7e6ec8cd220ccf7af74d3aaa4de26dd96df58936beb7cba820/rapidfuzz-3.14.3-cp314-cp314t-win32.whl", hash = "sha256:7ccbf68100c170e9a0581accbe9291850936711548c6688ce3bfb897b8c589ad", size = 1793465, upload-time = "2025-11-01T11:54:35.331Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cd/97/433b2d98e97abd9fff1c470a109b311669f44cdec8d0d5aa250aceaed1fb/rapidfuzz-3.14.3-cp314-cp314t-win_amd64.whl", hash = "sha256:9ec02e62ae765a318d6de38df609c57fc6dacc65c0ed1fd489036834fd8a620c", size = 1623491, upload-time = "2025-11-01T11:54:38.085Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e2/f6/e2176eb94f94892441bce3ddc514c179facb65db245e7ce3356965595b19/rapidfuzz-3.14.3-cp314-cp314t-win_arm64.whl", hash = "sha256:e805e52322ae29aa945baf7168b6c898120fbc16d2b8f940b658a5e9e3999253", size = 851487, upload-time = "2025-11-01T11:54:40.176Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "requests"
|
||||||
|
version = "2.32.5"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "certifi" },
|
||||||
|
{ name = "charset-normalizer" },
|
||||||
|
{ name = "idna" },
|
||||||
|
{ name = "urllib3" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rich"
|
||||||
|
version = "14.3.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "markdown-it-py" },
|
||||||
|
{ name = "pygments" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/a1/84/4831f881aa6ff3c976f6d6809b58cdfa350593ffc0dc3c58f5f6586780fb/rich-14.3.1.tar.gz", hash = "sha256:b8c5f568a3a749f9290ec6bddedf835cec33696bfc1e48bcfecb276c7386e4b8", size = 230125, upload-time = "2026-01-24T21:40:44.847Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/87/2a/a1810c8627b9ec8c57ec5ec325d306701ae7be50235e8fd81266e002a3cc/rich-14.3.1-py3-none-any.whl", hash = "sha256:da750b1aebbff0b372557426fb3f35ba56de8ef954b3190315eb64076d6fb54e", size = 309952, upload-time = "2026-01-24T21:40:42.969Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "setuptools"
|
||||||
|
version = "80.10.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/86/ff/f75651350db3cf2ef767371307eb163f3cc1ac03e16fdf3ac347607f7edb/setuptools-80.10.1.tar.gz", hash = "sha256:bf2e513eb8144c3298a3bd28ab1a5edb739131ec5c22e045ff93cd7f5319703a", size = 1229650, upload-time = "2026-01-21T09:42:03.061Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e0/76/f963c61683a39084aa575f98089253e1e852a4417cb8a3a8a422923a5246/setuptools-80.10.1-py3-none-any.whl", hash = "sha256:fc30c51cbcb8199a219c12cc9c281b5925a4978d212f84229c909636d9f6984e", size = 1099859, upload-time = "2026-01-21T09:42:00.688Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shiboken6"
|
||||||
|
version = "6.10.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6f/8b/e5db743d505ceea3efc4cd9634a3bee22a3e2bf6e07cefd28c9b9edabcc6/shiboken6-6.10.1-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:9f2990f5b61b0b68ecadcd896ab4441f2cb097eef7797ecc40584107d9850d71", size = 478483, upload-time = "2025-11-20T10:08:52.411Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/56/ba/b50c1a44b3c4643f482afbf1a0ea58f393827307100389ce29404f9ad3b0/shiboken6-6.10.1-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:f4221a52dfb81f24a0d20cc4f8981cb6edd810d5a9fb28287ce10d342573a0e4", size = 271993, upload-time = "2025-11-20T10:08:54.093Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/16/b8/939c24ebd662b0aa5c945443d0973145b3fb7079f0196274ef7bb4b98f73/shiboken6-6.10.1-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:c095b00f4d6bf578c0b2464bb4e264b351a99345374478570f69e2e679a2a1d0", size = 268691, upload-time = "2025-11-20T10:08:55.639Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cf/a6/8c65ee0fa5e172ebcca03246b1bc3bd96cdaf1d60537316648536b7072a5/shiboken6-6.10.1-cp39-abi3-win_amd64.whl", hash = "sha256:c1601d3cda1fa32779b141663873741b54e797cb0328458d7466281f117b0a4e", size = 1234704, upload-time = "2025-11-20T10:08:57.417Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7b/6a/c0fea2f2ac7d9d96618c98156500683a4d1f93fea0e8c5a2bc39913d7ef1/shiboken6-6.10.1-cp39-abi3-win_arm64.whl", hash = "sha256:5cf800917008587b551005a45add2d485cca66f5f7ecd5b320e9954e40448cc9", size = 1795567, upload-time = "2025-11-20T10:08:59.184Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "six"
|
||||||
|
version = "1.17.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smmap"
|
||||||
|
version = "5.0.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/44/cd/a040c4b3119bbe532e5b0732286f805445375489fceaec1f48306068ee3b/smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5", size = 22329, upload-time = "2025-01-02T07:14:40.909Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303, upload-time = "2025-01-02T07:14:38.724Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "text-unidecode"
|
||||||
|
version = "1.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/ab/e2/e9a00f0ccb71718418230718b3d900e71a5d16e701a3dae079a21e9cd8f8/text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93", size = 76885, upload-time = "2019-08-30T21:36:45.405Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a6/a5/c0b6468d3824fe3fde30dbb5e1f687b291608f9473681bbf7dabbf5a87d7/text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8", size = 78154, upload-time = "2019-08-30T21:37:03.543Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tomli-w"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/19/75/241269d1da26b624c0d5e110e8149093c759b7a286138f4efd61a60e75fe/tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021", size = 7184, upload-time = "2025-01-15T12:07:24.262Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", size = 6675, upload-time = "2025-01-15T12:07:22.074Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "truststore"
|
||||||
|
version = "0.10.4"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/53/a3/1585216310e344e8102c22482f6060c7a6ea0322b63e026372e6dcefcfd6/truststore-0.10.4.tar.gz", hash = "sha256:9d91bd436463ad5e4ee4aba766628dd6cd7010cf3e2461756b3303710eebc301", size = 26169, upload-time = "2025-08-12T18:49:02.73Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl", hash = "sha256:adaeaecf1cbb5f4de3b1959b42d41f6fab57b2b1666adb59e89cb0b53361d981", size = 18660, upload-time = "2025-08-12T18:49:01.46Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tzdata"
|
||||||
|
version = "2025.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "urllib3"
|
||||||
|
version = "2.6.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wheel"
|
||||||
|
version = "0.46.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "packaging" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/89/24/a2eb353a6edac9a0303977c4cb048134959dd2a51b48a269dfc9dde00c8a/wheel-0.46.3.tar.gz", hash = "sha256:e3e79874b07d776c40bd6033f8ddf76a7dad46a7b8aa1b2787a83083519a1803", size = 60605, upload-time = "2026-01-22T12:39:49.136Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/87/22/b76d483683216dde3d67cba61fb2444be8d5be289bf628c13fc0fd90e5f9/wheel-0.46.3-py3-none-any.whl", hash = "sha256:4b399d56c9d9338230118d705d9737a2a468ccca63d5e813e2a4fc7815d8bc4d", size = 30557, upload-time = "2026-01-22T12:39:48.099Z" },
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user