Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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