lcpcli 0.3.0__tar.gz → 0.3.2__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.
- {lcpcli-0.3.0 → lcpcli-0.3.2}/PKG-INFO +3 -2
- {lcpcli-0.3.0 → lcpcli-0.3.2}/lcpcli/__init__.py +1 -1
- {lcpcli-0.3.0 → lcpcli-0.3.2}/lcpcli/builder.py +74 -46
- {lcpcli-0.3.0 → lcpcli-0.3.2}/lcpcli/check_files.py +20 -16
- {lcpcli-0.3.0 → lcpcli-0.3.2}/lcpcli/conllu_builder.py +10 -13
- {lcpcli-0.3.0 → lcpcli-0.3.2}/lcpcli/corpert.py +5 -3
- {lcpcli-0.3.0 → lcpcli-0.3.2}/lcpcli/lcp_upload.py +301 -136
- {lcpcli-0.3.0 → lcpcli-0.3.2}/lcpcli/lcpcli.py +0 -52
- lcpcli-0.3.2/lcpcli/utils.py +235 -0
- {lcpcli-0.3.0 → lcpcli-0.3.2}/pyproject.toml +2 -1
- lcpcli-0.3.0/lcpcli/utils.py +0 -807
- {lcpcli-0.3.0 → lcpcli-0.3.2}/.gitignore +0 -0
- {lcpcli-0.3.0 → lcpcli-0.3.2}/LICENSE.txt +0 -0
- {lcpcli-0.3.0 → lcpcli-0.3.2}/README.md +0 -0
- {lcpcli-0.3.0 → lcpcli-0.3.2}/lcpcli/__main__.py +0 -0
- {lcpcli-0.3.0 → lcpcli-0.3.2}/lcpcli/cli.py +0 -0
- {lcpcli-0.3.0 → lcpcli-0.3.2}/lcpcli/data/free_video_corpus/input/doc.conllu +0 -0
- {lcpcli-0.3.0 → lcpcli-0.3.2}/lcpcli/data/free_video_corpus/input/meta.json +0 -0
- {lcpcli-0.3.0 → lcpcli-0.3.2}/lcpcli/data/free_video_corpus/input/namedentity.csv +0 -0
- {lcpcli-0.3.0 → lcpcli-0.3.2}/lcpcli/data/free_video_corpus/input/shot.csv +0 -0
- {lcpcli-0.3.0 → lcpcli-0.3.2}/lcpcli/data/free_video_corpus/output/media/bunny.mp4 +0 -0
- {lcpcli-0.3.0 → lcpcli-0.3.2}/lcpcli/data/input/in.conllu +0 -0
- {lcpcli-0.3.0 → lcpcli-0.3.2}/lcpcli/data/input/in.vert +0 -0
- {lcpcli-0.3.0 → lcpcli-0.3.2}/lcpcli/data/input/in_tei_spoken.xml +0 -0
- {lcpcli-0.3.0 → lcpcli-0.3.2}/lcpcli/data/lcp_corpus_template.json +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: lcpcli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: Helper for converting CONLLU files and uploading the corpus to LiRI Corpus Platform (LCP)
|
|
5
5
|
Project-URL: Homepage, https://github.com/liri-uzh/lcpcli
|
|
6
6
|
Project-URL: Issues, https://github.com/liri-uzh/lcpcli/issues
|
|
@@ -22,6 +22,7 @@ Requires-Dist: pandas>=2.2.2
|
|
|
22
22
|
Requires-Dist: py7zr>=0.20.5
|
|
23
23
|
Requires-Dist: requests>=2.30.0
|
|
24
24
|
Requires-Dist: tqdm>=4.65.0
|
|
25
|
+
Requires-Dist: tuspy==1.1.0
|
|
25
26
|
Requires-Dist: types-requests>=2.30.0.0
|
|
26
27
|
Requires-Dist: types-tqdm>=4.65.0.1
|
|
27
28
|
Requires-Dist: xmltodict>=0.13
|
|
@@ -18,6 +18,8 @@ ATYPES_LOOKUP = ("text", "dict", "labels")
|
|
|
18
18
|
NAMEDATALEN = 63
|
|
19
19
|
PATTERN_TXT = "(must start with a lower case, be at leat 2 characters long and only contain alpha-numerical characters)"
|
|
20
20
|
|
|
21
|
+
IS_NUM = re.compile(r"^[0-9]+(\.[0-9]+)?$")
|
|
22
|
+
|
|
21
23
|
|
|
22
24
|
def meta_subattr(meta: dict, k: str, v: Any) -> dict:
|
|
23
25
|
"""
|
|
@@ -26,11 +28,7 @@ def meta_subattr(meta: dict, k: str, v: Any) -> dict:
|
|
|
26
28
|
sub_attr = meta.setdefault(k, {})
|
|
27
29
|
if isinstance(v, list):
|
|
28
30
|
sub_attr["type"] = "labels"
|
|
29
|
-
elif (
|
|
30
|
-
isinstance(v, (int, float))
|
|
31
|
-
or isinstance(v, str)
|
|
32
|
-
and v.replace(".", "", 1).isdigit()
|
|
33
|
-
):
|
|
31
|
+
elif isinstance(v, (int, float)) or isinstance(v, str) and IS_NUM.match(v):
|
|
34
32
|
sub_attr["type"] = "text" if sub_attr.get("type") == "text" else "number"
|
|
35
33
|
elif isinstance(v, dict):
|
|
36
34
|
sub_attr["type"] = "dict"
|
|
@@ -48,6 +46,7 @@ def get_layer_method(layer: "Layer"):
|
|
|
48
46
|
corpus._layers.pop(layer._name, "")
|
|
49
47
|
fname = f"{layer._name.lower()}.csv"
|
|
50
48
|
corpus._files[fname].close()
|
|
49
|
+
os.unlink(corpus._files[fname].name)
|
|
51
50
|
corpus._files.pop(fname)
|
|
52
51
|
return GlobalAttribute(corpus, layer._name, args[0])
|
|
53
52
|
largs = [a for a in args]
|
|
@@ -168,6 +167,7 @@ class Corpus:
|
|
|
168
167
|
revision: int | float = 1,
|
|
169
168
|
url: str = "placeholder",
|
|
170
169
|
license: str | None = None,
|
|
170
|
+
tmp_dir: str | None = None,
|
|
171
171
|
):
|
|
172
172
|
self._name = name
|
|
173
173
|
self._document = document
|
|
@@ -185,10 +185,11 @@ class Corpus:
|
|
|
185
185
|
self._url = url
|
|
186
186
|
self._license = license
|
|
187
187
|
self._upperFrameDocument = 0
|
|
188
|
+
self._tmp_dir = tmp_dir
|
|
188
189
|
|
|
189
190
|
def _csv_writer(self, fn: str):
|
|
190
191
|
tmp = tempfile.NamedTemporaryFile(
|
|
191
|
-
"w+", encoding="utf-8", newline="\n", delete=False
|
|
192
|
+
"w+", encoding="utf-8", newline="\n", delete=False, dir=self._tmp_dir
|
|
192
193
|
)
|
|
193
194
|
self._files[fn] = tmp
|
|
194
195
|
return csv.writer(tmp)
|
|
@@ -339,7 +340,7 @@ class Corpus:
|
|
|
339
340
|
"corpusDescription": self._corpus_description,
|
|
340
341
|
"date": self._date,
|
|
341
342
|
"url": self._url,
|
|
342
|
-
"revision":
|
|
343
|
+
"revision": self._revision,
|
|
343
344
|
},
|
|
344
345
|
"firstClass": {
|
|
345
346
|
"token": self._token,
|
|
@@ -387,7 +388,11 @@ class Corpus:
|
|
|
387
388
|
if ais_global:
|
|
388
389
|
aopts["isGlobal"] = True
|
|
389
390
|
if aopts["type"] == "categorical" and not ais_global:
|
|
390
|
-
aopts["values"] = [
|
|
391
|
+
aopts["values"] = [
|
|
392
|
+
str(v)
|
|
393
|
+
for v in mapping.lookups[aname]
|
|
394
|
+
if v is not None and v != ""
|
|
395
|
+
]
|
|
391
396
|
elif aopts["type"] == "ref":
|
|
392
397
|
aopts.pop("type")
|
|
393
398
|
aopts.pop("nullable", "")
|
|
@@ -447,8 +452,7 @@ class Layer:
|
|
|
447
452
|
if re.match(r"[A-Z]", name):
|
|
448
453
|
corpus = self._corpus
|
|
449
454
|
layer = corpus._add_layer(name)
|
|
450
|
-
self.
|
|
451
|
-
layer._parents.append(self)
|
|
455
|
+
self.add(layer)
|
|
452
456
|
return get_layer_method(layer)
|
|
453
457
|
return super().__getattribute__(name)
|
|
454
458
|
|
|
@@ -494,7 +498,47 @@ class Layer:
|
|
|
494
498
|
ch.append(c)
|
|
495
499
|
return ch
|
|
496
500
|
|
|
497
|
-
def
|
|
501
|
+
def _update_parents_anchors(self):
|
|
502
|
+
"""Update the anchors of all the parents (recursively)"""
|
|
503
|
+
if not self._made:
|
|
504
|
+
return
|
|
505
|
+
corpus = self._corpus
|
|
506
|
+
parents = self._parents
|
|
507
|
+
while parents:
|
|
508
|
+
current_parents = [*parents]
|
|
509
|
+
parents = []
|
|
510
|
+
for parent in current_parents:
|
|
511
|
+
parents += parent._parents
|
|
512
|
+
for anc_name, anchors in self._anchorings.items():
|
|
513
|
+
if anc_name not in parent._anchorings:
|
|
514
|
+
parent._anchorings[anc_name] = [*anchors]
|
|
515
|
+
parent_anchors = parent._anchorings[anc_name]
|
|
516
|
+
if anchors[0] < parent_anchors[0]:
|
|
517
|
+
parent_anchors[0] = anchors[0]
|
|
518
|
+
if anc_name == "time" and parent._name == corpus._document:
|
|
519
|
+
if corpus._upperFrameDocument < parent_anchors[0]:
|
|
520
|
+
parent_anchors[0] = corpus._upperFrameDocument
|
|
521
|
+
corpus._upperFrameDocument = parent_anchors[1]
|
|
522
|
+
if anc_name != "location":
|
|
523
|
+
if anchors[1] > parent_anchors[1]:
|
|
524
|
+
parent_anchors[1] = anchors[1]
|
|
525
|
+
continue
|
|
526
|
+
if anchors[1] < parent_anchors[1]:
|
|
527
|
+
parent_anchors[1] = anchors[1]
|
|
528
|
+
if anchors[2] > parent_anchors[2]:
|
|
529
|
+
parent_anchors[2] = anchors[2]
|
|
530
|
+
if anchors[3] > parent_anchors[3]:
|
|
531
|
+
parent_anchors[3] = anchors[3]
|
|
532
|
+
|
|
533
|
+
def clear(self):
|
|
534
|
+
if not self._made:
|
|
535
|
+
return
|
|
536
|
+
# Prepare for deletion: no pointers to other layers/global attributes
|
|
537
|
+
self._parents = []
|
|
538
|
+
self._contains = []
|
|
539
|
+
self._attributes = {}
|
|
540
|
+
|
|
541
|
+
def make(self, clear=False):
|
|
498
542
|
if self._made:
|
|
499
543
|
return
|
|
500
544
|
corpus = self._corpus
|
|
@@ -528,35 +572,8 @@ class Layer:
|
|
|
528
572
|
)
|
|
529
573
|
self._anchorings["stream"] = [char_low, corpus._char_counter]
|
|
530
574
|
elif self._contains:
|
|
531
|
-
unset_anchorings = {a for a in ANCHORINGS if not self._anchorings.get(a)}
|
|
532
575
|
for child in self._contains:
|
|
533
576
|
child.make()
|
|
534
|
-
if child._name not in mapping.contains:
|
|
535
|
-
mapping.contains.append(child._name)
|
|
536
|
-
# Anchorings
|
|
537
|
-
for a in unset_anchorings:
|
|
538
|
-
if a not in child._anchorings:
|
|
539
|
-
continue
|
|
540
|
-
child_a = child._anchorings[a]
|
|
541
|
-
if a not in self._anchorings:
|
|
542
|
-
self._anchorings[a] = [*child_a]
|
|
543
|
-
self_a = self._anchorings[a]
|
|
544
|
-
if child_a[0] < self_a[0]:
|
|
545
|
-
self_a[0] = child_a[0]
|
|
546
|
-
if a == "time" and self._name == corpus._document:
|
|
547
|
-
if corpus._upperFrameDocument < self_a[0]:
|
|
548
|
-
self_a[0] = corpus._upperFrameDocument
|
|
549
|
-
corpus._upperFrameDocument = self_a[1]
|
|
550
|
-
if a != "location":
|
|
551
|
-
if child_a[1] > self_a[1]:
|
|
552
|
-
self_a[1] = child_a[1]
|
|
553
|
-
continue
|
|
554
|
-
if child_a[1] < self_a[1]:
|
|
555
|
-
self_a[1] = child_a[1]
|
|
556
|
-
if child_a[2] > self_a[2]:
|
|
557
|
-
self_a[2] = child_a[2]
|
|
558
|
-
if child_a[3] > self_a[3]:
|
|
559
|
-
self_a[3] = child_a[3]
|
|
560
577
|
if is_segment:
|
|
561
578
|
tokens = [
|
|
562
579
|
ch._attributes.values()
|
|
@@ -594,13 +611,17 @@ class Layer:
|
|
|
594
611
|
rows.append(v)
|
|
595
612
|
# Add any new attribute to mapping
|
|
596
613
|
for aname, attr in self._attributes.items():
|
|
614
|
+
atype = attr._type
|
|
597
615
|
if aname in mapping.attributes:
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
616
|
+
mattr = mapping.attributes[aname]
|
|
617
|
+
if atype == "text" and mattr["type"] != atype:
|
|
618
|
+
mattr["type"] = "text"
|
|
619
|
+
else:
|
|
620
|
+
try:
|
|
621
|
+
mapping.attributes[aname]["subtype"] = attr._subtype
|
|
622
|
+
except:
|
|
623
|
+
pass
|
|
602
624
|
continue
|
|
603
|
-
atype = attr._type
|
|
604
625
|
mapping.attributes[aname] = {
|
|
605
626
|
"type": atype,
|
|
606
627
|
"nullable": (
|
|
@@ -690,6 +711,9 @@ class Layer:
|
|
|
690
711
|
rows.append("" if val == None else str(val))
|
|
691
712
|
mapping.csvs["_main"].writerow(rows)
|
|
692
713
|
self._made = True
|
|
714
|
+
self._update_parents_anchors()
|
|
715
|
+
if clear:
|
|
716
|
+
self.clear()
|
|
693
717
|
return self
|
|
694
718
|
|
|
695
719
|
def set_time(self, *args):
|
|
@@ -745,13 +769,17 @@ class Layer:
|
|
|
745
769
|
return self
|
|
746
770
|
|
|
747
771
|
def add(self, *layers: "Layer"):
|
|
748
|
-
assert not self._contains or all(
|
|
749
|
-
|
|
750
|
-
), RuntimeError("All the children of a layer must be of the same type")
|
|
772
|
+
# assert not self._contains or all(
|
|
773
|
+
# l._name == self._contains[0]._name for l in layers
|
|
774
|
+
# ), RuntimeError("All the children of a layer must be of the same type")
|
|
751
775
|
self._contains += layers
|
|
776
|
+
mapping = self._corpus._layers[self._name]
|
|
752
777
|
for layer in layers:
|
|
778
|
+
if layer._name not in mapping.contains:
|
|
779
|
+
mapping.contains.append(layer._name)
|
|
753
780
|
if self not in layer._parents:
|
|
754
781
|
layer._parents.append(self)
|
|
782
|
+
layer._update_parents_anchors()
|
|
755
783
|
return self
|
|
756
784
|
|
|
757
785
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import csv
|
|
2
2
|
import json
|
|
3
3
|
import os
|
|
4
|
+
import re
|
|
4
5
|
import sys
|
|
5
6
|
|
|
6
7
|
from jsonschema import validate
|
|
7
|
-
from re import match, findall
|
|
8
8
|
from typing import Callable
|
|
9
9
|
from uuid import UUID
|
|
10
10
|
|
|
@@ -12,6 +12,8 @@ EXTENSIONS = (".csv", ".tsv")
|
|
|
12
12
|
LOOKUP_TYPES = ("dict", "text")
|
|
13
13
|
NAMEDATALEN = 63
|
|
14
14
|
|
|
15
|
+
IS_NUM = re.compile(r"^[0-9]+(\.[0-9]+)?$")
|
|
16
|
+
|
|
15
17
|
|
|
16
18
|
def is_lookup(p: dict) -> bool:
|
|
17
19
|
return p.get("type", "") in LOOKUP_TYPES or "ref" in p
|
|
@@ -86,16 +88,16 @@ class Checker:
|
|
|
86
88
|
assert UUID(uuid, version=4), SyntaxError(f"Invalid UUID ({uuid})")
|
|
87
89
|
|
|
88
90
|
def check_number(self, value: str, aname: str = "") -> None:
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if
|
|
91
|
+
is_num = IS_NUM.match(value.strip())
|
|
92
|
+
is_float = is_num and "." in value
|
|
93
|
+
if is_float:
|
|
92
94
|
raise TypeError(
|
|
93
95
|
f"Number attribute {aname} appears to contain floating values ({value}); add 'subtype': 'float' to its properties."
|
|
94
96
|
)
|
|
95
|
-
assert
|
|
97
|
+
assert is_num, TypeError(f"Number attribute {aname} is ill-formed: {value}")
|
|
96
98
|
|
|
97
99
|
def check_float(self, value: str, aname: str = "") -> None:
|
|
98
|
-
is_numerical = value.strip()
|
|
100
|
+
is_numerical = IS_NUM.match(value.strip())
|
|
99
101
|
assert is_numerical, TypeError(
|
|
100
102
|
f"Float number attribute {aname} is ill-formed: {value}"
|
|
101
103
|
)
|
|
@@ -109,6 +111,7 @@ class Checker:
|
|
|
109
111
|
)
|
|
110
112
|
|
|
111
113
|
def check_dict(self, str_obj: str, subtyps: dict) -> None:
|
|
114
|
+
error = ""
|
|
112
115
|
try:
|
|
113
116
|
json_obj = json.loads(str_obj)
|
|
114
117
|
assert isinstance(json_obj, dict), TypeError(
|
|
@@ -122,7 +125,7 @@ class Checker:
|
|
|
122
125
|
assert (
|
|
123
126
|
isinstance(v, (int, float))
|
|
124
127
|
or isinstance(v, str)
|
|
125
|
-
and
|
|
128
|
+
and IS_NUM.match(v)
|
|
126
129
|
), TypeError(f"Sub-attribute {k} is not a number ({v})")
|
|
127
130
|
elif typ in ("labels", "array"):
|
|
128
131
|
assert isinstance(v, list), TypeError(
|
|
@@ -132,15 +135,16 @@ class Checker:
|
|
|
132
135
|
assert isinstance(v, str), TypeError(
|
|
133
136
|
f"Sub-attribute {k} is not a valid text value ({v})"
|
|
134
137
|
)
|
|
135
|
-
except:
|
|
138
|
+
except Exception as e:
|
|
136
139
|
json_obj = None
|
|
140
|
+
error = str(e)
|
|
137
141
|
assert isinstance(json_obj, dict), SyntaxError(
|
|
138
|
-
f"Invalid syntax for dict entry ({str_obj})"
|
|
142
|
+
f"Invalid syntax for dict entry ({str_obj})\n{error}"
|
|
139
143
|
)
|
|
140
144
|
return None
|
|
141
145
|
|
|
142
146
|
def check_labels(self, bits: str, nbit: int) -> None:
|
|
143
|
-
assert match(r"^[01]*$", bits), ValueError(
|
|
147
|
+
assert re.match(r"^[01]*$", bits), ValueError(
|
|
144
148
|
f"Labels column should be series of 0s and 1s, got '{bits}'"
|
|
145
149
|
)
|
|
146
150
|
assert len(bits) == nbit, ValueError(
|
|
@@ -151,25 +155,25 @@ class Checker:
|
|
|
151
155
|
def check_ftsvector(self, vector: str) -> None:
|
|
152
156
|
whole_pattern = r"^('\d+([^']|'')*':\d+(,\d+)*(\s|$))+$"
|
|
153
157
|
simple_unit_pattern = r"('([^']|'')*':[^\s]+)(\s|$)"
|
|
154
|
-
units = findall(simple_unit_pattern, vector)
|
|
158
|
+
units = re.findall(simple_unit_pattern, vector)
|
|
155
159
|
for n, (unit, *_) in enumerate(units):
|
|
156
160
|
assert unit.startswith("'"), SyntaxError(
|
|
157
161
|
f"Each value in the tsvector must start with a single quote character ({unit} -- {n})"
|
|
158
162
|
)
|
|
159
|
-
assert match(r"'\d+", unit), SyntaxError(
|
|
163
|
+
assert re.match(r"'\d+", unit), SyntaxError(
|
|
160
164
|
f"Each value in the tsvector must start with a single quote character followed by an integer index ({unit} -- {n})"
|
|
161
165
|
)
|
|
162
|
-
m = match(r"'\d+(.*)':\d+(,\d+)*\s?$", unit)
|
|
166
|
+
m = re.match(r"'\d+(.*)':\d+(,\d+)*\s?$", unit)
|
|
163
167
|
assert m, SyntaxError(
|
|
164
168
|
f"Each value in the tsvector must end with a single quote followed by a colon and an integer index ({unit} -- {n})"
|
|
165
169
|
)
|
|
166
|
-
assert match(whole_pattern, vector), SyntaxError(
|
|
170
|
+
assert re.match(whole_pattern, vector), SyntaxError(
|
|
167
171
|
f"Invalid tsvector string ({vector})"
|
|
168
172
|
)
|
|
169
173
|
return None
|
|
170
174
|
|
|
171
175
|
def check_range(self, range: str, name: str) -> None:
|
|
172
|
-
m = match(r"\[(\d+),(\d+)\)", range)
|
|
176
|
+
m = re.match(r"\[(\d+),(\d+)\)", range)
|
|
173
177
|
assert m, SyntaxError(f"Range '{name}' not in the right format: {range}")
|
|
174
178
|
l, u = (m[1], m[2])
|
|
175
179
|
try:
|
|
@@ -192,7 +196,7 @@ class Checker:
|
|
|
192
196
|
return None
|
|
193
197
|
|
|
194
198
|
def check_xy_box(self, xy_box: str, name: str) -> None:
|
|
195
|
-
m = match(r"\((\d+),(\d+)\),\((\d+),(\d+)\)", xy_box)
|
|
199
|
+
m = re.match(r"\((\d+),(\d+)\),\((\d+),(\d+)\)", xy_box)
|
|
196
200
|
assert m, SyntaxError(f"Range '{name}' not in the right format: {xy_box}")
|
|
197
201
|
x1, y1, x2, y2 = (m[1], m[2], m[3], m[4])
|
|
198
202
|
try:
|
|
@@ -19,6 +19,8 @@ CONLLU_COLUMNS = (
|
|
|
19
19
|
"MISC",
|
|
20
20
|
)
|
|
21
21
|
|
|
22
|
+
IS_NUM = re.compile(r"^[0-9]+(\.[0-9]+)?$")
|
|
23
|
+
|
|
22
24
|
|
|
23
25
|
class LayerProxy:
|
|
24
26
|
dummy_corpus = Corpus("dummy")
|
|
@@ -36,10 +38,8 @@ class LayerProxy:
|
|
|
36
38
|
val = value
|
|
37
39
|
if isinstance(value, str):
|
|
38
40
|
val = value.strip()
|
|
39
|
-
if
|
|
40
|
-
val = int(val)
|
|
41
|
-
elif val.replace(".", "", 1).isdigit():
|
|
42
|
-
val = float(val)
|
|
41
|
+
if IS_NUM.match(val):
|
|
42
|
+
val = float(val) if "." in val else int(val)
|
|
43
43
|
self.attributes[name.strip()] = val
|
|
44
44
|
|
|
45
45
|
|
|
@@ -214,10 +214,8 @@ def create_corpus(
|
|
|
214
214
|
kwargs: dict = {}
|
|
215
215
|
for n, x in enumerate(column_names[2:]):
|
|
216
216
|
kwargs[x] = rest[n]
|
|
217
|
-
if rest[n]
|
|
218
|
-
kwargs[x] = int(rest[n])
|
|
219
|
-
elif rest[n].replace(".", "", 1).isdigit():
|
|
220
|
-
kwargs[x] = float(rest[n])
|
|
217
|
+
if IS_NUM.match(rest[n]):
|
|
218
|
+
kwargs[x] = float(rest[n]) if "." in rest[n] else int(rest[n])
|
|
221
219
|
if "feats" in column_names:
|
|
222
220
|
feats_idx = column_names.index("feats")
|
|
223
221
|
feats_str = rest[feats_idx - 2]
|
|
@@ -234,7 +232,8 @@ def create_corpus(
|
|
|
234
232
|
0 if kwargs["misc"].pop("SpaceAfter") == "No" else 1
|
|
235
233
|
)
|
|
236
234
|
token_proxy = TokenProxy()
|
|
237
|
-
|
|
235
|
+
head_val = kwargs.get("head", "")
|
|
236
|
+
if head_val and head_val != "_":
|
|
238
237
|
token_proxy.head = str(int(kwargs.pop("head")))
|
|
239
238
|
if "deprel" in kwargs:
|
|
240
239
|
token_proxy.deprel = kwargs.pop("deprel")
|
|
@@ -251,11 +250,9 @@ def create_corpus(
|
|
|
251
250
|
current_doc.entity.make()
|
|
252
251
|
print("Corpus created")
|
|
253
252
|
except Exception as e:
|
|
254
|
-
raise RuntimeError(
|
|
255
|
-
f"""Error when creating the corpus:
|
|
253
|
+
raise RuntimeError(f"""Error when creating the corpus:
|
|
256
254
|
{str(e)}
|
|
257
|
-
Are all input files valid CoNLL-U files?"""
|
|
258
|
-
)
|
|
255
|
+
Are all input files valid CoNLL-U files?""")
|
|
259
256
|
return c
|
|
260
257
|
|
|
261
258
|
|
|
@@ -4,7 +4,7 @@ import re
|
|
|
4
4
|
|
|
5
5
|
from .cli import _parse_cmd_line
|
|
6
6
|
from .conllu_builder import process_files
|
|
7
|
-
from .utils import default_json, find_config_file,
|
|
7
|
+
from .utils import default_json, find_config_file, say_yes
|
|
8
8
|
|
|
9
9
|
ERROR_MSG = """
|
|
10
10
|
Unrecognized input format.
|
|
@@ -21,6 +21,7 @@ class Corpert:
|
|
|
21
21
|
output=None,
|
|
22
22
|
extension=None,
|
|
23
23
|
combine=True,
|
|
24
|
+
force_yes=False,
|
|
24
25
|
**kwargs,
|
|
25
26
|
):
|
|
26
27
|
"""
|
|
@@ -39,6 +40,7 @@ class Corpert:
|
|
|
39
40
|
self._path = os.path.normpath(content)
|
|
40
41
|
self._combine = combine
|
|
41
42
|
self._on_disk = True
|
|
43
|
+
self._force_yes = force_yes
|
|
42
44
|
if os.path.isfile(content):
|
|
43
45
|
self._input_files.append(content)
|
|
44
46
|
elif os.path.isdir(content):
|
|
@@ -75,7 +77,7 @@ class Corpert:
|
|
|
75
77
|
print(
|
|
76
78
|
f"The destination folder {self.output} contains some JSON and/or CSV files which this operation might overwrite. Do you want to proceed?"
|
|
77
79
|
)
|
|
78
|
-
if not
|
|
80
|
+
if not say_yes(auto=self._force_yes):
|
|
79
81
|
print("Aborting the conversion operation.")
|
|
80
82
|
return
|
|
81
83
|
|
|
@@ -118,7 +120,7 @@ class Corpert:
|
|
|
118
120
|
f"The input folder ({self._path}) contains both files with a CoNLL extension and files with a different extension."
|
|
119
121
|
)
|
|
120
122
|
print("Ignore the files with a non-CoNLL extension?")
|
|
121
|
-
if
|
|
123
|
+
if say_yes(auto=self._force_yes):
|
|
122
124
|
doc_files = [
|
|
123
125
|
f for f in doc_files if f.lower().endswith((".conll", ".conllu"))
|
|
124
126
|
]
|