kwic 0.1.0__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.
- kwic-0.1.0/LICENSE +21 -0
- kwic-0.1.0/PKG-INFO +155 -0
- kwic-0.1.0/README.md +138 -0
- kwic-0.1.0/pyproject.toml +137 -0
- kwic-0.1.0/pyproject.toml.orig +143 -0
- kwic-0.1.0/src/kwic/__init__.py +19 -0
- kwic-0.1.0/src/kwic/constants.py +18 -0
- kwic-0.1.0/src/kwic/engines/__init__.py +14 -0
- kwic-0.1.0/src/kwic/engines/base.py +66 -0
- kwic-0.1.0/src/kwic/engines/lemminflect.py +48 -0
- kwic-0.1.0/src/kwic/engines/spacy.py +184 -0
- kwic-0.1.0/src/kwic/engines/stanza.py +201 -0
- kwic-0.1.0/src/kwic/models/__init__.py +18 -0
- kwic-0.1.0/src/kwic/models/annotations.py +32 -0
- kwic-0.1.0/src/kwic/models/contexts.py +7 -0
- kwic-0.1.0/src/kwic/models/matches.py +32 -0
- kwic-0.1.0/src/kwic/models/pos.py +32 -0
- kwic-0.1.0/src/kwic/models/queries.py +29 -0
- kwic-0.1.0/src/kwic/normalisation.py +66 -0
- kwic-0.1.0/src/kwic/py.typed +0 -0
- kwic-0.1.0/src/kwic/search/__init__.py +12 -0
- kwic-0.1.0/src/kwic/search/lexicon.py +126 -0
- kwic-0.1.0/src/kwic/search/locator.py +233 -0
- kwic-0.1.0/src/kwic/search/reading.py +140 -0
kwic-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Eva
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
kwic-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kwic
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Key Word In Context
|
|
5
|
+
Author: Eva
|
|
6
|
+
Author-email: Eva <eva.evangelisti03@gmail.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: spacy>=3.8.15
|
|
10
|
+
Requires-Dist: lemminflect>=0.2.3 ; extra == 'lemminflect'
|
|
11
|
+
Requires-Dist: stanza>=1.14.0 ; extra == 'stanza'
|
|
12
|
+
Requires-Python: >=3.12
|
|
13
|
+
Project-URL: Repository, https://github.com/evaevangelisti/kwic
|
|
14
|
+
Provides-Extra: lemminflect
|
|
15
|
+
Provides-Extra: stanza
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# Key Word In Context
|
|
19
|
+
|
|
20
|
+
Locates the lemmas of a query in the context that attests them.
|
|
21
|
+
|
|
22
|
+
<!-- installation -->
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
### Requirements
|
|
27
|
+
|
|
28
|
+
- Python 3.12 or later
|
|
29
|
+
|
|
30
|
+
### From PyPI
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
pip install kwic
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
A search reads with spaCy, whose pipelines are published apart from the library:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
python -m spacy download en_core_web_sm
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The other engines are extras:
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
pip install "kwic[stanza]"
|
|
46
|
+
pip install "kwic[lemminflect]"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
<!-- usage -->
|
|
50
|
+
|
|
51
|
+
## Usage
|
|
52
|
+
|
|
53
|
+
A search takes one context and the lemmas to look for.
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from kwic import Locator, POS, Query
|
|
57
|
+
|
|
58
|
+
locator = Locator()
|
|
59
|
+
|
|
60
|
+
locator.find("She found the keys she had lost.", [Query("find", POS.VERB)])
|
|
61
|
+
# (Match(lemma='find', pos=POS.VERB, form='found', word_index=1, offsets=(4, 9)),)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Query
|
|
65
|
+
|
|
66
|
+
| Field | Default | |
|
|
67
|
+
| --- | --- | --- |
|
|
68
|
+
| `lemma` | | Dictionary form to look for, in whatever case |
|
|
69
|
+
| `pos` | `None` | Tag a one-word occurrence must carry; a longer lemma is not narrowed |
|
|
70
|
+
| `forms` | `()` | How else the lemma is written, taken where the engine read another |
|
|
71
|
+
|
|
72
|
+
The engine cuts the lemma into words, and a space and a hyphen are one to it.
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
locator.find("It was hunky-dory.", [Query("hunky dory")])
|
|
76
|
+
# (Match(lemma='hunky dory', pos=POS.ADJ, form='hunky-dory', word_index=2, offsets=(7, 17)),)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
A phrasal verb written apart runs from the verb to the particle.
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
locator.find("She gave the money up.", [Query("give up")])
|
|
83
|
+
# (Match(lemma='give up', pos=POS.VERB, form='gave the money up', word_index=1, offsets=(4, 21)),)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Match
|
|
87
|
+
|
|
88
|
+
| Field | |
|
|
89
|
+
| --- | --- |
|
|
90
|
+
| `lemma` | The lemma you asked for, as you wrote it |
|
|
91
|
+
| `pos` | The tag it carries |
|
|
92
|
+
| `form` | How it is written |
|
|
93
|
+
| `word_index` | Where it opens among the words, from zero |
|
|
94
|
+
| `offsets` | Where it falls in the text, half-open and in code points |
|
|
95
|
+
|
|
96
|
+
### Contexts
|
|
97
|
+
|
|
98
|
+
A context is a text, or the words it was split into. The second has no range.
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
locator.find(("She", "found", "the", "keys"), [Query("find")])
|
|
102
|
+
# (Match(lemma='find', pos=POS.VERB, form='found', word_index=1, offsets=None),)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Many contexts
|
|
106
|
+
|
|
107
|
+
`find_all` takes context and lemmas in pairs, and reads a batch at a time.
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
for occurrences in locator.find_all(searches):
|
|
111
|
+
...
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Engines
|
|
115
|
+
|
|
116
|
+
An engine reads the context; the search reads the engine.
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
from kwic.engines.stanza import StanzaEngine
|
|
120
|
+
|
|
121
|
+
locator = Locator(StanzaEngine())
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
| Engine | Reads with | Install |
|
|
125
|
+
| --- | --- | --- |
|
|
126
|
+
| `SpacyEngine` | a spaCy pipeline, its English lemmatiser rules over the tag | `spacy` |
|
|
127
|
+
| `StanzaEngine` | Stanza, a dictionary with a neural model behind it | `kwic[stanza]` |
|
|
128
|
+
| `LemmInflectEngine` | spaCy for the tags, LemmInflect for the lemmas | `kwic[lemminflect]` |
|
|
129
|
+
|
|
130
|
+
An extra is imported from the module wrapping it, so a package without it still loads.
|
|
131
|
+
|
|
132
|
+
`SpacyEngine` takes the pipeline to load, `StanzaEngine` the language. Both parse unless told otherwise:
|
|
133
|
+
|
|
134
|
+
| Parser | Buys | Costs |
|
|
135
|
+
| --- | --- | --- |
|
|
136
|
+
| spaCy | phrasal verbs apart, and several universal tags | a tenth of a reading |
|
|
137
|
+
| Stanza | phrasal verbs apart | half its speed |
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
Locator(SpacyEngine(parse=False))
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
<!-- accuracy -->
|
|
144
|
+
|
|
145
|
+
## Accuracy
|
|
146
|
+
|
|
147
|
+
English-EWT test section: 2,077 sentences, 417 lemmas, 3,619 occurrences.
|
|
148
|
+
|
|
149
|
+
| Engine | Precision | Recall | F1 |
|
|
150
|
+
| --- | --- | --- | --- |
|
|
151
|
+
| `StanzaEngine` | 0.975 | 0.963 | 0.969 |
|
|
152
|
+
| `SpacyEngine`, `en_core_web_trf` | 0.981 | 0.905 | 0.942 |
|
|
153
|
+
| `SpacyEngine`, `en_core_web_lg` | 0.978 | 0.891 | 0.933 |
|
|
154
|
+
| `SpacyEngine`, `en_core_web_sm` | 0.978 | 0.882 | 0.928 |
|
|
155
|
+
| `LemmInflectEngine` | 0.976 | 0.872 | 0.921 |
|
kwic-0.1.0/README.md
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Key Word In Context
|
|
2
|
+
|
|
3
|
+
Locates the lemmas of a query in the context that attests them.
|
|
4
|
+
|
|
5
|
+
<!-- installation -->
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
### Requirements
|
|
10
|
+
|
|
11
|
+
- Python 3.12 or later
|
|
12
|
+
|
|
13
|
+
### From PyPI
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
pip install kwic
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
A search reads with spaCy, whose pipelines are published apart from the library:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
python -m spacy download en_core_web_sm
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The other engines are extras:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
pip install "kwic[stanza]"
|
|
29
|
+
pip install "kwic[lemminflect]"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
<!-- usage -->
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
A search takes one context and the lemmas to look for.
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from kwic import Locator, POS, Query
|
|
40
|
+
|
|
41
|
+
locator = Locator()
|
|
42
|
+
|
|
43
|
+
locator.find("She found the keys she had lost.", [Query("find", POS.VERB)])
|
|
44
|
+
# (Match(lemma='find', pos=POS.VERB, form='found', word_index=1, offsets=(4, 9)),)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Query
|
|
48
|
+
|
|
49
|
+
| Field | Default | |
|
|
50
|
+
| --- | --- | --- |
|
|
51
|
+
| `lemma` | | Dictionary form to look for, in whatever case |
|
|
52
|
+
| `pos` | `None` | Tag a one-word occurrence must carry; a longer lemma is not narrowed |
|
|
53
|
+
| `forms` | `()` | How else the lemma is written, taken where the engine read another |
|
|
54
|
+
|
|
55
|
+
The engine cuts the lemma into words, and a space and a hyphen are one to it.
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
locator.find("It was hunky-dory.", [Query("hunky dory")])
|
|
59
|
+
# (Match(lemma='hunky dory', pos=POS.ADJ, form='hunky-dory', word_index=2, offsets=(7, 17)),)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
A phrasal verb written apart runs from the verb to the particle.
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
locator.find("She gave the money up.", [Query("give up")])
|
|
66
|
+
# (Match(lemma='give up', pos=POS.VERB, form='gave the money up', word_index=1, offsets=(4, 21)),)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Match
|
|
70
|
+
|
|
71
|
+
| Field | |
|
|
72
|
+
| --- | --- |
|
|
73
|
+
| `lemma` | The lemma you asked for, as you wrote it |
|
|
74
|
+
| `pos` | The tag it carries |
|
|
75
|
+
| `form` | How it is written |
|
|
76
|
+
| `word_index` | Where it opens among the words, from zero |
|
|
77
|
+
| `offsets` | Where it falls in the text, half-open and in code points |
|
|
78
|
+
|
|
79
|
+
### Contexts
|
|
80
|
+
|
|
81
|
+
A context is a text, or the words it was split into. The second has no range.
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
locator.find(("She", "found", "the", "keys"), [Query("find")])
|
|
85
|
+
# (Match(lemma='find', pos=POS.VERB, form='found', word_index=1, offsets=None),)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Many contexts
|
|
89
|
+
|
|
90
|
+
`find_all` takes context and lemmas in pairs, and reads a batch at a time.
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
for occurrences in locator.find_all(searches):
|
|
94
|
+
...
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Engines
|
|
98
|
+
|
|
99
|
+
An engine reads the context; the search reads the engine.
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from kwic.engines.stanza import StanzaEngine
|
|
103
|
+
|
|
104
|
+
locator = Locator(StanzaEngine())
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
| Engine | Reads with | Install |
|
|
108
|
+
| --- | --- | --- |
|
|
109
|
+
| `SpacyEngine` | a spaCy pipeline, its English lemmatiser rules over the tag | `spacy` |
|
|
110
|
+
| `StanzaEngine` | Stanza, a dictionary with a neural model behind it | `kwic[stanza]` |
|
|
111
|
+
| `LemmInflectEngine` | spaCy for the tags, LemmInflect for the lemmas | `kwic[lemminflect]` |
|
|
112
|
+
|
|
113
|
+
An extra is imported from the module wrapping it, so a package without it still loads.
|
|
114
|
+
|
|
115
|
+
`SpacyEngine` takes the pipeline to load, `StanzaEngine` the language. Both parse unless told otherwise:
|
|
116
|
+
|
|
117
|
+
| Parser | Buys | Costs |
|
|
118
|
+
| --- | --- | --- |
|
|
119
|
+
| spaCy | phrasal verbs apart, and several universal tags | a tenth of a reading |
|
|
120
|
+
| Stanza | phrasal verbs apart | half its speed |
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
Locator(SpacyEngine(parse=False))
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
<!-- accuracy -->
|
|
127
|
+
|
|
128
|
+
## Accuracy
|
|
129
|
+
|
|
130
|
+
English-EWT test section: 2,077 sentences, 417 lemmas, 3,619 occurrences.
|
|
131
|
+
|
|
132
|
+
| Engine | Precision | Recall | F1 |
|
|
133
|
+
| --- | --- | --- | --- |
|
|
134
|
+
| `StanzaEngine` | 0.975 | 0.963 | 0.969 |
|
|
135
|
+
| `SpacyEngine`, `en_core_web_trf` | 0.981 | 0.905 | 0.942 |
|
|
136
|
+
| `SpacyEngine`, `en_core_web_lg` | 0.978 | 0.891 | 0.933 |
|
|
137
|
+
| `SpacyEngine`, `en_core_web_sm` | 0.978 | 0.882 | 0.928 |
|
|
138
|
+
| `LemmInflectEngine` | 0.976 | 0.872 | 0.921 |
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["uv_build>=0.12.3,<0.13"]
|
|
3
|
+
build-backend = "uv_build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "kwic"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Key Word In Context"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
dependencies = ["spacy>=3.8.15"]
|
|
14
|
+
|
|
15
|
+
[[project.authors]]
|
|
16
|
+
name = "Eva"
|
|
17
|
+
email = "eva.evangelisti03@gmail.com"
|
|
18
|
+
|
|
19
|
+
[project.optional-dependencies]
|
|
20
|
+
lemminflect = ["lemminflect>=0.2.3"]
|
|
21
|
+
stanza = ["stanza>=1.14.0"]
|
|
22
|
+
|
|
23
|
+
[project.urls]
|
|
24
|
+
Repository = "https://github.com/evaevangelisti/kwic"
|
|
25
|
+
|
|
26
|
+
[dependency-groups]
|
|
27
|
+
docs = [
|
|
28
|
+
"myst-parser>=5.1.0",
|
|
29
|
+
"shibuya>=2026.7.12",
|
|
30
|
+
"sphinx>=9.1.0",
|
|
31
|
+
]
|
|
32
|
+
lint = ["ruff>=0.16.2"]
|
|
33
|
+
models = [
|
|
34
|
+
"en-core-web-lg",
|
|
35
|
+
"en-core-web-sm",
|
|
36
|
+
"en-core-web-trf",
|
|
37
|
+
]
|
|
38
|
+
test = [
|
|
39
|
+
"hypothesis>=6.165.9",
|
|
40
|
+
"pytest>=9.1.1",
|
|
41
|
+
"pytest-cov>=7.1.0",
|
|
42
|
+
]
|
|
43
|
+
typing = ["basedpyright>=1.39.9"]
|
|
44
|
+
|
|
45
|
+
[tool.uv.sources.en-core-web-sm]
|
|
46
|
+
url = "https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.8.0/en_core_web_sm-3.8.0-py3-none-any.whl"
|
|
47
|
+
|
|
48
|
+
[tool.uv.sources.en-core-web-lg]
|
|
49
|
+
url = "https://github.com/explosion/spacy-models/releases/download/en_core_web_lg-3.8.0/en_core_web_lg-3.8.0-py3-none-any.whl"
|
|
50
|
+
|
|
51
|
+
[tool.uv.sources.en-core-web-trf]
|
|
52
|
+
url = "https://github.com/explosion/spacy-models/releases/download/en_core_web_trf-3.8.0/en_core_web_trf-3.8.0-py3-none-any.whl"
|
|
53
|
+
|
|
54
|
+
[tool.ruff]
|
|
55
|
+
line-length = 88
|
|
56
|
+
src = ["src"]
|
|
57
|
+
|
|
58
|
+
[tool.ruff.lint]
|
|
59
|
+
select = [
|
|
60
|
+
"A",
|
|
61
|
+
"ANN",
|
|
62
|
+
"ARG",
|
|
63
|
+
"ASYNC",
|
|
64
|
+
"B",
|
|
65
|
+
"BLE",
|
|
66
|
+
"C4",
|
|
67
|
+
"C90",
|
|
68
|
+
"D",
|
|
69
|
+
"DTZ",
|
|
70
|
+
"E",
|
|
71
|
+
"ERA",
|
|
72
|
+
"EXE",
|
|
73
|
+
"F",
|
|
74
|
+
"FBT",
|
|
75
|
+
"FLY",
|
|
76
|
+
"FURB",
|
|
77
|
+
"G",
|
|
78
|
+
"I",
|
|
79
|
+
"LOG",
|
|
80
|
+
"N",
|
|
81
|
+
"PERF",
|
|
82
|
+
"PGH",
|
|
83
|
+
"PIE",
|
|
84
|
+
"PLC",
|
|
85
|
+
"PLE",
|
|
86
|
+
"PLW",
|
|
87
|
+
"PT",
|
|
88
|
+
"PTH",
|
|
89
|
+
"PYI",
|
|
90
|
+
"RET",
|
|
91
|
+
"RSE",
|
|
92
|
+
"RUF",
|
|
93
|
+
"SIM",
|
|
94
|
+
"SLOT",
|
|
95
|
+
"T20",
|
|
96
|
+
"UP",
|
|
97
|
+
"W",
|
|
98
|
+
"YTT",
|
|
99
|
+
]
|
|
100
|
+
ignore = [
|
|
101
|
+
"D200",
|
|
102
|
+
"D212",
|
|
103
|
+
"PLC0415",
|
|
104
|
+
]
|
|
105
|
+
allowed-confusables = [
|
|
106
|
+
"–",
|
|
107
|
+
"’",
|
|
108
|
+
"‘",
|
|
109
|
+
"‐",
|
|
110
|
+
"‑",
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
[tool.ruff.lint.pycodestyle]
|
|
114
|
+
max-doc-length = 88
|
|
115
|
+
|
|
116
|
+
[tool.ruff.lint.pydocstyle]
|
|
117
|
+
convention = "google"
|
|
118
|
+
|
|
119
|
+
[tool.basedpyright]
|
|
120
|
+
typeCheckingMode = "recommended"
|
|
121
|
+
extraPaths = [
|
|
122
|
+
"tests",
|
|
123
|
+
"research",
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
[tool.pytest.ini_options]
|
|
127
|
+
testpaths = ["tests"]
|
|
128
|
+
addopts = [
|
|
129
|
+
"--import-mode=importlib",
|
|
130
|
+
"--strict-markers",
|
|
131
|
+
]
|
|
132
|
+
markers = ["pipeline: exercises a search through a real pipeline"]
|
|
133
|
+
pythonpath = ["tests"]
|
|
134
|
+
|
|
135
|
+
[tool.coverage.run]
|
|
136
|
+
source = ["src"]
|
|
137
|
+
branch = true
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["uv_build>=0.12.3,<0.13"]
|
|
3
|
+
build-backend = "uv_build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "kwic"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Key Word In Context"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [{ name = "Eva", email = "eva.evangelisti03@gmail.com" }]
|
|
14
|
+
dependencies = [
|
|
15
|
+
"spacy>=3.8.15",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[project.optional-dependencies]
|
|
19
|
+
lemminflect = ["lemminflect>=0.2.3"]
|
|
20
|
+
stanza = ["stanza>=1.14.0"]
|
|
21
|
+
|
|
22
|
+
[project.urls]
|
|
23
|
+
Repository = "https://github.com/evaevangelisti/kwic"
|
|
24
|
+
|
|
25
|
+
[dependency-groups]
|
|
26
|
+
docs = [
|
|
27
|
+
"myst-parser>=5.1.0",
|
|
28
|
+
"shibuya>=2026.7.12",
|
|
29
|
+
"sphinx>=9.1.0",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
lint = [
|
|
33
|
+
"ruff>=0.16.2",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
models = [
|
|
37
|
+
"en-core-web-lg",
|
|
38
|
+
"en-core-web-sm",
|
|
39
|
+
"en-core-web-trf",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
test = [
|
|
43
|
+
"hypothesis>=6.165.9",
|
|
44
|
+
"pytest>=9.1.1",
|
|
45
|
+
"pytest-cov>=7.1.0",
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
typing = [
|
|
49
|
+
"basedpyright>=1.39.9",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
# The pipelines are published as wheels off their own releases rather than to
|
|
53
|
+
# an index, so a lock file has to be told where each one is.
|
|
54
|
+
[tool.uv.sources]
|
|
55
|
+
en-core-web-sm = { url = "https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.8.0/en_core_web_sm-3.8.0-py3-none-any.whl" }
|
|
56
|
+
en-core-web-lg = { url = "https://github.com/explosion/spacy-models/releases/download/en_core_web_lg-3.8.0/en_core_web_lg-3.8.0-py3-none-any.whl" }
|
|
57
|
+
en-core-web-trf = { url = "https://github.com/explosion/spacy-models/releases/download/en_core_web_trf-3.8.0/en_core_web_trf-3.8.0-py3-none-any.whl" }
|
|
58
|
+
|
|
59
|
+
[tool.ruff]
|
|
60
|
+
line-length = 88
|
|
61
|
+
src = ["src"]
|
|
62
|
+
|
|
63
|
+
[tool.ruff.lint]
|
|
64
|
+
select = [
|
|
65
|
+
"A", # flake8-builtins
|
|
66
|
+
"ANN", # flake8-annotations
|
|
67
|
+
"ARG", # flake8-unused-arguments
|
|
68
|
+
"ASYNC", # flake8-async
|
|
69
|
+
"B", # flake8-bugbear
|
|
70
|
+
"BLE", # flake8-blind-except
|
|
71
|
+
"C4", # flake8-comprehensions
|
|
72
|
+
"C90", # mccabe
|
|
73
|
+
"D", # pydocstyle
|
|
74
|
+
"DTZ", # flake8-datetimez
|
|
75
|
+
"E", # pycodestyle, errors
|
|
76
|
+
"ERA", # eradicate
|
|
77
|
+
"EXE", # flake8-executable
|
|
78
|
+
"F", # Pyflakes
|
|
79
|
+
"FBT", # flake8-boolean-trap
|
|
80
|
+
"FLY", # flynt
|
|
81
|
+
"FURB", # refurb
|
|
82
|
+
"G", # flake8-logging-format
|
|
83
|
+
"I", # isort
|
|
84
|
+
"LOG", # flake8-logging
|
|
85
|
+
"N", # pep8-naming
|
|
86
|
+
"PERF", # Perflint
|
|
87
|
+
"PGH", # pygrep-hooks
|
|
88
|
+
"PIE", # flake8-pie
|
|
89
|
+
"PLC", # Pylint, conventions
|
|
90
|
+
"PLE", # Pylint, errors
|
|
91
|
+
"PLW", # Pylint, warnings
|
|
92
|
+
"PT", # flake8-pytest-style
|
|
93
|
+
"PTH", # flake8-use-pathlib
|
|
94
|
+
"PYI", # flake8-pyi
|
|
95
|
+
"RET", # flake8-return
|
|
96
|
+
"RSE", # flake8-raise
|
|
97
|
+
"RUF", # Ruff-specific rules
|
|
98
|
+
"SIM", # flake8-simplify
|
|
99
|
+
"SLOT", # flake8-slots
|
|
100
|
+
"T20", # flake8-print
|
|
101
|
+
"UP", # pyupgrade
|
|
102
|
+
"W", # pycodestyle, warnings
|
|
103
|
+
"YTT", # flake8-2020
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
ignore = [
|
|
107
|
+
"D200", # A docstring is written across three lines, however short.
|
|
108
|
+
"D212", # Its summary opens on the line below the quotes.
|
|
109
|
+
"PLC0415", # An engine imports what it wraps where it loads it, not before.
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
# A text sets its apostrophes and its hyphens typographically, which is what
|
|
113
|
+
# the search unifies before it reads a lemma back out of one.
|
|
114
|
+
allowed-confusables = ["–", "’", "‘", "‐", "‑"]
|
|
115
|
+
|
|
116
|
+
[tool.ruff.lint.pycodestyle]
|
|
117
|
+
max-doc-length = 88
|
|
118
|
+
|
|
119
|
+
[tool.ruff.lint.pydocstyle]
|
|
120
|
+
convention = "google"
|
|
121
|
+
|
|
122
|
+
[tool.basedpyright]
|
|
123
|
+
typeCheckingMode = "recommended"
|
|
124
|
+
|
|
125
|
+
# Where the suite and the studies keep what they share, which pytest and the
|
|
126
|
+
# scripts put on the path too.
|
|
127
|
+
extraPaths = ["tests", "research"]
|
|
128
|
+
|
|
129
|
+
[tool.pytest.ini_options]
|
|
130
|
+
testpaths = ["tests"]
|
|
131
|
+
addopts = ["--import-mode=importlib", "--strict-markers"]
|
|
132
|
+
|
|
133
|
+
# A pipeline is loaded once and read by every property, which is slow enough
|
|
134
|
+
# to be worth naming so that a run can leave it out.
|
|
135
|
+
markers = ["pipeline: exercises a search through a real pipeline"]
|
|
136
|
+
|
|
137
|
+
# The generators and the contexts the suite shares are written once, beside
|
|
138
|
+
# the tests drawing from them.
|
|
139
|
+
pythonpath = ["tests"]
|
|
140
|
+
|
|
141
|
+
[tool.coverage.run]
|
|
142
|
+
source = ["src"]
|
|
143
|
+
branch = true
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Locating the lemmas of a query in the contexts that attest them.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .engines import Engine, SpacyEngine
|
|
6
|
+
from .models import POS, Context, Match, Offsets, Query, Token
|
|
7
|
+
from .search import Locator
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"POS",
|
|
11
|
+
"Context",
|
|
12
|
+
"Engine",
|
|
13
|
+
"Locator",
|
|
14
|
+
"Match",
|
|
15
|
+
"Offsets",
|
|
16
|
+
"Query",
|
|
17
|
+
"SpacyEngine",
|
|
18
|
+
"Token",
|
|
19
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Values a search never varies.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
SPACY_PIPELINE = "en_core_web_sm"
|
|
6
|
+
"""The spaCy pipeline loaded unless another is named. What the larger English
|
|
7
|
+
pipelines add is vectors, which a search does not read."""
|
|
8
|
+
|
|
9
|
+
STANZA_LANGUAGE = "en"
|
|
10
|
+
"""The language Stanza loads its processors for unless another is named."""
|
|
11
|
+
|
|
12
|
+
BATCH_SIZE = 256
|
|
13
|
+
"""How many contexts a model reads at a time. Larger batches amortise the call
|
|
14
|
+
into the model and hold more contexts in memory."""
|
|
15
|
+
|
|
16
|
+
PROCESSES = 1
|
|
17
|
+
"""How many processes a pipeline may run. More than one pays off over long
|
|
18
|
+
runs alone, each having to load the model again."""
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""
|
|
2
|
+
The analysers a search may read with.
|
|
3
|
+
|
|
4
|
+
Only spaCy is loaded from here, it being the one dependency the package
|
|
5
|
+
takes. The others are extras, imported from the module that wraps them.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .base import Engine
|
|
9
|
+
from .spacy import SpacyEngine
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"Engine",
|
|
13
|
+
"SpacyEngine",
|
|
14
|
+
]
|