├── .gitignore ├── .pre-commit-config.yaml ├── .travis.yml ├── CHANGELOG.rst ├── LICENSE ├── MANIFEST.in ├── README.md ├── README.rst ├── _config.yml ├── pyheat ├── __init__.py ├── __version__.py ├── commandline.py └── pyheat.py ├── requirements.txt ├── setup.cfg ├── setup.py └── tests ├── __init__.py ├── pyheat_test.py └── test_program.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | .Python 3 | bin/ 4 | include/ 5 | lib/ 6 | pip-selfcheck.json 7 | py_heat.egg-info/ 8 | dist/ 9 | pyheat/__pycache__/ 10 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | exclude: '^docs/.*$|Pipfile|Pipfile.lock' 2 | repos: 3 | - repo: https://github.com/pre-commit/pre-commit-hooks 4 | rev: v4.0.1 5 | hooks: 6 | - id: check-docstring-first 7 | - id: check-executables-have-shebangs 8 | - id: check-json 9 | - id: check-merge-conflict 10 | - id: check-yaml 11 | - id: debug-statements 12 | - id: double-quote-string-fixer 13 | - id: end-of-file-fixer 14 | - id: trailing-whitespace 15 | - id: pretty-format-json 16 | args: [--no-ensure-ascii, --autofix] 17 | - repo: https://github.com/PyCQA/isort 18 | rev: 5.9.3 19 | hooks: 20 | - id: isort 21 | args: [-l=120, -m=VERTICAL_HANGING_INDENT, --tc] 22 | - repo: https://github.com/psf/black 23 | rev: 21.7b0 24 | hooks: 25 | - id: black 26 | args: [--line-length=120, --skip-string-normalization] 27 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | - "3.4" 5 | - "3.5" 6 | - "3.6" 7 | # Command to install dependencies. 8 | install: 9 | - "pip install -r requirements.txt" 10 | - "pip install coveralls" 11 | # Configure a headless display to test plot generation 12 | before_script: 13 | - "export DISPLAY=:99.0" 14 | - "sh -e /etc/init.d/xvfb start" 15 | - sleep 3 # give xvfb some time to start 16 | # Command to run tests. 17 | script: 18 | - "coverage run --source=pyheat setup.py test" 19 | after_success: 20 | - "coveralls" 21 | -------------------------------------------------------------------------------- /CHANGELOG.rst: -------------------------------------------------------------------------------- 1 | Release History 2 | =============== 3 | 4 | v0.0.5 - v0.0.6 5 | --------------- 6 | * Include scroll demo and minor corrections. 7 | 8 | v0.0.4 9 | ------ 10 | * Add scroll bar to allow for viewing large py files using scroll bar. 11 | 12 | 13 | v0.0.3 14 | ------ 15 | * Fix for upstream pprofile changes thanks to @hinnefe2. 16 | 17 | 18 | v0.0.2 19 | ------ 20 | * Ability to import ``PyHeat`` class from the module as ``from pyheat import PyHeat``. 21 | * Color inversion of code text for the darker end of the spectrum. 22 | * Continuous integration tested code. 23 | * Making pyfile as a positional argument as it is non optional. 24 | * Adding ``--out`` optional argument to the commandline to export the heatmap as an image file. 25 | 26 | 27 | v0.0.1 28 | ------ 29 | * Long time itch to code an idea. 30 | * First release. 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Vishwas B Sharma 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. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.rst LICENSE 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pyheat 2 | 3 | [![pypiv](https://img.shields.io/pypi/v/py-heat.svg)](https://pypi.python.org/pypi/py-heat) 4 | [![pyv](https://img.shields.io/pypi/pyversions/py-heat.svg)](https://pypi.python.org/pypi/py-heat) 5 | [![Build Status](https://travis-ci.org/csurfer/pyheat.svg?branch=master)](https://travis-ci.org/csurfer/pyheat) 6 | [![Coverage Status](https://coveralls.io/repos/github/csurfer/pyheat/badge.svg?branch=master)](https://coveralls.io/github/csurfer/pyheat?branch=master) 7 | [![Licence](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/csurfer/pyheat/master/LICENSE) 8 | [![Thanks](https://img.shields.io/badge/Say%20Thanks-!-1EAEDB.svg)](https://saythanks.io/to/csurfer) 9 | 10 | Profilers are extremely helpful tools. They help us dig deep into code, find and understand performance bottlenecks. But sometimes we just want to lay back, relax and still get a gist of the hot zones in our code. 11 | 12 | > A picture is worth a thousand words. 13 | 14 | So, instead of presenting the data in tabular form, if presented as a heatmap visualization, it makes comprehending the time distribution in the given program much easier and quicker. That is exactly what is being done here ! 15 | 16 | ## Demo 17 | 18 | ![Demo](http://i.imgur.com/qOeXUPR.png) 19 | 20 | ## Scroll Demo 21 | 22 | ![ScrollDemo](https://i.imgur.com/5IdH8AG.gif) 23 | 24 | ## Features 25 | 26 | - Simple CLI interface. 27 | - No complicated setup. 28 | - Heatmap visualization to view hot zones in code. 29 | - Ability to export the heatmap as an image file. 30 | - Ability to scroll, to help view heatmap of large py files. 31 | 32 | ## Setup 33 | 34 | ### Using pip 35 | 36 | ```bash 37 | pip install py-heat 38 | ``` 39 | 40 | ### Directly from the repository 41 | 42 | ```bash 43 | git clone https://github.com/csurfer/pyheat.git 44 | python pyheat/setup.py install 45 | ``` 46 | 47 | ## Usage 48 | 49 | ### As a command 50 | 51 | ```bash 52 | # To view the heatmap. 53 | pyheat 54 | # To output the heatmap as a file. 55 | pyheat --out image_file.png 56 | pyheat --help 57 | ``` 58 | 59 | ### As a module 60 | 61 | ```python 62 | from pyheat import PyHeat 63 | ph = PyHeat() 64 | ph.create_heatmap() 65 | # To view the heatmap. 66 | ph.show_heatmap() 67 | # To output the heatmap as a file. 68 | ph.show_heatmap('image_file.png') 69 | ``` 70 | 71 | ## Contributing 72 | 73 | ### Bug Reports and Feature Requests 74 | 75 | Please use [issue tracker](https://github.com/csurfer/pyheat/issues) for reporting bugs or feature requests. 76 | 77 | ### Development 78 | 79 | Pull requests are most welcome. 80 | 81 | ### Buy the developer a cup of coffee! 82 | 83 | If you found the utility helpful you can buy me a cup of coffee using 84 | 85 | [![Donate](https://www.paypalobjects.com/webstatic/en_US/i/btn/png/silver-pill-paypal-44px.png)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=3BSBW7D45C4YN&lc=US¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted) 86 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | pyheat 2 | ====== 3 | 4 | |pypiv| |pyv| |Licence| |Build Status| |Coverage Status| |Thanks| 5 | 6 | Profilers are extremely helpful tools. They help us dig deep into code, 7 | find and understand performance bottlenecks. But sometimes we just want 8 | to lay back, relax and still get a gist of the hot zones in our code. 9 | 10 | A picture is worth a thousand words. 11 | 12 | So, instead of presenting the data in tabular form, if presented as a 13 | heatmap visualization, it makes comprehending the time distribution in 14 | the given program much easier and quicker. That is exactly what is being 15 | done here ! 16 | 17 | Demo 18 | ---- 19 | 20 | |Demo| 21 | 22 | Scroll Demo 23 | ----------- 24 | 25 | |ScrollDemo| 26 | 27 | Features 28 | -------- 29 | 30 | * Simple CLI interface. 31 | 32 | * No complicated setup. 33 | 34 | * Heatmap visualization to view hot zones in code. 35 | 36 | * Ability to export the heatmap as an image file. 37 | 38 | * Ability to scroll, to help view heatmap of large py files. 39 | 40 | Setup 41 | ----- 42 | 43 | Using pip 44 | ~~~~~~~~~ 45 | 46 | .. code:: bash 47 | 48 | pip install py-heat 49 | 50 | Directly from the repository 51 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 52 | 53 | .. code:: bash 54 | 55 | git clone https://github.com/csurfer/pyheat.git 56 | python pyheat/setup.py install 57 | 58 | Usage 59 | ----- 60 | 61 | As a command 62 | ~~~~~~~~~~~~ 63 | 64 | .. code:: bash 65 | 66 | # To view the heatmap. 67 | pyheat 68 | # To output the heatmap as a file. 69 | pyheat --out image_file.png 70 | pyheat --help 71 | 72 | As a module 73 | ~~~~~~~~~~~ 74 | 75 | .. code:: python 76 | 77 | from pyheat import PyHeat 78 | ph = PyHeat() 79 | ph.create_heatmap() 80 | # To view the heatmap. 81 | ph.show_heatmap() 82 | # To output the heatmap as a file. 83 | ph.show_heatmap('image_file.png') 84 | 85 | Contributing 86 | ------------ 87 | 88 | Bug Reports and Feature Requests 89 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 90 | 91 | Please use `issue tracker`_ for reporting bugs or feature requests. 92 | 93 | Development 94 | ~~~~~~~~~~~ 95 | 96 | Pull requests are most welcome. 97 | 98 | 99 | Buy the developer a cup of coffee! 100 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 101 | 102 | If you found the utility helpful you can buy me a cup of coffee using 103 | 104 | |Donate| 105 | 106 | .. |Donate| image:: https://www.paypalobjects.com/webstatic/en_US/i/btn/png/silver-pill-paypal-44px.png 107 | :target: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=3BSBW7D45C4YN&lc=US¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted 108 | 109 | .. |Thanks| image:: https://img.shields.io/badge/Say%20Thanks-!-1EAEDB.svg 110 | :target: https://saythanks.io/to/csurfer 111 | 112 | .. _issue tracker: https://github.com/csurfer/pyheat/issues 113 | 114 | .. |Build Status| image:: https://travis-ci.org/csurfer/pyheat.svg?branch=master 115 | :target: https://travis-ci.org/csurfer/pyheat 116 | 117 | .. |Licence| image:: https://img.shields.io/badge/license-MIT-blue.svg 118 | :target: https://raw.githubusercontent.com/csurfer/pyheat/master/LICENSE 119 | 120 | .. |Coverage Status| image:: https://coveralls.io/repos/github/csurfer/pyheat/badge.svg?branch=master 121 | :target: https://coveralls.io/github/csurfer/pyheat?branch=master 122 | 123 | .. |Demo| image:: http://i.imgur.com/qOeXUPR.png 124 | 125 | .. |ScrollDemo| image:: https://i.imgur.com/5IdH8AG.gif 126 | 127 | .. |pypiv| image:: https://img.shields.io/pypi/v/py-heat.svg 128 | :target: https://pypi.python.org/pypi/py-heat 129 | 130 | .. |pyv| image:: https://img.shields.io/pypi/pyversions/py-heat.svg 131 | :target: https://pypi.python.org/pypi/py-heat 132 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate 2 | -------------------------------------------------------------------------------- /pyheat/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # __ __ 4 | # ____ __ __/ /_ ___ ____ _/ /_ 5 | # / __ \/ / / / __ \/ _ \/ __ `/ __/ 6 | # / /_/ / /_/ / / / / __/ /_/ / /_ 7 | # / .___/\__, /_/ /_/\___/\__,_/\__/ 8 | # /_/ /____/ 9 | 10 | """ 11 | pyheat module 12 | ~~~~~~~~~~~~~ 13 | 14 | Usage of PyHeat class: 15 | 16 | >>> from pyheat import PyHeat 17 | >>> ph = PyHeat() 18 | >>> ph.create_heatmap() 19 | >>> ph.show_heatmap() 20 | 21 | :copyright: (c) 2017 by Vishwas B Sharma. 22 | :license: MIT, see LICENSE for more details. 23 | """ 24 | 25 | from .pyheat import PyHeat 26 | -------------------------------------------------------------------------------- /pyheat/__version__.py: -------------------------------------------------------------------------------- 1 | # __ __ 2 | # ____ __ __/ /_ ___ ____ _/ /_ 3 | # / __ \/ / / / __ \/ _ \/ __ `/ __/ 4 | # / /_/ / /_/ / / / / __/ /_/ / /_ 5 | # / .___/\__, /_/ /_/\___/\__,_/\__/ 6 | # /_/ /____/ 7 | 8 | __title__ = 'pyheat' 9 | __description__ = 'pprofile + matplotlib = Python program profiled as an awesome heatmap!' 10 | __url__ = 'https://github.com/csurfer/pyheat' 11 | __version__ = '0.0.6' 12 | __author__ = 'Vishwas B Sharma' 13 | __author_email__ = 'sharma.vishwas88@gmail.com' 14 | __license__ = 'MIT' 15 | __copyright__ = 'Copyright 2017 Vishwas B Sharma' 16 | -------------------------------------------------------------------------------- /pyheat/commandline.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | pyheat as a command 5 | ~~~~~~~~~~~~~~~~~~ 6 | 7 | Usage: 8 | 9 | >>> pyheat --help 10 | usage: pyheat [-h] [-o OUT] pyfile 11 | 12 | positional arguments: 13 | pyfile Python file to be profiled 14 | 15 | optional arguments: 16 | -h, --help show this help message and exit 17 | -o OUT, --out OUT Output file 18 | 19 | >>> pyheat 20 | # Displays the heatmap for the file. 21 | 22 | >>> pyheat --out myimage.png 23 | # Saves the heatmap as an image in file myimage.png 24 | """ 25 | 26 | import argparse 27 | 28 | from .pyheat import PyHeat 29 | 30 | 31 | def main(): 32 | """Starting point for the program execution.""" 33 | # Create command line parser. 34 | parser = argparse.ArgumentParser() 35 | # Adding command line arguments. 36 | parser.add_argument('-o', '--out', help='Output file', default=None) 37 | parser.add_argument('pyfile', help='Python file to be profiled', default=None) 38 | # Parse command line arguments. 39 | arguments = parser.parse_args() 40 | if arguments.pyfile is not None: 41 | # Core functionality. 42 | pyheat = PyHeat(arguments.pyfile) 43 | pyheat.create_heatmap() 44 | pyheat.show_heatmap(output_file=arguments.out, enable_scroll=True) 45 | pyheat.close_heatmap() 46 | else: 47 | # Print command help 48 | parser.print_help() 49 | 50 | 51 | if __name__ == '__main__': 52 | main() 53 | -------------------------------------------------------------------------------- /pyheat/pyheat.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | pyheat.pyheat 4 | ~~~~~~~~~~~ 5 | 6 | Class definitions to view python file as a heatmap highlighting 7 | the most time consuming parts of the file. 8 | """ 9 | 10 | import matplotlib.pyplot as plt 11 | import numpy as np 12 | import pprofile 13 | from matplotlib.widgets import Slider 14 | 15 | 16 | class PyHeat(object): 17 | """Class to display the python file provided as a heatmap highlighting the 18 | most time consuming parts of the file. 19 | """ 20 | 21 | class FileDetails(object): 22 | """Class to keep track of useful file related details used in creating 23 | heatmaps. 24 | """ 25 | 26 | def __init__(self, filepath): 27 | """Constructor. 28 | 29 | @param filepath: Path of the file to profile. 30 | """ 31 | self.path = filepath 32 | self.lines = [] 33 | self.length = 0 34 | self.data = None 35 | 36 | def __init__(self, filepath): 37 | """Constructor. 38 | 39 | @param filepath: Path of the file to profile. 40 | """ 41 | self.pyfile = PyHeat.FileDetails(filepath) 42 | self.line_profiler = None 43 | 44 | def create_heatmap(self): 45 | """Method to define the heatmap using profile data.""" 46 | # Profile the file. 47 | self.__profile_file() 48 | # Map profile stats to heatmap data. 49 | self.__fetch_heatmap_data_from_profile() 50 | # Create heatmap. 51 | self.__create_heatmap_plot() 52 | 53 | def show_heatmap(self, blocking=True, output_file=None, enable_scroll=False): 54 | """Method to actually display the heatmap created. 55 | 56 | @param blocking: When set to False makes an unblocking plot show. 57 | @param output_file: If not None the heatmap image is output to this 58 | file. Supported formats: (eps, pdf, pgf, png, ps, raw, rgba, svg, 59 | svgz) 60 | @param enable_scroll: Flag used add a scroll bar to scroll long files. 61 | """ 62 | if output_file is None: 63 | if enable_scroll: 64 | # Add a new axes which will be used as scroll bar. 65 | axpos = plt.axes([0.12, 0.1, 0.625, 0.03]) 66 | spos = Slider(axpos, 'Scroll', 10, len(self.pyfile.lines)) 67 | 68 | def update(val): 69 | """Method to update position when slider is moved.""" 70 | pos = spos.val 71 | self.ax.axis([0, 1, pos, pos - 10]) 72 | self.fig.canvas.draw_idle() 73 | 74 | spos.on_changed(update) 75 | plt.show(block=blocking) 76 | else: 77 | plt.savefig(output_file) 78 | 79 | def close_heatmap(self): 80 | """Method to close the heatmap display created.""" 81 | plt.close('all') 82 | 83 | def __profile_file(self): 84 | """Method used to profile the given file line by line.""" 85 | self.line_profiler = pprofile.Profile() 86 | self.line_profiler.runfile(open(self.pyfile.path, 'r'), {}, self.pyfile.path) 87 | 88 | def __get_line_profile_data(self): 89 | """Method to procure line profiles. 90 | 91 | @return: Line profiles if the file has been profiles else empty 92 | dictionary. 93 | """ 94 | if self.line_profiler is None: 95 | return {} 96 | 97 | # the [0] is because pprofile.Profile.file_dict stores the line_dict 98 | # in a list so that it can be modified in a thread-safe way 99 | # see https://github.com/vpelletier/pprofile/blob/da3d60a1b59a061a0e2113bf768b7cb4bf002ccb/pprofile.py#L398 100 | return self.line_profiler.file_dict[self.pyfile.path][0].line_dict 101 | 102 | def __fetch_heatmap_data_from_profile(self): 103 | """Method to create heatmap data from profile information.""" 104 | # Read lines from file. 105 | with open(self.pyfile.path, 'r') as file_to_read: 106 | for line in file_to_read: 107 | # Remove return char from the end of the line and add a 108 | # space in the beginning for better visibility. 109 | self.pyfile.lines.append(' ' + line.strip('\n')) 110 | 111 | # Total number of lines in file. 112 | self.pyfile.length = len(self.pyfile.lines) 113 | 114 | # Fetch line profiles. 115 | line_profiles = self.__get_line_profile_data() 116 | 117 | # Creating an array of data points. As the profile keys are 1 indexed 118 | # we should range from 1 to line_count + 1 and not 0 to line_count. 119 | arr = [] 120 | for line_num in range(1, self.pyfile.length + 1): 121 | if line_num in line_profiles: 122 | # line_profiles[i] will have multiple entries if line i is 123 | # invoked from multiple places in the code. Here we sum over 124 | # each invocation to get the total time spent on that line. 125 | line_times = [ltime for _, ltime in line_profiles[line_num].values()] 126 | arr.append([sum(line_times)]) 127 | else: 128 | arr.append([0.0]) 129 | 130 | # Create nd-array from list of data points. 131 | self.pyfile.data = np.array(arr) 132 | 133 | def __create_heatmap_plot(self): 134 | """Method to actually create the heatmap from profile stats.""" 135 | # Define the heatmap plot. 136 | height = len(self.pyfile.lines) / 3 137 | width = max(map(lambda x: len(x), self.pyfile.lines)) / 8 138 | self.fig, self.ax = plt.subplots(figsize=(width, height)) 139 | 140 | # Set second sub plot to occupy bottom 20% 141 | plt.subplots_adjust(bottom=0.20) 142 | 143 | # Heat scale orange to red 144 | heatmap = self.ax.pcolor(self.pyfile.data, cmap='OrRd') 145 | 146 | # X Axis 147 | # Remove X axis. 148 | self.ax.xaxis.set_visible(False) 149 | 150 | # Y Axis 151 | # Create lables for y-axis ticks 152 | row_labels = range(1, self.pyfile.length + 1) 153 | # Put y-axis major ticks at the middle of each cell. 154 | self.ax.set_yticks(np.arange(self.pyfile.data.shape[0]) + 0.5, minor=False) 155 | # Set y-tick labels. 156 | self.ax.set_yticklabels(row_labels, minor=False) 157 | # Inver y-axis to have top down line numbers 158 | self.ax.invert_yaxis() 159 | 160 | # Plot definitions 161 | # Set plot y-axis label. 162 | plt.ylabel('Line Number') 163 | # Annotate each cell with lines in file in order. 164 | max_time_spent_on_a_line = max(self.pyfile.data) 165 | for i, line in enumerate(self.pyfile.lines): 166 | # In order to ensure easy readability of the code, we need to 167 | # invert colour of text display for darker colours which 168 | # correspond to higher amount of time spent on the line. 169 | if self.pyfile.data[i] >= 0.7 * max_time_spent_on_a_line: 170 | color = (1.0, 1.0, 1.0) # White text 171 | else: 172 | color = (0.0, 0.0, 0.0) # Black text 173 | plt.text( 174 | 0.0, 175 | i + 0.5, 176 | line, 177 | ha='left', 178 | va='center', 179 | color=color, 180 | clip_on=True, 181 | ) 182 | 183 | # Define legend 184 | cbar = plt.colorbar(heatmap) 185 | cbar.set_label('# of seconds') 186 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # Requirement for profiling the program. 2 | pprofile 3 | # Requirement for heatmap. 4 | matplotlib 5 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | # This flag says that the code is written to work on both Python 2 and Python 3. 3 | universal=1 4 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | try: 3 | from setuptools import setup 4 | except ImportError: 5 | from distutils.core import setup 6 | 7 | from os import path 8 | 9 | here = path.abspath(path.dirname(__file__)) 10 | 11 | # Get the long description from the README file 12 | with open(path.join(here, 'README.rst')) as f: 13 | long_description = f.read() 14 | 15 | # Get package and author details. 16 | about = {} 17 | with open(path.join(here, 'pyheat', '__version__.py')) as f: 18 | exec(f.read(), about) 19 | 20 | setup( 21 | # Name of the module 22 | name='py-heat', 23 | # Details 24 | version=about['__version__'], 25 | description=about['__description__'], 26 | long_description=long_description, 27 | # The project's main homepage. 28 | url=about['__url__'], 29 | # Author details 30 | author=about['__author__'], 31 | author_email=about['__author_email__'], 32 | # License 33 | license=about['__license__'], 34 | packages=['pyheat'], 35 | entry_points={'console_scripts': ['pyheat=pyheat.commandline:main']}, 36 | test_suite='tests', 37 | keywords='heatmap matplotlib profiling python', 38 | classifiers=[ 39 | # Intended Audience. 40 | 'Intended Audience :: Developers', 41 | 'Intended Audience :: Education', 42 | # License. 43 | 'License :: OSI Approved :: MIT License', 44 | # Project maturity. 45 | 'Development Status :: 3 - Alpha', 46 | # Operating Systems. 47 | 'Operating System :: POSIX', 48 | # Supported Languages. 49 | 'Programming Language :: Python :: 2.7', 50 | 'Programming Language :: Python :: 3.4', 51 | 'Programming Language :: Python :: 3.5', 52 | 'Programming Language :: Python :: 3.6', 53 | # Topic tags. 54 | 'Topic :: Software Development :: Build Tools', 55 | 'Topic :: Software Development :: Libraries :: Python Modules', 56 | ], 57 | install_requires=['pprofile', 'matplotlib'], 58 | ) 59 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/csurfer/pyheat/6517df5d6f169763f30afa2577d460aeecc6679d/tests/__init__.py -------------------------------------------------------------------------------- /tests/pyheat_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | pyheat tests 5 | ~~~~~~~~~~ 6 | 7 | Usage from git root: 8 | 9 | >>> python setup.py test 10 | """ 11 | 12 | import os 13 | import unittest 14 | 15 | from pyheat import PyHeat 16 | 17 | 18 | class PyHeatTest(unittest.TestCase): 19 | def setUp(self): 20 | data_path = os.path.dirname(os.path.realpath(__file__)) 21 | self.pyheat = PyHeat(data_path + '/test_program.py') 22 | 23 | def test_pyheat_show(self): 24 | """Basic test to check pyheat class works end to end.""" 25 | self.pyheat.create_heatmap() 26 | self.pyheat.show_heatmap(blocking=False) 27 | 28 | def tearDown(self): 29 | self.pyheat.close_heatmap() 30 | 31 | 32 | if __name__ == '__main__': 33 | unittest.main() 34 | -------------------------------------------------------------------------------- /tests/test_program.py: -------------------------------------------------------------------------------- 1 | """File to test the usage of pyheat scipt.""" 2 | 3 | 4 | def powfun(a, b): 5 | """Method to raise a to power b using pow() function.""" 6 | return pow(a, b) 7 | 8 | 9 | def powop(a, b): 10 | """Method to raise a to power b using ** operator.""" 11 | return a ** b 12 | 13 | 14 | def powmodexp(a, b): 15 | """Method to raise a to power b using modular exponentiation.""" 16 | base = a 17 | res = 1 18 | while b > 0: 19 | if b & 1: 20 | res *= base 21 | base *= base 22 | b >>= 1 23 | return res 24 | 25 | 26 | def main(): 27 | """Test function.""" 28 | a, b = 2377757, 773 29 | pow_function = powfun(a, b) 30 | pow_operator = powop(a, b) 31 | pow_modular_exponentiation = powmodexp(a, b) 32 | 33 | 34 | if __name__ == '__main__': 35 | main() 36 | --------------------------------------------------------------------------------