Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add comments to io/file.py #1925

Merged
merged 3 commits into from
Jun 28, 2024
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
Expand Up @@ -5,6 +5,7 @@
### Documentation and tutorial enhancements
- Simplified the introduction to NWB tutorial. @rly [#1914](https://github.com/NeurodataWithoutBorders/pynwb/pull/1914)
- Simplified the ecephys and ophys tutorials. [#1915](https://github.com/NeurodataWithoutBorders/pynwb/pull/1915)
- Add comments to `src/pynwb/io/file.py` to improve developer documentation. @rly [#1925](https://github.com/NeurodataWithoutBorders/pynwb/pull/1925)

### Bug fixes
- Fixed use of `channel_conversion` in `TimeSeries` `get_data_in_units`. @rohanshah [1923](https://github.com/NeurodataWithoutBorders/pynwb/pull/1923)
Expand Down
104 changes: 100 additions & 4 deletions src/pynwb/io/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,15 @@ def __init__(self, spec):

@ObjectMapper.object_attr('scratch_datas')
def scratch_datas(self, container, manager):
"""Set the value for the 'scratch_datas' spec on NWBFile to a list of ScratchData objects.

Used when writing (building) the NWBFile container to a file.

The 'scratch' group can contain both groups and datasets. This mapping function
is used when writing the value for the 'scratch_datas' spec (ScratchData type
-- see __init__ above). The value is set to a list of all ScratchData
objects in the 'scratch' field of the NWBFile container.
"""
scratch = container.scratch
ret = list()
for s in scratch.values():
Expand All @@ -136,6 +145,15 @@ def scratch_datas(self, container, manager):

@ObjectMapper.object_attr('scratch_containers')
def scratch_containers(self, container, manager):
"""Set the value for the 'scratch_containers' spec on NWBFile to a list of non-ScratchData objects.

Used when writing (building) the NWBFile container to a file.

The 'scratch' group can contain both groups and datasets. This mapping function
is used when writing the value for the 'scratch_containers' spec (NWBContainers
and DynamicTable type -- see __init__ above). The value is set to a list of all non-ScratchData
objects in the 'scratch' field of the NWBFile container.
"""
scratch = container.scratch
ret = list()
for s in scratch.values():
Expand All @@ -145,6 +163,14 @@ def scratch_containers(self, container, manager):

@ObjectMapper.constructor_arg('scratch')
def scratch(self, builder, manager):
"""Set the constructor arg for 'scratch' to a tuple of objects.

Used when constructing the NWBFile container from a written file.

The 'scratch' group can contain both groups and datasets. This mapping function
is used to construct the contained groups and datasets and put them into a single
field 'scratch' on the NWBFile container for user convenience.
"""
scratch = builder.get('scratch')
ret = list()
if scratch is not None:
Expand All @@ -156,28 +182,54 @@ def scratch(self, builder, manager):

@ObjectMapper.constructor_arg('session_start_time')
def dateconversion(self, builder, manager):
"""Set the constructor arg for 'session_start_time' to a datetime object.

Used when constructing the NWBFile container from a written file.

Dates are read into builders as strings and are parsed into datetime objects
for user convenience and consistency with how they are written.
"""
datestr = builder.get('session_start_time').data
date = dateutil_parse(datestr)
return date

@ObjectMapper.constructor_arg('timestamps_reference_time')
def dateconversion_trt(self, builder, manager):
"""Set the constructor arg for 'timestamps_reference_time' to a datetime object.

Used when constructing the NWBFile container from a written file.

Dates are read into builders as strings and are parsed into datetime objects
for user convenience and consistency with how they are written.
"""
datestr = builder.get('timestamps_reference_time').data
date = dateutil_parse(datestr)
return date

@ObjectMapper.constructor_arg('file_create_date')
def dateconversion_list(self, builder, manager):
"""Set the constructor arg for 'file_create_date' to a datetime object.

Used when constructing the NWBFile container from a written file.

Dates are read into builders as strings and are parsed into datetime objects
for user convenience and consistency with how they are written.
"""
datestr = builder.get('file_create_date').data
dates = list(map(dateutil_parse, datestr))
return dates

@ObjectMapper.constructor_arg('file_name')
Copy link
Contributor

Choose a reason for hiding this comment

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

just wanted to clarify why this constructor was removed? Otherwise, looks good to me!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Whoops I forgot to mention that. This maps a constructor argument that doesn't exist. It must have been a legacy thing.

def name(self, builder, manager):
return builder.name

@ObjectMapper.constructor_arg('experimenter')
def experimenter_carg(self, builder, manager):
"""Set the constructor arg for 'experimenter' to a tuple if the builder value is a string.

Used when constructing the NWBFile container from a written file.

In early versions of the NWB 2 schema, 'experimenter' was specified as a string.
Then it was changed to be a 1-D array of strings. This mapping function is necessary
to allow reading of both data where 'experimenter' was specified as a string and data
where 'experimenter' was specified as an array.
"""
ret = None
exp_bldr = builder['general'].get('experimenter')
if exp_bldr is not None:
Expand All @@ -189,13 +241,30 @@ def experimenter_carg(self, builder, manager):

@ObjectMapper.object_attr('experimenter')
def experimenter_obj_attr(self, container, manager):
"""Change the value for the field 'experimenter' on NWBFile to a tuple if it is a string.

Used when writing (building) the NWBFile container to a file.

In early versions of the NWB 2 schema, 'experimenter' was specified as a string.
Then it was changed to be a 1-D array of strings. This mapping function is necessary
for writing a valid 'experimenter' array if it is a string in the NWBFile container.
"""
ret = None
if isinstance(container.experimenter, str):
ret = (container.experimenter,)
return ret

@ObjectMapper.constructor_arg('related_publications')
def publications_carg(self, builder, manager):
"""Set the constructor arg for 'related_publications' to a tuple if the builder value is a string.

Used when constructing the NWBFile container from a written file.

In early versions of the NWB 2 schema, 'related_publications' was specified as a string.
Then it was changed to be a 1-D array of strings. This mapping function is necessary
to allow reading of both data where 'related_publications' was specified as a string and data
where 'related_publications' was specified as an array.
"""
ret = None
pubs_bldr = builder['general'].get('related_publications')
if pubs_bldr is not None:
Expand All @@ -207,6 +276,14 @@ def publications_carg(self, builder, manager):

@ObjectMapper.object_attr('related_publications')
def publication_obj_attr(self, container, manager):
"""Change the value for the field 'related_publications' on NWBFile to a tuple if it is a string.

Used when writing (building) the NWBFile container to a file.

In early versions of the NWB 2 schema, 'related_publications' was specified as a string.
Then it was changed to be a 1-D array of strings. This mapping function is necessary
for writing a valid 'related_publications' array if it is a string in the NWBFile container.
"""
ret = None
if isinstance(container.related_publications, str):
ret = (container.related_publications,)
Expand All @@ -218,6 +295,13 @@ class SubjectMap(ObjectMapper):

@ObjectMapper.constructor_arg('date_of_birth')
def dateconversion(self, builder, manager):
"""Set the constructor arg for 'date_of_birth' to a datetime object.

Used when constructing the Subject container from a written file.

Dates are read into builders as strings and are parsed into datetime objects
for user convenience and consistency with how they are written.
"""
dob_builder = builder.get('date_of_birth')
if dob_builder is None:
return
Expand All @@ -228,6 +312,18 @@ def dateconversion(self, builder, manager):

@ObjectMapper.constructor_arg("age__reference")
def age_reference_none(self, builder, manager):
"""Set the constructor arg for 'age__reference' to "unspecified" for NWB files < 2.6, else "birth".

Used when constructing the Subject container from a written file.

NWB schema 2.6.0 introduced a new optional attribute 'reference' on the 'age' dataset with a default
value of "birth". When data written with NWB versions < 2.6 are read, 'age__reference' is set to
"unspecified" in the Subject constructor. "unspecified" is a special non-None placeholder value
that is handled specially in Subject.__init__ to distinguish it from no value being provided by the
user. When data written with NWB versions >= 2.6 are read, 'age__reference' is set to the default
value, "birth", in the Subject constructor (this is not strictly necessary because Subject.__init__
has default value "birth" for 'age__reference').
"""
age_builder = builder.get("age")
age_reference = None
if age_builder is not None:
Expand Down
Loading