Compare commits
1 Commits
fix-issues
...
feat-email
| Author | SHA1 | Date | |
|---|---|---|---|
|
7b43826ef5
|
29
README.md
29
README.md
@@ -373,31 +373,26 @@ CREATE TABLE IF NOT EXISTS user_preferences (
|
||||
2. Convert: `pyside6-uic dialog.ui -o dialog_ui.py`
|
||||
3. Create dialog class in `src/ui/dialogs/`
|
||||
4. Connect signals to business logic
|
||||
### Building Documentation
|
||||
|
||||
## 📚 Documentation
|
||||
```bash
|
||||
# Using uv
|
||||
uv run mkdocs build
|
||||
uv run mkdocs serve # View at http://localhost:8000
|
||||
|
||||
- **[User Manual](docs/)**: Complete user guide built with Zola and the Tanuki theme
|
||||
- View documentation at `http://localhost:8000` when running the application
|
||||
# Or with activated venv
|
||||
mkdocs build
|
||||
mkdocs serve
|
||||
```*[API Documentation](docs/)**: Detailed module documentation
|
||||
- **[User Manual](docs/index.md)**: Complete user guide (MkDocs)
|
||||
|
||||
### Building Documentation
|
||||
|
||||
The documentation is built using [Zola](https://www.getzola.org/) with the Tanuki theme.
|
||||
|
||||
```bash
|
||||
# Build documentation using the provided script
|
||||
.\build_docs.ps1
|
||||
|
||||
# Or manually:
|
||||
cd docs
|
||||
zola build
|
||||
|
||||
# Serve documentation locally for development
|
||||
cd docs
|
||||
zola serve # View at http://127.0.0.1:1111
|
||||
mkdocs build
|
||||
mkdocs serve # View at http://localhost:8000
|
||||
```
|
||||
|
||||
The built documentation is served automatically when you run the application and access the documentation menu.
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
Contributions are welcome! Please follow these guidelines:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from typing import Optional, Any, Union
|
||||
from dataclasses import dataclass
|
||||
from omegaconf import OmegaConf, DictConfig, ListConfig
|
||||
from omegaconf import OmegaConf, DictConfig
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
@@ -140,7 +140,7 @@ class Config:
|
||||
|
||||
"""
|
||||
|
||||
_config: Optional[Union[DictConfig, ListConfig]] = None
|
||||
_config: Optional[DictConfig] = None
|
||||
config_exists: bool = True
|
||||
|
||||
def __init__(self, config_path: str):
|
||||
@@ -183,25 +183,22 @@ class Config:
|
||||
"""
|
||||
Reloads the configuration from the file.
|
||||
"""
|
||||
if self.config_path is not None:
|
||||
self._config = OmegaConf.load(self.config_path)
|
||||
|
||||
@property
|
||||
def zotero(self):
|
||||
if self._config is None:
|
||||
raise RuntimeError("Configuration not loaded")
|
||||
return Zotero(**self._config.zotero)
|
||||
|
||||
def get_zotero_attr(self, name: str):
|
||||
@property
|
||||
def zotero_attr(self, name: str):
|
||||
return getattr(self.zotero, name)
|
||||
|
||||
def set_zotero_attr(self, name: str, value: Any):
|
||||
@zotero_attr.setter
|
||||
def zotero_attr(self, name: str, value: Any):
|
||||
self.zotero._setattr(name, value)
|
||||
|
||||
@property
|
||||
def database(self):
|
||||
if self._config is None:
|
||||
raise RuntimeError("Configuration not loaded")
|
||||
return Database(**self._config.database)
|
||||
|
||||
@property
|
||||
@@ -214,48 +211,36 @@ class Config:
|
||||
|
||||
@property
|
||||
def openAI(self):
|
||||
if self._config is None:
|
||||
raise RuntimeError("Configuration not loaded")
|
||||
return OpenAI(**self._config.openAI)
|
||||
|
||||
@property
|
||||
def mail(self):
|
||||
if self._config is None:
|
||||
raise RuntimeError("Configuration not loaded")
|
||||
return Mail(**self._config.mail)
|
||||
|
||||
def mail_attr(self, name: str):
|
||||
return getattr(self.mail, name)
|
||||
|
||||
def set_mail_attr(self, name: str, value: Any):
|
||||
if self._config is not None:
|
||||
OmegaConf.update(self._config, f"mail.{name}", value)
|
||||
|
||||
def set_database_attr(self, name: str, value: Any):
|
||||
if self._config is not None:
|
||||
OmegaConf.update(self._config, f"database.{name}", value)
|
||||
|
||||
def set_zotero_attr(self, name: str, value: Any):
|
||||
if self._config is not None:
|
||||
OmegaConf.update(self._config, f"zotero.{name}", value)
|
||||
|
||||
def set_openai_attr(self, name: str, value: Any):
|
||||
if self._config is not None:
|
||||
OmegaConf.update(self._config, f"openAI.{name}", value)
|
||||
|
||||
def set_icon_attr(self, name: str, value: Any):
|
||||
if self._config is not None:
|
||||
OmegaConf.update(self._config, f"icons.{name}", value)
|
||||
|
||||
@property
|
||||
def save_path(self):
|
||||
if self._config is None:
|
||||
raise RuntimeError("Configuration not loaded")
|
||||
return self._config.save_path
|
||||
|
||||
@save_path.setter
|
||||
def save_path(self, value: str):
|
||||
if self._config is not None:
|
||||
self._config.save_path = value
|
||||
|
||||
def load_config(self, path, filename):
|
||||
@@ -263,8 +248,6 @@ class Config:
|
||||
|
||||
@property
|
||||
def icons(self):
|
||||
if self._config is None:
|
||||
raise RuntimeError("Configuration not loaded")
|
||||
icons = Icons()
|
||||
icons.assign("path", self._config.icon_path)
|
||||
icons.assign("colors", self._config.colors)
|
||||
|
||||
1
docs/themes/tanuki
vendored
Submodule
1
docs/themes/tanuki
vendored
Submodule
Submodule docs/themes/tanuki added at f81db54c4e
@@ -41,14 +41,34 @@ dev = [
|
||||
"pytest",
|
||||
"pytest-cov",
|
||||
"pyinstaller>=6.17.0",
|
||||
"ty>=0.0.15",
|
||||
]
|
||||
swbtest = ["alive-progress>=3.3.0"]
|
||||
|
||||
[tool.ruff]
|
||||
line-length = 88
|
||||
target-version = "py313"
|
||||
|
||||
[tool.bumpversion]
|
||||
current_version = "1.0.2"
|
||||
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
|
||||
serialize = ["{major}.{minor}.{patch}"]
|
||||
search = "{current_version}"
|
||||
replace = "{new_version}"
|
||||
regex = false
|
||||
ignore_missing_version = false
|
||||
ignore_missing_files = false
|
||||
tag = true
|
||||
sign_tags = false
|
||||
tag_name = "v{new_version}"
|
||||
tag_message = "Bump version: {current_version} → {new_version}"
|
||||
allow_dirty = true
|
||||
commit = true
|
||||
message = "Bump version: {current_version} → {new_version}"
|
||||
moveable_tags = []
|
||||
commit_args = ""
|
||||
setup_hooks = []
|
||||
pre_commit_hooks = []
|
||||
post_commit_hooks = []
|
||||
[[tool.bumpversion.files]]
|
||||
filename = "src/__init__.py"
|
||||
[[tool.bumpversion.files]]
|
||||
filename = ".version"
|
||||
|
||||
[[tool.uv.index]]
|
||||
name = "gitea"
|
||||
|
||||
@@ -33,8 +33,6 @@ if not _user_log_dir:
|
||||
if not _user_config_dir:
|
||||
_user_config_dir = str(get_app_base_path() / "config")
|
||||
|
||||
from config import Config # noqa: E402
|
||||
|
||||
LOG_DIR: str = _user_log_dir
|
||||
CONFIG_DIR: str = _user_config_dir
|
||||
|
||||
@@ -51,6 +49,8 @@ except Exception:
|
||||
Path(LOG_DIR).mkdir(parents=True, exist_ok=True)
|
||||
Path(CONFIG_DIR).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
from config import Config
|
||||
|
||||
|
||||
settings = Config(f"{CONFIG_DIR}/config.yaml")
|
||||
DATABASE_DIR: Union[Path, str] = ( # type: ignore
|
||||
|
||||
@@ -1216,9 +1216,9 @@ class Database:
|
||||
Optional[int]: the id of the apparat
|
||||
|
||||
"""
|
||||
log.debug("Creating apparat: {} - {}", app.appnr, app.name)
|
||||
app = apparat.apparat
|
||||
prof = apparat.prof
|
||||
log.debug("Creating apparat: {} - {}", app.appnr, app.name)
|
||||
present_prof = self.getProfByName(prof.name())
|
||||
prof_id = present_prof.id
|
||||
log.debug("Present prof: {}", preview(present_prof, 300))
|
||||
|
||||
@@ -24,5 +24,5 @@ class DocumentationThread(QThread):
|
||||
self._process.terminate() # terminate the subprocess
|
||||
try:
|
||||
self._process.wait(timeout=5) # wait up to 5 seconds
|
||||
except Exception:
|
||||
except:
|
||||
self._process.kill() # force kill if it doesn't stop
|
||||
|
||||
@@ -12,7 +12,7 @@ from .models import (
|
||||
Subjects,
|
||||
XMLMailSubmission,
|
||||
)
|
||||
from .constants import * # noqa: F403
|
||||
from .constants import *
|
||||
from .semester import Semester
|
||||
|
||||
__all__ = [
|
||||
|
||||
@@ -21,7 +21,7 @@ class Prof:
|
||||
telnr: str | None = None
|
||||
|
||||
# add function that sets the data based on a dict
|
||||
def from_dict(self, data: dict[str, Union[str, int]]) -> 'Prof':
|
||||
def from_dict(self, data: dict[str, Union[str, int]]):
|
||||
for key, value in data.items():
|
||||
if hasattr(self, key):
|
||||
setattr(self, key, value)
|
||||
@@ -38,40 +38,27 @@ class Prof:
|
||||
self._title = value
|
||||
|
||||
# add function that sets the data from a tuple
|
||||
def from_tuple(self, data: tuple[Union[int, str, None], ...]) -> 'Prof':
|
||||
self.id = data[0] if data[0] is not None and isinstance(data[0], int) else None
|
||||
self._title = str(data[1]) if data[1] is not None else None
|
||||
self.firstname = str(data[2]) if data[2] is not None else None
|
||||
self.lastname = str(data[3]) if data[3] is not None else None
|
||||
self.fullname = str(data[4]) if data[4] is not None else None
|
||||
self.mail = str(data[5]) if data[5] is not None else None
|
||||
self.telnr = str(data[6]) if data[6] is not None else None
|
||||
def from_tuple(self, data: tuple[Union[str, int], ...]) -> Prof:
|
||||
self.id = data[0]
|
||||
self._title = data[1]
|
||||
self.firstname = data[2]
|
||||
self.lastname = data[3]
|
||||
self.fullname = data[4]
|
||||
self.mail = data[5]
|
||||
self.telnr = data[6]
|
||||
return self
|
||||
|
||||
def name(self, comma: bool = False) -> Optional[str]:
|
||||
if self.firstname is None and self.lastname is None:
|
||||
if self.fullname and "," in self.fullname:
|
||||
parts = self.fullname.split(",")
|
||||
if len(parts) >= 2:
|
||||
self.firstname = parts[1].strip()
|
||||
self.lastname = parts[0].strip()
|
||||
if "," in self.fullname:
|
||||
self.firstname = self.fullname.split(",")[1].strip()
|
||||
self.lastname = self.fullname.split(",")[0].strip()
|
||||
else:
|
||||
return self.fullname
|
||||
|
||||
if comma:
|
||||
if self.lastname and self.firstname:
|
||||
return f"{self.lastname}, {self.firstname}"
|
||||
elif self.lastname:
|
||||
return self.lastname
|
||||
elif self.firstname:
|
||||
return f", {self.firstname}"
|
||||
elif self.lastname and self.firstname:
|
||||
return f"{self.lastname} {self.firstname}"
|
||||
elif self.lastname:
|
||||
return self.lastname
|
||||
elif self.firstname:
|
||||
return self.firstname
|
||||
return self.fullname
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -103,12 +90,10 @@ class BookData:
|
||||
if isinstance(self.language, list) and self.language:
|
||||
self.language = [lang.strip() for lang in self.language if lang.strip()]
|
||||
self.language = ",".join(self.language)
|
||||
if self.year is not None:
|
||||
year_str = regex.sub(r"[^\d]", "", str(self.year))
|
||||
self.year = int(year_str) if year_str else None
|
||||
self.year = regex.sub(r"[^\d]", "", str(self.year)) if self.year else None
|
||||
self.in_library = True if self.signature else False
|
||||
|
||||
def from_dict(self, data: dict[str, Any]) -> 'BookData':
|
||||
def from_dict(self, data: dict) -> BookData:
|
||||
for key, value in data.items():
|
||||
setattr(self, key, value)
|
||||
return self
|
||||
@@ -147,26 +132,23 @@ class BookData:
|
||||
del data_dict["old_book"]
|
||||
return json.dumps(data_dict, ensure_ascii=False)
|
||||
|
||||
def from_dataclass(self, data_obj: Optional[Any]) -> None:
|
||||
if data_obj is None:
|
||||
def from_dataclass(self, dataclass: Optional[Any]) -> None:
|
||||
if dataclass is None:
|
||||
return
|
||||
for key, value in data_obj.__dict__.items():
|
||||
for key, value in dataclass.__dict__.items():
|
||||
setattr(self, key, value)
|
||||
|
||||
def get_book_type(self) -> str:
|
||||
if self.pages and "Online" in self.pages:
|
||||
if "Online" in self.pages:
|
||||
return "eBook"
|
||||
return "Druckausgabe"
|
||||
|
||||
def from_string(self, data: str) -> 'BookData':
|
||||
def from_string(self, data: str) -> BookData:
|
||||
ndata = json.loads(data)
|
||||
# Create a new BookData instance and set its attributes
|
||||
book_data = BookData()
|
||||
for key, value in ndata.items():
|
||||
setattr(book_data, key, value)
|
||||
return book_data
|
||||
|
||||
def from_LehmannsSearchResult(self, result: Any) -> 'BookData':
|
||||
return BookData(**ndata)
|
||||
|
||||
def from_LehmannsSearchResult(self, result: Any) -> BookData:
|
||||
self.title = result.title
|
||||
self.author = "; ".join(result.authors) if result.authors else None
|
||||
self.edition = str(result.edition) if result.edition else None
|
||||
@@ -188,11 +170,23 @@ class BookData:
|
||||
def edition_number(self) -> Optional[int]:
|
||||
if self.edition is None:
|
||||
return 0
|
||||
match = regex.search(r"(\d+)", self.edition or "")
|
||||
match = regex.search(r"(\d+)", self.edition)
|
||||
if match:
|
||||
return int(match.group(1))
|
||||
return 0
|
||||
|
||||
def to_book(self) -> Book:
|
||||
return Book(
|
||||
author=self.author,
|
||||
year=self.year,
|
||||
edition=self.edition,
|
||||
title=self.title,
|
||||
location=self.place,
|
||||
publisher=self.publisher,
|
||||
signature=self.signature,
|
||||
internal_notes=None,
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class MailData:
|
||||
@@ -233,13 +227,13 @@ class Subjects(Enum):
|
||||
return self.value[0]
|
||||
|
||||
@property
|
||||
def subject_name(self) -> str:
|
||||
def name(self) -> str:
|
||||
return self.value[1]
|
||||
|
||||
@classmethod
|
||||
def get_index(cls, name: str) -> Optional[int]:
|
||||
for i in cls:
|
||||
if i.subject_name == name:
|
||||
if i.name == name:
|
||||
return i.id - 1
|
||||
return None
|
||||
|
||||
@@ -308,15 +302,18 @@ class ApparatData:
|
||||
|
||||
@dataclass
|
||||
class XMLMailSubmission:
|
||||
name: str | None
|
||||
lastname: str | None
|
||||
title: str | None
|
||||
telno: int | None
|
||||
email: str | None
|
||||
app_name: str | None
|
||||
subject: str | None
|
||||
semester: Semester | None
|
||||
books: list[BookData] | None
|
||||
name: str | None = None
|
||||
lastname: str | None = None
|
||||
title: str | None = None
|
||||
telno: int | None = None
|
||||
email: str | None = None
|
||||
app_name: str | None = None
|
||||
subject: str | None = None
|
||||
semester: Semester | None = None
|
||||
books: list[BookData] | None = None
|
||||
dauerapparat: bool = False
|
||||
# def __post_init__(self) -> None:
|
||||
# convert semester to string
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -373,24 +370,26 @@ class Book:
|
||||
|
||||
@dataclass
|
||||
class SemapDocument:
|
||||
subject: str | None = None
|
||||
phoneNumber: int | None = None
|
||||
mail: str | None = None
|
||||
title: str | None = None
|
||||
personName: str | None = None
|
||||
personTitle: str | None = None
|
||||
title_suggestions: list[str] = field(default_factory=list)
|
||||
semester: Union[str, 'Semester', None] = None
|
||||
books: list[Book] = field(default_factory=list)
|
||||
subject: str | None
|
||||
phoneNumber: int | None
|
||||
mail: str | None
|
||||
title: str | None
|
||||
personName: str | None
|
||||
personTitle: str | None
|
||||
title_suggestions: list[str] = None
|
||||
semester: Union[str, Semester] = None
|
||||
books: list[Book] = None
|
||||
eternal: bool = False
|
||||
title_length: int = 0
|
||||
title_max_length: int = 0
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
"""."""
|
||||
if self.phoneNumber is not None:
|
||||
phone_str = regex.sub(r"[^\d]", "", str(self.phoneNumber))
|
||||
self.phoneNumber = int(phone_str) if phone_str else None
|
||||
self.title_suggestions = []
|
||||
self.phoneNumber = int(
|
||||
regex.sub(r"[^\d]", "", str(self.phoneNumber)),
|
||||
)
|
||||
self.title_length = len(self.title) + 3 + len(self.personName.split(",")[0])
|
||||
|
||||
@property
|
||||
def nameSetter(self):
|
||||
@@ -416,7 +415,7 @@ class SemapDocument:
|
||||
def renameSemester(self) -> None:
|
||||
from src.services.openai import semester_converter
|
||||
|
||||
if self.semester and isinstance(self.semester, str):
|
||||
if self.semester:
|
||||
if ", Dauer" in self.semester:
|
||||
self.semester = self.semester.split(",")[0]
|
||||
self.eternal = True
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Semester helper class.
|
||||
"""Semester helper class
|
||||
|
||||
A small utility around the *German* academic calendar that distinguishes
|
||||
between *Wintersemester* (WiSe) and *Sommersemester* (SoSe).
|
||||
@@ -7,7 +7,7 @@ Key points
|
||||
----------
|
||||
* A **`Semester`** is identified by a *term* ("SoSe" or "WiSe") and the last two
|
||||
digits of the calendar year in which the term *starts*.
|
||||
* Formatting **never** pads the year with a leading zero - so ``6`` stays ``6``.
|
||||
* Formatting **never** pads the year with a leading zero – so ``6`` stays ``6``.
|
||||
* ``offset(n)`` and the static ``generate_missing`` reliably walk the timeline
|
||||
one semester at a time with correct year transitions:
|
||||
|
||||
@@ -26,13 +26,13 @@ class Semester:
|
||||
"""Represents a German university semester (WiSe or SoSe)."""
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Class-level defaults - will be *copied* to each instance and then
|
||||
# Class‑level defaults – will be *copied* to each instance and then
|
||||
# potentially overwritten in ``__init__``.
|
||||
# ------------------------------------------------------------------
|
||||
_year: int | None = None # Will be set in __post_init__
|
||||
_semester: str | None = None # "WiSe" or "SoSe" - set later
|
||||
_semester: str | None = None # "WiSe" or "SoSe" – set later
|
||||
_month: int | None = None # Will be set in __post_init__
|
||||
value: str | None = None # Human-readable label, e.g. "WiSe 23/24"
|
||||
value: str | None = None # Human‑readable label, e.g. "WiSe 23/24"
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Construction helpers
|
||||
@@ -89,22 +89,20 @@ class Semester:
|
||||
# ------------------------------------------------------------------
|
||||
def _generate_semester_from_month(self) -> None:
|
||||
"""Infer *WiSe* / *SoSe* from the month attribute."""
|
||||
if self._month is not None:
|
||||
self._semester = "WiSe" if (self._month <= 3 or self._month > 9) else "SoSe"
|
||||
else:
|
||||
self._semester = "WiSe" # Default value if month is None
|
||||
|
||||
def _compute_value(self) -> None:
|
||||
"""Human-readable semester label - e.g. ``WiSe 23/24`` or ``SoSe 24``."""
|
||||
if self._year is not None:
|
||||
"""Human‑readable semester label – e.g. ``WiSe 23/24`` or ``SoSe 24``."""
|
||||
year = self._year
|
||||
if self._semester == "WiSe":
|
||||
next_year = (year + 1) % 100 # wrap 99 → 0
|
||||
|
||||
self.value = f"WiSe {year}/{next_year}"
|
||||
else: # SoSe
|
||||
# year may only be the last two digits, so we don't want to pad it with a leading zero
|
||||
if len(str(year)) > 2:
|
||||
year = int(str(year)[-2:])
|
||||
self.value = f"SoSe {year}"
|
||||
else:
|
||||
self.value = "<invalid Semester>"
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Public API
|
||||
@@ -122,12 +120,10 @@ class Semester:
|
||||
if value == 0:
|
||||
return Semester(self._year, self._semester)
|
||||
|
||||
if self._year is None:
|
||||
raise ValueError("Cannot offset from a semester with no year")
|
||||
current_idx = self._year * 2 + (0 if self._semester == "SoSe" else 1)
|
||||
target_idx = current_idx + value
|
||||
if target_idx < 0:
|
||||
raise ValueError("offset would result in a negative year - not supported")
|
||||
raise ValueError("offset would result in a negative year – not supported")
|
||||
|
||||
new_year, semester_bit = divmod(target_idx, 2)
|
||||
new_semester = "SoSe" if semester_bit == 0 else "WiSe"
|
||||
@@ -171,14 +167,10 @@ class Semester:
|
||||
|
||||
@property
|
||||
def year(self) -> int:
|
||||
if self._year is None:
|
||||
raise ValueError("Year is not set for this semester")
|
||||
return self._year
|
||||
|
||||
@property
|
||||
def semester(self) -> str:
|
||||
if self._semester is None:
|
||||
raise ValueError("Semester is not set for this semester")
|
||||
return self._semester
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
@@ -189,14 +181,14 @@ class Semester:
|
||||
"""Return all consecutive semesters from *start* to *end* (inclusive)."""
|
||||
if not isinstance(start, Semester) or not isinstance(end, Semester):
|
||||
raise TypeError("start and end must be Semester instances")
|
||||
if start.is_future_semester(end) and not start.is_match(end):
|
||||
if start.is_future_semester(end) and not start.isMatch(end):
|
||||
raise ValueError("'start' must not be after 'end'")
|
||||
|
||||
chain: list[str] = [str(start)]
|
||||
chain: list[Semester] = [start.value]
|
||||
current = start
|
||||
while not current.is_match(end):
|
||||
while not current.isMatch(end):
|
||||
current = current.next
|
||||
chain.append(str(current))
|
||||
chain.append(current.value)
|
||||
if len(chain) > 1000: # sanity guard
|
||||
raise RuntimeError("generate_missing exceeded sane iteration limit")
|
||||
return chain
|
||||
@@ -206,9 +198,9 @@ class Semester:
|
||||
# ------------------------------------------------------------------
|
||||
@classmethod
|
||||
def from_string(cls, s: str) -> Semester:
|
||||
"""Parse a human-readable semester label and return a :class:`Semester`.
|
||||
"""Parse a human‑readable semester label and return a :class:`Semester`.
|
||||
|
||||
Accepted formats (case-insensitive)::
|
||||
Accepted formats (case‑insensitive)::
|
||||
|
||||
"SoSe <YY>" → SoSe of year YY
|
||||
"WiSe <YY>/<YY+1>" → Winter term starting in YY
|
||||
@@ -223,7 +215,7 @@ class Semester:
|
||||
m = re.fullmatch(pattern, s, flags=re.IGNORECASE)
|
||||
if not m:
|
||||
raise ValueError(
|
||||
"invalid semester string format - expected 'SoSe YY' or 'WiSe YY/YY' (spacing flexible)",
|
||||
"invalid semester string format – expected 'SoSe YY' or 'WiSe YY/YY' (spacing flexible)",
|
||||
)
|
||||
|
||||
term_raw, y1_str, y2_str = m.groups()
|
||||
@@ -247,7 +239,7 @@ class Semester:
|
||||
return cls(year, "WiSe")
|
||||
|
||||
|
||||
# ------------------------- quick self-test -------------------------
|
||||
# ------------------------- quick self‑test -------------------------
|
||||
if __name__ == "__main__":
|
||||
# Chain generation demo ------------------------------------------------
|
||||
s_start = Semester(6, "SoSe") # SoSe 6
|
||||
|
||||
@@ -123,7 +123,7 @@ class Database:
|
||||
try:
|
||||
if self.db_path is not None:
|
||||
self.run_migrations()
|
||||
except (sql.Error, OSError, IOError) as e:
|
||||
except Exception as e:
|
||||
log.error(f"Error while running migrations: {e}")
|
||||
|
||||
# --- Migration helpers integrated into Database ---
|
||||
@@ -212,9 +212,9 @@ class Database:
|
||||
).__str__()
|
||||
return result[0]
|
||||
|
||||
def getElsaMediaType(self, media_id):
|
||||
def getElsaMediaType(self, id):
|
||||
query = "SELECT type FROM elsa_media WHERE id=?"
|
||||
return self.query_db(query, (media_id,), one=True)[0]
|
||||
return self.query_db(query, (id,), one=True)[0]
|
||||
|
||||
def get_db_contents(self) -> Union[List[Tuple[Any]], None]:
|
||||
"""
|
||||
@@ -736,7 +736,7 @@ class Database:
|
||||
try:
|
||||
bloat.debug("Recreated file blob size: {} bytes", len(blob))
|
||||
bloat.debug("Recreated file blob (preview): {}", preview(blob, 2000))
|
||||
except (TypeError, UnicodeDecodeError, ValueError):
|
||||
except Exception:
|
||||
bloat.debug("Recreated file blob (preview): {}", preview(blob, 2000))
|
||||
tempdir = settings.database.temp.expanduser()
|
||||
if not tempdir.exists():
|
||||
@@ -990,16 +990,16 @@ class Database:
|
||||
person = Prof()
|
||||
return person.from_tuple(data)
|
||||
|
||||
def getProf(self, prof_id) -> Prof:
|
||||
def getProf(self, id) -> Prof:
|
||||
"""Get a professor based on the id
|
||||
|
||||
Args:
|
||||
prof_id ([type]): the id of the professor
|
||||
id ([type]): the id of the professor
|
||||
|
||||
Returns:
|
||||
Prof: a Prof object containing the data of the professor
|
||||
"""
|
||||
data = self.query_db("SELECT * FROM prof WHERE id=?", (prof_id,), one=True)
|
||||
data = self.query_db("SELECT * FROM prof WHERE id=?", (id,), one=True)
|
||||
return Prof().from_tuple(data)
|
||||
|
||||
def getProfs(self) -> list[Prof]:
|
||||
@@ -1278,17 +1278,17 @@ class Database:
|
||||
# print(apparat_nr, app_id)
|
||||
self.query_db("UPDATE media SET deleted=1 WHERE app_id=?", (app_id,))
|
||||
|
||||
def isEternal(self, apparat_id):
|
||||
def isEternal(self, id):
|
||||
"""check if the apparat is eternal (dauerapparat)
|
||||
|
||||
Args:
|
||||
apparat_id (int): the id of the apparat to be checked
|
||||
id (int): the id of the apparat to be checked
|
||||
|
||||
Returns:
|
||||
int: the state of the apparat
|
||||
"""
|
||||
return self.query_db(
|
||||
"SELECT dauer FROM semesterapparat WHERE appnr=?", (apparat_id,), one=True
|
||||
"SELECT dauer FROM semesterapparat WHERE appnr=?", (id,), one=True
|
||||
)
|
||||
|
||||
def getApparatName(self, app_id: Union[str, int], prof_id: Union[str, int]):
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import os
|
||||
from datetime import datetime
|
||||
from os.path import basename
|
||||
from pathlib import Path
|
||||
|
||||
from docx import Document
|
||||
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
|
||||
@@ -70,20 +69,20 @@ class SemesterDocument:
|
||||
full: bool = False,
|
||||
):
|
||||
assert isinstance(apparats, list), SemesterError(
|
||||
"Apparats must be a list of tuples",
|
||||
"Apparats must be a list of tuples"
|
||||
)
|
||||
assert all(isinstance(apparat, tuple) for apparat in apparats), SemesterError(
|
||||
"Apparats must be a list of tuples",
|
||||
"Apparats must be a list of tuples"
|
||||
)
|
||||
assert all(isinstance(apparat[0], int) for apparat in apparats), SemesterError(
|
||||
"Apparat numbers must be integers",
|
||||
"Apparat numbers must be integers"
|
||||
)
|
||||
assert all(isinstance(apparat[1], str) for apparat in apparats), SemesterError(
|
||||
"Apparat names must be strings",
|
||||
"Apparat names must be strings"
|
||||
)
|
||||
assert isinstance(semester, str), SemesterError("Semester must be a string")
|
||||
assert "." not in filename and isinstance(filename, str), SemesterError(
|
||||
"Filename must be a string and not contain an extension",
|
||||
"Filename must be a string and not contain an extension"
|
||||
)
|
||||
self.doc = Document()
|
||||
self.apparats = apparats
|
||||
@@ -109,7 +108,8 @@ class SemesterDocument:
|
||||
log.info("Document printed")
|
||||
|
||||
def set_table_border(self, table):
|
||||
"""Adds a full border to the table.
|
||||
"""
|
||||
Adds a full border to the table.
|
||||
|
||||
:param table: Table object to which the border will be applied.
|
||||
"""
|
||||
@@ -150,8 +150,7 @@ class SemesterDocument:
|
||||
trPr = row._tr.get_or_add_trPr() # Get or add the <w:trPr> element
|
||||
trHeight = OxmlElement("w:trHeight")
|
||||
trHeight.set(
|
||||
qn("w:val"),
|
||||
str(int(Pt(15).pt * 20)),
|
||||
qn("w:val"), str(int(Pt(15).pt * 20))
|
||||
) # Convert points to twips
|
||||
trHeight.set(qn("w:hRule"), "exact") # Use "exact" for fixed height
|
||||
trPr.append(trHeight)
|
||||
@@ -234,7 +233,7 @@ class SemesterDocument:
|
||||
self.save_document(self.filename + ".docx")
|
||||
docpath = os.path.abspath(self.filename + ".docx")
|
||||
doc = word.Documents.Open(docpath)
|
||||
curdir = Path.cwd()
|
||||
curdir = os.getcwd()
|
||||
doc.SaveAs(f"{curdir}/{self.filename}.pdf", FileFormat=17)
|
||||
doc.Close()
|
||||
word.Quit()
|
||||
@@ -318,7 +317,7 @@ class SemapSchilder:
|
||||
self.save_document()
|
||||
docpath = os.path.abspath(f"{self.filename}.docx")
|
||||
doc = word.Documents.Open(docpath)
|
||||
curdir = Path.cwd()
|
||||
curdir = os.getcwd()
|
||||
doc.SaveAs(f"{curdir}/{self.filename}.pdf", FileFormat=17)
|
||||
doc.Close()
|
||||
word.Quit()
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
# import basic error classes
|
||||
from .DatabaseErrors import * # noqa: F403
|
||||
from .DatabaseErrors import *
|
||||
|
||||
@@ -6,11 +6,3 @@ from .transformers import (
|
||||
RDSData,
|
||||
RISData,
|
||||
)
|
||||
|
||||
# Explicit re-exports to avoid F401 warnings
|
||||
RDS_AVAIL_DATA = RDS_AVAIL_DATA
|
||||
ARRAYData = ARRAYData
|
||||
BibTeXData = BibTeXData
|
||||
COinSData = COinSData
|
||||
RDSData = RDSData
|
||||
RISData = RISData
|
||||
|
||||
@@ -141,7 +141,7 @@ class ARRAYData:
|
||||
source = source.replace("\t", "").replace("\r", "")
|
||||
source = source.split(search)[1].split(")")[0]
|
||||
return _get_line(source, entry).replace("=>", "").strip()
|
||||
except Exception:
|
||||
except:
|
||||
return ""
|
||||
|
||||
def _get_isbn(source: str) -> list:
|
||||
@@ -157,7 +157,7 @@ class ARRAYData:
|
||||
continue
|
||||
ret.append(isb) if isb not in ret else None
|
||||
return ret
|
||||
except Exception:
|
||||
except:
|
||||
isbn = []
|
||||
return isbn
|
||||
|
||||
@@ -294,7 +294,7 @@ class COinSData:
|
||||
try:
|
||||
data = source.split(f"{search}=")[1] # .split("")[0].strip()
|
||||
return data.split("rft")[0].strip() if "rft" in data else data
|
||||
except Exception:
|
||||
except:
|
||||
return ""
|
||||
|
||||
return BookData(
|
||||
@@ -319,7 +319,7 @@ class RISData:
|
||||
try:
|
||||
data = source.split(f"{search} - ")[1] # .split("")[0].strip()
|
||||
return data.split("\n")[0].strip() if "\n" in data else data
|
||||
except Exception:
|
||||
except:
|
||||
return ""
|
||||
|
||||
return BookData(
|
||||
@@ -356,7 +356,7 @@ class BibTeXData:
|
||||
.replace("[", "")
|
||||
.replace("];", "")
|
||||
)
|
||||
except Exception:
|
||||
except:
|
||||
return ""
|
||||
|
||||
return BookData(
|
||||
|
||||
@@ -9,11 +9,11 @@ from ratelimit import limits, sleep_and_retry
|
||||
|
||||
from src.core.models import BookData
|
||||
from src.shared.logging import log, get_bloat_logger, preview
|
||||
from src.transformers import ARRAYData, BibTeXData, COinSData, RDSData, RISData
|
||||
from src.transformers.transformers import RDS_AVAIL_DATA, RDS_GENERIC_DATA
|
||||
|
||||
# bloat logger for large/raw HTTP responses
|
||||
bloat = get_bloat_logger()
|
||||
from src.transformers import ARRAYData, BibTeXData, COinSData, RDSData, RISData
|
||||
from src.transformers.transformers import RDS_AVAIL_DATA, RDS_GENERIC_DATA
|
||||
|
||||
# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
|
||||
|
||||
|
||||
@@ -6,11 +6,3 @@ from .transformers import (
|
||||
RDSData,
|
||||
RISData,
|
||||
)
|
||||
|
||||
# Explicit re-exports to avoid F401 warnings
|
||||
RDS_AVAIL_DATA = RDS_AVAIL_DATA
|
||||
ARRAYData = ARRAYData
|
||||
BibTeXData = BibTeXData
|
||||
COinSData = COinSData
|
||||
RDSData = RDSData
|
||||
RISData = RISData
|
||||
|
||||
@@ -141,7 +141,7 @@ class ARRAYData:
|
||||
source = source.replace("\t", "").replace("\r", "")
|
||||
source = source.split(search)[1].split(")")[0]
|
||||
return _get_line(source, entry).replace("=>", "").strip()
|
||||
except Exception:
|
||||
except:
|
||||
return ""
|
||||
|
||||
def _get_isbn(source: str) -> list:
|
||||
@@ -157,7 +157,7 @@ class ARRAYData:
|
||||
continue
|
||||
ret.append(isb) if isb not in ret else None
|
||||
return ret
|
||||
except Exception:
|
||||
except:
|
||||
isbn = []
|
||||
return isbn
|
||||
|
||||
@@ -294,7 +294,7 @@ class COinSData:
|
||||
try:
|
||||
data = source.split(f"{search}=")[1] # .split("")[0].strip()
|
||||
return data.split("rft")[0].strip() if "rft" in data else data
|
||||
except Exception:
|
||||
except:
|
||||
return ""
|
||||
|
||||
return BookData(
|
||||
@@ -319,7 +319,7 @@ class RISData:
|
||||
try:
|
||||
data = source.split(f"{search} - ")[1] # .split("")[0].strip()
|
||||
return data.split("\n")[0].strip() if "\n" in data else data
|
||||
except Exception:
|
||||
except:
|
||||
return ""
|
||||
|
||||
return BookData(
|
||||
@@ -356,7 +356,7 @@ class BibTeXData:
|
||||
.replace("[", "")
|
||||
.replace("];", "")
|
||||
)
|
||||
except Exception:
|
||||
except:
|
||||
return ""
|
||||
|
||||
return BookData(
|
||||
|
||||
@@ -2,9 +2,6 @@ import pathlib
|
||||
|
||||
from .semesterapparat_ui_ui import Ui_MainWindow as Ui_Semesterapparat
|
||||
|
||||
# Explicit re-export to avoid F401 warnings
|
||||
Ui_Semesterapparat = Ui_Semesterapparat
|
||||
|
||||
# from .dialogs import (
|
||||
# ApparatExtendDialog,
|
||||
# Mail_Dialog,
|
||||
|
||||
@@ -1,4 +1 @@
|
||||
from .newMailTemplateDesigner_ui import Ui_Dialog as NewMailTemplateDesignerDialog
|
||||
|
||||
# Explicit re-export to avoid F401 warnings
|
||||
NewMailTemplateDesignerDialog = NewMailTemplateDesignerDialog
|
||||
|
||||
@@ -9,12 +9,6 @@ from src.services.lehmanns import LehmannsClient
|
||||
from src.services.sru import SWB
|
||||
|
||||
|
||||
def filter_prefer_swb(response):
|
||||
"""Filter function to prefer SWB results when available."""
|
||||
# This is a placeholder implementation - adjust based on actual requirements
|
||||
return response
|
||||
|
||||
|
||||
class CheckThread(QtCore.QThread):
|
||||
updateSignal = QtCore.Signal()
|
||||
total_entries_signal = QtCore.Signal(int)
|
||||
|
||||
@@ -180,8 +180,7 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
|
||||
# self.update_app_media_list()
|
||||
self.populate_prof_dropdown()
|
||||
self.populate_appfach_dropdown()
|
||||
# if the focus is changed from the prof name dropdown, set the prof data if the
|
||||
# prof exists in the database, otherwise show a message
|
||||
# if the focus is changed from the prof name dropdown, set the prof data if the prof exists in the database, otherwise show a message
|
||||
self.drpdwn_prof_name.currentIndexChanged.connect(self.set_prof_data) # type:ignore
|
||||
self.cancel_active_selection.clicked.connect(self.btn_cancel_active_selection) # type:ignore
|
||||
self.check_eternal_app.stateChanged.connect(self.set_state) # type:ignore
|
||||
@@ -1244,26 +1243,23 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
|
||||
self.active_apparat,
|
||||
filetype=file_type,
|
||||
)
|
||||
if file_type == "pdf":
|
||||
match file_type:
|
||||
case "pdf":
|
||||
# TODO: implement parser here
|
||||
data = pdf_to_semap(file)
|
||||
signatures = data.signatures
|
||||
# self.confirm_popup("PDF Dateien werden nicht unterstützt!", title="Fehler")
|
||||
return signatures
|
||||
if file_type == "csv":
|
||||
case "csv":
|
||||
return csv_to_list(file)
|
||||
if file_type in ("docx", "doc"):
|
||||
data = word_to_semap(file)
|
||||
log.info("Converted data from semap file")
|
||||
log.debug("Got the data: {}", data)
|
||||
|
||||
return data
|
||||
if file_type == "eml":
|
||||
case _ if file_type in ("docx", "doc"):
|
||||
return word_to_semap(file)
|
||||
case "eml":
|
||||
data = eml_to_semap(file)
|
||||
log.info("Converted data from eml file")
|
||||
log.debug("Got the data: {}", data)
|
||||
|
||||
return data
|
||||
case _:
|
||||
error = "Dateityp wird nicht unterstützt"
|
||||
raise ValueError(error)
|
||||
|
||||
@@ -1315,6 +1311,7 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
|
||||
self.app_fach.setCurrentText(data.subject if data.subject in subjects else "")
|
||||
self.prof_title.setText(data.personTitle)
|
||||
self.drpdwn_prof_name.setCurrentText(data.personName)
|
||||
|
||||
self.sem_year.setText("20" + str(data.semester.year))
|
||||
if data.semester.semester == "SoSe":
|
||||
self.sem_sommer.setChecked(True)
|
||||
@@ -1326,9 +1323,13 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
|
||||
self.check_eternal_app.setChecked(True)
|
||||
self.validate_semester()
|
||||
if data.books != []:
|
||||
log.info("Importing books from document")
|
||||
log.info(data)
|
||||
self.btn_check_file_threaded(data)
|
||||
|
||||
def btn_check_file_threaded(self, c_document: Optional[SemapDocument] = None):
|
||||
log.info("Starting threaded file check")
|
||||
log.info(c_document)
|
||||
for runner in self.bookGrabber:
|
||||
if not runner.isRunning():
|
||||
runner.deleteLater()
|
||||
@@ -1374,8 +1375,7 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
|
||||
prof_id = self.db.getProfId(self.profdata)
|
||||
|
||||
# log.debug("Prof ID is None", prof_id)
|
||||
document = None
|
||||
|
||||
document = c_document
|
||||
if c_document is None:
|
||||
document = self.extract_document_data()
|
||||
if document is None:
|
||||
|
||||
@@ -4,36 +4,15 @@ from src.database import Database
|
||||
from src.utils.icon import Icon
|
||||
|
||||
|
||||
class AdminQueryWidget(QtWidgets.QWidget):
|
||||
class AdminQueryWidget(QtWidgets.QWidget, Ui_Form):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setupUi()
|
||||
self.setupUi(self)
|
||||
self.setWindowIcon(Icon("db_search").icon)
|
||||
self.db = Database()
|
||||
# Connect the button click to the method
|
||||
self.sendquery.clicked.connect(self.on_pushButton_clicked)
|
||||
|
||||
def setupUi(self):
|
||||
# Create the layout and widgets
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
|
||||
# Create SQL query input area
|
||||
self.sqlquery = QtWidgets.QTextEdit()
|
||||
self.sqlquery.setPlaceholderText("Enter SQL query here...")
|
||||
|
||||
# Create execute button
|
||||
self.sendquery = QtWidgets.QPushButton("Execute Query")
|
||||
|
||||
# Create results table
|
||||
self.queryResult = QtWidgets.QTableWidget()
|
||||
self.queryResult.setColumnCount(5) # Adjust as needed
|
||||
self.queryResult.setHorizontalHeaderLabels(["Column 1", "Column 2", "Column 3", "Column 4", "Column 5"])
|
||||
|
||||
# Add widgets to layout
|
||||
layout.addWidget(self.sqlquery)
|
||||
layout.addWidget(self.sendquery)
|
||||
layout.addWidget(self.queryResult)
|
||||
|
||||
def on_pushButton_clicked(self):
|
||||
# Handle button click event
|
||||
self.queryResult.setRowCount(0) # Clear previous results
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
"""Utilities for managing documentation server functionality."""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from src import LOG_DIR
|
||||
|
||||
log_path = Path(LOG_DIR) / "web_documentation.log"
|
||||
log_path = os.path.join(LOG_DIR, "web_documentation.log")
|
||||
|
||||
# Replace the default StreamHandler with a FileHandler
|
||||
logging.basicConfig(
|
||||
@@ -21,12 +19,13 @@ logger = logging.getLogger(__name__) # inherits the same file handler
|
||||
docport = 8000
|
||||
|
||||
|
||||
|
||||
def start_documentation_server():
|
||||
"""Start the Zensical documentation server as a subprocess.
|
||||
"""
|
||||
Start the Zensical documentation server as a subprocess.
|
||||
|
||||
Returns:
|
||||
subprocess.Popen: The subprocess object, or None if startup failed.
|
||||
|
||||
"""
|
||||
try:
|
||||
# Prepare subprocess arguments
|
||||
@@ -42,7 +41,7 @@ def start_documentation_server():
|
||||
stderr=subprocess.DEVNULL,
|
||||
stdin=subprocess.DEVNULL,
|
||||
creationflags=creationflags,
|
||||
cwd=Path.cwd(),
|
||||
cwd=os.getcwd(),
|
||||
)
|
||||
|
||||
logger.info(f"Documentation server started with PID {process.pid}")
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import os
|
||||
from datetime import datetime
|
||||
from os.path import basename
|
||||
from pathlib import Path
|
||||
|
||||
from docx import Document
|
||||
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
|
||||
@@ -70,20 +69,20 @@ class SemesterDocument:
|
||||
full: bool = False,
|
||||
):
|
||||
assert isinstance(apparats, list), SemesterError(
|
||||
"Apparats must be a list of tuples",
|
||||
"Apparats must be a list of tuples"
|
||||
)
|
||||
assert all(isinstance(apparat, tuple) for apparat in apparats), SemesterError(
|
||||
"Apparats must be a list of tuples",
|
||||
"Apparats must be a list of tuples"
|
||||
)
|
||||
assert all(isinstance(apparat[0], int) for apparat in apparats), SemesterError(
|
||||
"Apparat numbers must be integers",
|
||||
"Apparat numbers must be integers"
|
||||
)
|
||||
assert all(isinstance(apparat[1], str) for apparat in apparats), SemesterError(
|
||||
"Apparat names must be strings",
|
||||
"Apparat names must be strings"
|
||||
)
|
||||
assert isinstance(semester, str), SemesterError("Semester must be a string")
|
||||
assert "." not in filename and isinstance(filename, str), SemesterError(
|
||||
"Filename must be a string and not contain an extension",
|
||||
"Filename must be a string and not contain an extension"
|
||||
)
|
||||
self.doc = Document()
|
||||
self.apparats = apparats
|
||||
@@ -109,7 +108,8 @@ class SemesterDocument:
|
||||
log.info("Document printed")
|
||||
|
||||
def set_table_border(self, table):
|
||||
"""Adds a full border to the table.
|
||||
"""
|
||||
Adds a full border to the table.
|
||||
|
||||
:param table: Table object to which the border will be applied.
|
||||
"""
|
||||
@@ -150,8 +150,7 @@ class SemesterDocument:
|
||||
trPr = row._tr.get_or_add_trPr() # Get or add the <w:trPr> element
|
||||
trHeight = OxmlElement("w:trHeight")
|
||||
trHeight.set(
|
||||
qn("w:val"),
|
||||
str(int(Pt(15).pt * 20)),
|
||||
qn("w:val"), str(int(Pt(15).pt * 20))
|
||||
) # Convert points to twips
|
||||
trHeight.set(qn("w:hRule"), "exact") # Use "exact" for fixed height
|
||||
trPr.append(trHeight)
|
||||
@@ -234,7 +233,7 @@ class SemesterDocument:
|
||||
self.save_document(self.filename + ".docx")
|
||||
docpath = os.path.abspath(self.filename + ".docx")
|
||||
doc = word.Documents.Open(docpath)
|
||||
curdir = Path.cwd()
|
||||
curdir = os.getcwd()
|
||||
doc.SaveAs(f"{curdir}/{self.filename}.pdf", FileFormat=17)
|
||||
doc.Close()
|
||||
word.Quit()
|
||||
@@ -318,7 +317,7 @@ class SemapSchilder:
|
||||
self.save_document()
|
||||
docpath = os.path.abspath(f"{self.filename}.docx")
|
||||
doc = word.Documents.Open(docpath)
|
||||
curdir = Path.cwd()
|
||||
curdir = os.getcwd()
|
||||
doc.SaveAs(f"{curdir}/{self.filename}.pdf", FileFormat=17)
|
||||
doc.Close()
|
||||
word.Quit()
|
||||
|
||||
14
test.py
14
test.py
@@ -1,12 +1,10 @@
|
||||
# from src.services.webrequest import BibTextTransformer, TransformerType, WebRequest
|
||||
from src.services.webrequest import BibTextTransformer, TransformerType, WebRequest
|
||||
|
||||
# transformer = BibTextTransformer(TransformerType.RDS)
|
||||
transformer = BibTextTransformer(TransformerType.RDS)
|
||||
|
||||
# data = WebRequest().set_apparat(71)
|
||||
# data = data.get_ppn("CU 3700 R244 (2)").get_data()
|
||||
data = WebRequest().set_apparat(71)
|
||||
data = data.get_ppn("CU 3700 R244 (2)").get_data()
|
||||
|
||||
# rds = transformer.get_data(data).return_data("rds_availability")
|
||||
|
||||
# print(rds)
|
||||
from src.parsers.xml_parser import eml_parser, eml_to_semap
|
||||
rds = transformer.get_data(data).return_data("rds_availability")
|
||||
|
||||
print(rds)
|
||||
|
||||
163
uv.lock
generated
163
uv.lock
generated
@@ -307,75 +307,6 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/03/2f/ca9029d5da14b5a3a103d6061149a4a94a54ab848f56c7d2809dbb36f48c/comtypes-1.4.15-py3-none-any.whl", hash = "sha256:cda90486de8762ec57d7ce04e68721920911f3f03415cb29afdf7609c427c7e3", size = 274650, upload-time = "2026-01-19T23:45:44.34Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "coverage"
|
||||
version = "7.13.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/24/56/95b7e30fa389756cb56630faa728da46a27b8c6eb46f9d557c68fff12b65/coverage-7.13.4.tar.gz", hash = "sha256:e5c8f6ed1e61a8b2dcdf31eb0b9bbf0130750ca79c1c49eb898e2ad86f5ccc91", size = 827239, upload-time = "2026-02-09T12:59:03.86Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/db/23/aad45061a31677d68e47499197a131eea55da4875d16c1f42021ab963503/coverage-7.13.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b66a2da594b6068b48b2692f043f35d4d3693fb639d5ea8b39533c2ad9ac3ab9", size = 219474, upload-time = "2026-02-09T12:57:19.332Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/70/9b8b67a0945f3dfec1fd896c5cefb7c19d5a3a6d74630b99a895170999ae/coverage-7.13.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3599eb3992d814d23b35c536c28df1a882caa950f8f507cef23d1cbf334995ac", size = 219844, upload-time = "2026-02-09T12:57:20.66Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/97/fd/7e859f8fab324cef6c4ad7cff156ca7c489fef9179d5749b0c8d321281c2/coverage-7.13.4-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:93550784d9281e374fb5a12bf1324cc8a963fd63b2d2f223503ef0fd4aa339ea", size = 250832, upload-time = "2026-02-09T12:57:22.007Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e4/dc/b2442d10020c2f52617828862d8b6ee337859cd8f3a1f13d607dddda9cf7/coverage-7.13.4-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b720ce6a88a2755f7c697c23268ddc47a571b88052e6b155224347389fdf6a3b", size = 253434, upload-time = "2026-02-09T12:57:23.339Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/88/6728a7ad17428b18d836540630487231f5470fb82454871149502f5e5aa2/coverage-7.13.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7b322db1284a2ed3aa28ffd8ebe3db91c929b7a333c0820abec3d838ef5b3525", size = 254676, upload-time = "2026-02-09T12:57:24.774Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/bc/21244b1b8cedf0dff0a2b53b208015fe798d5f2a8d5348dbfece04224fff/coverage-7.13.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f4594c67d8a7c89cf922d9df0438c7c7bb022ad506eddb0fdb2863359ff78242", size = 256807, upload-time = "2026-02-09T12:57:26.125Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/97/a0/ddba7ed3251cff51006737a727d84e05b61517d1784a9988a846ba508877/coverage-7.13.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:53d133df809c743eb8bce33b24bcababb371f4441340578cd406e084d94a6148", size = 251058, upload-time = "2026-02-09T12:57:27.614Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9b/55/e289addf7ff54d3a540526f33751951bf0878f3809b47f6dfb3def69c6f7/coverage-7.13.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:76451d1978b95ba6507a039090ba076105c87cc76fc3efd5d35d72093964d49a", size = 252805, upload-time = "2026-02-09T12:57:29.066Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/4e/cc276b1fa4a59be56d96f1dabddbdc30f4ba22e3b1cd42504c37b3313255/coverage-7.13.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7f57b33491e281e962021de110b451ab8a24182589be17e12a22c79047935e23", size = 250766, upload-time = "2026-02-09T12:57:30.522Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/44/1093b8f93018f8b41a8cf29636c9292502f05e4a113d4d107d14a3acd044/coverage-7.13.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1731dc33dc276dafc410a885cbf5992f1ff171393e48a21453b78727d090de80", size = 254923, upload-time = "2026-02-09T12:57:31.946Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8b/55/ea2796da2d42257f37dbea1aab239ba9263b31bd91d5527cdd6db5efe174/coverage-7.13.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:bd60d4fe2f6fa7dff9223ca1bbc9f05d2b6697bc5961072e5d3b952d46e1b1ea", size = 250591, upload-time = "2026-02-09T12:57:33.842Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d4/fa/7c4bb72aacf8af5020675aa633e59c1fbe296d22aed191b6a5b711eb2bc7/coverage-7.13.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9181a3ccead280b828fae232df12b16652702b49d41e99d657f46cc7b1f6ec7a", size = 252364, upload-time = "2026-02-09T12:57:35.743Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/38/a8d2ec0146479c20bbaa7181b5b455a0c41101eed57f10dd19a78ab44c80/coverage-7.13.4-cp313-cp313-win32.whl", hash = "sha256:f53d492307962561ac7de4cd1de3e363589b000ab69617c6156a16ba7237998d", size = 222010, upload-time = "2026-02-09T12:57:37.25Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e2/0c/dbfafbe90a185943dcfbc766fe0e1909f658811492d79b741523a414a6cc/coverage-7.13.4-cp313-cp313-win_amd64.whl", hash = "sha256:e6f70dec1cc557e52df5306d051ef56003f74d56e9c4dd7ddb07e07ef32a84dd", size = 222818, upload-time = "2026-02-09T12:57:38.734Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/04/d1/934918a138c932c90d78301f45f677fb05c39a3112b96fd2c8e60503cdc7/coverage-7.13.4-cp313-cp313-win_arm64.whl", hash = "sha256:fb07dc5da7e849e2ad31a5d74e9bece81f30ecf5a42909d0a695f8bd1874d6af", size = 221438, upload-time = "2026-02-09T12:57:40.223Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/57/ee93ced533bcb3e6df961c0c6e42da2fc6addae53fb95b94a89b1e33ebd7/coverage-7.13.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:40d74da8e6c4b9ac18b15331c4b5ebc35a17069410cad462ad4f40dcd2d50c0d", size = 220165, upload-time = "2026-02-09T12:57:41.639Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c5/e0/969fc285a6fbdda49d91af278488d904dcd7651b2693872f0ff94e40e84a/coverage-7.13.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4223b4230a376138939a9173f1bdd6521994f2aff8047fae100d6d94d50c5a12", size = 220516, upload-time = "2026-02-09T12:57:44.215Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b1/b8/9531944e16267e2735a30a9641ff49671f07e8138ecf1ca13db9fd2560c7/coverage-7.13.4-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1d4be36a5114c499f9f1f9195e95ebf979460dbe2d88e6816ea202010ba1c34b", size = 261804, upload-time = "2026-02-09T12:57:45.989Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/f3/e63df6d500314a2a60390d1989240d5f27318a7a68fa30ad3806e2a9323e/coverage-7.13.4-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:200dea7d1e8095cc6e98cdabe3fd1d21ab17d3cee6dab00cadbb2fe35d9c15b9", size = 263885, upload-time = "2026-02-09T12:57:47.42Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/67/7654810de580e14b37670b60a09c599fa348e48312db5b216d730857ffe6/coverage-7.13.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8eb931ee8e6d8243e253e5ed7336deea6904369d2fd8ae6e43f68abbf167092", size = 266308, upload-time = "2026-02-09T12:57:49.345Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/37/6f/39d41eca0eab3cc82115953ad41c4e77935286c930e8fad15eaed1389d83/coverage-7.13.4-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:75eab1ebe4f2f64d9509b984f9314d4aa788540368218b858dad56dc8f3e5eb9", size = 267452, upload-time = "2026-02-09T12:57:50.811Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/50/6d/39c0fbb8fc5cd4d2090811e553c2108cf5112e882f82505ee7495349a6bf/coverage-7.13.4-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c35eb28c1d085eb7d8c9b3296567a1bebe03ce72962e932431b9a61f28facf26", size = 261057, upload-time = "2026-02-09T12:57:52.447Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/a2/60010c669df5fa603bb5a97fb75407e191a846510da70ac657eb696b7fce/coverage-7.13.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb88b316ec33760714a4720feb2816a3a59180fd58c1985012054fa7aebee4c2", size = 263875, upload-time = "2026-02-09T12:57:53.938Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/d9/63b22a6bdbd17f1f96e9ed58604c2a6b0e72a9133e37d663bef185877cf6/coverage-7.13.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7d41eead3cc673cbd38a4417deb7fd0b4ca26954ff7dc6078e33f6ff97bed940", size = 261500, upload-time = "2026-02-09T12:57:56.012Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/bf/69f86ba1ad85bc3ad240e4c0e57a2e620fbc0e1645a47b5c62f0e941ad7f/coverage-7.13.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:fb26a934946a6afe0e326aebe0730cdff393a8bc0bbb65a2f41e30feddca399c", size = 265212, upload-time = "2026-02-09T12:57:57.5Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/f2/5f65a278a8c2148731831574c73e42f57204243d33bedaaf18fa79c5958f/coverage-7.13.4-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:dae88bc0fc77edaa65c14be099bd57ee140cf507e6bfdeea7938457ab387efb0", size = 260398, upload-time = "2026-02-09T12:57:59.027Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ef/80/6e8280a350ee9fea92f14b8357448a242dcaa243cb2c72ab0ca591f66c8c/coverage-7.13.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:845f352911777a8e722bfce168958214951e07e47e5d5d9744109fa5fe77f79b", size = 262584, upload-time = "2026-02-09T12:58:01.129Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/63/01ff182fc95f260b539590fb12c11ad3e21332c15f9799cb5e2386f71d9f/coverage-7.13.4-cp313-cp313t-win32.whl", hash = "sha256:2fa8d5f8de70688a28240de9e139fa16b153cc3cbb01c5f16d88d6505ebdadf9", size = 222688, upload-time = "2026-02-09T12:58:02.736Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a9/43/89de4ef5d3cd53b886afa114065f7e9d3707bdb3e5efae13535b46ae483d/coverage-7.13.4-cp313-cp313t-win_amd64.whl", hash = "sha256:9351229c8c8407645840edcc277f4a2d44814d1bc34a2128c11c2a031d45a5dd", size = 223746, upload-time = "2026-02-09T12:58:05.362Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/35/39/7cf0aa9a10d470a5309b38b289b9bb07ddeac5d61af9b664fe9775a4cb3e/coverage-7.13.4-cp313-cp313t-win_arm64.whl", hash = "sha256:30b8d0512f2dc8c8747557e8fb459d6176a2c9e5731e2b74d311c03b78451997", size = 222003, upload-time = "2026-02-09T12:58:06.952Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/92/11/a9cf762bb83386467737d32187756a42094927150c3e107df4cb078e8590/coverage-7.13.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:300deaee342f90696ed186e3a00c71b5b3d27bffe9e827677954f4ee56969601", size = 219522, upload-time = "2026-02-09T12:58:08.623Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d3/28/56e6d892b7b052236d67c95f1936b6a7cf7c3e2634bf27610b8cbd7f9c60/coverage-7.13.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:29e3220258d682b6226a9b0925bc563ed9a1ebcff3cad30f043eceea7eaf2689", size = 219855, upload-time = "2026-02-09T12:58:10.176Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/69/233459ee9eb0c0d10fcc2fe425a029b3fa5ce0f040c966ebce851d030c70/coverage-7.13.4-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:391ee8f19bef69210978363ca930f7328081c6a0152f1166c91f0b5fdd2a773c", size = 250887, upload-time = "2026-02-09T12:58:12.503Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/90/2cdab0974b9b5bbc1623f7876b73603aecac11b8d95b85b5b86b32de5eab/coverage-7.13.4-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0dd7ab8278f0d58a0128ba2fca25824321f05d059c1441800e934ff2efa52129", size = 253396, upload-time = "2026-02-09T12:58:14.615Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ac/15/ea4da0f85bf7d7b27635039e649e99deb8173fe551096ea15017f7053537/coverage-7.13.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78cdf0d578b15148b009ccf18c686aa4f719d887e76e6b40c38ffb61d264a552", size = 254745, upload-time = "2026-02-09T12:58:16.162Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/11/bb356e86920c655ca4d61daee4e2bbc7258f0a37de0be32d233b561134ff/coverage-7.13.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:48685fee12c2eb3b27c62f2658e7ea21e9c3239cba5a8a242801a0a3f6a8c62a", size = 257055, upload-time = "2026-02-09T12:58:17.892Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c9/0f/9ae1f8cb17029e09da06ca4e28c9e1d5c1c0a511c7074592e37e0836c915/coverage-7.13.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4e83efc079eb39480e6346a15a1bcb3e9b04759c5202d157e1dd4303cd619356", size = 250911, upload-time = "2026-02-09T12:58:19.495Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/3a/adfb68558fa815cbc29747b553bc833d2150228f251b127f1ce97e48547c/coverage-7.13.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ecae9737b72408d6a950f7e525f30aca12d4bd8dd95e37342e5beb3a2a8c4f71", size = 252754, upload-time = "2026-02-09T12:58:21.064Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/32/b1/540d0c27c4e748bd3cd0bd001076ee416eda993c2bae47a73b7cc9357931/coverage-7.13.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ae4578f8528569d3cf303fef2ea569c7f4c4059a38c8667ccef15c6e1f118aa5", size = 250720, upload-time = "2026-02-09T12:58:22.622Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/95/383609462b3ffb1fe133014a7c84fc0dd01ed55ac6140fa1093b5af7ebb1/coverage-7.13.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:6fdef321fdfbb30a197efa02d48fcd9981f0d8ad2ae8903ac318adc653f5df98", size = 254994, upload-time = "2026-02-09T12:58:24.548Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f7/ba/1761138e86c81680bfc3c49579d66312865457f9fe405b033184e5793cb3/coverage-7.13.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b0f6ccf3dbe577170bebfce1318707d0e8c3650003cb4b3a9dd744575daa8b5", size = 250531, upload-time = "2026-02-09T12:58:26.271Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/8e/05900df797a9c11837ab59c4d6fe94094e029582aab75c3309a93e6fb4e3/coverage-7.13.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75fcd519f2a5765db3f0e391eb3b7d150cce1a771bf4c9f861aeab86c767a3c0", size = 252189, upload-time = "2026-02-09T12:58:27.807Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/00/bd/29c9f2db9ea4ed2738b8a9508c35626eb205d51af4ab7bf56a21a2e49926/coverage-7.13.4-cp314-cp314-win32.whl", hash = "sha256:8e798c266c378da2bd819b0677df41ab46d78065fb2a399558f3f6cae78b2fbb", size = 222258, upload-time = "2026-02-09T12:58:29.441Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a7/4d/1f8e723f6829977410efeb88f73673d794075091c8c7c18848d273dc9d73/coverage-7.13.4-cp314-cp314-win_amd64.whl", hash = "sha256:245e37f664d89861cf2329c9afa2c1fe9e6d4e1a09d872c947e70718aeeac505", size = 223073, upload-time = "2026-02-09T12:58:31.026Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/51/5b/84100025be913b44e082ea32abcf1afbf4e872f5120b7a1cab1d331b1e13/coverage-7.13.4-cp314-cp314-win_arm64.whl", hash = "sha256:ad27098a189e5838900ce4c2a99f2fe42a0bf0c2093c17c69b45a71579e8d4a2", size = 221638, upload-time = "2026-02-09T12:58:32.599Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a7/e4/c884a405d6ead1370433dad1e3720216b4f9fd8ef5b64bfd984a2a60a11a/coverage-7.13.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:85480adfb35ffc32d40918aad81b89c69c9cc5661a9b8a81476d3e645321a056", size = 220246, upload-time = "2026-02-09T12:58:34.181Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/81/5c/4d7ed8b23b233b0fffbc9dfec53c232be2e695468523242ea9fd30f97ad2/coverage-7.13.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:79be69cf7f3bf9b0deeeb062eab7ac7f36cd4cc4c4dd694bd28921ba4d8596cc", size = 220514, upload-time = "2026-02-09T12:58:35.704Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2f/6f/3284d4203fd2f28edd73034968398cd2d4cb04ab192abc8cff007ea35679/coverage-7.13.4-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:caa421e2684e382c5d8973ac55e4f36bed6821a9bad5c953494de960c74595c9", size = 261877, upload-time = "2026-02-09T12:58:37.864Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/09/aa/b672a647bbe1556a85337dc95bfd40d146e9965ead9cc2fe81bde1e5cbce/coverage-7.13.4-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:14375934243ee05f56c45393fe2ce81fe5cc503c07cee2bdf1725fb8bef3ffaf", size = 264004, upload-time = "2026-02-09T12:58:39.492Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/79/a1/aa384dbe9181f98bba87dd23dda436f0c6cf2e148aecbb4e50fc51c1a656/coverage-7.13.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25a41c3104d08edb094d9db0d905ca54d0cd41c928bb6be3c4c799a54753af55", size = 266408, upload-time = "2026-02-09T12:58:41.852Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/53/5e/5150bf17b4019bc600799f376bb9606941e55bd5a775dc1e096b6ffea952/coverage-7.13.4-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f01afcff62bf9a08fb32b2c1d6e924236c0383c02c790732b6537269e466a72", size = 267544, upload-time = "2026-02-09T12:58:44.093Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/ed/f1de5c675987a4a7a672250d2c5c9d73d289dbf13410f00ed7181d8017dd/coverage-7.13.4-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eb9078108fbf0bcdde37c3f4779303673c2fa1fe8f7956e68d447d0dd426d38a", size = 260980, upload-time = "2026-02-09T12:58:45.721Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/e3/fe758d01850aa172419a6743fe76ba8b92c29d181d4f676ffe2dae2ba631/coverage-7.13.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0e086334e8537ddd17e5f16a344777c1ab8194986ec533711cbe6c41cde841b6", size = 263871, upload-time = "2026-02-09T12:58:47.334Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/76/b829869d464115e22499541def9796b25312b8cf235d3bb00b39f1675395/coverage-7.13.4-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:725d985c5ab621268b2edb8e50dfe57633dc69bda071abc470fed55a14935fd3", size = 261472, upload-time = "2026-02-09T12:58:48.995Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/14/9e/caedb1679e73e2f6ad240173f55218488bfe043e38da577c4ec977489915/coverage-7.13.4-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:3c06f0f1337c667b971ca2f975523347e63ec5e500b9aa5882d91931cd3ef750", size = 265210, upload-time = "2026-02-09T12:58:51.178Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3a/10/0dd02cb009b16ede425b49ec344aba13a6ae1dc39600840ea6abcb085ac4/coverage-7.13.4-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:590c0ed4bf8e85f745e6b805b2e1c457b2e33d5255dd9729743165253bc9ad39", size = 260319, upload-time = "2026-02-09T12:58:53.081Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/92/8e/234d2c927af27c6d7a5ffad5bd2cf31634c46a477b4c7adfbfa66baf7ebb/coverage-7.13.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:eb30bf180de3f632cd043322dad5751390e5385108b2807368997d1a92a509d0", size = 262638, upload-time = "2026-02-09T12:58:55.258Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2f/64/e5547c8ff6964e5965c35a480855911b61509cce544f4d442caa759a0702/coverage-7.13.4-cp314-cp314t-win32.whl", hash = "sha256:c4240e7eded42d131a2d2c4dec70374b781b043ddc79a9de4d55ca71f8e98aea", size = 223040, upload-time = "2026-02-09T12:58:56.936Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/96/38086d58a181aac86d503dfa9c47eb20715a79c3e3acbdf786e92e5c09a8/coverage-7.13.4-cp314-cp314t-win_amd64.whl", hash = "sha256:4c7d3cc01e7350f2f0f6f7036caaf5673fb56b6998889ccfe9e1c1fe75a9c932", size = 224148, upload-time = "2026-02-09T12:58:58.645Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/72/8d10abd3740a0beb98c305e0c3faf454366221c0f37a8bcf8f60020bb65a/coverage-7.13.4-cp314-cp314t-win_arm64.whl", hash = "sha256:23e3f687cf945070d1c90f85db66d11e3025665d8dafa831301a0e0038f3db9b", size = 222172, upload-time = "2026-02-09T12:59:00.396Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0d/4a/331fe2caf6799d591109bb9c08083080f6de90a823695d412a935622abb2/coverage-7.13.4-py3-none-any.whl", hash = "sha256:1af1641e57cf7ba1bd67d677c9abdbcd6cc2ab7da3bca7fa1e2b7e50e65f2ad0", size = 211242, upload-time = "2026-02-09T12:59:02.032Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cryptography"
|
||||
version = "46.0.4"
|
||||
@@ -621,15 +552,6 @@ 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 = "iniconfig"
|
||||
version = "2.3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itsdangerous"
|
||||
version = "2.2.0"
|
||||
@@ -1077,12 +999,27 @@ wheels = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pluggy"
|
||||
version = "1.6.0"
|
||||
name = "prek"
|
||||
version = "0.3.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d3/f5/ee52def928dd1355c20bcfcf765e1e61434635c33f3075e848e7b83a157b/prek-0.3.2.tar.gz", hash = "sha256:dce0074ff1a21290748ca567b4bda7553ee305a8c7b14d737e6c58364a499364", size = 334229, upload-time = "2026-02-06T13:49:47.539Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/76/69/70a5fc881290a63910494df2677c0fb241d27cfaa435bbcd0de5cd2e2443/prek-0.3.2-py3-none-linux_armv6l.whl", hash = "sha256:4f352f9c3fc98aeed4c8b2ec4dbf16fc386e45eea163c44d67e5571489bd8e6f", size = 4614960, upload-time = "2026-02-06T13:50:05.818Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c0/15/a82d5d32a2207ccae5d86ea9e44f2b93531ed000faf83a253e8d1108e026/prek-0.3.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:4a000cfbc3a6ec7d424f8be3c3e69ccd595448197f92daac8652382d0acc2593", size = 4622889, upload-time = "2026-02-06T13:49:53.662Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/75/ea833b58a12741397017baef9b66a6e443bfa8286ecbd645d14111446280/prek-0.3.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5436bdc2702cbd7bcf9e355564ae66f8131211e65fefae54665a94a07c3d450a", size = 4239653, upload-time = "2026-02-06T13:50:02.88Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/b4/d9c3885987afac6e20df4cb7db14e3b0d5a08a77ae4916488254ebac4d0b/prek-0.3.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:0161b5f584f9e7f416d6cf40a17b98f17953050ff8d8350ec60f20fe966b86b6", size = 4595101, upload-time = "2026-02-06T13:49:49.813Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/21/a6/1a06473ed83dbc898de22838abdb13954e2583ce229f857f61828384634c/prek-0.3.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4e641e8533bca38797eebb49aa89ed0e8db0e61225943b27008c257e3af4d631", size = 4521978, upload-time = "2026-02-06T13:49:41.266Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/5e/c38390d5612e6d86b32151c1d2fdab74a57913473193591f0eb00c894c21/prek-0.3.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfca1810d49d3f9ef37599c958c4e716bc19a1d78a7e88cbdcb332e0b008994f", size = 4829108, upload-time = "2026-02-06T13:49:44.598Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/80/a6/cecce2ab623747ff65ed990bb0d95fa38449ee19b348234862acf9392fff/prek-0.3.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5d69d754299a95a85dc20196f633232f306bee7e7c8cba61791f49ce70404ec", size = 5357520, upload-time = "2026-02-06T13:49:48.512Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/18/d6bcb29501514023c76d55d5cd03bdbc037737c8de8b6bc41cdebfb1682c/prek-0.3.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:539dcb90ad9b20837968539855df6a29493b328a1ae87641560768eed4f313b0", size = 4852635, upload-time = "2026-02-06T13:49:58.347Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1b/0a/ae46f34ba27ba87aea5c9ad4ac9cd3e07e014fd5079ae079c84198f62118/prek-0.3.2-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:1998db3d0cbe243984736c82232be51318f9192e2433919a6b1c5790f600b5fd", size = 4599484, upload-time = "2026-02-06T13:49:43.296Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/a9/73bfb5b3f7c3583f9b0d431924873928705cdef6abb3d0461c37254a681b/prek-0.3.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:07ab237a5415a3e8c0db54de9d63899bcd947624bdd8820d26f12e65f8d19eb7", size = 4657694, upload-time = "2026-02-06T13:50:01.074Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a7/bc/0994bc176e1a80110fad3babce2c98b0ac4007630774c9e18fc200a34781/prek-0.3.2-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:0ced19701d69c14a08125f14a5dd03945982edf59e793c73a95caf4697a7ac30", size = 4509337, upload-time = "2026-02-06T13:49:54.891Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/13/e73f85f65ba8f626468e5d1694ab3763111513da08e0074517f40238c061/prek-0.3.2-py3-none-musllinux_1_1_i686.whl", hash = "sha256:ffb28189f976fa111e770ee94e4f298add307714568fb7d610c8a7095cb1ce59", size = 4697350, upload-time = "2026-02-06T13:50:04.526Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/14/47/98c46dcd580305b9960252a4eb966f1a7b1035c55c363f378d85662ba400/prek-0.3.2-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:f63134b3eea14421789a7335d86f99aee277cb520427196f2923b9260c60e5c5", size = 4955860, upload-time = "2026-02-06T13:49:56.581Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/73/42/1bb4bba3ff47897df11e9dfd774027cdfa135482c961a54e079af0faf45a/prek-0.3.2-py3-none-win32.whl", hash = "sha256:58c806bd1344becd480ef5a5ba348846cc000af0e1fbe854fef91181a2e06461", size = 4267619, upload-time = "2026-02-06T13:49:39.503Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/97/11/6665f47a7c350d83de17403c90bbf7a762ef50876ece456a86f64f46fbfb/prek-0.3.2-py3-none-win_amd64.whl", hash = "sha256:70114b48e9eb8048b2c11b4c7715ce618529c6af71acc84dd8877871a2ef71a6", size = 4624324, upload-time = "2026-02-06T13:49:45.922Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/e7/740997ca82574d03426f897fd88afe3fc8a7306b8c7ea342a8bc1c538488/prek-0.3.2-py3-none-win_arm64.whl", hash = "sha256:9144d176d0daa2469a25c303ef6f6fa95a8df015eb275232f5cb53551ecefef0", size = 4336008, upload-time = "2026-02-06T13:49:52.27Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1348,36 +1285,6 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b9/f9/c9757a984c4ffb6d12fab69e966d95dfc862a5d44e12b7900f3a03780b76/pyside6_essentials-6.10.2-cp39-abi3-win_arm64.whl", hash = "sha256:db5f4913648bb6afddb8b347edae151ee2378f12bceb03c8b2515a530a4b38d9", size = 55258626, upload-time = "2026-02-02T08:46:36.788Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "9.0.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
{ name = "iniconfig" },
|
||||
{ name = "packaging" },
|
||||
{ name = "pluggy" },
|
||||
{ name = "pygments" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-cov"
|
||||
version = "7.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "coverage" },
|
||||
{ name = "pluggy" },
|
||||
{ name = "pytest" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "python-dateutil"
|
||||
version = "2.9.0.post0"
|
||||
@@ -1664,10 +1571,8 @@ dev = [
|
||||
{ name = "bump-my-version" },
|
||||
{ name = "icecream" },
|
||||
{ name = "nuitka" },
|
||||
{ name = "prek" },
|
||||
{ name = "pyinstaller" },
|
||||
{ name = "pytest" },
|
||||
{ name = "pytest-cov" },
|
||||
{ name = "ty" },
|
||||
]
|
||||
swbtest = [
|
||||
{ name = "alive-progress" },
|
||||
@@ -1708,10 +1613,8 @@ dev = [
|
||||
{ name = "bump-my-version", specifier = ">=0.29.0" },
|
||||
{ name = "icecream", specifier = ">=2.1.4" },
|
||||
{ name = "nuitka", specifier = ">=2.5.9" },
|
||||
{ name = "prek", specifier = ">=0.3.2" },
|
||||
{ name = "pyinstaller", specifier = ">=6.17.0" },
|
||||
{ name = "pytest" },
|
||||
{ name = "pytest-cov" },
|
||||
{ name = "ty", specifier = ">=0.0.15" },
|
||||
]
|
||||
swbtest = [{ name = "alive-progress", specifier = ">=3.3.0" }]
|
||||
|
||||
@@ -1790,30 +1693,6 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf", size = 78374, upload-time = "2026-02-03T17:35:50.982Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ty"
|
||||
version = "0.0.15"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/4e/25/257602d316b9333089b688a7a11b33ebc660b74e8dacf400dc3dfdea1594/ty-0.0.15.tar.gz", hash = "sha256:4f9a5b8df208c62dba56e91b93bed8b5bb714839691b8cff16d12c983bfa1174", size = 5101936, upload-time = "2026-02-05T01:06:34.922Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/c5/35626e732b79bf0e6213de9f79aff59b5f247c0a1e3ce0d93e675ab9b728/ty-0.0.15-py3-none-linux_armv6l.whl", hash = "sha256:68e092458516c61512dac541cde0a5e4e5842df00b4e81881ead8f745ddec794", size = 10138374, upload-time = "2026-02-05T01:07:03.804Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d5/8a/48fd81664604848f79d03879b3ca3633762d457a069b07e09fb1b87edd6e/ty-0.0.15-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:79f2e75289eae3cece94c51118b730211af4ba5762906f52a878041b67e54959", size = 9947858, upload-time = "2026-02-05T01:06:47.453Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/85/c1ac8e97bcd930946f4c94db85b675561d590b4e72703bf3733419fc3973/ty-0.0.15-py3-none-macosx_11_0_arm64.whl", hash = "sha256:112a7b26e63e48cc72c8c5b03227d1db280cfa57a45f2df0e264c3a016aa8c3c", size = 9443220, upload-time = "2026-02-05T01:06:44.98Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/d9/244bc02599d950f7a4298fbc0c1b25cc808646b9577bdf7a83470b2d1cec/ty-0.0.15-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71f62a2644972975a657d9dc867bf901235cde51e8d24c20311067e7afd44a56", size = 9949976, upload-time = "2026-02-05T01:07:01.515Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/ab/3a0daad66798c91a33867a3ececf17d314ac65d4ae2bbbd28cbfde94da63/ty-0.0.15-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9e48b42be2d257317c85b78559233273b655dd636fc61e7e1d69abd90fd3cba4", size = 9965918, upload-time = "2026-02-05T01:06:54.283Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/39/4e/e62b01338f653059a7c0cd09d1a326e9a9eedc351a0f0de9db0601658c3d/ty-0.0.15-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27dd5b52a421e6871c5bfe9841160331b60866ed2040250cb161886478ab3e4f", size = 10424943, upload-time = "2026-02-05T01:07:08.777Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/65/b5/7aa06655ce69c0d4f3e845d2d85e79c12994b6d84c71699cfb437e0bc8cf/ty-0.0.15-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76b85c9ec2219e11c358a7db8e21b7e5c6674a1fb9b6f633836949de98d12286", size = 10964692, upload-time = "2026-02-05T01:06:37.103Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/04/36fdfe1f3c908b471e246e37ce3d011175584c26d3853e6c5d9a0364564c/ty-0.0.15-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9e8204c61d8ede4f21f2975dce74efdb80fafb2fae1915c666cceb33ea3c90b", size = 10692225, upload-time = "2026-02-05T01:06:49.714Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/41/5bf882649bd8b64ded5fbce7fb8d77fb3b868de1a3b1a6c4796402b47308/ty-0.0.15-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af87c3be7c944bb4d6609d6c63e4594944b0028c7bd490a525a82b88fe010d6d", size = 10516776, upload-time = "2026-02-05T01:06:52.047Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/56/75/66852d7e004f859839c17ffe1d16513c1e7cc04bcc810edb80ca022a9124/ty-0.0.15-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:50dccf7398505e5966847d366c9e4c650b8c225411c2a68c32040a63b9521eea", size = 9928828, upload-time = "2026-02-05T01:06:56.647Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/65/72/96bc16c7b337a3ef358fd227b3c8ef0c77405f3bfbbfb59ee5915f0d9d71/ty-0.0.15-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:bd797b8f231a4f4715110259ad1ad5340a87b802307f3e06d92bfb37b858a8f3", size = 9978960, upload-time = "2026-02-05T01:06:29.567Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/18/d2e316a35b626de2227f832cd36d21205e4f5d96fd036a8af84c72ecec1b/ty-0.0.15-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9deb7f20e18b25440a9aa4884f934ba5628ef456dbde91819d5af1a73da48af3", size = 10135903, upload-time = "2026-02-05T01:06:59.256Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/02/d3/b617a79c9dad10c888d7c15cd78859e0160b8772273637b9c4241a049491/ty-0.0.15-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7b31b3de031255b90a5f4d9cb3d050feae246067c87130e5a6861a8061c71754", size = 10615879, upload-time = "2026-02-05T01:07:06.661Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/b0/2652a73c71c77296a6343217063f05745da60c67b7e8a8e25f2064167fce/ty-0.0.15-py3-none-win32.whl", hash = "sha256:9362c528ceb62c89d65c216336d28d500bc9f4c10418413f63ebc16886e16cc1", size = 9578058, upload-time = "2026-02-05T01:06:42.928Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/84/6e/08a4aedebd2a6ce2784b5bc3760e43d1861f1a184734a78215c2d397c1df/ty-0.0.15-py3-none-win_amd64.whl", hash = "sha256:4db040695ae67c5524f59cb8179a8fa277112e69042d7dfdac862caa7e3b0d9c", size = 10457112, upload-time = "2026-02-05T01:06:39.885Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/be/1991f2bc12847ae2d4f1e3ac5dcff8bb7bc1261390645c0755bb55616355/ty-0.0.15-py3-none-win_arm64.whl", hash = "sha256:e5a98d4119e77d6136461e16ae505f8f8069002874ab073de03fbcb1a5e8bf25", size = 9937490, upload-time = "2026-02-05T01:06:32.388Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.15.0"
|
||||
|
||||
Reference in New Issue
Block a user