pyASDReader 1.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyASDReader/__init__.py +41 -0
- pyASDReader/_version.py +12 -0
- pyASDReader/asd_file_reader.py +940 -0
- pyASDReader/constant.py +138 -0
- pyASDReader/file_attributes.py +113 -0
- pyASDReader/logger_setup.py +35 -0
- pyasdreader-1.2.0.dist-info/METADATA +497 -0
- pyasdreader-1.2.0.dist-info/RECORD +11 -0
- pyasdreader-1.2.0.dist-info/WHEEL +5 -0
- pyasdreader-1.2.0.dist-info/licenses/LICENSE +21 -0
- pyasdreader-1.2.0.dist-info/top_level.txt +1 -0
pyASDReader/constant.py
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"""
|
|
2
|
+
The constant values for the ASD file format
|
|
3
|
+
"""
|
|
4
|
+
from enum import Enum
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# metadata.fileVersion: ASD File Version, at byte offset 0
|
|
8
|
+
class FileVersion_e(Enum):
|
|
9
|
+
FILE_VERSION_INVALID = 0
|
|
10
|
+
FILE_VERSION_1 = 1
|
|
11
|
+
FILE_VERSION_2 = 2
|
|
12
|
+
FILE_VERSION_3 = 3
|
|
13
|
+
FILE_VERSION_4 = 4
|
|
14
|
+
FILE_VERSION_5 = 5
|
|
15
|
+
FILE_VERSION_6 = 6
|
|
16
|
+
FILE_VERSION_7 = 7
|
|
17
|
+
FILE_VERSION_8 = 8
|
|
18
|
+
|
|
19
|
+
# metadata.instrument: Instrument type that created spectrum, at byte offset 431
|
|
20
|
+
class InstrumentType_e(Enum):
|
|
21
|
+
UNKNOWN_INSTRUMENT = 0
|
|
22
|
+
PSII_INSTRUMENT = 1
|
|
23
|
+
LSVNIR_INSTRUMENT = 2
|
|
24
|
+
FSVNIR_INSTRUMENT = 3
|
|
25
|
+
FSFR_INSTRUMENT = 4
|
|
26
|
+
FSNIR_INSTRUMENT = 5
|
|
27
|
+
CHEM_INSTRUMENT = 6
|
|
28
|
+
LAB_SPEC_PRO = 7
|
|
29
|
+
HAND_HELD_INSTRUMENT = 10
|
|
30
|
+
|
|
31
|
+
class InstrumentModel_e(Enum):
|
|
32
|
+
itVnir = 1
|
|
33
|
+
# itDual
|
|
34
|
+
itSwir1 = 4
|
|
35
|
+
itVnirSwir1 = 5
|
|
36
|
+
itSwir2 = 8
|
|
37
|
+
itVnirSwir2 = 9
|
|
38
|
+
itSwir1Swir2 = 12
|
|
39
|
+
itVnirSwir1Swir2 = 13
|
|
40
|
+
|
|
41
|
+
# metadata.dataType: Spectrum type, at byte offset 186
|
|
42
|
+
class SpectraType_e(Enum):
|
|
43
|
+
RAW = 0
|
|
44
|
+
REFLECTANCE = 1
|
|
45
|
+
RADIANCE = 2
|
|
46
|
+
NO_UNITS = 3
|
|
47
|
+
IRRADIANCE = 4
|
|
48
|
+
QUALITY_INDEX = 5
|
|
49
|
+
|
|
50
|
+
class SignatureState_e(Enum):
|
|
51
|
+
SIGNED_INVALID = -1
|
|
52
|
+
UN_SIGNED = 0
|
|
53
|
+
SIGNED = 1
|
|
54
|
+
# VERIFIED = 2
|
|
55
|
+
# NOT_VERIFIED = 3
|
|
56
|
+
|
|
57
|
+
class AuditLogType_e(Enum):
|
|
58
|
+
AUDIT_EVENT_ELEMENT = "Audit_Event"
|
|
59
|
+
AUDIT_APPLICATION_ELEMENT = "Audit_Application"
|
|
60
|
+
AUDIT_APP_VERSION_ELEMENT = "Audit_AppVersion"
|
|
61
|
+
AUDIT_FUNCTION_ELEMENT = "Audit_Function"
|
|
62
|
+
AUDIT_SOURCE_ELEMENT = "Audit_Source"
|
|
63
|
+
AUDIT_LOGIN_ELEMENT = "Audit_Login"
|
|
64
|
+
AUDIT_NAME_ELEMENT = "Audit_Name"
|
|
65
|
+
AUDIT_TIME_ELEMENT = "Audit_Time"
|
|
66
|
+
AUDIT_NOTES_ELEMENT = "Audit_Notes"
|
|
67
|
+
|
|
68
|
+
class IT_ms_e(Enum):
|
|
69
|
+
Invalid = 0 # 0 ms, not inluded in the original manual and codes, added by Kai Cao
|
|
70
|
+
ms_8 = 8 # 8 ms, not inluded in the original manual and codes, added by Kai Cao
|
|
71
|
+
ms_8_5 = 9
|
|
72
|
+
ms_17 = 17
|
|
73
|
+
ms_34 = 34
|
|
74
|
+
ms_68 = 68
|
|
75
|
+
ms_136 = 136
|
|
76
|
+
ms_272 = 272
|
|
77
|
+
ms_544 = 544
|
|
78
|
+
ms_1088 = 1088
|
|
79
|
+
ms_2176 = 2176
|
|
80
|
+
ms_4352 = 4352
|
|
81
|
+
ms_8704 = 8704
|
|
82
|
+
ms_17408 = 17408
|
|
83
|
+
ms_34816 = 34816
|
|
84
|
+
ms_69632 = 69632
|
|
85
|
+
ms_139264 = 139264
|
|
86
|
+
ms_278528 = 278528
|
|
87
|
+
ms_557056 = 557056
|
|
88
|
+
|
|
89
|
+
# metadata.dataFormat: Spectrum data format, at byte offset 199
|
|
90
|
+
class DataFormat_e(Enum):
|
|
91
|
+
df_FLOAT = 0
|
|
92
|
+
df_INTEGER = 1
|
|
93
|
+
df_DOUBLE = 2
|
|
94
|
+
df_UNKNOWN = 3
|
|
95
|
+
|
|
96
|
+
# metadata.calibrationSeries: Calibration type, at byte offset 432
|
|
97
|
+
class CalibrationType_e(Enum):
|
|
98
|
+
cb_ABSOLUTE = 0 # ABS, Absolute Reflectance File;
|
|
99
|
+
cb_BASE = 1 # BSE, Base File
|
|
100
|
+
cb_LAMP = 2 # LMP, Lamp File
|
|
101
|
+
cb_FIBER = 3 # FO, Fiber Optic File
|
|
102
|
+
cb_UNKNOWN = 4 # Unknown Calibration Series
|
|
103
|
+
|
|
104
|
+
class DataType_e(Enum):
|
|
105
|
+
dt_RAW_TYPE = 0 # Raw Spectrum File
|
|
106
|
+
dt_REF_TYPE = 1 # Reflectance File
|
|
107
|
+
dt_RAD_TYPE = 2 # Radiance File
|
|
108
|
+
dt_NOUNITS_TYPE = 3 # No Units File
|
|
109
|
+
dt_IRRAD_TYPE = 4 # Irradiance File
|
|
110
|
+
dt_QI_TYPE = 5 # Quality Index File
|
|
111
|
+
dt_TRANS_TYPE = 6 # Transmittance File
|
|
112
|
+
dt_UNKNOWN_TYPE = 7 # Unknown File
|
|
113
|
+
dt_ABS_TYPE = 8 # Absolute Reflectance File
|
|
114
|
+
# dt_ADF_TYPE
|
|
115
|
+
# dt_ADC_TYPE
|
|
116
|
+
# dt_MTF_TYPE
|
|
117
|
+
# dt_MTC_TYPE
|
|
118
|
+
# dt_RTF_TYPE
|
|
119
|
+
# dt_RTC_TYPE
|
|
120
|
+
# dt_SBF_TYPE
|
|
121
|
+
# dt_SBC_TYPE
|
|
122
|
+
|
|
123
|
+
# Classifier Data Type
|
|
124
|
+
class ClassiferDataType_e(Enum):
|
|
125
|
+
SAM = 0
|
|
126
|
+
GALACTIC = 1
|
|
127
|
+
CAMOPREDICT = 2
|
|
128
|
+
CAMOCLASSIFY = 3
|
|
129
|
+
PCAZ = 4
|
|
130
|
+
INFOMETRIX = 5
|
|
131
|
+
|
|
132
|
+
# Error types for flags2 in the metadata
|
|
133
|
+
class SaturationError_e(Enum):
|
|
134
|
+
VNIR_SATURATION = 1 # Vnir Saturation 0 0 0 0 0 0 0 1 0x01
|
|
135
|
+
SWIR1_SATURATION = 2 # Swir1 Saturation 0 0 0 0 0 0 1 0 0x02
|
|
136
|
+
SWIR2_SATURATION = 4 # Swir2 Saturation 0 0 0 0 0 1 0 0 0x04
|
|
137
|
+
SWIR1_TEC_ALARM = 8 # Swir1 Tec Alarm 0 0 0 0 1 0 0 0 0x08
|
|
138
|
+
SWIR2_TEC_ALARM = 16 # Swir2 Tec Alarm 0 0 0 1 0 0 0 0 0x16
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""
|
|
2
|
+
File attribute class includes the following aspects:
|
|
3
|
+
• File attributes include: file name, path, size, creation time, modification time, access time, file type, etc.
|
|
4
|
+
• Some basic operations can be provided for files, such as reading, writing, deleting, etc.
|
|
5
|
+
• File permission settings may need support (such as read-only, executable, etc.).
|
|
6
|
+
|
|
7
|
+
Main function description:
|
|
8
|
+
1. Initialization method (__init__): Receive the file path, check whether the file exists, and then get the basic information of the file (such as name, size, creation time, modification time, access time, etc.).
|
|
9
|
+
2. Get file type (get_file_type): Get the file type by the file extension.
|
|
10
|
+
3. Read file (read_file): Read the file's content and return it.
|
|
11
|
+
4. Write file (write_to_file): Write the content to the file, overwriting the original content.
|
|
12
|
+
5. Delete file (delete_file): Delete the file in the specified path.
|
|
13
|
+
6. Print basic information of the file (__str__): Returns brief information of the file, which is convenient for viewing the properties of the file.
|
|
14
|
+
|
|
15
|
+
3. To be added:
|
|
16
|
+
• More properties such as file permissions, file owners, and file locking mechanisms.
|
|
17
|
+
• Support file reading and writing in different encoding formats.
|
|
18
|
+
• Error handling mechanisms to ensure robustness in abnormal situations.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
import os
|
|
23
|
+
import time
|
|
24
|
+
import hashlib
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class FileAttributes(object):
|
|
28
|
+
def __init__(self, filepath):
|
|
29
|
+
|
|
30
|
+
if os.path.exists(filepath) and os.path.isfile(filepath):
|
|
31
|
+
self.filepath = filepath
|
|
32
|
+
else:
|
|
33
|
+
print(f"File \'{filepath}\' do not exist.")
|
|
34
|
+
exception = FileNotFoundError(f"File \'{filepath}\' do not exist.")
|
|
35
|
+
raise exception
|
|
36
|
+
|
|
37
|
+
# Basic file attributes
|
|
38
|
+
self.filepath = filepath
|
|
39
|
+
self.filename = os.path.basename(filepath)
|
|
40
|
+
self.filesize = os.path.getsize(filepath)
|
|
41
|
+
self.filetype = os.path.splitext(filepath)[1]
|
|
42
|
+
self.dirname = os.path.dirname(filepath)
|
|
43
|
+
self.creation_time = time.ctime(os.path.getctime(filepath))
|
|
44
|
+
self.modification_time = time.ctime(os.path.getmtime(filepath))
|
|
45
|
+
self.access_time = time.ctime(os.path.getatime(filepath))
|
|
46
|
+
self.file_permission = os.stat(filepath).st_mode
|
|
47
|
+
self._data = self.__get_data()
|
|
48
|
+
self._hashMD5 = None
|
|
49
|
+
self._hashSHA265 = None
|
|
50
|
+
|
|
51
|
+
def __get_data(self):
|
|
52
|
+
with open(self.filepath, 'rb') as file:
|
|
53
|
+
return file.read()
|
|
54
|
+
|
|
55
|
+
def delete(self):
|
|
56
|
+
if os.path.exists(self.filepath) and os.path.isfile(self.filepath):
|
|
57
|
+
os.remove(self.filepath)
|
|
58
|
+
else:
|
|
59
|
+
print(f"File delete fail: file \'{self.filepath}\' do not exist")
|
|
60
|
+
raise FileNotFoundError(f"File \'{self.filepath}\' do not exist")
|
|
61
|
+
|
|
62
|
+
def read(self):
|
|
63
|
+
if os.path.exists(self.filepath) and os.path.isfile(self.filepath):
|
|
64
|
+
with open(self.filepath, 'r', encoding='utf-8') as file:
|
|
65
|
+
return file.read()
|
|
66
|
+
|
|
67
|
+
def write(self, content):
|
|
68
|
+
if os.path.exists(self.filepath) and os.path.isfile(self.filepath):
|
|
69
|
+
with open(self.filepath, 'w', encoding='utf-8') as file:
|
|
70
|
+
file.write(content)
|
|
71
|
+
|
|
72
|
+
# def save(self):
|
|
73
|
+
# with open(self.filepath, 'wb') as file:
|
|
74
|
+
# file.write(content)
|
|
75
|
+
|
|
76
|
+
# def saveAS(self, filepath):
|
|
77
|
+
# with open(filepath, 'wb') as file:
|
|
78
|
+
# file.write(filepath)
|
|
79
|
+
|
|
80
|
+
def set_file_name(self, new_name):
|
|
81
|
+
self.file_name = new_name
|
|
82
|
+
self.file_path = os.path.join(os.path.dirname(self.file_path), new_name)
|
|
83
|
+
|
|
84
|
+
def set_file_path(self, new_path):
|
|
85
|
+
self.file_path = new_path
|
|
86
|
+
self.file_name = os.path.basename(new_path)
|
|
87
|
+
|
|
88
|
+
def __str__(self):
|
|
89
|
+
return f"File Name: \t\t{self.filename}\n" \
|
|
90
|
+
f"File Path: \t\t{self.filepath}\n" \
|
|
91
|
+
f"File Size: \t\t{self.filesize} bytes\n" \
|
|
92
|
+
f"Creation Time: \t\t{self.creation_time}\n" \
|
|
93
|
+
f"Modification Time: \t{self.modification_time}\n" \
|
|
94
|
+
f"Access Time: \t\t{self.access_time}\n" \
|
|
95
|
+
f"File type: \t\t{self.filetype}\n"\
|
|
96
|
+
f"MD5: \t\t\t{self.hashMD5}\n" \
|
|
97
|
+
f"SHA265: \t\t{self.hashSHA265}"
|
|
98
|
+
|
|
99
|
+
@property
|
|
100
|
+
def hashMD5(self):
|
|
101
|
+
if self._hashMD5 is None:
|
|
102
|
+
self._hashMD5 = hashlib.md5(self._data).hexdigest()
|
|
103
|
+
return self._hashMD5
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def hashSHA265(self):
|
|
107
|
+
if self._hashSHA265 is None:
|
|
108
|
+
self._hashSHA265 = hashlib.sha256(self._data).hexdigest()
|
|
109
|
+
return self._hashSHA265
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
if __name__ == '__main__':
|
|
113
|
+
pass
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def setup_logging(log_file, log_level=logging.INFO) -> None:
|
|
5
|
+
|
|
6
|
+
# To generate a log file name that includes the date
|
|
7
|
+
|
|
8
|
+
# Set up logging format and level
|
|
9
|
+
level_list = [
|
|
10
|
+
logging.CRITICAL,
|
|
11
|
+
logging.ERROR,
|
|
12
|
+
logging.WARNING,
|
|
13
|
+
logging.INFO,
|
|
14
|
+
logging.DEBUG,
|
|
15
|
+
logging.NOTSET
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
if log_level not in level_list:
|
|
19
|
+
raise ValueError(f"Invalid log level: {log_level}. Valid levels are as follows: {level_list}")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
logging.basicConfig(
|
|
23
|
+
# Set the logging level
|
|
24
|
+
level=log_level,
|
|
25
|
+
# Log format
|
|
26
|
+
# format='%(asctime)s - %(levelname)s - %(message)s',
|
|
27
|
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s - Line: %(lineno)d',
|
|
28
|
+
# format='%(levelname)s - %(message)s',
|
|
29
|
+
handlers=[
|
|
30
|
+
# NOTE: Create a file handler to log to console only
|
|
31
|
+
# logging.StreamHandler(),
|
|
32
|
+
# NOTE: Create a file handler to log to a file and console
|
|
33
|
+
logging.FileHandler(log_file, encoding='utf-8') # Log to file
|
|
34
|
+
]
|
|
35
|
+
)
|