librus-python-api 1.6.0__tar.gz → 1.6.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/CHANGELOG.md +10 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/PKG-INFO +6 -6
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/README.md +5 -5
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/__init__.py +1 -1
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/config.py +4 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/markup.py +4 -2
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/school_reads.py +18 -3
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/.gitignore +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/API.md +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/LICENSE +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/SECURITY.md +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/pyproject.toml +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/_notification_bootstrap.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/_notification_codec.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/_storage.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/_windows_filesystem.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/announcements.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/attachment_routes.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/attachments.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/attendance.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/attendance_frequency.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/budget.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/checkpoint.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/class_free_days.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/completed_lessons.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/detail_fields.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/diagnostics.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/exceptions.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/files.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/formative_grades.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/grade_parsers.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/grade_records.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/homework_range.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/lifecycle.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/message_content.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/messages.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/models.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/modern_body.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/modern_mailbox.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/modern_messages.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/notification_models.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/notification_persistence.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/notification_workflow.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/notifications.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/parsers.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/parsing.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/persistence.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/py.typed +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/recipients.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/scheduler.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/school_year_archive.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/sending.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/service.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/timetable.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/transport.py +0 -0
- {librus_python_api-1.6.0 → librus_python_api-1.6.1}/uv.lock +0 -0
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.6.1 (2026-10-12) - Sunday grade dates and calendar closures
|
|
4
|
+
|
|
5
|
+
- Accept both observed Sunday tooltip labels, `nd.` and `ndz.`, while retaining
|
|
6
|
+
the original grade metadata and strict rejection of unknown date suffixes.
|
|
7
|
+
- Preserve calendar closure events whose handler targets the separate closure
|
|
8
|
+
details page. Such events retain their text and date with `reference=None`;
|
|
9
|
+
they are never misrouted to ordinary agenda details or fetched automatically.
|
|
10
|
+
- Add regressions based on guarded structure-only observations with independently
|
|
11
|
+
authored text and IDs. Unknown closure handlers still fail closed.
|
|
12
|
+
|
|
3
13
|
## 1.6.0 (2026-10-09) - Class free days and capability outcomes
|
|
4
14
|
|
|
5
15
|
Compatible minor release with a new typed module-unavailable outcome. Consumers
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: librus-python-api
|
|
3
|
-
Version: 1.6.
|
|
3
|
+
Version: 1.6.1
|
|
4
4
|
Summary: Independent bounded async Librus Synergia client
|
|
5
5
|
Project-URL: Repository, https://github.com/krzysztofbury/librus-python-api
|
|
6
6
|
Project-URL: Issues, https://github.com/krzysztofbury/librus-python-api/issues
|
|
@@ -42,9 +42,9 @@ private ACLs. Windows installations include `pywin32` and `tzdata` automatically
|
|
|
42
42
|
Network paths, reparse-point paths and unsafe storage permissions fail closed.
|
|
43
43
|
See [platform requirements](contracts/persistence.md#windows-disk-boundary-25).
|
|
44
44
|
|
|
45
|
-
**Status:** `1.6.
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
**Status:** `1.6.1` fixes Sunday grade-date labels and calendar closure events.
|
|
46
|
+
Class free days, typed capability outcomes and the live-check freshness watchdog
|
|
47
|
+
remain available. See [verification](VERIFICATION.md).
|
|
48
48
|
The stable 1.x API does not guarantee every school layout. School features depend
|
|
49
49
|
on what each account can access. See the [compatibility policy](API.md#compatibility-policy).
|
|
50
50
|
See [limitations](#supported-features-and-limitations) below.
|
|
@@ -54,7 +54,7 @@ See [limitations](#supported-features-and-limitations) below.
|
|
|
54
54
|
Install the exact release from PyPI after its gated publication completes:
|
|
55
55
|
|
|
56
56
|
```sh
|
|
57
|
-
python -m pip install librus-python-api==1.6.
|
|
57
|
+
python -m pip install librus-python-api==1.6.1
|
|
58
58
|
```
|
|
59
59
|
|
|
60
60
|
Pin the exact version qualified by your application. Before publication, use a
|
|
@@ -70,7 +70,7 @@ python -m pip install .
|
|
|
70
70
|
To install a locally built wheel instead:
|
|
71
71
|
|
|
72
72
|
```sh
|
|
73
|
-
python -m pip install ./dist/librus_python_api-1.6.
|
|
73
|
+
python -m pip install ./dist/librus_python_api-1.6.1-py3-none-any.whl
|
|
74
74
|
```
|
|
75
75
|
|
|
76
76
|
No CLI or background process is installed: import the library in your own program.
|
|
@@ -16,9 +16,9 @@ private ACLs. Windows installations include `pywin32` and `tzdata` automatically
|
|
|
16
16
|
Network paths, reparse-point paths and unsafe storage permissions fail closed.
|
|
17
17
|
See [platform requirements](contracts/persistence.md#windows-disk-boundary-25).
|
|
18
18
|
|
|
19
|
-
**Status:** `1.6.
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
**Status:** `1.6.1` fixes Sunday grade-date labels and calendar closure events.
|
|
20
|
+
Class free days, typed capability outcomes and the live-check freshness watchdog
|
|
21
|
+
remain available. See [verification](VERIFICATION.md).
|
|
22
22
|
The stable 1.x API does not guarantee every school layout. School features depend
|
|
23
23
|
on what each account can access. See the [compatibility policy](API.md#compatibility-policy).
|
|
24
24
|
See [limitations](#supported-features-and-limitations) below.
|
|
@@ -28,7 +28,7 @@ See [limitations](#supported-features-and-limitations) below.
|
|
|
28
28
|
Install the exact release from PyPI after its gated publication completes:
|
|
29
29
|
|
|
30
30
|
```sh
|
|
31
|
-
python -m pip install librus-python-api==1.6.
|
|
31
|
+
python -m pip install librus-python-api==1.6.1
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
Pin the exact version qualified by your application. Before publication, use a
|
|
@@ -44,7 +44,7 @@ python -m pip install .
|
|
|
44
44
|
To install a locally built wheel instead:
|
|
45
45
|
|
|
46
46
|
```sh
|
|
47
|
-
python -m pip install ./dist/librus_python_api-1.6.
|
|
47
|
+
python -m pip install ./dist/librus_python_api-1.6.1-py3-none-any.whl
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
No CLI or background process is installed: import the library in your own program.
|
|
@@ -138,7 +138,7 @@ from librus_python_api.models import (
|
|
|
138
138
|
from librus_python_api.sending import SendAttempt
|
|
139
139
|
from librus_python_api.service import AccountClient, LibrusService
|
|
140
140
|
|
|
141
|
-
__version__ = "1.6.
|
|
141
|
+
__version__ = "1.6.1"
|
|
142
142
|
|
|
143
143
|
__all__ = [
|
|
144
144
|
"ArchiveAbsences",
|
|
@@ -860,6 +860,8 @@ HOMEWORK_MARK_DONE_HANDLER = (
|
|
|
860
860
|
r"\s*showConfirmQuestion\(\s*[0-9]{1,64}\s*,\s*[0-9]{1,64}\s*\);?\s*"
|
|
861
861
|
)
|
|
862
862
|
WEEKDAY_LABELS = ("pon.", "wt.", "śr.", "czw.", "pt.", "sob.", "ndz.")
|
|
863
|
+
# Grade tooltips also use the short Sunday display label.
|
|
864
|
+
CIVIL_DATE_WEEKDAY_LABELS = frozenset((*WEEKDAY_LABELS, "nd."))
|
|
863
865
|
# Observed page-level notices shown instead of the requested content.
|
|
864
866
|
PAGE_NOTICES = MappingProxyType(
|
|
865
867
|
{
|
|
@@ -881,6 +883,8 @@ COMPLETED_LESSONS_MAX_PAGE_ITEMS = 256
|
|
|
881
883
|
COMPLETED_LESSONS_MAX_BATCH_PAGES = 8
|
|
882
884
|
COMPLETED_LESSONS_MAX_BATCH_ITEMS = 256
|
|
883
885
|
AGENDA_DETAIL_PATH_PREFIX = "/terminarz/szczegoly/"
|
|
886
|
+
# Recognition only: closure details are not ordinary agenda-detail references.
|
|
887
|
+
AGENDA_CLOSURE_DETAIL_PATH_PREFIX = "/terminarz/szczegoly_wolne/"
|
|
884
888
|
HOMEWORK_DETAIL_PATH_PREFIX = "/moje_zadania/podglad/"
|
|
885
889
|
MESSAGE_MAX_PAGE_COUNT = 1000
|
|
886
890
|
MESSAGE_MAX_PAGE_ITEMS = 50
|
|
@@ -9,11 +9,11 @@ from lxml import etree, html
|
|
|
9
9
|
|
|
10
10
|
from librus_python_api.config import (
|
|
11
11
|
ATTENDANCE_DETAIL_PATH_PREFIX,
|
|
12
|
+
CIVIL_DATE_WEEKDAY_LABELS,
|
|
12
13
|
GRADE_MAX_COLUMNS,
|
|
13
14
|
GRADE_MAX_METADATA_FIELDS,
|
|
14
15
|
GRADE_MAX_METADATA_LENGTH,
|
|
15
16
|
UPSTREAM_ORIGINS,
|
|
16
|
-
WEEKDAY_LABELS,
|
|
17
17
|
)
|
|
18
18
|
from librus_python_api.exceptions import ErrorKind, LibrusError
|
|
19
19
|
from librus_python_api.parsers import parse_html_document
|
|
@@ -109,7 +109,9 @@ def tooltip_fields(element: html.HtmlElement) -> dict[str, str]:
|
|
|
109
109
|
def civil_date(value: str | None) -> date:
|
|
110
110
|
"""An ISO date, optionally followed by its weekday label in parentheses."""
|
|
111
111
|
match = re.fullmatch(r"([0-9]{4}-[0-9]{2}-[0-9]{2})(?: \(([^()]+)\))?", value or "")
|
|
112
|
-
if match is None or (
|
|
112
|
+
if match is None or (
|
|
113
|
+
match[2] is not None and match[2] not in CIVIL_DATE_WEEKDAY_LABELS
|
|
114
|
+
):
|
|
113
115
|
raise LibrusError(ErrorKind.PARSE)
|
|
114
116
|
try:
|
|
115
117
|
return date.fromisoformat(match[1])
|
|
@@ -9,6 +9,7 @@ from lxml import html
|
|
|
9
9
|
|
|
10
10
|
from librus_python_api import markup
|
|
11
11
|
from librus_python_api.config import (
|
|
12
|
+
AGENDA_CLOSURE_DETAIL_PATH_PREFIX,
|
|
12
13
|
AGENDA_DESCRIPTION_LABEL,
|
|
13
14
|
AGENDA_DETAIL_PATH_PREFIX,
|
|
14
15
|
AGENDA_TOOLTIP_LABELS,
|
|
@@ -42,13 +43,14 @@ def school_reference(
|
|
|
42
43
|
) -> SchoolReference | None:
|
|
43
44
|
"""Find the single detail link.
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
mark-done button;
|
|
46
|
+
Closure handlers stay inert without an ordinary agenda-detail reference.
|
|
47
|
+
Homework rows also carry a mark-done button; handlers are never followed.
|
|
47
48
|
"""
|
|
48
49
|
prefix = (
|
|
49
50
|
AGENDA_DETAIL_PATH_PREFIX if kind == "agenda" else HOMEWORK_DETAIL_PATH_PREFIX
|
|
50
51
|
)
|
|
51
52
|
found: set[str] = set()
|
|
53
|
+
closure = False
|
|
52
54
|
for node in nodes:
|
|
53
55
|
if not isinstance(node.tag, str):
|
|
54
56
|
continue
|
|
@@ -57,6 +59,19 @@ def school_reference(
|
|
|
57
59
|
raise LibrusError(ErrorKind.LIMIT)
|
|
58
60
|
if not action:
|
|
59
61
|
continue
|
|
62
|
+
if (
|
|
63
|
+
kind == "agenda"
|
|
64
|
+
and node is nodes[0]
|
|
65
|
+
and node.tag == "td"
|
|
66
|
+
and re.fullmatch(
|
|
67
|
+
r"location\.href='"
|
|
68
|
+
+ re.escape(AGENDA_CLOSURE_DETAIL_PATH_PREFIX)
|
|
69
|
+
+ r"[0-9]{1,64}'",
|
|
70
|
+
action,
|
|
71
|
+
)
|
|
72
|
+
):
|
|
73
|
+
closure = True
|
|
74
|
+
continue
|
|
60
75
|
if kind == "homework" and prefix not in action:
|
|
61
76
|
# Only the observed mark-done button is inert; anything else is new.
|
|
62
77
|
if re.fullmatch(HOMEWORK_MARK_DONE_HANDLER, action):
|
|
@@ -66,7 +81,7 @@ def school_reference(
|
|
|
66
81
|
if len(paths) != 1:
|
|
67
82
|
raise LibrusError(ErrorKind.UNSUPPORTED_CAPABILITY)
|
|
68
83
|
found.add(paths[0].removeprefix(prefix))
|
|
69
|
-
if len(found) > 1:
|
|
84
|
+
if len(found) > 1 or (closure and found):
|
|
70
85
|
raise LibrusError(ErrorKind.PARSE)
|
|
71
86
|
return SchoolReference(kind, next(iter(found)), account) if found else None
|
|
72
87
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/_notification_bootstrap.py
RENAMED
|
File without changes
|
{librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/_notification_codec.py
RENAMED
|
File without changes
|
|
File without changes
|
{librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/_windows_filesystem.py
RENAMED
|
File without changes
|
|
File without changes
|
{librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/attachment_routes.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/attendance_frequency.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/class_free_days.py
RENAMED
|
File without changes
|
{librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/completed_lessons.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/formative_grades.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/message_content.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/modern_messages.py
RENAMED
|
File without changes
|
{librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/notification_models.py
RENAMED
|
File without changes
|
|
File without changes
|
{librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/notification_workflow.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{librus_python_api-1.6.0 → librus_python_api-1.6.1}/src/librus_python_api/school_year_archive.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|