Przejdź do treści

olski.werdykt

Werdykt o zdaniu: zgłoszenie wraz z tym, co autor ma przeczytać.

Werdykt mówi o zdaniu więcej niż to, do której klasy je liczy, bo autor ma na niego zareagować. Zdanie o dwóch odczytaniach dostaje wiersz z tymi odczytaniami, a Verdict.explain pokazuje, gdzie one się rozchodzą; znaleziskiem, czyli tym, co autor ma poprawić, jest zdanie, które od odczytania dzieli jeden znak (Naprawa), a wieloznaczność nim nie jest (docs/subset.md#wieloznaczność-jest-odpowiedzią-a-nie-znaleziskiem); zdanie odrzucone dostaje miejsce, na którym rozbiór stanął, a zatrzymania każde takie miejsce, bo pierwsze zasłania następne. Skąd te odczytania się biorą, mówi Verdict.morfologia: rozchodzą się w rolach, a zaczynają w lemacie i znaczniku formy.

Kto pyta o cały tekst, dostaje nad_tekstem i Podsumowanie, czyli tyle wpisów (Zdanie), ile zdań, oraz jedną odpowiedź policzoną z nich regułą. Wpis niesie obok werdyktu to, czego z jednego zdania nie widać: zdania stojące przed nim w akapicie i zaimek wskazujący na dwie rzeczy naraz.

Warstwa ta ani nie wnosi wieloznaczności, ani jej nie zdejmuje, bo jest wypowiedzią o warstwach pod nią (docs/architecture.md). Gramatykę czyta gotową z olski/subset/, a segmentację, po której werdykt pada, z olski/segmentacja.py.

Podział na moduły jest tu decyzją i idzie za tym, o co dany moduł pyta. olski.werdykt.wykazy liczy z lasu wykaz wypisywany pod każdym odczytaniem, olski.werdykt.odrzucone płaci rozbiorem drugim za dwie odpowiedzi o napisie, którego gramatyka nie wyprowadza, olski.werdykt.zdanie składa z tego werdykt o jednym zdaniu, a olski.werdykt.tekst pyta o cały tekst. Import idzie tędy w jedną stronę i żaden z tych czterech nie zawraca: wykazy i odrzucone nie wiedzą o zdaniu, a zdanie nie wie o tekście. Podkreślenie w nazwie znaczy tu prywatne dla pakietu, a nie dla modułu: poza niego wychodzą same nazwy wyliczone w __all__.

ODNIESIENIE = 'niejasne odniesienie' module-attribute

ODNIESIENIE_W_ZDANIU = 'niejasne odniesienie w zdaniu' module-attribute

POPRAWKA = 'poprawka jednego znaku' module-attribute

WIELOZNACZNE = 'wieloznaczne' module-attribute

ZGŁOSZENIA = (WIELOZNACZNE, POPRAWKA, ODNIESIENIE, ODNIESIENIE_W_ZDANIU) module-attribute

ZNALEZISKA = (POPRAWKA, ODNIESIENIE) module-attribute

BRAK_ODCZYTANIA = 'brak odczytania' module-attribute

FRAGMENT = 'fragment' module-attribute

NIEDOMKNIĘTE = 'unclosed' module-attribute

__all__ = ['BRAK_ODCZYTANIA', 'check', 'dalsze_zatrzymania', 'FRAGMENT', 'nad_tekstem', 'Naprawa', 'NIEDOMKNIĘTE', 'niespełnione_żądania', 'ODNIESIENIE', 'ODNIESIENIE_W_ZDANIU', 'OdczytaniaFormy', 'Podsumowanie', 'POPRAWKA', 'Verdict', 'werdykt', 'WIELOZNACZNE', 'zatrzymania', 'Zdanie', 'ZGŁOSZENIA', 'ZNALEZISKA', 'Żądanie'] module-attribute

Naprawa dataclass

Poprawka jednego znaku, po której olski to zdanie czyta.

Klasa jest jedna na wszystkie takie poprawki, bo autorowi mówią one to samo: olski tego zdania nie czyta, a od czytania dzieli je jeden znak. Świadkiem jest w każdej z nich gramatyka, bo poprawka wchodzi tutaj dopiero wtedy, gdy rozbiór poprawionego napisu daje odczytanie. Reguła stojąca na takim świadku nie żąda kalibracji, której brak zamknął pakiet reguł (docs/linter.md#co-zamknęło-pakiet-reguł).

Liczba odczytań idzie razem z poprawką, bo policzona drugi raz żądałaby trzeciego rozbioru nad zdaniem, które werdykt rozebrał już dwa razy.

Source code in olski/werdykt/odrzucone.py
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
@dataclass(frozen=True)
class Naprawa:
    """Poprawka jednego znaku, po której olski to zdanie czyta.

    Klasa jest jedna na wszystkie takie poprawki, bo autorowi mówią one to samo:
    olski tego zdania nie czyta, a od czytania dzieli je jeden znak. Świadkiem
    jest w każdej z nich gramatyka, bo poprawka wchodzi tutaj dopiero wtedy, gdy
    rozbiór poprawionego napisu daje odczytanie. Reguła stojąca na takim świadku
    nie żąda kalibracji, której brak zamknął pakiet reguł
    (docs/linter.md#co-zamknęło-pakiet-reguł).

    Liczba odczytań idzie razem z poprawką, bo policzona drugi raz żądałaby
    trzeciego rozbioru nad zdaniem, które werdykt rozebrał już dwa razy.
    """

    #: Co autor ma poprawić, tak jak to stoi w wierszu werdyktu.
    poprawka: str
    #: Liczba odczytań, które olski nad poprawionym napisem czyta.
    czytań: int

poprawka instance-attribute

czytań instance-attribute

__init__(poprawka, czytań)

Podsumowanie dataclass

Znaleziska nad tekstem i to, o czym olski milczy, dla tego, kto pyta o cały tekst.

Liczby te wychodzą z wpisów jedną regułą — fragment nie jest zdaniem, więc nie wchodzi do mianownika, a zdanie odrzucone jest milczeniem, dopóki nie ma poprawki — i pyta o nie więcej niż jeden wołający, więc policzone u każdego z nich rozjeżdżają się po cichu: mianownik mniejszy o fragment czyta się jak pomiar, a nie jak pomyłka.

Zdanie naprawialne stoi w dwóch licznikach naraz, w naprawialne i w bez_odczytania, bo gramatyka go nie wyprowadza i pokrycie liczy je tak samo jak przedtem: znalezisko mówi o autorze, a nie o podzbiorze.

Source code in olski/werdykt/tekst.py
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
@dataclass(frozen=True)
class Podsumowanie:
    """Znaleziska nad tekstem i to, o czym olski milczy, dla tego, kto pyta o cały tekst.

    Liczby te wychodzą z wpisów jedną regułą — fragment nie jest zdaniem, więc
    nie wchodzi do mianownika, a zdanie odrzucone jest milczeniem, dopóki nie ma
    poprawki — i pyta o nie więcej niż jeden wołający, więc policzone u każdego z
    nich rozjeżdżają się po cichu: mianownik mniejszy o fragment czyta się jak
    pomiar, a nie jak pomyłka.

    Zdanie naprawialne stoi w dwóch licznikach naraz, w :attr:`naprawialne` i w
    :attr:`bez_odczytania`, bo gramatyka go nie wyprowadza i pokrycie liczy je
    tak samo jak przedtem: znalezisko mówi o autorze, a nie o podzbiorze.
    """

    #: Zdania, czyli to, o czym werdykt orzeka: fragmentów nie ma tu ani w liczniku.
    zdań: int
    #: Zdania o kilku odczytaniach. Liczba mówi, ile zdań olski czyta na kilka
    #: sposobów, a znaleziskiem nie jest i do :attr:`znalezisk` nie wchodzi.
    wieloznaczne: int
    #: Zdania, które od odczytania dzieli jeden znak, czyli pierwsze ze znalezisk
    #: (:class:`Naprawa`). Liczba jest osobna od :attr:`wieloznaczne`, bo mówi o
    #: zdaniu rzecz przeciwną: tamto olski czyta i ma o nim za dużo do
    #: powiedzenia, a to zdanie czyta dopiero po poprawce.
    naprawialne: int
    #: Zdania, których gramatyka nie wyprowadza. Olski o nich milczy, a milczenie
    #: liczy się osobno, bo bez tej liczby przebieg nad tekstem, którego nie
    #: przeczytał, czytałby się jak czysty.
    bez_odczytania: int
    #: Napisy, których nic nie interpunkuje jako zdania. Liczba jest jedna na oba
    #: werdykty o takim napisie, :data:`FRAGMENT` i :data:`NIEDOMKNIĘTE`, bo o
    #: mianowniku rozstrzyga jedno i to samo: domknięcia nie postawił nikt.
    fragmentów: int
    #: Zdania z zaimkiem, który wskazuje na dwie rzeczy naraz, czyli drugie ze
    #: znalezisk (``olski/odniesienia.py``). Zdanie wieloznaczne z takim zaimkiem
    #: stoi w dwóch licznikach naraz, tak samo jak zdanie naprawialne, i z tego
    #: samego powodu: liczby mówią o zdaniu co innego.
    niejasnych_odniesień: int

    @property
    def znalezisk(self) -> int:
        """Ile znalezisk narzędzie ma nad tekstem, bez względu na to, które.

        Pyta o to kod wyjścia (``olski/check.py``), bo o samym znalezisku
        rozstrzyga tu jedno miejsce, a znalezisko dopisane później dostaje ten
        kod wyjścia razem z własnym licznikiem. Wieloznaczność do tej liczby nie
        wchodzi (:data:`ZNALEZISKA`).
        """
        return self.naprawialne + self.niejasnych_odniesień

    @classmethod
    def ze_zdań(cls, zdania: Sequence[Zdanie]) -> Podsumowanie:
        """Podsumowanie tych zdań, choćby przyszły z kilku plików naraz."""
        punktowane = [wpis.werdykt for wpis in zdania if wpis.werdykt.punktowane]
        ile = collections.Counter(nazwa for wpis in zdania for nazwa in wpis.zgłoszenia)
        return cls(
            zdań=len(punktowane),
            wieloznaczne=ile[WIELOZNACZNE],
            naprawialne=ile[POPRAWKA],
            bez_odczytania=sum(verdict.result.rejected for verdict in punktowane),
            fragmentów=len(zdania) - len(punktowane),
            niejasnych_odniesień=ile[ODNIESIENIE],
        )

    def explain(self) -> str:
        #  Wiersz jest listą par, a nie zdaniem: liczba stoi za dwukropkiem, więc
        #  nie żąda zgody od słowa przed sobą i nic tu się nie odmienia.
        podsumowanie = (
            f"zdań: {self.zdań}; wieloznaczne: {self.wieloznaczne};"
            f" bez odczytania: {self.bez_odczytania}"
        )
        #  Wiersz rośnie o tę parę dopiero tam, gdzie poprawka pada, bo nad
        #  tekstem bez ani jednej mówiłaby zero o znalezisku, którego nie ma.
        if self.naprawialne:
            podsumowanie += f"; do poprawki jednym znakiem: {self.naprawialne}"
        #  Ta para rośnie pod tym samym warunkiem i z tego samego powodu.
        if self.niejasnych_odniesień:
            podsumowanie += f"; niejasne odniesienia: {self.niejasnych_odniesień}"
        if self.fragmentów:
            #  Nie „fragmenty, które nie są zdaniami”: napis niedomknięty jest w tej
            #  liczbie, a werdykt nad nim mówi, że olski to zdanie czyta.
            podsumowanie += f"; fragmenty, których nic nie punktuje jako zdania: {self.fragmentów}"
        return podsumowanie

zdań instance-attribute

wieloznaczne instance-attribute

naprawialne instance-attribute

bez_odczytania instance-attribute

fragmentów instance-attribute

niejasnych_odniesień instance-attribute

znalezisk property

Ile znalezisk narzędzie ma nad tekstem, bez względu na to, które.

Pyta o to kod wyjścia (olski/check.py), bo o samym znalezisku rozstrzyga tu jedno miejsce, a znalezisko dopisane później dostaje ten kod wyjścia razem z własnym licznikiem. Wieloznaczność do tej liczby nie wchodzi (ZNALEZISKA).

ze_zdań(zdania) classmethod

Podsumowanie tych zdań, choćby przyszły z kilku plików naraz.

Source code in olski/werdykt/tekst.py
173
174
175
176
177
178
179
180
181
182
183
184
185
@classmethod
def ze_zdań(cls, zdania: Sequence[Zdanie]) -> Podsumowanie:
    """Podsumowanie tych zdań, choćby przyszły z kilku plików naraz."""
    punktowane = [wpis.werdykt for wpis in zdania if wpis.werdykt.punktowane]
    ile = collections.Counter(nazwa for wpis in zdania for nazwa in wpis.zgłoszenia)
    return cls(
        zdań=len(punktowane),
        wieloznaczne=ile[WIELOZNACZNE],
        naprawialne=ile[POPRAWKA],
        bez_odczytania=sum(verdict.result.rejected for verdict in punktowane),
        fragmentów=len(zdania) - len(punktowane),
        niejasnych_odniesień=ile[ODNIESIENIE],
    )

explain()

Source code in olski/werdykt/tekst.py
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
def explain(self) -> str:
    #  Wiersz jest listą par, a nie zdaniem: liczba stoi za dwukropkiem, więc
    #  nie żąda zgody od słowa przed sobą i nic tu się nie odmienia.
    podsumowanie = (
        f"zdań: {self.zdań}; wieloznaczne: {self.wieloznaczne};"
        f" bez odczytania: {self.bez_odczytania}"
    )
    #  Wiersz rośnie o tę parę dopiero tam, gdzie poprawka pada, bo nad
    #  tekstem bez ani jednej mówiłaby zero o znalezisku, którego nie ma.
    if self.naprawialne:
        podsumowanie += f"; do poprawki jednym znakiem: {self.naprawialne}"
    #  Ta para rośnie pod tym samym warunkiem i z tego samego powodu.
    if self.niejasnych_odniesień:
        podsumowanie += f"; niejasne odniesienia: {self.niejasnych_odniesień}"
    if self.fragmentów:
        #  Nie „fragmenty, które nie są zdaniami”: napis niedomknięty jest w tej
        #  liczbie, a werdykt nad nim mówi, że olski to zdanie czyta.
        podsumowanie += f"; fragmenty, których nic nie punktuje jako zdania: {self.fragmentów}"
    return podsumowanie

__init__(zdań, wieloznaczne, naprawialne, bez_odczytania, fragmentów, niejasnych_odniesień)

Zdanie dataclass

Jedno zdanie tekstu: werdykt o nim wraz z tym, co dokłada tekst wokół.

Werdykt orzeka o samym zdaniu, a dwa pozostałe pola biorą się z akapitu, bo zdanie samo nie wie, co stoi przed nim.

Source code in olski/werdykt/tekst.py
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
@dataclass(frozen=True)
class Zdanie:
    """Jedno zdanie tekstu: werdykt o nim wraz z tym, co dokłada tekst wokół.

    Werdykt orzeka o samym zdaniu, a dwa pozostałe pola biorą się z akapitu,
    bo zdanie samo nie wie, co stoi przed nim.
    """

    werdykt: Verdict
    #: Zdania, które w tym akapicie stoją przed tym; czyta je ``olski/rozstrzyganie.py``.
    sąsiedztwo: Sąsiedztwo
    #: Zaimki wskazujące na dwie rzeczy naraz, drugie ze znalezisk (``olski/odniesienia.py``).
    odniesienia: tuple[Odniesienie, ...]

    @property
    def zgłoszenia(self) -> tuple[str, ...]:
        """Nazwy zgłoszeń, które olski ma o tym zdaniu, w kolejności :data:`ZGŁOSZENIA`.

        Jedno miejsce mówi, co olski nad zdaniem zgłasza: liczy z niego
        :class:`Podsumowanie` i ocenia je baza sądów (``harness/sądy.py``).
        Napis niepunktowany nie ma żadnego, jak w :attr:`Verdict.zgłoszenie`.
        """
        if not self.werdykt.punktowane:
            return ()
        obecne = {
            WIELOZNACZNE: bool(self.werdykt.result.ambiguous),
            POPRAWKA: self.werdykt.naprawa is not None,
            ODNIESIENIE: any(not o.w_zdaniu for o in self.odniesienia),
            ODNIESIENIE_W_ZDANIU: any(o.w_zdaniu for o in self.odniesienia),
        }
        return tuple(nazwa for nazwa in ZGŁOSZENIA if obecne[nazwa])

    @property
    def znaleziska(self) -> tuple[str, ...]:
        """Te ze zgłoszeń, które są znaleziskiem (:data:`ZNALEZISKA`)."""
        return tuple(nazwa for nazwa in self.zgłoszenia if nazwa in ZNALEZISKA)

werdykt instance-attribute

sąsiedztwo instance-attribute

odniesienia instance-attribute

zgłoszenia property

Nazwy zgłoszeń, które olski ma o tym zdaniu, w kolejności ZGŁOSZENIA.

Jedno miejsce mówi, co olski nad zdaniem zgłasza: liczy z niego Podsumowanie i ocenia je baza sądów (harness/sądy.py). Napis niepunktowany nie ma żadnego, jak w Verdict.zgłoszenie.

znaleziska property

Te ze zgłoszeń, które są znaleziskiem (ZNALEZISKA).

__init__(werdykt, sąsiedztwo, odniesienia)

OdczytaniaFormy dataclass

Forma zdania wraz z odczytaniami, którymi tam stać może, każde napisem.

Odczytanie jest napisem, a nie parą lematu i znacznika, bo oba wydruki wypisują je razem, a rozdzielone kazałyby każdemu z nich składać ten napis osobno.

Source code in olski/werdykt/wykazy.py
29
30
31
32
33
34
35
36
37
38
39
@dataclass(frozen=True)
class OdczytaniaFormy:
    """Forma zdania wraz z odczytaniami, którymi tam stać może, każde napisem.

    Odczytanie jest napisem, a nie parą lematu i znacznika, bo oba wydruki
    wypisują je razem, a rozdzielone kazałyby każdemu z nich składać ten napis
    osobno.
    """

    forma: str
    odczytania: tuple[str, ...]

forma instance-attribute

odczytania instance-attribute

__init__(forma, odczytania)

Żądanie dataclass

Czego czasownik zdania żąda od tego, co w jego pozycji stanęło.

Wiersz jest jeden na obsadzoną pozycję, a nie jeden na rolę, bo jedna rola obsadza czasem dwie pozycje naraz: Autor doradza czytelnikowi poprawkę. ma dopełnienie w celowniku obok dopełnienia w bierniku, a czasownik żąda od nich czego innego.

Source code in olski/werdykt/wykazy.py
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
@dataclass(frozen=True)
class Żądanie:
    """Czego czasownik zdania żąda od tego, co w jego pozycji stanęło.

    Wiersz jest jeden na obsadzoną pozycję, a nie jeden na rolę, bo jedna rola
    obsadza czasem dwie pozycje naraz: `Autor doradza czytelnikowi poprawkę.`
    ma dopełnienie w celowniku obok dopełnienia w bierniku, a czasownik żąda
    od nich czego innego.
    """

    #: Rola, którą streszczenie nazywa to wypełnienie.
    rola: str
    #: Formy wypełnienia i forma czasownika, tak jak stoją w zdaniu.
    wypełnienie: str
    czasownik: str
    #: Żądane klasy jako alternatywa, nazwane przed nienazwanymi
    #: (:data:`olski.żądania.NIENAZWANE`), a w każdej z tych grup alfabetycznie.
    klasy: tuple[str, ...]
    #: Lematy głowy wypełnienia, czyli słowa, którymi ta pozycja stoi. O nie pyta
    #: deklaracja osób (``olski/osoby.py``), bo deklaruje się lemat, a nie formę.
    #: Poza porównaniem, bo wiersz jest o pozycji, a nie o głowie, i dwa kształty
    #: dają czasem tę samą pozycję o dwóch głowach (:func:`_zwinięte`).
    lematy: frozenset[str] = field(compare=False)

rola instance-attribute

wypełnienie instance-attribute

czasownik instance-attribute

klasy instance-attribute

lematy = field(compare=False) class-attribute instance-attribute

__init__(rola, wypełnienie, czasownik, klasy, lematy)

Verdict dataclass

What olski says about one sentence.

Source code in olski/werdykt/zdanie.py
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
@dataclass(frozen=True)
class Verdict:
    """What olski says about one sentence."""

    #: Zdanie tak, jak stoi w tekście. Segmenty są krawędziami grafu, a nie
    #: listą, więc sklejone dają naraz każdy podział, jaki Morfeusz na formie
    #: widzi: ``ktoś`` wychodzi wtedy jako ``kto ktoś ś``.
    text: str
    result: Result
    #: Formy nie do ominięcia, którym żadna produkcja nie bierze ani jednego
    #: czytania: odrzucenie stanęło na nich, a nie na strukturze. Pola bez
    #: wartości domyślnej, bo pusta krotka jest tu twierdzeniem o zdaniu, a
    #: ``Nowa program zapisuje ustawienia.`` ma je puste i jest odrzucone.
    nielicencjonowane: tuple[str, ...]
    #: Forma, której nie wzięła ani jedna analiza częściowa, czyli miejsce, na
    #: którym odrzucenie stanęło; ``None``, gdy analiza doszła do ostatniego
    #: znaku zdania. Pola bez wartości domyślnej z tego samego powodu co wyżej:
    #: ``None`` jest tu twierdzeniem, a nie brakiem odpowiedzi.
    #: Twierdzeniem jest tylko wtedy, gdy o zatrzymanie pytano.
    #: Przebieg, który nie pytał (:func:`werdykt`), zostawia tu również ``None``.
    #: Rozdziela te dwa ``Result.furthest`` i o niego pyta :meth:`explain`.
    zatrzymanie: str | None
    #: Poprawka jednego znaku, po której olski ten napis czyta, albo ``None``.
    #: Pole, a nie właściwość, bo :func:`olski.werdykt.odrzucone._naprawa`
    #: kosztuje rozbiór, a właściwość płaciłaby tyle razy, ile razy ktoś ją przeczyta.
    naprawa: Naprawa | None

    @property
    def punktowane(self) -> bool:
        """Czy tekst punktuje ten napis jako zdanie.

        Mianownik pomiaru pyta o to, a nie o :attr:`status`, bo odpowiedź jest ta
        sama nad oboma werdyktami o napisie niepunktowanym i nie kosztuje rozbioru,
        którego kosztuje :attr:`domknięcie`
        (:class:`olski.werdykt.tekst.Podsumowanie`).
        """
        return bool(SENTENCE_CLOSE.search(self.text))

    @property
    def zgłoszenie(self) -> bool:
        """Czy narzędzie ma o tym zdaniu coś do powiedzenia.

        Wydruk domyślny niesie dwa zgłoszenia: wieloznaczność oraz poprawkę
        jednego znaku, a znaleziskiem jest tylko druga
        (docs/subset.md#wieloznaczność-jest-odpowiedzią-a-nie-znaleziskiem).
        Zaimek wskazujący na dwie rzeczy naraz pada obok werdyktu,
        bo rzeczy nazywa zdanie obok (``olski/odniesienia.py``), więc tutaj go nie ma.
        Warunek stoi tu raz, bo pyta o niego wydruk nad każdym zdaniem osobno;
        :class:`olski.werdykt.tekst.Podsumowanie` liczy każde z tych zgłoszeń
        nad tekstem i liczy je osobno.

        Napis niepunktowany zostaje poza zgłoszeniem także wtedy, gdy poprawkę
        ma, bo nagłówek i pozycja listy dochodzą tu jako takie napisy i żadne z
        nich nie jest zdaniem, którego autor nie domknął
        (docs/extraction.md); wydruk pokazuje je do flagi ``--zatrzymania``.
        """
        return self.punktowane and (self.result.ambiguous or self.naprawa is not None)

    @property
    def czytane(self) -> bool:
        """Czy olski to zdanie czyta.

        Nieczytane są trzy: zdanie odrzucone, napis, którego nic nie domyka,
        i fragment. O polszczyźnie żadnego z nich olski nie orzeka,
        więc wydruk milczy o nich do flagi (``olski/check.py``).
        """
        return self.punktowane and not self.result.rejected

    @property
    def status(self) -> str:
        """Klasa, do której werdykt to zdanie liczy, czyli słowo pomiaru.

        Wydruk komendy go nie podaje, bo dzieli zdania po liczbie odczytań,
        a nie po tym, czy narzędzie ma o zdaniu co powiedzieć (:attr:`znalezisko`).
        Czytają je pomiar pokrycia (``olski/pokrycie.py``), sondy w ``harness/``
        i znaczek na stronie (``witryna/skrypt.js``).
        """
        if not self.punktowane:
            return NIEDOMKNIĘTE if self.naprawa else FRAGMENT
        return self.result.status

    @property
    def readings(self) -> list[tuple[dict[str, str], ...]]:
        """Streszczenia odczytań, każde raz (:func:`streszczenia`).

        Odczytanie jest krotką streszczeń, po jednym na zdanie składowe, więc
        wpisem tej listy jest krotka, a nie jedno streszczenie.

        Lista jest po to, żeby pokazać różnicę między odczytaniami,
        a różnicę spoza zasięgu streszczenia nazywa wiersz o konstytuencie
        (:func:`_rozbieżny`), więc powtórzony napis nie zostawia jej nienazwanej.
        Liczbę odczytań podaje las (:attr:`Result.ile`),
        więc skrócenie tej listy jej nie rusza.
        """
        return [
            tuple(map(_po_szkolnemu, streszczenie))
            for streszczenie in streszczenia(self.result.readings, DEKLARACJA)
        ]

    @property
    def morfologia(self) -> list[tuple[OdczytaniaFormy, ...]]:
        """Czym formy stoją w każdym odczytaniu: wpis na streszczenie z :attr:`readings`.

        Wiersz dostaje forma czytana więcej niż jednym sposobem, a odczytania w
        nim licencjonują ją w tym kształcie (:attr:`olski.parse.Leaf.odczytania`);
        wiersze składa :func:`olski.werdykt.wykazy._pod_streszczeniem`,
        a nad streszczeniem, które zbiera kilka kształtów,
        bierze odczytania z każdego z nich.
        Wpisów jest tyle, ile streszczeń, więc nad zdaniem urwanym na
        :data:`olski.parse.MAX_READINGS` mówią one o odczytaniach wypisanych.

        Zdanie bez ani jednego odczytania dostaje jeden wpis, a w nim każde
        odczytanie każdej formy (:func:`olski.werdykt.wykazy._morfologia_zdania`):
        odsiać ich nie ma czym.
        Rozstrzyga się to tutaj, a nie w wydruku, bo wydruki są dwa
        (``olski/check.py`` i ``witryna/werdykty.py``) i rozjechałyby się po cichu.
        """
        if self.result.rejected or not self.punktowane:
            return [_morfologia_zdania(self.text)]
        return [
            _pod_streszczeniem(drzewa)
            for _streszczenie, drzewa in streszczone(self.result.readings, DEKLARACJA)
        ]

    @property
    def rachunki(self) -> list[tuple[tuple[str, int], ...]]:
        """Za co płaci każde odczytanie: wpis na streszczenie z :attr:`readings`.

        Wychodzą stąd pozycje policzone, a sumę liczy z nich ten, kto ją pokazuje
        (:func:`olski.cennik.razem`): jest nią miejsce w kolejce odczytań,
        bo las porządkuje je sumą cennika po całym drzewie.

        Streszczenie zbiera czasem kilka kształtów, a rachunek jest tego, który
        wyszedł z lasu pierwszy, czyli tego, przez którego to streszczenie stoi
        tam, gdzie stoi.
        """
        return [
            cennik.rachunek(koszty_drzewa(drzewa[0]))
            for _streszczenie, drzewa in streszczone(self.result.readings, DEKLARACJA)
        ]

    @property
    def żądania(self) -> list[tuple[Żądanie, ...]]:
        """Czego czasownik żąda od obsadzonych pozycji: wpis na streszczenie z :attr:`readings`.

        Po co ta odpowiedź autorowi i czego ona nie mówi, wywodzi
        ``olski/żądania.py``; wpis jest na streszczenie z tego samego powodu, co
        przy :attr:`morfologia`, i grupuje go to samo pytanie o las.

        Warunku na zdanie odrzucone nie ma i nie ma go czemu stawiać: pozycję
        obsadza czytanie, a takie zdanie nie ma ani jednego, więc lista wychodzi
        stąd pusta sama. Morfologia ma tam wpis, bo mówi o formach, a nie o rolach.
        """
        return [
            _żądania_streszczenia(drzewa)
            for _streszczenie, drzewa in streszczone(self.result.readings, DEKLARACJA)
        ]

    @property
    def rozbieżne(self) -> list[Rozbieżność]:
        """Konstytuenty rozbieżne, którym streszczenia naprawdę się różnią.

        Jedno streszczenie znaczy, że streszczenie tej różnicy nie widzi
        (:class:`Rozbieżność`), a wypisane byłoby wierszem bez treści.
        Warunek stoi tu raz na oba wydruki, na wiersz poleceń i na witrynę,
        bo napisany dwa razy rozjechałby się po cichu.
        """
        return [r for r in self.result.rozbieżności if len(r.czytania) > 1]

    def explain(self, brak_odczytania: str = BRAK_ODCZYTANIA) -> str:
        """Co narzędzie ma o tym zdaniu do powiedzenia, jednym wierszem.

        Nazwa braku przychodzi argumentem, bo dwa tryby nazywają go różnie, a
        mówią pod obiema nazwami to samo o analizie, więc powód stoi tu raz.
        Bierze ją samo zdanie odrzucone: poprawka jednego znaku i napis, którego
        nic nie punktuje jako zdania, mówią autorowi co innego i idą przed nim.
        """
        #  Poprawka wyprzedza każde inne wyjaśnienie i wyprzedza je nad zdaniem
        #  odrzuconym tak samo jak nad napisem niedomkniętym: zatrzymanie mówi,
        #  dokąd doszła analiza, a poprawka mówi, co z tym zrobić.
        if self.naprawa is not None:
            return _naprawiony(self.naprawa)
        if self.status == FRAGMENT:
            return "to nie zdanie: nic go nie punktuje jako zdania"
        if self.result.valid:
            return _odczytań(1)
        if self.result.rejected:
            if self.nielicencjonowane:
                # Cudzysłów jest treścią: najczęstszą formą bez licencji jest
                # przecinek, a lista rozdzielana przecinkami gubi bez niego granice.
                formy = ", ".join(f"„{forma}”" for forma in self.nielicencjonowane)
                return f"{brak_odczytania}: żadna produkcja nie bierze {formy}"
            if self.result.furthest is None:
                #  Tak samo odmawia ``bloker`` w ``olski/pokrycie.py`` i z tego
                #  samego powodu: milczenie o zatrzymaniu czytałoby się tu jako
                #  zdanie o analizie, która doszła do końca.
                raise ValueError(
                    "wyjaśnienie odrzucenia nazywa miejsce zatrzymania, "
                    "a ten przebieg o zatrzymanie nie pytał (werdykt w olski/werdykt/zdanie.py)"
                )
            if self.zatrzymanie is None:
                return f"{brak_odczytania}: analiza dochodzi do końca, a nic nie domyka zdania"
            return f"{brak_odczytania}: analiza staje na „{self.zatrzymanie}”"
        przyłączenia = self.result.przyłączenia
        # Przekład idzie i tutaj (:func:`_nazwy_szkolne`), bo wiersz ten nie ma
        # nazywać roli, której lista czytań pod nim nie nazywa.
        różne = sorted(
            {
                nazwa
                for role in self.result.różniące
                # Przyłączenie nazwane niżej mówi o tej roli więcej niż sama jej
                # nazwa, więc wypisana obok byłaby tym samym zdaniem dwa razy.
                if not (przyłączenia and role == WYRAŻENIE_PRZYIMKOWE)
                for nazwa in _nazwy_szkolne(role)
            }
        )
        # Liczba i role wychodzą z lasu, więc granica wyliczania sięga listy
        # czytań i nie sięga tego wiersza: liczba jest liczbą, a nie „64+”.
        wiersz = _odczytań(self.result.ile)
        if różne:
            # Dwukropek oddziela nazwy od zdania: bez niego „różne w dopełnienie”
            # czyta się jak rzeczownik, którego przyimek nie odmienił.
            wiersz += f", różne w {'roli' if len(różne) == 1 else 'rolach'}: {', '.join(różne)}"
        return "; ".join(
            [
                wiersz,
                *map(_nierozstrzygnięte, przyłączenia),
                *map(_rozbieżny, self.result.rozbieżności),
            ]
        )

text instance-attribute

result instance-attribute

nielicencjonowane instance-attribute

zatrzymanie instance-attribute

naprawa instance-attribute

punktowane property

Czy tekst punktuje ten napis jako zdanie.

Mianownik pomiaru pyta o to, a nie o status, bo odpowiedź jest ta sama nad oboma werdyktami o napisie niepunktowanym i nie kosztuje rozbioru, którego kosztuje domknięcie (olski.werdykt.tekst.Podsumowanie).

zgłoszenie property

Czy narzędzie ma o tym zdaniu coś do powiedzenia.

Wydruk domyślny niesie dwa zgłoszenia: wieloznaczność oraz poprawkę jednego znaku, a znaleziskiem jest tylko druga (docs/subset.md#wieloznaczność-jest-odpowiedzią-a-nie-znaleziskiem). Zaimek wskazujący na dwie rzeczy naraz pada obok werdyktu, bo rzeczy nazywa zdanie obok (olski/odniesienia.py), więc tutaj go nie ma. Warunek stoi tu raz, bo pyta o niego wydruk nad każdym zdaniem osobno; olski.werdykt.tekst.Podsumowanie liczy każde z tych zgłoszeń nad tekstem i liczy je osobno.

Napis niepunktowany zostaje poza zgłoszeniem także wtedy, gdy poprawkę ma, bo nagłówek i pozycja listy dochodzą tu jako takie napisy i żadne z nich nie jest zdaniem, którego autor nie domknął (docs/extraction.md); wydruk pokazuje je do flagi --zatrzymania.

czytane property

Czy olski to zdanie czyta.

Nieczytane są trzy: zdanie odrzucone, napis, którego nic nie domyka, i fragment. O polszczyźnie żadnego z nich olski nie orzeka, więc wydruk milczy o nich do flagi (olski/check.py).

status property

Klasa, do której werdykt to zdanie liczy, czyli słowo pomiaru.

Wydruk komendy go nie podaje, bo dzieli zdania po liczbie odczytań, a nie po tym, czy narzędzie ma o zdaniu co powiedzieć (znalezisko). Czytają je pomiar pokrycia (olski/pokrycie.py), sondy w harness/ i znaczek na stronie (witryna/skrypt.js).

readings property

Streszczenia odczytań, każde raz (streszczenia).

Odczytanie jest krotką streszczeń, po jednym na zdanie składowe, więc wpisem tej listy jest krotka, a nie jedno streszczenie.

Lista jest po to, żeby pokazać różnicę między odczytaniami, a różnicę spoza zasięgu streszczenia nazywa wiersz o konstytuencie (_rozbieżny), więc powtórzony napis nie zostawia jej nienazwanej. Liczbę odczytań podaje las (Result.ile), więc skrócenie tej listy jej nie rusza.

morfologia property

Czym formy stoją w każdym odczytaniu: wpis na streszczenie z readings.

Wiersz dostaje forma czytana więcej niż jednym sposobem, a odczytania w nim licencjonują ją w tym kształcie (olski.parse.Leaf.odczytania); wiersze składa olski.werdykt.wykazy._pod_streszczeniem, a nad streszczeniem, które zbiera kilka kształtów, bierze odczytania z każdego z nich. Wpisów jest tyle, ile streszczeń, więc nad zdaniem urwanym na olski.parse.MAX_READINGS mówią one o odczytaniach wypisanych.

Zdanie bez ani jednego odczytania dostaje jeden wpis, a w nim każde odczytanie każdej formy (olski.werdykt.wykazy._morfologia_zdania): odsiać ich nie ma czym. Rozstrzyga się to tutaj, a nie w wydruku, bo wydruki są dwa (olski/check.py i witryna/werdykty.py) i rozjechałyby się po cichu.

rachunki property

Za co płaci każde odczytanie: wpis na streszczenie z readings.

Wychodzą stąd pozycje policzone, a sumę liczy z nich ten, kto ją pokazuje (olski.cennik.razem): jest nią miejsce w kolejce odczytań, bo las porządkuje je sumą cennika po całym drzewie.

Streszczenie zbiera czasem kilka kształtów, a rachunek jest tego, który wyszedł z lasu pierwszy, czyli tego, przez którego to streszczenie stoi tam, gdzie stoi.

żądania property

Czego czasownik żąda od obsadzonych pozycji: wpis na streszczenie z readings.

Po co ta odpowiedź autorowi i czego ona nie mówi, wywodzi olski/żądania.py; wpis jest na streszczenie z tego samego powodu, co przy morfologia, i grupuje go to samo pytanie o las.

Warunku na zdanie odrzucone nie ma i nie ma go czemu stawiać: pozycję obsadza czytanie, a takie zdanie nie ma ani jednego, więc lista wychodzi stąd pusta sama. Morfologia ma tam wpis, bo mówi o formach, a nie o rolach.

rozbieżne property

Konstytuenty rozbieżne, którym streszczenia naprawdę się różnią.

Jedno streszczenie znaczy, że streszczenie tej różnicy nie widzi (Rozbieżność), a wypisane byłoby wierszem bez treści. Warunek stoi tu raz na oba wydruki, na wiersz poleceń i na witrynę, bo napisany dwa razy rozjechałby się po cichu.

explain(brak_odczytania=BRAK_ODCZYTANIA)

Co narzędzie ma o tym zdaniu do powiedzenia, jednym wierszem.

Nazwa braku przychodzi argumentem, bo dwa tryby nazywają go różnie, a mówią pod obiema nazwami to samo o analizie, więc powód stoi tu raz. Bierze ją samo zdanie odrzucone: poprawka jednego znaku i napis, którego nic nie punktuje jako zdania, mówią autorowi co innego i idą przed nim.

Source code in olski/werdykt/zdanie.py
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
def explain(self, brak_odczytania: str = BRAK_ODCZYTANIA) -> str:
    """Co narzędzie ma o tym zdaniu do powiedzenia, jednym wierszem.

    Nazwa braku przychodzi argumentem, bo dwa tryby nazywają go różnie, a
    mówią pod obiema nazwami to samo o analizie, więc powód stoi tu raz.
    Bierze ją samo zdanie odrzucone: poprawka jednego znaku i napis, którego
    nic nie punktuje jako zdania, mówią autorowi co innego i idą przed nim.
    """
    #  Poprawka wyprzedza każde inne wyjaśnienie i wyprzedza je nad zdaniem
    #  odrzuconym tak samo jak nad napisem niedomkniętym: zatrzymanie mówi,
    #  dokąd doszła analiza, a poprawka mówi, co z tym zrobić.
    if self.naprawa is not None:
        return _naprawiony(self.naprawa)
    if self.status == FRAGMENT:
        return "to nie zdanie: nic go nie punktuje jako zdania"
    if self.result.valid:
        return _odczytań(1)
    if self.result.rejected:
        if self.nielicencjonowane:
            # Cudzysłów jest treścią: najczęstszą formą bez licencji jest
            # przecinek, a lista rozdzielana przecinkami gubi bez niego granice.
            formy = ", ".join(f"„{forma}”" for forma in self.nielicencjonowane)
            return f"{brak_odczytania}: żadna produkcja nie bierze {formy}"
        if self.result.furthest is None:
            #  Tak samo odmawia ``bloker`` w ``olski/pokrycie.py`` i z tego
            #  samego powodu: milczenie o zatrzymaniu czytałoby się tu jako
            #  zdanie o analizie, która doszła do końca.
            raise ValueError(
                "wyjaśnienie odrzucenia nazywa miejsce zatrzymania, "
                "a ten przebieg o zatrzymanie nie pytał (werdykt w olski/werdykt/zdanie.py)"
            )
        if self.zatrzymanie is None:
            return f"{brak_odczytania}: analiza dochodzi do końca, a nic nie domyka zdania"
        return f"{brak_odczytania}: analiza staje na „{self.zatrzymanie}”"
    przyłączenia = self.result.przyłączenia
    # Przekład idzie i tutaj (:func:`_nazwy_szkolne`), bo wiersz ten nie ma
    # nazywać roli, której lista czytań pod nim nie nazywa.
    różne = sorted(
        {
            nazwa
            for role in self.result.różniące
            # Przyłączenie nazwane niżej mówi o tej roli więcej niż sama jej
            # nazwa, więc wypisana obok byłaby tym samym zdaniem dwa razy.
            if not (przyłączenia and role == WYRAŻENIE_PRZYIMKOWE)
            for nazwa in _nazwy_szkolne(role)
        }
    )
    # Liczba i role wychodzą z lasu, więc granica wyliczania sięga listy
    # czytań i nie sięga tego wiersza: liczba jest liczbą, a nie „64+”.
    wiersz = _odczytań(self.result.ile)
    if różne:
        # Dwukropek oddziela nazwy od zdania: bez niego „różne w dopełnienie”
        # czyta się jak rzeczownik, którego przyimek nie odmienił.
        wiersz += f", różne w {'roli' if len(różne) == 1 else 'rolach'}: {', '.join(różne)}"
    return "; ".join(
        [
            wiersz,
            *map(_nierozstrzygnięte, przyłączenia),
            *map(_rozbieżny, self.result.rozbieżności),
        ]
    )

__init__(text, result, nielicencjonowane, zatrzymanie, naprawa)

zatrzymania(segmenty, grammar=None)

Każde zatrzymanie odrzuconego zdania, a nie samo pierwsze.

Werdykt nazywa jedno miejsce (na_czym_stanęło), a zdanie długie ma ich kilka i pierwsze zasłania resztę, więc kto pisze pod tę gramatykę, nie widzi z werdyktu, ile jeszcze poprawek to zdanie zabierze.

Cięcie nie wskazuje usterki ani granicy konstrukcji, tak samo jak jedno zatrzymanie jej nie wskazuje.

Source code in olski/werdykt/odrzucone.py
150
151
152
153
154
155
156
157
158
159
160
161
def zatrzymania(segmenty: list[Segment], grammar: Grammar | None = None) -> tuple[str, ...]:
    """Każde zatrzymanie odrzuconego zdania, a nie samo pierwsze.

    Werdykt nazywa jedno miejsce (:func:`na_czym_stanęło`), a zdanie długie ma ich
    kilka i pierwsze zasłania resztę, więc kto pisze pod tę gramatykę, nie widzi z
    werdyktu, ile jeszcze poprawek to zdanie zabierze.

    Cięcie nie wskazuje usterki ani granicy konstrukcji, tak samo jak jedno
    zatrzymanie jej nie wskazuje.
    """
    grammar = grammar or GRAMMAR
    return _od_zatrzymania(segmenty, grammar, _pierwsze_zatrzymanie(segmenty, grammar))

check(text, grammar=None)

Check every sentence of a text against the grammar.

Bare verdicts and nothing else: what the surrounding text adds comes with nad_tekstem.

Source code in olski/werdykt/tekst.py
47
48
49
50
51
52
53
def check(text: str, grammar: Grammar | None = None) -> list[Verdict]:
    """Check every sentence of a text against the grammar.

    Bare verdicts and nothing else:
    what the surrounding text adds comes with :func:`nad_tekstem`.
    """
    return [werdykt(zdanie, morphology(zdanie), grammar) for zdanie in sentences(text)]

nad_tekstem(text, w_zdaniu=False)

Co narzędzie ma do powiedzenia o tekście: wpis na zdanie, w kolejności zdań.

Wejście jest jedno na oba wyjścia — wiersz poleceń (olski/check.py) i witrynę (witryna/werdykty.py) — bo różnią się one brzegiem, a nie środkiem: pierwsze drukuje wiersze, drugie składa JSON. Znalezisko dopisane następne dochodzi przez to w jednym miejscu i w jednym się liczy (Podsumowanie.ze_zdań).

w_zdaniu przepuszcza flagę do warstwy zaimkowej i pyta o nią sonda oceniająca, a nie wydruk (olski/odniesienia.py).

Sąsiedztwa liczą się zawsze, choć wiersz poleceń pyta o warstwę rozstrzygającą dopiero pod flagą: obok rozbioru nie kosztują nic, bo tną tekst na zdania, a słowa liczą w nich dopiero pod świadkiem (olski.rozstrzyganie.Sąsiedztwo).

Source code in olski/werdykt/tekst.py
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
def nad_tekstem(text: str, w_zdaniu: bool = False) -> list[Zdanie]:
    """Co narzędzie ma do powiedzenia o tekście: wpis na zdanie, w kolejności zdań.

    Wejście jest jedno na oba wyjścia — wiersz poleceń (``olski/check.py``)
    i witrynę (``witryna/werdykty.py``) — bo różnią się one brzegiem, a nie
    środkiem: pierwsze drukuje wiersze, drugie składa JSON. Znalezisko dopisane
    następne dochodzi przez to w jednym miejscu i w jednym się liczy
    (:meth:`Podsumowanie.ze_zdań`).

    ``w_zdaniu`` przepuszcza flagę do warstwy zaimkowej i pyta o nią sonda
    oceniająca, a nie wydruk (``olski/odniesienia.py``).

    Sąsiedztwa liczą się zawsze, choć wiersz poleceń pyta o warstwę
    rozstrzygającą dopiero pod flagą: obok rozbioru nie kosztują nic, bo tną
    tekst na zdania, a słowa liczą w nich dopiero pod świadkiem
    (:class:`olski.rozstrzyganie.Sąsiedztwo`).
    """
    werdykty = check(text)
    return [
        Zdanie(verdict, sąsiedztwo, odniesienia)
        for verdict, sąsiedztwo, odniesienia in zip(
            werdykty,
            sąsiedztwa(text),
            niejasne_odniesienia(text, [verdict.result for verdict in werdykty], w_zdaniu),
            strict=True,
        )
    ]

dalsze_zatrzymania(verdict, grammar=None)

Zatrzymania tego zdania poza tym, które nazwał już werdykt.

Zdanie z czytaniem nie stanęło nigdzie, więc krotka jest wtedy pusta, i tak samo pusta jest nad fragmentem. Segmentacja idzie tu drugi raz, bo werdykt segmentów nie niesie (werdykt).

Pierwsze zatrzymanie bierze się z Result.furthest, a nie z rozbioru: werdykt tę liczbę już policzył, a rozbiór po całym zdaniu jest najdroższy z całej pętli. Węzeł stamtąd nazywa tutaj tę samą krawędź, bo oba wołania olski.segmentacja.morphology biorą ten sam napis.

Source code in olski/werdykt/zdanie.py
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
def dalsze_zatrzymania(verdict: Verdict, grammar: Grammar | None = None) -> tuple[str, ...]:
    """Zatrzymania tego zdania poza tym, które nazwał już werdykt.

    Zdanie z czytaniem nie stanęło nigdzie, więc krotka jest wtedy pusta, i tak
    samo pusta jest nad fragmentem. Segmentacja idzie tu drugi raz, bo werdykt
    segmentów nie niesie (:func:`werdykt`).

    Pierwsze zatrzymanie bierze się z ``Result.furthest``, a nie z rozbioru:
    werdykt tę liczbę już policzył,
    a rozbiór po całym zdaniu jest najdroższy z całej pętli.
    Węzeł stamtąd nazywa tutaj tę samą krawędź,
    bo oba wołania :func:`olski.segmentacja.morphology` biorą ten sam napis.
    """
    if not verdict.punktowane or not verdict.result.rejected:
        return ()
    if verdict.result.furthest is None:
        #  Tak samo odmawiają ``Verdict.explain`` i ``bloker`` (``olski/pokrycie.py``):
        #  krotka pusta czytałaby się jak zdanie stające raz.
        raise ValueError(
            "zatrzymania dalsze liczą się od pierwszego, "
            "a ten przebieg o zatrzymanie nie pytał (werdykt w olski/werdykt/zdanie.py)"
        )
    segmenty = morphology(verdict.text)
    stanęło = na_czym_stanęło(segmenty, verdict.result.furthest)
    return _od_zatrzymania(segmenty, grammar or GRAMMAR, stanęło)[1:]

niespełnione_żądania(verdict, deklaracja=OSOBY_PROJEKTU)

Pozycje, w których czasownik żąda kogoś, a nikt w nich nie stoi.

Obie połowy pytania spotykają się tutaj: żądanie przychodzi z pliku żądań (olski.żądania.żąda_osoby), a spełnienie z deklaracji projektu (olski/osoby.py). Wiersz zostaje po tej pozycji, której żądania nie spełnia nic z tego, czym jest jej głowa.

Wiersz jest o zdaniu, a nie o odczytaniu, i tym różni się ten wykaz od Verdict.żądania. Pozycję obsadza czytanie, więc wiersz mówi tyle, że w którymś z nich stoi rzecz tam, gdzie czasownik żąda kogoś. Zdanie wieloznaczne ma czytań kilkanaście, a wiersz o jednej pozycji w każdym z nich ten sam, więc wykaz na odczytanie kazałby przeczytać kilkanaście kopii jednego wiersza.

Source code in olski/werdykt/zdanie.py
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
def niespełnione_żądania(
    verdict: Verdict, deklaracja: Osoby = OSOBY_PROJEKTU
) -> tuple[Żądanie, ...]:
    """Pozycje, w których czasownik żąda kogoś, a nikt w nich nie stoi.

    Obie połowy pytania spotykają się tutaj: żądanie przychodzi z pliku żądań
    (:func:`olski.żądania.żąda_osoby`), a spełnienie z deklaracji projektu
    (``olski/osoby.py``). Wiersz zostaje po tej pozycji, której żądania nie
    spełnia nic z tego, czym jest jej głowa.

    **Wiersz jest o zdaniu, a nie o odczytaniu**, i tym różni się ten wykaz od
    :attr:`Verdict.żądania`. Pozycję obsadza czytanie, więc wiersz mówi tyle,
    że w którymś z nich stoi rzecz tam, gdzie czasownik żąda kogoś. Zdanie
    wieloznaczne ma czytań kilkanaście, a wiersz o jednej pozycji w każdym z nich
    ten sam, więc wykaz na odczytanie kazałby przeczytać kilkanaście kopii
    jednego wiersza.
    """
    return tuple(
        żądanie
        for żądanie in _zwinięte(żądanie for tabela in verdict.żądania for żądanie in tabela)
        if żąda_osoby(żądanie.klasy) and not deklaracja.nazywają(żądanie.lematy)
    )

werdykt(zdanie, segmenty, grammar=None, zatrzymanie=True)

Werdykt o zdaniu już zsegmentowanym, wraz z całym podsumowaniem.

Segmenty przychodzą argumentem, a nie powstają tutaj, bo zależą od napisu, a nie od gramatyki: kto pyta o jedno zdanie kilka gramatyk — sonda różnicowa nad prozą — segmentuje je raz i pyta tyle razy, ile ma wariantów.

Zatrzymanie jest najdroższym z podsumowań i jedynym, które wolno pominąć. Nad zdaniem odrzuconym przechodzi tablicę drugi raz i unifikuje przy tym przebyte ciała (olski.parse.podsumuj), a nad prozą, której olski w większości nie wyprowadza, odrzuconych jest osiem zdań na dziesięć, więc waży w takim przebiegu więcej niż każde inne podsumowanie. Czytają je Verdict.explain i kolejka blokerów (olski/pokrycie.py); kto go nie czyta, prosi o werdykt bez niego.

Flagą, a nie pytaniem leniwym: Result trzymający las liczyłby punkt przy pierwszym pytaniu, ale przebieg nad bankiem drzew pyta o niego przy każdym zdaniu odrzuconym, a las porzuca rozmyślnie, bo waży tyle, ile jego tablica (zmierz_zdanie w harness/pomiar.py).

Napis bez znaku kończącego pyta o zatrzymanie mimo flagi, bo od niego zależy wtedy sam status: poprawki domykającej szuka się nad analizą, która doszła do końca (olski.werdykt.odrzucone._naprawa), a nad napisem punktowanym nie szuka się jej wcale.

Source code in olski/werdykt/zdanie.py
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
def werdykt(
    zdanie: str,
    segmenty: list[Segment],
    grammar: Grammar | None = None,
    zatrzymanie: bool = True,
) -> Verdict:
    """Werdykt o zdaniu już zsegmentowanym, wraz z całym podsumowaniem.

    Segmenty przychodzą argumentem, a nie powstają tutaj, bo zależą od napisu, a
    nie od gramatyki: kto pyta o jedno zdanie kilka gramatyk — sonda różnicowa
    nad prozą — segmentuje je raz i pyta tyle razy, ile ma wariantów.

    Zatrzymanie jest najdroższym z podsumowań i jedynym, które wolno pominąć.
    Nad zdaniem odrzuconym przechodzi tablicę drugi raz
    i unifikuje przy tym przebyte ciała (:func:`olski.parse.podsumuj`),
    a nad prozą, której olski w większości nie wyprowadza,
    odrzuconych jest osiem zdań na dziesięć,
    więc waży w takim przebiegu więcej niż każde inne podsumowanie.
    Czytają je :meth:`Verdict.explain` i kolejka blokerów (``olski/pokrycie.py``);
    kto go nie czyta, prosi o werdykt bez niego.

    Flagą, a nie pytaniem leniwym: ``Result`` trzymający las liczyłby punkt przy
    pierwszym pytaniu, ale przebieg nad bankiem drzew pyta o niego przy każdym
    zdaniu odrzuconym, a las porzuca rozmyślnie, bo waży tyle, ile jego tablica
    (``zmierz_zdanie`` w ``harness/pomiar.py``).

    Napis bez znaku kończącego pyta o zatrzymanie mimo flagi, bo od niego zależy
    wtedy sam status: poprawki domykającej szuka się nad analizą, która doszła
    do końca (:func:`olski.werdykt.odrzucone._naprawa`),
    a nad napisem punktowanym nie szuka się jej wcale.
    """
    grammar = grammar or GRAMMAR
    pytane = zatrzymanie or not SENTENCE_CLOSE.search(zdanie)
    result = parse(grammar, segmenty, deklaracja=DEKLARACJA, zatrzymanie=pytane)
    stanęło = na_czym_stanęło(segmenty, result.furthest) if pytane else None
    #  Brak formy jest dojściem do końca dopiero wtedy, gdy pytano:
    #  bez pytania ``stanęło`` jest puste także nad analizą, która stanęła.
    doszło_do_końca = pytane and stanęło is None
    nielicencjonowane = bez_licencji(segmenty, grammar)
    return Verdict(
        text=zdanie,
        result=result,
        nielicencjonowane=nielicencjonowane,
        zatrzymanie=stanęło.form if stanęło is not None else None,
        naprawa=_naprawa(zdanie, grammar, result.rejected, nielicencjonowane, doszło_do_końca),
    )