bosos-dev-tools 0.0.2__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.
- bosos_dev_tools-0.0.2/LICENSE +21 -0
- bosos_dev_tools-0.0.2/PKG-INFO +136 -0
- bosos_dev_tools-0.0.2/README.md +93 -0
- bosos_dev_tools-0.0.2/pyproject.toml +36 -0
- bosos_dev_tools-0.0.2/setup.cfg +4 -0
- bosos_dev_tools-0.0.2/src/bosos_dev_tools.egg-info/PKG-INFO +136 -0
- bosos_dev_tools-0.0.2/src/bosos_dev_tools.egg-info/SOURCES.txt +18 -0
- bosos_dev_tools-0.0.2/src/bosos_dev_tools.egg-info/dependency_links.txt +1 -0
- bosos_dev_tools-0.0.2/src/bosos_dev_tools.egg-info/requires.txt +2 -0
- bosos_dev_tools-0.0.2/src/bosos_dev_tools.egg-info/top_level.txt +2 -0
- bosos_dev_tools-0.0.2/src/dev_tools/__init__.py +12 -0
- bosos_dev_tools-0.0.2/src/dev_tools/custom_decorators.py +25 -0
- bosos_dev_tools-0.0.2/src/dev_tools/custom_handlers.py +119 -0
- bosos_dev_tools-0.0.2/src/dev_tools/debug_tools.py +103 -0
- bosos_dev_tools-0.0.2/src/dev_tools/progress_bar.py +86 -0
- bosos_dev_tools-0.0.2/src/tests/__init__.py +0 -0
- bosos_dev_tools-0.0.2/src/tests/test_custom_decorators.py +14 -0
- bosos_dev_tools-0.0.2/src/tests/test_custom_handlers.py +22 -0
- bosos_dev_tools-0.0.2/src/tests/test_debug_tools.py +22 -0
- bosos_dev_tools-0.0.2/src/tests/test_progress_bar.py +18 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 bjorngun
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: bosos-dev-tools
|
|
3
|
+
Version: 0.0.2
|
|
4
|
+
Summary: Dev Tools is a collection of utility tools for Python developers, designed to simplify debugging, logging, and monitoring tasks. This package includes custom logging handlers, decorators for measuring execution time, and a progress bar utility to enhance the development workflow.
|
|
5
|
+
Author-email: Björn Gunnarsson <bosos3@hotmail.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2024 bjorngun
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Source, https://github.com/bjorngun/developer-tools
|
|
29
|
+
Project-URL: Tracker, https://github.com/bjorngun/developer-tools/issues
|
|
30
|
+
Keywords: development,tools,logging,decorators
|
|
31
|
+
Classifier: Development Status :: 3 - Alpha
|
|
32
|
+
Classifier: Programming Language :: Python :: 3
|
|
33
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
34
|
+
Classifier: Intended Audience :: Developers
|
|
35
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
36
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
37
|
+
Classifier: Operating System :: OS Independent
|
|
38
|
+
Requires-Python: >=3.12
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
License-File: LICENSE
|
|
41
|
+
Requires-Dist: pyodbc
|
|
42
|
+
Requires-Dist: python-dotenv
|
|
43
|
+
|
|
44
|
+
# Bosos Dev Tools
|
|
45
|
+
|
|
46
|
+
Bosos Dev Tools is a collection of utility tools for Python developers, designed to simplify debugging, logging, and monitoring tasks. This package includes custom logging handlers, decorators for measuring execution time, and a progress bar utility to enhance the development workflow.
|
|
47
|
+
|
|
48
|
+
## Features
|
|
49
|
+
|
|
50
|
+
- **Custom Logging Handlers**: Log messages to various destinations, including databases, with customizable formats.
|
|
51
|
+
- **Timing Decorators**: Easily measure the execution time of your functions with minimal code changes.
|
|
52
|
+
- **Progress Bar Utility**: Visualize the progress of long-running operations in the console.
|
|
53
|
+
- **Debug Tools**: Check if debug or timing modes are enabled via environment variables.
|
|
54
|
+
|
|
55
|
+
## Installation
|
|
56
|
+
|
|
57
|
+
You can install the package via pip:
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
pip install bosos-dev-tools
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Usage
|
|
64
|
+
|
|
65
|
+
### Custom Logging Handler
|
|
66
|
+
|
|
67
|
+
The `LogDBHandler` allows you to log messages directly to a database.
|
|
68
|
+
|
|
69
|
+
``` py
|
|
70
|
+
import logging
|
|
71
|
+
from dev_tools.custom_handlers import LogDBHandler
|
|
72
|
+
|
|
73
|
+
logger = logging.getLogger('test_logger')
|
|
74
|
+
db_handler = LogDBHandler(db_table='test_table')
|
|
75
|
+
logger.addHandler(db_handler)
|
|
76
|
+
logger.setLevel(logging.INFO)
|
|
77
|
+
|
|
78
|
+
logger.info('This is a test log message.')
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Timing Decorator
|
|
82
|
+
|
|
83
|
+
Use the `timing_decorator` to measure the execution time of functions.
|
|
84
|
+
|
|
85
|
+
``` py
|
|
86
|
+
from dev_tools.custom_decorators import timing_decorator
|
|
87
|
+
|
|
88
|
+
@timing_decorator
|
|
89
|
+
def example_function():
|
|
90
|
+
for i in range(1000000):
|
|
91
|
+
pass
|
|
92
|
+
|
|
93
|
+
example_function()
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Progress Bar
|
|
97
|
+
|
|
98
|
+
Use the `progress_bar` to measure the execution time of functions.
|
|
99
|
+
|
|
100
|
+
``` py
|
|
101
|
+
from dev_tools.progress_bar import progress_bar
|
|
102
|
+
|
|
103
|
+
for item in progress_bar(range(10)):
|
|
104
|
+
pass
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Debug Tools
|
|
108
|
+
|
|
109
|
+
Check if debug or timing modes are enabled via environment variables.
|
|
110
|
+
Use the `logger_setup` to set up your logging settings at the beginning of the script.
|
|
111
|
+
|
|
112
|
+
``` py
|
|
113
|
+
from dev_tools.debug_tools import is_debug_on, is_timing_on
|
|
114
|
+
|
|
115
|
+
print('Is debug on:', is_debug_on())
|
|
116
|
+
print('Is timing on:', is_timing_on())
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
``` py
|
|
120
|
+
from dev_tools.debug_tools import logger_setup
|
|
121
|
+
|
|
122
|
+
def main():
|
|
123
|
+
logger_setup()
|
|
124
|
+
|
|
125
|
+
if __name__ == '__main__':
|
|
126
|
+
main()
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
|
|
131
|
+
This project is licensed under the MIT License. See the [LICENSE](https://github.com/bjorngun/developer-tools/blob/main/LICENSE) file for more details.
|
|
132
|
+
|
|
133
|
+
## Links
|
|
134
|
+
|
|
135
|
+
- **Source Code**: [GitHub Repository](https://github.com/bjorngun/developer-tools)
|
|
136
|
+
- **Issue Tracker**: [GitHub Issues](https://github.com/bjorngun/developer-tools/issues)
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Bosos Dev Tools
|
|
2
|
+
|
|
3
|
+
Bosos Dev Tools is a collection of utility tools for Python developers, designed to simplify debugging, logging, and monitoring tasks. This package includes custom logging handlers, decorators for measuring execution time, and a progress bar utility to enhance the development workflow.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Custom Logging Handlers**: Log messages to various destinations, including databases, with customizable formats.
|
|
8
|
+
- **Timing Decorators**: Easily measure the execution time of your functions with minimal code changes.
|
|
9
|
+
- **Progress Bar Utility**: Visualize the progress of long-running operations in the console.
|
|
10
|
+
- **Debug Tools**: Check if debug or timing modes are enabled via environment variables.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
You can install the package via pip:
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
pip install bosos-dev-tools
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
### Custom Logging Handler
|
|
23
|
+
|
|
24
|
+
The `LogDBHandler` allows you to log messages directly to a database.
|
|
25
|
+
|
|
26
|
+
``` py
|
|
27
|
+
import logging
|
|
28
|
+
from dev_tools.custom_handlers import LogDBHandler
|
|
29
|
+
|
|
30
|
+
logger = logging.getLogger('test_logger')
|
|
31
|
+
db_handler = LogDBHandler(db_table='test_table')
|
|
32
|
+
logger.addHandler(db_handler)
|
|
33
|
+
logger.setLevel(logging.INFO)
|
|
34
|
+
|
|
35
|
+
logger.info('This is a test log message.')
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Timing Decorator
|
|
39
|
+
|
|
40
|
+
Use the `timing_decorator` to measure the execution time of functions.
|
|
41
|
+
|
|
42
|
+
``` py
|
|
43
|
+
from dev_tools.custom_decorators import timing_decorator
|
|
44
|
+
|
|
45
|
+
@timing_decorator
|
|
46
|
+
def example_function():
|
|
47
|
+
for i in range(1000000):
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
example_function()
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Progress Bar
|
|
54
|
+
|
|
55
|
+
Use the `progress_bar` to measure the execution time of functions.
|
|
56
|
+
|
|
57
|
+
``` py
|
|
58
|
+
from dev_tools.progress_bar import progress_bar
|
|
59
|
+
|
|
60
|
+
for item in progress_bar(range(10)):
|
|
61
|
+
pass
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Debug Tools
|
|
65
|
+
|
|
66
|
+
Check if debug or timing modes are enabled via environment variables.
|
|
67
|
+
Use the `logger_setup` to set up your logging settings at the beginning of the script.
|
|
68
|
+
|
|
69
|
+
``` py
|
|
70
|
+
from dev_tools.debug_tools import is_debug_on, is_timing_on
|
|
71
|
+
|
|
72
|
+
print('Is debug on:', is_debug_on())
|
|
73
|
+
print('Is timing on:', is_timing_on())
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
``` py
|
|
77
|
+
from dev_tools.debug_tools import logger_setup
|
|
78
|
+
|
|
79
|
+
def main():
|
|
80
|
+
logger_setup()
|
|
81
|
+
|
|
82
|
+
if __name__ == '__main__':
|
|
83
|
+
main()
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## License
|
|
87
|
+
|
|
88
|
+
This project is licensed under the MIT License. See the [LICENSE](https://github.com/bjorngun/developer-tools/blob/main/LICENSE) file for more details.
|
|
89
|
+
|
|
90
|
+
## Links
|
|
91
|
+
|
|
92
|
+
- **Source Code**: [GitHub Repository](https://github.com/bjorngun/developer-tools)
|
|
93
|
+
- **Issue Tracker**: [GitHub Issues](https://github.com/bjorngun/developer-tools/issues)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ['setuptools>=42', 'wheel']
|
|
3
|
+
build-backend = 'setuptools.build_meta'
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = 'bosos-dev-tools'
|
|
7
|
+
version = '0.0.2'
|
|
8
|
+
description = 'Dev Tools is a collection of utility tools for Python developers, designed to simplify debugging, logging, and monitoring tasks. This package includes custom logging handlers, decorators for measuring execution time, and a progress bar utility to enhance the development workflow.'#TODO
|
|
9
|
+
authors = [{ name = 'Björn Gunnarsson', email = 'bosos3@hotmail.com' }]
|
|
10
|
+
license = { file = 'LICENSE' }
|
|
11
|
+
readme = 'README.md'
|
|
12
|
+
keywords = ['development', 'tools', 'logging', 'decorators']
|
|
13
|
+
classifiers = [
|
|
14
|
+
'Development Status :: 3 - Alpha',
|
|
15
|
+
'Programming Language :: Python :: 3',
|
|
16
|
+
'Programming Language :: Python :: 3.12',
|
|
17
|
+
'Intended Audience :: Developers',
|
|
18
|
+
'Topic :: Software Development :: Build Tools',
|
|
19
|
+
'License :: OSI Approved :: MIT License',
|
|
20
|
+
'Operating System :: OS Independent',
|
|
21
|
+
]
|
|
22
|
+
requires-python = '>=3.12'
|
|
23
|
+
dependencies = [
|
|
24
|
+
'pyodbc',
|
|
25
|
+
'python-dotenv',
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Source = 'https://github.com/bjorngun/developer-tools'
|
|
30
|
+
Tracker = 'https://github.com/bjorngun/developer-tools/issues'
|
|
31
|
+
|
|
32
|
+
[tool.setuptools.packages.find]
|
|
33
|
+
where = ['src']
|
|
34
|
+
|
|
35
|
+
[tool.setuptools]
|
|
36
|
+
package-dir = {'' = 'src'}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: bosos-dev-tools
|
|
3
|
+
Version: 0.0.2
|
|
4
|
+
Summary: Dev Tools is a collection of utility tools for Python developers, designed to simplify debugging, logging, and monitoring tasks. This package includes custom logging handlers, decorators for measuring execution time, and a progress bar utility to enhance the development workflow.
|
|
5
|
+
Author-email: Björn Gunnarsson <bosos3@hotmail.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2024 bjorngun
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Source, https://github.com/bjorngun/developer-tools
|
|
29
|
+
Project-URL: Tracker, https://github.com/bjorngun/developer-tools/issues
|
|
30
|
+
Keywords: development,tools,logging,decorators
|
|
31
|
+
Classifier: Development Status :: 3 - Alpha
|
|
32
|
+
Classifier: Programming Language :: Python :: 3
|
|
33
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
34
|
+
Classifier: Intended Audience :: Developers
|
|
35
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
36
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
37
|
+
Classifier: Operating System :: OS Independent
|
|
38
|
+
Requires-Python: >=3.12
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
License-File: LICENSE
|
|
41
|
+
Requires-Dist: pyodbc
|
|
42
|
+
Requires-Dist: python-dotenv
|
|
43
|
+
|
|
44
|
+
# Bosos Dev Tools
|
|
45
|
+
|
|
46
|
+
Bosos Dev Tools is a collection of utility tools for Python developers, designed to simplify debugging, logging, and monitoring tasks. This package includes custom logging handlers, decorators for measuring execution time, and a progress bar utility to enhance the development workflow.
|
|
47
|
+
|
|
48
|
+
## Features
|
|
49
|
+
|
|
50
|
+
- **Custom Logging Handlers**: Log messages to various destinations, including databases, with customizable formats.
|
|
51
|
+
- **Timing Decorators**: Easily measure the execution time of your functions with minimal code changes.
|
|
52
|
+
- **Progress Bar Utility**: Visualize the progress of long-running operations in the console.
|
|
53
|
+
- **Debug Tools**: Check if debug or timing modes are enabled via environment variables.
|
|
54
|
+
|
|
55
|
+
## Installation
|
|
56
|
+
|
|
57
|
+
You can install the package via pip:
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
pip install bosos-dev-tools
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Usage
|
|
64
|
+
|
|
65
|
+
### Custom Logging Handler
|
|
66
|
+
|
|
67
|
+
The `LogDBHandler` allows you to log messages directly to a database.
|
|
68
|
+
|
|
69
|
+
``` py
|
|
70
|
+
import logging
|
|
71
|
+
from dev_tools.custom_handlers import LogDBHandler
|
|
72
|
+
|
|
73
|
+
logger = logging.getLogger('test_logger')
|
|
74
|
+
db_handler = LogDBHandler(db_table='test_table')
|
|
75
|
+
logger.addHandler(db_handler)
|
|
76
|
+
logger.setLevel(logging.INFO)
|
|
77
|
+
|
|
78
|
+
logger.info('This is a test log message.')
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Timing Decorator
|
|
82
|
+
|
|
83
|
+
Use the `timing_decorator` to measure the execution time of functions.
|
|
84
|
+
|
|
85
|
+
``` py
|
|
86
|
+
from dev_tools.custom_decorators import timing_decorator
|
|
87
|
+
|
|
88
|
+
@timing_decorator
|
|
89
|
+
def example_function():
|
|
90
|
+
for i in range(1000000):
|
|
91
|
+
pass
|
|
92
|
+
|
|
93
|
+
example_function()
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Progress Bar
|
|
97
|
+
|
|
98
|
+
Use the `progress_bar` to measure the execution time of functions.
|
|
99
|
+
|
|
100
|
+
``` py
|
|
101
|
+
from dev_tools.progress_bar import progress_bar
|
|
102
|
+
|
|
103
|
+
for item in progress_bar(range(10)):
|
|
104
|
+
pass
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Debug Tools
|
|
108
|
+
|
|
109
|
+
Check if debug or timing modes are enabled via environment variables.
|
|
110
|
+
Use the `logger_setup` to set up your logging settings at the beginning of the script.
|
|
111
|
+
|
|
112
|
+
``` py
|
|
113
|
+
from dev_tools.debug_tools import is_debug_on, is_timing_on
|
|
114
|
+
|
|
115
|
+
print('Is debug on:', is_debug_on())
|
|
116
|
+
print('Is timing on:', is_timing_on())
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
``` py
|
|
120
|
+
from dev_tools.debug_tools import logger_setup
|
|
121
|
+
|
|
122
|
+
def main():
|
|
123
|
+
logger_setup()
|
|
124
|
+
|
|
125
|
+
if __name__ == '__main__':
|
|
126
|
+
main()
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
|
|
131
|
+
This project is licensed under the MIT License. See the [LICENSE](https://github.com/bjorngun/developer-tools/blob/main/LICENSE) file for more details.
|
|
132
|
+
|
|
133
|
+
## Links
|
|
134
|
+
|
|
135
|
+
- **Source Code**: [GitHub Repository](https://github.com/bjorngun/developer-tools)
|
|
136
|
+
- **Issue Tracker**: [GitHub Issues](https://github.com/bjorngun/developer-tools/issues)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/bosos_dev_tools.egg-info/PKG-INFO
|
|
5
|
+
src/bosos_dev_tools.egg-info/SOURCES.txt
|
|
6
|
+
src/bosos_dev_tools.egg-info/dependency_links.txt
|
|
7
|
+
src/bosos_dev_tools.egg-info/requires.txt
|
|
8
|
+
src/bosos_dev_tools.egg-info/top_level.txt
|
|
9
|
+
src/dev_tools/__init__.py
|
|
10
|
+
src/dev_tools/custom_decorators.py
|
|
11
|
+
src/dev_tools/custom_handlers.py
|
|
12
|
+
src/dev_tools/debug_tools.py
|
|
13
|
+
src/dev_tools/progress_bar.py
|
|
14
|
+
src/tests/__init__.py
|
|
15
|
+
src/tests/test_custom_decorators.py
|
|
16
|
+
src/tests/test_custom_handlers.py
|
|
17
|
+
src/tests/test_debug_tools.py
|
|
18
|
+
src/tests/test_progress_bar.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from dev_tools.progress_bar import progress_bar
|
|
2
|
+
from dev_tools.custom_decorators import timing_decorator
|
|
3
|
+
from dev_tools.custom_handlers import LogDBHandler
|
|
4
|
+
from dev_tools.debug_tools import is_debug_on, logger_setup
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"logger_setup",
|
|
8
|
+
"is_debug_on",
|
|
9
|
+
"progress_bar",
|
|
10
|
+
"timing_decorator",
|
|
11
|
+
"LogDBHandler",
|
|
12
|
+
]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import time
|
|
2
|
+
from typing import Any, Callable
|
|
3
|
+
from functools import wraps
|
|
4
|
+
|
|
5
|
+
from dev_tools.debug_tools import is_timing_on
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def timing_decorator(func: Callable) -> Callable:
|
|
9
|
+
@wraps(func)
|
|
10
|
+
def wrapper(*args, **kwargs) -> Any:
|
|
11
|
+
start_time = time.time()
|
|
12
|
+
result = func(*args, **kwargs)
|
|
13
|
+
end_time = time.time()
|
|
14
|
+
elapsed_time = end_time - start_time
|
|
15
|
+
|
|
16
|
+
# Print elapsed time
|
|
17
|
+
print(f"Elapsed time for {func.__name__}: {elapsed_time:.2f} seconds")
|
|
18
|
+
|
|
19
|
+
# Check if timing is enabled and log if applicable
|
|
20
|
+
if is_timing_on() and args and hasattr(args[0], 'logger'):
|
|
21
|
+
logger = getattr(args[0], 'logger')
|
|
22
|
+
logger.info(f"Elapsed time for {func.__name__}: {elapsed_time:.2f} seconds")
|
|
23
|
+
|
|
24
|
+
return result
|
|
25
|
+
return wrapper
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
import pyodbc
|
|
5
|
+
import getpass
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class LogDBHandler(logging.Handler):
|
|
10
|
+
"""Customized logging handler that puts logs to the database."""
|
|
11
|
+
|
|
12
|
+
class SQLLogConnection:
|
|
13
|
+
"""Connection class for a SQL database."""
|
|
14
|
+
|
|
15
|
+
def __init__(self):
|
|
16
|
+
"""Initializes connection to a database."""
|
|
17
|
+
try:
|
|
18
|
+
connection_string = (f'SERVER={os.getenv("LOGGER_DB_SERVER")};'
|
|
19
|
+
f'DATABASE={os.getenv("LOGGER_DB_NAME")};'
|
|
20
|
+
f'DRIVER={os.getenv("LOGGER_SQL_DRIVER")};'
|
|
21
|
+
'Trusted_Connection=yes;')
|
|
22
|
+
|
|
23
|
+
conn = pyodbc.connect(
|
|
24
|
+
connection_string,
|
|
25
|
+
autocommit=True,
|
|
26
|
+
TrustServerCertificate='YES',
|
|
27
|
+
)
|
|
28
|
+
self.cursor = conn.cursor()
|
|
29
|
+
except pyodbc.Error as e:
|
|
30
|
+
logging.getLogger('sql_logger').error(f"Error connecting to database: {e}")
|
|
31
|
+
self.cursor = None
|
|
32
|
+
|
|
33
|
+
def insert(self, table: str, columns: list[str], values: list):
|
|
34
|
+
"""Executes Insert statement in the connected database.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
table (str): Name of the table being inserted into
|
|
38
|
+
columns (list[str]): List of names of the columns that are being inserted into
|
|
39
|
+
values (list): List of the values
|
|
40
|
+
"""
|
|
41
|
+
if self.cursor is None:
|
|
42
|
+
logging.getLogger('sql_logger').error("No database connection available.")
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
table = f'[dbo].[{table}]'
|
|
46
|
+
header = ', '.join([f'[{x}]' for x in columns])
|
|
47
|
+
parameters = ', '.join(['?']*len(columns))
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
self.cursor.execute(
|
|
51
|
+
f'INSERT INTO {table} ({header}) VALUES({parameters})', values)
|
|
52
|
+
except pyodbc.Error as e:
|
|
53
|
+
logging.getLogger('sql_logger').error(f"Error executing insert statement: {e}")
|
|
54
|
+
except TypeError as e:
|
|
55
|
+
logging.getLogger('sql_logger').error(f"Type error with provided values: {e}")
|
|
56
|
+
except Exception as e:
|
|
57
|
+
logging.getLogger('sql_logger').error(f"Unexpected error: {e}")
|
|
58
|
+
|
|
59
|
+
# Maximum length for the log message to be stored in the database
|
|
60
|
+
MAX_LOG_LEN = 2048
|
|
61
|
+
# Message to append if the log message is truncated
|
|
62
|
+
MAX_LOG_MSG = '... too long, check the local logs to see the full msg'
|
|
63
|
+
|
|
64
|
+
def __init__(self, db_table: str):
|
|
65
|
+
"""Initializes the handler and the SQL connection."""
|
|
66
|
+
logging.Handler.__init__(self)
|
|
67
|
+
self.sql_connection = self.SQLLogConnection()
|
|
68
|
+
self.db_table = db_table
|
|
69
|
+
|
|
70
|
+
def emit(self, record):
|
|
71
|
+
"""Emits a record to the database."""
|
|
72
|
+
|
|
73
|
+
# Ensure message is a string and escape quotes if necessary
|
|
74
|
+
try:
|
|
75
|
+
log_message = str(record.msg).replace("'", "''")
|
|
76
|
+
except Exception as e:
|
|
77
|
+
logging.getLogger('sql_logger').error(f"Error processing log message: {e}")
|
|
78
|
+
return
|
|
79
|
+
|
|
80
|
+
# Truncate the log message if it exceeds the maximum length
|
|
81
|
+
if len(log_message) > self.MAX_LOG_LEN:
|
|
82
|
+
log_message = f'{log_message[:self.MAX_LOG_LEN - len(self.MAX_LOG_MSG)]}{self.MAX_LOG_MSG}'
|
|
83
|
+
|
|
84
|
+
# Set current time
|
|
85
|
+
current_time = datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f")
|
|
86
|
+
|
|
87
|
+
# Database columns for the log entry
|
|
88
|
+
db_columns = [
|
|
89
|
+
'log_level',
|
|
90
|
+
'log_levelname',
|
|
91
|
+
'log_module',
|
|
92
|
+
'log_func',
|
|
93
|
+
'log',
|
|
94
|
+
'script',
|
|
95
|
+
'created_at',
|
|
96
|
+
'created_by',
|
|
97
|
+
'pathname',
|
|
98
|
+
'process_id',
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
# Values for the log entry
|
|
102
|
+
row_values = [
|
|
103
|
+
record.levelno,
|
|
104
|
+
record.levelname,
|
|
105
|
+
record.name,
|
|
106
|
+
record.funcName,
|
|
107
|
+
log_message,
|
|
108
|
+
os.getenv("SCRIPT_NAME", Path.cwd().name),
|
|
109
|
+
current_time,
|
|
110
|
+
getpass.getuser(),
|
|
111
|
+
record.pathname,
|
|
112
|
+
os.getpid(),
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
# Insert the log entry into the database
|
|
116
|
+
try:
|
|
117
|
+
self.sql_connection.insert(self.db_table, db_columns, row_values)
|
|
118
|
+
except Exception as e:
|
|
119
|
+
logging.getLogger('sql_logger').error(f"Error inserting log into database: {e}")
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import atexit
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
import logging
|
|
4
|
+
import logging.config
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from dotenv import load_dotenv
|
|
9
|
+
|
|
10
|
+
from .custom_handlers import LogDBHandler
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def is_debug_on() -> bool:
|
|
14
|
+
"""Determine if debug mode is enabled."""
|
|
15
|
+
return os.getenv('DEBUG', 'False').lower() in ['true', '1', 't', 'yes']
|
|
16
|
+
|
|
17
|
+
def is_timing_on() -> bool:
|
|
18
|
+
"""Determine if timing mode is enabled."""
|
|
19
|
+
return os.getenv('TIMING', 'False').lower() in ['true', '1', 't', 'yes']
|
|
20
|
+
|
|
21
|
+
def is_database_logging_on() -> bool:
|
|
22
|
+
"""Determine if database logging mode is enabled."""
|
|
23
|
+
return os.getenv('LOGGER_DATABASE', 'False').lower() in ['true', '1', 't', 'yes']
|
|
24
|
+
|
|
25
|
+
def log_exit_code():
|
|
26
|
+
"""Log the exit code of the script."""
|
|
27
|
+
logger = logging.getLogger(__name__)
|
|
28
|
+
exit_code = 0 if sys.exc_info() == (None, None, None) else 1
|
|
29
|
+
logger.info(f'Exit code: {exit_code}')
|
|
30
|
+
|
|
31
|
+
def default_logging_config(logger_file_path: str):
|
|
32
|
+
"""Default logging configuration."""
|
|
33
|
+
return {
|
|
34
|
+
'version': 1,
|
|
35
|
+
'disable_existing_loggers': False,
|
|
36
|
+
'formatters': {
|
|
37
|
+
'simple': {
|
|
38
|
+
'format': '%(levelname)s | %(name)s | %(message)s',
|
|
39
|
+
'datefmt': '%Y-%m-%dT%H:%M:%S',
|
|
40
|
+
},
|
|
41
|
+
'complex': {
|
|
42
|
+
'format': '%(levelname)s | %(asctime)s | %(name)s | %(funcName)s | %(message)s',
|
|
43
|
+
'datefmt': '%Y-%m-%dT%H:%M:%S',
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
'handlers': {
|
|
47
|
+
'screen': {
|
|
48
|
+
'class': 'logging.StreamHandler',
|
|
49
|
+
'formatter': 'simple',
|
|
50
|
+
'level': 'INFO' if is_debug_on() else 'WARNING',
|
|
51
|
+
'stream': 'ext://sys.stdout',
|
|
52
|
+
},
|
|
53
|
+
'file': {
|
|
54
|
+
'class': 'logging.FileHandler',
|
|
55
|
+
'formatter': 'complex',
|
|
56
|
+
'level': 'DEBUG' if is_debug_on() else 'INFO',
|
|
57
|
+
'filename': logger_file_path,
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
'root': {
|
|
61
|
+
'handlers': ['screen', 'file'],
|
|
62
|
+
'level': 'DEBUG' if is_debug_on() else 'INFO',
|
|
63
|
+
},
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
def logger_setup():
|
|
67
|
+
"""Set up logging configuration based on environment variables and debug mode."""
|
|
68
|
+
atexit.register(log_exit_code)
|
|
69
|
+
|
|
70
|
+
#Loads up all the environment variables
|
|
71
|
+
load_dotenv()
|
|
72
|
+
debug = is_debug_on()
|
|
73
|
+
today = datetime.now()
|
|
74
|
+
|
|
75
|
+
logger_conf_path = Path(os.getenv('LOGGER_CONF_PATH', 'logging.conf'))
|
|
76
|
+
if debug:
|
|
77
|
+
logger_conf_path = Path(os.getenv('LOGGER_CONF_DEV_PATH', 'logging_dev.conf'))
|
|
78
|
+
logger_folder_path = f'{os.getenv("LOGGER_PATH", "./logs")}/{today.strftime("%Y-%m-%d")}'
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
Path(logger_folder_path).mkdir(parents=True, exist_ok=True)
|
|
82
|
+
except Exception as e:
|
|
83
|
+
print(f'Error creating log directory {Path(logger_folder_path)}: {e}', file=sys.stderr)
|
|
84
|
+
sys.exit(1)
|
|
85
|
+
|
|
86
|
+
logger_file_path = f'{logger_folder_path}/{today.strftime("%Y-%m-%dT%H%M%S")}.log'
|
|
87
|
+
logger_db_table = os.getenv('LOGGER_DB_TABLE', 'python_transfer_data_log')
|
|
88
|
+
if logger_conf_path.exists():
|
|
89
|
+
try:
|
|
90
|
+
logging.config.fileConfig(logger_conf_path, defaults={
|
|
91
|
+
'logfilename': logger_file_path,
|
|
92
|
+
})
|
|
93
|
+
except Exception as e:
|
|
94
|
+
print(f'Error setting up logging configuration from {logger_conf_path}: {e}', file=sys.stderr)
|
|
95
|
+
sys.exit(1)
|
|
96
|
+
else:
|
|
97
|
+
logging.config.dictConfig(default_logging_config(logger_file_path))
|
|
98
|
+
if (is_database_logging_on()):
|
|
99
|
+
log_db_handler = LogDBHandler(logger_db_table)
|
|
100
|
+
logging.getLogger('').addHandler(log_db_handler)
|
|
101
|
+
|
|
102
|
+
logger = logging.getLogger(__name__)
|
|
103
|
+
logger.info(f'Setting up logger for {os.getenv("SCRIPT_NAME", Path.cwd().name)}')
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import time
|
|
3
|
+
from collections.abc import Iterable
|
|
4
|
+
from dev_tools.debug_tools import is_debug_on, is_timing_on
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def progress_bar(
|
|
8
|
+
iterable: Iterable,
|
|
9
|
+
prefix: str = "",
|
|
10
|
+
suffix: str = "",
|
|
11
|
+
decimals: int = 1,
|
|
12
|
+
length: int = 50,
|
|
13
|
+
fill: str = "█",
|
|
14
|
+
print_end: str = "\r",
|
|
15
|
+
) -> Iterable:
|
|
16
|
+
"""
|
|
17
|
+
Call in a loop to create terminal progress bar
|
|
18
|
+
@params:
|
|
19
|
+
iterable - Required : iterable object (Iterable)
|
|
20
|
+
prefix - Optional : prefix string (Str)
|
|
21
|
+
suffix - Optional : suffix string (Str)
|
|
22
|
+
decimals - Optional : positive number of decimals in percent complete (Int)
|
|
23
|
+
length - Optional : character length of bar (Int)
|
|
24
|
+
fill - Optional : bar fill character (Str)
|
|
25
|
+
print_end - Optional : end character (e.g. "\r", "\r\n") (Str)
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
debug = is_debug_on()
|
|
29
|
+
timing = is_timing_on()
|
|
30
|
+
total = len(iterable)
|
|
31
|
+
start_time = time.time()
|
|
32
|
+
logger = logging.getLogger(__name__)
|
|
33
|
+
errors = {}
|
|
34
|
+
|
|
35
|
+
def print_progress_bar(iteration: int) -> None:
|
|
36
|
+
if not debug or total == 0:
|
|
37
|
+
return
|
|
38
|
+
|
|
39
|
+
percent = f"{100 * (iteration / float(total)):.{decimals}f}"
|
|
40
|
+
filled_length = int(length * iteration // total)
|
|
41
|
+
bar = fill * filled_length + "-" * (length - filled_length)
|
|
42
|
+
time_str = get_timing_str(iteration)
|
|
43
|
+
|
|
44
|
+
try:
|
|
45
|
+
print(f"\r{prefix} |{bar}| {percent}% {suffix}{time_str}{'':<10}", end=print_end)
|
|
46
|
+
except UnicodeEncodeError:
|
|
47
|
+
if "UnicodeEncodeError" not in errors:
|
|
48
|
+
errors["UnicodeEncodeError"] = True
|
|
49
|
+
logger.exception("Progress bar is not able to print, DEBUG = %s", debug)
|
|
50
|
+
logging.exception("Progress bar is not able to print, DEBUG = %s", debug)
|
|
51
|
+
|
|
52
|
+
def get_timing_str(iteration: int) -> str:
|
|
53
|
+
if not timing:
|
|
54
|
+
return ""
|
|
55
|
+
|
|
56
|
+
et = time.time() - start_time
|
|
57
|
+
et_str = f"Elapsed time: {format_time(et)}"
|
|
58
|
+
eta_str = "Time remaining: N/A"
|
|
59
|
+
if iteration > 0 and et > 0:
|
|
60
|
+
eta_seconds = et / (iteration / float(total)) - et
|
|
61
|
+
eta_str = f"Time remaining: {format_time(eta_seconds)}"
|
|
62
|
+
|
|
63
|
+
return f" |--{et_str} - {eta_str}--|"
|
|
64
|
+
|
|
65
|
+
def format_time(seconds) -> str:
|
|
66
|
+
minutes = int(seconds // 60)
|
|
67
|
+
seconds = seconds % 60
|
|
68
|
+
|
|
69
|
+
hours = int(minutes // 60)
|
|
70
|
+
minutes = minutes % 60
|
|
71
|
+
|
|
72
|
+
time_str = ""
|
|
73
|
+
if hours > 0:
|
|
74
|
+
time_str += f"{hours}h "
|
|
75
|
+
if minutes > 0:
|
|
76
|
+
time_str += f"{minutes}m "
|
|
77
|
+
time_str += f"{seconds:.2f}s"
|
|
78
|
+
return time_str
|
|
79
|
+
|
|
80
|
+
print_progress_bar(0)
|
|
81
|
+
for i, item in enumerate(iterable):
|
|
82
|
+
yield item
|
|
83
|
+
print_progress_bar(i + 1)
|
|
84
|
+
# Print New Line on Complete
|
|
85
|
+
if debug and total > 0:
|
|
86
|
+
print()
|
|
File without changes
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from dev_tools.custom_decorators import timing_decorator
|
|
3
|
+
|
|
4
|
+
class TestTimingDecorator(unittest.TestCase):
|
|
5
|
+
def test_timing_decorator(self):
|
|
6
|
+
@timing_decorator
|
|
7
|
+
def sample_function(x, y):
|
|
8
|
+
return x + y
|
|
9
|
+
|
|
10
|
+
result = sample_function(1, 2)
|
|
11
|
+
self.assertEqual(result, 3)
|
|
12
|
+
|
|
13
|
+
if __name__ == '__main__':
|
|
14
|
+
unittest.main()
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from unittest.mock import patch
|
|
3
|
+
import logging
|
|
4
|
+
from dev_tools.custom_handlers import LogDBHandler
|
|
5
|
+
|
|
6
|
+
class TestLogDBHandler(unittest.TestCase):
|
|
7
|
+
@patch('dev_tools.custom_handlers.pyodbc.connect')
|
|
8
|
+
def test_emit(self, mock_connect):
|
|
9
|
+
mock_connect.return_value.cursor.return_value.execute.return_value = None
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger('test_logger')
|
|
12
|
+
db_handler = LogDBHandler(db_table='test_table')
|
|
13
|
+
logger.addHandler(db_handler)
|
|
14
|
+
logger.setLevel(logging.INFO)
|
|
15
|
+
|
|
16
|
+
with self.assertLogs('test_logger', level='INFO') as log:
|
|
17
|
+
logger.info('This is a test log message')
|
|
18
|
+
|
|
19
|
+
self.assertIn('This is a test log message', log.output[0])
|
|
20
|
+
|
|
21
|
+
if __name__ == '__main__':
|
|
22
|
+
unittest.main()
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import os
|
|
3
|
+
from unittest.mock import patch
|
|
4
|
+
from dev_tools.debug_tools import is_debug_on, is_timing_on, logger_setup
|
|
5
|
+
|
|
6
|
+
class TestDebugTools(unittest.TestCase):
|
|
7
|
+
@patch.dict(os.environ, {'DEBUG': 'true', 'TIMING': 'true'})
|
|
8
|
+
def test_is_debug_on(self):
|
|
9
|
+
self.assertTrue(is_debug_on())
|
|
10
|
+
|
|
11
|
+
@patch.dict(os.environ, {'DEBUG': 'false', 'TIMING': 'true'})
|
|
12
|
+
def test_is_timing_on(self):
|
|
13
|
+
self.assertTrue(is_timing_on())
|
|
14
|
+
|
|
15
|
+
@patch('dev_tools.debug_tools.logging.config.fileConfig')
|
|
16
|
+
@patch('dev_tools.debug_tools.logging.config.dictConfig')
|
|
17
|
+
def test_logger_setup(self, mock_dictConfig, mock_fileConfig):
|
|
18
|
+
logger_setup()
|
|
19
|
+
mock_dictConfig.assert_called()
|
|
20
|
+
|
|
21
|
+
if __name__ == '__main__':
|
|
22
|
+
unittest.main()
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import os
|
|
3
|
+
from unittest.mock import patch
|
|
4
|
+
from dev_tools.progress_bar import progress_bar
|
|
5
|
+
|
|
6
|
+
class TestProgressBar(unittest.TestCase):
|
|
7
|
+
|
|
8
|
+
@patch('builtins.print')
|
|
9
|
+
@patch.dict(os.environ, {'DEBUG': 'true', 'TIMING': 'true'})
|
|
10
|
+
def test_progress_bar(self, mock_print):
|
|
11
|
+
items = list(range(10))
|
|
12
|
+
result = list(progress_bar(items))
|
|
13
|
+
|
|
14
|
+
self.assertEqual(result, items)
|
|
15
|
+
self.assertTrue(mock_print.called)
|
|
16
|
+
|
|
17
|
+
if __name__ == '__main__':
|
|
18
|
+
unittest.main()
|