Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-line_profiler for openSUSE:Factory checked in at 2022-09-30 17:57:52 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-line_profiler (Old) and /work/SRC/openSUSE:Factory/.python-line_profiler.new.2275 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-line_profiler" Fri Sep 30 17:57:52 2022 rev:7 rq:1007071 version:3.5.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-line_profiler/python-line_profiler.changes 2022-01-08 23:24:05.898255107 +0100 +++ /work/SRC/openSUSE:Factory/.python-line_profiler.new.2275/python-line_profiler.changes 2022-09-30 17:58:10.389297184 +0200 @@ -1,0 +2,17 @@ +Thu Sep 29 14:50:17 UTC 2022 - Yogalakshmi Arunachalam <yarunacha...@suse.com> + +- Update to Version 3.5.2 + * FIX: filepath test in is_ipython_kernel_cell for Windows #161 + * ADD: setup.py now checks LINE_PROFILER_BUILD_METHOD to determine how to build binaries + * ADD: LineProfiler.add_function warns if an added function has a __wrapped__ attribute + +- Update to Version 3.5.1 + * FIX: #19 line profiler now works on async functions again + +- Update to Version 3.5.0 + * FIX: #109 kernprof fails to write to stdout if stdout was replaced + * FIX: Fixes max of an empty sequence error #118 + * Make IPython optional + * FIX: #100 Exception raise ZeroDivisionError + +------------------------------------------------------------------- Old: ---- line_profiler-3.4.0.tar.gz New: ---- line_profiler-3.5.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-line_profiler.spec ++++++ --- /var/tmp/diff_new_pack.5WmRH9/_old 2022-09-30 17:58:10.789298039 +0200 +++ /var/tmp/diff_new_pack.5WmRH9/_new 2022-09-30 17:58:10.793298048 +0200 @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-line_profiler -Version: 3.4.0 +Version: 3.5.1 Release: 0 Summary: Line-by-line profiler License: BSD-3-Clause ++++++ line_profiler-3.4.0.tar.gz -> line_profiler-3.5.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/CHANGELOG.rst new/line_profiler-3.5.1/CHANGELOG.rst --- old/line_profiler-3.4.0/CHANGELOG.rst 2021-12-30 02:01:08.000000000 +0100 +++ new/line_profiler-3.5.1/CHANGELOG.rst 2022-05-29 03:05:18.000000000 +0200 @@ -1,10 +1,21 @@ Changes ======= +3.5.1 +~~~~~ +* FIX: #19 line profiler now works on async functions again + +3.5.0 +~~~~~ +* FIX: #109 kernprof fails to write to stdout if stdout was replaced +* FIX: Fixes max of an empty sequence error #118 +* Make IPython optional +* FIX: #100 Exception raise ZeroDivisionError + 3.4.0 ~~~~~ * Drop support for Python <= 3.5.x -* FIX: #104 issue with new IPython kernels +* FIX: #104 issue with new IPython kernels 3.3.1 ~~~~~ @@ -18,7 +29,7 @@ 3.2.6 ~~~~~ * FIX: Update MANIFEST.in to package pyproj.toml and missing pyx file -* CHANGE: Removed version experimental augmentation. +* CHANGE: Removed version experimental augmentation. 3.2.5 ~~~~~ @@ -40,7 +51,7 @@ 3.2.0 ~~~~~ -* Dropped 2.7 support, manylinux docker images no longer support 2.7 +* Dropped 2.7 support, manylinux docker images no longer support 2.7 * ENH: Add command line option to specify time unit and skip displaying functions which have not been profiled. * ENH: Unified versions of line_profiler and kernprof: kernprof version is now @@ -110,4 +121,3 @@ ~~~~~ * Initial release. - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/MANIFEST.in new/line_profiler-3.5.1/MANIFEST.in --- old/line_profiler-3.4.0/MANIFEST.in 1970-01-01 01:00:00.000000000 +0100 +++ new/line_profiler-3.5.1/MANIFEST.in 2021-05-01 00:40:57.000000000 +0200 @@ -0,0 +1,14 @@ +include *.md +include *.rst +include *.py +include *.txt +include *.toml +include run_tests.sh +recursive-include requirements *.txt +recursive-include tests *.py +recursive-include line_profiler *.txt +recursive-include line_profiler *.pyx +recursive-include line_profiler *.pxd +recursive-include line_profiler *.pyd +recursive-include line_profiler *.c +recursive-include line_profiler *.h diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/PKG-INFO new/line_profiler-3.5.1/PKG-INFO --- old/line_profiler-3.4.0/PKG-INFO 2021-12-30 02:01:24.562787500 +0100 +++ new/line_profiler-3.5.1/PKG-INFO 2022-05-29 03:05:39.600498000 +0200 @@ -1,19 +1,11 @@ Metadata-Version: 2.1 Name: line_profiler -Version: 3.4.0 +Version: 3.5.1 Summary: Line-by-line profiler. Home-page: https://github.com/pyutils/line_profiler Author: Robert Kern Author-email: robert.k...@enthought.com License: BSD -Description: line_profiler will profile the time individual lines of code take to execute. - The profiler is implemented in C via Cython in order to reduce the overhead of - profiling. - - Also included is the script kernprof.py which can be used to conveniently - profile Python applications and scripts either with line_profiler or with the - function-level profiling tools in the Python standard library. - Keywords: timing,timer,profiling,profiler,line_profiler Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable @@ -31,5 +23,18 @@ Classifier: Topic :: Software Development Description-Content-Type: text/x-rst Provides-Extra: all +Provides-Extra: ipython Provides-Extra: tests Provides-Extra: build +License-File: LICENSE.txt +License-File: LICENSE_Python.txt + +line_profiler will profile the time individual lines of code take to execute. +The profiler is implemented in C via Cython in order to reduce the overhead of +profiling. + +Also included is the script kernprof.py which can be used to conveniently +profile Python applications and scripts either with line_profiler or with the +function-level profiling tools in the Python standard library. + + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/README.rst new/line_profiler-3.5.1/README.rst --- old/line_profiler-3.4.0/README.rst 2021-12-30 02:01:08.000000000 +0100 +++ new/line_profiler-3.5.1/README.rst 2022-05-29 02:22:11.000000000 +0200 @@ -33,6 +33,10 @@ $ pip install line_profiler +Installation while ensuring a compatible IPython version can also be installed using pip:: + + $ pip install line_profiler[ipython] + Source releases and any binaries can be downloaded from the PyPI link. http://pypi.python.org/pypi/line_profiler @@ -56,7 +60,7 @@ As of 2021-06-04 Linux (x86_64 and i686), OSX (10_9_x86_64), and Win32 (win32, and amd64) binaries are available on pypi. -Alternateively on windows you might consider using Christoph Gohlke's +Alternatively on windows you might consider using Christoph Gohlke's unofficial line-profiler `precompiled win32 wheels <https://www.lfd.uci.edu/~gohlke/pythonlibs/#line_profiler>`_. @@ -251,12 +255,35 @@ $ python -m pstats script_to_profile.py.prof -Such files may also be viewed with graphical tools like SnakeViz_ and converted -through pyprof2calltree_ to run on kcachegrind_ and compatible apps. -.. _kcachegrind: http://kcachegrind.sourceforge.net/html/Home.html +Such files may also be viewed with graphical tools. A list of 3rd party tools +built on ``cProfile`` or ``line_profiler`` are as follows: + +* `pyprof2calltree <pyprof2calltree_>`_: converts profiling data to a format + that can be visualized using kcachegrind_ (linux only), wincachegrind_ + (windows only, unmaintained), or qcachegrind_. + +* `Line Profiler GUI <qt_profiler_gui_>`_: Qt GUI for line_profiler. + +* `SnakeViz <SnakeViz_>`_: A web viewer for Python profiling data. + +* `SnakeRunner <SnakeRunner_>`_: A fork of RunSnakeRun_, ported to Python 3. + +* `Pycharm plugin <pycharm_line_profiler_plugin_>`_: A PyCharm plugin for line_profiler. + +* `Spyder plugin <spyder_line_profiler_plugin_>`_: A plugin to run line_profiler from within the Spyder IDE. + + +.. _qcachegrind: https://sourceforge.net/projects/qcachegrindwin/ +.. _kcachegrind: https://kcachegrind.github.io/html/Home.html +.. _wincachegrind: https://github.com/ceefour/wincachegrind .. _pyprof2calltree: http://pypi.python.org/pypi/pyprof2calltree/ .. _SnakeViz: https://github.com/jiffyclub/snakeviz/ +.. _SnakeRunner: https://github.com/venthur/snakerunner +.. _RunSnakeRun: https://pypi.org/project/RunSnakeRun/ +.. _qt_profiler_gui: https://github.com/Nodd/lineprofilergui +.. _pycharm_line_profiler_plugin: https://plugins.jetbrains.com/plugin/16536-line-profiler +.. _spyder_line_profiler_plugin: https://github.com/spyder-ide/spyder-line-profiler Frequently Asked Questions ========================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/_skbuild/linux-x86_64-3.8/cmake-install/kernprof.py new/line_profiler-3.5.1/_skbuild/linux-x86_64-3.8/cmake-install/kernprof.py --- old/line_profiler-3.4.0/_skbuild/linux-x86_64-3.8/cmake-install/kernprof.py 1970-01-01 01:00:00.000000000 +0100 +++ new/line_profiler-3.5.1/_skbuild/linux-x86_64-3.8/cmake-install/kernprof.py 2021-12-29 23:20:40.000000000 +0100 @@ -0,0 +1,236 @@ +#!/usr/bin/env python +""" Script to conveniently run profilers on code in a variety of circumstances. +""" +import builtins +import functools +import os +import sys +from argparse import ArgumentError, ArgumentParser + +# NOTE: This version needs to be manually maintained with the line_profiler +# __version__ for now. +__version__ = '3.4.0' + +# Guard the import of cProfile such that 3.x people +# without lsprof can still use this script. +try: + from cProfile import Profile +except ImportError: + try: + from lsprof import Profile + except ImportError: + from profile import Profile + + +def execfile(filename, globals=None, locals=None): + """ Python 3.x doesn't have 'execfile' builtin """ + with open(filename, 'rb') as f: + exec(compile(f.read(), filename, 'exec'), globals, locals) +# ===================================== + + +CO_GENERATOR = 0x0020 + + +def is_generator(f): + """ Return True if a function is a generator. + """ + isgen = (f.__code__.co_flags & CO_GENERATOR) != 0 + return isgen + + +class ContextualProfile(Profile): + """ A subclass of Profile that adds a context manager for Python + 2.5 with: statements and a decorator. + """ + + def __init__(self, *args, **kwds): + super().__init__(*args, **kwds) + self.enable_count = 0 + + def enable_by_count(self, subcalls=True, builtins=True): + """ Enable the profiler if it hasn't been enabled before. + """ + if self.enable_count == 0: + self.enable(subcalls=subcalls, builtins=builtins) + self.enable_count += 1 + + def disable_by_count(self): + """ Disable the profiler if the number of disable requests matches the + number of enable requests. + """ + if self.enable_count > 0: + self.enable_count -= 1 + if self.enable_count == 0: + self.disable() + + def __call__(self, func): + """ Decorate a function to start the profiler on function entry and stop + it on function exit. + """ + # FIXME: refactor this into a utility function so that both it and + # line_profiler can use it. + if is_generator(func): + wrapper = self.wrap_generator(func) + else: + wrapper = self.wrap_function(func) + return wrapper + + # FIXME: refactor this stuff so that both LineProfiler and + # ContextualProfile can use the same implementation. + def wrap_generator(self, func): + """ Wrap a generator to profile it. + """ + @functools.wraps(func) + def wrapper(*args, **kwds): + g = func(*args, **kwds) + # The first iterate will not be a .send() + self.enable_by_count() + try: + item = next(g) + except StopIteration: + return + finally: + self.disable_by_count() + input = (yield item) + # But any following one might be. + while True: + self.enable_by_count() + try: + item = g.send(input) + except StopIteration: + return + finally: + self.disable_by_count() + input = (yield item) + return wrapper + + def wrap_function(self, func): + """ Wrap a function to profile it. + """ + @functools.wraps(func) + def wrapper(*args, **kwds): + self.enable_by_count() + try: + result = func(*args, **kwds) + finally: + self.disable_by_count() + return result + return wrapper + + def __enter__(self): + self.enable_by_count() + + def __exit__(self, exc_type, exc_val, exc_tb): + self.disable_by_count() + + +def find_script(script_name): + """ Find the script. + + If the input is not a file, then $PATH will be searched. + """ + if os.path.isfile(script_name): + return script_name + path = os.getenv('PATH', os.defpath).split(os.pathsep) + for dir in path: + if dir == '': + continue + fn = os.path.join(dir, script_name) + if os.path.isfile(fn): + return fn + + sys.stderr.write('Could not find script %s\n' % script_name) + raise SystemExit(1) + + +def main(args=None): + def positive_float(value): + val = float(value) + if val <= 0: + raise ArgumentError + return val + + parser = ArgumentParser(description='Run and profile a python script.') + parser.add_argument('-V', '--version', action='version', version=__version__) + parser.add_argument('-l', '--line-by-line', action='store_true', + help='Use the line-by-line profiler instead of cProfile. Implies --builtin.') + parser.add_argument('-b', '--builtin', action='store_true', + help="Put 'profile' in the builtins. Use 'profile.enable()'/'.disable()', " + "'@profile' to decorate functions, or 'with profile:' to profile a " + 'section of code.') + parser.add_argument('-o', '--outfile', + help="Save stats to <outfile> (default: 'scriptname.lprof' with " + "--line-by-line, 'scriptname.prof' without)") + parser.add_argument('-s', '--setup', + help='Code to execute before the code to profile') + parser.add_argument('-v', '--view', action='store_true', + help='View the results of the profile in addition to saving it') + parser.add_argument('-u', '--unit', default='1e-6', type=positive_float, + + help='Output unit (in seconds) in which the timing info is ' + 'displayed (default: 1e-6)') + parser.add_argument('-z', '--skip-zero', action='store_true', + help='Hide functions which have not been called') + + parser.add_argument('script', help='The python script file to run') + parser.add_argument('args', nargs='...', help='Optional script arguments') + + options = parser.parse_args(args) + + if not options.outfile: + extension = 'lprof' if options.line_by_line else 'prof' + options.outfile = '%s.%s' % (os.path.basename(options.script), extension) + + sys.argv = [options.script] + options.args + if options.setup is not None: + # Run some setup code outside of the profiler. This is good for large + # imports. + setup_file = find_script(options.setup) + __file__ = setup_file + __name__ = '__main__' + # Make sure the script's directory is on sys.path instead of just + # kernprof.py's. + sys.path.insert(0, os.path.dirname(setup_file)) + ns = locals() + execfile(setup_file, ns, ns) + + if options.line_by_line: + import line_profiler + prof = line_profiler.LineProfiler() + options.builtin = True + else: + prof = ContextualProfile() + if options.builtin: + builtins.__dict__['profile'] = prof + + script_file = find_script(options.script) + __file__ = script_file + __name__ = '__main__' + # Make sure the script's directory is on sys.path instead of just + # kernprof.py's. + sys.path.insert(0, os.path.dirname(script_file)) + + try: + try: + execfile_ = execfile + ns = locals() + if options.builtin: + execfile(script_file, ns, ns) + else: + prof.runctx('execfile_(%r, globals())' % (script_file,), ns, ns) + except (KeyboardInterrupt, SystemExit): + pass + finally: + prof.dump_stats(options.outfile) + print('Wrote profile results to %s' % options.outfile) + if options.view: + if isinstance(prof, ContextualProfile): + prof.print_stats() + else: + prof.print_stats(output_unit=options.unit, + stripzeros=options.skip_zero) + + +if __name__ == '__main__': + main(sys.argv[1:]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/_skbuild/linux-x86_64-3.8/cmake-install/line_profiler/__init__.py new/line_profiler-3.5.1/_skbuild/linux-x86_64-3.8/cmake-install/line_profiler/__init__.py --- old/line_profiler-3.4.0/_skbuild/linux-x86_64-3.8/cmake-install/line_profiler/__init__.py 1970-01-01 01:00:00.000000000 +0100 +++ new/line_profiler-3.5.1/_skbuild/linux-x86_64-3.8/cmake-install/line_profiler/__init__.py 2021-12-29 23:20:40.000000000 +0100 @@ -0,0 +1,22 @@ +""" +The line_profiler modula for doing line-by-line profiling of functions +""" +__submodules__ = [ + 'line_profiler', +] + +__autogen__ = """ +mkinit ./line_profiler/__init__.py --relative +mkinit ./line_profiler/__init__.py --relative -w +""" + + +from .line_profiler import __version__ + +from .line_profiler import (LineProfiler, LineProfilerMagics, + load_ipython_extension, load_stats, main, + show_func, show_text,) + +__all__ = ['LineProfiler', 'LineProfilerMagics', 'line_profiler', + 'load_ipython_extension', 'load_stats', 'main', 'show_func', + 'show_text', '__version__'] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/_skbuild/linux-x86_64-3.8/cmake-install/line_profiler/__main__.py new/line_profiler-3.5.1/_skbuild/linux-x86_64-3.8/cmake-install/line_profiler/__main__.py --- old/line_profiler-3.4.0/_skbuild/linux-x86_64-3.8/cmake-install/line_profiler/__main__.py 1970-01-01 01:00:00.000000000 +0100 +++ new/line_profiler-3.5.1/_skbuild/linux-x86_64-3.8/cmake-install/line_profiler/__main__.py 2021-12-29 23:20:40.000000000 +0100 @@ -0,0 +1,4 @@ +from .line_profiler import main + +if __name__ == '__main__': + main() Binary files old/line_profiler-3.4.0/_skbuild/linux-x86_64-3.8/cmake-install/line_profiler/_line_profiler.cpython-38-x86_64-linux-gnu.so and new/line_profiler-3.5.1/_skbuild/linux-x86_64-3.8/cmake-install/line_profiler/_line_profiler.cpython-38-x86_64-linux-gnu.so differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/_skbuild/linux-x86_64-3.8/cmake-install/line_profiler/line_profiler.py new/line_profiler-3.5.1/_skbuild/linux-x86_64-3.8/cmake-install/line_profiler/line_profiler.py --- old/line_profiler-3.4.0/_skbuild/linux-x86_64-3.8/cmake-install/line_profiler/line_profiler.py 1970-01-01 01:00:00.000000000 +0100 +++ new/line_profiler-3.5.1/_skbuild/linux-x86_64-3.8/cmake-install/line_profiler/line_profiler.py 2021-12-29 23:20:40.000000000 +0100 @@ -0,0 +1,421 @@ +#!/usr/bin/env python +import pickle +import functools +import inspect +import linecache +import tempfile +import os +import sys +from io import StringIO +from argparse import ArgumentError, ArgumentParser + +from IPython.core.magic import (Magics, magics_class, line_magic) +from IPython.core.page import page +from IPython.utils.ipstruct import Struct +from IPython.core.error import UsageError + +try: + from ._line_profiler import LineProfiler as CLineProfiler +except ImportError as ex: + raise ImportError( + 'The line_profiler._line_profiler c-extension is not importable. ' + f'Has it been compiled? Underlying error is ex={ex!r}' + ) + +__version__ = '3.4.0' + + +def is_coroutine(f): + return False + + +CO_GENERATOR = 0x0020 + + +def is_generator(f): + """ Return True if a function is a generator. + """ + isgen = (f.__code__.co_flags & CO_GENERATOR) != 0 + return isgen + + +class LineProfiler(CLineProfiler): + """ A profiler that records the execution times of individual lines. + """ + + def __call__(self, func): + """ Decorate a function to start the profiler on function entry and stop + it on function exit. + """ + self.add_function(func) + if is_coroutine(func): + wrapper = self.wrap_coroutine(func) + elif is_generator(func): + wrapper = self.wrap_generator(func) + else: + wrapper = self.wrap_function(func) + return wrapper + + def wrap_generator(self, func): + """ Wrap a generator to profile it. + """ + @functools.wraps(func) + def wrapper(*args, **kwds): + g = func(*args, **kwds) + # The first iterate will not be a .send() + self.enable_by_count() + try: + item = next(g) + except StopIteration: + return + finally: + self.disable_by_count() + input_ = (yield item) + # But any following one might be. + while True: + self.enable_by_count() + try: + item = g.send(input_) + except StopIteration: + return + finally: + self.disable_by_count() + input_ = (yield item) + return wrapper + + def wrap_function(self, func): + """ Wrap a function to profile it. + """ + @functools.wraps(func) + def wrapper(*args, **kwds): + self.enable_by_count() + try: + result = func(*args, **kwds) + finally: + self.disable_by_count() + return result + return wrapper + + def dump_stats(self, filename): + """ Dump a representation of the data to a file as a pickled LineStats + object from `get_stats()`. + """ + lstats = self.get_stats() + with open(filename, 'wb') as f: + pickle.dump(lstats, f, pickle.HIGHEST_PROTOCOL) + + def print_stats(self, stream=None, output_unit=None, stripzeros=False): + """ Show the gathered statistics. + """ + lstats = self.get_stats() + show_text(lstats.timings, lstats.unit, output_unit=output_unit, stream=stream, stripzeros=stripzeros) + + def run(self, cmd): + """ Profile a single executable statment in the main namespace. + """ + import __main__ + main_dict = __main__.__dict__ + return self.runctx(cmd, main_dict, main_dict) + + def runctx(self, cmd, globals, locals): + """ Profile a single executable statement in the given namespaces. + """ + self.enable_by_count() + try: + exec(cmd, globals, locals) + finally: + self.disable_by_count() + return self + + def runcall(self, func, *args, **kw): + """ Profile a single function call. + """ + self.enable_by_count() + try: + return func(*args, **kw) + finally: + self.disable_by_count() + + def add_module(self, mod): + """ Add all the functions in a module and its classes. + """ + from inspect import isclass, isfunction + + nfuncsadded = 0 + for item in mod.__dict__.values(): + if isclass(item): + for k, v in item.__dict__.items(): + if isfunction(v): + self.add_function(v) + nfuncsadded += 1 + elif isfunction(item): + self.add_function(item) + nfuncsadded += 1 + + return nfuncsadded + + +def is_ipython_kernel_cell(filename): + """ Return True if a filename corresponds to a Jupyter Notebook cell + """ + return ( + filename.startswith('<ipython-input-') or + filename.startswith(tempfile.gettempdir() + '/ipykernel_') or + filename.startswith(tempfile.gettempdir() + '/xpython_') + ) + + +def show_func(filename, start_lineno, func_name, timings, unit, + output_unit=None, stream=None, stripzeros=False): + """ Show results for a single function. + """ + if stream is None: + stream = sys.stdout + + template = '%6s %9s %12s %8s %8s %-s' + d = {} + total_time = 0.0 + linenos = [] + for lineno, nhits, time in timings: + total_time += time + linenos.append(lineno) + + if stripzeros and total_time == 0: + return + + if output_unit is None: + output_unit = unit + scalar = unit / output_unit + + stream.write('Total time: %g s\n' % (total_time * unit)) + if os.path.exists(filename) or is_ipython_kernel_cell(filename): + stream.write(f'File: {filename}\n') + stream.write(f'Function: {func_name} at line {start_lineno}\n') + if os.path.exists(filename): + # Clear the cache to ensure that we get up-to-date results. + linecache.clearcache() + all_lines = linecache.getlines(filename) + sublines = inspect.getblock(all_lines[start_lineno - 1:]) + else: + stream.write('\n') + stream.write(f'Could not find file {filename}\n') + stream.write('Are you sure you are running this program from the same directory\n') + stream.write('that you ran the profiler from?\n') + stream.write("Continuing without the function's contents.\n") + # Fake empty lines so we can see the timings, if not the code. + nlines = max(linenos) - min(min(linenos), start_lineno) + 1 + sublines = [''] * nlines + for lineno, nhits, time in timings: + d[lineno] = (nhits, + '%5.1f' % (time * scalar), + '%5.1f' % (float(time) * scalar / nhits), + '%5.1f' % (100 * time / total_time) ) + linenos = range(start_lineno, start_lineno + len(sublines)) + empty = ('', '', '', '') + header = template % ('Line #', 'Hits', 'Time', 'Per Hit', '% Time', + 'Line Contents') + stream.write('\n') + stream.write(header) + stream.write('\n') + stream.write('=' * len(header)) + stream.write('\n') + for lineno, line in zip(linenos, sublines): + nhits, time, per_hit, percent = d.get(lineno, empty) + txt = template % (lineno, nhits, time, per_hit, percent, + line.rstrip('\n').rstrip('\r')) + stream.write(txt) + stream.write('\n') + stream.write('\n') + + +def show_text(stats, unit, output_unit=None, stream=None, stripzeros=False): + """ Show text for the given timings. + """ + if stream is None: + stream = sys.stdout + + if output_unit is not None: + stream.write('Timer unit: %g s\n\n' % output_unit) + else: + stream.write('Timer unit: %g s\n\n' % unit) + + for (fn, lineno, name), timings in sorted(stats.items()): + show_func(fn, lineno, name, stats[fn, lineno, name], unit, + output_unit=output_unit, stream=stream, + stripzeros=stripzeros) + + +@magics_class +class LineProfilerMagics(Magics): + + @line_magic + def lprun(self, parameter_s=''): + """ Execute a statement under the line-by-line profiler from the + line_profiler module. + + Usage: + %lprun -f func1 -f func2 <statement> + + The given statement (which doesn't require quote marks) is run via the + LineProfiler. Profiling is enabled for the functions specified by the -f + options. The statistics will be shown side-by-side with the code through the + pager once the statement has completed. + + Options: + + -f <function>: LineProfiler only profiles functions and methods it is told + to profile. This option tells the profiler about these functions. Multiple + -f options may be used. The argument may be any expression that gives + a Python function or method object. However, one must be careful to avoid + spaces that may confuse the option parser. + + -m <module>: Get all the functions/methods in a module + + One or more -f or -m options are required to get any useful results. + + -D <filename>: dump the raw statistics out to a pickle file on disk. The + usual extension for this is ".lprof". These statistics may be viewed later + by running line_profiler.py as a script. + + -T <filename>: dump the text-formatted statistics with the code side-by-side + out to a text file. + + -r: return the LineProfiler object after it has completed profiling. + + -s: strip out all entries from the print-out that have zeros. + + -u: specify time unit for the print-out in seconds. + """ + + # Escape quote markers. + opts_def = Struct(D=[''], T=[''], f=[], m=[], u=None) + parameter_s = parameter_s.replace('"', r'\"').replace("'", r"\'") + opts, arg_str = self.parse_options(parameter_s, 'rsf:m:D:T:u:', list_all=True) + opts.merge(opts_def) + + global_ns = self.shell.user_global_ns + local_ns = self.shell.user_ns + + # Get the requested functions. + funcs = [] + for name in opts.f: + try: + funcs.append(eval(name, global_ns, local_ns)) + except Exception as e: + raise UsageError(f'Could not find module {name}.\n{e.__class__.__name__}: {e}') + + profile = LineProfiler(*funcs) + + # Get the modules, too + for modname in opts.m: + try: + mod = __import__(modname, fromlist=['']) + profile.add_module(mod) + except Exception as e: + raise UsageError(f'Could not find module {modname}.\n{e.__class__.__name__}: {e}') + + if opts.u is not None: + try: + output_unit = float(opts.u[0]) + except Exception: + raise TypeError('Timer unit setting must be a float.') + else: + output_unit = None + + # Add the profiler to the builtins for @profile. + import builtins + + if 'profile' in builtins.__dict__: + had_profile = True + old_profile = builtins.__dict__['profile'] + else: + had_profile = False + old_profile = None + builtins.__dict__['profile'] = profile + + try: + try: + profile.runctx(arg_str, global_ns, local_ns) + message = '' + except SystemExit: + message = """*** SystemExit exception caught in code being profiled.""" + except KeyboardInterrupt: + message = ('*** KeyboardInterrupt exception caught in code being ' + 'profiled.') + finally: + if had_profile: + builtins.__dict__['profile'] = old_profile + + # Trap text output. + stdout_trap = StringIO() + profile.print_stats(stdout_trap, output_unit=output_unit, stripzeros='s' in opts) + output = stdout_trap.getvalue() + output = output.rstrip() + + page(output) + print(message, end='') + + dump_file = opts.D[0] + if dump_file: + profile.dump_stats(dump_file) + print(f'\n*** Profile stats pickled to file {dump_file!r}. {message}') + + text_file = opts.T[0] + if text_file: + pfile = open(text_file, 'w') + pfile.write(output) + pfile.close() + print(f'\n*** Profile printout saved to text file {text_file!r}. {message}') + + return_value = None + if 'r' in opts: + return_value = profile + + return return_value + + +def load_ipython_extension(ip): + """ API for IPython to recognize this module as an IPython extension. + """ + ip.register_magics(LineProfilerMagics) + + +def load_stats(filename): + """ Utility function to load a pickled LineStats object from a given + filename. + """ + with open(filename, 'rb') as f: + return pickle.load(f) + + +def main(): + def positive_float(value): + val = float(value) + if val <= 0: + raise ArgumentError + return val + + parser = ArgumentParser() + parser.add_argument('-V', '--version', action='version', version=__version__) + parser.add_argument( + '-u', + '--unit', + default='1e-6', + type=positive_float, + help='Output unit (in seconds) in which the timing info is displayed (default: 1e-6)', + ) + parser.add_argument( + '-z', + '--skip-zero', + action='store_true', + help='Hide functions which have not been called', + ) + parser.add_argument('profile_output', help='*.lprof file created by kernprof') + + args = parser.parse_args() + lstats = load_stats(args.profile_output) + show_text(lstats.timings, lstats.unit, output_unit=args.unit, stripzeros=args.skip_zero) + + +if __name__ == '__main__': + main() Binary files old/line_profiler-3.4.0/_skbuild/linux-x86_64-3.9/cmake-install/line_profiler/_line_profiler.cpython-39-x86_64-linux-gnu.so and new/line_profiler-3.5.1/_skbuild/linux-x86_64-3.9/cmake-install/line_profiler/_line_profiler.cpython-39-x86_64-linux-gnu.so differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/kernprof.py new/line_profiler-3.5.1/kernprof.py --- old/line_profiler-3.4.0/kernprof.py 2021-12-30 02:01:08.000000000 +0100 +++ new/line_profiler-3.5.1/kernprof.py 2022-05-29 03:05:18.000000000 +0200 @@ -9,7 +9,7 @@ # NOTE: This version needs to be manually maintained with the line_profiler # __version__ for now. -__version__ = '3.4.0' +__version__ = '3.5.1' # Guard the import of cProfile such that 3.x people # without lsprof can still use this script. @@ -211,6 +211,7 @@ # kernprof.py's. sys.path.insert(0, os.path.dirname(script_file)) + original_stdout = sys.stdout try: try: execfile_ = execfile @@ -226,10 +227,11 @@ print('Wrote profile results to %s' % options.outfile) if options.view: if isinstance(prof, ContextualProfile): - prof.print_stats() + prof.print_stats(stream=original_stdout) else: prof.print_stats(output_unit=options.unit, - stripzeros=options.skip_zero) + stripzeros=options.skip_zero, + stream=original_stdout) if __name__ == '__main__': diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/line_profiler/__init__.py new/line_profiler-3.5.1/line_profiler/__init__.py --- old/line_profiler-3.4.0/line_profiler/__init__.py 2021-12-30 02:01:08.000000000 +0100 +++ new/line_profiler-3.5.1/line_profiler/__init__.py 2022-04-01 08:53:10.000000000 +0200 @@ -3,6 +3,7 @@ """ __submodules__ = [ 'line_profiler', + 'ipython_extension', ] __autogen__ = """ @@ -13,10 +14,10 @@ from .line_profiler import __version__ -from .line_profiler import (LineProfiler, LineProfilerMagics, +from .line_profiler import (LineProfiler, load_ipython_extension, load_stats, main, show_func, show_text,) -__all__ = ['LineProfiler', 'LineProfilerMagics', 'line_profiler', +__all__ = ['LineProfiler', 'line_profiler', 'load_ipython_extension', 'load_stats', 'main', 'show_func', 'show_text', '__version__'] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/line_profiler/ipython_extension.py new/line_profiler-3.5.1/line_profiler/ipython_extension.py --- old/line_profiler-3.4.0/line_profiler/ipython_extension.py 1970-01-01 01:00:00.000000000 +0100 +++ new/line_profiler-3.5.1/line_profiler/ipython_extension.py 2022-04-01 08:53:10.000000000 +0200 @@ -0,0 +1,143 @@ +from io import StringIO + +from IPython.core.magic import Magics, magics_class, line_magic +from IPython.core.page import page +from IPython.utils.ipstruct import Struct +from IPython.core.error import UsageError + +from .line_profiler import LineProfiler + + +@magics_class +class LineProfilerMagics(Magics): + @line_magic + def lprun(self, parameter_s=""): + """ Execute a statement under the line-by-line profiler from the + line_profiler module. + + Usage: + %lprun -f func1 -f func2 <statement> + + The given statement (which doesn't require quote marks) is run via the + LineProfiler. Profiling is enabled for the functions specified by the -f + options. The statistics will be shown side-by-side with the code through the + pager once the statement has completed. + + Options: + + -f <function>: LineProfiler only profiles functions and methods it is told + to profile. This option tells the profiler about these functions. Multiple + -f options may be used. The argument may be any expression that gives + a Python function or method object. However, one must be careful to avoid + spaces that may confuse the option parser. + + -m <module>: Get all the functions/methods in a module + + One or more -f or -m options are required to get any useful results. + + -D <filename>: dump the raw statistics out to a pickle file on disk. The + usual extension for this is ".lprof". These statistics may be viewed later + by running line_profiler.py as a script. + + -T <filename>: dump the text-formatted statistics with the code side-by-side + out to a text file. + + -r: return the LineProfiler object after it has completed profiling. + + -s: strip out all entries from the print-out that have zeros. + + -u: specify time unit for the print-out in seconds. + """ + + # Escape quote markers. + opts_def = Struct(D=[""], T=[""], f=[], m=[], u=None) + parameter_s = parameter_s.replace('"', r"\"").replace("'", r"\'") + opts, arg_str = self.parse_options(parameter_s, "rsf:m:D:T:u:", list_all=True) + opts.merge(opts_def) + + global_ns = self.shell.user_global_ns + local_ns = self.shell.user_ns + + # Get the requested functions. + funcs = [] + for name in opts.f: + try: + funcs.append(eval(name, global_ns, local_ns)) + except Exception as e: + raise UsageError( + f"Could not find module {name}.\n{e.__class__.__name__}: {e}" + ) + + profile = LineProfiler(*funcs) + + # Get the modules, too + for modname in opts.m: + try: + mod = __import__(modname, fromlist=[""]) + profile.add_module(mod) + except Exception as e: + raise UsageError( + f"Could not find module {modname}.\n{e.__class__.__name__}: {e}" + ) + + if opts.u is not None: + try: + output_unit = float(opts.u[0]) + except Exception: + raise TypeError("Timer unit setting must be a float.") + else: + output_unit = None + + # Add the profiler to the builtins for @profile. + import builtins + + if "profile" in builtins.__dict__: + had_profile = True + old_profile = builtins.__dict__["profile"] + else: + had_profile = False + old_profile = None + builtins.__dict__["profile"] = profile + + try: + try: + profile.runctx(arg_str, global_ns, local_ns) + message = "" + except SystemExit: + message = """*** SystemExit exception caught in code being profiled.""" + except KeyboardInterrupt: + message = ( + "*** KeyboardInterrupt exception caught in code being " "profiled." + ) + finally: + if had_profile: + builtins.__dict__["profile"] = old_profile + + # Trap text output. + stdout_trap = StringIO() + profile.print_stats( + stdout_trap, output_unit=output_unit, stripzeros="s" in opts + ) + output = stdout_trap.getvalue() + output = output.rstrip() + + page(output) + print(message, end="") + + dump_file = opts.D[0] + if dump_file: + profile.dump_stats(dump_file) + print(f"\n*** Profile stats pickled to file {dump_file!r}. {message}") + + text_file = opts.T[0] + if text_file: + pfile = open(text_file, "w") + pfile.write(output) + pfile.close() + print(f"\n*** Profile printout saved to text file {text_file!r}. {message}") + + return_value = None + if "r" in opts: + return_value = profile + + return return_value diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/line_profiler/line_profiler.py new/line_profiler-3.5.1/line_profiler/line_profiler.py --- old/line_profiler-3.4.0/line_profiler/line_profiler.py 2021-12-30 02:01:08.000000000 +0100 +++ new/line_profiler-3.5.1/line_profiler/line_profiler.py 2022-05-29 03:05:18.000000000 +0200 @@ -6,14 +6,8 @@ import tempfile import os import sys -from io import StringIO from argparse import ArgumentError, ArgumentParser -from IPython.core.magic import (Magics, magics_class, line_magic) -from IPython.core.page import page -from IPython.utils.ipstruct import Struct -from IPython.core.error import UsageError - try: from ._line_profiler import LineProfiler as CLineProfiler except ImportError as ex: @@ -22,11 +16,18 @@ f'Has it been compiled? Underlying error is ex={ex!r}' ) -__version__ = '3.4.0' +__version__ = '3.5.1' + + +def load_ipython_extension(ip): + """ API for IPython to recognize this module as an IPython extension. + """ + from .ipython_extension import LineProfilerMagics + ip.register_magics(LineProfilerMagics) def is_coroutine(f): - return False + return inspect.iscoroutinefunction(f) CO_GENERATOR = 0x0020 @@ -56,6 +57,22 @@ wrapper = self.wrap_function(func) return wrapper + def wrap_coroutine(self, func): + """ + Wrap a Python 3.5 coroutine to profile it. + """ + + @functools.wraps(func) + async def wrapper(*args, **kwds): + self.enable_by_count() + try: + result = await func(*args, **kwds) + finally: + self.disable_by_count() + return result + + return wrapper + def wrap_generator(self, func): """ Wrap a generator to profile it. """ @@ -155,6 +172,8 @@ return nfuncsadded +# This could be in the ipython_extension submodule, +# but it doesn't depend on the IPython module so it's easier to just let it stay here. def is_ipython_kernel_cell(filename): """ Return True if a filename corresponds to a Jupyter Notebook cell """ @@ -203,13 +222,17 @@ stream.write('that you ran the profiler from?\n') stream.write("Continuing without the function's contents.\n") # Fake empty lines so we can see the timings, if not the code. - nlines = max(linenos) - min(min(linenos), start_lineno) + 1 + nlines = 1 if not linenos else max(linenos) - min(min(linenos), start_lineno) + 1 sublines = [''] * nlines for lineno, nhits, time in timings: + if total_time == 0: # Happens rarely on empty function + percent = '' + else: + percent = '%5.1f' % (100 * time / total_time) d[lineno] = (nhits, '%5.1f' % (time * scalar), '%5.1f' % (float(time) * scalar / nhits), - '%5.1f' % (100 * time / total_time) ) + percent) linenos = range(start_lineno, start_lineno + len(sublines)) empty = ('', '', '', '') header = template % ('Line #', 'Hits', 'Time', 'Per Hit', '% Time', @@ -244,142 +267,6 @@ output_unit=output_unit, stream=stream, stripzeros=stripzeros) - -@magics_class -class LineProfilerMagics(Magics): - - @line_magic - def lprun(self, parameter_s=''): - """ Execute a statement under the line-by-line profiler from the - line_profiler module. - - Usage: - %lprun -f func1 -f func2 <statement> - - The given statement (which doesn't require quote marks) is run via the - LineProfiler. Profiling is enabled for the functions specified by the -f - options. The statistics will be shown side-by-side with the code through the - pager once the statement has completed. - - Options: - - -f <function>: LineProfiler only profiles functions and methods it is told - to profile. This option tells the profiler about these functions. Multiple - -f options may be used. The argument may be any expression that gives - a Python function or method object. However, one must be careful to avoid - spaces that may confuse the option parser. - - -m <module>: Get all the functions/methods in a module - - One or more -f or -m options are required to get any useful results. - - -D <filename>: dump the raw statistics out to a pickle file on disk. The - usual extension for this is ".lprof". These statistics may be viewed later - by running line_profiler.py as a script. - - -T <filename>: dump the text-formatted statistics with the code side-by-side - out to a text file. - - -r: return the LineProfiler object after it has completed profiling. - - -s: strip out all entries from the print-out that have zeros. - - -u: specify time unit for the print-out in seconds. - """ - - # Escape quote markers. - opts_def = Struct(D=[''], T=[''], f=[], m=[], u=None) - parameter_s = parameter_s.replace('"', r'\"').replace("'", r"\'") - opts, arg_str = self.parse_options(parameter_s, 'rsf:m:D:T:u:', list_all=True) - opts.merge(opts_def) - - global_ns = self.shell.user_global_ns - local_ns = self.shell.user_ns - - # Get the requested functions. - funcs = [] - for name in opts.f: - try: - funcs.append(eval(name, global_ns, local_ns)) - except Exception as e: - raise UsageError(f'Could not find module {name}.\n{e.__class__.__name__}: {e}') - - profile = LineProfiler(*funcs) - - # Get the modules, too - for modname in opts.m: - try: - mod = __import__(modname, fromlist=['']) - profile.add_module(mod) - except Exception as e: - raise UsageError(f'Could not find module {modname}.\n{e.__class__.__name__}: {e}') - - if opts.u is not None: - try: - output_unit = float(opts.u[0]) - except Exception: - raise TypeError('Timer unit setting must be a float.') - else: - output_unit = None - - # Add the profiler to the builtins for @profile. - import builtins - - if 'profile' in builtins.__dict__: - had_profile = True - old_profile = builtins.__dict__['profile'] - else: - had_profile = False - old_profile = None - builtins.__dict__['profile'] = profile - - try: - try: - profile.runctx(arg_str, global_ns, local_ns) - message = '' - except SystemExit: - message = """*** SystemExit exception caught in code being profiled.""" - except KeyboardInterrupt: - message = ('*** KeyboardInterrupt exception caught in code being ' - 'profiled.') - finally: - if had_profile: - builtins.__dict__['profile'] = old_profile - - # Trap text output. - stdout_trap = StringIO() - profile.print_stats(stdout_trap, output_unit=output_unit, stripzeros='s' in opts) - output = stdout_trap.getvalue() - output = output.rstrip() - - page(output) - print(message, end='') - - dump_file = opts.D[0] - if dump_file: - profile.dump_stats(dump_file) - print(f'\n*** Profile stats pickled to file {dump_file!r}. {message}') - - text_file = opts.T[0] - if text_file: - pfile = open(text_file, 'w') - pfile.write(output) - pfile.close() - print(f'\n*** Profile printout saved to text file {text_file!r}. {message}') - - return_value = None - if 'r' in opts: - return_value = profile - - return return_value - - -def load_ipython_extension(ip): - """ API for IPython to recognize this module as an IPython extension. - """ - ip.register_magics(LineProfilerMagics) - - def load_stats(filename): """ Utility function to load a pickled LineStats object from a given filename. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/line_profiler.egg-info/PKG-INFO new/line_profiler-3.5.1/line_profiler.egg-info/PKG-INFO --- old/line_profiler-3.4.0/line_profiler.egg-info/PKG-INFO 1970-01-01 01:00:00.000000000 +0100 +++ new/line_profiler-3.5.1/line_profiler.egg-info/PKG-INFO 2022-05-29 03:05:39.000000000 +0200 @@ -0,0 +1,40 @@ +Metadata-Version: 2.1 +Name: line-profiler +Version: 3.5.1 +Summary: Line-by-line profiler. +Home-page: https://github.com/pyutils/line_profiler +Author: Robert Kern +Author-email: robert.k...@enthought.com +License: BSD +Keywords: timing,timer,profiling,profiler,line_profiler +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: C +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Topic :: Software Development +Description-Content-Type: text/x-rst +Provides-Extra: all +Provides-Extra: ipython +Provides-Extra: tests +Provides-Extra: build +License-File: LICENSE.txt +License-File: LICENSE_Python.txt + +line_profiler will profile the time individual lines of code take to execute. +The profiler is implemented in C via Cython in order to reduce the overhead of +profiling. + +Also included is the script kernprof.py which can be used to conveniently +profile Python applications and scripts either with line_profiler or with the +function-level profiling tools in the Python standard library. + + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/line_profiler.egg-info/SOURCES.txt new/line_profiler-3.5.1/line_profiler.egg-info/SOURCES.txt --- old/line_profiler-3.4.0/line_profiler.egg-info/SOURCES.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/line_profiler-3.5.1/line_profiler.egg-info/SOURCES.txt 2022-05-29 03:05:39.000000000 +0200 @@ -0,0 +1,42 @@ +CHANGELOG.rst +CMakeLists.txt +LICENSE.txt +LICENSE_Python.txt +MANIFEST.in +README.rst +kernprof.py +pyproject.toml +requirements.txt +run_tests.py +setup.py +_skbuild/linux-x86_64-3.8/cmake-install/kernprof.py +_skbuild/linux-x86_64-3.8/cmake-install/line_profiler/__init__.py +_skbuild/linux-x86_64-3.8/cmake-install/line_profiler/__main__.py +_skbuild/linux-x86_64-3.8/cmake-install/line_profiler/_line_profiler.cpython-38-x86_64-linux-gnu.so +_skbuild/linux-x86_64-3.8/cmake-install/line_profiler/line_profiler.py +_skbuild/linux-x86_64-3.9/cmake-install/line_profiler/_line_profiler.cpython-39-x86_64-linux-gnu.so +line_profiler/CMakeLists.txt +line_profiler/__init__.py +line_profiler/__main__.py +line_profiler/_line_profiler.pyx +line_profiler/ipython_extension.py +line_profiler/line_profiler.py +line_profiler/python25.pxd +line_profiler/timers.c +line_profiler/timers.h +line_profiler/unset_trace.c +line_profiler/unset_trace.h +line_profiler.egg-info/PKG-INFO +line_profiler.egg-info/SOURCES.txt +line_profiler.egg-info/dependency_links.txt +line_profiler.egg-info/entry_points.txt +line_profiler.egg-info/requires.txt +line_profiler.egg-info/top_level.txt +requirements/build.txt +requirements/ipython.txt +requirements/runtime.txt +requirements/tests.txt +tests/test_cli.py +tests/test_ipython.py +tests/test_kernprof.py +tests/test_line_profiler.py \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/line_profiler.egg-info/dependency_links.txt new/line_profiler-3.5.1/line_profiler.egg-info/dependency_links.txt --- old/line_profiler-3.4.0/line_profiler.egg-info/dependency_links.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/line_profiler-3.5.1/line_profiler.egg-info/dependency_links.txt 2022-05-29 03:05:39.000000000 +0200 @@ -0,0 +1 @@ + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/line_profiler.egg-info/entry_points.txt new/line_profiler-3.5.1/line_profiler.egg-info/entry_points.txt --- old/line_profiler-3.4.0/line_profiler.egg-info/entry_points.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/line_profiler-3.5.1/line_profiler.egg-info/entry_points.txt 2022-05-29 03:05:39.000000000 +0200 @@ -0,0 +1,3 @@ +[console_scripts] +kernprof = kernprof:main + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/line_profiler.egg-info/requires.txt new/line_profiler-3.5.1/line_profiler.egg-info/requires.txt --- old/line_profiler-3.4.0/line_profiler.egg-info/requires.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/line_profiler-3.5.1/line_profiler.egg-info/requires.txt 2022-05-29 03:05:39.000000000 +0200 @@ -0,0 +1,44 @@ + +[all] +Cython +scikit-build +cmake +ninja +pytest>=4.6.11 +pytest-cov>=2.10.1 +coverage[toml]>=5.3 +ubelt>=1.0.1 + +[all:python_version <= "3.6"] +IPython<7.17.0,>=0.13 +IPython<7.17.0,>=0.13 + +[all:python_version >= "3.7"] +IPython>=0.13 +IPython>=0.13 + +[build] +Cython +scikit-build +cmake +ninja + +[ipython] + +[ipython:python_version <= "3.6"] +IPython<7.17.0,>=0.13 + +[ipython:python_version >= "3.7"] +IPython>=0.13 + +[tests] +pytest>=4.6.11 +pytest-cov>=2.10.1 +coverage[toml]>=5.3 +ubelt>=1.0.1 + +[tests:python_version <= "3.6"] +IPython<7.17.0,>=0.13 + +[tests:python_version >= "3.7"] +IPython>=0.13 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/line_profiler.egg-info/top_level.txt new/line_profiler-3.5.1/line_profiler.egg-info/top_level.txt --- old/line_profiler-3.4.0/line_profiler.egg-info/top_level.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/line_profiler-3.5.1/line_profiler.egg-info/top_level.txt 2022-05-29 03:05:39.000000000 +0200 @@ -0,0 +1,2 @@ +kernprof +line_profiler diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/requirements/ipython.txt new/line_profiler-3.5.1/requirements/ipython.txt --- old/line_profiler-3.4.0/requirements/ipython.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/line_profiler-3.5.1/requirements/ipython.txt 2022-04-01 08:53:10.000000000 +0200 @@ -0,0 +1,2 @@ +IPython >=0.13 ; python_version >= '3.7' +IPython >=0.13, <7.17.0 ; python_version <= '3.6' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/requirements/runtime.txt new/line_profiler-3.5.1/requirements/runtime.txt --- old/line_profiler-3.4.0/requirements/runtime.txt 2021-12-30 02:01:08.000000000 +0100 +++ new/line_profiler-3.5.1/requirements/runtime.txt 2022-04-01 08:53:10.000000000 +0200 @@ -1,2 +0,0 @@ -IPython >=0.13 ; python_version >= '3.7' -IPython >=0.13, <7.17.0 ; python_version <= '3.6' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/requirements/tests.txt new/line_profiler-3.5.1/requirements/tests.txt --- old/line_profiler-3.4.0/requirements/tests.txt 2021-12-30 02:01:08.000000000 +0100 +++ new/line_profiler-3.5.1/requirements/tests.txt 2022-04-01 08:54:20.000000000 +0200 @@ -1,4 +1,6 @@ pytest >= 4.6.11 pytest-cov >= 2.10.1 coverage[toml] >= 5.3 -ubelt >= 0.8.7 +ubelt >= 1.0.1 +IPython >=0.13 ; python_version >= '3.7' +IPython >=0.13, <7.17.0 ; python_version <= '3.6' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/requirements.txt new/line_profiler-3.5.1/requirements.txt --- old/line_profiler-3.4.0/requirements.txt 2021-12-30 02:01:08.000000000 +0100 +++ new/line_profiler-3.5.1/requirements.txt 2022-04-01 08:53:10.000000000 +0200 @@ -1,3 +1,4 @@ -r requirements/runtime.txt +-r requirements/ipython.txt -r requirements/build.txt -r requirements/tests.txt diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/setup.cfg new/line_profiler-3.5.1/setup.cfg --- old/line_profiler-3.4.0/setup.cfg 1970-01-01 01:00:00.000000000 +0100 +++ new/line_profiler-3.5.1/setup.cfg 2022-05-29 03:05:39.600498000 +0200 @@ -0,0 +1,4 @@ +[egg_info] +tag_build = +tag_date = 0 + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/setup.py new/line_profiler-3.5.1/setup.py --- old/line_profiler-3.4.0/setup.py 2021-12-30 02:01:08.000000000 +0100 +++ new/line_profiler-3.5.1/setup.py 2022-04-01 08:53:10.000000000 +0200 @@ -259,6 +259,7 @@ install_requires=parse_requirements('requirements/runtime.txt'), extras_require={ 'all': parse_requirements('requirements.txt'), + 'ipython': parse_requirements('requirements/ipython.txt'), 'tests': parse_requirements('requirements/tests.txt'), 'build': parse_requirements('requirements/build.txt'), }, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/line_profiler-3.4.0/tests/test_ipython.py new/line_profiler-3.5.1/tests/test_ipython.py --- old/line_profiler-3.4.0/tests/test_ipython.py 1970-01-01 01:00:00.000000000 +0100 +++ new/line_profiler-3.5.1/tests/test_ipython.py 2022-04-01 08:53:10.000000000 +0200 @@ -0,0 +1,21 @@ +import unittest +import io + +from IPython.testing.globalipapp import get_ipython + +class TestIPython(unittest.TestCase): + def test_init(self): + ip = get_ipython() + ip.run_line_magic('load_ext', 'line_profiler') + ip.run_cell(raw_cell='def func():\n return 2**20') + lprof = ip.run_line_magic('lprun', '-r -f func func()') + + timings = lprof.get_stats().timings + self.assertEqual(len(timings), 1) # 1 function + + func_data, lines_data = next(iter(timings.items())) + self.assertEqual(func_data[1], 1) # lineno of the function + self.assertEqual(func_data[2], "func") # function name + self.assertEqual(len(lines_data), 1) # 1 line of code + self.assertEqual(lines_data[0][0], 2) # lineno + self.assertEqual(lines_data[0][1], 1) # hits