Repository: ResearchObject/ro-crate-py
Pull request #221 (2025-04-25 09:48:48)

Proposing add_formal_parameter function
Following yesterday's call, here is a small PR proposing the addition of a function to facilitate the definition of FormalParameters in a workflow crate.

It makes use of type hints, which is available from python 3.5, support could be added for earlier version by adding the [typing package](https://pypi.org/project/typing/) to the list of dependencies, checking the version of python to only install if needed.

I am happy to write tests and documentation for this function if you think that's a valid addition.
Currently it can be tested with 

```python
from rocrate.rocrate import ROCrate
from pprint import pprint

crate = ROCrate()
formal_parameter = crate.add_formal_parameter(identifier = "my_param",
                                              additionalType = "Text",
                                              name = "my_param",
                                              description = "",
                                              valueRequired = False,
                                              defaultValue = "")
pprint(formal_parameter.as_jsonld())
``` 

Actually for testing I typically install the package in editable mode like so
`pip install -e .`
but I got an exception that it's not possible

`DEPRECATION: Legacy editable install of rocrate==0.13.0 from file:///Users/thomasl/Documents/repos/ro-crate-py (setup.py develop) is deprecated. pip 25.1 will enforce this behaviour change. A possible replacement is to add a pyproject.toml or enable --use-pep517, and use setuptools >= 64. If the resulting installation is not behaving as expected, try using --config-settings editable_mode=compat. Please consult the setuptools documentation for more information. Discussion can be found at https://github.com/pypa/pip/issues/11457`

So I was wondering how you test it usually.
I also had issues with test discovery, but that's maybe something with my VScode config.

Cheers !


Patch:
diff --git a/.gitignore b/.gitignore
index 032df4b..32d67b1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -103,3 +103,7 @@ ENV/
 
 # vim 
 *.swp
+
+# other
+.DS_Store
+/.vscode
diff --git a/CITATION.cff b/CITATION.cff
index e2e64b2..b61307e 100644
--- a/CITATION.cff
+++ b/CITATION.cff
@@ -46,6 +46,10 @@ author:
   - family-names: Soiland-Reyes
     given-names: Stian
     orcid: https://orcid.org/0000-0001-9842-9718
+  - family-names: Thomas
+    given-names: Laurent
+    orcid: https://orcid.org/0000-0001-7686-3249
+   
 title: "ro-crate-py"
 version: 0.13.0
 doi: 10.5281/zenodo.3956493
diff --git a/README.md b/README.md
index 87feb62..c42645b 100644
--- a/README.md
+++ b/README.md
@@ -468,6 +468,7 @@ Options:
 * Copyright 2024-2025 Data Centre, SciLifeLab, SE
 * Copyright 2024-2025 National Institute of Informatics (NII), JP
 * Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+* Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 
 Licensed under the
 Apache License, version 2.0 <https://www.apache.org/licenses/LICENSE-2.0>,
diff --git a/examples/fastapi/main.py b/examples/fastapi/main.py
index cb57627..b3e0311 100644
--- a/examples/fastapi/main.py
+++ b/examples/fastapi/main.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..ad0679d
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,3 @@
+[build-system]
+requires = ["setuptools >= 64"]
+build-backend = "setuptools.build_meta"
diff --git a/rocrate/__init__.py b/rocrate/__init__.py
index 0af2084..e5a026c 100644
--- a/rocrate/__init__.py
+++ b/rocrate/__init__.py
@@ -8,6 +8,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -44,7 +45,8 @@ __author__ = ", ".join((
     'Luca Pireddu',
     'Laura Rodríguez-Navas',
     'Raül Sirvent',
-    'Stian Soiland-Reyes'
+    'Stian Soiland-Reyes',
+    'Laurent Thomas'
 ))
 __copyright__ = """\
 Copyright 2019-2025 The University of Manchester, UK
@@ -55,6 +57,7 @@ Copyright 2022-2025 École Polytechnique Fédérale de Lausanne, CH
 Copyright 2024-2025 Data Centre, SciLifeLab, SE
 Copyright 2024-2025 National Institute of Informatics (NII), JP
 Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 """
 __license__ = ("Apache License, version 2.0 "
                "<https://www.apache.org/licenses/LICENSE-2.0>")
diff --git a/rocrate/cli.py b/rocrate/cli.py
index 60f9404..8f5be57 100644
--- a/rocrate/cli.py
+++ b/rocrate/cli.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/rocrate/memory_buffer.py b/rocrate/memory_buffer.py
index aa5ba37..b811804 100644
--- a/rocrate/memory_buffer.py
+++ b/rocrate/memory_buffer.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/rocrate/metadata.py b/rocrate/metadata.py
index 17139d5..dd8a688 100644
--- a/rocrate/metadata.py
+++ b/rocrate/metadata.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/rocrate/model/__init__.py b/rocrate/model/__init__.py
index 554f054..ae42887 100644
--- a/rocrate/model/__init__.py
+++ b/rocrate/model/__init__.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/rocrate/model/computationalworkflow.py b/rocrate/model/computationalworkflow.py
index e48455b..bbe306f 100644
--- a/rocrate/model/computationalworkflow.py
+++ b/rocrate/model/computationalworkflow.py
@@ -8,6 +8,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/rocrate/model/computerlanguage.py b/rocrate/model/computerlanguage.py
index 3e91ea7..7faa498 100644
--- a/rocrate/model/computerlanguage.py
+++ b/rocrate/model/computerlanguage.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/rocrate/model/contextentity.py b/rocrate/model/contextentity.py
index 7355549..97ea0f4 100644
--- a/rocrate/model/contextentity.py
+++ b/rocrate/model/contextentity.py
@@ -8,6 +8,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/rocrate/model/creativework.py b/rocrate/model/creativework.py
index e20d9ee..317f9ef 100644
--- a/rocrate/model/creativework.py
+++ b/rocrate/model/creativework.py
@@ -8,6 +8,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/rocrate/model/data_entity.py b/rocrate/model/data_entity.py
index e74cb94..1b19aa0 100644
--- a/rocrate/model/data_entity.py
+++ b/rocrate/model/data_entity.py
@@ -8,6 +8,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/rocrate/model/dataset.py b/rocrate/model/dataset.py
index 2832607..457000d 100644
--- a/rocrate/model/dataset.py
+++ b/rocrate/model/dataset.py
@@ -8,6 +8,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/rocrate/model/entity.py b/rocrate/model/entity.py
index faa281b..9937b32 100644
--- a/rocrate/model/entity.py
+++ b/rocrate/model/entity.py
@@ -8,6 +8,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/rocrate/model/file.py b/rocrate/model/file.py
index 8ecfbc9..b3c3c06 100644
--- a/rocrate/model/file.py
+++ b/rocrate/model/file.py
@@ -8,6 +8,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/rocrate/model/file_or_dir.py b/rocrate/model/file_or_dir.py
index b7751d3..83eaf60 100644
--- a/rocrate/model/file_or_dir.py
+++ b/rocrate/model/file_or_dir.py
@@ -8,6 +8,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/rocrate/model/metadata.py b/rocrate/model/metadata.py
index ced0a16..9a7c63e 100644
--- a/rocrate/model/metadata.py
+++ b/rocrate/model/metadata.py
@@ -8,6 +8,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/rocrate/model/person.py b/rocrate/model/person.py
index ba59478..3a4376d 100644
--- a/rocrate/model/person.py
+++ b/rocrate/model/person.py
@@ -8,6 +8,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/rocrate/model/preview.py b/rocrate/model/preview.py
index e8dab67..e29927d 100644
--- a/rocrate/model/preview.py
+++ b/rocrate/model/preview.py
@@ -8,6 +8,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/rocrate/model/root_dataset.py b/rocrate/model/root_dataset.py
index b346af6..66394f9 100644
--- a/rocrate/model/root_dataset.py
+++ b/rocrate/model/root_dataset.py
@@ -8,6 +8,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/rocrate/model/softwareapplication.py b/rocrate/model/softwareapplication.py
index d54f3fe..a5f41a5 100644
--- a/rocrate/model/softwareapplication.py
+++ b/rocrate/model/softwareapplication.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/rocrate/rocrate.py b/rocrate/rocrate.py
index b602873..372660e 100644
--- a/rocrate/rocrate.py
+++ b/rocrate/rocrate.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -628,6 +629,47 @@ class ROCrate():
         self.root_dataset.append_to("mentions", action)
         return action
 
+    def add_formal_parameter(
+            self,
+            name,
+            additionalType,
+            identifier=None,
+            description=None,
+            valueRequired=False,
+            defaultValue=None,
+            properties=None
+    ):
+        """\
+        Add a FormalParameter to describe an input or output of a workflow.
+
+        A FormalParameter represents an input or output slot of a workflow, not
+        the actual value taken by a parameter. For further information see
+        https://w3id.org/ro/wfrun/workflow
+
+        Returns the created FormalParameter entity, which can be associated to
+        a workflow (e.g. as an input) using the syntax:
+          workflow_entity.append_to("input", formal_parameter_entity)
+        """
+        if properties is None:
+            properties = {}
+        props = {
+            "@type": "FormalParameter",
+            "name": name,
+            "additionalType": additionalType,
+            "valueRequired": valueRequired,
+            "conformsTo": {
+                "@id": "https://bioschemas.org/profiles/FormalParameter/1.0-RELEASE"
+            }
+        }
+        if description:
+            props["description"] = description
+        if defaultValue:
+            props["defaultValue"] = defaultValue
+        props.update(properties)
+        return self.add(
+            ContextEntity(self, identifier=identifier, properties=props)
+        )
+
     def add_jsonld(self, jsonld):
         """Add a JSON-LD dictionary as a contextual entity to the RO-Crate.
 
diff --git a/rocrate/utils.py b/rocrate/utils.py
index 66c4f9d..b40bfe9 100644
--- a/rocrate/utils.py
+++ b/rocrate/utils.py
@@ -8,6 +8,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/rocrate/vocabs.py b/rocrate/vocabs.py
index 60f3b1e..0fd6b72 100644
--- a/rocrate/vocabs.py
+++ b/rocrate/vocabs.py
@@ -8,6 +8,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/setup.py b/setup.py
index f310ec4..f942037 100755
--- a/setup.py
+++ b/setup.py
@@ -8,6 +8,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -72,7 +73,8 @@ setup(
         'Luca Pireddu',
         'Laura Rodríguez-Navas',
         'Raül Sirvent',
-        'Stian Soiland-Reyes'
+        'Stian Soiland-Reyes',
+        'Laurent Thomas'
     )),
     python_requires='>=3.9',
     author_email='stain@apache.org',
diff --git a/tools/add_boilerplate.py b/tools/add_boilerplate.py
index 348bc65..52f88c1 100644
--- a/tools/add_boilerplate.py
+++ b/tools/add_boilerplate.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -41,6 +42,7 @@ START_YEAR_MAP = {
     "Data Centre, SciLifeLab, SE": "2024",
     "National Institute of Informatics (NII), JP": "2024",
     "Senckenberg Society for Nature Research (SGN), DE": "2025",
+    "European Molecular Biology Laboratory (EMBL), Heidelberg, DE": "2025",
 }
 THIS_YEAR = str(datetime.date.today().year)
 BOILERPLATE_START = "Copyright [yyyy] [name of copyright owner]"


Test patch:
diff --git a/examples/read_test_metadata.py b/examples/read_test_metadata.py
index 5eb9805..05ae341 100644
--- a/examples/read_test_metadata.py
+++ b/examples/read_test_metadata.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/rocrate/model/testdefinition.py b/rocrate/model/testdefinition.py
index 327731c..1e1f990 100644
--- a/rocrate/model/testdefinition.py
+++ b/rocrate/model/testdefinition.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/rocrate/model/testinstance.py b/rocrate/model/testinstance.py
index 9df936e..bd966ca 100644
--- a/rocrate/model/testinstance.py
+++ b/rocrate/model/testinstance.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/rocrate/model/testservice.py b/rocrate/model/testservice.py
index b0fff4d..bd54cd3 100644
--- a/rocrate/model/testservice.py
+++ b/rocrate/model/testservice.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/rocrate/model/testsuite.py b/rocrate/model/testsuite.py
index e2d70bd..b2f3be5 100644
--- a/rocrate/model/testsuite.py
+++ b/rocrate/model/testsuite.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/test/conftest.py b/test/conftest.py
index 8e28356..ce6a7e7 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/test/test_cli.py b/test/test_cli.py
index 7ea3338..daea347 100644
--- a/test/test_cli.py
+++ b/test/test_cli.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/test/test_jsonld.py b/test/test_jsonld.py
index 0f789d0..3df9977 100644
--- a/test/test_jsonld.py
+++ b/test/test_jsonld.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/test/test_metadata.py b/test/test_metadata.py
index 9d6522f..826dece 100644
--- a/test/test_metadata.py
+++ b/test/test_metadata.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/test/test_model.py b/test/test_model.py
index fd0b864..e195ede 100644
--- a/test/test_model.py
+++ b/test/test_model.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/test/test_read.py b/test/test_read.py
index 98b812e..c0dd702 100644
--- a/test/test_read.py
+++ b/test/test_read.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/test/test_readwrite.py b/test/test_readwrite.py
index a94182a..42c0cea 100644
--- a/test/test_readwrite.py
+++ b/test/test_readwrite.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/test/test_test_metadata.py b/test/test_test_metadata.py
index 2b9c925..de8eb04 100644
--- a/test/test_test_metadata.py
+++ b/test/test_test_metadata.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/test/test_utils.py b/test/test_utils.py
index 50cb205..61e0f43 100644
--- a/test/test_utils.py
+++ b/test/test_utils.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/test/test_workflow_ro_crate.py b/test/test_workflow_ro_crate.py
index 355d68c..103eff6 100644
--- a/test/test_workflow_ro_crate.py
+++ b/test/test_workflow_ro_crate.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/test/test_write.py b/test/test_write.py
index 205bc09..2096fe4 100644
--- a/test/test_write.py
+++ b/test/test_write.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/test/test_wrroc.py b/test/test_wrroc.py
index baebce2..ec88c30 100644
--- a/test/test_wrroc.py
+++ b/test/test_wrroc.py
@@ -6,6 +6,7 @@
 # Copyright 2024-2025 Data Centre, SciLifeLab, SE
 # Copyright 2024-2025 National Institute of Informatics (NII), JP
 # Copyright 2025 Senckenberg Society for Nature Research (SGN), DE
+# Copyright 2025 European Molecular Biology Laboratory (EMBL), Heidelberg, DE
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -79,3 +80,36 @@ def test_add_action(tmpdir):
     assert "result" not in activate_action
     assert activate_action.get("name") == f"Run 2 of {instrument.id}"
     assert activate_action.get("endTime") == "2018-10-25T16:48:41.021563"
+
+
+def test_add_formal_parameter():
+    crate = ROCrate()
+    name = "test_json_param"
+    additionalType = "File"
+    encodingFormat = "application/json"
+    fp = crate.add_formal_parameter(
+        name=name,
+        additionalType=additionalType,
+        properties={"encodingFormat": encodingFormat}
+    )
+    assert fp.type == "FormalParameter"
+    assert fp.get("name") == name
+    assert fp.get("additionalType") == additionalType
+    assert not fp.get("valueRequired")
+    assert "defaultValue" not in fp
+    assert fp.get("encodingFormat") == encodingFormat
+    assert fp.get("conformsTo") == "https://bioschemas.org/profiles/FormalParameter/1.0-RELEASE"
+
+    list_formal_parameter = crate.get_by_type("FormalParameter")
+    assert list_formal_parameter == [fp]
+
+    # Test with defaultValue and valueRequired
+    defaultValue = "default"
+    fp2 = crate.add_formal_parameter(
+        name="param_string",
+        additionalType="Text",
+        defaultValue=defaultValue,
+        valueRequired=True
+    )
+    assert fp2.get("defaultValue") == defaultValue
+    assert fp2.get("valueRequired")