Skip to content
Snippets Groups Projects
Commit 40412bf2 authored by Robert Goldmann's avatar Robert Goldmann
Browse files

BaseUtils: Added Profile decorator

parent 16dfa676
No related branches found
No related tags found
No related merge requests found
import os
import subprocess
import sys
import tempfile
import time
import webbrowser
from functools import wraps
import psutil
def Profile(filePath=None):
"""
Decorator for method profiling.
:param filePath: Optional. Absolute file path where the profiling file should be saved (timestamp will be added
automatically). If left empty the file is saved in the temp directory in a sub folder called "profiling"
:type filePath: str
:example:
@Profile()
@Profile('C:/profiles/myProfiling.prof')
"""
if not isinstance(filePath, (type(None), str)):
raise RuntimeError('Decorator "Profile()" must used function call (with parenthesis)!')
def ProfileDecorator(func):
@wraps(func)
def f(*args, **kwargs):
import cProfile
profFile = __determine_profile_path(filePath, callerName=func.__name__)
prof = cProfile.Profile()
try:
return prof.runcall(func, *args, **kwargs)
finally:
__finalize(prof, profFile)
return f
return ProfileDecorator
def __finalize(prof, profFile):
print(f'Saving profiling file to: {profFile}')
prof.dump_stats(profFile)
__open_snakeviz(profFile)
def __determine_profile_path(filePath, callerName):
formattedDateTime = time.strftime('%Y-%m-%d_%H%M%S')
if filePath is None:
fileDir = os.path.join(tempfile.gettempdir(), 'profiling')
filePath = f'{callerName}_{formattedDateTime}.prof'
else:
fileDir, theFileName = os.path.split(filePath)
filePath = f'{os.path.splitext(filePath)[0]}_{formattedDateTime}.prof'
profFile = os.path.join(fileDir, filePath)
if not os.path.isdir(fileDir):
os.makedirs(fileDir)
return profFile
def __open_snakeviz(profFile):
snakeVizExecutable = __get_snakeviz_executable()
executable = os.path.join(os.path.dirname(sys.executable), snakeVizExecutable)
if not os.path.isfile(executable):
raise ImportError(f'Snakeviz not installed ({executable} not found)')
isAlreadyRunning = snakeVizExecutable in {p.name() for p in psutil.process_iter()}
if isAlreadyRunning:
browser = __get_webbrowser()
browser.open_new_tab(f'http://127.0.0.1:8080/snakeviz/{profFile}')
else:
subprocess.check_call(f'"{executable}" "{profFile}"', shell=True)
def __get_snakeviz_executable():
if sys.platform == 'win32':
return 'snakeviz.exe'
return 'snakeviz'
def __get_webbrowser():
webbrowser.register('firefox', None,
webbrowser.BackgroundBrowser('C://Program Files//Mozilla Firefox//firefox.exe'))
try:
return webbrowser.get('firefox')
except webbrowser.Error:
pass
return webbrowser.get()
if __name__ == '__main__':
@Profile()
def test():
os.listdir('c:')
test()
...@@ -3,7 +3,7 @@ from setuptools import setup ...@@ -3,7 +3,7 @@ from setuptools import setup
setup( setup(
name='TheCodeLabs-BaseUtils', name='TheCodeLabs-BaseUtils',
packages=['TheCodeLabs_BaseUtils'], packages=['TheCodeLabs_BaseUtils'],
version='1.2.0', version='1.3.0',
license='MIT', license='MIT',
description='Useful python classes', description='Useful python classes',
author='TheCodeLabs', author='TheCodeLabs',
...@@ -12,6 +12,8 @@ setup( ...@@ -12,6 +12,8 @@ setup(
download_url='https://pypi.thecodelabs.de', download_url='https://pypi.thecodelabs.de',
keywords=[], keywords=[],
install_requires=[ install_requires=[
'psutil',
'snakeviz'
], ],
setup_requires=[ setup_requires=[
'wheel' 'wheel'
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment