python-backpack 1.0.5__tar.gz → 2.0.0__tar.gz

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 (36) hide show
  1. python_backpack-2.0.0/PKG-INFO +12 -0
  2. {python-backpack-1.0.5 → python_backpack-2.0.0}/backpack/cache.py +23 -19
  3. {python-backpack-1.0.5 → python_backpack-2.0.0}/backpack/custom_errors.py +8 -7
  4. {python-backpack-1.0.5 → python_backpack-2.0.0}/backpack/file_utils.py +27 -19
  5. {python-backpack-1.0.5 → python_backpack-2.0.0}/backpack/folder_utils.py +14 -13
  6. {python-backpack-1.0.5 → python_backpack-2.0.0}/backpack/json_metadata.py +32 -35
  7. {python-backpack-1.0.5 → python_backpack-2.0.0}/backpack/json_user_settings.py +24 -18
  8. {python-backpack-1.0.5 → python_backpack-2.0.0}/backpack/json_utils.py +14 -10
  9. {python-backpack-1.0.5 → python_backpack-2.0.0}/backpack/logger.py +2 -2
  10. {python-backpack-1.0.5 → python_backpack-2.0.0}/backpack/patterns.py +5 -3
  11. {python-backpack-1.0.5 → python_backpack-2.0.0}/backpack/strings.py +45 -31
  12. {python-backpack-1.0.5 → python_backpack-2.0.0}/backpack/test_utils.py +5 -5
  13. {python-backpack-1.0.5 → python_backpack-2.0.0}/backpack/version.py +8 -2
  14. python_backpack-2.0.0/pyproject.toml +22 -0
  15. python-backpack-1.0.5/MANIFEST.in +0 -1
  16. python-backpack-1.0.5/PKG-INFO +0 -74
  17. python-backpack-1.0.5/README.md +0 -53
  18. python-backpack-1.0.5/python_backpack.egg-info/PKG-INFO +0 -74
  19. python-backpack-1.0.5/python_backpack.egg-info/SOURCES.txt +0 -32
  20. python-backpack-1.0.5/python_backpack.egg-info/dependency_links.txt +0 -1
  21. python-backpack-1.0.5/python_backpack.egg-info/top_level.txt +0 -2
  22. python-backpack-1.0.5/setup.cfg +0 -4
  23. python-backpack-1.0.5/setup.py +0 -37
  24. python-backpack-1.0.5/tests/__init__.py +0 -0
  25. python-backpack-1.0.5/tests/test_cache.py +0 -27
  26. python-backpack-1.0.5/tests/test_errors.py +0 -50
  27. python-backpack-1.0.5/tests/test_file_utils.py +0 -49
  28. python-backpack-1.0.5/tests/test_folder_utils.py +0 -96
  29. python-backpack-1.0.5/tests/test_json_user_settings.py +0 -76
  30. python-backpack-1.0.5/tests/test_json_utils.py +0 -46
  31. python-backpack-1.0.5/tests/test_jsonmd.py +0 -90
  32. python-backpack-1.0.5/tests/test_misc.py +0 -54
  33. python-backpack-1.0.5/tests/test_strings.py +0 -94
  34. python-backpack-1.0.5/tests/test_test_utils.py +0 -45
  35. {python-backpack-1.0.5 → python_backpack-2.0.0}/LICENSE +0 -0
  36. {python-backpack-1.0.5 → python_backpack-2.0.0}/backpack/__init__.py +0 -0
@@ -0,0 +1,12 @@
1
+ Metadata-Version: 2.4
2
+ Name: python-backpack
3
+ Version: 2.0.0
4
+ Summary: A collection of personal scripts for json, File/Folder Operations, String Validation, Custom Errors, Cache and stuff.
5
+ License-File: LICENSE
6
+ Author: Maximiliano Rocamora
7
+ Requires-Python: >=3.11,<4.0
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Programming Language :: Python :: 3.14
@@ -3,17 +3,20 @@
3
3
  # Maximiliano Rocamora / maxirocamora@gmail.com
4
4
  # https://github.com/MaxRocamora/python-backpack
5
5
  # ----------------------------------------------------------------------------------------
6
+ from datetime import datetime, timedelta, timezone
6
7
  from functools import lru_cache, wraps
7
- from datetime import datetime, timedelta
8
- from datetime import timezone
8
+ from typing import Any, Callable, TypeVar, cast
9
9
 
10
10
  from backpack.logger import get_logger
11
11
 
12
12
  log = get_logger('Python Backpack - Cache')
13
13
 
14
+ F = TypeVar('F', bound=Callable[..., Any])
15
+
16
+
17
+ def timed_lru_cache(seconds: int, maxsize: int = 128) -> Callable[[F], F]:
18
+ """Lru_cache with expiration time.
14
19
 
15
- def timed_lru_cache(seconds: int, maxsize: int = 128):
16
- ''' lru_cache with expiration time
17
20
  Args:
18
21
  seconds (int): expiration time in seconds
19
22
  maxsize (int): maxsize for lru_cache
@@ -34,34 +37,35 @@ def timed_lru_cache(seconds: int, maxsize: int = 128):
34
37
  # * to clear the cache, use force_clear=True on the function call
35
38
  my_function(force_clear=True)
36
39
 
37
- '''
38
-
39
- def wrapper_cache(func):
40
+ """
40
41
 
41
- func = lru_cache(maxsize=maxsize)(func)
42
- func.lifetime = timedelta(seconds=seconds)
43
- func.expiration = datetime.now(timezone.utc) + func.lifetime
42
+ def wrapper_cache(func: F) -> F:
43
+ cached_func = cast(Any, lru_cache(maxsize=maxsize)(func))
44
+ cached_func.lifetime = timedelta(seconds=seconds)
45
+ cached_func.expiration = datetime.now(timezone.utc) + cached_func.lifetime
44
46
 
45
47
  @wraps(func)
46
48
  def wrapped_func(*args, force_clear: bool = False, show_log: bool = False, **kwargs):
47
- ''' wrapper function for lru_cache with expiration time
49
+ """Wrapper function for lru_cache with expiration time.
50
+
48
51
  Args:
52
+ *args: function arguments
49
53
  force_clear (bool): forces a clear cache
50
54
  show_log (bool): show log on clear
55
+ **kwargs: function keyword arguments
51
56
  Returns:
52
57
  function result
53
- '''
54
-
55
- if force_clear or datetime.now(timezone.utc) >= func.expiration:
58
+ """
56
59
 
60
+ if force_clear or datetime.now(timezone.utc) >= cached_func.expiration:
57
61
  if show_log:
58
- log.debug(f'Cache cleared for {func.__name__}')
62
+ log.debug(f'Cache cleared for {cached_func.__name__}')
59
63
 
60
- func.cache_clear()
61
- func.expiration = datetime.now(timezone.utc) + func.lifetime
64
+ cached_func.cache_clear()
65
+ cached_func.expiration = datetime.now(timezone.utc) + cached_func.lifetime
62
66
 
63
- return func(*args, **kwargs)
67
+ return cached_func(*args, **kwargs)
64
68
 
65
- return wrapped_func
69
+ return cast(F, wrapped_func)
66
70
 
67
71
  return wrapper_cache
@@ -4,33 +4,34 @@
4
4
  # https://github.com/MaxRocamora/python-backpack
5
5
  # ----------------------------------------------------------------------------------------
6
6
 
7
- class EnvironmentVariableNotFound(Exception):
8
7
 
8
+ class EnvironmentVariableNotFoundError(Exception):
9
9
  def __init__(self, var_name: str) -> None:
10
- '''Error Raised when a required environment variable is missing from os.
10
+ """Error Raised when a required environment variable is missing from os.
11
11
 
12
12
  Args:
13
13
  var_name (str): name of the required variable missing
14
- '''
14
+ """
15
15
  self.var_name = var_name
16
16
  self.message = f'Required Environment Variable [{var_name}] not found.'
17
17
  super().__init__(self.message)
18
18
 
19
19
  def __str__(self):
20
+ """Return the error message."""
20
21
  return self.message
21
22
 
22
23
 
23
- class ApplicationNotFound(Exception):
24
-
24
+ class ApplicationNotFoundError(Exception):
25
25
  def __init__(self, app_name: str) -> None:
26
- '''Error Raised when an Application Name required is not found.
26
+ """Error Raised when an Application Name required is not found.
27
27
 
28
28
  Args:
29
29
  app_name (str): name of the required application missing
30
- '''
30
+ """
31
31
  self.app_name = app_name
32
32
  self.message = f'Application ({app_name}) not found.'
33
33
  super().__init__(self.message)
34
34
 
35
35
  def __str__(self):
36
+ """Return the error message."""
36
37
  return self.message
@@ -12,19 +12,21 @@ log = get_logger('Python Backpack - FileUtils')
12
12
 
13
13
 
14
14
  def replace_strings_in_file(ascii_file: str, strings: list, new_string: str) -> None:
15
- ''' Opens ascii file and replaces all occurrences from strings into new_string.
15
+ """Opens ascii file and replaces all occurrences from strings into new_string.
16
+
16
17
  In this class we use a full path to avoid use of os.dirname, which
17
18
  causes string encode problems.
19
+
18
20
  Args:
19
- ascii_file (fullpath) file to open
20
- strings (list) strings to replace
21
- new_string (string) new string or path to set
22
- '''
21
+ ascii_file: (fullpath string) file to open
22
+ strings: (list) strings to replace
23
+ new_string: (string) new string or path to set
24
+ """
23
25
 
24
26
  # force forward slashes
25
- new_string = new_string.replace("\\", "/")
27
+ new_string = new_string.replace('\\', '/')
26
28
 
27
- log.info(f"Replacing Strings, Opening File: {ascii_file}")
29
+ log.info(f'Replacing Strings, Opening File: {ascii_file}')
28
30
 
29
31
  with open(ascii_file) as f:
30
32
  file_data = f.read()
@@ -37,37 +39,43 @@ def replace_strings_in_file(ascii_file: str, strings: list, new_string: str) ->
37
39
  with open(ascii_file, 'w') as f:
38
40
  f.write(file_data)
39
41
  f.close()
40
- log.info(f"Closing File: {ascii_file}")
42
+ log.info(f'Closing File: {ascii_file}')
43
+
41
44
 
45
+ def remove_line_from_file(ascii_file: str, strings: list, verbose: bool = False) -> None:
46
+ """Removes given lines from ascii file.
42
47
 
43
- def remove_line_from_file(ascii_file: str, strings: str) -> None:
44
- ''' removes given lines from ascii file.
45
48
  Args:
46
- ascii_file (path) ASCII file to process
47
- strings (list) match lines to remove
48
- '''
49
+ ascii_file: (string path) ASCII file to process
50
+ strings: (list) match lines to remove
51
+ verbose: (bool) if true, prints removed lines
52
+ """
49
53
 
50
54
  with open(ascii_file) as f:
51
55
  file_content = f.read().splitlines()
52
56
 
53
57
  for line in file_content:
54
- print('file line', line)
58
+ if verbose:
59
+ log.info(f'Checking line: {line}')
55
60
  with contextlib.suppress(ValueError):
56
61
  if line in strings:
62
+ if verbose:
63
+ log.info(f'Removing line: {line}')
57
64
  file_content.pop(file_content.index(line))
58
65
 
59
- with open(ascii_file, "w") as f:
60
- contents = "\n".join(file_content)
66
+ with open(ascii_file, 'w') as f:
67
+ contents = '\n'.join(file_content)
61
68
  f.write(contents)
62
69
 
63
70
 
64
71
  def file_is_writeable(filepath: str) -> bool:
65
- ''' checks if a file is locked and can be overwritten
72
+ """Checks if a file is locked and can be overwritten.
73
+
66
74
  Args:
67
- filepath (str)) file to check
75
+ filepath: (str) file to check
68
76
  Returns:
69
77
  bool : true if file is writeable
70
- '''
78
+ """
71
79
  try:
72
80
  with open(filepath, 'r+') as _:
73
81
  return True
@@ -14,38 +14,39 @@ log = get_logger('Python Backpack - FolderUtils')
14
14
 
15
15
 
16
16
  def browse_folder(folder: str) -> bool:
17
- ''' Open windows explorer on folder
17
+ """Open windows explorer on folder.
18
+
18
19
  Args:
19
- folder (path) folder to open
20
- '''
20
+ folder: (string path) folder to open
21
+ """
21
22
  if folder and os.path.isdir(folder):
22
- subprocess.Popen(f"explorer {os.path.abspath(folder)}")
23
+ subprocess.Popen(f'explorer {os.path.abspath(folder)}')
23
24
  return True
24
25
 
25
- log.warning(f"Unable to open folder {folder}")
26
+ log.warning(f'Unable to open folder {folder}')
26
27
  return False
27
28
 
28
29
 
29
30
  def create_folders(folders: list, force_empty: bool = False, verbose: bool = False):
30
- ''' Creates multiple folders on disc.
31
+ """Creates multiple folders on disc.
31
32
 
32
33
  Args:
33
34
  folders (list): folder list
34
35
  force_empty (bool, optional): forces clearing folder content. Defaults to False.
35
36
  verbose (bool, optional):shows log. Defaults to False.
36
- '''
37
+ """
37
38
  for folder in folders:
38
39
  create_folder(folder, force_empty=force_empty, verbose=verbose)
39
40
 
40
41
 
41
42
  def create_folder(path: str, force_empty: bool = False, verbose: bool = True):
42
- '''creates a folder
43
+ """Creates a folder.
43
44
 
44
45
  Args:
45
46
  path (str): folder path
46
47
  force_empty (bool, optional): forces clearing folder content. Defaults to False.
47
48
  verbose (bool, optional): show log. Defaults to True.
48
- '''
49
+ """
49
50
  abspath = os.path.abspath(path)
50
51
  if verbose:
51
52
  log.info(f'Creating Folder {abspath}')
@@ -56,14 +57,14 @@ def create_folder(path: str, force_empty: bool = False, verbose: bool = True):
56
57
  elif force_empty:
57
58
  remove_files_in_dir(abspath)
58
59
  except OSError as e:
59
- log.warning(f"Unable to create folder: {path}")
60
+ log.warning(f'Unable to create folder: {path}')
60
61
  log.error(str(e))
61
62
 
62
63
  return True
63
64
 
64
65
 
65
66
  def remove_files_in_dir(path: str):
66
- ''' clears all content in given directory '''
67
+ """Clears all content in given directory."""
67
68
  for root, dirs, files in os.walk(path):
68
69
  for f in files:
69
70
  os.unlink(os.path.join(root, f))
@@ -72,12 +73,12 @@ def remove_files_in_dir(path: str):
72
73
 
73
74
 
74
75
  def recursive_dir_copy(source_path: str, target_path: str):
75
- ''' Copy all files src dir to dest dir, including sub-directories.
76
+ """Copy all files src dir to dest dir, including sub-directories.
76
77
 
77
78
  Args:
78
79
  source_path (str): source path
79
80
  target_path (str): destination path
80
- '''
81
+ """
81
82
 
82
83
  create_folder(source_path)
83
84
  create_folder(target_path)
@@ -3,62 +3,59 @@
3
3
  # Maximiliano Rocamora / maxirocamora@gmail.com
4
4
  # https://github.com/MaxRocamora/python-backpack
5
5
  # ----------------------------------------------------------------------------------------
6
- import sys
6
+ import inspect
7
7
  import os
8
+ import platform
9
+ import sys
8
10
  import time
9
- import inspect
10
11
  from datetime import datetime
11
- import platform
12
12
  from typing import Any
13
13
 
14
14
  from backpack.json_utils import json_load, json_save
15
15
  from backpack.version import version
16
16
 
17
17
 
18
- class JsonMetaFile():
19
-
20
- PREFIX = "MD_"
18
+ class JsonMetaFile:
19
+ PREFIX = 'MD_'
21
20
 
22
21
  def __init__(self, name: str, path: str) -> None:
23
- '''saves/load a class/dict as a json metadata file
22
+ """saves/load a class/dict as a json metadata file.
24
23
 
25
24
  Args:
26
25
  name (str): name of the file/class
27
26
  path (str, optional): filepath. Defaults to None.
28
- '''
27
+ """
29
28
  self._name = name
30
29
  self._path = path
31
- self._data = {
32
- "_about": {'package': 'python-backpack', 'version': self.version}
33
- }
30
+ self._data = {'_about': {'package': 'python-backpack', 'version': self.version}}
34
31
 
35
32
  @property
36
33
  def name(self) -> str:
37
- ''' name of this metadata class'''
34
+ """Name of this metadata class."""
38
35
  return self._name
39
36
 
40
37
  @property
41
38
  def version(self) -> str:
42
- ''' version of this metadata class'''
39
+ """Version of this metadata class."""
43
40
  return version
44
41
 
45
42
  @property
46
43
  def filename(self) -> str:
47
- ''' Returns default filename with prefix and extension '''
44
+ """Returns default filename with prefix and extension."""
48
45
  return self.PREFIX + self.name + '.json'
49
46
 
50
47
  @property
51
48
  def filepath(self) -> str:
52
- ''' full json metadata filepath '''
49
+ """Full json metadata filepath."""
53
50
  return os.path.join(self.path, self.filename)
54
51
 
55
52
  @property
56
53
  def path(self) -> str:
57
- ''' base path location of metadata json file '''
54
+ """Base path location of metadata json file."""
58
55
  return self._path
59
56
 
60
57
  def has_file(self) -> bool:
61
- ''' returns true if file exists '''
58
+ """Returns true if file exists."""
62
59
  return os.path.exists(self.filepath)
63
60
 
64
61
  # ------------------------------------------------------------------------------------
@@ -66,20 +63,20 @@ class JsonMetaFile():
66
63
  # ------------------------------------------------------------------------------------
67
64
 
68
65
  def load(self) -> None:
69
- ''' loads metadata from disk '''
66
+ """Loads metadata from disk."""
70
67
  self._data = json_load(self.filepath) if self.has_file() else {}
71
68
 
72
69
  def insert(self, key: str, value: Any) -> None:
73
- ''' inserts value into metadata '''
70
+ """Inserts value into metadata."""
74
71
  self._data[key] = value
75
72
 
76
73
  def remove(self, key: str) -> None:
77
- ''' remove key from metadata '''
74
+ """Remove key from metadata."""
78
75
  if key in self._data.keys():
79
76
  del self._data[key]
80
77
 
81
78
  def save(self) -> None:
82
- ''' Save current metadata into json file. '''
79
+ """Save current metadata into json file."""
83
80
  if not os.path.exists(self.path):
84
81
  os.makedirs(self.path)
85
82
 
@@ -91,12 +88,12 @@ class JsonMetaFile():
91
88
  # ------------------------------------------------------------------------------------
92
89
 
93
90
  def load_as_class(self) -> type:
94
- ''' returns the metadata dict as a class obj '''
95
- metadataClass = type(self.name, (), self._data)
96
- return metadataClass
91
+ """Returns the metadata dict as a class obj."""
92
+ metadata_class = type(self.name, (), self._data)
93
+ return metadata_class
97
94
 
98
95
  def insert_class(self, _class: type) -> None:
99
- ''' load all attributes from a given class into this class metadata '''
96
+ """Load all attributes from a given class into this class metadata."""
100
97
  attributes = {}
101
98
  for name in dir(_class):
102
99
  value = getattr(_class, name)
@@ -110,7 +107,7 @@ class JsonMetaFile():
110
107
  # ------------------------------------------------------------------------------------
111
108
 
112
109
  def _system_data(self) -> dict:
113
- ''' add system metadata to the default data before save '''
110
+ """Add system metadata to the default data before save."""
114
111
  return {
115
112
  'name': self.name,
116
113
  'app': os.path.basename(sys.executable),
@@ -121,15 +118,15 @@ class JsonMetaFile():
121
118
  }
122
119
 
123
120
  def _current_time_metadata(self) -> dict:
124
- ''' Get export time info. '''
125
- ftime = time.strftime("%Y,%b,%d,%j,%H:%M", time.localtime())
126
- times = ftime.split(",")
121
+ """Get export time info."""
122
+ ftime = time.strftime('%Y,%b,%d,%j,%H:%M', time.localtime())
123
+ times = ftime.split(',')
127
124
  td = {
128
- "year": times[0],
129
- "month": times[1],
130
- "day": times[2],
131
- "year_day": times[3],
132
- "time": times[4],
133
- 'save_time': datetime.now().ctime()
125
+ 'year': times[0],
126
+ 'month': times[1],
127
+ 'day': times[2],
128
+ 'year_day': times[3],
129
+ 'time': times[4],
130
+ 'save_time': datetime.now().ctime(),
134
131
  }
135
132
  return td
@@ -1,29 +1,32 @@
1
1
  # ----------------------------------------------------------------------------------------
2
2
  # Json Settings Class
3
3
  # This class handle load/save json files on win/linux local user folder
4
- ''' Usage:
4
+
5
+ """Usage.
6
+
5
7
  us = JsonUserSettings('my_app')
6
8
  us.save(someDict)
7
9
  data = us.load()
8
10
 
9
- '''
11
+ """
12
+
10
13
  # ----------------------------------------------------------------------------------------
11
14
  import os
12
15
 
16
+ from backpack.json_utils import json_load, json_save
13
17
  from backpack.logger import get_logger
14
- from backpack.json_utils import json_save, json_load
15
18
 
16
19
  log = get_logger('Python Backpack - UserSettings')
17
20
 
18
21
 
19
- class JsonUserSettings():
22
+ class JsonUserSettings:
20
23
  def __init__(self, folder: str, name: str) -> None:
21
- '''Manages saving/loading json file on local user folder
24
+ """Manages saving/loading json file on local user folder.
22
25
 
23
26
  Args:
24
27
  folder (str): name of sub folder inside user path. Defaults to 'json_settings'.
25
- filename (str): name used for the json file. Defaults to 'user_data'.
26
- '''
28
+ name (str): name used for the json file. Defaults to 'user_data'.
29
+ """
27
30
  self.name = name
28
31
  self.folder = folder
29
32
  self._user_data = {}
@@ -31,18 +34,18 @@ class JsonUserSettings():
31
34
 
32
35
  @property
33
36
  def filepath(self) -> str:
34
- ''' Returns user filepath '''
37
+ """Returns user filepath."""
35
38
  path = os.path.join(self.os_user_folder, self.folder, f'{self.name}.json')
36
39
  return os.path.abspath(path)
37
40
 
38
41
  @property
39
42
  def os_user_folder(self) -> str:
40
- ''' returns os users home directory '''
43
+ """Returns os users home directory."""
41
44
  return os.path.expanduser('~')
42
45
 
43
46
  @property
44
47
  def user_data(self) -> dict:
45
- ''' override this property to modify saving dict '''
48
+ """Override this property to modify saving dict."""
46
49
  return self._user_data
47
50
 
48
51
  @user_data.setter
@@ -50,20 +53,23 @@ class JsonUserSettings():
50
53
  self._user_data = v
51
54
 
52
55
  def _verify_path(self) -> bool:
53
- ''' Checks for target directory or make it '''
56
+ """Checks for target directory or make it."""
54
57
  path = os.path.dirname(self.filepath)
55
58
  if not os.path.exists(path):
56
59
  os.makedirs(path)
57
60
 
58
61
  return True
59
62
 
60
- def save_settings(self, data=False) -> bool:
61
- ''' Saves a dictionary into a json file (os user path)
63
+ def save_settings(self, data: dict | None = None) -> bool | None:
64
+ """Saves a dictionary into a json file (os user path).
65
+
62
66
  Args:
63
- data (dictionary) : info dictionary to save, if set to False,
67
+ data (dictionary): info dictionary to save, if not provided,
64
68
  saves instead local self.user_data property
65
- '''
66
- if not data:
69
+ Returns:
70
+ bool | None: True if file was saved, False if error, None if no data to save.
71
+ """
72
+ if data is None:
67
73
  data = self.user_data
68
74
 
69
75
  r = json_save(data, self.filepath)
@@ -71,8 +77,8 @@ class JsonUserSettings():
71
77
  log.info('json settings file saved! [%s]', self.filepath)
72
78
  return r
73
79
 
74
- def load_settings(self) -> dict:
75
- ''' Load json file from path and returns its contents '''
80
+ def load_settings(self) -> dict | bool:
81
+ """Load json file from path and returns its contents."""
76
82
  try:
77
83
  return json_load(self.filepath)
78
84
  except OSError:
@@ -1,5 +1,5 @@
1
- import os
2
1
  import json
2
+ import os
3
3
 
4
4
  from backpack.logger import get_logger
5
5
 
@@ -7,33 +7,37 @@ log = get_logger('Python Backpack - JsonUtils')
7
7
 
8
8
 
9
9
  def json_load(json_file: str) -> dict:
10
- ''' Reads a json file
10
+ """Reads a json file.
11
+
11
12
  Args:
12
- json_file (filepath) json file to read data.
13
+ json_file: (string filepath) json file to read data.
14
+
13
15
  Returns:
14
16
  dict (file content)
15
- '''
17
+ """
16
18
  if not os.path.exists(json_file):
17
- raise OSError(f"json_load: File not found: {json_file}.")
19
+ raise OSError(f'json_load: File not found: {json_file}.')
18
20
 
19
21
  with open(json_file) as json_file_opened:
20
22
  try:
21
23
  value = json.load(json_file_opened)
22
24
  except ValueError as e:
23
25
  json_file_opened.close()
24
- raise OSError(f"{json_file} \n JSON File issue: {str(e)}") from e
26
+ raise OSError(f'{json_file} \n JSON File issue: {str(e)}') from e
25
27
 
26
28
  return value
27
29
 
28
30
 
29
31
  def json_save(data: dict, json_file: str) -> bool:
30
- ''' Saves a dictionary into a json file
32
+ """Saves a dictionary into a json file.
33
+
31
34
  Args:
32
- data (dict) : dictionary to save
33
- json_file (filepath) json file to save data.
35
+ data: (dict) dictionary to save
36
+ json_file: (string filepath) json file to save data.
37
+
34
38
  Returns:
35
39
  bool (True if success)
36
- '''
40
+ """
37
41
 
38
42
  if not os.path.exists(os.path.dirname(json_file)):
39
43
  os.makedirs(os.path.dirname(json_file))
@@ -1,8 +1,8 @@
1
1
  import logging
2
2
 
3
3
 
4
- def get_logger(name: str):
5
- ''' basic log'''
4
+ def get_logger(name: str) -> logging.Logger:
5
+ """Returns a logger object with a stream handler."""
6
6
  _log = logging.getLogger(name)
7
7
  _log.propagate = False
8
8
  _log.setLevel(logging.DEBUG)
@@ -5,8 +5,9 @@
5
5
  # ----------------------------------------------------------------------------------------
6
6
 
7
7
 
8
- class Singleton():
9
- ''' Python Singleton BaseClass
8
+ class Singleton:
9
+ """Python Singleton BaseClass.
10
+
10
11
  Usage:
11
12
 
12
13
  class MyClass(Singleton, otherClass):
@@ -14,11 +15,12 @@ class Singleton():
14
15
 
15
16
  obj = MyClass() # any new object will be taken from the same instance
16
17
 
17
- '''
18
+ """
18
19
 
19
20
  _instance = None
20
21
 
21
22
  def __new__(cls, *args, **kwargs):
23
+ """Singleton __new__ method."""
22
24
  if not isinstance(cls._instance, cls):
23
25
  # print(f'Initializing {cls.__name__}')
24
26
  cls._instance = object.__new__(cls)