Skip to content

Commit 1f3a29e

Browse files
committed
OAProc: ensure binary outputs are not UTF-8 decoded (#2304)
1 parent 08031d4 commit 1f3a29e

File tree

3 files changed

+32
-4
lines changed

3 files changed

+32
-4
lines changed

pygeoapi/process/hello_world.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# Authors: Tom Kralidis <tomkralidis@gmail.com>
44
# Francesco Martinelli <francesco.martinelli@ingv.it>
55
#
6-
# Copyright (c) 2022 Tom Kralidis
6+
# Copyright (c) 2026 Tom Kralidis
77
# Copyright (c) 2024 Francesco Martinelli
88
#
99
# Permission is hereby granted, free of charge, to any person
@@ -29,6 +29,7 @@
2929
#
3030
# =================================================================
3131

32+
import json
3233
import logging
3334

3435
from pygeoapi.process.base import BaseProcessor, ProcessorExecuteError
@@ -82,6 +83,17 @@
8283
'minOccurs': 0,
8384
'maxOccurs': 1,
8485
'keywords': ['message']
86+
},
87+
'as_bytes': {
88+
'title': 'As bytes',
89+
'description': 'Whether to force return as bytes',
90+
'schema': {
91+
'type': 'bool',
92+
'default': False
93+
},
94+
'minOccurs': 0,
95+
'maxOccurs': 1,
96+
'keywords': ['as_bytes']
8597
}
8698
},
8799
'outputs': {
@@ -136,6 +148,9 @@ def execute(self, data, outputs=None):
136148
'value': value
137149
}
138150

151+
if data.get('as_bytes', False):
152+
json.dumps(produced_outputs).encode('utf-8')
153+
139154
return mimetype, produced_outputs
140155

141156
def __repr__(self):

pygeoapi/process/manager/base.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# Ricardo Garcia Silva <ricardo.garcia.silva@geobeyond.it>
55
# Francesco Martinelli <francesco.martinelli@ingv.it>
66
#
7-
# Copyright (c) 2024 Tom Kralidis
7+
# Copyright (c) 2026 Tom Kralidis
88
# (c) 2023 Ricardo Garcia Silva
99
# (c) 2026 Francesco Martinelli
1010
#
@@ -277,7 +277,8 @@ def _execute_handler_sync(self, p: BaseProcessor, job_id: str,
277277
current_status = JobStatus.running
278278
jfmt, outputs = p.execute(data_dict, **extra_execute_parameters)
279279

280-
if isinstance(outputs, bytes):
280+
if isinstance(outputs, bytes) and outputs.isascii():
281+
LOGGER.debug('output is ASCII; decoding utf-8')
281282
outputs = outputs.decode('utf-8')
282283

283284
if requested_response == RequestedResponse.document.value:

tests/api/test_processes.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ def test_describe_processes(config, api_):
9595
assert process['title'] == 'Hello World'
9696
assert len(process['keywords']) == 3
9797
assert len(process['links']) == 6
98-
assert len(process['inputs']) == 2
98+
assert len(process['inputs']) == 3
9999
assert len(process['outputs']) == 1
100100
assert len(process['outputTransmission']) == 1
101101
assert len(process['jobControlOptions']) == 2
@@ -242,6 +242,12 @@ def test_execute_process(config, api_):
242242
'name': 'Test document'
243243
}
244244
}
245+
req_body_10 = {
246+
'inputs': {
247+
'name': 'Test document as bytes response',
248+
'as_bytes': True
249+
}
250+
}
245251

246252
cleanup_jobs = set()
247253

@@ -410,6 +416,12 @@ def test_execute_process(config, api_):
410416
response2 = '{"id":"echo","value":"Hello Test document!"}'
411417
assert response == response2
412418

419+
req = mock_api_request(data=req_body_10)
420+
rsp_headers, code, response = execute_process(api_, req, 'hello-world')
421+
422+
response2 = '{"id":"echo","value":"Hello Test document as bytes response!"}' # noqa
423+
assert response == response2
424+
413425
# Cleanup
414426
time.sleep(2) # Allow time for any outstanding async jobs
415427
for _, job_id in cleanup_jobs:

0 commit comments

Comments
 (0)