grobid-client-python 0.2.0__tar.gz → 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/PKG-INFO +7 -6
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/Readme.md +6 -5
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client/grobid_client.py +71 -65
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client_python.egg-info/PKG-INFO +7 -6
- grobid_client_python-0.2.1/grobid_client_python.egg-info/scm_version.json +8 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/pyproject.toml +1 -1
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/test_grobid_client.py +37 -0
- grobid_client_python-0.2.0/grobid_client_python.egg-info/scm_version.json +0 -8
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/.github/dependabot.yml +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/.github/workflows/ci-build.yml +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/.github/workflows/ci-release.yml +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/.gitignore +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/LICENSE +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/MANIFEST.in +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/config.json +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/example.py +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client/__init__.py +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client/client.py +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client/format/TEI2LossyJSON.py +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client/format/TEI2LossyJSON_cli.py +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client/format/TEI2Markdown.py +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client/format/TEI2Markdown_cli.py +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client/format/__init__.py +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client/format/__main__.py +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client/format/validate_json_refs.py +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client/py.typed +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client_python.egg-info/SOURCES.txt +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client_python.egg-info/dependency_links.txt +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client_python.egg-info/entry_points.txt +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client_python.egg-info/requires.txt +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client_python.egg-info/scm_file_list.json +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client_python.egg-info/top_level.txt +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/pytest.ini +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/requirements.txt +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/resources/20180928112135.png +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/resources/20180928112138.csv +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/resources/test_pdf/0046d83a-edd6-4631-b57c-755cdcce8b7f.pdf +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/resources/test_pdf/0046d83a-edd6-4631-b57c-755cdcce8b7f.tei.xml +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/resources/test_pdf/mjb3wlzxcb2mc-migowebupload-1766042162782.grobid.tei.xml +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/resources/test_txt/reference-strings-1.txt +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/resources/test_txt/reference-strings-2.txt +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/resources/test_txt/reference-strings-3.txt +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/resources/test_txt/reference-strings-4.txt +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/resources/test_txt/reference-strings-5.txt +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/resources/test_txt/reference-strings-6.txt +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/resources/test_txt/reference-strings-7.txt +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/setup.cfg +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/__init__.py +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/conftest.py +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/resources/0046d83a-edd6-4631-b57c-755cdcce8b7f.tei.xml +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/resources/__init__.py +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/resources/article_withdrawn.grobid.tei.xml +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/resources/refs_offsets/10.1038_s41477-023-01501-1.grobid.tei.xml +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/resources/refs_offsets/10.1038_s41477-023-01501-1.json +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/resources/refs_offsets/10.1038_s41586-023-05895-y.grobid.tei.xml +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/resources/refs_offsets/10.1038_s41586-023-05895-y.json +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/resources/refs_offsets/10.1038_s41598-023-32039-z.grobid.tei.xml +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/resources/refs_offsets/10.1038_s41598-023-32039-z.json +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/resources/refs_offsets/10.1371_journal.pone.0218311.grobid.tei.xml +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/resources/refs_offsets/10.1371_journal.pone.0218311.json +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/resources/refs_offsets/10.7554_elife.78558.grobid.tei.xml +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/resources/refs_offsets/10.7554_elife.78558.json +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/resources/refs_offsets/2021.naacl-main.224.grobid.tei.xml +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/resources/repeated_text/ijms-24-05988.grobid.tei.xml +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/resources/repeated_text/ijms-24-05988.json +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/resources/repeated_text/ijms-24-05988.md +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/run_tests.py +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/test_client.py +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/test_config.json +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/test_conversions.py +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/test_integration.py +0 -0
- {grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/tests/test_s3.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: grobid-client-python
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Simple python client for GROBID REST services
|
|
5
5
|
Author-email: Patrice Lopez <patrice.lopez@science-miner.com>
|
|
6
6
|
Maintainer-email: Patrice Lopez <patrice.lopez@science-miner.com>, Luca Foppiano <lucanoro@duck.com>
|
|
@@ -636,18 +636,19 @@ settings.
|
|
|
636
636
|
|
|
637
637
|
### Choosing a queue size
|
|
638
638
|
|
|
639
|
-
`queue_size` controls how many files are grouped into one processing chunk. It is a memory
|
|
639
|
+
`queue_size` controls how many files are grouped into one processing chunk. It is a memory knob, not a
|
|
640
640
|
concurrency one: parallelism toward the GROBID server is set by `-n`, and each chunk is processed `n` files at a time.
|
|
641
641
|
When `queue_size` is not set, the client picks a sensible default per input type (see the table above); set it
|
|
642
642
|
explicitly only if you need to override that. A few guidelines:
|
|
643
643
|
|
|
644
644
|
- **Never set it below `n`.** Effective parallelism is `min(n, queue_size)`: a queue smaller than the thread pool
|
|
645
645
|
leaves workers idle. A bit of headroom above `n` (the default streaming value is 1.2 × `n`) keeps the pool busy.
|
|
646
|
-
- **Results are written
|
|
647
|
-
|
|
646
|
+
- **Results are written as they complete.** Each output file lands on disk as soon as its document has been
|
|
647
|
+
processed, whatever the queue size, so an interrupted run only loses the documents that were in flight
|
|
648
648
|
(already-written results are skipped on re-run unless `--force` is used).
|
|
649
|
-
- **Local PDF directories:** the queue holds only file paths
|
|
650
|
-
1000.
|
|
649
|
+
- **Local PDF directories:** the queue holds only file paths (each file is opened when it is sent), so large values
|
|
650
|
+
are essentially free — the default is 1000. At the end of each chunk the pool waits for its slowest document, so a
|
|
651
|
+
large queue keeps the workers busy.
|
|
651
652
|
- **Archives (zip/tar) and S3:** each chunk is read or downloaded *into memory* before processing starts, so peak RAM
|
|
652
653
|
grows with `queue_size × average file size`. Keep it moderate — the 1.2 × `n` default is a safe floor; going up to
|
|
653
654
|
a few multiples of `n` (e.g. 2–5 ×) trades memory for slightly better throughput around chunk boundaries.
|
|
@@ -414,18 +414,19 @@ settings.
|
|
|
414
414
|
|
|
415
415
|
### Choosing a queue size
|
|
416
416
|
|
|
417
|
-
`queue_size` controls how many files are grouped into one processing chunk. It is a memory
|
|
417
|
+
`queue_size` controls how many files are grouped into one processing chunk. It is a memory knob, not a
|
|
418
418
|
concurrency one: parallelism toward the GROBID server is set by `-n`, and each chunk is processed `n` files at a time.
|
|
419
419
|
When `queue_size` is not set, the client picks a sensible default per input type (see the table above); set it
|
|
420
420
|
explicitly only if you need to override that. A few guidelines:
|
|
421
421
|
|
|
422
422
|
- **Never set it below `n`.** Effective parallelism is `min(n, queue_size)`: a queue smaller than the thread pool
|
|
423
423
|
leaves workers idle. A bit of headroom above `n` (the default streaming value is 1.2 × `n`) keeps the pool busy.
|
|
424
|
-
- **Results are written
|
|
425
|
-
|
|
424
|
+
- **Results are written as they complete.** Each output file lands on disk as soon as its document has been
|
|
425
|
+
processed, whatever the queue size, so an interrupted run only loses the documents that were in flight
|
|
426
426
|
(already-written results are skipped on re-run unless `--force` is used).
|
|
427
|
-
- **Local PDF directories:** the queue holds only file paths
|
|
428
|
-
1000.
|
|
427
|
+
- **Local PDF directories:** the queue holds only file paths (each file is opened when it is sent), so large values
|
|
428
|
+
are essentially free — the default is 1000. At the end of each chunk the pool waits for its slowest document, so a
|
|
429
|
+
large queue keeps the workers busy.
|
|
429
430
|
- **Archives (zip/tar) and S3:** each chunk is read or downloaded *into memory* before processing starts, so peak RAM
|
|
430
431
|
grows with `queue_size × average file size`. Keep it moderate — the 1.2 × `n` default is a safe floor; going up to
|
|
431
432
|
a few multiples of `n` (e.g. 2–5 ×) trades memory for slightly better throughput around chunk boundaries.
|
|
@@ -646,6 +646,8 @@ class GrobidClient(ApiClient):
|
|
|
646
646
|
fs_files.extend(self._collect_directory_files(path, service))
|
|
647
647
|
elif os.path.isfile(path) and self._is_eligible_input(os.path.basename(path), service):
|
|
648
648
|
fs_files.append(path)
|
|
649
|
+
elif not os.path.exists(path):
|
|
650
|
+
self.logger.warning(f"Input path does not exist: {path}")
|
|
649
651
|
else:
|
|
650
652
|
self.logger.debug(f"Skipping input (not an eligible file/dir/archive): {path}")
|
|
651
653
|
|
|
@@ -927,6 +929,10 @@ class GrobidClient(ApiClient):
|
|
|
927
929
|
|
|
928
930
|
def _is_eligible_input(self, filename: str, service: str) -> bool:
|
|
929
931
|
"""Return True if a file name is a valid input for the given service."""
|
|
932
|
+
# macOS AppleDouble metadata entries (._paper.pdf), which tar and zip
|
|
933
|
+
# add next to the real files, carry the extension but not the document
|
|
934
|
+
if filename.startswith("._"):
|
|
935
|
+
return False
|
|
930
936
|
if filename.endswith(".pdf") or filename.endswith(".PDF"):
|
|
931
937
|
return True
|
|
932
938
|
if service == 'processCitationList' and (
|
|
@@ -1529,75 +1535,75 @@ class GrobidClient(ApiClient):
|
|
|
1529
1535
|
|
|
1530
1536
|
results.append(r)
|
|
1531
1537
|
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1538
|
+
for r in concurrent.futures.as_completed(results):
|
|
1539
|
+
input_file, status, text = r.result()
|
|
1540
|
+
filename = self._output_file_name(input_file, input_path, output)
|
|
1535
1541
|
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1542
|
+
if status != 200 or text is None:
|
|
1543
|
+
self.logger.error(f"Processing of {input_file} failed with error {status}: {text}")
|
|
1544
|
+
error_count += 1
|
|
1545
|
+
# writing error file with suffixed error code
|
|
1546
|
+
error_filename = self._error_file_name(filename, status)
|
|
1547
|
+
try:
|
|
1548
|
+
self._write_atomic(error_filename, text if text is not None else "")
|
|
1549
|
+
self.logger.info(f"Error details written to {error_filename}")
|
|
1550
|
+
# A previous run may have failed with a different status code;
|
|
1551
|
+
# keep only the marker of this run so the error state of the
|
|
1552
|
+
# document stays unambiguous (and skippable).
|
|
1553
|
+
self._remove_error_files(filename, keep=error_filename)
|
|
1554
|
+
except OSError as e:
|
|
1555
|
+
self.logger.error(f"Failed to write error file {filename}: {str(e)}")
|
|
1556
|
+
else:
|
|
1557
|
+
processed_count += 1
|
|
1558
|
+
# writing TEI file
|
|
1559
|
+
try:
|
|
1560
|
+
self._write_atomic(filename, text)
|
|
1561
|
+
self.logger.debug(f"Successfully wrote TEI file: {filename}")
|
|
1556
1562
|
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1563
|
+
# The document no longer is in error: drop the marker left by
|
|
1564
|
+
# a previous failed run so it is not skipped by --skip-errors.
|
|
1565
|
+
self._remove_error_files(filename)
|
|
1560
1566
|
|
|
1561
1567
|
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1568
|
+
# Convert to JSON if requested
|
|
1569
|
+
if json_output:
|
|
1570
|
+
try:
|
|
1571
|
+
converter = TEI2LossyJSONConverter()
|
|
1572
|
+
json_data = converter.convert_tei_file(filename, stream=False)
|
|
1573
|
+
|
|
1574
|
+
if json_data:
|
|
1575
|
+
json_filename = filename.replace('.grobid.tei.xml', '.json')
|
|
1576
|
+
# Always write JSON file when TEI is written (respects --force behavior)
|
|
1577
|
+
json_filename_expanded = os.path.expanduser(json_filename)
|
|
1578
|
+
self._write_atomic(
|
|
1579
|
+
json_filename_expanded,
|
|
1580
|
+
json.dumps(json_data, indent=2, ensure_ascii=False))
|
|
1581
|
+
self.logger.debug(f"Successfully wrote JSON file: {json_filename_expanded}")
|
|
1582
|
+
else:
|
|
1583
|
+
self.logger.warning(f"Failed to convert TEI to JSON for {filename}")
|
|
1584
|
+
except Exception as e:
|
|
1585
|
+
self.logger.error(f"Failed to convert TEI to JSON for {filename}: {str(e)}")
|
|
1586
|
+
|
|
1587
|
+
# Convert to Markdown if requested
|
|
1588
|
+
if markdown_output:
|
|
1589
|
+
try:
|
|
1590
|
+
from .format.TEI2Markdown import TEI2MarkdownConverter
|
|
1591
|
+
converter = TEI2MarkdownConverter()
|
|
1592
|
+
markdown_data = converter.convert_tei_file(filename)
|
|
1593
|
+
|
|
1594
|
+
if markdown_data is not None:
|
|
1595
|
+
markdown_filename = filename.replace('.grobid.tei.xml', '.md')
|
|
1596
|
+
# Always write Markdown file when TEI is written (respects --force behavior)
|
|
1597
|
+
markdown_filename_expanded = os.path.expanduser(markdown_filename)
|
|
1598
|
+
self._write_atomic(markdown_filename_expanded, markdown_data)
|
|
1599
|
+
self.logger.debug(f"Successfully wrote Markdown file: {markdown_filename_expanded}")
|
|
1600
|
+
else:
|
|
1601
|
+
self.logger.warning(f"Failed to convert TEI to Markdown for {filename}")
|
|
1602
|
+
except Exception as e:
|
|
1603
|
+
self.logger.error(f"Failed to convert TEI to Markdown for {filename}: {str(e)}")
|
|
1604
|
+
|
|
1605
|
+
except OSError as e:
|
|
1606
|
+
self.logger.error(f"Failed to write TEI XML file {filename}: {str(e)}")
|
|
1601
1607
|
|
|
1602
1608
|
# Calculate batch statistics
|
|
1603
1609
|
batch_runtime = time.time() - batch_start_time
|
{grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client_python.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: grobid-client-python
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Simple python client for GROBID REST services
|
|
5
5
|
Author-email: Patrice Lopez <patrice.lopez@science-miner.com>
|
|
6
6
|
Maintainer-email: Patrice Lopez <patrice.lopez@science-miner.com>, Luca Foppiano <lucanoro@duck.com>
|
|
@@ -636,18 +636,19 @@ settings.
|
|
|
636
636
|
|
|
637
637
|
### Choosing a queue size
|
|
638
638
|
|
|
639
|
-
`queue_size` controls how many files are grouped into one processing chunk. It is a memory
|
|
639
|
+
`queue_size` controls how many files are grouped into one processing chunk. It is a memory knob, not a
|
|
640
640
|
concurrency one: parallelism toward the GROBID server is set by `-n`, and each chunk is processed `n` files at a time.
|
|
641
641
|
When `queue_size` is not set, the client picks a sensible default per input type (see the table above); set it
|
|
642
642
|
explicitly only if you need to override that. A few guidelines:
|
|
643
643
|
|
|
644
644
|
- **Never set it below `n`.** Effective parallelism is `min(n, queue_size)`: a queue smaller than the thread pool
|
|
645
645
|
leaves workers idle. A bit of headroom above `n` (the default streaming value is 1.2 × `n`) keeps the pool busy.
|
|
646
|
-
- **Results are written
|
|
647
|
-
|
|
646
|
+
- **Results are written as they complete.** Each output file lands on disk as soon as its document has been
|
|
647
|
+
processed, whatever the queue size, so an interrupted run only loses the documents that were in flight
|
|
648
648
|
(already-written results are skipped on re-run unless `--force` is used).
|
|
649
|
-
- **Local PDF directories:** the queue holds only file paths
|
|
650
|
-
1000.
|
|
649
|
+
- **Local PDF directories:** the queue holds only file paths (each file is opened when it is sent), so large values
|
|
650
|
+
are essentially free — the default is 1000. At the end of each chunk the pool waits for its slowest document, so a
|
|
651
|
+
large queue keeps the workers busy.
|
|
651
652
|
- **Archives (zip/tar) and S3:** each chunk is read or downloaded *into memory* before processing starts, so peak RAM
|
|
652
653
|
grows with `queue_size × average file size`. Keep it moderate — the 1.2 × `n` default is a safe floor; going up to
|
|
653
654
|
a few multiples of `n` (e.g. 2–5 ×) trades memory for slightly better throughput around chunk boundaries.
|
|
@@ -1378,6 +1378,43 @@ class TestSkipErrors:
|
|
|
1378
1378
|
assert (processed, errors, skipped) == (0, 0, 1)
|
|
1379
1379
|
|
|
1380
1380
|
|
|
1381
|
+
class TestIncrementalWrites:
|
|
1382
|
+
"""Results are written as each document finishes, not once the whole queue is done."""
|
|
1383
|
+
|
|
1384
|
+
def test_finished_document_is_written_while_others_are_in_flight(self):
|
|
1385
|
+
with patch('grobid_client.grobid_client.GrobidClient._test_server_connection'):
|
|
1386
|
+
with patch('grobid_client.grobid_client.GrobidClient._configure_logging'):
|
|
1387
|
+
client = GrobidClient(check_server=False)
|
|
1388
|
+
client.logger = Mock()
|
|
1389
|
+
|
|
1390
|
+
with tempfile.TemporaryDirectory() as d:
|
|
1391
|
+
inp = os.path.join(d, 'in')
|
|
1392
|
+
out = os.path.join(d, 'out')
|
|
1393
|
+
os.makedirs(inp)
|
|
1394
|
+
for name in ('a.pdf', 'b.pdf'):
|
|
1395
|
+
with open(os.path.join(inp, name), 'wb') as f:
|
|
1396
|
+
f.write(b'%PDF')
|
|
1397
|
+
a_output = os.path.join(out, 'a.grobid.tei.xml')
|
|
1398
|
+
seen_while_in_flight = []
|
|
1399
|
+
|
|
1400
|
+
def fake_post(url, files=None, data=None, headers=None, timeout=None):
|
|
1401
|
+
if os.path.basename(files['input'][0]) == 'b.pdf':
|
|
1402
|
+
# Hold b until a's result reaches the disk (or give up)
|
|
1403
|
+
deadline = time.time() + 5
|
|
1404
|
+
while not os.path.isfile(a_output) and time.time() < deadline:
|
|
1405
|
+
time.sleep(0.01)
|
|
1406
|
+
seen_while_in_flight.append(os.path.isfile(a_output))
|
|
1407
|
+
resp = Mock()
|
|
1408
|
+
resp.text = '<TEI>ok</TEI>'
|
|
1409
|
+
return (resp, 200)
|
|
1410
|
+
|
|
1411
|
+
with patch.object(GrobidClient, 'post', side_effect=fake_post):
|
|
1412
|
+
client.process('processFulltextDocument', inp, output=out, n=2)
|
|
1413
|
+
|
|
1414
|
+
assert seen_while_in_flight == [True]
|
|
1415
|
+
assert os.path.isfile(os.path.join(out, 'b.grobid.tei.xml'))
|
|
1416
|
+
|
|
1417
|
+
|
|
1381
1418
|
class TestInMemoryDocuments:
|
|
1382
1419
|
"""Processing a PDF that is already in memory, without writing it to disk.
|
|
1383
1420
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client/format/TEI2LossyJSON.py
RENAMED
|
File without changes
|
{grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client/format/TEI2LossyJSON_cli.py
RENAMED
|
File without changes
|
{grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client/format/TEI2Markdown.py
RENAMED
|
File without changes
|
{grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client/format/TEI2Markdown_cli.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client/format/validate_json_refs.py
RENAMED
|
File without changes
|
|
File without changes
|
{grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client_python.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/grobid_client_python.egg-info/requires.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/resources/test_txt/reference-strings-1.txt
RENAMED
|
File without changes
|
{grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/resources/test_txt/reference-strings-2.txt
RENAMED
|
File without changes
|
{grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/resources/test_txt/reference-strings-3.txt
RENAMED
|
File without changes
|
{grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/resources/test_txt/reference-strings-4.txt
RENAMED
|
File without changes
|
{grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/resources/test_txt/reference-strings-5.txt
RENAMED
|
File without changes
|
{grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/resources/test_txt/reference-strings-6.txt
RENAMED
|
File without changes
|
{grobid_client_python-0.2.0 → grobid_client_python-0.2.1}/resources/test_txt/reference-strings-7.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|