1414import warnings
1515from collections import OrderedDict
1616from os import path
17+ from pathlib import Path
1718
1819import numpy as np
1920
@@ -176,7 +177,7 @@ def __init__(self, metadata=None, data_file=None, global_info=None, skip_checksu
176177 map_readonly: bool, default True
177178 Indicates whether assignments on the numpy.memmap are allowed.
178179 """
179- super (SigMFFile , self ).__init__ ()
180+ super ().__init__ ()
180181 self .data_file = None
181182 self .sample_count = 0
182183 self ._memmap = None
@@ -731,22 +732,36 @@ class SigMFCollection(SigMFMetafile):
731732 ]
732733 VALID_KEYS = {COLLECTION_KEY : VALID_COLLECTION_KEYS }
733734
734- def __init__ (self , metafiles = None , metadata = None , skip_checksums = False ):
735- """Create a SigMF Collection object.
736-
737- Parameters:
738-
739- metafiles -- A list of SigMF metadata filenames objects comprising the Collection,
740- there must be at least one file. If the files do not exist, this will
741- raise a SigMFFileError.
742-
743- metadata -- collection metadata to use, if not provided this will populate a
744- minimal set of default metadata. The core:streams field will be
745- regenerated automatically
735+ def __init__ (self , metafiles : list = None , metadata : dict = None , base_path = None , skip_checksums : bool = False ) -> None :
746736 """
747- super (SigMFCollection , self ).__init__ ()
737+ Create a SigMF Collection object.
738+
739+ Parameters
740+ ----------
741+ metafiles: list, optional
742+ A list of SigMF metadata filenames objects comprising the Collection.
743+ There should be at least one file.
744+ metadata: dict, optional
745+ Collection metadata to use, if not provided this will populate a minimal set of default metadata.
746+ The `core:streams` field will be regenerated automatically.
747+ base_path : str | bytes | PathLike, optional
748+ Base path of the collection recordings.
749+ skip_checksums : bool, optional
750+ If true will skip calculating checksum on datasets.
751+
752+ Raises
753+ ------
754+ SigMFError
755+ If metadata files do not exist.
756+ """
757+ super ().__init__ ()
748758 self .skip_checksums = skip_checksums
749759
760+ if base_path is None :
761+ self .base_path = Path ("" )
762+ else :
763+ self .base_path = Path (base_path )
764+
750765 if metadata is None :
751766 self ._metadata = {self .COLLECTION_KEY : {}}
752767 self ._metadata [self .COLLECTION_KEY ][self .STREAMS_KEY ] = []
@@ -764,55 +779,64 @@ def __init__(self, metafiles=None, metadata=None, skip_checksums=False):
764779 if not self .skip_checksums :
765780 self .verify_stream_hashes ()
766781
767- def __len__ (self ):
782+ def __len__ (self ) -> int :
768783 """
769- the length of a collection is the number of streams
784+ The length of a collection is the number of streams.
770785 """
771786 return len (self .get_stream_names ())
772787
773- def verify_stream_hashes (self ):
788+ def verify_stream_hashes (self ) -> None :
774789 """
775- compares the stream hashes in the collection metadata to the metadata files
790+ Compares the stream hashes in the collection metadata to the metadata files.
791+
792+ Raises
793+ ------
794+ SigMFFileError
795+ If any dataset checksums do not match saved metadata.
776796 """
777797 streams = self .get_collection_field (self .STREAMS_KEY , [])
778798 for stream in streams :
779799 old_hash = stream .get ("hash" )
780800 metafile_name = get_sigmf_filenames (stream .get ("name" ))["meta_fn" ]
781- if path .isfile (metafile_name ):
782- new_hash = sigmf_hash .calculate_sha512 (filename = metafile_name )
801+ metafile_path = self .base_path / metafile_name
802+ if path .isfile (metafile_path ):
803+ new_hash = sigmf_hash .calculate_sha512 (filename = metafile_path )
783804 if old_hash != new_hash :
784- raise SigMFFileError (f"Calculated file hash for { metafile_name } does not match collection metadata." )
805+ raise SigMFFileError (
806+ f"Calculated file hash for { metafile_path } does not match collection metadata."
807+ )
785808
786- def set_streams (self , metafiles ):
809+ def set_streams (self , metafiles ) -> None :
787810 """
788- configures the collection `core:streams` field from the specified list of metafiles
811+ Configures the collection `core:streams` field from the specified list of metafiles.
789812 """
790813 self .metafiles = metafiles
791814 streams = []
792815 for metafile in self .metafiles :
793- if metafile .endswith (".sigmf-meta" ) and path .isfile (metafile ):
816+ metafile_path = self .base_path / metafile
817+ if metafile .endswith (".sigmf-meta" ) and path .isfile (metafile_path ):
794818 stream = {
795819 "name" : get_sigmf_filenames (metafile )["base_fn" ],
796- "hash" : sigmf_hash .calculate_sha512 (filename = metafile ),
820+ "hash" : sigmf_hash .calculate_sha512 (filename = metafile_path ),
797821 }
798822 streams .append (stream )
799823 else :
800- raise SigMFFileError (f"Specifed stream file { metafile } is not a valid SigMF Metadata file" )
824+ raise SigMFFileError (f"Specifed stream file { metafile_path } is not a valid SigMF Metadata file" )
801825 self .set_collection_field (self .STREAMS_KEY , streams )
802826
803- def get_stream_names (self ):
827+ def get_stream_names (self ) -> list :
804828 """
805- returns a list of `name` object(s) from the `collection` level `core:streams` metadata
829+ Returns a list of `name` object(s) from the `collection` level `core:streams` metadata.
806830 """
807831 return [s .get ("name" ) for s in self .get_collection_field (self .STREAMS_KEY , [])]
808832
809- def set_collection_info (self , new_collection ) :
833+ def set_collection_info (self , new_collection : dict ) -> None :
810834 """
811835 Overwrite the collection info with a new dictionary.
812836 """
813837 self ._metadata [self .COLLECTION_KEY ] = new_collection .copy ()
814838
815- def get_collection_info (self ):
839+ def get_collection_info (self ) -> dict :
816840 """
817841 Returns a dictionary with all the collection info.
818842 """
@@ -821,19 +845,19 @@ def get_collection_info(self):
821845 except AttributeError :
822846 return {}
823847
824- def set_collection_field (self , key , value ):
848+ def set_collection_field (self , key : str , value ) -> None :
825849 """
826850 Inserts a value into the collection field.
827851 """
828852 self ._metadata [self .COLLECTION_KEY ][key ] = value
829853
830- def get_collection_field (self , key , default = None ):
854+ def get_collection_field (self , key : str , default = None ):
831855 """
832856 Return a field from the collection info, or default if the field is not set.
833857 """
834858 return self ._metadata [self .COLLECTION_KEY ].get (key , default )
835859
836- def tofile (self , file_path , pretty = True ):
860+ def tofile (self , file_path , pretty : bool = True ) -> None :
837861 """
838862 Write metadata file
839863
@@ -844,10 +868,10 @@ def tofile(self, file_path, pretty=True):
844868 pretty : bool, default True
845869 When True will write more human-readable output, otherwise will be flat JSON.
846870 """
847- fns = get_sigmf_filenames (file_path )
848- with open (fns ["collection_fn" ], "w" ) as fp :
849- self .dump (fp , pretty = pretty )
850- fp .write ("\n " ) # text files should end in carriage return
871+ filenames = get_sigmf_filenames (file_path )
872+ with open (filenames ["collection_fn" ], "w" ) as handle :
873+ self .dump (handle , pretty = pretty )
874+ handle .write ("\n " ) # text files should end in carriage return
851875
852876 def get_SigMFFile (self , stream_name = None , stream_index = None ):
853877 """
@@ -857,11 +881,11 @@ def get_SigMFFile(self, stream_name=None, stream_index=None):
857881 if stream_name is not None :
858882 if stream_name in self .get_stream_names ():
859883 metafile = stream_name + ".sigmf_meta"
860- if stream_index is not None and stream_index < self . __len__ ( ):
884+ if stream_index is not None and stream_index < len ( self ):
861885 metafile = self .get_stream_names ()[stream_index ] + ".sigmf_meta"
862-
863886 if metafile is not None :
864- return fromfile (metafile , skip_checksum = self .skip_checksums )
887+ metafile_path = self .base_path / metafile
888+ return fromfile (metafile_path , skip_checksum = self .skip_checksums )
865889
866890
867891def dtype_info (datatype ):
@@ -1022,7 +1046,8 @@ def fromfile(filename, skip_checksum=False):
10221046 metadata = json .load (mdfile_reader )
10231047 collection_fp .close ()
10241048
1025- return SigMFCollection (metadata = metadata , skip_checksums = skip_checksum )
1049+ dir_path = path .split (meta_fn )[0 ]
1050+ return SigMFCollection (metadata = metadata , base_path = dir_path , skip_checksums = skip_checksum )
10261051
10271052 else :
10281053 meta_fp = open (meta_fn , "rb" )
0 commit comments