Skip to content

Commit 8908c81

Browse files
committed
PR #736 Code style cleanup
to improve signal/noise ratio of PR (using darker and ruff)
1 parent ab9bcc1 commit 8908c81

4 files changed

Lines changed: 62 additions & 61 deletions

File tree

openeo/extra/job_management/__init__.py

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
from urllib3.util import Retry
3434

3535
from openeo import BatchJob, Connection
36+
from openeo.extra.job_management.thread_worker import _JobManagerWorkerThreadPool
3637
from openeo.internal.processes.parse import (
3738
Parameter,
3839
Process,
@@ -41,8 +42,6 @@
4142
from openeo.rest import OpenEoApiError
4243
from openeo.rest.auth.auth import BearerAuth
4344
from openeo.util import LazyLoadCache, deep_get, repr_truncate, rfc3339
44-
from openeo.extra.job_management.thread_worker import _JobManagerWorkerThreadPool
45-
4645

4746
_log = logging.getLogger(__name__)
4847

@@ -369,7 +368,15 @@ def run_loop():
369368
# TODO: support user-provided `stats`
370369
stats = collections.defaultdict(int)
371370

372-
while sum(job_db.count_by_status(statuses=["not_started", "created", "queued", "queued_for_start", "running"]).values()) > 0 and not self._stop_thread:
371+
while (
372+
sum(
373+
job_db.count_by_status(
374+
statuses=["not_started", "created", "queued", "queued_for_start", "running"]
375+
).values()
376+
)
377+
> 0
378+
and not self._stop_thread
379+
):
373380
self._job_update_loop(job_db=job_db, start_job=start_job, stats=stats)
374381
stats["run_jobs loop"] += 1
375382

@@ -380,10 +387,8 @@ def run_loop():
380387
if self._stop_thread:
381388
break
382389

383-
384390
self._thread = Thread(target=run_loop)
385391
self._thread.start()
386-
387392

388393
def stop_job_thread(self, timeout_seconds: Optional[float] = _UNSET):
389394
"""
@@ -402,7 +407,6 @@ def stop_job_thread(self, timeout_seconds: Optional[float] = _UNSET):
402407
if timeout_seconds is _UNSET:
403408
timeout_seconds = 2 * self.poll_sleep
404409
self._thread.join(timeout_seconds)
405-
406410
if self._thread.is_alive():
407411
_log.warning("Job thread did not stop after timeout")
408412
else:
@@ -502,7 +506,14 @@ def run_jobs(
502506

503507
self._worker_pool = _JobManagerWorkerThreadPool()
504508

505-
while sum(job_db.count_by_status(statuses=["not_started", "created", "queued", "queued_for_start", "running"]).values()) > 0:
509+
while (
510+
sum(
511+
job_db.count_by_status(
512+
statuses=["not_started", "created", "queued", "queued_for_start", "running"]
513+
).values()
514+
)
515+
> 0
516+
):
506517
self._job_update_loop(job_db=job_db, start_job=start_job, stats=stats)
507518
stats["run_jobs loop"] += 1
508519

@@ -564,7 +575,6 @@ def _job_update_loop(
564575

565576
for job, row in jobs_cancel:
566577
self.on_job_cancel(job, row)
567-
568578

569579
def _launch_job(self, start_job, df, i, backend_name, stats: Optional[dict] = None):
570580
"""Helper method for launching jobs
@@ -623,14 +633,12 @@ def _launch_job(self, start_job, df, i, backend_name, stats: Optional[dict] = No
623633
_log.info(f"Job : {job.job_id} created, submitting to thread pool")
624634
job_con = job.connection
625635
self._worker_pool.submit_work(
626-
627-
_JobManagerWorkerThreadPool.WORK_TYPE_START_JOB,
628-
(
629-
job_con.root_url,
630-
job_con.auth.bearer if isinstance(job_con.auth, BearerAuth) else None,
631-
job.job_id,
632-
),
633-
636+
_JobManagerWorkerThreadPool.WORK_TYPE_START_JOB,
637+
(
638+
job_con.root_url,
639+
job_con.auth.bearer if isinstance(job_con.auth, BearerAuth) else None,
640+
job.job_id,
641+
),
634642
)
635643
stats["job queued for start"] += 1
636644
df.loc[i, "status"] = "queued_for_start"
@@ -706,7 +714,6 @@ def _cancel_prolonged_job(self, job: BatchJob, row):
706714
elapsed = current_time - job_running_start_time
707715

708716
if elapsed > self._cancel_running_job_after:
709-
710717
_log.info(
711718
f"Cancelling long-running job {job.job_id} (after {elapsed}, running since {job_running_start_time})"
712719
)

openeo/extra/job_management/thread_worker.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
2-
from typing import Tuple, Any, List, Dict
1+
import concurrent.futures
32
import logging
3+
from typing import Any, Dict, List, Tuple
4+
45
import openeo
5-
import concurrent.futures
66

77
_log = logging.getLogger(__name__)
88

9+
910
class _JobManagerWorkerThreadPool:
1011
"""
1112
A worker thread pool for processing job management tasks asynchronously.
@@ -53,7 +54,6 @@ def submit_work(self, work_type: str, work_args: Tuple[Any, ...]) -> None:
5354
future = self._executor.submit(self._process_work_item, work_type, work_args)
5455
self._futures.append(future)
5556

56-
5757
def _process_work_item(self, work_type: str, work_args: Tuple[Any, ...]) -> Tuple[str, bool, str]:
5858
"""
5959
Process a work item and return its result.
@@ -75,10 +75,9 @@ def _process_work_item(self, work_type: str, work_args: Tuple[Any, ...]) -> Tupl
7575
"""
7676

7777
root_url, bearer, job_id = work_args
78-
78+
7979
try:
8080
if work_type == self.WORK_TYPE_START_JOB:
81-
8281
conn = openeo.connect(root_url)
8382
if bearer:
8483
conn.authenticate_bearer_token(bearer)
@@ -107,12 +106,13 @@ def process_futures(self, stats: Dict[str, int]) -> None:
107106
"""
108107

109108
if not self._futures:
110-
return # no futures to process
111-
109+
return # no futures to process
110+
112111
done, _ = concurrent.futures.wait(
113-
self._futures,
114-
timeout=0,
115-
return_when=concurrent.futures.FIRST_COMPLETED)
112+
self._futures,
113+
timeout=0,
114+
return_when=concurrent.futures.FIRST_COMPLETED,
115+
)
116116

117117
completed = []
118118

@@ -128,7 +128,7 @@ def process_futures(self, stats: Dict[str, int]) -> None:
128128
except Exception as e:
129129
_log.exception(f"Unexpected error processing future: {e}")
130130
completed.append(future)
131-
131+
132132
_log.info(f"Processed {len(completed)} jobs")
133133
# Remove processed futures
134134
for future in completed:
@@ -170,7 +170,7 @@ def _validate_work_args(self, work_type: str, work_args: Tuple[Any, ...]) -> Non
170170
error_msg = f"job_id must be a string, got {job_id}"
171171
_log.error(error_msg)
172172
raise TypeError(error_msg)
173-
173+
174174
def shutdown(self):
175175
"""
176176
Shut down the thread pool gracefully.
@@ -180,4 +180,4 @@ def shutdown(self):
180180
- It waits for all pending tasks to complete before shutting down.
181181
"""
182182
_log.info("Shutting down worker thread pool")
183-
self._executor.shutdown(wait=True)
183+
self._executor.shutdown(wait=True)

tests/extra/job_management/test_job_management.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
import threading
77
from pathlib import Path
88
from time import sleep
9-
from typing import Union
9+
from typing import Union
1010
from unittest import mock
11+
1112
import dirty_equals
1213
import geopandas
1314

@@ -364,8 +365,6 @@ def start_worker_thread():
364365
for filename in ["job-results.json", f"job_{job_id}.json", "result.data"]
365366
}
366367

367-
368-
369368
def test_on_error_log(self, tmp_path, requests_mock):
370369
backend = "http://foo.test"
371370
requests_mock.get(backend, json={"api_version": "1.1.0"})
@@ -598,8 +597,7 @@ def get_status(job_id, current_status):
598597
job_manager.run_jobs(df=df, start_job=self._create_year_job, job_db=job_db_path)
599598

600599
final_df = CsvJobDatabase(job_db_path).read()
601-
assert dirty_equals.IsPartialDict(id="job-2024", status=expected_status
602-
) == final_df.iloc[0].to_dict()
600+
assert dirty_equals.IsPartialDict(id="job-2024", status=expected_status) == final_df.iloc[0].to_dict()
603601

604602
assert dummy_backend_foo.batch_jobs == {
605603
"job-2024": {

tests/extra/job_management/test_thread_worker.py

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,27 @@
1-
import pytest
1+
import logging
22
import time
33
from collections import defaultdict
4-
import logging
4+
5+
import pytest
6+
57
from openeo.extra.job_management.thread_worker import _JobManagerWorkerThreadPool
68

9+
710
# Fixture for creating and cleaning up the worker thread pool
811
@pytest.fixture
912
def worker_pool():
1013
worker_pool = _JobManagerWorkerThreadPool()
1114
yield worker_pool
1215
worker_pool.shutdown()
1316

17+
1418
# Fixture for the shared stats dictionary
1519
@pytest.fixture
1620
def stats():
1721
return defaultdict(int)
1822

19-
class TestJobManagerWorkerThreadPool:
2023

24+
class TestJobManagerWorkerThreadPool:
2125
def test_worker_thread_lifecycle(self, worker_pool, caplog):
2226
with caplog.at_level(logging.INFO):
2327
assert not worker_pool._executor._shutdown
@@ -44,17 +48,12 @@ def test_start_job_success(self, worker_pool, stats, requests_mock):
4448
f"{backend_url}/jobs",
4549
json={"job_id": job_id, "status": "created"},
4650
status_code=201,
47-
headers={"openeo-identifier": job_id}
51+
headers={"openeo-identifier": job_id},
4852
)
4953
requests_mock.post(
50-
f"{backend_url}/jobs/{job_id}/results",
51-
json={"job_id": job_id, "status": "finished"},
52-
status_code=202
53-
)
54-
requests_mock.get(
55-
f"{backend_url}/jobs/{job_id}",
56-
json={"id": job_id, "status": "finished"}
54+
f"{backend_url}/jobs/{job_id}/results", json={"job_id": job_id, "status": "finished"}, status_code=202
5755
)
56+
requests_mock.get(f"{backend_url}/jobs/{job_id}", json={"id": job_id, "status": "finished"})
5857
# Submit several valid jobs
5958
for _ in range(3):
6059
worker_pool.submit_work(worker_pool.WORK_TYPE_START_JOB, (backend_url, "token", job_id))
@@ -82,11 +81,10 @@ def test_process_futures_mixed_success_and_failure(self, worker_pool, stats, req
8281
requests_mock.post(
8382
f"{backend_url_success}/jobs/{job_id_success}/results",
8483
json={"job_id": job_id_success, "status": "finished"},
85-
status_code=202
84+
status_code=202,
8685
)
8786
requests_mock.get(
88-
f"{backend_url_success}/jobs/{job_id_success}",
89-
json={"id": job_id_success, "status": "finished"}
87+
f"{backend_url_success}/jobs/{job_id_success}", json={"id": job_id_success, "status": "finished"}
9088
)
9189
# Failed job
9290
backend_url_failure = "https://failure.test"
@@ -105,29 +103,27 @@ def test_invalid_work_type(self, worker_pool, stats, requests_mock, caplog):
105103
backend_url = "https://foo.test"
106104
job_id = "job-123"
107105
requests_mock.get(backend_url, json={"api_version": "1.1.0"})
108-
106+
109107
# Test that invalid work type raises ValueError
110108
with pytest.raises(ValueError) as exc_info:
111109
worker_pool.submit_work("invalid_work_type", (backend_url, "token", job_id))
112-
110+
113111
assert "Unsupported work type: invalid_work_type" in str(exc_info.value)
114112
assert len(worker_pool._futures) == 0
115113

116-
117114
@pytest.mark.parametrize(
118-
"work_args,expected_log",
119-
[
120-
(("https://foo.test", "token"), "Expected 3 arguments for work type start_job, got 2"),
121-
((None, "token", "job-123"), "root_url must be a string"),
122-
]
115+
"work_args,expected_log",
116+
[
117+
(("https://foo.test", "token"), "Expected 3 arguments for work type start_job, got 2"),
118+
((None, "token", "job-123"), "root_url must be a string"),
119+
],
123120
)
124121
def test_invalid_work_args(self, worker_pool, stats, caplog, work_args, expected_log):
125-
with caplog.at_level(logging.ERROR):
122+
with caplog.at_level(logging.ERROR):
126123
with pytest.raises(Exception): # Expect an exception to be raised
127124
worker_pool.submit_work(worker_pool.WORK_TYPE_START_JOB, work_args)
128-
125+
129126
# Verify the expected log message
130127
assert expected_log in caplog.text
131128
assert len(worker_pool._futures) == 0
132129
assert stats["job start"] == 0
133-

0 commit comments

Comments
 (0)