librus-python-api 1.6.0__py3-none-any.whl → 1.6.1__py3-none-any.whl

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.
@@ -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.0"
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 (match[2] is not None and match[2] not in WEEKDAY_LABELS):
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
- Agenda cells must not carry any other handler. Homework rows also carry a
46
- mark-done button; the library never follows handlers, so it is inert here.
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
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: librus-python-api
3
- Version: 1.6.0
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.0` adds class free days and a typed module-unavailable outcome,
46
- plus an independent live-check freshness watchdog and targeted mutation/load
47
- evidence. See [verification](VERIFICATION.md).
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.0
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.0-py3-none-any.whl
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.
@@ -1,4 +1,4 @@
1
- librus_python_api/__init__.py,sha256=DhWaUkE_sGZgqB1aWZh5ZUtyjfIeMJl1KhUPV5WpzLA,6513
1
+ librus_python_api/__init__.py,sha256=xKt_-6GBCNzMZZdK3BH_ItqM6TbgoB-4vwhUBjDcsNw,6513
2
2
  librus_python_api/_notification_bootstrap.py,sha256=18nzH0doXBNaZXCz-_ckIvRrlHTWV5Mm1t5m2-5eYGI,4669
3
3
  librus_python_api/_notification_codec.py,sha256=hU6G3zGJ5fR8wfPC6fV2OqBKs-7XpT9eRnKO3FGsTzY,13451
4
4
  librus_python_api/_storage.py,sha256=M_6ZAzN4zs7laOdKJBRH1I2rvy3pgqYgC_MZtsd2xtM,15893
@@ -12,7 +12,7 @@ librus_python_api/budget.py,sha256=8fvqT7eIxyVX2P2OBG27XsYHk_HbtSS4lzuecYpHtgs,2
12
12
  librus_python_api/checkpoint.py,sha256=QBmG9GtpyaGRaFq-FXuGA3yR1BjuMFN9V3RTvvi_FNQ,1930
13
13
  librus_python_api/class_free_days.py,sha256=IwoCgr-9ZgEYYQ6717s4cDpyFzbosHMzESMabXJLGqA,2422
14
14
  librus_python_api/completed_lessons.py,sha256=sR2oLSGb2q1580l-2upCBv9sQfIcHi7CQfWr1K0EFXI,7635
15
- librus_python_api/config.py,sha256=A5UNZ0oc8Oxt13y0To1REdQLWPgLrH-VRRpcuwodElc,55482
15
+ librus_python_api/config.py,sha256=ZkYxYxBy-FLNMpZSu3U9itHpoyrOCgZSG0dUdWgGGAY,55749
16
16
  librus_python_api/detail_fields.py,sha256=K10Stx_ehDTttkUI7-G7a2Ko9exYEu5NJpR-3sBnQ60,1789
17
17
  librus_python_api/diagnostics.py,sha256=2l7wq6RA3it-Gwj-JRLcw5qbI37fl3xII6GZA2mZj0o,856
18
18
  librus_python_api/exceptions.py,sha256=adVcJuzfB8wGrUlF2SfiyIlE9ZZyTAvGdWRtQIjsA3I,4879
@@ -22,7 +22,7 @@ librus_python_api/grade_parsers.py,sha256=91Kr1-TArzqO-b94ipeIR0a98OV7tRCZQdBWsd
22
22
  librus_python_api/grade_records.py,sha256=K0ZzmU1KsA8Jo1MXh30mStApgrigaOKk5ldoBnwRrH8,17901
23
23
  librus_python_api/homework_range.py,sha256=erYfvS6PhHU5XhnR6LkiLNy677hGVflY3UAuHOs-YUw,1663
24
24
  librus_python_api/lifecycle.py,sha256=XzA5CEdZFo7iL5IMUrawnRvf2m9BFe0OseP-fpQFaAE,856
25
- librus_python_api/markup.py,sha256=mjCZf6KJTWUz2vjfXbJ4zM17hnev7a5AFIOW3ip3gsE,5677
25
+ librus_python_api/markup.py,sha256=vd483NSUQbVYvSV2IaUmsyGcRhpWtbyDHMeEhbc7siA,5713
26
26
  librus_python_api/message_content.py,sha256=v_qoEAoaYS0_9MQBaj57i5XnC7pzv_HHWefgTt4CNyM,9043
27
27
  librus_python_api/messages.py,sha256=K9F8XVs1SojfFpdxxLV8gx9E0g81YxEHjigDzLHmDCg,10230
28
28
  librus_python_api/models.py,sha256=Z6eV-ftjaN8YGUW8SntVTLjGCqe1EWRpd0P1Va8EwDs,40991
@@ -39,13 +39,13 @@ librus_python_api/persistence.py,sha256=C5oDHQg1Xzy9Jb9obVsRNndCiXps-QQQtQ_M7_l5
39
39
  librus_python_api/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
40
  librus_python_api/recipients.py,sha256=6GQCKo-Zjg3VFSg1J8YXcDsy_U3r6-MUS4VCvz0xdaQ,10033
41
41
  librus_python_api/scheduler.py,sha256=3JplYxqvQdFz3aKXcoQUJHE9s3FPw_xRhQ2CPNLuQmA,10729
42
- librus_python_api/school_reads.py,sha256=PCnZ4lv44j-68FgJpQiMteaPSyfhbX8_3CUyE6zhFcQ,14760
42
+ librus_python_api/school_reads.py,sha256=YHta7DmhjS5vSa4Djq8pzp01-2jhVfGOo1Mnc738rV4,15209
43
43
  librus_python_api/school_year_archive.py,sha256=D0A1ywMKgoYgvi-d70__SFreMGvMb_72870Akkbb_m8,15492
44
44
  librus_python_api/sending.py,sha256=Nvvk2r-6D6Us53a2fH5GW9PcA6bWEfuOvy6c3M5QVcE,4549
45
45
  librus_python_api/service.py,sha256=7ioLx-8C-I0Qla8YUyu5UqhjBPlcUvEFpQSYH-9yjzs,96232
46
46
  librus_python_api/timetable.py,sha256=tX1QK9fQABxzfLaHHqTe8e6rAgdOkCoTOfAHdPwNmLE,9836
47
47
  librus_python_api/transport.py,sha256=QnYXnrv1lW4qToYoTv6HyZw-Lt4rDc-_SMTJpMp6_bc,35297
48
- librus_python_api-1.6.0.dist-info/METADATA,sha256=O_HfTBq306xfvGOiGLwpWeWdHb2G9m_2c2PN9HmY4VY,11994
49
- librus_python_api-1.6.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
50
- librus_python_api-1.6.0.dist-info/licenses/LICENSE,sha256=IuerLb3cnZCsaB23znydjjvKqP-LmSJd3syKa9NGUts,1071
51
- librus_python_api-1.6.0.dist-info/RECORD,,
48
+ librus_python_api-1.6.1.dist-info/METADATA,sha256=rMKHaG2F1BVuZ7gCBUdhmQXT8Ox6wrRSsiyN4UQXqqg,12005
49
+ librus_python_api-1.6.1.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
50
+ librus_python_api-1.6.1.dist-info/licenses/LICENSE,sha256=IuerLb3cnZCsaB23znydjjvKqP-LmSJd3syKa9NGUts,1071
51
+ librus_python_api-1.6.1.dist-info/RECORD,,