PyDPEET 0.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.
Files changed (122) hide show
  1. pydpeet/__init__.py +56 -0
  2. pydpeet/citations/__init__.py +7 -0
  3. pydpeet/citations/citeme.py +397 -0
  4. pydpeet/citations/html_writer.py +137 -0
  5. pydpeet/dev_utils/__init__.py +7 -0
  6. pydpeet/dev_utils/generate_inits/__init__.py +7 -0
  7. pydpeet/dev_utils/generate_inits/generate_inits.py +327 -0
  8. pydpeet/io/__init__.py +7 -0
  9. pydpeet/io/configs/__init__.py +7 -0
  10. pydpeet/io/configs/config.py +227 -0
  11. pydpeet/io/configs/const.py +1 -0
  12. pydpeet/io/convert.py +594 -0
  13. pydpeet/io/device/__init__.py +7 -0
  14. pydpeet/io/device/arbin_4_23_PV090331/__init__.py +7 -0
  15. pydpeet/io/device/arbin_4_23_PV090331/formatter.py +22 -0
  16. pydpeet/io/device/arbin_4_23_PV090331/mapper.py +18 -0
  17. pydpeet/io/device/arbin_4_23_PV090331/reader.py +68 -0
  18. pydpeet/io/device/arbin_8_00_PV221201/__init__.py +7 -0
  19. pydpeet/io/device/arbin_8_00_PV221201/formatter.py +26 -0
  20. pydpeet/io/device/arbin_8_00_PV221201/mapper.py +18 -0
  21. pydpeet/io/device/arbin_8_00_PV221201/reader.py +66 -0
  22. pydpeet/io/device/basytec_6_3_1_0/__init__.py +7 -0
  23. pydpeet/io/device/basytec_6_3_1_0/formatter.py +18 -0
  24. pydpeet/io/device/basytec_6_3_1_0/mapper.py +18 -0
  25. pydpeet/io/device/basytec_6_3_1_0/reader.py +54 -0
  26. pydpeet/io/device/digatron_4_20_6_236/__init__.py +7 -0
  27. pydpeet/io/device/digatron_4_20_6_236/formatter.py +27 -0
  28. pydpeet/io/device/digatron_4_20_6_236/mapper.py +18 -0
  29. pydpeet/io/device/digatron_4_20_6_236/reader.py +45 -0
  30. pydpeet/io/device/digatron_eis_4_20_6_236/__init__.py +7 -0
  31. pydpeet/io/device/digatron_eis_4_20_6_236/formatter.py +39 -0
  32. pydpeet/io/device/digatron_eis_4_20_6_236/mapper.py +18 -0
  33. pydpeet/io/device/digatron_eis_4_20_6_236/reader.py +42 -0
  34. pydpeet/io/device/neware_8_0_0_516/__init__.py +7 -0
  35. pydpeet/io/device/neware_8_0_0_516/formatter.py +31 -0
  36. pydpeet/io/device/neware_8_0_0_516/mapper.py +18 -0
  37. pydpeet/io/device/neware_8_0_0_516/reader.py +397 -0
  38. pydpeet/io/device/parstat_2_63_3/__init__.py +7 -0
  39. pydpeet/io/device/parstat_2_63_3/formatter.py +34 -0
  40. pydpeet/io/device/parstat_2_63_3/mapper.py +18 -0
  41. pydpeet/io/device/parstat_2_63_3/reader.py +34 -0
  42. pydpeet/io/device/safion_1_9/__init__.py +7 -0
  43. pydpeet/io/device/safion_1_9/formatter.py +25 -0
  44. pydpeet/io/device/safion_1_9/mapper.py +18 -0
  45. pydpeet/io/device/safion_1_9/reader.py +89 -0
  46. pydpeet/io/device/zahner/__init__.py +7 -0
  47. pydpeet/io/device/zahner/formatter.py +73 -0
  48. pydpeet/io/device/zahner/mapper.py +34 -0
  49. pydpeet/io/device/zahner/reader.py +46 -0
  50. pydpeet/io/device/zahner_new/__init__.py +7 -0
  51. pydpeet/io/device/zahner_new/formatter.py +72 -0
  52. pydpeet/io/device/zahner_new/mapper.py +50 -0
  53. pydpeet/io/device/zahner_new/reader.py +46 -0
  54. pydpeet/io/map.py +69 -0
  55. pydpeet/io/read.py +50 -0
  56. pydpeet/io/utils/__init__.py +7 -0
  57. pydpeet/io/utils/ext_path.py +34 -0
  58. pydpeet/io/utils/formatter_utils.py +429 -0
  59. pydpeet/io/utils/load_custom_module.py +33 -0
  60. pydpeet/io/utils/timing.py +36 -0
  61. pydpeet/io/write.py +99 -0
  62. pydpeet/process/__init__.py +7 -0
  63. pydpeet/process/analyze/__init__.py +7 -0
  64. pydpeet/process/analyze/average.py +297 -0
  65. pydpeet/process/analyze/capacity.py +208 -0
  66. pydpeet/process/analyze/configs/__init__.py +7 -0
  67. pydpeet/process/analyze/configs/battery_config.py +38 -0
  68. pydpeet/process/analyze/configs/ocv_config.py +177 -0
  69. pydpeet/process/analyze/configs/step_analyzer_config.py +178 -0
  70. pydpeet/process/analyze/cycle.py +63 -0
  71. pydpeet/process/analyze/efficiency.py +182 -0
  72. pydpeet/process/analyze/energy.py +51 -0
  73. pydpeet/process/analyze/extract/__init__.py +7 -0
  74. pydpeet/process/analyze/extract/dva_ica.py +224 -0
  75. pydpeet/process/analyze/extract/ocv.py +196 -0
  76. pydpeet/process/analyze/power.py +32 -0
  77. pydpeet/process/analyze/resistance.py +87 -0
  78. pydpeet/process/analyze/soc.py +418 -0
  79. pydpeet/process/analyze/soh.py +72 -0
  80. pydpeet/process/analyze/utils.py +122 -0
  81. pydpeet/process/merge/__init__.py +7 -0
  82. pydpeet/process/merge/series.py +274 -0
  83. pydpeet/process/sequence/__init__.py +7 -0
  84. pydpeet/process/sequence/configs/__init__.py +7 -0
  85. pydpeet/process/sequence/configs/config.py +17 -0
  86. pydpeet/process/sequence/step_analyzer.py +440 -0
  87. pydpeet/process/sequence/utils/__init__.py +7 -0
  88. pydpeet/process/sequence/utils/annotate/__init__.py +7 -0
  89. pydpeet/process/sequence/utils/annotate/annotate_primitives.py +419 -0
  90. pydpeet/process/sequence/utils/configs/CONFIG_Fallback.py +231 -0
  91. pydpeet/process/sequence/utils/configs/CONFIG_preprocessing.py +243 -0
  92. pydpeet/process/sequence/utils/configs/__init__.py +7 -0
  93. pydpeet/process/sequence/utils/console_prints/__init__.py +7 -0
  94. pydpeet/process/sequence/utils/console_prints/log_time.py +30 -0
  95. pydpeet/process/sequence/utils/postprocessing/__init__.py +7 -0
  96. pydpeet/process/sequence/utils/postprocessing/df_primitives_correction.py +166 -0
  97. pydpeet/process/sequence/utils/postprocessing/filter_df.py +168 -0
  98. pydpeet/process/sequence/utils/postprocessing/generate_instructions.py +297 -0
  99. pydpeet/process/sequence/utils/preprocessing/__init__.py +7 -0
  100. pydpeet/process/sequence/utils/preprocessing/calculate_thresholds.py +27 -0
  101. pydpeet/process/sequence/utils/processing/__init__.py +7 -0
  102. pydpeet/process/sequence/utils/processing/analyze_segments.py +368 -0
  103. pydpeet/process/sequence/utils/processing/attempt_to_merge_neighboring_segments.py +122 -0
  104. pydpeet/process/sequence/utils/processing/check_CV_results.py +226 -0
  105. pydpeet/process/sequence/utils/processing/check_power_zero_watt_segments.py +85 -0
  106. pydpeet/process/sequence/utils/processing/check_zero_length.py +117 -0
  107. pydpeet/process/sequence/utils/processing/split_in_segments.py +97 -0
  108. pydpeet/process/sequence/utils/processing/supress_smaller_segments.py +99 -0
  109. pydpeet/process/sequence/utils/processing/widen_constant_segments.py +185 -0
  110. pydpeet/process/sequence/utils/visualize/__init__.py +7 -0
  111. pydpeet/process/sequence/utils/visualize/visualize_data.py +288 -0
  112. pydpeet/res/__init__.py +7 -0
  113. pydpeet/settings.py +0 -0
  114. pydpeet/utils/__init__.py +7 -0
  115. pydpeet/utils/logging_style.py +28 -0
  116. pydpeet/version.py +0 -0
  117. pydpeet-0.2.0.dist-info/METADATA +85 -0
  118. pydpeet-0.2.0.dist-info/RECORD +122 -0
  119. pydpeet-0.2.0.dist-info/WHEEL +5 -0
  120. pydpeet-0.2.0.dist-info/licenses/AUTHORS.md +0 -0
  121. pydpeet-0.2.0.dist-info/licenses/LICENCE.md +27 -0
  122. pydpeet-0.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,73 @@
1
+ import pandas as pd
2
+
3
+ from pydpeet.io.utils.formatter_utils import nan_to_none_in_column, round_testtime, typecast
4
+
5
+
6
+ def get_data_into_format_zahner_1(df: pd.DataFrame) -> pd.DataFrame:
7
+ """
8
+ Format a DataFrame in the format of a Zahner EIS file, type 1.
9
+
10
+ The DataFrame is modified in-place.
11
+
12
+ The modifications are as follows:
13
+
14
+ - The "Test_Time[s]" column is rounded to 5 decimal places.
15
+ - NaN values in the "Test_Time[s]" column are replaced with None.
16
+ - The "Step_Count" column is typecast to int.
17
+ - The "EIS_f[Hz]" column is typecast to float.
18
+ - The "EIS_Z_Real[Ohm]" column is typecast to float.
19
+ - The "EIS_Z_Imag[Ohm]" column is typecast to float.
20
+
21
+ Parameters
22
+ ----------
23
+ dataFrame : pandas.DataFrame
24
+ DataFrame to be modified.
25
+
26
+ Returns
27
+ -------
28
+ pandas.DataFrame
29
+ Modified DataFrame.
30
+ """
31
+ df = round_testtime(df)
32
+ df = nan_to_none_in_column(df, "Test_Time[s]")
33
+ typecast(df, "Step_Count", int)
34
+ typecast(df, "EIS_f[Hz]", float)
35
+ typecast(df, "EIS_Z_Real[Ohm]", float)
36
+ typecast(df, "EIS_Z_Imag[Ohm]", float)
37
+
38
+ return df
39
+
40
+
41
+ def get_data_into_format_zahner_2(df: pd.DataFrame) -> pd.DataFrame:
42
+ """
43
+ Format a DataFrame in the format of a Zahner EIS file, type 2.
44
+
45
+ The DataFrame is modified in-place.
46
+
47
+ The modifications are as follows:
48
+
49
+ - The "Test_Time[s]" column is rounded to 5 decimal places.
50
+ - NaN values in the "Test_Time[s]" column are replaced with None.
51
+ - The "Step_Count" column is typecast to int.
52
+ - The "Voltage[V]" column is typecast to float.
53
+ - The "Current[A]" column is typecast to float.
54
+ - The "Test_Time[s]" column is typecast to float.
55
+
56
+ Parameters
57
+ ----------
58
+ dataFrame : pandas.DataFrame
59
+ DataFrame to be modified.
60
+
61
+ Returns
62
+ -------
63
+ pandas.DataFrame
64
+ Modified DataFrame.
65
+ """
66
+ df = round_testtime(df)
67
+ df = nan_to_none_in_column(df, "Test_Time[s]")
68
+ typecast(df, "Step_Count", int)
69
+ typecast(df, "Voltage[V]", float)
70
+ typecast(df, "Current[A]", float)
71
+ typecast(df, "Test_Time[s]", float)
72
+
73
+ return df
@@ -0,0 +1,34 @@
1
+ # Map raw-data column names (left) to standardized column names (right)
2
+ COLUMN_MAP_1 = {
3
+ "Frequency/Hz": "EIS_f[Hz]",
4
+ "Number": "Step_Count",
5
+ r"R/": "EIS_Z_Real[Ohm]",
6
+ r"I/": "EIS_Z_Imag[Ohm]",
7
+ }
8
+
9
+ COLUMN_MAP_2 = {
10
+ "step": "Step_Count",
11
+ "voltage V": "Voltage[V]",
12
+ "time s": "Test_Time[s]",
13
+ "current A": "Current[A]",
14
+ }
15
+
16
+ # Default columns of the standardized format
17
+ # which are not present in the raw data files.
18
+ MISSING_REQUIRED_COLUMNS_1 = [
19
+ "Test_Time[s]",
20
+ "Voltage[V]",
21
+ "Current[A]",
22
+ "Date_Time",
23
+ "Temperature[°C]",
24
+ "EIS_DC[A]",
25
+ ]
26
+
27
+ MISSING_REQUIRED_COLUMNS_2 = [
28
+ "EIS_DC[A]",
29
+ "Temperature[°C]",
30
+ "Date_Time",
31
+ "EIS_f[Hz]",
32
+ "EIS_Z_Real[Ohm]",
33
+ "EIS_Z_Imag[Ohm]",
34
+ ]
@@ -0,0 +1,46 @@
1
+ import pandas as pd
2
+
3
+
4
+ def to_dataframe(input_path: str) -> tuple[pd.DataFrame, str]:
5
+ """
6
+ Parses the input file from the new Zahner Cycler into a pandas DataFrame.
7
+
8
+ Parameters:
9
+ input_path (str): Path to the input file.
10
+
11
+ Returns:
12
+ (pd.DataFrame, str): A tuple containing the DataFrame with data and metadata as a string.
13
+ """
14
+ metadata = []
15
+
16
+ # Open the file and process lines
17
+ with open(input_path, encoding="us-ascii") as file:
18
+ # Read metadata until a data header line is detected
19
+ line = file.readline()
20
+ while not (line.strip().startswith("time") or line.strip().startswith("Number")):
21
+ metadata.append(line.strip())
22
+ line = file.readline()
23
+
24
+ # Detect delimiter and process the header
25
+ if ";" in line:
26
+ delimiter = ";"
27
+ elif "," in line:
28
+ delimiter = ","
29
+ else:
30
+ delimiter = None # Whitespace-delimited
31
+
32
+ # Read and parse data lines
33
+ if delimiter:
34
+ headers = line.strip().split(delimiter)
35
+ data_lines = [row.strip().split(delimiter) for row in file if row.strip()]
36
+ else:
37
+ headers = line.strip().split()
38
+ data_lines = [row.strip().split() for row in file if row.strip()]
39
+
40
+ # Join metadata into a single string
41
+ metadata_str = "\n".join(metadata)
42
+
43
+ # Create DataFrame
44
+ df = pd.DataFrame(data_lines, columns=headers)
45
+
46
+ return df, metadata_str
@@ -0,0 +1,7 @@
1
+ """
2
+ Auto-generated __init__ file.
3
+ Created: 2026-03-06 15:11:49
4
+ """
5
+
6
+ # Restrictive package init: start with no public API
7
+ __all__ = []
@@ -0,0 +1,72 @@
1
+ import pandas as pd
2
+
3
+ from pydpeet.io.utils.formatter_utils import nan_to_none_in_column, round_testtime, typecast
4
+
5
+
6
+ def get_data_into_format_zahner_1(df: pd.DataFrame) -> pd.DataFrame:
7
+ """
8
+ Rounds the values in the "Test_Time[s]" column of the DataFrame to 5 decimal places, replaces NaN values with None, and typecasts the "Step_Count" and "EIS_f[Hz]" columns to int and float, respectively.
9
+
10
+ Parameters
11
+ ----------
12
+ dataFrame : pandas.DataFrame
13
+ DataFrame to be modified
14
+
15
+ Returns
16
+ -------
17
+ pandas.DataFrame
18
+ Modified DataFrame
19
+ """
20
+ round_testtime(df)
21
+ nan_to_none_in_column(df, "Test_Time[s]")
22
+ typecast(df, "Step_Count", int)
23
+ typecast(df, "EIS_f[Hz]", float)
24
+
25
+ return df
26
+
27
+
28
+ def get_data_into_format_zahner_2(df: pd.DataFrame) -> pd.DataFrame:
29
+ """
30
+ Rounds the values in the "Test_Time[s]" column of the DataFrame to 5 decimal places, replaces NaN values with None, and typecasts the "Step_Count", "Voltage[V]", and "Current[A]" columns to int, float, and float, respectively.
31
+
32
+ Parameters
33
+ ----------
34
+ dataFrame : pandas.DataFrame
35
+ DataFrame to be modified
36
+
37
+ Returns
38
+ -------
39
+ pandas.DataFrame
40
+ Modified DataFrame
41
+ """
42
+ df = round_testtime(df)
43
+ df = nan_to_none_in_column(df, "Test_Time[s]")
44
+ typecast(df, "Step_Count", int)
45
+ typecast(df, "Voltage[V]", float)
46
+ typecast(df, "Current[A]", float)
47
+
48
+ return df
49
+
50
+
51
+ def get_data_into_format_zahner_3(df: pd.DataFrame) -> pd.DataFrame:
52
+ """
53
+ Rounds the values in the "Test_Time[s]" column of the DataFrame to 5 decimal places, replaces NaN values with None, and typecasts the "Step_Count", "Voltage[V]", "Current[A]", and "EIS_f[Hz]" columns to int, float, float, and float, respectively.
54
+
55
+ Parameters
56
+ ----------
57
+ dataFrame : pandas.DataFrame
58
+ DataFrame to be modified
59
+
60
+ Returns
61
+ -------
62
+ pandas.DataFrame
63
+ Modified DataFrame
64
+ """
65
+ df = round_testtime(df)
66
+ df = nan_to_none_in_column(df, "Test_Time[s]")
67
+ typecast(df, "Step_Count", int)
68
+ typecast(df, "Voltage[V]", float)
69
+ typecast(df, "Current[A]", float)
70
+ typecast(df, "EIS_f[Hz]", float)
71
+
72
+ return df
@@ -0,0 +1,50 @@
1
+ # Map raw-data column names (left) to standardized column names (right)
2
+ COLUMN_MAP_1 = {
3
+ r"Frequency/Hz": "EIS_f[Hz]",
4
+ "Number": "Step_Count",
5
+ }
6
+
7
+ COLUMN_MAP_2 = {
8
+ "step": "Step_Count",
9
+ "voltage V": "Voltage[V]",
10
+ "time s": "Test_Time[s]",
11
+ "current A": "Current[A]",
12
+ }
13
+
14
+ COLUMN_MAP_3 = {
15
+ "Number": "Step_Count",
16
+ "Voltage/V": "Voltage[V]",
17
+ "Current/A": "Current[A]",
18
+ "Time/s": "Test_Time[s]",
19
+ "Frequency/Hz": "EIS_f[Hz]",
20
+ }
21
+
22
+ # Default columns of the standardized format
23
+ # which are not present in the raw data files.
24
+ MISSING_REQUIRED_COLUMNS_1 = [
25
+ "Test_Time[s]",
26
+ "Voltage[V]",
27
+ "Current[A]",
28
+ "Date_Time",
29
+ "Temperature[°C]",
30
+ "EIS_DC[A]",
31
+ "EIS_Z_Real[Ohm]",
32
+ "EIS_Z_Imag[Ohm]",
33
+ ]
34
+
35
+ MISSING_REQUIRED_COLUMNS_2 = [
36
+ "EIS_DC[A]",
37
+ "Temperature[°C]",
38
+ "Date_Time",
39
+ "EIS_f[Hz]",
40
+ "EIS_Z_Real[Ohm]",
41
+ "EIS_Z_Imag[Ohm]",
42
+ ]
43
+
44
+ MISSING_REQUIRED_COLUMNS_3 = [
45
+ "Temperature[°C]",
46
+ "Date_Time",
47
+ "EIS_Z_Real[Ohm]",
48
+ "EIS_Z_Imag[Ohm]",
49
+ "EIS_DC[A]",
50
+ ]
@@ -0,0 +1,46 @@
1
+ import pandas as pd
2
+
3
+
4
+ def to_dataframe(input_path: str) -> tuple[pd.DataFrame, str]:
5
+ """
6
+ Parses the input file from the Zahner Cycler into a pandas DataFrame.
7
+
8
+ Parameters:
9
+ input_path (str): Path to the input file.
10
+
11
+ Returns:
12
+ (pd.DataFrame, str): A tuple containing the DataFrame with data and metadata as a string.
13
+ """
14
+ metadata = []
15
+
16
+ # Open the file and process lines
17
+ with open(input_path, encoding="us-ascii") as file:
18
+ # Read metadata until a data header line is detected
19
+ line = file.readline()
20
+ while not (line.strip().startswith("time") or line.strip().startswith("Number")):
21
+ metadata.append(line.strip())
22
+ line = file.readline()
23
+
24
+ # Detect delimiter and process the header
25
+ if ";" in line:
26
+ delimiter = ";"
27
+ elif "," in line:
28
+ delimiter = ","
29
+ else:
30
+ delimiter = None # Whitespace-delimited
31
+
32
+ # Read and parse data lines
33
+ if delimiter:
34
+ headers = line.strip().split(delimiter)
35
+ data_lines = [row.strip().split(delimiter) for row in file if row.strip()]
36
+ else:
37
+ headers = line.strip().split()
38
+ data_lines = [row.strip().split() for row in file if row.strip()]
39
+
40
+ # Join metadata into a single string
41
+ metadata_str = "\n".join(metadata)
42
+
43
+ # Create DataFrame
44
+ df = pd.DataFrame(data_lines, columns=headers)
45
+
46
+ return df, metadata_str
pydpeet/io/map.py ADDED
@@ -0,0 +1,69 @@
1
+ import logging
2
+
3
+ import pandas as pd
4
+
5
+ from pydpeet.io.configs.config import STANDARD_COLUMNS
6
+
7
+
8
+ def mapping(
9
+ df: pd.DataFrame,
10
+ column_map: dict,
11
+ missing_columns: list,
12
+ ) -> pd.DataFrame:
13
+ """
14
+ Renames and maps specific columns in the DataFrame to standardized names.
15
+ If a standardized column doesn't exist in the DataFrame, it is added with default None values.
16
+ Non-mapped columns will remain unchanged in the resulting DataFrame.
17
+
18
+ Parameters:
19
+ dataFrame (pandas.DataFrame): The input DataFrame to be processed.
20
+ column_map (dict): A dictionary mapping existing column names to new standardized names.
21
+ missing_columns (list): A list of column names to ensure their existence in the DataFrame.
22
+
23
+ Returns:
24
+ pandas.DataFrame: The updated DataFrame with standardized column names.
25
+
26
+ Assumptions:
27
+ column_map and missing_columns contain all standard columns
28
+ (If you want to rename more or add more columns do it after the conversion)
29
+ """
30
+ if df is None:
31
+ raise ValueError("dataFrame is None")
32
+ if column_map is None:
33
+ raise ValueError("column_map is None")
34
+ if missing_columns is None:
35
+ raise ValueError("missing_columns is None")
36
+ if type(df) is not pd.DataFrame:
37
+ raise ValueError("dataFrame is not a DataFrame")
38
+ if type(column_map) is not dict:
39
+ raise ValueError("column_map is not a dictionary")
40
+ if type(missing_columns) is not list:
41
+ raise ValueError("missing_columns is not a list")
42
+ standard_columns_excluding_metadata = [col for col in STANDARD_COLUMNS if not col.startswith("Meta_Data")]
43
+ if not all(col in list(column_map.values()) + missing_columns for col in standard_columns_excluding_metadata):
44
+ raise ValueError("column_map and missing_columns do not contain all standard columns")
45
+ if any(col not in STANDARD_COLUMNS for col in list(column_map.values()) + missing_columns):
46
+ raise ValueError("column_map and missing_columns contain columns that are not standard columns")
47
+
48
+ # Create a copy of the DataFrame to avoid modifying the original
49
+ df_copy = df.copy()
50
+
51
+ # Add missing columns with None values if they do not exist, and issue warnings
52
+ for missing in missing_columns:
53
+ if missing not in df_copy.columns:
54
+ logging.warning(f"Missing column: '{missing}'. Adding Collumn (with None values) named: '{missing}'.")
55
+ df_copy[missing] = None
56
+
57
+ # Warn if a column that should be mapped is missing and add it with None values
58
+ for original_col in column_map.keys():
59
+ if original_col not in df_copy.columns:
60
+ logging.warning(
61
+ f"Column to be mapped '{original_col}' does not exist in DataFrame. Adding it with None values."
62
+ )
63
+ df_copy[original_col] = None
64
+
65
+ # Rename the existing columns as per the column_map
66
+ # Columns not in the column_map will remain unchanged
67
+ df_copy.rename(columns=column_map, inplace=True)
68
+
69
+ return df_copy
pydpeet/io/read.py ADDED
@@ -0,0 +1,50 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from pathlib import Path
5
+
6
+ import pandas as pd
7
+
8
+ from pydpeet.io.configs.config import Config
9
+ from pydpeet.io.convert import (
10
+ convert_file,
11
+ convert_files_in_directory,
12
+ )
13
+
14
+ ConfigLike = Config | str
15
+ PathLike = str | Path
16
+
17
+
18
+ def read(
19
+ config: ConfigLike,
20
+ input_path: object,
21
+ keep_all_additional_data: bool = False,
22
+ custom_folder_path: str = None,
23
+ ) -> pd.DataFrame | list[pd.DataFrame]:
24
+ # TODO: Docstring
25
+ if isinstance(input_path, str):
26
+ if os.path.isfile(input_path):
27
+ return convert_file(config, input_path, None, keep_all_additional_data, custom_folder_path)
28
+ elif os.path.isdir(input_path):
29
+ return convert_files_in_directory(config, input_path, None, keep_all_additional_data, custom_folder_path)
30
+ else:
31
+ raise ValueError("Input path is invalid!")
32
+ elif isinstance(input_path, list):
33
+ dfs = []
34
+ for input_item in input_path:
35
+ if isinstance(input_item, str):
36
+ if os.path.isfile(input_item):
37
+ dfs.append(convert_file(config, input_item, None, keep_all_additional_data, custom_folder_path))
38
+ elif os.path.isdir(input_item):
39
+ dfs.append(
40
+ convert_files_in_directory(
41
+ config, input_item, None, keep_all_additional_data, custom_folder_path
42
+ )
43
+ )
44
+ else:
45
+ raise ValueError("Input path item is invalid!")
46
+ else:
47
+ raise ValueError("Input path item is of invalid type!")
48
+ return dfs
49
+ else:
50
+ raise ValueError("Input path is of invalid type!")
@@ -0,0 +1,7 @@
1
+ """
2
+ Auto-generated __init__ file.
3
+ Created: 2026-03-06 15:11:49
4
+ """
5
+
6
+ # Restrictive package init: start with no public API
7
+ __all__ = []
@@ -0,0 +1,34 @@
1
+ from pathlib import Path
2
+
3
+
4
+ class ExtPath(Path):
5
+ @staticmethod
6
+ def is_not_valid(path: str | None) -> bool:
7
+ """
8
+ Checks if a given path is not valid.
9
+
10
+ Args:
11
+ path (str | None): The path to check.
12
+
13
+ Returns:
14
+ bool: True if the path is not valid; False otherwise.
15
+ """
16
+ return not ExtPath.is_valid(path)
17
+
18
+ @staticmethod
19
+ def is_valid(path: str | None) -> bool:
20
+ """
21
+ Checks if a given path is valid.
22
+
23
+ A path is valid if it is not None or empty and if it exists.
24
+
25
+ Args:
26
+ path (str | None): The path to check.
27
+
28
+ Returns:
29
+ bool: True if the path is valid; False otherwise.
30
+ """
31
+ return bool(path) and Path(path).exists()
32
+
33
+ def is_excel_file(self) -> bool:
34
+ return self.exists() and self.is_file() and self.suffix in (".xlsx", ".xls")