diff --git a/bin/martinize2 b/bin/martinize2
index 3b810f8..a27bc9b 100755
--- a/bin/martinize2
+++ b/bin/martinize2
@@ -426,6 +426,10 @@ def entry():
         write_canon=args.write_canon,
     )
 
+    LOGGER.info('Read input.', type='step')
+    for molecule in system.molecules:
+        LOGGER.debug("Read molecule {}.", molecule, type='step')
+
     target_ff = known_force_fields[args.to_ff]
     if args.dssp is not None:
         AnnotateDSSP(executable=args.dssp, savedir='.').run_system(system)
@@ -531,6 +535,9 @@ def entry():
         defines = ()
 
     LOGGER.info('Writing output.', type='step')
+    for molecule in system.molecules:
+        LOGGER.debug("Writing molecule {}.", molecule, type='step')
+
     # Write the topology if requested
     header = [
         'This file was generated using the following command:',
diff --git a/vermouth/molecule.py b/vermouth/molecule.py
index a9c6cfc..79052a1 100644
--- a/vermouth/molecule.py
+++ b/vermouth/molecule.py
@@ -352,6 +352,42 @@ class Molecule(nx.Graph):
             and self.same_interactions(other)
         )
 
+    @staticmethod
+    def _sort_interactions(all_interactions):
+        """
+        Returns keys in interactions sorted by (number_of_atoms, name). Keys
+        with no interactions are skipped.
+        """
+        sort_keys = {}
+        for interaction_type, interactions in all_interactions.items():
+            if not interactions:
+                continue
+            sort_keys[interaction_type] = len(interactions[0].atoms), interaction_type
+        return sorted(sort_keys, key=lambda k: sort_keys[k])
+
+    def __str__(self):
+        moltype = self.meta.get('moltype', 'molecule')
+
+        interaction_count = OrderedDict()
+        # Make sure atoms and edges get sorted first.
+        interaction_count['atoms'] = len(self.nodes)
+        if len(self.interactions.get('bonds', [])) != len(self.edges):
+            interaction_count['edges'] = len(self.edges)
+
+        for itype in self._sort_interactions(self.interactions):
+            interaction_count[itype] = len(self.interactions[itype])
+
+        # interaction_count will always contain at least 'atoms'.
+        last_item = interaction_count.popitem(last=True)
+        out = "{} with ".format(moltype)
+        out += ', '.join('{} {}'.format(number, itype)
+                         for itype, number in interaction_count.items())
+        if interaction_count:
+            out += ', and '
+        out += '{} {}'.format(last_item[1],
+                              last_item[0])
+        return out
+
     @property
     def force_field(self):
         """

Printing Molecule does not display anything
`print(Molecule())` does not display anything.
diff --git a/vermouth/tests/test_molecule.py b/vermouth/tests/test_molecule.py
index 3b1a573..af2f1cd 100644
--- a/vermouth/tests/test_molecule.py
+++ b/vermouth/tests/test_molecule.py
@@ -1179,3 +1179,66 @@ def test_same_non_edges(left, right, expected):
     link_right.non_edges = right
     assert link_left.same_non_edges(link_right) == expected
     assert link_right.same_non_edges(link_left) == expected
+
+
+
+@pytest.mark.parametrize('interactions, expected', (
+    (
+        {},
+        []
+    ),
+    (
+        {'bonds': []},
+        []
+    ),
+    (
+        {'bonds': [Interaction(atoms=(1, 2), parameters=[], meta=[])]},
+        ['bonds']
+    ),
+    (
+        {'bonds': [Interaction(atoms=(1, 2), parameters=[], meta=[])],
+         'angles': []},
+        ['bonds']
+    ),
+    (
+        {'bonds': [Interaction(atoms=(1, 2), parameters=[], meta=[])],
+         'angles': [Interaction(atoms=(1, 2, 3), parameters=[], meta=[])]},
+        ['bonds', 'angles']
+    ),
+    (
+        {'angles': [Interaction(atoms=(1, 2, 3), parameters=[], meta=[])],
+         'bonds': [Interaction(atoms=(1, 2), parameters=[], meta=[])],},
+        ['bonds', 'angles']
+    ),
+    (
+        {'angles': [Interaction(atoms=(1, 2, 3), parameters=[], meta=[])],
+         'a_bonds': [Interaction(atoms=(10, 2), parameters=[], meta=[])],
+         'bonds': [Interaction(atoms=(1, 2), parameters=[], meta=[])],},
+        ['a_bonds', 'bonds', 'angles']
+    ),
+))
+def test_interaction_sort(interactions, expected):
+    """
+    Test the order produced by Molecule._sort_interactions.
+    """
+    assert vermouth.molecule.Molecule._sort_interactions(interactions) == expected
+
+
+@hypothesis.given(moltype=st.one_of(st.none(), st.text()), mol=random_molecule())
+def test_str_method(mol, moltype):
+    """
+    Test Molecule.__str__
+    """
+    if moltype is not None:
+        mol.meta['moltype'] = moltype
+    else: 
+        moltype = 'molecule'
+    found = str(mol)
+    assert '{} with '.format(moltype) in found
+    assert '{} {}'.format(len(mol), 'atoms') in found
+    hypothesis.assume('' not in mol.interactions)
+    for itype, interactions in mol.interactions.items():
+        if interactions:
+            assert '{} {}'.format(len(interactions), itype) in found
+        else:
+            assert '{} {}'.format(0, itype) not in found

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest coverage pytest-cov pylint hypothesis hypothesis-networkx codecov
apt-get update apt-get install -y gcc
3.9
requirements-docs.txt requirements-tests.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.16
astroid==3.3.9
attrs==25.3.0
babel==2.17.0
certifi==2025.1.31
charset-normalizer==3.4.1
codecov==2.1.13
coverage==7.8.0
dill==0.3.9
docutils==0.21.2
exceptiongroup==1.2.2
hypothesis==6.130.5
hypothesis-networkx==0.3.0
idna==3.10
imagesize==1.4.1
importlib_metadata==8.6.1
iniconfig==2.1.0
isort==6.0.1
Jinja2==3.1.6
MarkupSafe==3.0.2
mccabe==0.7.0
networkx==2.8.8
numpy==2.0.2
packaging==24.2
pbr==6.1.1
platformdirs==4.3.7
pluggy==1.5.0
Pygments==2.19.1
pylint==3.3.6
pytest==8.3.5
pytest-cov==6.0.0
requests==2.32.3
scipy==1.13.1
snowballstemmer==2.2.0
sortedcontainers==2.4.0
Sphinx==7.4.7
sphinxcontrib-apidoc==0.5.0
sphinxcontrib-applehelp==2.0.0
sphinxcontrib-devhelp==2.0.0
sphinxcontrib-htmlhelp==2.1.0
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==2.0.0
sphinxcontrib-serializinghtml==2.0.0
tomli==2.2.1
tomlkit==0.13.2
typing_extensions==4.13.0
urllib3==2.3.0
-e git+https://github.com/marrink-lab/vermouth-martinize.git@c935d675b567a21cea8099c1721a0a2a389cc143#egg=vermouth
zipp==3.21.0

name: vermouth-martinize
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.16
      - astroid==3.3.9
      - attrs==25.3.0
      - babel==2.17.0
      - certifi==2025.1.31
      - charset-normalizer==3.4.1
      - codecov==2.1.13
      - coverage==7.8.0
      - dill==0.3.9
      - docutils==0.21.2
      - exceptiongroup==1.2.2
      - hypothesis==6.130.5
      - hypothesis-networkx==0.3.0
      - idna==3.10
      - imagesize==1.4.1
      - importlib-metadata==8.6.1
      - iniconfig==2.1.0
      - isort==6.0.1
      - jinja2==3.1.6
      - markupsafe==3.0.2
      - mccabe==0.7.0
      - networkx==2.8.8
      - numpy==2.0.2
      - packaging==24.2
      - pbr==6.1.1
      - platformdirs==4.3.7
      - pluggy==1.5.0
      - pygments==2.19.1
      - pylint==3.3.6
      - pytest==8.3.5
      - pytest-cov==6.0.0
      - requests==2.32.3
      - scipy==1.13.1
      - snowballstemmer==2.2.0
      - sortedcontainers==2.4.0
      - sphinx==7.4.7
      - sphinxcontrib-apidoc==0.5.0
      - sphinxcontrib-applehelp==2.0.0
      - sphinxcontrib-devhelp==2.0.0
      - sphinxcontrib-htmlhelp==2.1.0
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-qthelp==2.0.0
      - sphinxcontrib-serializinghtml==2.0.0
      - tomli==2.2.1
      - tomlkit==0.13.2
      - typing-extensions==4.13.0
      - urllib3==2.3.0
      - vermouth==0.1.1.dev10
      - zipp==3.21.0
prefix: /opt/conda/envs/vermouth-martinize

vermouth/tests/test_molecule.py::test_interaction_sort[interactions0-expected0] vermouth/tests/test_molecule.py::test_interaction_sort[interactions1-expected1] vermouth/tests/test_molecule.py::test_interaction_sort[interactions2-expected2] vermouth/tests/test_molecule.py::test_interaction_sort[interactions3-expected3] vermouth/tests/test_molecule.py::test_interaction_sort[interactions4-expected4] vermouth/tests/test_molecule.py::test_interaction_sort[interactions5-expected5] vermouth/tests/test_molecule.py::test_interaction_sort[interactions6-expected6]
vermouth/tests/test_molecule.py::test_molecule_equal vermouth/tests/test_molecule.py::test_block_equal vermouth/tests/test_molecule.py::test_link_equal vermouth/tests/test_molecule.py::test_str_method
vermouth/tests/test_molecule.py::test_remove_nodes_from[atoms0-bonds0-interactions0-removed0-expected0] vermouth/tests/test_molecule.py::test_remove_nodes_from[atoms1-bonds1-interactions1-removed1-expected1] vermouth/tests/test_molecule.py::test_remove_nodes_from[atoms2-bonds2-interactions2-removed2-expected2] vermouth/tests/test_molecule.py::test_remove_nodes_from[atoms3-bonds3-interactions3-removed3-expected3] vermouth/tests/test_molecule.py::test_remove_nodes_from[atoms4-bonds4-interactions4-removed4-expected4] vermouth/tests/test_molecule.py::test_remove_nodes_from[atoms5-bonds5-interactions5-removed5-expected5] vermouth/tests/test_molecule.py::test_remove_nodes_from[atoms6-bonds6-interactions6-removed6-expected6] vermouth/tests/test_molecule.py::test_remove_nodes_from[atoms7-bonds7-interactions7-removed7-expected7] vermouth/tests/test_molecule.py::test_remove_node[atoms0-bonds0-interactions0-None-expected0] vermouth/tests/test_molecule.py::test_remove_node[atoms1-bonds1-interactions1-2-expected1] vermouth/tests/test_molecule.py::test_remove_node[atoms2-bonds2-interactions2-2-expected2] vermouth/tests/test_molecule.py::test_remove_node[atoms3-bonds3-interactions3-5-expected3] vermouth/tests/test_molecule.py::test_remove_node[atoms4-bonds4-interactions4-5-expected4] vermouth/tests/test_molecule.py::test_remove_node[atoms5-bonds5-interactions5-3-expected5] vermouth/tests/test_molecule.py::test_remove_node[atoms6-bonds6-interactions6-2-expected6] vermouth/tests/test_molecule.py::test_copy vermouth/tests/test_molecule.py::test_copy_meta_mod vermouth/tests/test_molecule.py::test_copy_node_mod vermouth/tests/test_molecule.py::test_copy_edge_mod vermouth/tests/test_molecule.py::test_copy_interactions_mod vermouth/tests/test_molecule.py::test_subgraph_base vermouth/tests/test_molecule.py::test_subgraph_interactions vermouth/tests/test_molecule.py::test_link_predicate_match vermouth/tests/test_molecule.py::test_edges_between[0-1-expected0-True] vermouth/tests/test_molecule.py::test_edges_between[0-1-expected0-False] vermouth/tests/test_molecule.py::test_edges_between[0-2-expected1-True] vermouth/tests/test_molecule.py::test_edges_between[0-2-expected1-False] vermouth/tests/test_molecule.py::test_edges_between[0-4-expected2-True] vermouth/tests/test_molecule.py::test_edges_between[0-4-expected2-False] vermouth/tests/test_molecule.py::test_edges_between[1-2-expected3-True] vermouth/tests/test_molecule.py::test_edges_between[1-2-expected3-False] vermouth/tests/test_molecule.py::test_edges_between[2-3-expected4-True] vermouth/tests/test_molecule.py::test_edges_between[2-3-expected4-False] vermouth/tests/test_molecule.py::test_edges_between[0-3-expected5-True] vermouth/tests/test_molecule.py::test_edges_between[0-3-expected5-False] vermouth/tests/test_molecule.py::test_edges_between[1-3-expected6-True] vermouth/tests/test_molecule.py::test_edges_between[1-3-expected6-False] vermouth/tests/test_molecule.py::test_edges_between[1-4-expected7-True] vermouth/tests/test_molecule.py::test_edges_between[1-4-expected7-False] vermouth/tests/test_molecule.py::test_edges_between[2-4-expected8-True] vermouth/tests/test_molecule.py::test_edges_between[2-4-expected8-False] vermouth/tests/test_molecule.py::test_subgraph_edges[0-expected0] vermouth/tests/test_molecule.py::test_subgraph_edges[1-expected1] vermouth/tests/test_molecule.py::test_subgraph_edges[2-expected2] vermouth/tests/test_molecule.py::test_subgraph_edges[3-expected3] vermouth/tests/test_molecule.py::test_subgraph_edges[4-expected4] vermouth/tests/test_molecule.py::test_same_interactions[left0-right0-True] vermouth/tests/test_molecule.py::test_same_interactions[left1-right1-False] vermouth/tests/test_molecule.py::test_same_interactions[left2-right2-False] vermouth/tests/test_molecule.py::test_same_interactions[left3-right3-False] vermouth/tests/test_molecule.py::test_same_interactions[left4-right4-True] vermouth/tests/test_molecule.py::test_same_interactions[left5-right5-False] vermouth/tests/test_molecule.py::test_same_interactions[left6-right6-False] vermouth/tests/test_molecule.py::test_same_interactions[left7-right7-False] vermouth/tests/test_molecule.py::test_same_interactions[left8-right8-False] vermouth/tests/test_molecule.py::test_same_interactions[left9-right9-True] vermouth/tests/test_molecule.py::test_same_nodes[left0-right0-True] vermouth/tests/test_molecule.py::test_same_nodes[left1-right1-False] vermouth/tests/test_molecule.py::test_same_nodes[left2-right2-False] vermouth/tests/test_molecule.py::test_same_nodes[left3-right3-False] vermouth/tests/test_molecule.py::test_same_nodes[left4-right4-False] vermouth/tests/test_molecule.py::test_same_nodes[left5-right5-True] vermouth/tests/test_molecule.py::test_same_nodes[left6-right6-False] vermouth/tests/test_molecule.py::test_same_nodes[left7-right7-False] vermouth/tests/test_molecule.py::test_same_nodes[left8-right8-False] vermouth/tests/test_molecule.py::test_same_nodes[left9-right9-False] vermouth/tests/test_molecule.py::test_same_nodes[left10-right10-True] vermouth/tests/test_molecule.py::test_same_nodes[left11-right11-False] vermouth/tests/test_molecule.py::test_link_parameter_effector_equal[None-ParamDistance] vermouth/tests/test_molecule.py::test_link_parameter_effector_equal[None-ParamAngle] vermouth/tests/test_molecule.py::test_link_parameter_effector_equal[None-ParamDihedral] vermouth/tests/test_molecule.py::test_link_parameter_effector_equal[None-ParamDihedralPhase] vermouth/tests/test_molecule.py::test_link_parameter_effector_equal[.2f-ParamDistance] vermouth/tests/test_molecule.py::test_link_parameter_effector_equal[.2f-ParamAngle] vermouth/tests/test_molecule.py::test_link_parameter_effector_equal[.2f-ParamDihedral] vermouth/tests/test_molecule.py::test_link_parameter_effector_equal[.2f-ParamDihedralPhase] vermouth/tests/test_molecule.py::test_link_parameter_effector_equal[0.3f-ParamDistance] vermouth/tests/test_molecule.py::test_link_parameter_effector_equal[0.3f-ParamAngle] vermouth/tests/test_molecule.py::test_link_parameter_effector_equal[0.3f-ParamDihedral] vermouth/tests/test_molecule.py::test_link_parameter_effector_equal[0.3f-ParamDihedralPhase] vermouth/tests/test_molecule.py::test_link_parameter_effector_diff_format[None-.2f-ParamDistance] vermouth/tests/test_molecule.py::test_link_parameter_effector_diff_format[None-.2f-ParamAngle] vermouth/tests/test_molecule.py::test_link_parameter_effector_diff_format[None-.2f-ParamDihedral] vermouth/tests/test_molecule.py::test_link_parameter_effector_diff_format[None-.2f-ParamDihedralPhase] vermouth/tests/test_molecule.py::test_link_parameter_effector_diff_format[None-0.3f-ParamDistance] vermouth/tests/test_molecule.py::test_link_parameter_effector_diff_format[None-0.3f-ParamAngle] vermouth/tests/test_molecule.py::test_link_parameter_effector_diff_format[None-0.3f-ParamDihedral] vermouth/tests/test_molecule.py::test_link_parameter_effector_diff_format[None-0.3f-ParamDihedralPhase] vermouth/tests/test_molecule.py::test_link_parameter_effector_diff_format[.2f-0.3f-ParamDistance] vermouth/tests/test_molecule.py::test_link_parameter_effector_diff_format[.2f-0.3f-ParamAngle] vermouth/tests/test_molecule.py::test_link_parameter_effector_diff_format[.2f-0.3f-ParamDihedral] vermouth/tests/test_molecule.py::test_link_parameter_effector_diff_format[.2f-0.3f-ParamDihedralPhase] vermouth/tests/test_molecule.py::test_link_parameter_effector_diff_keys[ParamDistance] vermouth/tests/test_molecule.py::test_link_parameter_effector_diff_keys[ParamAngle] vermouth/tests/test_molecule.py::test_link_parameter_effector_diff_keys[ParamDihedral] vermouth/tests/test_molecule.py::test_link_parameter_effector_diff_keys[ParamDihedralPhase] vermouth/tests/test_molecule.py::test_link_parameter_effector_diff_class[ParamDistance-ParamAngle] vermouth/tests/test_molecule.py::test_link_parameter_effector_diff_class[ParamDistance-ParamDihedral] vermouth/tests/test_molecule.py::test_link_parameter_effector_diff_class[ParamDistance-ParamDihedralPhase] vermouth/tests/test_molecule.py::test_link_parameter_effector_diff_class[ParamAngle-ParamDihedral] vermouth/tests/test_molecule.py::test_link_parameter_effector_diff_class[ParamAngle-ParamDihedralPhase] vermouth/tests/test_molecule.py::test_link_parameter_effector_diff_class[ParamDihedral-ParamDihedralPhase] vermouth/tests/test_molecule.py::test_same_edges[left0-right0-True] vermouth/tests/test_molecule.py::test_same_edges[left1-right1-True] vermouth/tests/test_molecule.py::test_same_edges[left2-right2-True] vermouth/tests/test_molecule.py::test_same_edges[left3-right3-False] vermouth/tests/test_molecule.py::test_same_edges[left4-right4-False] vermouth/tests/test_molecule.py::test_same_non_edges[left0-right0-True] vermouth/tests/test_molecule.py::test_same_non_edges[left1-right1-True] vermouth/tests/test_molecule.py::test_same_non_edges[left2-right2-False] vermouth/tests/test_molecule.py::test_same_non_edges[left3-right3-False] vermouth/tests/test_molecule.py::test_same_non_edges[left4-right4-False] vermouth/tests/test_molecule.py::test_same_non_edges[left5-right5-False] vermouth/tests/test_molecule.py::test_same_non_edges[left6-right6-False]
vermouth/molecule.py bin/martinize2
vermouth/molecule.py bin/martinize2