Skip to content

Commit d7e537a

Browse files
Added the left shift and right shift to the Logger.
- Added the cin and cout functionalities. - Moved Examples out of `README.md`.
1 parent 2d8ee49 commit d7e537a

4 files changed

Lines changed: 387 additions & 382 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ Help this project by [Donation](DONATE.md)
66
Changes
77
-------
88

9+
### 2.9.0
10+
11+
+ Added `<<` and `>>` (left shift and right shift operators) to `log21.Logger.Logger`.
12+
913
### 2.8.1
1014

1115
+ Fixed Carriage Return Handling.

EXAMPLES.md

Lines changed: 378 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,378 @@
1+
Usage Examples of log21
2+
=======================
3+
4+
### Basic Logging
5+
6+
```python
7+
import log21
8+
9+
log21.print(log21.get_color('#FF0000') + 'This' + log21.get_color((0, 255, 0)) + ' is' + log21.get_color('Blue') +
10+
' Blue' + log21.get_colors('BackgroundWhite', 'Black') + ' 8)')
11+
12+
logger = log21.get_logger('My Logger', level_names={21: 'SpecialInfo', log21.WARNING: ' ! ', log21.ERROR: '!!!'})
13+
logger.info('You are reading the README.md file...')
14+
15+
logger.log(21, 'Here', '%s', 'GO!', args=('we',))
16+
17+
logger.setLevel(log21.WARNING)
18+
logger.warning("We can't log messages with a level less than 30 anymore!")
19+
20+
logger.debug("You won't see this!")
21+
logger.info("Am I visible?")
22+
23+
logger.error(log21.get_colors('LightRed') + "I'm still here ;1")
24+
```
25+
26+
![Basic Logging](https://github.com/MPCodeWriter21/log21/raw/master/screen-shots/example-1.png)
27+
28+
----------------
29+
30+
### Argument Parsing (See Also: [Argumentify](https://github.com/MPCodeWriter21/log21#argumentify-check-out-the-manual-way))
31+
32+
```python
33+
import log21
34+
from log21 import ColorizingArgumentParser, get_logger, get_colors as gc
35+
36+
parser = ColorizingArgumentParser(description="This is a simple example of a ColorizingArgumentParser.",
37+
colors={'help': 'LightCyan'})
38+
parser.add_argument('test1', action='store', help='Test 1')
39+
parser.add_argument('test2', action='store', help='Test 2')
40+
parser.add_argument('--optional-arg', '-o', action='store', type=int, help='An optional integer')
41+
parser.add_argument('--verbose', '-v', action='store_true', help='Increase verbosity.')
42+
43+
args = parser.parse_args()
44+
45+
logger = get_logger('My Logger', level_names={log21.DEBUG: ' ? ', log21.INFO: ' + ', log21.WARNING: ' ! ',
46+
log21.ERROR: '!!!'})
47+
48+
if args.verbose:
49+
logger.setLevel(log21.DEBUG)
50+
else:
51+
logger.setLevel(log21.INFO)
52+
53+
logger.debug(gc('LightBlue') + 'Verbose mode on!')
54+
55+
logger.debug('Arguments:\n'
56+
'\tTest 1: %s\n'
57+
'\tTest 2: %s\n'
58+
'\tOptional: %s', args=(args.test1, args.test2, args.optional_arg))
59+
60+
logger.info(gc('LightGreen') + args.test1)
61+
62+
logger.info(gc('LightWhite') + 'Done!')
63+
64+
```
65+
66+
![No argument](https://github.com/MPCodeWriter21/log21/raw/master/screen-shots/example-2.1.png)
67+
68+
![Help](https://github.com/MPCodeWriter21/log21/raw/master/screen-shots/example-2.2.png)
69+
70+
![Valid example 1](https://github.com/MPCodeWriter21/log21/raw/master/screen-shots/example-2.3.png)
71+
72+
![Valid example 2](https://github.com/MPCodeWriter21/log21/raw/master/screen-shots/example-2.4.png)
73+
74+
![Valid example 3](https://github.com/MPCodeWriter21/log21/raw/master/screen-shots/example-2.5.png)
75+
76+
------------------
77+
78+
### Pretty-Printing and Tree-Printing
79+
80+
```python
81+
import json
82+
import log21
83+
84+
data = json.load(open('json.json', 'r'))
85+
86+
# Prints data using python's built-in print function
87+
print(data)
88+
89+
# Uses `log21.pprint` to print the data
90+
log21.pprint(data)
91+
92+
# Uses `log21.tree_print` to print the data
93+
log21.tree_print(data)
94+
```
95+
96+
![Python print](https://github.com/MPCodeWriter21/log21/raw/master/screen-shots/example-3.1.png)
97+
![log21 pretty print](https://github.com/MPCodeWriter21/log21/raw/master/screen-shots/example-3.2.png)
98+
![log21 tree print 1](https://github.com/MPCodeWriter21/log21/raw/master/screen-shots/example-3.3.1.png)
99+
![log21 tree print 1](https://github.com/MPCodeWriter21/log21/raw/master/screen-shots/example-3.3.2.png)
100+
101+
------------------
102+
103+
### Logging Window
104+
105+
```python
106+
import log21
107+
108+
window = log21.get_logging_window('My Logging Window', width=80)
109+
window.font = ('Courier New', 9)
110+
111+
# Basic logging
112+
window.info('This is a basic logging message.')
113+
114+
# Using ANSI and HEX colors
115+
# List of ANSI colors: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
116+
# ANSI color format: \033[<attribute>m
117+
window.info('\033[91mThis is RED message.')
118+
window.info('\033[102mThis is message with GREEN background.')
119+
# HEX color format: \033#<HEX-COLOR>hf (where f represents the foreground color) and
120+
# \033#<HEX-COLOR>hb (where b represents the background color)
121+
window.info('\x1b#009900hbThis is a text with GREEN background.')
122+
window.info('\033#0000FFhf\033[103mThis is message with BLUE foreground and YELLOW background.')
123+
124+
import random, string
125+
126+
# And here is a text with random colors
127+
text = 'I have random colors XD'
128+
colored_text = ''
129+
for character in text:
130+
color = '\033#' + ''.join(random.choice(string.hexdigits) for _ in range(6)) + 'hf'
131+
colored_text += color + character
132+
133+
window.error(colored_text)
134+
135+
# See more examples in
136+
# https://github.com/MPCodeWriter21/log21/blob/066efc1e72542531012d36974bbf6cd4c5941378/log21/LoggingWindow.py#L155
137+
# and
138+
# https://github.com/MPCodeWriter21/log21/blob/066efc1e72542531012d36974bbf6cd4c5941378/log21/__init__.py#L144
139+
140+
```
141+
142+
![The LoggingWindow](https://github.com/MPCodeWriter21/log21/raw/master/screen-shots/example-4.png)
143+
144+
------------------
145+
146+
### ProgressBar
147+
148+
```python
149+
# Example 1
150+
import log21, time
151+
152+
# Define a very simple log21 progress bar
153+
progress_bar = log21.ProgressBar()
154+
155+
# And here is a simple loop that will print the progress bar
156+
for i in range(100):
157+
progress_bar(i + 1, 100)
158+
time.sleep(0.08)
159+
160+
# Example 2
161+
import time, random
162+
from log21 import ProgressBar, get_colors as gc
163+
164+
# Let's customize the progress bar a little bit this time
165+
progress_bar = ProgressBar(
166+
width=50,
167+
fill='#',
168+
empty='-',
169+
prefix='[',
170+
suffix=']',
171+
colors={'progress in-progress': gc('Bright Red'), 'progress complete': gc('Bright Cyan'),
172+
'percentage in-progress': gc('Green'), 'percentage complete': gc('Bright Cyan'),
173+
'prefix-color in-progress': gc('Bright White'), 'prefix-color complete': gc('Bright White'),
174+
'prefix-color failed': gc('Bright White'), 'suffix-color in-progress': gc('Bright White'),
175+
'suffix-color complete': gc('Bright White'), 'suffix-color failed': gc('Bright White')})
176+
177+
for i in range(84):
178+
progress_bar(i + 1, 84)
179+
time.sleep(random.uniform(0.05, 0.21))
180+
181+
```
182+
183+
![ProgressBar - Example 1](https://github.com/MPCodeWriter21/log21/raw/master/screen-shots/example-5.1.gif)
184+
![ProgressBar - Example 2](https://github.com/MPCodeWriter21/log21/raw/master/screen-shots/example-5.2.gif)
185+
186+
------------------
187+
188+
### Argumentify (Check out [the manual way](https://github.com/MPCodeWriter21/log21#argument-parsing-see-also-argumentify))
189+
190+
```python
191+
# Common Section
192+
import log21
193+
194+
195+
class ReversedText:
196+
def __init__(self, text: str):
197+
self._text = text[::-1]
198+
199+
def __str__(self):
200+
return self._text
201+
202+
def __repr__(self):
203+
return f"<{self.__class__.__name__}(text='{self._text}') at {hex(id(self))}>"
204+
205+
206+
# Old way
207+
def main():
208+
"""Here is my main function"""
209+
parser = log21.ColorizingArgumentParser()
210+
parser.add_argument('--positional-arg', '-p', action='store', type=int,
211+
required=True, help="This argument is positional!")
212+
parser.add_argument('--optional-arg', '-o', action='store', type=ReversedText,
213+
help="Whatever you pass here will be REVERSED!")
214+
parser.add_argument('--arg-with-default', '-a', action='store', default=21,
215+
help="The default value is 21")
216+
parser.add_argument('--additional-arg', '-A', action='store',
217+
help="This one is extra.")
218+
parser.add_argument('--verbose', '-v', action='store_true',
219+
help="Increase verbosity")
220+
args = parser.parse_args()
221+
222+
if args.verbose:
223+
log21.basic_config(level='DEBUG')
224+
225+
log21.info(f"positional_arg = {args.positional_arg}")
226+
log21.info(f"optional_arg = {args.optional_arg}")
227+
log21.debug(f"arg_with_default = {args.arg_with_default}")
228+
log21.debug(f"additional_arg = {args.additional_arg}")
229+
230+
231+
if __name__ == '__main__':
232+
main()
233+
234+
235+
# New way
236+
def main(positional_arg: int, /, optional_arg: ReversedText, arg_with_default: int = 21,
237+
additional_arg=None, verbose: bool = False):
238+
"""Some description
239+
240+
:param positional_arg: This argument is positional!
241+
:param optional_arg: Whatever you pass here will be REVERSED!
242+
:param arg_with_default: The default value is 21
243+
:param additional_arg: This one is extra.
244+
:param verbose: Increase verbosity
245+
"""
246+
if verbose:
247+
log21.basic_config(level='DEBUG')
248+
249+
log21.info(f"{positional_arg = }")
250+
log21.info(f"{optional_arg = !s}")
251+
log21.debug(f"{arg_with_default = }")
252+
log21.debug(f"{additional_arg = !s}")
253+
254+
255+
if __name__ == '__main__':
256+
log21.argumentify(main)
257+
```
258+
259+
![Old-Way](https://github.com/MPCodeWriter21/log21/raw/master/screen-shots/example-6.1.png)
260+
![New-Way](https://github.com/MPCodeWriter21/log21/raw/master/screen-shots/example-6.2.png)
261+
262+
Example with multiple functions as entry-point:
263+
264+
```python
265+
import ast
266+
import operator
267+
from functools import reduce
268+
269+
import log21
270+
271+
# `safe_eval` Based on https://stackoverflow.com/a/9558001/1113207
272+
# Supported Operators
273+
operators = {
274+
ast.Add: operator.add,
275+
ast.Sub: operator.sub,
276+
ast.Mult: operator.mul,
277+
ast.Div: operator.truediv,
278+
ast.FloorDiv: operator.floordiv,
279+
ast.Pow: operator.pow,
280+
ast.BitXor: operator.xor,
281+
ast.USub: operator.neg
282+
}
283+
284+
285+
def safe_eval(expr: str):
286+
"""Safely evaluate a mathematical expression.
287+
288+
>>> eval_expr('2^6')
289+
4
290+
>>> eval_expr('2**6')
291+
64
292+
>>> eval_expr('1 + 2*3**(4^5) / (6 + -7)')
293+
-5.0
294+
295+
:param expr: expression to evaluate
296+
:raises SyntaxError: on invalid expression
297+
:return: result of the evaluation
298+
"""
299+
try:
300+
return _eval(ast.parse(expr, mode='eval').body)
301+
except (TypeError, KeyError, SyntaxError):
302+
log21.error(f'Invalid expression: {expr}')
303+
raise
304+
305+
306+
def _eval(node: ast.AST):
307+
"""Internal implementation of `safe_eval`.
308+
309+
:param node: AST node to evaluate
310+
:raises TypeError: on invalid node
311+
:raises KeyError: on invalid operator
312+
:raises ZeroDivisionError: on division by zero
313+
:raises ValueError: on invalid literal
314+
:raises SyntaxError: on invalid syntax
315+
:return: result of the evaluation
316+
"""
317+
if isinstance(node, ast.Num): # <number>
318+
return node.n
319+
if isinstance(node, ast.BinOp): # <left> <operator> <right>
320+
return operators[type(node.op)](_eval(node.left), _eval(node.right))
321+
if isinstance(node, ast.UnaryOp): # <operator> <operand> e.g., -1
322+
return operators[type(node.op)](_eval(node.operand))
323+
raise TypeError(node)
324+
325+
326+
# Example code
327+
def addition(*numbers: float):
328+
"""Addition of numbers.
329+
330+
Args:
331+
numbers (float): numbers to add
332+
"""
333+
if len(numbers) < 2:
334+
log21.error('At least two numbers are required! Use `-n`.')
335+
return
336+
log21.info(f'Result: {sum(numbers)}')
337+
338+
339+
def multiplication(*numbers: float):
340+
"""Multiplication of numbers.
341+
342+
Args:
343+
numbers (float): numbers to multiply
344+
"""
345+
if len(numbers) < 2:
346+
log21.error('At least two numbers are required! Use `-n`.')
347+
return
348+
log21.info(f'Result: {reduce(lambda x, y: x * y, numbers)}')
349+
350+
351+
def calc(*inputs: str, verbose: bool = False):
352+
"""Calculate numbers.
353+
354+
:param inputs: numbers and operators
355+
"""
356+
expression = ' '.join(inputs)
357+
358+
if len(expression) < 3:
359+
log21.error('At least two numbers and one operator are required! Use `-i`.')
360+
return
361+
362+
if verbose:
363+
log21.basic_config(level='DEBUG')
364+
365+
log21.debug(f'Expression: {expression}')
366+
try:
367+
log21.info(f'Result: {safe_eval(expression)}')
368+
except (TypeError, KeyError, SyntaxError):
369+
pass
370+
371+
372+
if __name__ == "__main__":
373+
log21.argumentify({'add': addition, 'mul': multiplication, 'calc': calc})
374+
```
375+
376+
![multi-entry](https://github.com/MPCodeWriter21/log21/raw/master/screen-shots/example-6.3.png)
377+
378+

0 commit comments

Comments
 (0)