technologydata 0.1.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.
@@ -0,0 +1,310 @@
1
+ # SPDX-FileCopyrightText: technologydata contributors
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+
5
+ """Classes for Commons methods."""
6
+
7
+ import enum
8
+ import logging
9
+ import re
10
+ from typing import Any
11
+
12
+ import dateutil
13
+ import pandas as pd
14
+
15
+ from technologydata.utils.units import CURRENCY_UNIT_PATTERN, get_iso3_to_currency_codes
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+ all_currency_codes = set(get_iso3_to_currency_codes().values())
20
+
21
+
22
+ class DateFormatEnum(str, enum.Enum):
23
+ """
24
+ Enum for date formats used in different sources.
25
+
26
+ Attributes
27
+ ----------
28
+ SOURCES_CSV : str
29
+ Date format for CSV sources, e.g., "2023-10-01 12:00:00".
30
+ WAYBACK : str
31
+ Date format for Wayback Machine, e.g., "20231001120000".
32
+ NONE : str
33
+ Represents an empty date format.
34
+
35
+ """
36
+
37
+ SOURCES_CSV = "%Y-%m-%d %H:%M:%S"
38
+ WAYBACK = "%Y%m%d%H%M%S"
39
+ NONE = ""
40
+
41
+
42
+ class FileExtensionEnum(enum.Enum):
43
+ """
44
+ An enumeration that maps various file extensions to their corresponding MIME types.
45
+
46
+ This Enum provides a structured way to associate common file extensions with their respective
47
+ MIME types, facilitating easy retrieval of file extensions based on content types. Each member
48
+ of the enumeration is a tuple containing the file extension and its associated MIME type.
49
+
50
+ Members
51
+ --------
52
+ TEXT_PLAIN : tuple
53
+ Represents the MIME type "text/plain" with the file extension ".txt".
54
+ TEXT_HTML : tuple
55
+ Represents the MIME type "text/html" with the file extension ".html".
56
+ TEXT_CSV : tuple
57
+ Represents the MIME type "text/csv" with the file extension ".csv".
58
+ TEXT_XML : tuple
59
+ Represents the MIME type "text/xml" with the file extension ".xml".
60
+ APPLICATION_MS_EXCEL : tuple
61
+ Represents the MIME type "application/vnd.ms-excel" with the file extension ".xls".
62
+ APPLICATION_ODS : tuple
63
+ Represents the MIME type "application/vnd.oasis.opendocument.spreadsheet" with the file extension ".ods".
64
+ APPLICATION_OPENXML_EXCEL : tuple
65
+ Represents the MIME type "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
66
+ with the file extension ".xlsx".
67
+ APPLICATION_JSON : tuple
68
+ Represents the MIME type "application/json" with the file extension ".json".
69
+ APPLICATION_XML : tuple
70
+ Represents the MIME type "application/xml" with the file extension ".xml".
71
+ APPLICATION_PDF : tuple
72
+ Represents the MIME type "application/pdf" with the file extension ".pdf".
73
+ APPLICATION_PARQUET : tuple
74
+ Represents the MIME type "application/parquet" with the file extension ".parquet".
75
+ APPLICATION_VDN_PARQUET : tuple
76
+ Represents the MIME type "application/vdn.apache.parquet" with the file extension ".parquet".
77
+ APPLICATION_RAR_WINDOWS : tuple
78
+ Represents the MIME type "application/x-rar-compressed" with the file extension ".rar".
79
+ APPLICATION_RAR : tuple
80
+ Represents the MIME type "application/vnd.rar" with the file extension ".rar".
81
+ APPLICATION_ZIP : tuple
82
+ Represents the MIME type "application/zip" with the file extension ".zip".
83
+ APPLICATION_ZIP_WINDOWS : tuple
84
+ Represents the MIME type "application/x-zip-compressed" with the file extension ".zip".
85
+ """
86
+
87
+ TEXT_PLAIN = (".txt", "text/plain")
88
+ TEXT_HTML = (".html", "text/html")
89
+ TEXT_CSV = (".csv", "text/csv")
90
+ TEXT_XML = (".xml", "text/xml")
91
+ APPLICATION_MS_EXCEL = (".xls", "application/vnd.ms-excel")
92
+ APPLICATION_ODS = (".ods", "application/vnd.oasis.opendocument.spreadsheet")
93
+ APPLICATION_OPENXML_EXCEL = (
94
+ ".xlsx",
95
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
96
+ )
97
+ APPLICATION_JSON = (".json", "application/json")
98
+ APPLICATION_XML = (".xml", "application/xml")
99
+ APPLICATION_PDF = (".pdf", "application/pdf")
100
+ APPLICATION_PARQUET = (".parquet", "application/parquet")
101
+ APPLICATION_VDN_PARQUET = (".parquet", "application/vdn.apache.parquet")
102
+ APPLICATION_RAR_WINDOWS = (".rar", "application/x-rar-compressed")
103
+ APPLICATION_RAR = (".rar", "application/vnd.rar")
104
+ APPLICATION_ZIP = (".zip", "application/zip")
105
+ APPLICATION_ZIP_WINDOWS = (".zip", "application/x-zip-compressed")
106
+
107
+ @classmethod
108
+ def get_extension(cls, content_type: str) -> str | None:
109
+ """
110
+ Retrieve the file extension associated with a given MIME type.
111
+
112
+ Parameters
113
+ ----------
114
+ content_type : str
115
+ The MIME type for which the corresponding file extension is to be retrieved.
116
+
117
+ Returns
118
+ -------
119
+ str | None
120
+ The file extension associated with the given MIME type, or None if the
121
+ MIME type is not supported.
122
+
123
+ Examples
124
+ --------
125
+ >>> FileExtensionEnum.get_extension("application/pdf")
126
+ >>> '.pdf'
127
+
128
+ >>> FileExtensionEnum.get_extension("application/unknown")
129
+ >>> None
130
+
131
+ """
132
+ for member in cls:
133
+ if member.value[1] == content_type:
134
+ return member.value[0]
135
+ return None
136
+
137
+ @classmethod
138
+ def search_file_extension_in_url(cls, url: str) -> str | None:
139
+ """
140
+ Search for the file extension in a given URL.
141
+
142
+ Parameters
143
+ ----------
144
+ url : str
145
+ The URL to search for the file extension.
146
+
147
+ Returns
148
+ -------
149
+ str | None
150
+ The file extension, or None if no match is found.
151
+
152
+ Examples
153
+ --------
154
+ >>> FileExtensionEnum.search_file_extension_in_url("https://example.com/file.pdf")
155
+ '.pdf'
156
+
157
+ >>> FileExtensionEnum.search_file_extension_in_url("https://example.com/file.unknown")
158
+ None
159
+
160
+ """
161
+ for member in cls:
162
+ if re.search(r"\b" + re.escape(member.value[0]) + r"\b", url):
163
+ return member.value[0]
164
+ return None
165
+
166
+
167
+ class Commons:
168
+ """
169
+ A utility class for various helper functions.
170
+
171
+ This class provides static methods for common tasks, such as changing the format of datetime strings and replacing
172
+ special characters in strings. The methods are stateless and can be called without instantiating the class.
173
+
174
+ Methods
175
+ -------
176
+ change_datetime_format(input_datetime_string: str, output_datetime_format: DateFormatEnum) -> str | None:
177
+ Change the format of a given datetime string to a specified output format.
178
+ replace_special_characters(input_string: str) -> str:
179
+ Replace special characters and spaces in a string with underscores.
180
+
181
+ Examples
182
+ --------
183
+ >>> Commons.change_datetime_format("20250520144500", DateFormatEnum.SOURCES_CSV)
184
+ '2025-05-20 14:45:00'
185
+ >>> Commons.replace_special_characters("Hello, World! Welcome to Python @ 2023.")
186
+ 'hello_world_welcome_to_python_2023'
187
+
188
+ """
189
+
190
+ @staticmethod
191
+ def change_datetime_format(
192
+ input_datetime_string: str,
193
+ output_datetime_format: DateFormatEnum,
194
+ ) -> str | Any:
195
+ """
196
+ Change the format of a given datetime string to a specified output format.
197
+
198
+ The method takes a datetime string and automatically detects its format, then converts it to the specified output format.
199
+ If the input string cannot be parsed, it logs an error and returns None.
200
+
201
+ Parameters
202
+ ----------
203
+ input_datetime_string : str
204
+ datetime string that needs to be reformatted
205
+
206
+ output_datetime_format : DateFormatEnum
207
+ desired format for the output datetime string, following the strftime format codes.
208
+
209
+ Returns
210
+ -------
211
+ str | None
212
+ reformatted datetime string if successful, otherwise None
213
+
214
+ Raises
215
+ ------
216
+ ValueError
217
+ If the input datetime string cannot be parsed.
218
+
219
+ Examples
220
+ --------
221
+ >>> Commons.change_datetime_format("20250520144500", DateFormatEnum.SOURCES_CSV)
222
+ >>> "2025-05-20 14:45:00"
223
+
224
+ """
225
+ try:
226
+ # Automatically detect the format of the input datetime string
227
+ dt = dateutil.parser.parse(input_datetime_string)
228
+ logger.debug(f"The datetime string has been parsed successfully: {dt}")
229
+ output_datetime_string = dt.strftime(output_datetime_format.value)
230
+ logger.debug(f"The format is now changed to {output_datetime_format.value}")
231
+ return output_datetime_string
232
+ except ValueError as e:
233
+ raise ValueError(f"Error during datetime formatting: {e}")
234
+
235
+ @staticmethod
236
+ def replace_special_characters(input_string: str) -> str:
237
+ """
238
+ Replace special characters and spaces in a string.
239
+
240
+ The method replaces special characters and spaces in a string with underscores,
241
+ collapsing multiple consecutive underscores into a single underscore. Finally, it lowercases all characters of the string and removes leading or
242
+ trailing underscores.
243
+
244
+ Parameters
245
+ ----------
246
+ input_string : str
247
+ The input string from which special characters and spaces will be replaced.
248
+
249
+ Returns
250
+ -------
251
+ str
252
+ A new string with all special characters and spaces replaced by a single underscore
253
+ where consecutive underscores occur.
254
+
255
+ Examples
256
+ --------
257
+ >>> replace_special_characters("Hello, World! Welcome to Python @ 2023.")
258
+ 'hello_world_welcome_to_python_2023'
259
+
260
+ >>> replace_special_characters("Special#Characters$Are%Fun!")
261
+ 'special_characters_are_fun'
262
+
263
+ """
264
+ # Replace any character that is not a word character or whitespace with underscore
265
+ replaced = re.sub(r"[^\w\s]", "_", input_string)
266
+ # Replace whitespace with underscore
267
+ replaced = replaced.replace(" ", "_")
268
+ # Collapse multiple consecutive underscores into a single underscore
269
+ replaced = re.sub(r"_+", "_", replaced)
270
+ # Remove leading and trailing underscores
271
+ replaced = replaced.strip("_")
272
+ # Lower case the string
273
+ replaced = replaced.casefold()
274
+ return replaced
275
+
276
+ @staticmethod
277
+ def update_unit_with_currency_year(unit: str, currency_year: str) -> str:
278
+ """
279
+ Update unit string to include currency year for currency-based units.
280
+
281
+ Parameters
282
+ ----------
283
+ unit : str
284
+ A unit string
285
+ currency_year: str
286
+ A currency year string
287
+
288
+ Returns
289
+ -------
290
+ str
291
+ Updated unit
292
+
293
+ """
294
+ # Check if the units contain a currency-like string, defined as "{3-letter currency code}_{year as YYYY}"
295
+ matches = CURRENCY_UNIT_PATTERN.findall(unit)
296
+
297
+ # Check if unit is a string, contains the currency, and currency_year is not null
298
+ if isinstance(unit, str) and pd.notna(currency_year):
299
+ for currency_code in all_currency_codes:
300
+ if (
301
+ pd.notna(currency_code)
302
+ and currency_code in unit
303
+ and len(matches) == 0
304
+ ):
305
+ # Replace currency with currency_currency_year
306
+ unit = unit.replace(
307
+ currency_code, f"{currency_code}_{currency_year}"
308
+ )
309
+
310
+ return unit
@@ -0,0 +1,17 @@
1
+ # SPDX-FileCopyrightText: technologydata contributors
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+
5
+ # Definitions for the default heating values supported by the package.
6
+ # Each heating value is defined as an independent dimension.
7
+ # This way, pint allows for operations like division or multiplication,
8
+ # and at the same time prevents incompatible operations on these dimensions.
9
+ #
10
+ # See also: https://pint.readthedocs.io/en/latest/defining.html
11
+
12
+
13
+ # Format:
14
+ # <heating_value_name> = [<heating_value_name>] [= <alias>]
15
+
16
+ lower_heating_value = [lower_heating_value] = LHV = NCV = net_calorific_value
17
+ higher_heating_value = [higher_heating_value] = HHV = GCV = gross_calorific_value