14
14
import warnings
15
15
from collections import OrderedDict
16
16
from os import path
17
+ from pathlib import Path
17
18
18
19
import numpy as np
19
20
@@ -176,7 +177,7 @@ def __init__(self, metadata=None, data_file=None, global_info=None, skip_checksu
176
177
map_readonly: bool, default True
177
178
Indicates whether assignments on the numpy.memmap are allowed.
178
179
"""
179
- super (SigMFFile , self ).__init__ ()
180
+ super ().__init__ ()
180
181
self .data_file = None
181
182
self .sample_count = 0
182
183
self ._memmap = None
@@ -731,22 +732,36 @@ class SigMFCollection(SigMFMetafile):
731
732
]
732
733
VALID_KEYS = {COLLECTION_KEY : VALID_COLLECTION_KEYS }
733
734
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 :
746
736
"""
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__ ()
748
758
self .skip_checksums = skip_checksums
749
759
760
+ if base_path is None :
761
+ self .base_path = Path ("" )
762
+ else :
763
+ self .base_path = Path (base_path )
764
+
750
765
if metadata is None :
751
766
self ._metadata = {self .COLLECTION_KEY : {}}
752
767
self ._metadata [self .COLLECTION_KEY ][self .STREAMS_KEY ] = []
@@ -764,55 +779,64 @@ def __init__(self, metafiles=None, metadata=None, skip_checksums=False):
764
779
if not self .skip_checksums :
765
780
self .verify_stream_hashes ()
766
781
767
- def __len__ (self ):
782
+ def __len__ (self ) -> int :
768
783
"""
769
- the length of a collection is the number of streams
784
+ The length of a collection is the number of streams.
770
785
"""
771
786
return len (self .get_stream_names ())
772
787
773
- def verify_stream_hashes (self ):
788
+ def verify_stream_hashes (self ) -> None :
774
789
"""
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.
776
796
"""
777
797
streams = self .get_collection_field (self .STREAMS_KEY , [])
778
798
for stream in streams :
779
799
old_hash = stream .get ("hash" )
780
800
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 )
783
804
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
+ )
785
808
786
- def set_streams (self , metafiles ):
809
+ def set_streams (self , metafiles ) -> None :
787
810
"""
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.
789
812
"""
790
813
self .metafiles = metafiles
791
814
streams = []
792
815
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 ):
794
818
stream = {
795
819
"name" : get_sigmf_filenames (metafile )["base_fn" ],
796
- "hash" : sigmf_hash .calculate_sha512 (filename = metafile ),
820
+ "hash" : sigmf_hash .calculate_sha512 (filename = metafile_path ),
797
821
}
798
822
streams .append (stream )
799
823
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" )
801
825
self .set_collection_field (self .STREAMS_KEY , streams )
802
826
803
- def get_stream_names (self ):
827
+ def get_stream_names (self ) -> list :
804
828
"""
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.
806
830
"""
807
831
return [s .get ("name" ) for s in self .get_collection_field (self .STREAMS_KEY , [])]
808
832
809
- def set_collection_info (self , new_collection ) :
833
+ def set_collection_info (self , new_collection : dict ) -> None :
810
834
"""
811
835
Overwrite the collection info with a new dictionary.
812
836
"""
813
837
self ._metadata [self .COLLECTION_KEY ] = new_collection .copy ()
814
838
815
- def get_collection_info (self ):
839
+ def get_collection_info (self ) -> dict :
816
840
"""
817
841
Returns a dictionary with all the collection info.
818
842
"""
@@ -821,19 +845,19 @@ def get_collection_info(self):
821
845
except AttributeError :
822
846
return {}
823
847
824
- def set_collection_field (self , key , value ):
848
+ def set_collection_field (self , key : str , value ) -> None :
825
849
"""
826
850
Inserts a value into the collection field.
827
851
"""
828
852
self ._metadata [self .COLLECTION_KEY ][key ] = value
829
853
830
- def get_collection_field (self , key , default = None ):
854
+ def get_collection_field (self , key : str , default = None ):
831
855
"""
832
856
Return a field from the collection info, or default if the field is not set.
833
857
"""
834
858
return self ._metadata [self .COLLECTION_KEY ].get (key , default )
835
859
836
- def tofile (self , file_path , pretty = True ):
860
+ def tofile (self , file_path , pretty : bool = True ) -> None :
837
861
"""
838
862
Write metadata file
839
863
@@ -844,10 +868,10 @@ def tofile(self, file_path, pretty=True):
844
868
pretty : bool, default True
845
869
When True will write more human-readable output, otherwise will be flat JSON.
846
870
"""
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
851
875
852
876
def get_SigMFFile (self , stream_name = None , stream_index = None ):
853
877
"""
@@ -857,11 +881,11 @@ def get_SigMFFile(self, stream_name=None, stream_index=None):
857
881
if stream_name is not None :
858
882
if stream_name in self .get_stream_names ():
859
883
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 ):
861
885
metafile = self .get_stream_names ()[stream_index ] + ".sigmf_meta"
862
-
863
886
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 )
865
889
866
890
867
891
def dtype_info (datatype ):
@@ -1022,7 +1046,8 @@ def fromfile(filename, skip_checksum=False):
1022
1046
metadata = json .load (mdfile_reader )
1023
1047
collection_fp .close ()
1024
1048
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 )
1026
1051
1027
1052
else :
1028
1053
meta_fp = open (meta_fn , "rb" )
0 commit comments