diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 86c6569..905eb4f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,34 +21,36 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip wheel - pip install -r dev-requirements.txt - pip install -e .[R,julia] + pip install -e .[dev,julia] - name: Setup Apptainer uses: eWaterCycle/setup-apptainer@v2 with: apptainer-version: 1.1.9 - name: Pull Docker image run: docker pull ewatercycle/walrus-grpc4bmi:v0.3.1 - - name: Cache Apptainer image - id: cache-apptainer-image - uses: actions/cache@v3 - with: - path: ~/.apptainer - key: apptainer-image - - name: Pull Apptainer image - if: steps.cache-apptainer-image.outputs.cache-hit != 'true' - run: apptainer pull docker://ewatercycle/walrus-grpc4bmi:v0.3.1 - uses: r-lib/actions/setup-r@v2 with: - install-r: false + install-r: true - name: Install R dependencies run: | Rscript -e "install.packages('remotes')" Rscript -e "install.packages('R6')" + - name: Install rpy2 (first requires R to be available). + run: | + pip install -e .[R] - name: Install Julia uses: julia-actions/setup-julia@v1 with: version: '^1.9' + - name: Cache Apptainer image + id: cache-apptainer-image + uses: actions/cache@v3 + with: + path: ~/.apptainer + key: apptainer-image + - name: Pull Apptainer image + if: steps.cache-apptainer-image.outputs.cache-hit != 'true' + run: apptainer pull docker://ewatercycle/walrus-grpc4bmi:v0.3.1 - name: Test with pytest run: | pytest -vv --cov=grpc4bmi --cov-report xml diff --git a/README.md b/README.md index 5921afa..7b62bd7 100644 --- a/README.md +++ b/README.md @@ -180,7 +180,7 @@ python3 -m venv .venv . venv/bin/activate # Make sure latest pip and wheel are install pip install -U pip wheel -pip install -r dev-requirements.txt +pip install -e .[dev] # For R integration also install the R extras with pip install -e .[R] # For building docs (cd docs && make html) also install the docs extras with diff --git a/dev-requirements.txt b/dev-requirements.txt deleted file mode 100644 index f06d76f..0000000 --- a/dev-requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ --e .[dev] -# Dependencies which are URLs can not be part -# of pyproject.toml:project.optional-dependencies:dev -# so they are listed here -bmi-heat@https://github.com/csdms/bmi-example-python/archive/refs/heads/master.zip diff --git a/docs/conf.py b/docs/conf.py index 19358e3..4db4be1 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -33,7 +33,7 @@ extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.napoleon', 'sphinx.ext.intersphinx', 'sphinx.ext.autosectionlabel', - 'sphinxarg.ext', 'sphinxcontrib.apidoc', + 'sphinxarg.ext', 'sphinx.ext.apidoc', 'sphinx_copybutton', 'sphinxcontrib.jquery', ] @@ -175,7 +175,7 @@ ] intersphinx_mapping = { - 'https://docs.python.org/': None, + 'python': ('https://docs.python.org/', None), 'numpy': ('http://docs.scipy.org/doc/numpy', None), "bmipy": ("https://bmi.readthedocs.io/en/latest/", None), } diff --git a/pyproject.toml b/pyproject.toml index 2b36fa1..501f08c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,6 +48,7 @@ dev = [ "nbconvert", "ipykernel", "nbformat", + "bmi-heat@git+https://github.com/csdms/bmi-example-python", ] docs = [ "sphinx", diff --git a/test/test_apptainer.py b/test/test_apptainer.py index 3a144b8..0a00976 100644 --- a/test/test_apptainer.py +++ b/test/test_apptainer.py @@ -29,7 +29,7 @@ def test_too_old(self, test_input: str, error_class: Type[ApptainerVersionExcept with pytest.raises(error_class, match=expected): check_apptainer_version_string(test_input) -IMAGE_NAME = "docker://ewatercycle/walrus-grpc4bmi:v0.2.0" +IMAGE_NAME = "docker://ewatercycle/walrus-grpc4bmi:v0.3.1" @pytest.fixture def walrus_model(tmp_path, walrus_input): diff --git a/test/test_client.py b/test/test_client.py index 9017f2a..b7ff5dd 100644 --- a/test/test_client.py +++ b/test/test_client.py @@ -110,7 +110,10 @@ def test_initialize_with_nonstring(): assert client is not None with pytest.raises(TypeError, match='bad argument type for built-in operation'): client.initialize(42) - client.finalize() + try: # Can't finalize model which is not initialized. + client.finalize() + except MyRpcError as err: + assert "has no attribute '_model'" in str(err) del client @@ -132,7 +135,7 @@ def test_update_until(): def test_get_time_unit(): - client, local = make_bmi_classes() + client, local = make_bmi_classes(True) assert client.get_time_units() == local.get_time_units() client.finalize() del client @@ -819,18 +822,18 @@ class TestCreateGrpcChannel: def test_defaults(self): with BmiClient.create_grpc_channel() as channel: target = channel._channel.target() - assert target == b'localhost:50051' + assert target == b'dns:///localhost:50051' def test_custom(self): with BmiClient.create_grpc_channel(51234, 'somehost') as channel: target = channel._channel.target() - assert target == b'somehost:51234' + assert target == b'dns:///somehost:51234' def test_same_port_twice(self): port = 51235 with BmiClient.create_grpc_channel(port) as channel1, BmiClient.create_grpc_channel(port) as channel2: - assert channel1._channel.target() == b'localhost:51235' - assert channel2._channel.target() == b'localhost:51235' + assert channel1._channel.target() == b'dns:///localhost:51235' + assert channel2._channel.target() == b'dns:///localhost:51235' class TestModelWithItemSizeZeroAndVarTypeFloat32: name = 'plate_surface__temperature' diff --git a/test/test_julia.py b/test/test_julia.py index 17eef7c..f413ae8 100644 --- a/test/test_julia.py +++ b/test/test_julia.py @@ -55,7 +55,7 @@ def model(self, cfg_file): ("get_input_var_names", tuple(), ["plate_surface__temperature"]), ("get_output_var_names", tuple(), ["plate_surface__temperature"]), ("get_start_time", tuple(), 0.0), - ("get_end_time", tuple(), np.Inf), + ("get_end_time", tuple(), np.inf), ("get_time_step", tuple(), 0.25), ("get_time_units", tuple(), "s"), ("get_var_type", ["plate_surface__temperature"], "float64"), diff --git a/test/test_legacy_server.py b/test/test_legacy_server.py index 2ba1dbf..5f36baf 100644 --- a/test/test_legacy_server.py +++ b/test/test_legacy_server.py @@ -86,7 +86,7 @@ def test_update(): def test_get_time_unit(): - server, local = make_bmi_classes() + server, local = make_bmi_classes(True) assert server.getTimeUnits(None, None).units == make_string(local.get_time_units()) server.finalize(None, None) del server diff --git a/test/test_memoized.py b/test/test_memoized.py index c0c831f..9404513 100644 --- a/test/test_memoized.py +++ b/test/test_memoized.py @@ -83,9 +83,11 @@ def test_nonmemoized_methods(mut_name, mut_args): mot = getattr(client, mut_name) mot(*mut_args) - mot(*mut_args) - - assert mock_method.call_count == 2 + if mut_name != "finalize": + mot(*mut_args) + assert mock_method.call_count == 2 + else: + assert mock_method.call_count == 1 def test_initialize_clears_cache(): diff --git a/test/test_optionaldest.py b/test/test_optionaldest.py index 268a2e6..33d30e5 100644 --- a/test/test_optionaldest.py +++ b/test/test_optionaldest.py @@ -50,7 +50,7 @@ def test_methods_with_optional_dest(orig_model, method_name, method_args, expect [ (BmiHeat(), 'update', tuple()), (BmiHeat(), 'update_until', [2]), - (BmiHeat(), 'finalize', tuple()), + # (BmiHeat(), 'finalize', tuple()), # Can't test finalize: double finalize not allowed. (BmiHeat(), 'get_current_time', tuple()), (BmiHeat(), 'get_component_name', tuple()), (BmiHeat(), 'get_input_item_count', tuple()), diff --git a/test/test_server.py b/test/test_server.py index c187969..e99bf6c 100644 --- a/test/test_server.py +++ b/test/test_server.py @@ -111,7 +111,7 @@ def test_update(): def test_get_time_unit(): - server, local = make_bmi_classes() + server, local = make_bmi_classes(True) assert server.getTimeUnits(None, None).units == make_string(local.get_time_units()) server.finalize(None, None) del server diff --git a/test/test_subproc.py b/test/test_subproc.py index e57b6a2..77b50f4 100644 --- a/test/test_subproc.py +++ b/test/test_subproc.py @@ -65,7 +65,7 @@ def test_update(): def test_get_time_unit(): - client, local = make_bmi_classes() + client, local = make_bmi_classes(True) assert client.get_time_units() == local.get_time_units() client.finalize() del client