diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 80ba2e99..1f2527ba 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -15,7 +15,8 @@ jobs:
- name: Install dependencies
run: |
- sudo apt-get install -y build-essential cmake gfortran libopenmpi-dev pkg-config wget
+ sudo apt-get update
+ sudo apt-get install -y build-essential cmake gfortran libopenmpi-dev pkg-config wget valgrind
sudo apt-get install -y libssl-dev zlib1g-dev
pip install ymmsl==0.10.1
diff --git a/.github/workflows/ci_python3.5.1.yaml b/.github/workflows/ci_python3.5.1.yaml
index 57799ba5..414110fb 100644
--- a/.github/workflows/ci_python3.5.1.yaml
+++ b/.github/workflows/ci_python3.5.1.yaml
@@ -15,5 +15,5 @@ jobs:
path: ${{ github.workspace }}/.eggs
key: python-compatibility-3.5.1-eggs
- - name: Run Python tests on 3.5.1 latest
- run: docker run -v "${GITHUB_WORKSPACE}:/home/muscle3" python:3.5.1 /bin/bash -c 'cd /home/muscle3 && pip install -U pip setuptools wheel ymmsl==0.10.1 && make test_python_only'
+ - name: Run Python tests on 3.5.1
+ run: docker run -v "${GITHUB_WORKSPACE}:/home/muscle3" python:3.5.1 /bin/bash -c 'cd /home/muscle3 && pip install -U pip setuptools wheel "numpy<1.19" ymmsl==0.10.1 && make test_python_only'
diff --git a/.github/workflows/ci_python3.5.yaml b/.github/workflows/ci_python3.5.yaml
index bb4232eb..3d79cf5f 100644
--- a/.github/workflows/ci_python3.5.yaml
+++ b/.github/workflows/ci_python3.5.yaml
@@ -16,4 +16,4 @@ jobs:
key: python-compatibility-3.5-eggs
- name: Run Python tests on 3.5 latest
- run: docker run -v "${GITHUB_WORKSPACE}:/home/muscle3" python:3.5 /bin/bash -c 'cd /home/muscle3 && pip install ymmsl==0.10.1 && make test_python_only'
+ run: docker run -v "${GITHUB_WORKSPACE}:/home/muscle3" python:3.5 /bin/bash -c 'cd /home/muscle3 && pip install numpy ymmsl==0.10.1 && make test_python_only'
diff --git a/.github/workflows/ci_ubuntu16.04.yaml b/.github/workflows/ci_ubuntu16.04.yaml
index 1b29991f..7d783789 100644
--- a/.github/workflows/ci_ubuntu16.04.yaml
+++ b/.github/workflows/ci_ubuntu16.04.yaml
@@ -4,6 +4,9 @@ name: native_compatibility_ubuntu16.04
on:
schedule:
- cron: '0 1 * * 0'
+ push:
+ branches:
+ - 'release-*'
jobs:
build:
runs-on: ubuntu-latest
@@ -12,4 +15,4 @@ jobs:
- uses: actions/checkout@v2
- name: Run tests on Ubuntu 16.04
- run: docker run -v "${GITHUB_WORKSPACE}:/home/muscle3" --env LC_ALL=C.UTF-8 --env LANG=C.UTF-8 --env DEBIAN_FRONTEND=noninteractive ubuntu:16.04 /bin/bash -c 'apt-get update && apt-get -y dist-upgrade && apt-get -y install build-essential cmake gfortran libopenmpi-dev pkg-config python3 python3-pip python3-venv curl && apt-get -y remove libssl-dev zlib1g-dev && pip3 install -U pip setuptools wheel && cd /home/muscle3 && pip3 install ymmsl==0.10.1 && make test_examples'
+ run: docker run -v "${GITHUB_WORKSPACE}:/home/muscle3" --env LC_ALL=C.UTF-8 --env LANG=C.UTF-8 --env DEBIAN_FRONTEND=noninteractive ubuntu:16.04 /bin/bash -c 'apt-get update && apt-get -y dist-upgrade && apt-get -y install build-essential cmake gfortran valgrind libopenmpi-dev pkg-config python3 python3-pip python3-venv curl && apt-get -y remove libssl-dev zlib1g-dev && pip3 install -U pip setuptools wheel && cd /home/muscle3 && pip3 install ymmsl==0.10.1 && make test_examples'
diff --git a/.github/workflows/ci_ubuntu18.04.yaml b/.github/workflows/ci_ubuntu18.04.yaml
index 86c79e8c..3d9b313f 100644
--- a/.github/workflows/ci_ubuntu18.04.yaml
+++ b/.github/workflows/ci_ubuntu18.04.yaml
@@ -4,6 +4,9 @@ name: native_compatibility_ubuntu18.04
on:
schedule:
- cron: '0 2 * * 0'
+ push:
+ branches:
+ - 'release-*'
jobs:
build:
runs-on: ubuntu-latest
@@ -12,4 +15,4 @@ jobs:
- uses: actions/checkout@v2
- name: Run tests on Ubuntu 18.04
- run: docker run -v "${GITHUB_WORKSPACE}:/home/muscle3" --env LC_ALL=C.UTF-8 --env LANG=C.UTF-8 --env DEBIAN_FRONTEND=noninteractive ubuntu:18.04 /bin/bash -c 'apt-get update && apt-get -y dist-upgrade && apt-get -y install build-essential cmake gfortran libopenmpi-dev pkg-config python3 python3-pip python3-venv curl && apt-get -y remove libssl-dev zlib1g-dev && pip3 install -U pip setuptools wheel && cd /home/muscle3 && pip3 install ymmsl==0.10.1 && make test_examples'
+ run: docker run -v "${GITHUB_WORKSPACE}:/home/muscle3" --env LC_ALL=C.UTF-8 --env LANG=C.UTF-8 --env DEBIAN_FRONTEND=noninteractive ubuntu:18.04 /bin/bash -c 'apt-get update && apt-get -y dist-upgrade && apt-get -y install build-essential cmake gfortran valgrind libopenmpi-dev pkg-config python3 python3-pip python3-venv curl && apt-get -y remove libssl-dev zlib1g-dev && pip3 install -U pip setuptools wheel && cd /home/muscle3 && pip3 install ymmsl==0.10.1 && make test_examples'
diff --git a/.github/workflows/ci_ubuntu19.10.yaml b/.github/workflows/ci_ubuntu19.10.yaml
index 6f220106..560d5284 100644
--- a/.github/workflows/ci_ubuntu19.10.yaml
+++ b/.github/workflows/ci_ubuntu19.10.yaml
@@ -4,6 +4,9 @@ name: native_compatibility_ubuntu19.10
on:
schedule:
- cron: '0 3 * * 0'
+ push:
+ branches:
+ - 'release-*'
jobs:
build:
runs-on: ubuntu-latest
@@ -12,4 +15,4 @@ jobs:
- uses: actions/checkout@v2
- name: Run tests on Ubuntu 19.10
- run: docker run -v "${GITHUB_WORKSPACE}:/home/muscle3" --env LC_ALL=C.UTF-8 --env LANG=C.UTF-8 --env DEBIAN_FRONTEND=noninteractive ubuntu:19.10 /bin/bash -c 'apt-get update && apt-get -y dist-upgrade && apt-get -y install build-essential cmake gfortran libopenmpi-dev pkg-config python3 python3-pip python3-venv curl && apt-get -y remove libssl-dev zlib1g-dev && pip3 install -U pip setuptools wheel && cd /home/muscle3 && pip3 install ymmsl==0.10.1 && make test_examples'
+ run: docker run -v "${GITHUB_WORKSPACE}:/home/muscle3" --env LC_ALL=C.UTF-8 --env LANG=C.UTF-8 --env DEBIAN_FRONTEND=noninteractive ubuntu:19.10 /bin/bash -c 'apt-get update && apt-get -y dist-upgrade && apt-get -y install build-essential cmake gfortran valgrind libopenmpi-dev pkg-config python3 python3-pip python3-venv curl && apt-get -y remove libssl-dev zlib1g-dev && pip3 install -U pip setuptools wheel && cd /home/muscle3 && pip3 install ymmsl==0.10.1 && make test_examples'
diff --git a/.github/workflows/ci_ubuntu20.04.yaml b/.github/workflows/ci_ubuntu20.04.yaml
index c46af0f9..ea711557 100644
--- a/.github/workflows/ci_ubuntu20.04.yaml
+++ b/.github/workflows/ci_ubuntu20.04.yaml
@@ -4,6 +4,9 @@ name: native_compatibility_ubuntu20.04
on:
schedule:
- cron: '0 4 * * 0'
+ push:
+ branches:
+ - 'release-*'
jobs:
build:
runs-on: ubuntu-latest
@@ -12,4 +15,4 @@ jobs:
- uses: actions/checkout@v2
- name: Run tests on Ubuntu 20.04
- run: docker run -v "${GITHUB_WORKSPACE}:/home/muscle3" --env LC_ALL=C.UTF-8 --env LANG=C.UTF-8 --env DEBIAN_FRONTEND=noninteractive ubuntu:20.04 /bin/bash -c 'apt-get update && apt-get -y dist-upgrade && apt-get -y install build-essential cmake gfortran libopenmpi-dev pkg-config python3 python3-pip python3-venv curl && apt-get -y remove libssl-dev zlib1g-dev && pip3 install -U pip setuptools wheel && cd /home/muscle3 && pip3 install ymmsl==0.10.1 && make test_examples'
+ run: docker run -v "${GITHUB_WORKSPACE}:/home/muscle3" --env LC_ALL=C.UTF-8 --env LANG=C.UTF-8 --env DEBIAN_FRONTEND=noninteractive ubuntu:20.04 /bin/bash -c 'apt-get update && apt-get -y dist-upgrade && apt-get -y install build-essential cmake gfortran valgrind libopenmpi-dev pkg-config python3 python3-pip python3-venv curl && apt-get -y remove libssl-dev zlib1g-dev && pip3 install -U pip setuptools wheel && cd /home/muscle3 && pip3 install ymmsl==0.10.1 && make test_examples'
diff --git a/.github/workflows/ci_ubuntu20.10.yaml b/.github/workflows/ci_ubuntu20.10.yaml
new file mode 100644
index 00000000..285eb940
--- /dev/null
+++ b/.github/workflows/ci_ubuntu20.10.yaml
@@ -0,0 +1,18 @@
+# Run Continuous Integration for the latest Ubuntu release
+# This mainly checks for issues/regressions in the native build
+name: native_compatibility_ubuntu20.10
+on:
+ schedule:
+ - cron: '0 4 * * 0'
+ push:
+ branches:
+ - 'release-*'
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Run tests on Ubuntu 20.10
+ run: docker run -v "${GITHUB_WORKSPACE}:/home/muscle3" --env LC_ALL=C.UTF-8 --env LANG=C.UTF-8 --env DEBIAN_FRONTEND=noninteractive ubuntu:20.10 /bin/bash -c 'apt-get update && apt-get -y dist-upgrade && apt-get -y install build-essential cmake gfortran valgrind libopenmpi-dev pkg-config python3 python3-pip python3-venv curl && apt-get -y remove libssl-dev zlib1g-dev && pip3 install -U pip setuptools wheel && cd /home/muscle3 && pip3 install ymmsl==0.10.1 && make test_examples'
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 25dbf0d2..2994d239 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -5,6 +5,32 @@ Change Log
All notable changes to this project will be documented in this file.
This project adheres to `Semantic Versioning `_.
+0.3.2
+*****
+
+Improved
+--------
+
+* Accessing settings from C++ now more flexible
+* Python produces more detailed logs to aid in debugging
+* Improved pkg-config set-up
+* Improved build system output to help find problems
+* Documentation on logging in Python
+* Protobuf dependency build now more compatible
+
+Fixed
+-----
+
+* C++ list/dict building functions
+* C++ use-after-free when receiving grids
+
+Thanks
+------
+
+* Pavel for testing and reporting issues
+* Dongwei for testing and reporting issues
+
+
0.3.1
*****
diff --git a/Makefile b/Makefile
index dff04cad..575756fa 100644
--- a/Makefile
+++ b/Makefile
@@ -85,7 +85,7 @@ install: all
@echo " You can also use pkg-config. Add $(PREFIX)/lib/pkgconfig"
@echo '* to your PKG_CONFIG_PATH environment variable and use module *'
@echo '* names libmuscle, libmuscle_mpi, libmuscle_fortran or *'
- @echo '* libmuscle_mpi_fortran. *'
+ @echo '* libmuscle_mpi_fortran and ymmsl or ymmsl_fortran. *'
@echo '* *'
@echo '* If the directory you installed MUSCLE 3 in is not in your *'
@echo "* system's library search path, then you have to set *"
@@ -116,6 +116,7 @@ clean:
cd scripts && $(MAKE) clean
cd docs/source/examples && $(MAKE) clean
rm -rf ./build
+ rm -rf $(CURDIR)/libmuscle/build/test_install/*
.PHONY: distclean
distclean:
@@ -124,6 +125,7 @@ distclean:
cd scripts && $(MAKE) distclean
cd docs/source/examples && $(MAKE) clean
rm -rf ./build
+ rm -rf $(CURDIR)/libmuscle/build/test_install/*
.PHONY: fortran
fortran: cpp
diff --git a/README.rst b/README.rst
index 9ec89a33..d5adf666 100644
--- a/README.rst
+++ b/README.rst
@@ -1,4 +1,4 @@
-.. image:: https://github.com/multiscale/muscle3/raw/master/docs/source/muscle3_logo_readme.png
+.. image:: https://github.com/multiscale/muscle3/raw/develop/docs/source/muscle3_logo_readme.png
:alt: MUSCLE 3
.. image:: https://readthedocs.org/projects/muscle3/badge/?version=master
diff --git a/VERSION b/VERSION
index 9e11b32f..d15723fb 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.3.1
+0.3.2
diff --git a/docs/source/examples/cpp/build/Makefile b/docs/source/examples/cpp/build/Makefile
index da31e583..14e6a558 100644
--- a/docs/source/examples/cpp/build/Makefile
+++ b/docs/source/examples/cpp/build/Makefile
@@ -1,10 +1,12 @@
CXX ?= g++
-MPICXX := mpic++
-CXXFLAGS += -std=c++14 -g $(shell pkg-config --cflags libmuscle)
-MPI_CXXFLAGS := -std=c++14 -g $(shell pkg-config --cflags libmuscle_mpi)
+CXXFLAGS += -std=c++14 -g $(shell pkg-config --cflags libmuscle ymmsl)
+LDFLAGS += $(shell pkg-config --libs libmuscle ymmsl)
-MPI_LDFLAGS := $(LDFLAGS) $(shell pkg-config --libs libmuscle_mpi)
-LDFLAGS += $(shell pkg-config --libs libmuscle)
+ifdef MUSCLE_ENABLE_MPI
+ MPICXX := mpic++
+ MPI_CXXFLAGS := -std=c++14 -g $(shell pkg-config --cflags libmuscle_mpi ymmsl)
+ MPI_LDFLAGS := $(shell pkg-config --libs libmuscle_mpi ymmsl)
+endif
binaries := reaction diffusion mc_driver load_balancer
diff --git a/docs/source/examples/fortran/build/Makefile b/docs/source/examples/fortran/build/Makefile
index 049d7948..578672ee 100644
--- a/docs/source/examples/fortran/build/Makefile
+++ b/docs/source/examples/fortran/build/Makefile
@@ -1,9 +1,12 @@
FC ?= gfortran
-MPIFC ?= mpifort
-FFLAGS += -std=f2003 -g $(shell pkg-config --cflags libmuscle_fortran)
+FFLAGS += -std=f2003 -g $(shell pkg-config --cflags libmuscle_fortran ymmsl_fortran)
+LDFLAGS := $(shell pkg-config --libs libmuscle_fortran ymmsl_fortran)
-MPI_LDFLAGS := $(shell pkg-config --libs libmuscle_mpi_fortran)
-LDFLAGS := $(shell pkg-config --libs libmuscle_fortran)
+ifdef MUSCLE_ENABLE_MPI
+ MPIFC ?= mpifort
+ MPI_FFLAGS := -std=f2003 -g $(shell pkg-config --cflags libmuscle_mpi_fortran ymmsl_fortran)
+ MPI_LDFLAGS := $(shell pkg-config --libs libmuscle_mpi_fortran ymmsl_fortran)
+endif
binaries := reaction diffusion mc_driver load_balancer
@@ -26,5 +29,5 @@ clean:
LD_LIBRARY_PATH=$(MUSCLE3_HOME)/lib:$(LD_LIBRARY_PATH) $(FC) $(FFLAGS) -o $@ $^ $(LDFLAGS)
%_mpi: ../%_mpi.f03
- LD_LIBRARY_PATH=$(MUSCLE3_HOME)/lib:$(LD_LIBRARY_PATH) $(MPIFC) $(FFLAGS) -o $@ $^ $(MPI_LDFLAGS)
+ LD_LIBRARY_PATH=$(MUSCLE3_HOME)/lib:$(LD_LIBRARY_PATH) $(MPIFC) $(MPI_FFLAGS) -o $@ $^ $(MPI_LDFLAGS)
diff --git a/docs/source/fortran_api.rst b/docs/source/fortran_api.rst
index febc3bb1..345ac43f 100644
--- a/docs/source/fortran_api.rst
+++ b/docs/source/fortran_api.rst
@@ -2302,6 +2302,22 @@ YMMSL_Settings
:r is: ``.true.`` if the value is of type logical.
:rtype is: logical
+.. f:function:: YMMSL_Settings_is_a_int4(self, key, err_code, err_msg)
+
+ Return whether a value is of type ``YMMSL_int4``.
+
+ This returns ``.true.`` if the value is an integer and fits in an int4.
+
+ If the given key does not exist, then ``err_code`` will be set to
+ ``YMMSL_out_of_bounds`` and the result will be invalid.
+
+ :p YMMSL_Settings self: The Settings object to inspect.
+ :p character key: The name of the setting to check.
+ :p integer err_code: An error code output (optional).
+ :p character err_msg: An error message output (allocatable, optional).
+ :r is: ``.true.`` if the value is of type ``YMMSL_int4``.
+ :rtype is: logical
+
.. f:function:: YMMSL_Settings_is_a_int8(self, key, err_code, err_msg)
Return whether a value is of type ``YMMSL_int8``.
@@ -2320,6 +2336,9 @@ YMMSL_Settings
Return whether a value is of type ``YMMSL_real8``.
+ This will also return ``.true.`` if the value is an integer, even if
+ converting it would lose precision.
+
If the given key does not exist, then ``err_code`` will be set to
``YMMSL_out_of_bounds`` and the result will be invalid.
@@ -2365,9 +2384,10 @@ YMMSL_Settings
If no setting with the given key exists, one is added, if one does,
it is overwritten.
- ``value`` may be a character (string), a logical, an 8-byte integer (e.g.
- ``YMMSL_int8``), an 8-byte real number (``YMMSL_real8``), or a one- or
- two-dimensional arrays of 8-byte real numbers.
+ ``value`` may be a character (string), a logical, a 4-byte integer (e.g.
+ ``YMMSL_int4``), an 8-byte integer (e.g. ``YMMSL_int8``), an 8-byte real
+ number (``YMMSL_real8``), or a one- or two-dimensional arrays of 8-byte real
+ numbers.
:p YMMSL_Settings self: The Settings object to modify.
:p character key: The name of the setting.
@@ -2401,6 +2421,20 @@ YMMSL_Settings
:r value: The value at the given index
:rtype value: logical
+.. f:function:: YMMSL_Settings_get_as_int4(self, key, err_code, err_msg)
+
+ Return the value of an integer-typed setting.
+
+ If this setting is not currently set to a integer-typed value, or the
+ value is out of range for an int4, then ``err_code`` will be set to
+ ``YMMSL_bad_cast`` and the result will be invalid.
+
+ :p character key: The name of the setting to get.
+ :p integer err_code: An error code output (optional).
+ :p character err_msg: An error message output (allocatable, optional).
+ :r value: The value at the given index (YMMSL_int4)
+ :rtype value: integer
+
.. f:function:: YMMSL_Settings_get_as_int8(self, key, err_code, err_msg)
Return the value of an integer-typed setting.
@@ -2419,7 +2453,10 @@ YMMSL_Settings
Return the value of a real-typed setting.
- If this setting is not currently set to a real-typed value,
+ This will also work if the setting is integer-typed in which case it
+ will be converted, with possible loss of precision.
+
+ If this setting is not currently set to a real- or integer-typed value,
then ``err_code`` will be set to ``YMMSL_bad_cast`` and the result
will be invalid.
diff --git a/docs/source/installing.rst.in b/docs/source/installing.rst.in
index e2173f25..d57974c1 100644
--- a/docs/source/installing.rst.in
+++ b/docs/source/installing.rst.in
@@ -305,7 +305,7 @@ libraries in case you need them. If you link statically, then you must add the
MUSCLE 3 also supports ``pkg-config``. To use ``pkg-config``, add
``/lib/pkgconfig`` to your ``PKG_CONFIG_PATH`` and use the module names
-``libmuscle`` or ``libmuscle_mpi``.
+``ymmsl`` and either ``libmuscle`` or ``libmuscle_mpi``.
There's one more thing: the directory that you've installed MUSCLE into is
probably not in your system's library search path, and as a result the dynamic
@@ -397,7 +397,7 @@ the libmuscle library instead:
MUSCLE 3 also supports ``pkg-config``. To use ``pkg-config``, add
``/lib/pkgconfig`` to your ``PKG_CONFIG_PATH`` and use the module names
-``libmuscle_fortran`` or ``libmuscle_mpi_fortran``.
+``ymmsl_fortran`` and either ``libmuscle_fortran`` or ``libmuscle_mpi_fortran``.
There's one more thing: the directory that you've installed MUSCLE into is
probably not in your system's library search path, and as a result the dynamic
diff --git a/docs/source/releasing.rst b/docs/source/releasing.rst
index eada37b8..f4fbd66c 100644
--- a/docs/source/releasing.rst
+++ b/docs/source/releasing.rst
@@ -55,7 +55,7 @@ shows up:
.. code-block:: bash
- python setup.py build_sphinx
+ make docs
It may give some warnings about missing references, that's a known issue and
normally harmless. Next, point your web browser to
@@ -67,8 +67,8 @@ Run tests
---------
Before we make a commit, the tests should be run, and this is a good idea anyway
-if we're making a release. So run ``python setup.py test`` and check that
-everything is in order.
+if we're making a release. So run ``make test`` and check that everything is in
+order.
Commit the version update
-------------------------
@@ -136,8 +136,13 @@ can start using it. To build, use:
.. code-block:: bash
+ rm -r ./build
python3 setup.py sdist bdist_wheel
+Note that we remove ``./build``, which is the build directory setuptools uses,
+to ensure that we're doing a clean build, I've seen some weird mixes of versions
+on occasion so it's better to be safe than sorry.
+
We can then check to see if everything is okay using
.. code-block:: bash
@@ -150,6 +155,13 @@ and if all seems well, we can upload to PyPI:
twine upload dist/muscle3-x.y.z*
+Announce release
+----------------
+
+Announce the release in the usual places, so that people know it exists. There
+should be a short release message listing new features and fixed bugs, and don't
+forget to thank everyone who contributed!
+
Merge the release branch back into develop
------------------------------------------
diff --git a/docs/source/tutorial.rst b/docs/source/tutorial.rst
index 67b71c0a..681189de 100644
--- a/docs/source/tutorial.rst
+++ b/docs/source/tutorial.rst
@@ -544,3 +544,47 @@ usual Python way in your models, and MUSCLE 3 will automatically take care of
writing them to the log file. Any messages at level ``WARNING`` or higher will
be sent to the manager log as well. This helps give an overview of what went
wrong in a single place in case of errors.
+
+Note that by default, Python (and MUSCLE 3) only logs messages at level
+``WARNING`` or higher. So if you add a statement like
+
+.. code-block:: python
+
+ logging.info('Some useful information')
+
+then you'll find that it will not show up in either of the log files, because
+``INFO`` is a lower level than ``WARNING``. To get more or less local log output
+(e.g. in ``muscle3.macro.log``), you can use one of these commands:
+
+.. code-block:: python
+
+ # least output
+ logging.getLogger().setLevel(logging.CRITICAL)
+ logging.getLogger().setLevel(logging.ERROR)
+ logging.getLogger().setLevel(logging.WARNING)
+ logging.getLogger().setLevel(logging.INFO)
+ logging.getLogger().setLevel(logging.DEBUG)
+ # most output
+
+The minimum log level for sending a message to the central log file
+(``muscle_manager.log``) is set by the ``muscle_remote_log_level`` setting. For
+example, if you change the example to read
+
+.. code-block:: python
+
+ settings = Settings(OrderedDict([
+ ('muscle_remote_log_level', 'DEBUG'),
+ ('micro.t_max', 2.469136e-6),
+ ('micro.dt', 2.469136e-8),
+ ('macro.t_max', 1.234568e-4),
+ ('macro.dt', 2.469136e-6),
+ ('x_max', 1.01),
+ ('dx', 0.01),
+ ('k', -4.05e4), # reaction parameter
+ ('d', 4.05e-2) # diffusion parameter
+ ]))
+
+then all log messages from all submodels will be sent to the manager log. This
+does slow down the simulation if you have many log statements, so it's good to
+use this to debug and to learn, but do increase the level again for production
+runs.
diff --git a/integration_test/conftest.py b/integration_test/conftest.py
index 46bac069..a64b0717 100644
--- a/integration_test/conftest.py
+++ b/integration_test/conftest.py
@@ -8,7 +8,7 @@
import yatiml
import ymmsl
-import integration_test.include_libmuscle
+import integration_test.include_libmuscle # noqa: F401
from libmuscle.manager.instance_registry import InstanceRegistry
from libmuscle.manager.logger import Logger
diff --git a/integration_test/test_all.py b/integration_test/test_all.py
index 780c0b32..f314396a 100644
--- a/integration_test/test_all.py
+++ b/integration_test/test_all.py
@@ -1,11 +1,8 @@
from collections import OrderedDict
-import sys
-from typing import List
import numpy as np
-import pytest
from ymmsl import (ComputeElement, Conduit, Configuration, Model, Operator,
- Reference, Settings)
+ Settings)
from libmuscle import Grid, Instance, Message
from libmuscle.runner import run_simulation
diff --git a/integration_test/test_cpp_mmp_client.py b/integration_test/test_cpp_mmp_client.py
index 29b31b1f..1c51de0a 100644
--- a/integration_test/test_cpp_mmp_client.py
+++ b/integration_test/test_cpp_mmp_client.py
@@ -5,13 +5,11 @@
import ymmsl
from ymmsl import Port, Reference
-from libmuscle.logging import LogLevel, LogMessage, Timestamp
from libmuscle.manager.instance_registry import InstanceRegistry
from libmuscle.manager.logger import Logger
from libmuscle.manager.mmp_server import MMPServer
from libmuscle.manager.manager import elements_for_model
from libmuscle.manager.topology_store import TopologyStore
-from libmuscle.mmp_client import MMPClient
from libmuscle.operator import Operator
from .conftest import skip_if_python_only
@@ -85,7 +83,7 @@ def mock_remove(name: Reference):
assert result.returncode == 0
# check submit_log_message
- assert caplog.records[0].name == 'test_logging'
+ assert caplog.records[0].name == 'instances.test_logging'
assert caplog.records[0].time_stamp == '1970-01-01T00:00:02Z'
assert caplog.records[0].levelname == 'CRITICAL'
assert caplog.records[0].message == 'Integration testing'
diff --git a/integration_test/test_cpp_tcp_client.py b/integration_test/test_cpp_tcp_client.py
index 23c61f19..273b7f63 100644
--- a/integration_test/test_cpp_tcp_client.py
+++ b/integration_test/test_cpp_tcp_client.py
@@ -3,11 +3,8 @@
import subprocess
from unittest.mock import MagicMock
-import msgpack
-
from libmuscle.mcp.tcp_server import TcpServer
from libmuscle.mcp.message import Message
-from libmuscle.post_office import PostOffice
from ymmsl import Reference, Settings
diff --git a/integration_test/test_cpp_tcp_server.py b/integration_test/test_cpp_tcp_server.py
index cd1a4e2f..d4a87f3a 100644
--- a/integration_test/test_cpp_tcp_server.py
+++ b/integration_test/test_cpp_tcp_server.py
@@ -1,8 +1,5 @@
from pathlib import Path
import subprocess
-from unittest.mock import MagicMock
-
-import msgpack
from libmuscle.mcp.tcp_client import TcpClient
from libmuscle.mcp.message import Message
diff --git a/integration_test/test_duplication_mapper.py b/integration_test/test_duplication_mapper.py
index dba5ffdf..36dbf3ba 100644
--- a/integration_test/test_duplication_mapper.py
+++ b/integration_test/test_duplication_mapper.py
@@ -1,8 +1,5 @@
-from typing import List
-
-import pytest
-from ymmsl import (ComputeElement, Conduit, Configuration, Operator, Reference,
- Model, Settings)
+from ymmsl import (ComputeElement, Conduit, Configuration, Operator, Model,
+ Settings)
from libmuscle import Instance, Message
from libmuscle.runner import run_simulation
diff --git a/integration_test/test_logging.py b/integration_test/test_logging.py
index 4b4a3fc0..1c92a694 100644
--- a/integration_test/test_logging.py
+++ b/integration_test/test_logging.py
@@ -9,7 +9,6 @@
from libmuscle.manager.manager import elements_for_model
from libmuscle.manager.topology_store import TopologyStore
from libmuscle.mmp_client import MMPClient
-from libmuscle.operator import Operator
def do_logging_test(caplog):
@@ -50,14 +49,14 @@ def do_logging_test(caplog):
message = LogMessage(
instance_id='test_logging',
timestamp=Timestamp(2.0),
- level=LogLevel.CRITICAL,
+ level=LogLevel.DEBUG,
text='Integration testing')
# log and check
client.submit_log_message(message)
- assert caplog.records[0].name == 'test_logging'
+ assert caplog.records[0].name == 'instances.test_logging'
assert caplog.records[0].time_stamp == '1970-01-01T00:00:02Z'
- assert caplog.records[0].levelname == 'CRITICAL'
+ assert caplog.records[0].levelname == 'DEBUG'
assert caplog.records[0].message == 'Integration testing'
server.stop()
diff --git a/integration_test/test_parameter_overlays.py b/integration_test/test_parameter_overlays.py
index f0d9ef17..a4211cef 100644
--- a/integration_test/test_parameter_overlays.py
+++ b/integration_test/test_parameter_overlays.py
@@ -1,8 +1,7 @@
from collections import OrderedDict
-import pytest
from ymmsl import (ComputeElement, Conduit, Configuration, Model, Operator,
- Reference, Settings)
+ Settings)
from libmuscle import Instance, Message
from libmuscle.runner import run_simulation
diff --git a/libmuscle/cpp/build/check_tools.make b/libmuscle/cpp/build/check_tools.make
index 892f4dde..14e12471 100644
--- a/libmuscle/cpp/build/check_tools.make
+++ b/libmuscle/cpp/build/check_tools.make
@@ -1,6 +1,17 @@
# Make module that verifies that we have all needed tools
$(info )
+# Output some information about the environment
+$(info Environment information:)
+
+$(info Variables:)
+$(info $(.VARIABLES))
+$(info )
+$(info Make invocation: $(MAKE))
+$(info Make command goals: $(MAKECMDGOALS))
+$(info Make flags: $(MAKEFLAGS))
+$(info )
+
# Check Python version
$(info Looking for Python...)
_python_version := $(shell python3 --version || echo NOTFOUND)
@@ -84,6 +95,26 @@ else
$(info - Will extract archives using $(TAR).)
endif
+# Check for valgrind (for testing for memory leaks)
+$(info )
+$(info Looking for valgrind...)
+tool_var := VALGRIND
+include $(TOOLDIR)/check_override.make
+
+tool_command := valgrind
+include $(TOOLDIR)/detect_tool.make
+
+ifeq ($(VALGRIND), valgrind)
+ export VALGRIND := valgrind --leak-check=full --error-exitcode=1
+endif
+
+ifndef VALGRIND
+ $(warning - Could not find valgrind, so tests will run without it.)
+ $(warning - To fix this, install valgrind and if necessary set VALGRIND to point to it.)
+else
+ $(info - Will check for leaks using $(VALGRIND).)
+endif
+
# Check number of cores
ifndef NCORES
NCORES := $(shell nproc 2>/dev/null || echo 2)
diff --git a/libmuscle/cpp/build/libmuscle/Makefile b/libmuscle/cpp/build/libmuscle/Makefile
index c947552a..06c77679 100644
--- a/libmuscle/cpp/build/libmuscle/Makefile
+++ b/libmuscle/cpp/build/libmuscle/Makefile
@@ -42,7 +42,8 @@ header_root := $(CURDIR)/../../src
CXXFLAGS += -I$(header_root)
public_headers := libmuscle/data.hpp libmuscle/data.tpp libmuscle/instance.hpp
-public_headers += libmuscle/libmuscle.hpp libmuscle/message.hpp
+public_headers += libmuscle/libmuscle.hpp libmuscle/mcp/data_pack.hpp
+public_headers += libmuscle/mcp/data_pack.tpp libmuscle/message.hpp
public_headers += libmuscle/ports_description.hpp libmuscle/util.hpp libmuscle/util.tpp
installed_headers := $(public_headers:%=$(PREFIX)/include/%)
@@ -209,9 +210,10 @@ libmuscle.pc:
@echo 'Description: Library for MUSCLE 3' >>$@
@echo 'URL: https://muscle3.readthedocs.io' >>$@
@echo 'Version: $(muscle_version)' >>$@
+ @echo 'Requires: ymmsl = $(muscle_version)' >>$@
@echo 'Requires.private: grpc++ >= 1.24.3, protobuf >= 3.10.0, msgpack >= 3.1.0' >>$@
@echo 'Cflags: -I$${includedir}' >>$@
- @echo 'Libs: -L$${libdir} -lymmsl -lmuscle' >>$@
+ @echo 'Libs: -L$${libdir} -lmuscle' >>$@
libmuscle_mpi.pc:
@echo 'prefix=$(PREFIX)' >$@
@@ -223,7 +225,8 @@ libmuscle_mpi.pc:
@echo 'Description: Library for MUSCLE 3' >>$@
@echo 'URL: https://muscle3.readthedocs.io' >>$@
@echo 'Version: $(muscle_version)' >>$@
+ @echo 'Requires: ymmsl = $(muscle_version)' >>$@
@echo 'Requires.private: grpc++ >= 1.24.3, protobuf >= 3.10.0, msgpack >= 3.1.0' >>$@
@echo 'Cflags: -I$${includedir} -DMUSCLE_ENABLE_MPI' >>$@
- @echo 'Libs: -L$${libdir} -lymmsl -lmuscle_mpi' >>$@
+ @echo 'Libs: -L$${libdir} -lmuscle_mpi' >>$@
diff --git a/libmuscle/cpp/build/libmuscle/libmuscle.version b/libmuscle/cpp/build/libmuscle/libmuscle.version
index fef68798..96854ff1 100644
--- a/libmuscle/cpp/build/libmuscle/libmuscle.version
+++ b/libmuscle/cpp/build/libmuscle/libmuscle.version
@@ -120,7 +120,9 @@
"libmuscle::impl::Data::byte_array(char const*, unsigned int)";
"libmuscle::impl::Data::byte_array(unsigned int)";
"libmuscle::impl::Data::dict()";
+ "libmuscle::impl::Data::init_dict_(unsigned int)";
"libmuscle::impl::Data::list()";
+ "libmuscle::impl::Data::init_list_(unsigned int)";
"libmuscle::impl::Data::nils(unsigned long)";
"libmuscle::impl::Data::operator=(libmuscle::impl::Data const&)";
"libmuscle::impl::Data::operator[](unsigned long)";
diff --git a/libmuscle/cpp/build/libmuscle/libmuscle.version.in b/libmuscle/cpp/build/libmuscle/libmuscle.version.in
index 5163da10..3b463354 100644
--- a/libmuscle/cpp/build/libmuscle/libmuscle.version.in
+++ b/libmuscle/cpp/build/libmuscle/libmuscle.version.in
@@ -120,7 +120,9 @@
"libmuscle::impl::Data::byte_array(char const*, unsigned int)";
"libmuscle::impl::Data::byte_array(unsigned int)";
"libmuscle::impl::Data::dict()";
+ "libmuscle::impl::Data::init_dict_(unsigned int)";
"libmuscle::impl::Data::list()";
+ "libmuscle::impl::Data::init_list_(unsigned int)";
"libmuscle::impl::Data::nils(unsigned long)";
"libmuscle::impl::Data::operator=(libmuscle::impl::Data const&)";
"libmuscle::impl::Data::operator[](unsigned long)";
diff --git a/libmuscle/cpp/build/libmuscle/libmuscle_mpi.version b/libmuscle/cpp/build/libmuscle/libmuscle_mpi.version
index fa6c204a..395cb218 100644
--- a/libmuscle/cpp/build/libmuscle/libmuscle_mpi.version
+++ b/libmuscle/cpp/build/libmuscle/libmuscle_mpi.version
@@ -120,7 +120,9 @@
"libmuscle::impl::Data::byte_array(char const*, unsigned int)";
"libmuscle::impl::Data::byte_array(unsigned int)";
"libmuscle::impl::Data::dict()";
+ "libmuscle::impl::Data::init_dict_(unsigned int)";
"libmuscle::impl::Data::list()";
+ "libmuscle::impl::Data::init_list_(unsigned int)";
"libmuscle::impl::Data::nils(unsigned long)";
"libmuscle::impl::Data::operator=(libmuscle::impl::Data const&)";
"libmuscle::impl::Data::operator[](unsigned long)";
diff --git a/libmuscle/cpp/build/libmuscle/tests/Makefile b/libmuscle/cpp/build/libmuscle/tests/Makefile
index 7d6a322f..e285659a 100644
--- a/libmuscle/cpp/build/libmuscle/tests/Makefile
+++ b/libmuscle/cpp/build/libmuscle/tests/Makefile
@@ -93,5 +93,5 @@ test_dep_lib_paths := $(subst $(space),:,$(foreach DIR,$(DEP_DIRS),$(DIR)/lib))
.PHONY: run_test%
run_test%: test%
- export LD_LIBRARY_PATH=$(test_dep_lib_paths) ; ./$<
+ export LD_LIBRARY_PATH=$(test_dep_lib_paths) ; $(VALGRIND) ./$<
diff --git a/libmuscle/cpp/build/protobuf/.gitignore b/libmuscle/cpp/build/protobuf/.gitignore
index a0991ff4..7213c2a0 100644
--- a/libmuscle/cpp/build/protobuf/.gitignore
+++ b/libmuscle/cpp/build/protobuf/.gitignore
@@ -1,3 +1,4 @@
*
!.gitignore
!Makefile
+!*.patch
diff --git a/libmuscle/cpp/build/protobuf/Makefile b/libmuscle/cpp/build/protobuf/Makefile
index d5d228b1..863347a4 100644
--- a/libmuscle/cpp/build/protobuf/Makefile
+++ b/libmuscle/cpp/build/protobuf/Makefile
@@ -20,6 +20,7 @@ protobuf-cpp-$(protobuf_VERSION).tar.gz:
protobuf-$(protobuf_VERSION): protobuf-cpp-$(protobuf_VERSION).tar.gz
$(TAR) xf protobuf-cpp-$(protobuf_VERSION).tar.gz
+ patch -p0 $@
+ @echo 'exec_prefix=$${prefix}' >>$@
+ @echo 'includedir=$${prefix}/include' >>$@
+ @echo 'libdir=$${exec_prefix}/lib' >>$@
+ @echo >>$@
+ @echo 'Name: yMMSL for C++' >>$@
+ @echo 'Description: Partial yMMSL support library for MUSCLE 3' >>$@
+ @echo 'URL: https://muscle3.readthedocs.io' >>$@
+ @echo 'Version: $(muscle_version)' >>$@
+ @echo 'Cflags: -I$${includedir}' >>$@
+ @echo 'Libs: -L$${libdir} -lymmsl' >>$@
+
diff --git a/libmuscle/cpp/build/ymmsl/ymmsl.version b/libmuscle/cpp/build/ymmsl/ymmsl.version
index d48e63d6..32a4773b 100644
--- a/libmuscle/cpp/build/ymmsl/ymmsl.version
+++ b/libmuscle/cpp/build/ymmsl/ymmsl.version
@@ -122,18 +122,21 @@
YMMSL_Settings_size_;
YMMSL_Settings_empty_;
YMMSL_Settings_is_a_character_;
+ YMMSL_Settings_is_a_int4_;
YMMSL_Settings_is_a_int8_;
YMMSL_Settings_is_a_real8_;
YMMSL_Settings_is_a_logical_;
YMMSL_Settings_is_a_real8array_;
YMMSL_Settings_is_a_real8array2_;
YMMSL_Settings_set_character_;
+ YMMSL_Settings_set_int4_;
YMMSL_Settings_set_int8_;
YMMSL_Settings_set_real8_;
YMMSL_Settings_set_logical_;
YMMSL_Settings_set_real8array_;
YMMSL_Settings_set_real8array2_;
YMMSL_Settings_get_as_character_;
+ YMMSL_Settings_get_as_int4_;
YMMSL_Settings_get_as_int8_;
YMMSL_Settings_get_as_real8_;
YMMSL_Settings_get_as_logical_;
diff --git a/libmuscle/cpp/src/libmuscle/bindings/cmdlineargs.hpp b/libmuscle/cpp/src/libmuscle/bindings/cmdlineargs.hpp
index 3c00ef97..6a64aaf2 100644
--- a/libmuscle/cpp/src/libmuscle/bindings/cmdlineargs.hpp
+++ b/libmuscle/cpp/src/libmuscle/bindings/cmdlineargs.hpp
@@ -9,7 +9,7 @@ namespace libmuscle { namespace impl { namespace bindings {
// Simple helper class for passing command line args from Fortran to C++.
class CmdLineArgs {
public:
- CmdLineArgs(int count);
+ explicit CmdLineArgs(int count);
void set_arg(int i, std::string const & arg);
diff --git a/libmuscle/cpp/src/libmuscle/data.cpp b/libmuscle/cpp/src/libmuscle/data.cpp
index 4637d380..c7b0245c 100644
--- a/libmuscle/cpp/src/libmuscle/data.cpp
+++ b/libmuscle/cpp/src/libmuscle/data.cpp
@@ -310,6 +310,7 @@ DataConstRef::DataConstRef(Settings const & settings)
void DataConstRef::reseat(DataConstRef const & target) {
mp_zones_ = target.mp_zones_;
mp_obj_ = target.mp_obj_;
+ obj_cache_ = target.obj_cache_;
}
template <>
@@ -718,8 +719,10 @@ DataConstRef DataConstRef::grid_dict_() const {
if (oh.get().type != msgpack::type::MAP)
throw std::runtime_error("Invalid grid format. Bug in MUSCLE 3?");
- auto zone = std::make_shared();
- return DataConstRef(mcp::unpack_data(zone, ext.data(), ext.size()));
+ if (!obj_cache_)
+ obj_cache_ = std::make_shared(
+ mcp::unpack_data(mp_zones_->at(0), ext.data(), ext.size()));
+ return *obj_cache_;
}
/* This is here in the .cpp and instantiated explicitly, because it requires the
@@ -853,6 +856,7 @@ Data & Data::operator=(Data const & rhs) {
if (mp_zones_ != rhs.mp_zones_)
mp_zones_->insert(mp_zones_->end(),
rhs.mp_zones_->cbegin(), rhs.mp_zones_->cend());
+ obj_cache_ = rhs.obj_cache_;
}
return *this;
}
diff --git a/libmuscle/cpp/src/libmuscle/data.hpp b/libmuscle/cpp/src/libmuscle/data.hpp
index 02b83321..30407693 100644
--- a/libmuscle/cpp/src/libmuscle/data.hpp
+++ b/libmuscle/cpp/src/libmuscle/data.hpp
@@ -462,6 +462,9 @@ class DataConstRef {
Zones_ mp_zones_;
msgpack::object * mp_obj_;
+ // cache for extracted complex object, e.g. Settings, Grid
+ mutable std::shared_ptr obj_cache_;
+
// create DCR pointing to the given object and sharing the given zone
DataConstRef(
msgpack::object * data,
@@ -473,7 +476,7 @@ class DataConstRef {
Zones_ const & zones);
// create DCR sharing the given zone
- DataConstRef(std::shared_ptr const & zone);
+ explicit DataConstRef(std::shared_ptr const & zone);
// create DCR with given data packed as ext type
DataConstRef(char ext_type_id, DataConstRef const & data);
diff --git a/libmuscle/cpp/src/libmuscle/instance.cpp b/libmuscle/cpp/src/libmuscle/instance.cpp
index 11faed51..bc4d8823 100644
--- a/libmuscle/cpp/src/libmuscle/instance.cpp
+++ b/libmuscle/cpp/src/libmuscle/instance.cpp
@@ -132,6 +132,7 @@ Instance::Impl::Impl(
communicator_.reset(new Communicator(name_(), index_(), ports, *logger_, 0));
register_();
connect_();
+ set_log_level_();
#ifdef MUSCLE_ENABLE_MPI
auto sbase_data = Data(settings_manager_.base);
msgpack::sbuffer sbuf;
diff --git a/libmuscle/cpp/src/libmuscle/libmuscle.hpp b/libmuscle/cpp/src/libmuscle/libmuscle.hpp
index 19813429..c7d74ada 100644
--- a/libmuscle/cpp/src/libmuscle/libmuscle.hpp
+++ b/libmuscle/cpp/src/libmuscle/libmuscle.hpp
@@ -1,5 +1,6 @@
#include
#include
+#include
#include
#include
diff --git a/libmuscle/cpp/src/libmuscle/mcp/tcp_client.cpp b/libmuscle/cpp/src/libmuscle/mcp/tcp_client.cpp
index 01068cd9..a79eeac5 100644
--- a/libmuscle/cpp/src/libmuscle/mcp/tcp_client.cpp
+++ b/libmuscle/cpp/src/libmuscle/mcp/tcp_client.cpp
@@ -68,9 +68,8 @@ int connect(std::string const & address) {
// try to connect to each in turn until we find one that works
addrinfo * p;
- int socket_fd;
for (p = address_info.get(); p != nullptr; p = p->ai_next) {
- socket_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
+ int socket_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (socket_fd == -1) continue;
err_code = connect(socket_fd, p->ai_addr, p->ai_addrlen);
diff --git a/libmuscle/cpp/src/libmuscle/mcp/tcp_server.cpp b/libmuscle/cpp/src/libmuscle/mcp/tcp_server.cpp
index e4045f3b..95384355 100644
--- a/libmuscle/cpp/src/libmuscle/mcp/tcp_server.cpp
+++ b/libmuscle/cpp/src/libmuscle/mcp/tcp_server.cpp
@@ -35,7 +35,7 @@ class TcpServerWorker {
*
* @param post_office The PostOffice to get messages from.
*/
- TcpServerWorker(PostOffice & post_office)
+ explicit TcpServerWorker(PostOffice & post_office)
: post_office_(post_office)
, shutting_down_(false)
, connections_()
@@ -296,12 +296,12 @@ TcpServer::AddrInfoList_ TcpServer::get_address_info_(
std::vector TcpServer::create_sockets_(addrinfo const * addresses) const {
std::vector result;
- int err = 0;
for (addrinfo const *p = addresses; p != nullptr; p = p->ai_next) {
int sockfd;
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
continue;
+ int err = 0;
if ((err = bind(sockfd, p->ai_addr, p->ai_addrlen)) == -1) {
::close(sockfd);
continue;
@@ -324,19 +324,18 @@ std::string TcpServer::get_address_string_(int sockfd) const {
getsockname(sockfd, reinterpret_cast(&bound_addr), &addr_len);
char addr_buf[INET6_ADDRSTRLEN];
- int port = 0;
auto family = reinterpret_cast(&bound_addr)->sa_family;
if (family == AF_INET) {
auto ipv4_addr = reinterpret_cast(&bound_addr);
inet_ntop(AF_INET, &(ipv4_addr->sin_addr), addr_buf, INET6_ADDRSTRLEN);
- port = ntohs(ipv4_addr->sin_port);
+ int port = ntohs(ipv4_addr->sin_port);
location = std::string(addr_buf) + ":" + std::to_string(port);
}
else if (family == AF_INET6) {
auto ipv6_addr = reinterpret_cast(&bound_addr);
inet_ntop(AF_INET6, &(ipv6_addr->sin6_addr), addr_buf, INET6_ADDRSTRLEN);
- port = ntohs(ipv6_addr->sin6_port);
+ int port = ntohs(ipv6_addr->sin6_port);
location = "[" + std::string(addr_buf) + "]:" + std::to_string(port);
}
else
diff --git a/libmuscle/cpp/src/libmuscle/mmp_client.hpp b/libmuscle/cpp/src/libmuscle/mmp_client.hpp
index 0bac14d5..743c90f3 100644
--- a/libmuscle/cpp/src/libmuscle/mmp_client.hpp
+++ b/libmuscle/cpp/src/libmuscle/mmp_client.hpp
@@ -32,7 +32,7 @@ class MMPClient {
*
* @param location A connection string of the form hostname:port.
*/
- MMPClient(std::string const & location);
+ explicit MMPClient(std::string const & location);
/** Send a log message to the manager.
*
diff --git a/libmuscle/cpp/src/libmuscle/tests/mocks/mock_mmp_client.hpp b/libmuscle/cpp/src/libmuscle/tests/mocks/mock_mmp_client.hpp
index 9135743c..c8dcfdb2 100644
--- a/libmuscle/cpp/src/libmuscle/tests/mocks/mock_mmp_client.hpp
+++ b/libmuscle/cpp/src/libmuscle/tests/mocks/mock_mmp_client.hpp
@@ -15,7 +15,7 @@ namespace libmuscle { namespace impl {
class MockMMPClient {
public:
- MockMMPClient(std::string const & location);
+ explicit MockMMPClient(std::string const & location);
void submit_log_message(LogMessage const & message);
diff --git a/libmuscle/cpp/src/libmuscle/tests/test_data.cpp b/libmuscle/cpp/src/libmuscle/tests/test_data.cpp
index 88bf5dd4..0b3419ac 100644
--- a/libmuscle/cpp/src/libmuscle/tests/test_data.cpp
+++ b/libmuscle/cpp/src/libmuscle/tests/test_data.cpp
@@ -349,6 +349,27 @@ TEST(libmuscle_mcp_data, list_dict) {
ASSERT_EQ(data[2]["test2"].as(), 87);
}
+TEST(libmuscle_mcp_data, list_list) {
+ auto list = Data::list("test1", "test2", 13);
+
+ msgpack::sbuffer buf;
+ msgpack::pack(buf, Data::list(1, 2.0, list));
+ auto zone = std::make_shared();
+ auto data = unpack_data(zone, buf.data(), buf.size());
+
+ ASSERT_TRUE(data.is_a_list());
+ ASSERT_EQ(data.size(), 3);
+ ASSERT_TRUE(data[0].is_a());
+ ASSERT_EQ(data[0].as(), 1);
+ ASSERT_TRUE(data[1].is_a());
+ ASSERT_EQ(data[1].as(), 2.0);
+ ASSERT_TRUE(data[2].is_a_list());
+ ASSERT_EQ(data[2].size(), 3);
+ ASSERT_EQ(data[2][0].as(), "test1");
+ ASSERT_EQ(data[2][1].as(), "test2");
+ ASSERT_EQ(data[2][2].as(), 13);
+}
+
TEST(libmuscle_mcp_data, list_dataconstref) {
// regression test
Data dict = Data::list(DataConstRef());
diff --git a/libmuscle/cpp/src/libmuscle/tests/test_instance.cpp b/libmuscle/cpp/src/libmuscle/tests/test_instance.cpp
index 6cbdeedf..d6537296 100644
--- a/libmuscle/cpp/src/libmuscle/tests/test_instance.cpp
+++ b/libmuscle/cpp/src/libmuscle/tests/test_instance.cpp
@@ -154,13 +154,27 @@ TEST(libmuscle_instance, get_setting) {
Settings settings;
settings["test1"] = "test";
settings["test2"] = {1.0, 2.0};
+ settings["test3"] = 10;
+ settings["test4"] = 10000000000l; // does not fit 32 bits
+ settings["test5"] = 10.0;
+ settings["test6"] = 1.0f / 3.0f; // not exactly representable
TestInstance::settings_manager_(instance).base = settings;
ASSERT_TRUE(instance.get_setting("test1").is_a());
ASSERT_EQ(instance.get_setting("test1").as(), "test");
ASSERT_EQ(instance.get_setting_as("test1"), "test");
+
ASSERT_EQ(instance.get_setting_as>("test2"), std::vector({1.0, 2.0}));
+ ASSERT_EQ(instance.get_setting_as("test3"), 10l);
+ ASSERT_EQ(instance.get_setting_as("test4"), 10000000000l);
+ ASSERT_EQ(static_cast(instance.get_setting_as("test3")), 10);
+ ASSERT_THROW(instance.get_setting_as("test4"), std::bad_cast);
+
+ ASSERT_EQ(instance.get_setting_as("test5"), 10.0);
+ ASSERT_EQ(instance.get_setting_as("test6"), 1.0f / 3.0f);
+ ASSERT_EQ(instance.get_setting_as("test3"), 10.0);
+
ASSERT_THROW(instance.get_setting("testx"), std::out_of_range);
ASSERT_THROW(instance.get_setting_as("test1"), std::bad_cast);
}
diff --git a/libmuscle/cpp/src/libmuscle/tests/test_util.cpp b/libmuscle/cpp/src/libmuscle/tests/test_util.cpp
index 5b103712..18106df9 100644
--- a/libmuscle/cpp/src/libmuscle/tests/test_util.cpp
+++ b/libmuscle/cpp/src/libmuscle/tests/test_util.cpp
@@ -58,13 +58,13 @@ struct OptMock {
++rhs.move_constructed_from;
}
- OptMock const & operator=(OptMock const & rhs) {
+ OptMock & operator=(OptMock const & rhs) {
++copy_assigned_to;
++rhs.copy_assigned_from;
return *this;
}
- OptMock const & operator=(OptMock && rhs) {
+ OptMock & operator=(OptMock && rhs) {
++move_assigned_to;
++rhs.move_assigned_from;
return *this;
diff --git a/libmuscle/cpp/src/ymmsl/bindings/ymmsl_fortran_c.cpp b/libmuscle/cpp/src/ymmsl/bindings/ymmsl_fortran_c.cpp
index 57d97d95..f642e515 100644
--- a/libmuscle/cpp/src/ymmsl/bindings/ymmsl_fortran_c.cpp
+++ b/libmuscle/cpp/src/ymmsl/bindings/ymmsl_fortran_c.cpp
@@ -89,6 +89,51 @@ bool YMMSL_Settings_is_a_character_(std::intptr_t self, char * key, std::size_t
}
}
+bool YMMSL_Settings_is_a_int4_(std::intptr_t self, char * key, std::size_t key_size, int * err_code, char ** err_msg, std::size_t * err_msg_len) {
+ Settings * self_p = reinterpret_cast(self);
+ std::string key_s(key, key_size);
+ try {
+ *err_code = 0;
+ bool result = self_p->at(key_s).is_a();
+ return result;
+ }
+ catch (std::domain_error const & e) {
+ *err_code = 1;
+ static std::string msg;
+ msg = e.what();
+ *err_msg = const_cast(msg.data());
+ *err_msg_len = msg.size();
+ }
+ catch (std::out_of_range const & e) {
+ *err_code = 2;
+ static std::string msg;
+ msg = e.what();
+ *err_msg = const_cast(msg.data());
+ *err_msg_len = msg.size();
+ }
+ catch (std::logic_error const & e) {
+ *err_code = 3;
+ static std::string msg;
+ msg = e.what();
+ *err_msg = const_cast(msg.data());
+ *err_msg_len = msg.size();
+ }
+ catch (std::runtime_error const & e) {
+ *err_code = 4;
+ static std::string msg;
+ msg = e.what();
+ *err_msg = const_cast(msg.data());
+ *err_msg_len = msg.size();
+ }
+ catch (std::bad_cast const & e) {
+ *err_code = 5;
+ static std::string msg;
+ msg = e.what();
+ *err_msg = const_cast(msg.data());
+ *err_msg_len = msg.size();
+ }
+}
+
bool YMMSL_Settings_is_a_int8_(std::intptr_t self, char * key, std::size_t key_size, int * err_code, char ** err_msg, std::size_t * err_msg_len) {
Settings * self_p = reinterpret_cast(self);
std::string key_s(key, key_size);
@@ -322,6 +367,13 @@ void YMMSL_Settings_set_character_(std::intptr_t self, char * key, std::size_t k
return;
}
+void YMMSL_Settings_set_int4_(std::intptr_t self, char * key, std::size_t key_size, int32_t value) {
+ Settings * self_p = reinterpret_cast(self);
+ std::string key_s(key, key_size);
+ (*self_p)[key_s] = value;
+ return;
+}
+
void YMMSL_Settings_set_int8_(std::intptr_t self, char * key, std::size_t key_size, int64_t value) {
Settings * self_p = reinterpret_cast(self);
std::string key_s(key, key_size);
@@ -411,6 +463,51 @@ void YMMSL_Settings_get_as_character_(std::intptr_t self, char * key, std::size_
}
}
+int32_t YMMSL_Settings_get_as_int4_(std::intptr_t self, char * key, std::size_t key_size, int * err_code, char ** err_msg, std::size_t * err_msg_len) {
+ Settings * self_p = reinterpret_cast(self);
+ std::string key_s(key, key_size);
+ try {
+ *err_code = 0;
+ int32_t result = self_p->at(key_s).as();
+ return result;
+ }
+ catch (std::domain_error const & e) {
+ *err_code = 1;
+ static std::string msg;
+ msg = e.what();
+ *err_msg = const_cast(msg.data());
+ *err_msg_len = msg.size();
+ }
+ catch (std::out_of_range const & e) {
+ *err_code = 2;
+ static std::string msg;
+ msg = e.what();
+ *err_msg = const_cast(msg.data());
+ *err_msg_len = msg.size();
+ }
+ catch (std::logic_error const & e) {
+ *err_code = 3;
+ static std::string msg;
+ msg = e.what();
+ *err_msg = const_cast(msg.data());
+ *err_msg_len = msg.size();
+ }
+ catch (std::runtime_error const & e) {
+ *err_code = 4;
+ static std::string msg;
+ msg = e.what();
+ *err_msg = const_cast(msg.data());
+ *err_msg_len = msg.size();
+ }
+ catch (std::bad_cast const & e) {
+ *err_code = 5;
+ static std::string msg;
+ msg = e.what();
+ *err_msg = const_cast(msg.data());
+ *err_msg_len = msg.size();
+ }
+}
+
int64_t YMMSL_Settings_get_as_int8_(std::intptr_t self, char * key, std::size_t key_size, int * err_code, char ** err_msg, std::size_t * err_msg_len) {
Settings * self_p = reinterpret_cast(self);
std::string key_s(key, key_size);
diff --git a/libmuscle/cpp/src/ymmsl/settings.cpp b/libmuscle/cpp/src/ymmsl/settings.cpp
index 3b7f68dd..5d2f5257 100644
--- a/libmuscle/cpp/src/ymmsl/settings.cpp
+++ b/libmuscle/cpp/src/ymmsl/settings.cpp
@@ -81,14 +81,14 @@ SettingValue::SettingValue(SettingValue && other)
other.deactivate_();
}
-SettingValue const & SettingValue::operator=(SettingValue const & other) {
+SettingValue & SettingValue::operator=(SettingValue const & other) {
deactivate_();
copy_value_from_(other);
type_ = other.type_;
return *this;
}
-SettingValue const & SettingValue::operator=(SettingValue && other) {
+SettingValue & SettingValue::operator=(SettingValue && other) {
deactivate_();
move_value_from_(std::move(other));
type_ = other.type_;
diff --git a/libmuscle/cpp/src/ymmsl/settings.hpp b/libmuscle/cpp/src/ymmsl/settings.hpp
index fde216ec..ed64e874 100644
--- a/libmuscle/cpp/src/ymmsl/settings.hpp
+++ b/libmuscle/cpp/src/ymmsl/settings.hpp
@@ -101,11 +101,11 @@ class SettingValue {
/** Copy-assigns a SettingValue.
*/
- SettingValue const & operator=(SettingValue const & other);
+ SettingValue & operator=(SettingValue const & other);
/** Move-assigns a SettingValue.
*/
- SettingValue const & operator=(SettingValue && other);
+ SettingValue & operator=(SettingValue && other);
/** Destructs a SettingValue.
*/
@@ -129,8 +129,16 @@ class SettingValue {
/** Return whether this SettingValue holds a value of the given type.
*
- * @param T A valid type, being one of std::string, int64_t, double,
- * bool, std::vector, or
+ * Note that for int32_t, this function will return true only if the
+ * value is integer and fits in an int32_t. For double, it will return
+ * true if the value is integer, even if converting it to a double
+ * would reduce precision.
+ *
+ * Since int and long are usually equivalent to int32_t or int64_t,
+ * you can use those values too.
+ *
+ * @param T A valid type, being one of std::string, int32_t, int64_t,
+ * double, bool, std::vector, or
* std::vector>.
*/
template
@@ -140,8 +148,8 @@ class SettingValue {
*
* Only call if is_a() returns true.
*
- * @param T A valid type, being one of std::string, int64_t, double,
- * bool, std::vector, or
+ * @param T A valid type, being one of std::string, int32_t, int64_t,
+ * double, bool, std::vector, or
* std::vector>.
*
* @throw std::bad_cast if the type of this value does not match the
diff --git a/libmuscle/cpp/src/ymmsl/settings.tpp b/libmuscle/cpp/src/ymmsl/settings.tpp
index 6e13ef36..99e6b5a0 100644
--- a/libmuscle/cpp/src/ymmsl/settings.tpp
+++ b/libmuscle/cpp/src/ymmsl/settings.tpp
@@ -1,5 +1,8 @@
// Template implementation. Do not include directly!
+#include
+
+
namespace ymmsl { namespace impl {
template<>
@@ -12,9 +15,19 @@ inline bool SettingValue::is_a() const {
return type_ == Type_::INT;
}
+template<>
+inline bool SettingValue::is_a() const {
+ if (type_ != Type_::INT) return false;
+
+ bool too_small = (int_value_ < std::numeric_limits::min());
+ bool too_big = (int_value_ > std::numeric_limits::max());
+
+ return !(too_small || too_big);
+}
+
template<>
inline bool SettingValue::is_a() const {
- return type_ == Type_::FLOAT;
+ return (type_ == Type_::FLOAT) || (type_ == Type_::INT);
}
template<>
@@ -52,10 +65,19 @@ inline int64_t SettingValue::as() const {
return int_value_;
}
+template<>
+inline int32_t SettingValue::as() const {
+ if (!is_a())
+ throw std::bad_cast();
+ return int_value_;
+}
+
template<>
inline double SettingValue::as() const {
if (!is_a())
throw std::bad_cast();
+ if (is_a())
+ return static_cast(int_value_);
return float_value_;
}
diff --git a/libmuscle/fortran/build/libmuscle/Makefile b/libmuscle/fortran/build/libmuscle/Makefile
index f5dcda51..8d3da959 100644
--- a/libmuscle/fortran/build/libmuscle/Makefile
+++ b/libmuscle/fortran/build/libmuscle/Makefile
@@ -121,9 +121,10 @@ libmuscle_fortran.pc:
@echo 'Description: Library for MUSCLE 3 - Fortran version' >>$@
@echo 'URL: https://muscle3.readthedocs.io' >>$@
@echo 'Version: $(muscle_version)' >>$@
+ @echo 'Requires: ymmsl_fortran = $(muscle_version)' >>$@
@echo 'Requires.private: libmuscle = $(muscle_version)' >>$@
@echo 'Cflags: -I$${includedir}' >>$@
- @echo 'Libs: -L$${libdir} -lymmsl_fortran -lmuscle_fortran' >>$@
+ @echo 'Libs: -L$${libdir} -lmuscle_fortran' >>$@
libmuscle_mpi_fortran.pc:
@echo 'prefix=$(PREFIX)' >$@
@@ -135,7 +136,8 @@ libmuscle_mpi_fortran.pc:
@echo 'Description: Library for MUSCLE 3 - Fortran-MPI version' >>$@
@echo 'URL: https://muscle3.readthedocs.io' >>$@
@echo 'Version: $(muscle_version)' >>$@
+ @echo 'Requires: ymmsl_fortran = $(muscle_version)' >>$@
@echo 'Requires.private: libmuscle_mpi = $(muscle_version)' >>$@
@echo 'Cflags: -I$${includedir}' >>$@
- @echo 'Libs: -L$${libdir} -lymmsl_fortran -lmuscle_mpi_fortran' >>$@
+ @echo 'Libs: -L$${libdir} -lmuscle_mpi_fortran' >>$@
diff --git a/libmuscle/fortran/build/ymmsl/Makefile b/libmuscle/fortran/build/ymmsl/Makefile
index 858c892c..9b1d105c 100644
--- a/libmuscle/fortran/build/ymmsl/Makefile
+++ b/libmuscle/fortran/build/ymmsl/Makefile
@@ -6,10 +6,12 @@ objects := $(sources:$(srcdir)/%.f03=%.o)
lobjects := $(sources:$(srcdir)/%.f03=%.lo)
libs := libymmsl_fortran.a libymmsl_fortran.so
modules := $(sources:$(srcdir)/%.f03=%.mod)
+pkg_config_files := ymmsl_fortran.pc
installed_sources := $(sources:$(srcdir)/%=$(PREFIX)/include/%)
installed_modules := $(modules:%=$(PREFIX)/include/%)
installed_libs := $(libs:%=$(PREFIX)/lib/%)
+installed_pkg_config_files := $(pkg_config_files:%=$(PREFIX)/lib/pkgconfig/%)
LDFLAGS := -L../../../cpp/build/ymmsl -lymmsl
FFLAGS := -std=f2003
@@ -28,14 +30,14 @@ test: tests
.PHONY: clean
clean:
- rm -f $(objects) $(modules) $(libs)
+ rm -f $(objects) $(modules) $(libs) $(pkg_config_files)
rm -f mod_dump/*.mod
.PHONY: distclean
distclean: clean
.PHONY: install
-install: $(installed_sources) $(installed_modules) $(installed_libs)
+install: $(installed_sources) $(installed_modules) $(installed_libs) $(installed_pkg_config_files)
%.o: $(srcdir)/%.f03
$(FC) -c $(FFLAGS) $^ -o $@ $(LDFLAGS)
@@ -62,3 +64,22 @@ $(PREFIX)/include/%: %
$(PREFIX)/lib/%: %
@mkdir -p $(@D)
cp $< $@
+
+$(PREFIX)/lib/pkgconfig/%: %
+ @mkdir -p $(@D)
+ cp $< $@
+
+ymmsl_fortran.pc:
+ @echo 'prefix=$(PREFIX)' >$@
+ @echo 'exec_prefix=$${prefix}' >>$@
+ @echo 'includedir=$${prefix}/include' >>$@
+ @echo 'libdir=$${exec_prefix}/lib' >>$@
+ @echo >>$@
+ @echo 'Name: yMMSL for Fortran' >>$@
+ @echo 'Description: Partial yMMSL support library for MUSCLE 3' >>$@
+ @echo 'URL: https://muscle3.readthedocs.io' >>$@
+ @echo 'Version: $(muscle_version)' >>$@
+ @echo 'Requires.private: ymmsl = $(muscle_version)' >>$@
+ @echo 'Cflags: -I$${includedir}' >>$@
+ @echo 'Libs: -L$${libdir} -lymmsl_fortran' >>$@
+
diff --git a/libmuscle/fortran/src/libmuscle/tests/test_settings.f03 b/libmuscle/fortran/src/libmuscle/tests/test_settings.f03
index 5de4dc68..38919fdb 100644
--- a/libmuscle/fortran/src/libmuscle/tests/test_settings.f03
+++ b/libmuscle/fortran/src/libmuscle/tests/test_settings.f03
@@ -66,11 +66,12 @@ subroutine test_settings_set_get_as
ra3 = reshape((/1.0d0, 2.0d0, 3.0d0, 4.0d0, 5.0d0, 6.0d0/), (/3, 2/))
call YMMSL_Settings_set(s1, 'key1', 'value1')
- call YMMSL_Settings_set(s1, 'key2', 42424242424242_YMMSL_int8)
- call YMMSL_Settings_set(s1, 'key3', .false.)
- call YMMSL_Settings_set(s1, 'key4', 13.13d0)
- call YMMSL_Settings_set(s1, 'key5', ra1)
- call YMMSL_Settings_set(s1, 'key6', ra3)
+ call YMMSL_Settings_set(s1, 'key2', 242424242_YMMSL_int4)
+ call YMMSL_Settings_set(s1, 'key3', 42424242424242_YMMSL_int8)
+ call YMMSL_Settings_set(s1, 'key4', .false.)
+ call YMMSL_Settings_set(s1, 'key5', 13.13d0)
+ call YMMSL_Settings_set(s1, 'key6', ra1)
+ call YMMSL_Settings_set(s1, 'key7', ra3)
call assert_true(YMMSL_Settings_contains(s1, 'key1'))
call assert_true(YMMSL_Settings_contains(s1, 'key2'))
@@ -78,15 +79,19 @@ subroutine test_settings_set_get_as
call assert_true(YMMSL_Settings_contains(s1, 'key4'))
call assert_true(YMMSL_Settings_contains(s1, 'key5'))
call assert_true(YMMSL_Settings_contains(s1, 'key6'))
+ call assert_true(YMMSL_Settings_contains(s1, 'key7'))
call assert_false(YMMSL_Settings_contains(s1, 'nokey'))
call assert_eq_character(YMMSL_Settings_get_as_character(s1, 'key1'), 'value1')
- call assert_eq_int8(YMMSL_Settings_get_as_int8(s1, 'key2'), 42424242424242_YMMSL_int8)
- call assert_eq_logical(YMMSL_Settings_get_as_logical(s1, 'key3'), .false.)
- call assert_eq_real8(YMMSL_Settings_get_as_real8(s1, 'key4'), 13.13d0)
- call YMMSL_Settings_get_as_real8array(s1, 'key5', ra2)
+ call assert_eq_int4(YMMSL_Settings_get_as_int4(s1, 'key2'), 242424242_YMMSL_int4)
+ call assert_eq_int8(YMMSL_Settings_get_as_int8(s1, 'key2'), 242424242_YMMSL_int8)
+ call assert_eq_int8(YMMSL_Settings_get_as_int8(s1, 'key3'), 42424242424242_YMMSL_int8)
+ call assert_eq_logical(YMMSL_Settings_get_as_logical(s1, 'key4'), .false.)
+ call assert_eq_real8(YMMSL_Settings_get_as_real8(s1, 'key5'), 13.13d0)
+ call assert_eq_real8(YMMSL_Settings_get_as_real8(s1, 'key2'), 242424242d0)
+ call YMMSL_Settings_get_as_real8array(s1, 'key6', ra2)
call assert_eq_real8array(ra2, ra1)
- call YMMSL_Settings_get_as_real8array2(s1, 'key6', ra4)
+ call YMMSL_Settings_get_as_real8array2(s1, 'key7', ra4)
call assert_eq_real8array2(ra4, ra3)
call YMMSL_Settings_free(s1)
@@ -109,18 +114,22 @@ subroutine test_settings_is_a
ra2 = reshape((/1.0d0, 2.0d0, 3.0d0, 4.0d0, 5.0d0, 6.0d0/), (/3, 2/))
call YMMSL_Settings_set(s1, 'key1', 'value1')
- call YMMSL_Settings_set(s1, 'key2', 42424242424242_YMMSL_int8)
- call YMMSL_Settings_set(s1, 'key3', .false.)
- call YMMSL_Settings_set(s1, 'key4', 13.13d0)
- call YMMSL_Settings_set(s1, 'key5', ra1)
- call YMMSL_Settings_set(s1, 'key6', ra2)
+ call YMMSL_Settings_set(s1, 'key2', 242424242_YMMSL_int4)
+ call YMMSL_Settings_set(s1, 'key3', 42424242424242_YMMSL_int8)
+ call YMMSL_Settings_set(s1, 'key4', .false.)
+ call YMMSL_Settings_set(s1, 'key5', 13.13d0)
+ call YMMSL_Settings_set(s1, 'key6', ra1)
+ call YMMSL_Settings_set(s1, 'key7', ra2)
call assert_true(YMMSL_Settings_is_a_character(s1, 'key1'))
+ call assert_true(YMMSL_Settings_is_a_int4(s1, 'key2'))
call assert_true(YMMSL_Settings_is_a_int8(s1, 'key2'))
- call assert_true(YMMSL_Settings_is_a_logical(s1, 'key3'))
- call assert_true(YMMSL_Settings_is_a_real8(s1, 'key4'))
- call assert_true(YMMSL_Settings_is_a_real8array(s1, 'key5'))
- call assert_true(YMMSL_Settings_is_a_real8array2(s1, 'key6'))
+ call assert_false(YMMSL_Settings_is_a_int4(s1, 'key3'))
+ call assert_true(YMMSL_Settings_is_a_int8(s1, 'key3'))
+ call assert_true(YMMSL_Settings_is_a_logical(s1, 'key4'))
+ call assert_true(YMMSL_Settings_is_a_real8(s1, 'key5'))
+ call assert_true(YMMSL_Settings_is_a_real8array(s1, 'key6'))
+ call assert_true(YMMSL_Settings_is_a_real8array2(s1, 'key7'))
call assert_false(YMMSL_Settings_is_a_int8(s1, 'key1'))
call assert_false(YMMSL_Settings_is_a_logical(s1, 'key1'))
diff --git a/libmuscle/fortran/src/ymmsl/ymmsl.f03 b/libmuscle/fortran/src/ymmsl/ymmsl.f03
index cdeec328..07e0db91 100644
--- a/libmuscle/fortran/src/ymmsl/ymmsl.f03
+++ b/libmuscle/fortran/src/ymmsl/ymmsl.f03
@@ -41,12 +41,14 @@ module ymmsl
public :: YMMSL_Settings_size
public :: YMMSL_Settings_empty
public :: YMMSL_Settings_is_a_character
+ public :: YMMSL_Settings_is_a_int4
public :: YMMSL_Settings_is_a_int8
public :: YMMSL_Settings_is_a_real8
public :: YMMSL_Settings_is_a_logical
public :: YMMSL_Settings_is_a_real8array
public :: YMMSL_Settings_is_a_real8array2
public :: YMMSL_Settings_set_character
+ public :: YMMSL_Settings_set_int4
public :: YMMSL_Settings_set_int8
public :: YMMSL_Settings_set_real8
public :: YMMSL_Settings_set_logical
@@ -54,6 +56,7 @@ module ymmsl
public :: YMMSL_Settings_set_real8array2
public :: YMMSL_Settings_set
public :: YMMSL_Settings_get_as_character
+ public :: YMMSL_Settings_get_as_int4
public :: YMMSL_Settings_get_as_int8
public :: YMMSL_Settings_get_as_real8
public :: YMMSL_Settings_get_as_logical
@@ -121,6 +124,24 @@ logical (c_bool) function YMMSL_Settings_is_a_character_( &
integer (c_size_t), intent(out) :: err_msg_len
end function YMMSL_Settings_is_a_character_
+ logical (c_bool) function YMMSL_Settings_is_a_int4_( &
+ self, &
+ key, &
+ key_size, &
+ err_code, &
+ err_msg, &
+ err_msg_len) &
+ bind(C, name="YMMSL_Settings_is_a_int4_")
+
+ use iso_c_binding
+ integer (c_intptr_t), value, intent(in) :: self
+ character, intent(in) :: key
+ integer (c_size_t), value, intent(in) :: key_size
+ integer (c_int), intent(out) :: err_code
+ type (c_ptr), intent(out) :: err_msg
+ integer (c_size_t), intent(out) :: err_msg_len
+ end function YMMSL_Settings_is_a_int4_
+
logical (c_bool) function YMMSL_Settings_is_a_int8_( &
self, &
key, &
@@ -227,6 +248,20 @@ subroutine YMMSL_Settings_set_character_( &
integer (c_size_t), value, intent(in) :: value_size
end subroutine YMMSL_Settings_set_character_
+ subroutine YMMSL_Settings_set_int4_( &
+ self, &
+ key, &
+ key_size, &
+ value) &
+ bind(C, name="YMMSL_Settings_set_int4_")
+
+ use iso_c_binding
+ integer (c_intptr_t), value, intent(in) :: self
+ character, intent(in) :: key
+ integer (c_size_t), value, intent(in) :: key_size
+ integer (c_int32_t), value, intent(in) :: value
+ end subroutine YMMSL_Settings_set_int4_
+
subroutine YMMSL_Settings_set_int8_( &
self, &
key, &
@@ -323,6 +358,24 @@ subroutine YMMSL_Settings_get_as_character_( &
integer (c_size_t), intent(out) :: err_msg_len
end subroutine YMMSL_Settings_get_as_character_
+ integer (c_int32_t) function YMMSL_Settings_get_as_int4_( &
+ self, &
+ key, &
+ key_size, &
+ err_code, &
+ err_msg, &
+ err_msg_len) &
+ bind(C, name="YMMSL_Settings_get_as_int4_")
+
+ use iso_c_binding
+ integer (c_intptr_t), value, intent(in) :: self
+ character, intent(in) :: key
+ integer (c_size_t), value, intent(in) :: key_size
+ integer (c_int), intent(out) :: err_code
+ type (c_ptr), intent(out) :: err_msg
+ integer (c_size_t), intent(out) :: err_msg_len
+ end function YMMSL_Settings_get_as_int4_
+
integer (c_int64_t) function YMMSL_Settings_get_as_int8_( &
self, &
key, &
@@ -477,6 +530,7 @@ end subroutine YMMSL_Settings_key_
interface YMMSL_Settings_set
module procedure &
YMMSL_Settings_set_character, &
+ YMMSL_Settings_set_int4, &
YMMSL_Settings_set_int8, &
YMMSL_Settings_set_real8, &
YMMSL_Settings_set_logical, &
@@ -609,6 +663,62 @@ function YMMSL_Settings_is_a_character( &
YMMSL_Settings_is_a_character = ret_val
end function YMMSL_Settings_is_a_character
+ function YMMSL_Settings_is_a_int4( &
+ self, &
+ key, &
+ err_code, &
+ err_msg)
+ implicit none
+ type(YMMSL_Settings), intent(in) :: self
+ character (len=*), intent(in) :: key
+ integer, optional, intent(out) :: err_code
+ character(:), allocatable, optional, intent(out) :: err_msg
+ logical :: YMMSL_Settings_is_a_int4
+
+ logical (c_bool) :: ret_val
+ integer (c_int) :: err_code_v
+ type (c_ptr) :: err_msg_v
+ integer (c_size_t) :: err_msg_len_v
+ character (c_char), dimension(:), pointer :: err_msg_f
+ character(:), allocatable :: err_msg_p
+ integer (c_size_t) :: err_msg_i
+
+ ret_val = YMMSL_Settings_is_a_int4_( &
+ self%ptr, &
+ key, int(len(key), c_size_t), &
+ err_code_v, &
+ err_msg_v, &
+ err_msg_len_v)
+
+ if (err_code_v .ne. 0) then
+ if (present(err_code)) then
+ err_code = err_code_v
+ if (present(err_msg)) then
+ call c_f_pointer(err_msg_v, err_msg_f, (/err_msg_len_v/))
+ allocate (character(err_msg_len_v) :: err_msg)
+ do err_msg_i = 1, err_msg_len_v
+ err_msg(err_msg_i:err_msg_i) = err_msg_f(err_msg_i)
+ end do
+ end if
+ return
+ else
+ call c_f_pointer(err_msg_v, err_msg_f, (/err_msg_len_v/))
+ allocate (character(err_msg_len_v) :: err_msg_p)
+ do err_msg_i = 1, err_msg_len_v
+ err_msg_p(err_msg_i:err_msg_i) = err_msg_f(err_msg_i)
+ end do
+ print *, err_msg_p
+ stop
+ end if
+ else
+ if (present(err_code)) then
+ err_code = 0
+ end if
+ end if
+
+ YMMSL_Settings_is_a_int4 = ret_val
+ end function YMMSL_Settings_is_a_int4
+
function YMMSL_Settings_is_a_int8( &
self, &
key, &
@@ -904,6 +1014,21 @@ subroutine YMMSL_Settings_set_character( &
value, int(len(value), c_size_t))
end subroutine YMMSL_Settings_set_character
+ subroutine YMMSL_Settings_set_int4( &
+ self, &
+ key, &
+ value)
+ implicit none
+ type(YMMSL_Settings), intent(in) :: self
+ character (len=*), intent(in) :: key
+ integer (YMMSL_int4), intent(in) :: value
+
+ call YMMSL_Settings_set_int4_( &
+ self%ptr, &
+ key, int(len(key), c_size_t), &
+ value)
+ end subroutine YMMSL_Settings_set_int4
+
subroutine YMMSL_Settings_set_int8( &
self, &
key, &
@@ -1044,6 +1169,61 @@ function YMMSL_Settings_get_as_character( &
end do
end function YMMSL_Settings_get_as_character
+ function YMMSL_Settings_get_as_int4( &
+ self, &
+ key, &
+ err_code, &
+ err_msg)
+ implicit none
+ type(YMMSL_Settings), intent(in) :: self
+ character (len=*), intent(in) :: key
+ integer, optional, intent(out) :: err_code
+ character(:), allocatable, optional, intent(out) :: err_msg
+ integer (YMMSL_int4) :: YMMSL_Settings_get_as_int4
+
+ integer (c_int32_t) :: ret_val
+ integer (c_int) :: err_code_v
+ type (c_ptr) :: err_msg_v
+ integer (c_size_t) :: err_msg_len_v
+ character (c_char), dimension(:), pointer :: err_msg_f
+ character(:), allocatable :: err_msg_p
+ integer (c_size_t) :: err_msg_i
+
+ ret_val = YMMSL_Settings_get_as_int4_( &
+ self%ptr, &
+ key, int(len(key), c_size_t), &
+ err_code_v, &
+ err_msg_v, &
+ err_msg_len_v)
+ if (err_code_v .ne. 0) then
+ if (present(err_code)) then
+ err_code = err_code_v
+ if (present(err_msg)) then
+ call c_f_pointer(err_msg_v, err_msg_f, (/err_msg_len_v/))
+ allocate (character(err_msg_len_v) :: err_msg)
+ do err_msg_i = 1, err_msg_len_v
+ err_msg(err_msg_i:err_msg_i) = err_msg_f(err_msg_i)
+ end do
+ end if
+ return
+ else
+ call c_f_pointer(err_msg_v, err_msg_f, (/err_msg_len_v/))
+ allocate (character(err_msg_len_v) :: err_msg_p)
+ do err_msg_i = 1, err_msg_len_v
+ err_msg_p(err_msg_i:err_msg_i) = err_msg_f(err_msg_i)
+ end do
+ print *, err_msg_p
+ stop
+ end if
+ else
+ if (present(err_code)) then
+ err_code = 0
+ end if
+ end if
+
+ YMMSL_Settings_get_as_int4 = ret_val
+ end function YMMSL_Settings_get_as_int4
+
function YMMSL_Settings_get_as_int8( &
self, &
key, &
diff --git a/libmuscle/python/libmuscle/__init__.py b/libmuscle/python/libmuscle/__init__.py
index 4b5407ce..707dbdae 100644
--- a/libmuscle/python/libmuscle/__init__.py
+++ b/libmuscle/python/libmuscle/__init__.py
@@ -1,6 +1,3 @@
-import os
-import pathlib
-
from libmuscle.communicator import Message
from libmuscle.grid import Grid
from libmuscle.instance import Instance
diff --git a/libmuscle/python/libmuscle/communicator.py b/libmuscle/python/libmuscle/communicator.py
index 5614a6cc..49f3ec06 100644
--- a/libmuscle/python/libmuscle/communicator.py
+++ b/libmuscle/python/libmuscle/communicator.py
@@ -1,5 +1,5 @@
-import msgpack
-from typing import Any, Dict, List, Optional, Tuple, Union, cast
+import logging
+from typing import Any, Dict, List, Optional, Tuple, cast
from ymmsl import Conduit, Identifier, Operator, Reference, Settings
from libmuscle.endpoint import Endpoint
@@ -11,7 +11,10 @@
from libmuscle.post_office import PostOffice
from libmuscle.port import Port
from libmuscle.profiler import Profiler
-from libmuscle.profiling import ProfileEvent, ProfileEventType
+from libmuscle.profiling import ProfileEventType
+
+
+_logger = logging.getLogger(__name__)
MessageObject = Any
@@ -35,7 +38,7 @@ class Message:
# actually goes out on the wire, see libmuscle.mcp.Message for that.
def __init__(self, timestamp: float, next_timestamp: Optional[float],
data: MessageObject,
- settings: Optional[Settings]=None
+ settings: Optional[Settings] = None
) -> None:
"""Create a Message.
@@ -176,7 +179,7 @@ def get_port(self, port_name: str) -> Port:
def send_message(
self, port_name: str, message: Message,
- slot: Optional[int]=None) -> None:
+ slot: Optional[int] = None) -> None:
"""Send a message and settings to the outside world.
Sending is non-blocking, a copy of the message will be made
@@ -188,8 +191,10 @@ def send_message(
slot: The slot to send the message on, if any.
"""
if slot is None:
+ _logger.info('Sending message on {}'.format(port_name))
slot_list = [] # type: List[int]
else:
+ _logger.info('Sending message on {}[{}]'.format(port_name, slot))
slot_list = [slot]
slot_length = self._ports[port_name].get_length()
if slot_length <= slot:
@@ -226,8 +231,8 @@ def send_message(
profile_event.port_length = port.get_length()
profile_event.message_size = len(encoded_message)
- def receive_message(self, port_name: str, slot: Optional[int]=None,
- default: Optional[Message]=None
+ def receive_message(self, port_name: str, slot: Optional[int] = None,
+ default: Optional[Message] = None
) -> Message:
"""Receive a message and attached settings overlay.
@@ -255,8 +260,11 @@ def receive_message(self, port_name: str, slot: Optional[int]=None,
connected.
"""
if slot is None:
+ _logger.info('Waiting for message on {}'.format(port_name))
slot_list = [] # type: List[int]
else:
+ _logger.info('Waiting for message on {}[{}]'.format(
+ port_name, slot))
slot_list = [slot]
recv_endpoint = self.__get_endpoint(port_name, slot_list)
@@ -268,6 +276,9 @@ def receive_message(self, port_name: str, slot: Optional[int]=None,
' given. Either specify a default, or'
' connect a sending component to this'
' port.').format(port_name))
+ _logger.info(
+ 'No message received on {} as it is not connected'.format(
+ port_name))
return default
if port_name in self._ports:
@@ -303,9 +314,19 @@ def receive_message(self, port_name: str, slot: Optional[int]=None,
profile_event.port_length = port.get_length()
profile_event.message_size = len(mcp_message_bytes)
+ if slot is None:
+ _logger.info('Received message on {}'.format(port_name))
+ if isinstance(mcp_message.data, ClosePort):
+ _logger.info('Port {} is now closed'.format(port_name))
+ else:
+ _logger.info('Received message on {}[{}]'.format(port_name, slot))
+ if isinstance(mcp_message.data, ClosePort):
+ _logger.info('Port {}[{}] is now closed'.format(
+ port_name, slot))
+
return message
- def close_port(self, port_name: str, slot: Optional[int]=None
+ def close_port(self, port_name: str, slot: Optional[int] = None
) -> None:
"""Closes the given port.
@@ -317,6 +338,10 @@ def close_port(self, port_name: str, slot: Optional[int]=None
port_name: The name of the port to close.
"""
message = Message(float('inf'), None, ClosePort(), Settings())
+ if slot is None:
+ _logger.info('Closing port {}'.format(port_name))
+ else:
+ _logger.info('Closing port {}[{}]'.format(port_name, slot))
self.send_message(port_name, message, slot)
def shutdown(self) -> None:
diff --git a/libmuscle/python/libmuscle/instance.py b/libmuscle/python/libmuscle/instance.py
index 517ab936..13338b2d 100644
--- a/libmuscle/python/libmuscle/instance.py
+++ b/libmuscle/python/libmuscle/instance.py
@@ -1,13 +1,11 @@
from copy import copy
import logging
-from pathlib import Path
import sys
-from typing import cast, Dict, List, Optional, Tuple, Union
-from typing_extensions import Type
+from typing import cast, Dict, List, Optional, Tuple
import grpc
-from ymmsl import (Conduit, Identifier, Operator, SettingValue, Port,
- Reference, Settings)
+from ymmsl import (Identifier, Operator, SettingValue, Port, Reference,
+ Settings)
from libmuscle.communicator import Communicator, Message
from libmuscle.settings_manager import SettingsManager
@@ -15,17 +13,20 @@
from libmuscle.mcp.message import ClosePort
from libmuscle.mmp_client import MMPClient
from libmuscle.profiler import Profiler
-from libmuscle.profiling import ProfileEvent, ProfileEventType
+from libmuscle.profiling import ProfileEventType
from libmuscle.util import extract_log_file_location
+_logger = logging.getLogger(__name__)
+
+
class Instance:
"""Represents a compute element instance in a MUSCLE3 simulation.
This class provides a low-level send/receive API for the instance
to use.
"""
- def __init__(self, ports: Optional[Dict[Operator, List[str]]]=None
+ def __init__(self, ports: Optional[Dict[Operator, List[str]]] = None
) -> None:
"""Create an Instance.
@@ -66,8 +67,9 @@ def __init__(self, ports: Optional[Dict[Operator, List[str]]]=None
self._register()
self._connect()
+ self._set_log_level()
- def reuse_instance(self, apply_overlay: bool=True) -> bool:
+ def reuse_instance(self, apply_overlay: bool = True) -> bool:
"""Decide whether to run this instance again.
In a multiscale simulation, instances get reused all the time.
@@ -107,6 +109,8 @@ def reuse_instance(self, apply_overlay: bool=True) -> bool:
# At least emit a warning.
self.__pre_receive_f_init(apply_overlay)
+ self._set_log_level()
+
ports = self._communicator.list_ports()
f_init_not_connected = all(
[not self.is_connected(port)
@@ -253,7 +257,7 @@ def set_port_length(self, port: str, length: int) -> None:
self._communicator.get_port(port).set_length(length)
def send(self, port_name: str, message: Message,
- slot: Optional[int]=None) -> None:
+ slot: Optional[int] = None) -> None:
"""Send a message to the outside world.
Sending is non-blocking, a copy of the message will be made
@@ -271,8 +275,8 @@ def send(self, port_name: str, message: Message,
self._communicator.send_message(port_name, message, slot)
- def receive(self, port_name: str, slot: Optional[int]=None,
- default: Optional[Message]=None
+ def receive(self, port_name: str, slot: Optional[int] = None,
+ default: Optional[Message] = None
) -> Message:
"""Receive a message from the outside world.
@@ -304,8 +308,8 @@ def receive(self, port_name: str, slot: Optional[int]=None,
return self.__receive_message(port_name, slot, default, False)
def receive_with_settings(
- self, port_name: str, slot: Optional[int]=None,
- default: Optional[Message]=None
+ self, port_name: str, slot: Optional[int] = None,
+ default: Optional[Message] = None
) -> Message:
"""Receive a message with attached settings overlay.
@@ -410,9 +414,9 @@ def __set_up_logging(self) -> None:
logging.getLogger().addHandler(local_handler)
if self.__manager is not None:
- mmp_handler = MuscleManagerHandler(id_str, logging.WARNING,
- self.__manager)
- logging.getLogger().addHandler(mmp_handler)
+ self._mmp_handler = MuscleManagerHandler(id_str, logging.WARNING,
+ self.__manager)
+ logging.getLogger().addHandler(self._mmp_handler)
def __receive_message(
self, port_name: str, slot: Optional[int],
@@ -580,6 +584,7 @@ def pre_receive(port_name: str, slot: Optional[int]) -> None:
self._f_init_cache = dict()
ports = self._communicator.list_ports()
for port_name in ports.get(Operator.F_INIT, []):
+ _logger.info('Pre-receiving on port {}'.format(port_name))
port = self._communicator.get_port(port_name)
if not port.is_connected():
continue
@@ -592,6 +597,42 @@ def pre_receive(port_name: str, slot: Optional[int]) -> None:
for slot in range(1, port.get_length()):
pre_receive(port_name, slot)
+ def _set_log_level(self) -> None:
+ """Sets the remote log level.
+
+ This is the minimum level a message must have to be sent to
+ the manager. It gets this from the muscle_remote_log_level
+ setting.
+
+ Note that this also sets the global log level to this level
+ if it is currently higher, otherwise we still get no output.
+
+ """
+ try:
+ log_level_str = cast(
+ str, self.get_setting('muscle_remote_log_level', 'str'))
+ level_map = {
+ 'CRITICAL': logging.CRITICAL,
+ 'ERROR': logging.ERROR,
+ 'WARNING': logging.WARNING,
+ 'INFO': logging.INFO,
+ 'DEBUG': logging.DEBUG}
+
+ if log_level_str.upper() not in level_map:
+ _logger.warning(
+ ('muscle_remote_log_level is set to {}, which is not a'
+ ' valid log level. Please use one of DEBUG, INFO,'
+ ' WARNING, ERROR, or CRITICAL').format(log_level_str))
+ return
+
+ log_level = level_map[log_level_str]
+ self._mmp_handler.setLevel(log_level)
+ if not logging.getLogger().isEnabledFor(log_level):
+ logging.getLogger().setLevel(log_level)
+ except KeyError:
+ # muscle_remote_log_level not set, do nothing and keep the default
+ pass
+
def __apply_overlay(self, message: Message) -> None:
"""Sets local overlay if we don't already have one.
@@ -702,7 +743,7 @@ def __shutdown(self, message: str) -> None:
that we're shutting down, and deregisters from the manager.
"""
if not self.__is_shut_down:
- logging.critical(message)
+ _logger.critical(message)
self.__close_ports()
self._communicator.shutdown()
self._deregister()
diff --git a/libmuscle/python/libmuscle/logging.py b/libmuscle/python/libmuscle/logging.py
index 917b0347..e40a6635 100644
--- a/libmuscle/python/libmuscle/logging.py
+++ b/libmuscle/python/libmuscle/logging.py
@@ -1,13 +1,9 @@
-import datetime
from enum import Enum
import logging
from typing import Dict
-from typing_extensions import NewType
-from ymmsl import Operator
import muscle_manager_protocol.muscle_manager_protocol_pb2 as mmp
-from libmuscle.operator import operator_to_grpc
from libmuscle.timestamp import Timestamp
diff --git a/libmuscle/python/libmuscle/manager/instance_registry.py b/libmuscle/python/libmuscle/manager/instance_registry.py
index d1d265fb..4cd9e47d 100644
--- a/libmuscle/python/libmuscle/manager/instance_registry.py
+++ b/libmuscle/python/libmuscle/manager/instance_registry.py
@@ -1,7 +1,7 @@
from enum import Enum
from threading import Condition
from typing import Dict # noqa
-from typing import cast, List
+from typing import List
from ymmsl import Port, Reference
diff --git a/libmuscle/python/libmuscle/manager/logger.py b/libmuscle/python/libmuscle/manager/logger.py
index 3e2d6056..b91f321f 100644
--- a/libmuscle/python/libmuscle/manager/logger.py
+++ b/libmuscle/python/libmuscle/manager/logger.py
@@ -1,7 +1,6 @@
import logging
from libmuscle.logging import LogLevel, Timestamp
-from libmuscle.operator import Operator
from libmuscle.util import extract_log_file_location
@@ -30,9 +29,8 @@ def __init__(self) -> None:
logging.getLogger().addHandler(self._local_handler)
# hardwired for now
- logging.getLogger().setLevel(logging.INFO)
- logging.getLogger('yatiml.loader').setLevel(logging.WARNING)
- logging.getLogger('yatiml.dumper').setLevel(logging.WARNING)
+ logging.getLogger('instances').setLevel(1)
+ logging.getLogger('yatiml').setLevel(logging.WARNING)
def close(self) -> None:
logging.getLogger().removeHandler(self._local_handler)
@@ -53,7 +51,7 @@ def log_message(
level: The log level of the message.
text: The message text.
"""
- logger = logging.getLogger(instance_id)
+ logger = logging.getLogger('instances.{}'.format(instance_id))
logger.log(
level.as_python_level(),
text,
diff --git a/libmuscle/python/libmuscle/manager/mmp_server.py b/libmuscle/python/libmuscle/manager/mmp_server.py
index fe65f7a6..14e9775f 100644
--- a/libmuscle/python/libmuscle/manager/mmp_server.py
+++ b/libmuscle/python/libmuscle/manager/mmp_server.py
@@ -1,5 +1,4 @@
from concurrent import futures
-import logging
import time
import socket
from typing import cast, Generator, List
@@ -12,7 +11,6 @@
from libmuscle.manager.instance_registry import InstanceRegistry
from libmuscle.manager.logger import Logger
from libmuscle.manager.topology_store import TopologyStore
-from libmuscle.operator import operator_from_grpc
from libmuscle.util import (conduit_to_grpc, generate_indices,
instance_indices, instance_to_kernel)
@@ -136,7 +134,7 @@ def RegisterInstance(
self.__log(LogLevel.INFO, 'Registered instance {}'.format(
request.instance_name))
return mmp.RegistrationResult(status=mmp.RESULT_STATUS_SUCCESS)
- except ValueError as e:
+ except ValueError:
return mmp.RegistrationResult(
status=mmp.RESULT_STATUS_ERROR,
error_message=('An instance with name {} was already'
@@ -197,7 +195,7 @@ def DeregisterInstance(self, request: mmp.DeregistrationRequest,
self.__log(LogLevel.INFO, 'Deregistered instance {}'.format(
request.instance_name))
return mmp.DeregistrationResult(status=mmp.RESULT_STATUS_SUCCESS)
- except ValueError as e:
+ except ValueError:
return mmp.DeregistrationResult(
status=mmp.RESULT_STATUS_ERROR,
error_message=('No instance with name {} was registered'
diff --git a/libmuscle/python/libmuscle/manager/test/conftest.py b/libmuscle/python/libmuscle/manager/test/conftest.py
index 2b0900e1..8d05a800 100644
--- a/libmuscle/python/libmuscle/manager/test/conftest.py
+++ b/libmuscle/python/libmuscle/manager/test/conftest.py
@@ -1,6 +1,6 @@
import pytest
-from ymmsl import (ComputeElement, Conduit, Configuration, Identifier, Model,
- Reference, Settings)
+from ymmsl import (ComputeElement, Conduit, Configuration, Model, Reference,
+ Settings)
from libmuscle.manager.instance_registry import InstanceRegistry
from libmuscle.manager.logger import Logger
diff --git a/libmuscle/python/libmuscle/manager/test/test_logger.py b/libmuscle/python/libmuscle/manager/test/test_logger.py
index e734df0f..01f1166b 100644
--- a/libmuscle/python/libmuscle/manager/test/test_logger.py
+++ b/libmuscle/python/libmuscle/manager/test/test_logger.py
@@ -1,7 +1,6 @@
import logging
from libmuscle.logging import LogLevel, Timestamp
-from libmuscle.operator import Operator
from libmuscle.manager.logger import Logger
@@ -17,10 +16,10 @@ def test_create_logger():
def test_log_message(logger, caplog):
logger.log_message(
- 'test_log_message', Timestamp(123.0),
+ 'test_instance', Timestamp(123.0),
LogLevel.CRITICAL, 'Testing the logging system')
- assert caplog.records[0].name == 'test_log_message'
+ assert caplog.records[0].name == 'instances.test_instance'
assert caplog.records[0].time_stamp == '1970-01-01T00:02:03Z'
assert caplog.records[0].levelname == 'CRITICAL'
assert caplog.records[0].message == 'Testing the logging system'
diff --git a/libmuscle/python/libmuscle/manager/test/test_mmp_servicer.py b/libmuscle/python/libmuscle/manager/test/test_mmp_servicer.py
index 9c1854cb..091914ae 100644
--- a/libmuscle/python/libmuscle/manager/test/test_mmp_servicer.py
+++ b/libmuscle/python/libmuscle/manager/test/test_mmp_servicer.py
@@ -1,5 +1,5 @@
from google.protobuf.timestamp_pb2 import Timestamp
-from ymmsl import Operator, Reference
+from ymmsl import Operator
from libmuscle.manager.mmp_server import MMPServicer
import muscle_manager_protocol.muscle_manager_protocol_pb2 as mmp
@@ -20,7 +20,7 @@ def test_log_message(mmp_servicer, caplog):
text='Testing log message')
result = mmp_servicer.SubmitLogMessage(message, None)
assert isinstance(result, mmp.LogResult)
- assert caplog.records[0].name == 'test_instance_id'
+ assert caplog.records[0].name == 'instances.test_instance_id'
assert caplog.records[0].time_stamp == '1970-01-01T00:00:00Z'
assert caplog.records[0].levelname == 'WARNING'
assert caplog.records[0].message == (
diff --git a/libmuscle/python/libmuscle/mcp/pipe_multiplexer.py b/libmuscle/python/libmuscle/mcp/pipe_multiplexer.py
index 36b059b9..79e6b94a 100644
--- a/libmuscle/python/libmuscle/mcp/pipe_multiplexer.py
+++ b/libmuscle/python/libmuscle/mcp/pipe_multiplexer.py
@@ -3,7 +3,7 @@
# The below line seems to help avoid crashes, something to do with
# a background thread in the library and forking threaded processes.
from multiprocessing import resource_sharer # type: ignore
-from typing import Dict, List, Tuple
+from typing import Dict, List
import uuid
from ymmsl import Reference
diff --git a/libmuscle/python/libmuscle/mcp/server.py b/libmuscle/python/libmuscle/mcp/server.py
index 68060e11..6ee98af1 100644
--- a/libmuscle/python/libmuscle/mcp/server.py
+++ b/libmuscle/python/libmuscle/mcp/server.py
@@ -1,5 +1,3 @@
-from typing import Dict
-
from ymmsl import Reference
from libmuscle.post_office import PostOffice
diff --git a/libmuscle/python/libmuscle/mcp/tcp_client.py b/libmuscle/python/libmuscle/mcp/tcp_client.py
index db38290c..7c535c56 100644
--- a/libmuscle/python/libmuscle/mcp/tcp_client.py
+++ b/libmuscle/python/libmuscle/mcp/tcp_client.py
@@ -1,6 +1,5 @@
import socket
-import msgpack
from typing import Optional
from ymmsl import Reference
diff --git a/libmuscle/python/libmuscle/mcp/tcp_server.py b/libmuscle/python/libmuscle/mcp/tcp_server.py
index 6e8aeae2..5385ce48 100644
--- a/libmuscle/python/libmuscle/mcp/tcp_server.py
+++ b/libmuscle/python/libmuscle/mcp/tcp_server.py
@@ -3,7 +3,6 @@
from typing import cast, List, Optional, Tuple
from typing_extensions import Type
-import msgpack
import netifaces
from ymmsl import Reference
diff --git a/libmuscle/python/libmuscle/mcp/test/test_direct_communication.py b/libmuscle/python/libmuscle/mcp/test/test_direct_communication.py
index f8f3bfe8..b2fe60d2 100644
--- a/libmuscle/python/libmuscle/mcp/test/test_direct_communication.py
+++ b/libmuscle/python/libmuscle/mcp/test/test_direct_communication.py
@@ -1,7 +1,3 @@
-from unittest.mock import patch
-from typing import Dict
-
-import pytest
from ymmsl import Reference
from libmuscle.mcp.direct_client import DirectClient
diff --git a/libmuscle/python/libmuscle/mcp/test/test_direct_server.py b/libmuscle/python/libmuscle/mcp/test/test_direct_server.py
index 103fe3e5..ea9f9b7d 100644
--- a/libmuscle/python/libmuscle/mcp/test/test_direct_server.py
+++ b/libmuscle/python/libmuscle/mcp/test/test_direct_server.py
@@ -1,11 +1,6 @@
-from typing import Dict
-
-import pytest
from ymmsl import Reference
-from libmuscle.outbox import Outbox
-from libmuscle.post_office import PostOffice
-from libmuscle.mcp.direct_server import DirectServer, registered_servers
+from libmuscle.mcp.direct_server import registered_servers
from libmuscle.mcp.message import Message
diff --git a/libmuscle/python/libmuscle/mcp/test/test_pipe_communication.py b/libmuscle/python/libmuscle/mcp/test/test_pipe_communication.py
index 3992e4c5..cf725b2a 100644
--- a/libmuscle/python/libmuscle/mcp/test/test_pipe_communication.py
+++ b/libmuscle/python/libmuscle/mcp/test/test_pipe_communication.py
@@ -2,8 +2,6 @@
import time
from ymmsl import Reference
-import pytest
-
from libmuscle.mcp.pipe_client import PipeClient
from libmuscle.mcp.pipe_server import PipeServer
import libmuscle.mcp.pipe_multiplexer as mux
diff --git a/libmuscle/python/libmuscle/mcp/test/test_tcp_communication.py b/libmuscle/python/libmuscle/mcp/test/test_tcp_communication.py
index 8c3f84ea..0d4c5b3e 100644
--- a/libmuscle/python/libmuscle/mcp/test/test_tcp_communication.py
+++ b/libmuscle/python/libmuscle/mcp/test/test_tcp_communication.py
@@ -1,11 +1,7 @@
-import time
from ymmsl import Reference
-import pytest
-
from libmuscle.mcp.tcp_client import TcpClient
from libmuscle.mcp.tcp_server import TcpServer
-from libmuscle.mcp.message import Message
def test_send_receive(receiver, post_office):
diff --git a/libmuscle/python/libmuscle/mcp/test/test_tcp_server.py b/libmuscle/python/libmuscle/mcp/test/test_tcp_server.py
index 1c063a42..274eebd2 100644
--- a/libmuscle/python/libmuscle/mcp/test/test_tcp_server.py
+++ b/libmuscle/python/libmuscle/mcp/test/test_tcp_server.py
@@ -1,14 +1,7 @@
import socket
-from typing import Dict
-import msgpack
-import pytest
from ymmsl import Reference
-from libmuscle.outbox import Outbox
-from libmuscle.post_office import PostOffice
-from libmuscle.mcp.message import Message
-
def test_create(tcp_server):
assert tcp_server._instance_id == Reference('test_sender')
diff --git a/libmuscle/python/libmuscle/outbox.py b/libmuscle/python/libmuscle/outbox.py
index 042a7a6f..26190b02 100644
--- a/libmuscle/python/libmuscle/outbox.py
+++ b/libmuscle/python/libmuscle/outbox.py
@@ -1,7 +1,4 @@
from queue import Queue
-from typing import List
-
-from ymmsl import Reference
class Outbox:
diff --git a/libmuscle/python/libmuscle/port.py b/libmuscle/python/libmuscle/port.py
index c826d3ea..d15364aa 100644
--- a/libmuscle/python/libmuscle/port.py
+++ b/libmuscle/python/libmuscle/port.py
@@ -1,5 +1,5 @@
from typing import List, Optional
-from ymmsl import Identifier, Operator, Reference
+from ymmsl import Identifier, Operator
import ymmsl
from libmuscle.operator import operator_from_grpc, operator_to_grpc
diff --git a/libmuscle/python/libmuscle/profiler.py b/libmuscle/python/libmuscle/profiler.py
index aa2713ea..04ab390b 100644
--- a/libmuscle/python/libmuscle/profiler.py
+++ b/libmuscle/python/libmuscle/profiler.py
@@ -3,7 +3,6 @@
from ymmsl import Port, Reference
-import muscle_manager_protocol.muscle_manager_protocol_pb2 as mmp
from libmuscle.mmp_client import MMPClient
from libmuscle.profiling import ProfileEvent, ProfileEventType
from libmuscle.timestamp import Timestamp
@@ -23,9 +22,9 @@ def __init__(self, instance_id: Reference, manager: MMPClient) -> None:
self._manager = manager
self._events = list() # type: List[ProfileEvent]
- def start(self, event_type: ProfileEventType, port: Optional[Port]=None,
- port_length: Optional[int]=None, slot: Optional[int]=None,
- message_size: Optional[int]=None
+ def start(self, event_type: ProfileEventType, port: Optional[Port] = None,
+ port_length: Optional[int] = None, slot: Optional[int] = None,
+ message_size: Optional[int] = None
) -> ProfileEvent:
"""Start measuring an event.
diff --git a/libmuscle/python/libmuscle/profiling.py b/libmuscle/python/libmuscle/profiling.py
index a459e312..f535d5aa 100644
--- a/libmuscle/python/libmuscle/profiling.py
+++ b/libmuscle/python/libmuscle/profiling.py
@@ -1,12 +1,10 @@
-import datetime
from enum import Enum
import time
-from typing import Dict, List, Optional
+from typing import Dict, Optional
import muscle_manager_protocol.muscle_manager_protocol_pb2 as mmp
from ymmsl import Port, Reference
-from libmuscle.operator import operator_to_grpc
from libmuscle.port import optional_port_to_grpc
from libmuscle.timestamp import Timestamp
@@ -98,10 +96,10 @@ def __init__(
start_time: Timestamp,
stop_time: Timestamp,
event_type: ProfileEventType,
- port: Optional[Port]=None,
- port_length: Optional[int]=None,
- slot: Optional[int]=None,
- message_size: Optional[int]=None
+ port: Optional[Port] = None,
+ port_length: Optional[int] = None,
+ slot: Optional[int] = None,
+ message_size: Optional[int] = None
) -> None:
self.instance_id = instance_id
diff --git a/libmuscle/python/libmuscle/test/test_communicator.py b/libmuscle/python/libmuscle/test/test_communicator.py
index 8723a311..5e939629 100644
--- a/libmuscle/python/libmuscle/test/test_communicator.py
+++ b/libmuscle/python/libmuscle/test/test_communicator.py
@@ -6,7 +6,6 @@
from ymmsl import Conduit, Identifier, Operator, Reference, Settings
-import msgpack
import pytest
from unittest.mock import patch, MagicMock
diff --git a/libmuscle/python/libmuscle/test/test_grid.py b/libmuscle/python/libmuscle/test/test_grid.py
index 0db64741..a24462e3 100644
--- a/libmuscle/python/libmuscle/test/test_grid.py
+++ b/libmuscle/python/libmuscle/test/test_grid.py
@@ -6,11 +6,11 @@
def test_grid() -> None:
a = np.array([[1, 2, 3], [4, 5, 6]])
- grid = Grid(a)
- grid = Grid(a, ['x', 'y'])
+ _ = Grid(a)
+ _ = Grid(a, ['x', 'y'])
with pytest.raises(ValueError):
- grid = Grid(a, ['x'])
+ _ = Grid(a, ['x'])
with pytest.raises(ValueError):
- grid = Grid(a, ['x', 'y', 'z'])
+ _ = Grid(a, ['x', 'y', 'z'])
diff --git a/libmuscle/python/libmuscle/test/test_instance.py b/libmuscle/python/libmuscle/test/test_instance.py
index d00c2fa5..1949cb9c 100644
--- a/libmuscle/python/libmuscle/test/test_instance.py
+++ b/libmuscle/python/libmuscle/test/test_instance.py
@@ -1,9 +1,9 @@
import sys
-from typing import Generator, List
+from typing import Generator
from unittest.mock import MagicMock, patch
import pytest
-from ymmsl import Conduit, Operator, Reference, Settings
+from ymmsl import Operator, Reference, Settings
from libmuscle.communicator import Message
from libmuscle.instance import Instance
@@ -61,7 +61,7 @@ def instance(sys_argv_instance):
@pytest.fixture
def instance2(sys_argv_instance):
with patch('libmuscle.instance.MMPClient') as mmp_client, \
- patch('libmuscle.instance.Communicator') as comm_type:
+ patch('libmuscle.instance.Communicator'):
mmp_client_object = MagicMock()
mmp_client_object.request_peers.return_value = (None, None, None)
mmp_client.return_value = mmp_client_object
diff --git a/libmuscle/python/libmuscle/test/test_mmp_client.py b/libmuscle/python/libmuscle/test/test_mmp_client.py
index 66516767..ee627b36 100644
--- a/libmuscle/python/libmuscle/test/test_mmp_client.py
+++ b/libmuscle/python/libmuscle/test/test_mmp_client.py
@@ -1,4 +1,4 @@
-from unittest.mock import MagicMock, patch
+from unittest.mock import patch
import pytest
from ymmsl import Conduit, Port, Reference
diff --git a/scripts/api_generator.py b/scripts/api_generator.py
index 8a7ffc11..2823c4fc 100644
--- a/scripts/api_generator.py
+++ b/scripts/api_generator.py
@@ -2,7 +2,7 @@
from copy import copy
import textwrap
-from typing import Callable, Dict, List, Optional, Tuple, Union
+from typing import Dict, List, Optional, Tuple, Union
error_codes = {
@@ -129,7 +129,7 @@ def fc_return(self) -> str:
def f_call_c(self, result_name: str, call: str) -> str:
return ' call {}\n'.format(call)
- def f_return_result(self, result_name: str, call: str) -> str:
+ def f_return_result(self, return_name: str, result_name: str) -> str:
return ''
@@ -233,7 +233,7 @@ def f_return_result(self, return_name: str, result_name: str) -> str:
def fi_type(self) -> str:
return self._regular_type(
- ['real (c_double), dimension(*)'.format(self.ns_prefix),
+ ['real (c_double), dimension(*)',
('integer (c_size_t), value', '_size')])
def fi_ret_type(self) -> str:
@@ -386,7 +386,7 @@ def f_return_result(self, return_name: str, result_name: str) -> str:
def fi_type(self) -> str:
return self._regular_type(
- ['integer (c_size_t), dimension(*)'.format(self.ns_prefix),
+ ['integer (c_size_t), dimension(*)',
('integer (c_size_t), value', '_size')])
def fi_ret_type(self) -> str:
@@ -429,7 +429,7 @@ def __init__(
name: Name of the parameter.
"""
if name is None:
- name = self.elem_type.name
+ name = elem_type.name
self.elem_type = elem_type
else:
self.elem_type = copy(elem_type)
@@ -1524,8 +1524,11 @@ class Constructor(MemFun):
This generates code suitable for a constructor, rather than
the default code.
"""
- def __init__(self, params: List[Par] = list(), name: str = 'create', **args
- ) -> None:
+ def __init__(
+ self, params: Optional[List[Par]] = None, name: str = 'create',
+ **args) -> None:
+ if params is None:
+ params = list()
super().__init__(Obj(''), name, params, **args)
def __copy__(self) -> 'Constructor':
diff --git a/scripts/make_libmuscle_api.py b/scripts/make_libmuscle_api.py
index cd7fd427..33a17a52 100755
--- a/scripts/make_libmuscle_api.py
+++ b/scripts/make_libmuscle_api.py
@@ -5,8 +5,6 @@
from textwrap import indent
from typing import Dict, List, Optional
-import api_generator
-
from api_generator import (
API, Array, AssignmentOperator, Bool, Bytes, Char, Class, Constructor,
Destructor, Double, Enum, EnumVal, Float, IndexAssignmentOperator, Int,
@@ -33,7 +31,7 @@ def __init__(self, with_names: bool) -> None:
This creates a set of named constructors, one for each
combination of five element types and seven dimensions. If
- with_types is True, every instance has n additional string
+ with_names is True, every instance has n additional string
arguments for index names, where n is the number of dimensions
of the array it accepts.
@@ -55,7 +53,6 @@ def __init__(self, with_names: bool) -> None:
typ.name = 'data_array'
typ.set_ns_prefix({}, 'LIBMUSCLE')
- instance_ret_type = Obj('')
instance_params = [Array(1, copy(typ), 'data_array')]
if not with_names:
instance_name = 'grid_{}_a'.format(typ.tname())
@@ -115,7 +112,6 @@ def __init__(self, with_names: bool) -> None:
# generate instances
for typ in self.types:
for ndims in range(1, 8):
- instance_ret_type = Obj('')
instance_params = [Array(ndims, copy(typ), 'data_array')]
if with_names:
for i in range(1, ndims+1):
diff --git a/scripts/make_ymmsl_api.py b/scripts/make_ymmsl_api.py
index 07d50df4..656f17d6 100755
--- a/scripts/make_ymmsl_api.py
+++ b/scripts/make_ymmsl_api.py
@@ -3,15 +3,12 @@
import argparse
from textwrap import indent
-import api_generator
-
from api_generator import (
API, AssignmentOperator, Bool, Bytes, Char, Class, Constructor,
Destructor, Double, Enum, EnumVal, EqualsOperator, Float,
IndexAssignmentOperator, Int, Int16t, Int32t, Int64t, MemFun,
MemFunTmpl, NamedConstructor, Namespace, Obj, OverloadSet,
- ShiftedIndexAssignmentOperator, Sizet, String, T, VecDbl, Vec2Dbl,
- Void)
+ Sizet, String, T, VecDbl, Vec2Dbl, Void)
# These need to kept in sync with the values in the C++ implementation
@@ -32,21 +29,22 @@
MemFun(Sizet('size'), 'size'),
MemFun(Bool('empty'), 'empty'),
MemFunTmpl(
- [String(), Int64t(), Double(), Bool(), VecDbl(), Vec2Dbl()],
+ [String(), Int32t(), Int64t(), Double(), Bool(), VecDbl(), Vec2Dbl()],
Bool(), 'is_a', [String('key')], True,
cpp_chain_call=lambda **kwargs: 'self_p->at({}).is_a<{}>()'.format(
kwargs['cpp_args'], kwargs['tpl_type'])),
IndexAssignmentOperator('set_character', [String('key'), String('value')]),
+ IndexAssignmentOperator('set_int4', [String('key'), Int32t('value')]),
IndexAssignmentOperator('set_int8', [String('key'), Int64t('value')]),
IndexAssignmentOperator('set_real8', [String('key'), Double('value')]),
IndexAssignmentOperator('set_logical', [String('key'), Bool('value')]),
IndexAssignmentOperator('set_real8array', [String('key'), VecDbl('value')]),
IndexAssignmentOperator('set_real8array2', [String('key'), Vec2Dbl('value')]),
OverloadSet('set', [
- 'set_character', 'set_int8', 'set_real8', 'set_logical',
+ 'set_character', 'set_int4', 'set_int8', 'set_real8', 'set_logical',
'set_real8array', 'set_real8array2']),
MemFunTmpl(
- [String(), Int64t(), Double(), Bool(), VecDbl('value'),
+ [String(), Int32t(), Int64t(), Double(), Bool(), VecDbl('value'),
Vec2Dbl('value')
],
T(), 'get_as', [String('key')], True,
diff --git a/scripts/tests/cmdlineargs.hpp b/scripts/tests/cmdlineargs.hpp
index b63ab0f5..15f6e839 100644
--- a/scripts/tests/cmdlineargs.hpp
+++ b/scripts/tests/cmdlineargs.hpp
@@ -9,7 +9,7 @@ namespace echolib { namespace impl {
// Simple helper class for passing command line args from Fortran to C++.
class CmdLineArgs {
public:
- CmdLineArgs(int count);
+ explicit CmdLineArgs(int count);
void set_arg(int i, std::string const & arg);
diff --git a/scripts/tests/make_echolib_api.py b/scripts/tests/make_echolib_api.py
index e1ee22fa..1db884e2 100755
--- a/scripts/tests/make_echolib_api.py
+++ b/scripts/tests/make_echolib_api.py
@@ -2,8 +2,6 @@
import argparse
-import api_generator
-
from api_generator import (
API, Bool, Bytes, Class, Constructor, Destructor, Double, Enum,
EnumVal, Int, Int64t, MemFun, MemFunTmpl, Namespace, Obj, OverloadSet,
diff --git a/setup.cfg b/setup.cfg
index 637e67b4..4742cd5b 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -4,8 +4,8 @@ test = pytest
[tool:pytest]
testpaths = muscle_manager libmuscle/python integration_test
-addopts = --mypy --pep8 --cov --cov-report xml --cov-report term-missing
-pep8ignore =
+addopts = --mypy --flake8 --cov --cov-report xml --cov-report term-missing -x
+flake8-ignore =
setup.py E501
muscle_manager/protocol/*.py ALL
libmuscle/manager_protocol/*.py ALL
diff --git a/setup.py b/setup.py
index 156f2d13..4c771b49 100644
--- a/setup.py
+++ b/setup.py
@@ -30,7 +30,9 @@
'License :: OSI Approved :: Apache Software License',
'Operating System :: POSIX :: Linux',
'Programming Language :: Python :: 3.5',
- 'Programming Language :: Python :: 3.6'],
+ 'Programming Language :: Python :: 3.6',
+ 'Programming Language :: Python :: 3.7',
+ 'Programming Language :: Python :: 3.8'],
# packages=['muscle_manager', 'muscle_manager_protocol', 'libmuscle', 'libmuscle.mcp'],
packages=_muscle3_packages,
@@ -48,7 +50,7 @@
'msgpack',
'netifaces',
'numpy>=1.12',
- 'protobuf>=3.10.0',
+ 'protobuf>=3.10.0, <4',
'typing_extensions',
'ymmsl==0.10.1' # Also in CI, update there as well
],
@@ -56,7 +58,9 @@
'pytest-runner',
# dependencies for `python setup.py build_sphinx`
'breathe',
- 'sphinx',
+ 'sphinx<3.2',
+ 'sphinx_rtd_theme',
+ 'sphinx-fortran',
'recommonmark',
'sphinx-rtd-theme'
],
@@ -65,7 +69,6 @@
'mypy',
'pytest>=3.5',
'pytest-cov',
- 'pytest-pep8',
'pytest-flake8',
'pytest-mypy'
],
@@ -73,7 +76,7 @@
'dev': [
'grpcio-tools==1.17.1',
'mypy-protobuf',
- 'sphinx',
+ 'sphinx<3.2',
'sphinx_rtd_theme',
'sphinx-fortran',
'yapf',