Skip to content

Commit cc89546

Browse files
committed
Remove xcube.util.start_server dependency on xcube
start_server will now exit with a log message if xcube is not present in the environment, rather than raising an ImportError as before. Related to #56.
1 parent b54e521 commit cc89546

2 files changed

Lines changed: 56 additions & 12 deletions

File tree

test/test_util.py

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import argparse
12
import logging
23
import os
34
import sys
@@ -85,17 +86,19 @@ def test_write_stac(tmp_path, dataset, write_datasets, pre_existing_catalog):
8586
}
8687

8788

88-
orig_import = __import__
89-
def import_mock(name, *args):
90-
if name == 'pystac':
91-
raise ModuleNotFoundError("No module named 'pystac'")
92-
return orig_import(name, *args)
89+
9390

9491

9592
def test_write_stac_no_pystac(tmp_path, dataset):
9693
# Import hooks are the recommended "clean" way to do this, but don't work
9794
# in this case.
98-
with mock.patch('builtins.__import__', side_effect=import_mock):
95+
orig_import = __import__
96+
def import_mock(name, *args):
97+
if name == "pystac":
98+
raise ModuleNotFoundError("No module named 'pystac'")
99+
return orig_import(name, *args)
100+
101+
with mock.patch("builtins.__import__", side_effect=import_mock):
99102
# pytest imports xcengine.util long before we can patch __import__,
100103
# so we delete pystac from util's namespace (if present) instead.
101104
# This gives a NameError on access rather than a ModuleNotFoundError
@@ -108,6 +111,36 @@ def test_write_stac_no_pystac(tmp_path, dataset):
108111
# We want nothing to happen here, so no explicit assertions.
109112

110113

114+
def test_start_server_no_xcube(dataset):
115+
import io
116+
orig_import = __import__
117+
def import_mock(name, *args):
118+
if name == "xcube" or name.startswith("xcube."):
119+
raise ModuleNotFoundError(f"No module named {name}")
120+
return orig_import(name, *args)
121+
122+
with mock.patch("builtins.__import__", side_effect=import_mock):
123+
import xcengine.util
124+
util_vars = (
125+
k for k in xcengine.util.__dict__.keys()
126+
if k == "xcube" or k.startswith("xcube.")
127+
)
128+
for v in util_vars: del xcengine.util.__dict__[v]
129+
from xcengine.util import start_server
130+
logger = logging.getLogger("test-start-server-logger")
131+
logger.setLevel(logging.INFO)
132+
logger.addHandler(logging.StreamHandler(log_stream := io.StringIO()))
133+
start_server(
134+
{"ds1": dataset},
135+
{},
136+
argparse.Namespace(batch=False, from_saved=False),
137+
logger
138+
)
139+
logged = log_stream.getvalue()
140+
assert "Not starting" in logged
141+
assert "Starting server" not in logged
142+
143+
111144
@pytest.mark.parametrize("eoap_mode", [False, True])
112145
@pytest.mark.parametrize("ds2_format", [None, "zarr", "netcdf"])
113146
def test_save_datasets(tmp_path, dataset, eoap_mode, ds2_format):

xcengine/util.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# Copyright (c) 2024-2026 by Brockmann Consult GmbH
22
# Permissions are hereby granted under the terms of the MIT License:
33
# https://opensource.org/licenses/MIT.
4-
4+
import argparse
5+
import logging
56
from datetime import datetime
67
import json
78
import pathlib
@@ -128,11 +129,21 @@ def save_datasets(
128129
return saved_datasets
129130

130131

131-
def start_server(datasets, saved_datasets, args, logger):
132-
import xcube.util.plugin
133-
import xcube.webapi.viewer
134-
from xcube.server.server import Server
135-
from xcube.server.framework import get_framework_class
132+
def start_server(
133+
datasets: Mapping[str, xr.Dataset],
134+
saved_datasets: dict[str, pathlib.Path],
135+
args: argparse.Namespace,
136+
logger: logging.Logger
137+
):
138+
try:
139+
import xcube.util.plugin
140+
import xcube.webapi.viewer
141+
from xcube.server.server import Server
142+
from xcube.server.framework import get_framework_class
143+
except ImportError as e:
144+
logger.info(e.msg)
145+
logger.info("Not starting server, since xcube not available")
146+
return
136147

137148
xcube.util.plugin.init_plugins()
138149
server = Server(framework=get_framework_class("tornado")(), config={})

0 commit comments

Comments
 (0)