Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# v0.9.2 (Upcoming)

## Removals, Deprecations and Changes
* Enforced keyword-only arguments across all data interfaces: `__init__` methods now only accept `file_path`/`folder_path`/`file_paths` as positional arguments, and `add_to_nwbfile` methods only accept `nwbfile` and `metadata` as positional arguments. Existing positional usage in `add_to_nwbfile` will emit a `FutureWarning` and will be removed on or after August 2026. [PR #1663](https://github.com/catalystneuro/neuroconv/pull/1663)
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CHANGELOG entry should mention that both __init__ and add_to_nwbfile methods will emit FutureWarning for positional argument usage. Currently, it only mentions add_to_nwbfile. Consider updating to: "Existing positional usage in both __init__ and add_to_nwbfile will emit a FutureWarning and will be removed on or after August 2026."

Suggested change
* Enforced keyword-only arguments across all data interfaces: `__init__` methods now only accept `file_path`/`folder_path`/`file_paths` as positional arguments, and `add_to_nwbfile` methods only accept `nwbfile` and `metadata` as positional arguments. Existing positional usage in `add_to_nwbfile` will emit a `FutureWarning` and will be removed on or after August 2026. [PR #1663](https://github.com/catalystneuro/neuroconv/pull/1663)
* Enforced keyword-only arguments across all data interfaces: `__init__` methods now only accept `file_path`/`folder_path`/`file_paths` as positional arguments, and `add_to_nwbfile` methods only accept `nwbfile` and `metadata` as positional arguments. Existing positional usage in both `__init__` and `add_to_nwbfile` will emit a `FutureWarning` and will be removed on or after August 2026. [PR #1663](https://github.com/catalystneuro/neuroconv/pull/1663)

Copilot uses AI. Check for mistakes.
* Deprecated using `write_imaging_to_nwbfile` and `write_segmentation_to_nwbfile` without `nwbfile_path`. Use `add_imaging_to_nwbfile` and `add_segmentation_to_nwbfile` instead for adding data to in-memory NWBFile objects. Will be removed on or after June 2026. [PR #1649](https://github.com/catalystneuro/neuroconv/pull/1649)
* Deprecated returning NWBFile when using `append_on_disk_nwbfile=True` in `write_imaging_to_nwbfile` and `write_segmentation_to_nwbfile`. Will return None on or after June 2026. [PR #1649](https://github.com/catalystneuro/neuroconv/pull/1649)

Expand Down
13 changes: 13 additions & 0 deletions docs/developer_guide/style_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,19 @@ DataInterface conventions
#. Use :code:`file_path` and :code:`folder_path` as arguments for the location of input files and folders/directories respectively.
#. As an exception to convention to separate words for underscores, we use :code:`nwbfile` to refer to an instance
of :py:class:`~pynwb.file.NWBFile`.
#. In :code:`__init__` methods of data interfaces, only :code:`file_path`, :code:`folder_path`, or :code:`file_paths`
should be accepted as positional arguments. All other parameters must be keyword-only, enforced with the :code:`*`
separator after the path parameter. For example:

.. code-block:: python

def __init__(self, file_path: FilePath, *, verbose: bool = False, metadata_key: str = "ElectricalSeries"):

#. In :code:`add_to_nwbfile` methods of leaf interfaces (not converters), only :code:`nwbfile` and :code:`metadata`
should be accepted as positional arguments. All other parameters (conversion options) must be keyword-only.
When deprecating existing positional usage, use the :code:`*args` pattern with a :code:`FutureWarning` to maintain
backward compatibility during the transition period. After the deprecation date, replace :code:`*args` with
:code:`*` to enforce keyword-only arguments.

Other conventions
-----------------
Expand Down
62 changes: 61 additions & 1 deletion src/neuroconv/datainterfaces/behavior/audio/audiointerface.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import json
import struct
import warnings
from pathlib import Path
from typing import Literal

Expand Down Expand Up @@ -30,7 +31,9 @@ class AudioInterface(BaseTemporalAlignmentInterface):
info = "Interface for writing audio recordings to an NWB file."

@validate_call
def __init__(self, file_paths: list[FilePath], verbose: bool = False):
def __init__(
self, file_paths: list[FilePath], *args, verbose: bool = False
): # TODO: change to * (keyword only) on or after August 2026
"""
Data interface for writing acoustic recordings to an NWB file.

Expand All @@ -47,6 +50,31 @@ def __init__(self, file_paths: list[FilePath], verbose: bool = False):

verbose : bool, default: False
"""
# Handle deprecated positional arguments
if args:
parameter_names = [
"verbose",
]
num_positional_args_before_args = 1 # file_paths
if len(args) > len(parameter_names):
raise TypeError(
f"__init__() takes at most {len(parameter_names) + num_positional_args_before_args + 1} positional arguments but "
f"{len(args) + num_positional_args_before_args + 1} were given. "
"Note: Positional arguments are deprecated and will be removed on or after August 2026. "
"Please use keyword arguments."
)
positional_values = dict(zip(parameter_names, args))
passed_as_positional = list(positional_values.keys())
warnings.warn(
f"Passing arguments positionally to AudioInterface.__init__() is deprecated "
f"and will be removed on or after August 2026. "
f"The following arguments were passed positionally: {passed_as_positional}. "
"Please use keyword arguments instead.",
FutureWarning,
stacklevel=2,
)
verbose = positional_values.get("verbose", verbose)

# This import is to assure that ndx_sound is in the global namespace when an pynwb.io object is created.
# For more detail, see https://github.com/rly/ndx-pose/issues/36
import ndx_sound # noqa: F401
Expand Down Expand Up @@ -168,6 +196,7 @@ def add_to_nwbfile(
self,
nwbfile: NWBFile,
metadata: dict | None = None,
*args, # TODO: change to * (keyword only) on or after August 2026
stub_test: bool = False,
stub_frames: int = 1000,
write_as: Literal["stimulus", "acquisition"] = "stimulus",
Expand All @@ -191,6 +220,37 @@ def add_to_nwbfile(
-------
NWBFile
"""
# Handle deprecated positional arguments
if args:
parameter_names = [
"stub_test",
"stub_frames",
"write_as",
"iterator_options",
]
num_positional_args_before_args = 2 # nwbfile, metadata
if len(args) > len(parameter_names):
raise TypeError(
f"add_to_nwbfile() takes at most {len(parameter_names) + num_positional_args_before_args} positional arguments but "
f"{len(args) + num_positional_args_before_args} were given. "
"Note: Positional arguments are deprecated and will be removed on or after August 2026. "
"Please use keyword arguments."
)
positional_values = dict(zip(parameter_names, args))
passed_as_positional = list(positional_values.keys())
warnings.warn(
f"Passing arguments positionally to AudioInterface.add_to_nwbfile() is deprecated "
f"and will be removed on or after August 2026. "
f"The following arguments were passed positionally: {passed_as_positional}. "
"Please use keyword arguments instead.",
FutureWarning,
stacklevel=2,
)
stub_test = positional_values.get("stub_test", stub_test)
stub_frames = positional_values.get("stub_frames", stub_frames)
write_as = positional_values.get("write_as", write_as)
iterator_options = positional_values.get("iterator_options", iterator_options)

import scipy

metadata = metadata or self.get_metadata()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ def get_available_subjects(file_path: FilePath) -> list[str]:
def __init__(
self,
file_path: FilePath,
*args, # TODO: change to * (keyword only) on or after August 2026
config_file_path: FilePath | None = None,
subject_name: str = "ind1",
pose_estimation_metadata_key: str = "PoseEstimationDeepLabCut",
Expand Down Expand Up @@ -171,6 +172,39 @@ def __init__(
- When the subject_name matches a subject_id in the NWBFile, the skeleton will be automatically
linked to that subject.
"""
# Handle deprecated positional arguments
if args:
parameter_names = [
"config_file_path",
"subject_name",
"pose_estimation_metadata_key",
"verbose",
]
num_positional_args_before_args = 1 # file_path
if len(args) > len(parameter_names):
raise TypeError(
f"__init__() takes at most {len(parameter_names) + num_positional_args_before_args + 1} positional arguments but "
f"{len(args) + num_positional_args_before_args + 1} were given. "
"Note: Positional arguments are deprecated and will be removed on or after August 2026. "
"Please use keyword arguments."
)
positional_values = dict(zip(parameter_names, args))
passed_as_positional = list(positional_values.keys())
warnings.warn(
f"Passing arguments positionally to DeepLabCutInterface.__init__() is deprecated "
f"and will be removed on or after August 2026. "
f"The following arguments were passed positionally: {passed_as_positional}. "
"Please use keyword arguments instead.",
FutureWarning,
stacklevel=2,
)
config_file_path = positional_values.get("config_file_path", config_file_path)
subject_name = positional_values.get("subject_name", subject_name)
pose_estimation_metadata_key = positional_values.get(
"pose_estimation_metadata_key", pose_estimation_metadata_key
)
verbose = positional_values.get("verbose", verbose)

# This import is to assure that the ndx_pose is in the global namespace when an pynwb.io object is created
from importlib.metadata import version

Expand Down Expand Up @@ -525,6 +559,7 @@ def add_to_nwbfile(
self,
nwbfile: NWBFile,
metadata: dict | None = None,
*args, # TODO: change to * (keyword only) on or after August 2026
container_name: str | None = None,
):
"""
Expand All @@ -543,6 +578,30 @@ def add_to_nwbfile(
the content of the metadata.

"""
# Handle deprecated positional arguments
if args:
parameter_names = [
"container_name",
]
num_positional_args_before_args = 2 # nwbfile, metadata
if len(args) > len(parameter_names):
raise TypeError(
f"add_to_nwbfile() takes at most {len(parameter_names) + num_positional_args_before_args} positional arguments but "
f"{len(args) + num_positional_args_before_args} were given. "
"Note: Positional arguments are deprecated and will be removed on or after August 2026. "
"Please use keyword arguments."
)
positional_values = dict(zip(parameter_names, args))
passed_as_positional = list(positional_values.keys())
warnings.warn(
f"Passing arguments positionally to DeepLabCutInterface.add_to_nwbfile() is deprecated "
f"and will be removed on or after August 2026. "
f"The following arguments were passed positionally: {passed_as_positional}. "
"Please use keyword arguments instead.",
FutureWarning,
stacklevel=2,
)
container_name = positional_values.get("container_name", container_name)
from ._dlc_utils import (
_add_pose_estimation_to_nwbfile,
_ensure_individuals_in_header,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import json
import re
import warnings
from datetime import datetime, timezone
from pathlib import Path

Expand Down Expand Up @@ -156,6 +157,7 @@ def get_source_schema(cls) -> dict:
def __init__(
self,
file_path: FilePath,
*args, # TODO: change to * (keyword only) on or after August 2026
radius: float | None = None,
configuration_file_path: FilePath | None = None,
verbose: bool = False,
Expand All @@ -175,6 +177,35 @@ def __init__(
verbose : bool, default: False
controls verbosity. ``True`` by default.
"""
# Handle deprecated positional arguments
if args:
parameter_names = [
"radius",
"configuration_file_path",
"verbose",
]
num_positional_args_before_args = 1 # file_path
if len(args) > len(parameter_names):
raise TypeError(
f"__init__() takes at most {len(parameter_names) + num_positional_args_before_args + 1} positional arguments but "
f"{len(args) + num_positional_args_before_args + 1} were given. "
"Note: Positional arguments are deprecated and will be removed on or after August 2026. "
"Please use keyword arguments."
)
positional_values = dict(zip(parameter_names, args))
passed_as_positional = list(positional_values.keys())
warnings.warn(
f"Passing arguments positionally to FicTracDataInterface.__init__() is deprecated "
f"and will be removed on or after August 2026. "
f"The following arguments were passed positionally: {passed_as_positional}. "
"Please use keyword arguments instead.",
FutureWarning,
stacklevel=2,
)
radius = positional_values.get("radius", radius)
configuration_file_path = positional_values.get("configuration_file_path", configuration_file_path)
verbose = positional_values.get("verbose", verbose)

self.file_path = Path(file_path)
self.verbose = verbose
self.radius = radius
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def add_to_nwbfile(
self,
nwbfile: NWBFile,
metadata: dict,
*args,
*args, # TODO: change to * (keyword only) on or after August 2026
reference_frame: str | None = None,
confidence_definition: str | None = None,
external_mode: bool = True,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import re
import warnings
from copy import deepcopy
from datetime import datetime
from pathlib import Path
Expand Down Expand Up @@ -62,6 +63,7 @@ def get_metadata_schema(self) -> dict:
def __init__(
self,
file_path: FilePath,
*args, # TODO: change to * (keyword only) on or after August 2026
original_video_file_path: FilePath,
labeled_video_file_path: FilePath | None = None,
verbose: bool = False,
Expand All @@ -80,6 +82,34 @@ def __init__(
verbose : bool, default: False
controls verbosity. ``True`` by default.
"""
# Handle deprecated positional arguments
if args:
parameter_names = [
"original_video_file_path",
"labeled_video_file_path",
"verbose",
]
num_positional_args_before_args = 1 # file_path
if len(args) > len(parameter_names):
raise TypeError(
f"__init__() takes at most {len(parameter_names) + num_positional_args_before_args + 1} positional arguments but "
f"{len(args) + num_positional_args_before_args + 1} were given. "
"Note: Positional arguments are deprecated and will be removed on or after August 2026. "
"Please use keyword arguments."
)
positional_values = dict(zip(parameter_names, args))
passed_as_positional = list(positional_values.keys())
warnings.warn(
f"Passing arguments positionally to LightningPoseDataInterface.__init__() is deprecated "
f"and will be removed on or after August 2026. "
f"The following arguments were passed positionally: {passed_as_positional}. "
"Please use keyword arguments instead.",
FutureWarning,
stacklevel=2,
)
original_video_file_path = positional_values.get("original_video_file_path", original_video_file_path)
labeled_video_file_path = positional_values.get("labeled_video_file_path", labeled_video_file_path)
verbose = positional_values.get("verbose", verbose)

# This import is to assure that the ndx_pose is in the global namespace when an pynwb.io object is created
# For more detail, see https://github.com/rly/ndx-pose/issues/36
Expand Down Expand Up @@ -192,6 +222,7 @@ def add_to_nwbfile(
self,
nwbfile: NWBFile,
metadata: dict | None = None,
*args, # TODO: change to * (keyword only) on or after August 2026
reference_frame: str | None = None,
confidence_definition: str | None = None,
stub_test: bool | None = False,
Expand All @@ -211,6 +242,35 @@ def add_to_nwbfile(
The description of how the confidence was computed, e.g., 'Softmax output of the deep neural network'.
stub_test : bool, default: False
"""
# Handle deprecated positional arguments
if args:
parameter_names = [
"reference_frame",
"confidence_definition",
"stub_test",
]
num_positional_args_before_args = 2 # nwbfile, metadata
if len(args) > len(parameter_names):
raise TypeError(
f"add_to_nwbfile() takes at most {len(parameter_names) + num_positional_args_before_args} positional arguments but "
f"{len(args) + num_positional_args_before_args} were given. "
"Note: Positional arguments are deprecated and will be removed on or after August 2026. "
"Please use keyword arguments."
)
positional_values = dict(zip(parameter_names, args))
passed_as_positional = list(positional_values.keys())
warnings.warn(
f"Passing arguments positionally to LightningPoseDataInterface.add_to_nwbfile() is deprecated "
f"and will be removed on or after August 2026. "
f"The following arguments were passed positionally: {passed_as_positional}. "
"Please use keyword arguments instead.",
FutureWarning,
stacklevel=2,
)
reference_frame = positional_values.get("reference_frame", reference_frame)
confidence_definition = positional_values.get("confidence_definition", confidence_definition)
stub_test = positional_values.get("stub_test", stub_test)

from ndx_pose import PoseEstimation, PoseEstimationSeries, Skeleton, Skeletons

metadata_copy = deepcopy(metadata)
Expand Down
Loading
Loading