log21 2.9.2__tar.gz → 2.10.1__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 (27) hide show
  1. {log21-2.9.2/src/log21.egg-info → log21-2.10.1}/PKG-INFO +5 -4
  2. {log21-2.9.2 → log21-2.10.1}/README.md +4 -3
  3. {log21-2.9.2 → log21-2.10.1}/pyproject.toml +17 -17
  4. {log21-2.9.2 → log21-2.10.1}/src/log21/Argparse.py +47 -12
  5. {log21-2.9.2 → log21-2.10.1}/src/log21/Argumentify.py +105 -15
  6. {log21-2.9.2 → log21-2.10.1}/src/log21/__init__.py +5 -3
  7. {log21-2.9.2 → log21-2.10.1/src/log21.egg-info}/PKG-INFO +5 -4
  8. {log21-2.9.2 → log21-2.10.1}/LICENSE.txt +0 -0
  9. {log21-2.9.2 → log21-2.10.1}/setup.cfg +0 -0
  10. {log21-2.9.2 → log21-2.10.1}/src/log21/Colors.py +0 -0
  11. {log21-2.9.2 → log21-2.10.1}/src/log21/CrashReporter/Formatters.py +0 -0
  12. {log21-2.9.2 → log21-2.10.1}/src/log21/CrashReporter/Reporters.py +0 -0
  13. {log21-2.9.2 → log21-2.10.1}/src/log21/CrashReporter/__init__.py +0 -0
  14. {log21-2.9.2 → log21-2.10.1}/src/log21/FileHandler.py +0 -0
  15. {log21-2.9.2 → log21-2.10.1}/src/log21/Formatters.py +0 -0
  16. {log21-2.9.2 → log21-2.10.1}/src/log21/Levels.py +0 -0
  17. {log21-2.9.2 → log21-2.10.1}/src/log21/Logger.py +0 -0
  18. {log21-2.9.2 → log21-2.10.1}/src/log21/LoggingWindow.py +0 -0
  19. {log21-2.9.2 → log21-2.10.1}/src/log21/Manager.py +0 -0
  20. {log21-2.9.2 → log21-2.10.1}/src/log21/PPrint.py +0 -0
  21. {log21-2.9.2 → log21-2.10.1}/src/log21/ProgressBar.py +0 -0
  22. {log21-2.9.2 → log21-2.10.1}/src/log21/StreamHandler.py +0 -0
  23. {log21-2.9.2 → log21-2.10.1}/src/log21/TreePrint.py +0 -0
  24. {log21-2.9.2 → log21-2.10.1}/src/log21.egg-info/SOURCES.txt +0 -0
  25. {log21-2.9.2 → log21-2.10.1}/src/log21.egg-info/dependency_links.txt +0 -0
  26. {log21-2.9.2 → log21-2.10.1}/src/log21.egg-info/requires.txt +0 -0
  27. {log21-2.9.2 → log21-2.10.1}/src/log21.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: log21
3
- Version: 2.9.2
3
+ Version: 2.10.1
4
4
  Summary: A simple logging package that helps you log colorized messages in Windows console.
5
5
  Author-email: "CodeWriter21(Mehrad Pooryoussof)" <CodeWriter21@gmail.com>
6
6
  License: Apache License 2.0
@@ -92,10 +92,11 @@ pip install git+https://github.com/MPCodeWriter21/log21
92
92
  Changes
93
93
  -------
94
94
 
95
- ### 2.9.2
95
+ ### 2.10.0
96
96
 
97
- + Added `Sequence[T]` as a supported type to the ColorizingArgumentParser.
98
- + Bug fixes.
97
+ + Added some exception classes to raise in the "argumentified" functions to show
98
+ *parser error* to the user: `ArgumentError`, `IncompatibleArguments`,
99
+ `RequiredArgument`, `TooFewArguments`
99
100
 
100
101
  [Full CHANGELOG](https://github.com/MPCodeWriter21/log21/blob/master/CHANGELOG.md)
101
102
 
@@ -61,10 +61,11 @@ pip install git+https://github.com/MPCodeWriter21/log21
61
61
  Changes
62
62
  -------
63
63
 
64
- ### 2.9.2
64
+ ### 2.10.0
65
65
 
66
- + Added `Sequence[T]` as a supported type to the ColorizingArgumentParser.
67
- + Bug fixes.
66
+ + Added some exception classes to raise in the "argumentified" functions to show
67
+ *parser error* to the user: `ArgumentError`, `IncompatibleArguments`,
68
+ `RequiredArgument`, `TooFewArguments`
68
69
 
69
70
  [Full CHANGELOG](https://github.com/MPCodeWriter21/log21/blob/master/CHANGELOG.md)
70
71
 
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "log21"
7
7
  authors = [
8
- {name = "CodeWriter21(Mehrad Pooryoussof)", email = "CodeWriter21@gmail.com"}
8
+ {name = "CodeWriter21(Mehrad Pooryoussof)", email = "CodeWriter21@gmail.com"}
9
9
  ]
10
10
  description = "A simple logging package that helps you log colorized messages in Windows console."
11
11
  readme = {file = "README.md", content-type = "text/markdown"}
@@ -13,20 +13,20 @@ requires-python = ">=3.8"
13
13
  keywords = ['python', 'log', 'colorize', 'color', 'logging', 'Python3', 'CodeWriter21']
14
14
  license = {text = "Apache License 2.0"}
15
15
  classifiers = [
16
- "Intended Audience :: Developers",
17
- "Programming Language :: Python :: 3",
18
- "Programming Language :: Python :: 3.7",
19
- "Programming Language :: Python :: 3.10",
20
- "Programming Language :: Python :: 3.11",
21
- "Operating System :: Unix",
22
- "Operating System :: Microsoft :: Windows",
23
- "Operating System :: MacOS :: MacOS X"
16
+ "Intended Audience :: Developers",
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3.7",
19
+ "Programming Language :: Python :: 3.10",
20
+ "Programming Language :: Python :: 3.11",
21
+ "Operating System :: Unix",
22
+ "Operating System :: Microsoft :: Windows",
23
+ "Operating System :: MacOS :: MacOS X"
24
24
  ]
25
25
  dependencies = [
26
- "webcolors",
27
- "docstring-parser"
26
+ "webcolors",
27
+ "docstring-parser"
28
28
  ]
29
- version = "2.9.2"
29
+ version = "2.10.1"
30
30
 
31
31
  [tool.setuptools.packages.find]
32
32
  where = ["src"]
@@ -43,11 +43,11 @@ dev = ["yapf", "isort", "docformatter", "pylint", "json5", "pytest"]
43
43
  max-line-length = 88
44
44
 
45
45
  disable = [
46
- "too-few-public-methods",
47
- "too-many-arguments",
48
- "protected-access",
49
- "too-many-locals",
50
- "fixme",
46
+ "too-few-public-methods",
47
+ "too-many-arguments",
48
+ "protected-access",
49
+ "too-many-locals",
50
+ "fixme",
51
51
  ]
52
52
 
53
53
  [tool.pylint.design]
@@ -280,15 +280,28 @@ class ColorizingHelpFormatter(_argparse.HelpFormatter):
280
280
  group_actions = set()
281
281
  inserts = {}
282
282
  for group in groups:
283
+ if not group._group_actions:
284
+ raise ValueError(f'empty group {group}')
285
+
283
286
  try:
284
287
  start = actions.index(group._group_actions[0])
285
288
  except ValueError:
286
289
  continue
287
290
  else:
288
- end = start + len(group._group_actions)
291
+ group_action_count = len(group._group_actions)
292
+ end = start + group_action_count
289
293
  if actions[start:end] == group._group_actions:
294
+
295
+ suppressed_actions_count = 0
290
296
  for action in group._group_actions:
291
297
  group_actions.add(action)
298
+ if action.help is _argparse.SUPPRESS:
299
+ suppressed_actions_count += 1
300
+
301
+ exposed_actions_count = group_action_count - suppressed_actions_count
302
+ if not exposed_actions_count:
303
+ continue
304
+
292
305
  if not group.required:
293
306
  if start in inserts:
294
307
  inserts[start] += ' ['
@@ -298,7 +311,7 @@ class ColorizingHelpFormatter(_argparse.HelpFormatter):
298
311
  inserts[end] += ']'
299
312
  else:
300
313
  inserts[end] = ']'
301
- else:
314
+ elif exposed_actions_count > 1:
302
315
  if start in inserts:
303
316
  inserts[start] += ' ('
304
317
  else:
@@ -941,7 +954,22 @@ class ColorizingArgumentParser(_argparse.ArgumentParser, _ActionsContainer):
941
954
 
942
955
  # get the optional identified at this index
943
956
  option_tuple = option_string_indices[start_index]
944
- action, option_string, explicit_arg = option_tuple
957
+ if len(option_tuple) == 3:
958
+ action, option_string, explicit_arg = option_tuple
959
+ sep = None
960
+ elif len(option_tuple) == 4:
961
+ action, option_string, sep, explicit_arg = option_tuple
962
+ else:
963
+ # Tell the user that there seem to have been a change in argparse module
964
+ # and if they see this error they should immediately report it in an
965
+ # issue at GitHub.com/MPCodeWriter21/log21 with their Python version
966
+ raise ValueError(
967
+ 'Unknown option tuple length, please report this issue at: '
968
+ 'https://GitHub.com/MPCodeWriter21/log21\n'
969
+ f'Python version: {_sys.version}'
970
+ f'Option tuple: {option_tuple}'
971
+ f'log21 version: {_log21.__version__}'
972
+ )
945
973
 
946
974
  # identify additional optionals in the same arg string
947
975
  # (e.g. -xyz is the same as -x -y -z if no args are required)
@@ -964,20 +992,27 @@ class ColorizingArgumentParser(_argparse.ArgumentParser, _ActionsContainer):
964
992
  # of the tail of the option string
965
993
  chars = self.prefix_chars
966
994
  if arg_count == 0 and option_string[1] not in chars:
995
+ if sep or explicit_arg[0] in chars:
996
+ msg = _gettext('ignored explicit argument %r')
997
+ raise _argparse.ArgumentError(action, msg % explicit_arg)
967
998
  action_tuples.append((action, [], option_string))
968
999
  char = option_string[0]
969
1000
  option_string = char + explicit_arg[0]
970
- new_explicit_arg = explicit_arg[1:] or None
971
1001
  optionals_map = self._option_string_actions
972
1002
  if option_string in optionals_map:
973
1003
  action = optionals_map[option_string]
974
- explicit_arg = new_explicit_arg
1004
+ explicit_arg = explicit_arg[1:]
1005
+ if not explicit_arg:
1006
+ sep = explicit_arg = None
1007
+ elif explicit_arg[0] == '=':
1008
+ sep = '='
1009
+ explicit_arg = explicit_arg[1:]
1010
+ else:
1011
+ sep = ''
975
1012
  else:
976
- msg = _gettext(
977
- f'ignored explicit argument {explicit_arg!r}'
978
- )
979
- raise _argparse.ArgumentError(action, msg)
980
-
1013
+ extras.append(char + explicit_arg)
1014
+ stop = start_index + 1
1015
+ break
981
1016
  # if the action expect exactly one argument, we've
982
1017
  # successfully matched the option; exit the loop
983
1018
  elif arg_count == 1:
@@ -989,8 +1024,8 @@ class ColorizingArgumentParser(_argparse.ArgumentParser, _ActionsContainer):
989
1024
  # error if a double-dash option did not use the
990
1025
  # explicit argument
991
1026
  else:
992
- msg = _gettext(f'ignored explicit argument {explicit_arg!r}')
993
- raise _argparse.ArgumentError(action, msg)
1027
+ msg = _gettext('ignored explicit argument %r')
1028
+ raise _argparse.ArgumentError(action, msg % explicit_arg)
994
1029
 
995
1030
  # if there is no explicit argument, try to match the
996
1031
  # optional's string arguments with the following strings
@@ -18,7 +18,8 @@ import log21.Argparse as _Argparse
18
18
  __all__ = [
19
19
  'argumentify', 'ArgumentifyError', 'ArgumentTypeError', 'FlagGenerationError',
20
20
  'RESERVED_FLAGS', 'Callable', 'Argument', 'FunctionInfo', 'generate_flag',
21
- 'normalize_name', 'normalize_name_to_snake_case'
21
+ 'normalize_name', 'normalize_name_to_snake_case', 'ArgumentError',
22
+ 'IncompatibleArguments', 'RequiredArgument', 'TooFewArguments'
22
23
  ]
23
24
 
24
25
  Callable = _Union[_Callable[..., _Any], _Callable[..., _Coroutine[_Any, _Any, _Any]]]
@@ -76,6 +77,90 @@ class FlagGenerationError(ArgumentifyError, RuntimeError):
76
77
  self.arg_name = arg_name
77
78
 
78
79
 
80
+ class ArgumentError(ArgumentifyError):
81
+ """Base of errors to raise in the argumentified functions to raise parser errors."""
82
+
83
+ def __init__(self, *args, message: _Optional[str] = None):
84
+ """Initialize the exception.
85
+
86
+ :param args: The arguments that have a problem.
87
+ :param message: The error message to show.
88
+ """
89
+ if message is None:
90
+ if args:
91
+ if len(args) > 1:
92
+ message = "There is a problem with the arguments: " + ', '.join(
93
+ f"`{arg}`" for arg in args
94
+ )
95
+ else:
96
+ message = "The argument `" + args[0] + "` is invalid."
97
+ self.message = message
98
+ self.arguments = args
99
+
100
+
101
+ class IncompatibleArguments(ArgumentError):
102
+ """Raise when the user has used arguments that are incompatible with each other."""
103
+
104
+ def __init__(self, *args, message: _Optional[str] = None):
105
+ """Initialize the exception.
106
+
107
+ :param args: The arguments that are incompatible.
108
+ :param message: The error message to show.
109
+ """
110
+ super().__init__(*args, message)
111
+ if message is None:
112
+ if args:
113
+ if len(args) > 1:
114
+ message = "You cannot use all these together: " + ', '.join(
115
+ f"`{arg}`" for arg in args
116
+ )
117
+ else:
118
+ message = "The argument `" + args[0] + "` is not compatible."
119
+ self.message = message
120
+
121
+
122
+ class RequiredArgument(ArgumentError):
123
+ """Raise this when there is a required argument missing."""
124
+
125
+ def __init__(self, *args, message: _Optional[str] = None):
126
+ """Initialize the exception.
127
+
128
+ :param args: The arguments that are required.
129
+ :param message: The error message to show.
130
+ """
131
+ super().__init__(*args, message)
132
+ if message is None:
133
+ if args:
134
+ if len(args) > 1:
135
+ message = "These arguments are required: " + ', '.join(
136
+ f"`{arg}`" for arg in args
137
+ )
138
+ else:
139
+ message = "The argument `" + args[0] + "` is required."
140
+ self.message = message
141
+
142
+
143
+ class TooFewArguments(ArgumentError):
144
+ """Raise this when there were not enough arguments passed."""
145
+
146
+ def __init__(self, *args, message: _Optional[str] = None):
147
+ """Initialize the exception.
148
+
149
+ :param args: The arguments that should be passed.
150
+ :param message: The error message to show.
151
+ """
152
+ super().__init__(*args, message)
153
+ if message is None:
154
+ if args:
155
+ if len(args) > 1:
156
+ message = "You should use these arguments: " + ', '.join(
157
+ f"`{arg}`" for arg in args
158
+ )
159
+ else:
160
+ message = "The argument `" + args[0] + "` should be used."
161
+ self.message = message
162
+
163
+
79
164
  def normalize_name_to_snake_case(name: str, sep_char: str = '_') -> str:
80
165
  """Returns the normalized name a class.
81
166
 
@@ -278,8 +363,7 @@ def _add_arguments(
278
363
 
279
364
 
280
365
  def _argumentify_one(func: Callable):
281
- """This function argumentifies one function as the entry point of the
282
- script.
366
+ """This function argumentifies one function as the entry point of the script.
283
367
 
284
368
  :param function: The function to argumentify.
285
369
  """
@@ -312,15 +396,18 @@ def _argumentify_one(func: Callable):
312
396
  args.extend(getattr(cli_args, argument.name) or [])
313
397
  else:
314
398
  kwargs[argument.name] = getattr(cli_args, argument.name)
315
- result = func(*args, **kwargs)
316
- # Check if the result is a coroutine
317
- if isinstance(result, (_Coroutine, _Awaitable)):
318
- _asyncio.run(result)
399
+ try:
400
+ result = func(*args, **kwargs)
401
+ # Check if the result is a coroutine
402
+ if isinstance(result, (_Coroutine, _Awaitable)):
403
+ _asyncio.run(result)
404
+ except ArgumentError as error:
405
+ parser.error(error.message)
319
406
 
320
407
 
321
408
  def _argumentify(functions: _Dict[str, Callable]):
322
- """This function argumentifies one or more functions as the entry point of
323
- the script.
409
+ """This function argumentifies one or more functions as the entry point of the
410
+ script.
324
411
 
325
412
  :param functions: A dictionary of functions to argumentify.
326
413
  :raises RuntimeError:
@@ -361,15 +448,18 @@ def _argumentify(functions: _Dict[str, Callable]):
361
448
  args.extend(getattr(cli_args, argument.name) or [])
362
449
  else:
363
450
  kwargs[argument.name] = getattr(cli_args, argument.name)
364
- result = function(*args, **kwargs)
365
- # Check if the result is a coroutine
366
- if isinstance(result, (_Coroutine, _Awaitable)):
367
- _asyncio.run(result)
451
+ try:
452
+ result = function(*args, **kwargs)
453
+ # Check if the result is a coroutine
454
+ if isinstance(result, (_Coroutine, _Awaitable)):
455
+ _asyncio.run(result)
456
+ except ArgumentError as error:
457
+ parser.error(error.message)
368
458
 
369
459
 
370
460
  def argumentify(entry_point: _Union[Callable, _List[Callable], _Dict[str, Callable]]):
371
- """This function argumentifies one or more functions as the entry point of
372
- the script.
461
+ """This function argumentifies one or more functions as the entry point of the
462
+ script.
373
463
 
374
464
  1 #!/usr/bin/env python
375
465
  2 # argumentified.py
@@ -16,14 +16,15 @@ from .Manager import Manager
16
16
  from .Argparse import ColorizingArgumentParser
17
17
  from .TreePrint import TreePrint, tree_format
18
18
  from .Formatters import ColorizingFormatter, DecolorizingFormatter, _Formatter
19
- from .Argumentify import argumentify
19
+ from .Argumentify import (ArgumentError, TooFewArguments, RequiredArgument,
20
+ IncompatibleArguments, argumentify)
20
21
  from .FileHandler import FileHandler, DecolorizingFileHandler
21
22
  from .ProgressBar import ProgressBar
22
23
  from .LoggingWindow import LoggingWindow, LoggingWindowHandler
23
24
  from .StreamHandler import StreamHandler, ColorizingStreamHandler
24
25
 
25
26
  __author__ = 'CodeWriter21 (Mehrad Pooryoussof)'
26
- __version__ = '2.9.2'
27
+ __version__ = '2.10.1'
27
28
  __github__ = 'Https://GitHub.com/MPCodeWriter21/log21'
28
29
  __all__ = [
29
30
  'ColorizingStreamHandler', 'DecolorizingFileHandler', 'ColorizingFormatter',
@@ -35,7 +36,8 @@ __all__ = [
35
36
  'debug', 'info', 'warning', 'warn', 'error', 'critical', 'fatal', 'exception',
36
37
  'log', 'basic_config', 'basicConfig', 'ProgressBar', 'progress_bar',
37
38
  'LoggingWindow', 'LoggingWindowHandler', 'get_logging_window', 'CrashReporter',
38
- 'console_reporter', 'file_reporter', 'argumentify'
39
+ 'console_reporter', 'file_reporter', 'argumentify', 'ArgumentError',
40
+ 'IncompatibleArguments', 'RequiredArgument', 'TooFewArguments'
39
41
  ]
40
42
 
41
43
  _manager = Manager()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: log21
3
- Version: 2.9.2
3
+ Version: 2.10.1
4
4
  Summary: A simple logging package that helps you log colorized messages in Windows console.
5
5
  Author-email: "CodeWriter21(Mehrad Pooryoussof)" <CodeWriter21@gmail.com>
6
6
  License: Apache License 2.0
@@ -92,10 +92,11 @@ pip install git+https://github.com/MPCodeWriter21/log21
92
92
  Changes
93
93
  -------
94
94
 
95
- ### 2.9.2
95
+ ### 2.10.0
96
96
 
97
- + Added `Sequence[T]` as a supported type to the ColorizingArgumentParser.
98
- + Bug fixes.
97
+ + Added some exception classes to raise in the "argumentified" functions to show
98
+ *parser error* to the user: `ArgumentError`, `IncompatibleArguments`,
99
+ `RequiredArgument`, `TooFewArguments`
99
100
 
100
101
  [Full CHANGELOG](https://github.com/MPCodeWriter21/log21/blob/master/CHANGELOG.md)
101
102
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes