python-ubercode-utils 2.0.0__py3-none-any.whl → 2.0.2__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.
@@ -1,12 +1,11 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-ubercode-utils
3
- Version: 2.0.0
3
+ Version: 2.0.2
4
4
  Summary: Core python utilities for all apps
5
5
  Home-page: https://github.com/sstacha/python-ubercode-utils
6
6
  Author: Steve Stacha
7
7
  Author-email: sstacha@gmail.com
8
8
  License: MIT
9
- Platform: UNKNOWN
10
9
  Classifier: Development Status :: 3 - Alpha
11
10
  Classifier: Programming Language :: Python :: 3
12
11
  Classifier: License :: OSI Approved :: MIT License
@@ -14,6 +13,7 @@ Classifier: Operating System :: OS Independent
14
13
  Classifier: Topic :: Utilities
15
14
  Requires-Python: >=3.8
16
15
  Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
17
 
18
18
  # python-ubercode-utils
19
19
  Extracting common python utilities re-used between all projects. The intent is to have minimal dependencies
@@ -27,5 +27,3 @@ python-utils-core:
27
27
  - manipulating urls and their parameters
28
28
  - helper classes to make working with xml and json data easier
29
29
  - minimal helper classes to convert database cursor results to dictionaries or tuples
30
-
31
-
@@ -0,0 +1,14 @@
1
+ ubercode/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ ubercode/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ ubercode/utils/convert.py,sha256=YWIacPg3MaUTGSANZ2yzxanIkUCH2oyqOR6Wvtz91Fg,11371
4
+ ubercode/utils/cursor.py,sha256=zHqbmUavCF0l7ck_Tu4PfgSzRO762ULKHYsnqa3r0uY,1118
5
+ ubercode/utils/data.py,sha256=DStj9BAXPSPvQRZwfEQVYt19EoMavyNFt11U8ZnhagE,4364
6
+ ubercode/utils/dataframe.py,sha256=3AYoZGZB7wtN5brBDfRgnuIaEubhRrSc7qx8hi_vaaE,1616
7
+ ubercode/utils/environment.py,sha256=zSgemMspWx1mBPeI2CSStCSj_kjVm_rEVZaNRkEMsZM,13657
8
+ ubercode/utils/logging.py,sha256=s4yIJWHo9MVO4oSk5IF3z6XTk-FOuyEiKnPFkiza3h4,9204
9
+ ubercode/utils/urls.py,sha256=PaksDHVg_aSXEqcN4SlLgY-erqeMCNw8mYK9qt3q05I,9652
10
+ python_ubercode_utils-2.0.2.dist-info/LICENSE,sha256=lch0WEJaqJY3C5aCYSr0u6Gw0set96a2fp9ZWJRYuR8,1069
11
+ python_ubercode_utils-2.0.2.dist-info/METADATA,sha256=Oe6G8phzfGZ6SFVZdd7FDgsNGjjF999kF4e70dU4dEE,1225
12
+ python_ubercode_utils-2.0.2.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
13
+ python_ubercode_utils-2.0.2.dist-info/top_level.txt,sha256=5BojzbvNCpPkFXcVQVr7cfovhbYQYAlMKgiHSMgi7VU,9
14
+ python_ubercode_utils-2.0.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.38.4)
2
+ Generator: bdist_wheel (0.44.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
ubercode/utils/data.py CHANGED
@@ -9,7 +9,7 @@ import xml.etree.ElementTree as Etree
9
9
  from collections import defaultdict
10
10
 
11
11
 
12
- class JSON:
12
+ class JsonData:
13
13
  """ simple json class to encapsulate basic json operations """
14
14
  def __init__(self, json_string: str or None = None, encode_ampersands: bool = False):
15
15
  # data is core python objects (list, dict, object, etc) from the core python JSON.loads
@@ -49,7 +49,7 @@ class JSON:
49
49
  return str(self.data)
50
50
 
51
51
 
52
- class XML:
52
+ class XmlData:
53
53
  """ simple xml class to encapsulate basic xml operations using build in python ETree """
54
54
  def __init__(self, xml_string: str or None = None, encode_ampersands: bool = False):
55
55
  # data is core python ElementTree object
@@ -95,7 +95,7 @@ class XML:
95
95
  output to dict
96
96
  :return: dict
97
97
  """
98
- return XML.tree_to_dict(self.data)
98
+ return XmlData.tree_to_dict(self.data)
99
99
 
100
100
  @staticmethod
101
101
  def tree_to_dict(t: Etree) -> dict:
@@ -108,7 +108,7 @@ class XML:
108
108
  children = list(t)
109
109
  if children:
110
110
  dd = defaultdict(list)
111
- for dc in map(XML.tree_to_dict, children):
111
+ for dc in map(XmlData.tree_to_dict, children):
112
112
  for k, v in dc.items():
113
113
  dd[k].append(v)
114
114
  d = {t.tag: {k: v[0] if len(v) == 1 else v for k, v in dd.items()}}
@@ -1,7 +1,26 @@
1
1
  """ common utilities for working with dataframes"""
2
2
  from typing import Any
3
3
  from . import logging
4
+ from datetime import datetime
4
5
 
6
+ default_date_formats = {
7
+ 'date': '%Y-%m-%d',
8
+ 'datetime': '%Y-%m-%d %H:%M:%S',
9
+ 'datetimemilli': '%Y-%m-%d %H:%M:%S.%f'
10
+ }
11
+
12
+ def to_date_str(date_string: str or None, date_col: str, date_field_map: dict, date_formats: dict) -> str or None:
13
+ if date_string == 'None' or date_string == 'NaT' or not date_string:
14
+ return None
15
+ if '.' in date_string:
16
+ dt = datetime.strptime(date_string, date_formats['datetimemilli'])
17
+ elif ':' in date_string:
18
+ dt = datetime.strptime(date_string, date_formats['datetime'])
19
+ else:
20
+ dt = datetime.strptime(date_string, date_formats['date'])
21
+ if not dt:
22
+ return None
23
+ return dt.strftime(date_formats[date_field_map[date_col]])
5
24
 
6
25
  # extend the logging to include log.dataframe()
7
26
  # NOTE: making dataframe type Any, so we don't have to include pandas but intended use is dataframe
@@ -6,6 +6,7 @@ import os
6
6
  import time
7
7
  from datetime import datetime
8
8
  from typing import Any, Tuple
9
+ from pathlib import Path
9
10
  from ubercode.utils.logging import ColorLogger
10
11
  from ubercode.utils import convert
11
12
 
@@ -223,3 +224,61 @@ class Environment:
223
224
  self._logger.warn(
224
225
  f"{db_parts[0]}[{db_parts[1]}][{db_parts[2]}] has a database or property naming issue!")
225
226
  return db_dict
227
+
228
+ class FauxApp:
229
+ def __init__(self, logger: ColorLogger = None, notebook_path: Path = Path(), default_dict: dict = None) -> None:
230
+ self._logger = logger if logger else _utils_settings_logger
231
+ self.notebook_path = notebook_path.resolve()
232
+ self.app_path = os.path.dirname(self.notebook_path)
233
+ self.project_path = os.path.dirname(self.app_path)
234
+ self.instance_path = os.path.join(self.project_path, 'instance')
235
+ self.config = default_dict or dict(
236
+ SECRET_KEY = 'localmachine',
237
+ LOG_LEVEL = 'DEBUG',
238
+ DEBUG = True,
239
+ APP_DIR = self.app_path,
240
+ PROJECT_DIR = self.project_path,
241
+ DATABASE_DEBUG = False,
242
+ SA_URL_APP = f'sqlite+pysqlite:///{os.path.join(self.instance_path, "nbsync.sqlite3")}',
243
+ SA_URL_SRC_LOCAL = f'sqlite+pysqlite:///{os.path.join(self.instance_path, "src.sqlite3")}',
244
+ SA_URL_DST_LOCAL = f'sqlite+pysqlite:///{os.path.join(self.instance_path, "dst.sqlite3")}',
245
+ )
246
+
247
+ def from_mapping(self, mapping: dict) -> None:
248
+ self.config = self.config | mapping
249
+
250
+ def from_pyfile(self, config_file: str = '~/conf/nbsync.cfg') -> None:
251
+ # read the config file into dict if exists then merge
252
+ abs_cfg = os.path.expanduser(config_file)
253
+ try:
254
+ with open(abs_cfg, 'r') as fp:
255
+ for line in fp:
256
+ line = line.strip()
257
+ if line.startswith('#') or not line:
258
+ continue
259
+ # Split only on the first '=' to allow '=' in the value
260
+ try:
261
+ key, val = line.split('=', 1)
262
+ self.config[key.strip().strip("'").strip('"')] = val.strip().strip("'").strip('"')
263
+ except ValueError:
264
+ # Handle lines that might not have an '='
265
+ continue
266
+ except FileNotFoundError:
267
+ self._logger.debug(f'[{config_file}] does not exist')
268
+
269
+ def from_prefixed_env(self, prefix: str = 'UC'):
270
+ # read environment variables with the given prefix and merge into config
271
+ prefix_len = len(prefix) + 1 # +1 for the underscore
272
+ for key, value in os.environ.items():
273
+ if key.startswith(f'{prefix}_'):
274
+ config_key = key[prefix_len:] # remove the prefix and underscore
275
+ self.config[config_key] = value
276
+ # lastly, attempt to convert 'true'/'false' to boolean
277
+ if value.lower() == 'true':
278
+ self.config[config_key] = True
279
+ elif value.lower() == 'false':
280
+ self.config[config_key] = False
281
+
282
+ def __repr__(self):
283
+ return convert.obj_to_str(self)
284
+
ubercode/utils/logging.py CHANGED
@@ -183,7 +183,7 @@ class ColorLogger:
183
183
  c_msg = str(msg)
184
184
  if self.color_output and color:
185
185
  c_msg = color + c_msg + TermColor.ENDC
186
- if msg == self.repeat_msg:
186
+ if str(msg) == self.repeat_msg:
187
187
  # the first time we start repeating track the indent level
188
188
  if not self.repeat_cnt:
189
189
  if indent is not None:
@@ -1,14 +0,0 @@
1
- ubercode/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- ubercode/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- ubercode/utils/convert.py,sha256=YWIacPg3MaUTGSANZ2yzxanIkUCH2oyqOR6Wvtz91Fg,11371
4
- ubercode/utils/cursor.py,sha256=zHqbmUavCF0l7ck_Tu4PfgSzRO762ULKHYsnqa3r0uY,1118
5
- ubercode/utils/data.py,sha256=ima4E8Do8O2UevS9mr-I3dc2m_GCE72QNL3qzaLHzlM,4348
6
- ubercode/utils/dataframe.py,sha256=JLeTj401KuiF0LZax-DnYChKNArvlhRkX6cOInRELmE,870
7
- ubercode/utils/environment.py,sha256=jblV5_1V58lkiiB44T-Bt39tMPyyKzmCiR1xgmjRXhQ,10854
8
- ubercode/utils/logging.py,sha256=e35pXVFN-rNNK3Lg6rM4DB9DHS-91MIBHq03AOAuRUs,9199
9
- ubercode/utils/urls.py,sha256=PaksDHVg_aSXEqcN4SlLgY-erqeMCNw8mYK9qt3q05I,9652
10
- python_ubercode_utils-2.0.0.dist-info/LICENSE,sha256=lch0WEJaqJY3C5aCYSr0u6Gw0set96a2fp9ZWJRYuR8,1069
11
- python_ubercode_utils-2.0.0.dist-info/METADATA,sha256=6xfZmgwxMxgpXobISKa3iRZGWOCPj5x4o1VZNpeA9VA,1223
12
- python_ubercode_utils-2.0.0.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
13
- python_ubercode_utils-2.0.0.dist-info/top_level.txt,sha256=5BojzbvNCpPkFXcVQVr7cfovhbYQYAlMKgiHSMgi7VU,9
14
- python_ubercode_utils-2.0.0.dist-info/RECORD,,