Skip to content

Commit 849ec67

Browse files
committed
Rename batch_size config to queue_size
The value controls how many files are queued per processing chunk, not a batch or thread pool size. Renamed across config, client API, tests, and README. Old config files using batch_size are still accepted with a deprecation warning.
1 parent ed8164e commit 849ec67

9 files changed

Lines changed: 60 additions & 42 deletions

File tree

Readme.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ grobid_client --input "~/data/**/*.pdf" --output ~/results processFulltextDocu
190190
> [!NOTE]
191191
> `--input` accepts a directory, a single file, an **archive**, or a **glob pattern**:
192192
> - **Archives** (`.zip`, `.tar`, `.tar.gz`/`.tgz`, `.tar.bz2`/`.tbz2`) are streamed: eligible entries are read into
193-
> memory in chunks of `batch_size` and sent to GROBID straight from there — the archive is never fully decompressed and
193+
> memory in chunks of `queue_size` and sent to GROBID straight from there — the archive is never fully decompressed and
194194
> nothing but the results in `--output` ever touches the disk. If `--output` is omitted, results go to a directory named
195195
> after the archive (e.g. `papers.zip``papers/`).
196196
> - **Glob patterns** (`paper.zip`, `paper*.zip`, `**/paper*.zip`, `**/*.pdf`, …) are expanded with `**` recursion; each
@@ -384,7 +384,7 @@ settings.
384384
```json
385385
{
386386
"grobid_server": "http://localhost:8070",
387-
"batch_size": 1000,
387+
"queue_size": 1000,
388388
"sleep_time": 5,
389389
"timeout": 60,
390390
"coordinates": [
@@ -403,7 +403,7 @@ settings.
403403
| Parameter | Description | Default |
404404
|-----------------|------------------------------------------------------------------------------------------------------------------|-------------------------|
405405
| `grobid_server` | GROBID server URL | `http://localhost:8070` |
406-
| `batch_size` | Thread pool size. **Tune carefully: a large batch size will result in the data being written less frequently** | 1000 |
406+
| `queue_size` | Number of files queued per processing chunk. **Tune carefully: a large queue size will result in the data being written less frequently** | 1000 |
407407
| `sleep_time` | Wait time when server is busy (seconds) | 5 |
408408
| `timeout` | Client-side timeout (seconds) | 180 |
409409
| `coordinates` | XML elements for coordinate extraction | See above |

config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"grobid_server": "http://localhost:8070",
3-
"batch_size": 1000,
3+
"queue_size": 1000,
44
"timeout": 180,
55
"sleep_time": 5,
66
"coordinates": [

grobid_client/grobid_client.py

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ class GrobidClient(ApiClient):
9191
# Default configuration values
9292
DEFAULT_CONFIG: dict = {
9393
'grobid_server': 'http://localhost:8070',
94-
'batch_size': 10,
94+
'queue_size': 10,
9595
'sleep_time': 5,
9696
'timeout': 180,
9797
'coordinates': [
@@ -121,7 +121,7 @@ class GrobidClient(ApiClient):
121121
def __init__(
122122
self,
123123
grobid_server: Optional[str] = None,
124-
batch_size: Optional[int] = None,
124+
queue_size: Optional[int] = None,
125125
coordinates: Optional[list] = None,
126126
sleep_time: Optional[int] = None,
127127
timeout: Optional[int] = None,
@@ -143,7 +143,7 @@ def __init__(
143143
# This ensures CLI arguments override config file values
144144
self._set_config_params({
145145
'grobid_server': grobid_server,
146-
'batch_size': batch_size,
146+
'queue_size': queue_size,
147147
'coordinates': coordinates,
148148
'sleep_time': sleep_time,
149149
'timeout': timeout
@@ -328,6 +328,11 @@ def _load_config(self, path: str = "./config.json") -> None:
328328
config_json = config_file.read()
329329
# Update the default config with values from the file
330330
file_config = json.loads(config_json)
331+
if 'batch_size' in file_config:
332+
file_config.setdefault('queue_size', file_config.pop('batch_size'))
333+
temp_logger.warning(
334+
"Config key 'batch_size' is deprecated, use 'queue_size' instead"
335+
)
331336
self.config.update(file_config)
332337
temp_logger.info("Configuration file loaded successfully")
333338
except FileNotFoundError as e:
@@ -850,11 +855,11 @@ def _run_file_batches(
850855
markdown_output: bool,
851856
skip_errors: bool = False
852857
) -> Tuple[int, int, int]:
853-
"""Run process_batch over a list of files in chunks of batch_size.
858+
"""Run process_batch over a list of files in chunks of queue_size.
854859
855860
Returns the aggregated (processed, errors, skipped) counts.
856861
"""
857-
batch_size_pdf = self.config["batch_size"]
862+
queue_size = self.config["queue_size"]
858863
processed_files_count = 0
859864
errors_files_count = 0
860865
skipped_files_count = 0
@@ -870,7 +875,7 @@ def _run_file_batches(
870875

871876
batch.append(input_file)
872877

873-
if len(batch) == batch_size_pdf:
878+
if len(batch) == queue_size:
874879
batch_processed, batch_errors, batch_skipped = self.process_batch(
875880
service, batch, input_path, output, n, generate_ids,
876881
consolidate_header, consolidate_citations, include_raw_citations,
@@ -1057,7 +1062,7 @@ def process_archive(
10571062
"""Process the eligible files contained in a zip/tar archive.
10581063
10591064
The archive is never fully decompressed: entries are read straight into
1060-
memory in chunks of ``batch_size`` (from the config) and each chunk is
1065+
memory in chunks of ``queue_size`` (from the config) and each chunk is
10611066
sent to GROBID via ``process_batch``, so memory usage stays bounded by
10621067
the chunk size and nothing but the results ever touches the disk. (The
10631068
exception is ``processCitationList``, whose ``.txt`` inputs are read
@@ -1112,7 +1117,7 @@ def _process_archive_core(
11121117
Does not print the final summary (the caller does), so it can be
11131118
aggregated with other inputs when resolving a glob pattern.
11141119
"""
1115-
batch_size_pdf = self.config["batch_size"]
1120+
queue_size = self.config["queue_size"]
11161121

11171122
# Results must survive the temporary extraction directories, so when no
11181123
# output is given we default to a directory named after the archive. For
@@ -1151,8 +1156,8 @@ def _process_archive_core(
11511156
# read straight from the archive into memory and posted from there.
11521157
use_disk = service == 'processCitationList'
11531158

1154-
for chunk_start in range(0, total_files, batch_size_pdf):
1155-
chunk = eligible_members[chunk_start:chunk_start + batch_size_pdf]
1159+
for chunk_start in range(0, total_files, queue_size):
1160+
chunk = eligible_members[chunk_start:chunk_start + queue_size]
11561161

11571162
if not use_disk:
11581163
documents = []
@@ -1273,7 +1278,7 @@ def _process_remote_files(
12731278
if output is None:
12741279
output = "."
12751280

1276-
batch_size_pdf = self.config["batch_size"]
1281+
queue_size = self.config["queue_size"]
12771282
print(f"Found {total} remote file(s) to process")
12781283
processed_count = 0
12791284
error_count = 0
@@ -1284,8 +1289,8 @@ def _process_remote_files(
12841289
# fetched straight into memory and posted from there.
12851290
use_disk = service == 'processCitationList'
12861291

1287-
for chunk_start in range(0, total, batch_size_pdf):
1288-
chunk = uris[chunk_start:chunk_start + batch_size_pdf]
1292+
for chunk_start in range(0, total, queue_size):
1293+
chunk = uris[chunk_start:chunk_start + queue_size]
12891294

12901295
if not use_disk:
12911296
documents = []

tests/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def temp_config_file(temp_dir):
2323
"""Create a temporary config file for tests."""
2424
config = {
2525
'grobid_server': 'http://localhost:8070',
26-
'batch_size': 10,
26+
'queue_size': 10,
2727
'coordinates': ["persName", "figure"],
2828
'sleep_time': 2,
2929
'timeout': 30,

tests/test_config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"grobid_server": "http://localhost:8070",
3-
"batch_size": 10,
3+
"queue_size": 10,
44
"coordinates": ["persName", "figure", "ref"],
55
"sleep_time": 2,
66
"timeout": 30,

tests/test_conversions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def setup_method(self):
3939

4040
self.test_config = {
4141
'grobid_server': 'http://localhost:8070',
42-
'batch_size': 10,
42+
'queue_size': 10,
4343
'sleep_time': 5,
4444
'timeout': 180,
4545
'logging': {

tests/test_grobid_client.py

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def setup_method(self):
2222
"""Set up test fixtures."""
2323
self.test_config = {
2424
'grobid_server': 'http://localhost:8070',
25-
'batch_size': 1000,
25+
'queue_size': 1000,
2626
'coordinates': ["persName", "figure", "ref"],
2727
'sleep_time': 5,
2828
'timeout': 60,
@@ -43,7 +43,7 @@ def test_init_default_values(self, mock_configure_logging, mock_test_server):
4343
client = GrobidClient(check_server=False)
4444

4545
assert client.config['grobid_server'] == 'http://localhost:8070'
46-
assert client.config['batch_size'] == 10
46+
assert client.config['queue_size'] == 10
4747
assert client.config['sleep_time'] == 5
4848
assert client.config['timeout'] == 180
4949
assert 'persName' in client.config['coordinates']
@@ -58,15 +58,15 @@ def test_init_custom_values(self, mock_configure_logging, mock_test_server):
5858
custom_coords = ["figure", "ref"]
5959
client = GrobidClient(
6060
grobid_server='http://custom:9090',
61-
batch_size=500,
61+
queue_size=500,
6262
coordinates=custom_coords,
6363
sleep_time=10,
6464
timeout=120,
6565
check_server=False
6666
)
6767

6868
assert client.config['grobid_server'] == 'http://custom:9090'
69-
assert client.config['batch_size'] == 500
69+
assert client.config['queue_size'] == 500
7070
assert client.config['coordinates'] == custom_coords
7171
assert client.config['sleep_time'] == 10
7272
assert client.config['timeout'] == 120
@@ -114,6 +114,19 @@ def test_load_config_success(self, mock_configure_logging, mock_test_server, moc
114114
mock_file.assert_called_once_with('/path/to/config.json', 'r')
115115
assert client.config['grobid_server'] == 'http://test:8080'
116116

117+
@patch('builtins.open', new_callable=mock_open, read_data='{"batch_size": 250}')
118+
@patch('grobid_client.grobid_client.GrobidClient._test_server_connection')
119+
@patch('grobid_client.grobid_client.GrobidClient._configure_logging')
120+
def test_load_config_legacy_batch_size(self, mock_configure_logging, mock_test_server, mock_file):
121+
"""Test that the deprecated batch_size config key is mapped to queue_size."""
122+
mock_test_server.return_value = (True, 200)
123+
124+
client = GrobidClient(check_server=False)
125+
client._load_config('/path/to/config.json')
126+
127+
assert client.config['queue_size'] == 250
128+
assert 'batch_size' not in client.config
129+
117130
@patch('grobid_client.grobid_client.GrobidClient._test_server_connection')
118131
@patch('grobid_client.grobid_client.GrobidClient._configure_logging')
119132
def test_load_config_file_not_found(self, mock_configure_logging, mock_test_server):
@@ -680,12 +693,12 @@ def test_get_server_url_edge_cases(self, mock_configure_logging, mock_test_serve
680693
class TestArchiveInput:
681694
"""Tests for streaming zip/tar archives as input (process_archive)."""
682695

683-
def _client(self, batch_size=2):
696+
def _client(self, queue_size=2):
684697
with patch('grobid_client.grobid_client.GrobidClient._test_server_connection'):
685698
with patch('grobid_client.grobid_client.GrobidClient._configure_logging'):
686699
client = GrobidClient(check_server=False)
687700
client.logger = Mock()
688-
client.config['batch_size'] = batch_size
701+
client.config['queue_size'] = queue_size
689702
return client
690703

691704
@staticmethod
@@ -757,7 +770,7 @@ def test_safe_member_path_blocks_traversal(self):
757770
assert client._safe_member_path(dest, '.') is None
758771

759772
def test_process_zip_streams_all_pdfs(self):
760-
client = self._client(batch_size=2)
773+
client = self._client(queue_size=2)
761774
with tempfile.TemporaryDirectory() as d:
762775
zip_path = os.path.join(d, 'docs.zip')
763776
self._make_zip(zip_path, {
@@ -779,7 +792,7 @@ def test_process_zip_streams_all_pdfs(self):
779792
]
780793

781794
def test_process_targz(self):
782-
client = self._client(batch_size=10)
795+
client = self._client(queue_size=10)
783796
with tempfile.TemporaryDirectory() as d:
784797
tar_path = os.path.join(d, 'docs.tar.gz')
785798
self._make_targz(tar_path, {'x.pdf': b'%PDF-x', 'nested/y.pdf': b'%PDF-y'}, d)
@@ -802,7 +815,7 @@ def test_process_routes_archive_to_core(self):
802815
assert mock_core.call_args.args[1] == zip_path
803816

804817
def test_process_zip_default_output_named_after_archive(self):
805-
client = self._client(batch_size=10)
818+
client = self._client(queue_size=10)
806819
with tempfile.TemporaryDirectory() as d:
807820
zip_path = os.path.join(d, 'mydocs.zip')
808821
self._make_zip(zip_path, {'a.pdf': b'%PDF'})
@@ -811,7 +824,7 @@ def test_process_zip_default_output_named_after_archive(self):
811824

812825
def test_archive_entries_never_touch_disk(self):
813826
"""PDFs go from the archive straight to GROBID, without a temp dir."""
814-
client = self._client(batch_size=2)
827+
client = self._client(queue_size=2)
815828
with tempfile.TemporaryDirectory() as d:
816829
zip_path = os.path.join(d, 'docs.zip')
817830
self._make_zip(zip_path, {'a.pdf': b'%PDF-a', 'sub/b.pdf': b'%PDF-b'})
@@ -831,7 +844,7 @@ def fake_post(url, files=None, data=None, headers=None, timeout=None):
831844

832845
def test_citation_lists_are_still_extracted_to_disk(self):
833846
"""process_txt reads from a path, so citation lists keep the temp-dir route."""
834-
client = self._client(batch_size=10)
847+
client = self._client(queue_size=10)
835848
with tempfile.TemporaryDirectory() as d:
836849
zip_path = os.path.join(d, 'refs.zip')
837850
self._make_zip(zip_path, {'refs.txt': b'one reference per line'})
@@ -954,7 +967,7 @@ def fake_post(url=None, files=None, data=None, headers=None, timeout=None):
954967
def test_archive_processing_runs_the_preflight(self):
955968
import zipfile
956969
client = self._client()
957-
client.config['batch_size'] = 10
970+
client.config['queue_size'] = 10
958971
with tempfile.TemporaryDirectory() as d:
959972
zip_path = os.path.join(d, 'docs.zip')
960973
with zipfile.ZipFile(zip_path, 'w') as z:
@@ -974,7 +987,7 @@ def fake_post(url, files=None, data=None, headers=None, timeout=None):
974987
def test_local_files_skip_the_preflight(self):
975988
"""Plain file processing does not gain a new health call."""
976989
client = self._client()
977-
client.config['batch_size'] = 10
990+
client.config['queue_size'] = 10
978991
with tempfile.TemporaryDirectory() as d:
979992
with open(os.path.join(d, 'a.pdf'), 'wb') as f:
980993
f.write(b'%PDF')
@@ -994,12 +1007,12 @@ def fake_post(url, files=None, data=None, headers=None, timeout=None):
9941007
class TestGlobInput:
9951008
"""Tests for glob-pattern input resolution (--input as a glob)."""
9961009

997-
def _client(self, batch_size=50):
1010+
def _client(self, queue_size=50):
9981011
with patch('grobid_client.grobid_client.GrobidClient._test_server_connection'):
9991012
with patch('grobid_client.grobid_client.GrobidClient._configure_logging'):
10001013
client = GrobidClient(check_server=False)
10011014
client.logger = Mock()
1002-
client.config['batch_size'] = batch_size
1015+
client.config['queue_size'] = queue_size
10031016
return client
10041017

10051018
@staticmethod
@@ -1213,7 +1226,7 @@ def _client(self):
12131226
with patch('grobid_client.grobid_client.GrobidClient._configure_logging'):
12141227
client = GrobidClient(check_server=False)
12151228
client.logger = Mock()
1216-
client.config['batch_size'] = 50
1229+
client.config['queue_size'] = 50
12171230
return client
12181231

12191232
@staticmethod

tests/test_integration.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def setup_method(self):
2222
# Create a temporary config file
2323
self.temp_config = {
2424
'grobid_server': self.test_server_url,
25-
'batch_size': 10,
25+
'queue_size': 10,
2626
'coordinates': ["persName", "figure"],
2727
'sleep_time': 2,
2828
'timeout': 30,
@@ -60,7 +60,7 @@ def test_client_initialization_with_config_file(self, mock_get):
6060

6161
# Verify config was loaded
6262
assert client.config['grobid_server'] == self.test_server_url
63-
assert client.config['batch_size'] == 10
63+
assert client.config['queue_size'] == 10
6464
assert client.config['sleep_time'] == 2
6565
assert client.config['timeout'] == 30
6666

@@ -91,14 +91,14 @@ def test_configuration_validation(self):
9191
with patch('grobid_client.grobid_client.GrobidClient._configure_logging'):
9292
client = GrobidClient(
9393
grobid_server='http://custom:9090',
94-
batch_size=500,
94+
queue_size=500,
9595
config_path=self.config_file,
9696
check_server=False
9797
)
9898

9999
# Constructor values should override config file values (CLI precedence)
100100
assert client.config['grobid_server'] == 'http://custom:9090'
101-
assert client.config['batch_size'] == 500
101+
assert client.config['queue_size'] == 500
102102

103103
def test_logging_configuration(self):
104104
"""Test logging configuration from config file."""

tests/test_s3.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,12 @@ def _aws_env(monkeypatch):
3434
monkeypatch.setenv("AWS_DEFAULT_REGION", REGION)
3535

3636

37-
def _client(batch_size=2):
37+
def _client(queue_size=2):
3838
with patch.object(GrobidClient, "_test_server_connection"):
3939
with patch.object(GrobidClient, "_configure_logging"):
4040
c = GrobidClient(check_server=False)
4141
c.logger = Mock()
42-
c.config["batch_size"] = batch_size
42+
c.config["queue_size"] = queue_size
4343
return c
4444

4545

0 commit comments

Comments
 (0)