Hello community,

here is the log from the commit of package python-memory_profiler for 
openSUSE:Factory checked in at 2020-01-22 22:46:37
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-memory_profiler (Old)
 and      /work/SRC/openSUSE:Factory/.python-memory_profiler.new.26092 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-memory_profiler"

Wed Jan 22 22:46:37 2020 rev:6 rq:766366 version:0.57.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-memory_profiler/python-memory_profiler.changes
    2019-04-24 13:57:39.439978351 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-memory_profiler.new.26092/python-memory_profiler.changes
 2020-01-22 22:47:03.740599539 +0100
@@ -1,0 +2,6 @@
+Wed Jan 22 15:34:33 UTC 2020 - Martin Sirringhaus <[email protected]>
+
+- Update to 0.57.0:
+  * no upstream changelog available
+
+-------------------------------------------------------------------

Old:
----
  memory_profiler-0.55.0.tar.gz

New:
----
  memory_profiler-0.57.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-memory_profiler.spec ++++++
--- /var/tmp/diff_new_pack.vRu4zo/_old  2020-01-22 22:47:04.964600155 +0100
+++ /var/tmp/diff_new_pack.vRu4zo/_new  2020-01-22 22:47:04.968600157 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-memory_profiler
 #
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-memory_profiler
-Version:        0.55.0
+Version:        0.57.0
 Release:        0
 Summary:        A module for monitoring memory usage of a python program
 License:        BSD-3-Clause

++++++ memory_profiler-0.55.0.tar.gz -> memory_profiler-0.57.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memory_profiler-0.55.0/PKG-INFO 
new/memory_profiler-0.57.0/PKG-INFO
--- old/memory_profiler-0.55.0/PKG-INFO 2018-12-14 16:21:33.000000000 +0100
+++ new/memory_profiler-0.57.0/PKG-INFO 2020-01-11 01:45:10.000000000 +0100
@@ -1,8 +1,8 @@
 Metadata-Version: 1.1
 Name: memory_profiler
-Version: 0.55.0
+Version: 0.57.0
 Summary: A module for monitoring memory usage of a python program
-Home-page: http://pypi.python.org/pypi/memory_profiler
+Home-page: https://github.com/pythonprofilers/memory_profiler
 Author: Fabian Pedregosa
 Author-email: [email protected]
 License: BSD
@@ -158,6 +158,11 @@
            :target: https://github.com/scikit-learn/scikit-learn/pull/2248
            :height: 350px
         
+        or, with ``mprof plot --flame`` (the function and timestamp names will 
appear on hover):
+        
+        .. image:: ./images/flamegraph.png
+           :height: 350px
+        
         A discussion of these capabilities can be found `here 
<http://fa.bianp.net/blog/2014/plot-memory-usage-as-a-function-of-time/>`_.
         
         .. warning:: If your Python file imports the memory profiler `from 
memory_profiler import profile` these timestamps will not be recorded. Comment 
out the import, leave your functions decorated, and re-run.
@@ -205,6 +210,19 @@
         the API directly, note that the return from ``memory_usage`` will 
include the
         child memory in a nested list along with the main process memory.
         
+        Plot settings
+        ===============================
+        
+        By default, the command line call is set as the graph title. If you 
wish to customize it, you can use the ``-t`` option to manually set the figure 
title.
+        
+        
+            mprof plot -t 'Recorded memory usage'
+        
+        You can also hide the function timestamps using the ``n`` flag, such as
+        
+            mprof plot -n
+        
+        
         Setting debugger breakpoints
         =============================
         It is possible to set breakpoints depending on the amount of memory 
used.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memory_profiler-0.55.0/README.rst 
new/memory_profiler-0.57.0/README.rst
--- old/memory_profiler-0.55.0/README.rst       2018-12-13 16:49:08.000000000 
+0100
+++ new/memory_profiler-0.57.0/README.rst       2019-11-05 21:56:35.000000000 
+0100
@@ -150,6 +150,11 @@
    :target: https://github.com/scikit-learn/scikit-learn/pull/2248
    :height: 350px
 
+or, with ``mprof plot --flame`` (the function and timestamp names will appear 
on hover):
+
+.. image:: ./images/flamegraph.png
+   :height: 350px
+
 A discussion of these capabilities can be found `here 
<http://fa.bianp.net/blog/2014/plot-memory-usage-as-a-function-of-time/>`_.
 
 .. warning:: If your Python file imports the memory profiler `from 
memory_profiler import profile` these timestamps will not be recorded. Comment 
out the import, leave your functions decorated, and re-run.
@@ -197,6 +202,19 @@
 the API directly, note that the return from ``memory_usage`` will include the
 child memory in a nested list along with the main process memory.
 
+Plot settings
+===============================
+
+By default, the command line call is set as the graph title. If you wish to 
customize it, you can use the ``-t`` option to manually set the figure title.
+
+
+    mprof plot -t 'Recorded memory usage'
+
+You can also hide the function timestamps using the ``n`` flag, such as
+
+    mprof plot -n
+
+
 Setting debugger breakpoints
 =============================
 It is possible to set breakpoints depending on the amount of memory used.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/memory_profiler-0.55.0/memory_profiler.egg-info/PKG-INFO 
new/memory_profiler-0.57.0/memory_profiler.egg-info/PKG-INFO
--- old/memory_profiler-0.55.0/memory_profiler.egg-info/PKG-INFO        
2018-12-14 16:21:33.000000000 +0100
+++ new/memory_profiler-0.57.0/memory_profiler.egg-info/PKG-INFO        
2020-01-11 01:45:10.000000000 +0100
@@ -1,8 +1,8 @@
 Metadata-Version: 1.1
 Name: memory-profiler
-Version: 0.55.0
+Version: 0.57.0
 Summary: A module for monitoring memory usage of a python program
-Home-page: http://pypi.python.org/pypi/memory_profiler
+Home-page: https://github.com/pythonprofilers/memory_profiler
 Author: Fabian Pedregosa
 Author-email: [email protected]
 License: BSD
@@ -158,6 +158,11 @@
            :target: https://github.com/scikit-learn/scikit-learn/pull/2248
            :height: 350px
         
+        or, with ``mprof plot --flame`` (the function and timestamp names will 
appear on hover):
+        
+        .. image:: ./images/flamegraph.png
+           :height: 350px
+        
         A discussion of these capabilities can be found `here 
<http://fa.bianp.net/blog/2014/plot-memory-usage-as-a-function-of-time/>`_.
         
         .. warning:: If your Python file imports the memory profiler `from 
memory_profiler import profile` these timestamps will not be recorded. Comment 
out the import, leave your functions decorated, and re-run.
@@ -205,6 +210,19 @@
         the API directly, note that the return from ``memory_usage`` will 
include the
         child memory in a nested list along with the main process memory.
         
+        Plot settings
+        ===============================
+        
+        By default, the command line call is set as the graph title. If you 
wish to customize it, you can use the ``-t`` option to manually set the figure 
title.
+        
+        
+            mprof plot -t 'Recorded memory usage'
+        
+        You can also hide the function timestamps using the ``n`` flag, such as
+        
+            mprof plot -n
+        
+        
         Setting debugger breakpoints
         =============================
         It is possible to set breakpoints depending on the amount of memory 
used.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/memory_profiler-0.55.0/memory_profiler.egg-info/SOURCES.txt 
new/memory_profiler-0.57.0/memory_profiler.egg-info/SOURCES.txt
--- old/memory_profiler-0.55.0/memory_profiler.egg-info/SOURCES.txt     
2018-12-14 16:21:33.000000000 +0100
+++ new/memory_profiler-0.57.0/memory_profiler.egg-info/SOURCES.txt     
2020-01-11 01:45:10.000000000 +0100
@@ -25,5 +25,6 @@
 test/test_nested.py
 test/test_precision_command_line.py
 test/test_precision_import.py
+test/test_stream_unicode.py
 test/test_tracemalloc.py
 test/test_unicode.py
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memory_profiler-0.55.0/memory_profiler.py 
new/memory_profiler-0.57.0/memory_profiler.py
--- old/memory_profiler-0.55.0/memory_profiler.py       2018-12-14 
16:14:18.000000000 +0100
+++ new/memory_profiler-0.57.0/memory_profiler.py       2020-01-11 
01:44:21.000000000 +0100
@@ -3,7 +3,7 @@
 # .. we'll use this to pass it to the child script ..
 _CLEAN_GLOBALS = globals().copy()
 
-__version__ = '0.55.0'
+__version__ = '0.57.0'
 
 _CMD_USAGE = "python -m memory_profiler script_file.py"
 
@@ -18,6 +18,7 @@
 import time
 import traceback
 import warnings
+import contextlib
 
 if sys.platform == "win32":
     # any value except signal.CTRL_C_EVENT and signal.CTRL_BREAK_EVENT
@@ -48,13 +49,11 @@
 
 if PY2:
     import __builtin__ as builtins
+    to_str = lambda x: x
     from future_builtins import filter
 else:
     import builtins
-
-
-    def unicode(x, *args):
-        return str(x)
+    to_str = lambda x: str(x)
 
 # .. get available packages ..
 try:
@@ -239,7 +238,7 @@
 
 def memory_usage(proc=-1, interval=.1, timeout=None, timestamps=False,
                  include_children=False, multiprocess=False, max_usage=False,
-                 retval=False, stream=None, backend=None):
+                 retval=False, stream=None, backend=None, max_iterations=None):
     """
     Return the memory usage of a process or piece of code
 
@@ -281,6 +280,10 @@
         to this file instead of stored in memory and returned at the end of
         the subprocess. Useful for long-running processes.
         Implies timestamps=True.
+        
+    max_iterations : int
+        Limits the number of iterations (calls to the process being 
monitored). Relevent
+        when the process is a python function. 
 
     Returns
     -------
@@ -301,13 +304,15 @@
         ret = -1
 
     if timeout is not None:
-        max_iter = int(timeout / interval)
+        max_iter = int(round(timeout / interval))
     elif isinstance(proc, int):
         # external process and no timeout
         max_iter = 1
     else:
         # for a Python function wait until it finishes
         max_iter = float('inf')
+        if max_iterations is not None:
+            max_iter = max_iterations
 
     if callable(proc):
         proc = (proc, (), {})
@@ -321,7 +326,9 @@
         else:
             raise ValueError
 
+        current_iter = 0
         while True:
+            current_iter += 1
             child_conn, parent_conn = Pipe()  # this will store MemTimer's 
results
             p = MemTimer(os.getpid(), interval, child_conn, backend,
                          timestamps=timestamps,
@@ -337,6 +344,9 @@
                 parent_conn.send(0)  # finish timing
                 ret = parent_conn.recv()
                 n_measurements = parent_conn.recv()
+                if max_usage:
+                    # Convert the one element list produced by MemTimer to a 
singular value
+                    ret = ret[0]
                 if retval:
                     ret = ret, returned
             except Exception:
@@ -347,7 +357,8 @@
                 raise
 
             p.join(5 * interval)
-            if n_measurements > 4 or interval < 1e-6:
+            
+            if (n_measurements > 4) or (current_iter == max_iter) or (interval 
< 1e-6):
                 break
             interval /= 10.
     elif isinstance(proc, subprocess.Popen):
@@ -459,16 +470,25 @@
 class _TimeStamperCM(object):
     """Time-stamping context manager."""
 
-    def __init__(self, timestamps, filename, backend):
+    def __init__(self, timestamps, filename, backend, timestamper=None, 
func=None):
         self.timestamps = timestamps
         self.filename = filename
         self.backend = backend
+        self.ts = timestamper
+        self.func = func
 
     def __enter__(self):
+        if self.ts is not None:
+            self.ts.current_stack_level += 1
+            self.ts.stack[self.func].append(self.ts.current_stack_level)
+
         self.timestamps.append(
             _get_memory(os.getpid(), self.backend, timestamps=True, 
filename=self.filename))
 
     def __exit__(self, *args):
+        if self.ts is not None:
+            self.ts.current_stack_level -= 1
+
         self.timestamps.append(
             _get_memory(os.getpid(), self.backend, timestamps=True, 
filename=self.filename))
 
@@ -481,6 +501,8 @@
     def __init__(self, backend):
         self.functions = {}
         self.backend = backend
+        self.current_stack_level = -1
+        self.stack = {}
 
     def __call__(self, func=None, precision=None):
         if func is not None:
@@ -515,11 +537,18 @@
             filename = inspect.getsourcefile(func)
         except TypeError:
             filename = '<unknown>'
-        return _TimeStamperCM(timestamps, filename, self.backend)
+        return _TimeStamperCM(
+            timestamps,
+            filename,
+            self.backend,
+            timestamper=self,
+            func=func
+        )
 
     def add_function(self, func):
         if func not in self.functions:
             self.functions[func] = []
+            self.stack[func] = []
 
     def wrap_function(self, func):
         """ Wrap a function to timestamp it.
@@ -535,7 +564,8 @@
                 _get_memory(os.getpid(), self.backend, timestamps=True, 
filename=filename)]
             self.functions[func].append(timestamps)
             try:
-                return func(*args, **kwds)
+                with self.call_on_stack(func, *args, **kwds) as result:
+                    return result
             finally:
                 # end time
                 timestamps.append(_get_memory(os.getpid(), self.backend, 
timestamps=True,
@@ -543,15 +573,24 @@
 
         return f
 
+    @contextlib.contextmanager
+    def call_on_stack(self, func, *args, **kwds):
+        self.current_stack_level += 1
+        self.stack[func].append(self.current_stack_level)
+
+        yield func(*args, **kwds)
+
+        self.current_stack_level -= 1
+
     def show_results(self, stream=None):
         if stream is None:
             stream = sys.stdout
 
         for func, timestamps in self.functions.items():
             function_name = "%s.%s" % (func.__module__, func.__name__)
-            for ts in timestamps:
-                stream.write("FUNC %s %.4f %.4f %.4f %.4f\n" % (
-                    (function_name,) + ts[0] + ts[1]))
+            for ts, level in zip(timestamps, self.stack[func]):
+                stream.write("FUNC %s %.4f %.4f %.4f %.4f %d\n" % (
+                    (function_name,) + ts[0] + ts[1] + (level,)))
 
 
 class CodeMap(dict):
@@ -778,7 +817,7 @@
                 mem = u''
                 inc = u''
             tmp = template.format(lineno, mem, inc, all_lines[lineno - 1])
-            stream.write(unicode(tmp, 'UTF-8'))
+            stream.write(to_str(tmp))
         stream.write(u'\n\n')
 
 
@@ -1013,7 +1052,7 @@
                                timeout=timeout, interval=interval,
                                max_usage=True,
                                include_children=include_children)
-            mem_usage.append(tmp[0])
+            mem_usage.append(tmp)
 
         result = MemitResult(mem_usage, baseline, repeat, timeout, interval,
                              include_children)
@@ -1118,7 +1157,15 @@
 def exec_with_profiler(filename, profiler, backend, passed_args=[]):
     from runpy import run_module
     builtins.__dict__['profile'] = profiler
-    ns = dict(_CLEAN_GLOBALS, profile=profiler)
+    ns = dict(_CLEAN_GLOBALS,
+              profile=profiler,
+             # Make sure the __file__ variable is usable
+             # by the script we're profiling
+              __file__=filename)
+    # Make sure the script's directory in on sys.path
+    # credit to line_profiler
+    sys.path.insert(0, os.path.dirname(script_filename))
+
     _backend = choose_backend(backend)
     sys.argv = [filename] + passed_args
     try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memory_profiler-0.55.0/mprof.py 
new/memory_profiler-0.57.0/mprof.py
--- old/memory_profiler-0.55.0/mprof.py 2018-12-14 16:13:49.000000000 +0100
+++ new/memory_profiler-0.57.0/mprof.py 2019-11-05 21:56:35.000000000 +0100
@@ -7,10 +7,12 @@
 import time
 import math
 import logging
+import itertools
 
 from collections import defaultdict
 from argparse import ArgumentParser, ArgumentError, REMAINDER, 
RawTextHelpFormatter
 
+import importlib
 import memory_profiler as mp
 
 ALL_ACTIONS = ("run", "rm", "clean", "list", "plot")
@@ -202,7 +204,7 @@
                              'Option 4: (--python flag present) 
"<PYTHON_MODULE> <ARG1> <ARG2>..." - profile python module\n'
                         )
     args = parser.parse_args()
-    
+
     if len(args.program) == 0:
         print("A program to run must be provided. Use -h for help")
         sys.exit(1)
@@ -329,8 +331,12 @@
             values = value.split(' ')
             f_name, mem_start, start, mem_end, end = values[:5]
             ts = func_ts.get(f_name, [])
-            ts.append([float(start), float(end),
-                       float(mem_start), float(mem_end)])
+            to_append = [float(start), float(end), float(mem_start), 
float(mem_end)]
+            if len(values) >= 6:
+                # There is a stack level field
+                stack_level = values[5]
+                to_append.append(int(stack_level))
+            ts.append(to_append)
             func_ts[f_name] = ts
 
         elif field == "CHLD":
@@ -450,6 +456,207 @@
     return mprofile
 
 
+
+FLAME_PLOTTER_VARS = {
+    'hovered_rect': None,
+    'hovered_text': None,
+    'alpha': None
+}
+
+def flame_plotter(filename, index=0, timestamps=True, children=True, 
options=None):
+    try:
+        import pylab as pl
+    except ImportError as e:
+        print("matplotlib is needed for plotting.")
+        print(e)
+        sys.exit(1)
+    import numpy as np  # pylab requires numpy anyway
+    mprofile = read_mprofile_file(filename)
+
+    if len(mprofile['timestamp']) == 0:
+        print('** No memory usage values have been found in the profile '
+              'file.**\nFile path: {0}\n'
+              'File may be empty or invalid.\n'
+              'It can be deleted with "mprof rm {0}"'.format(
+            mprofile['filename']))
+        sys.exit(0)
+
+    # Merge function timestamps and memory usage together
+    ts = mprofile['func_timestamp']
+    t = mprofile['timestamp']
+    mem = mprofile['mem_usage']
+    chld = mprofile['children']
+
+    if len(ts) > 0:
+        for values in ts.values():
+            for v in values:
+                t.extend(v[:2])
+                mem.extend(v[2:4])
+
+    mem = np.asarray(mem)
+    t = np.asarray(t)
+    ind = t.argsort()
+    mem = mem[ind]
+    t = t[ind]
+
+    if ts:
+        stack_size = 1 + max(ex[4] for executions in ts.values() for ex in 
executions)
+    else:
+        stack_size = 0
+    def level_to_saturation(level):
+        return 1 - 0.75 * level / stack_size
+
+    colors = [
+        itertools.cycle([
+            pl.matplotlib.colors.hsv_to_rgb((0, level_to_saturation(level), 
1)),
+            pl.matplotlib.colors.hsv_to_rgb((0.1, level_to_saturation(level), 
1)),
+        ]) for level in range(stack_size)
+    ]
+
+    # Plot curves
+    global_start = float(t[0])
+    t = t - global_start
+
+    max_mem = mem.max()
+    max_mem_ind = mem.argmax()
+
+    # cmap = pl.cm.get_cmap('gist_rainbow')
+    mem_line_colors = ("k", "b", "r", "g", "c", "y", "m")
+    mem_line_label = time.strftime("%d / %m / %Y - start at %H:%M:%S",
+                                   time.localtime(global_start)) \
+                     + ".{0:03d}".format(int(round(math.modf(global_start)[0] 
* 1000)))
+
+    pl.plot(t, mem, "-" + mem_line_colors[index % len(mem_line_colors)],
+            label=mem_line_label)
+
+    bottom, top = pl.ylim()
+    bottom += 0.001
+    top -= 0.001
+
+    ax = pl.gca()
+    ax.grid(True)
+    timestamp_ax = ax.twinx()
+    timestamp_ax.set_yticks([])
+    timestamp_ax.set_ylim((0, stack_size + 1))
+    timestamp_ax.grid(False)
+
+    # plot children, if any
+    if len(chld) > 0 and children:
+        cmpoint = (0,0) # maximal child memory
+
+        for idx, (proc, data) in enumerate(chld.items()):
+            # Create the numpy arrays from the series data
+            cts  = np.asarray([item[1] for item in data]) - global_start
+            cmem = np.asarray([item[0] for item in data])
+
+            # Plot the line to the figure
+            pl.plot(cts, cmem, "+-"  + mem_line_colors[(idx+1) % 
len(mem_line_colors)],
+                     label="child {}".format(proc))
+
+            # Detect the maximal child memory point
+            cmax_mem = cmem.max()
+            if cmax_mem > cmpoint[1]:
+                cmpoint = (cts[cmem.argmax()], cmax_mem)
+
+        # Add the marker lines for the maximal child memory usage
+        pl.vlines(cmpoint[0], pl.ylim()[0]+0.001, pl.ylim()[1] - 0.001, 'r', 
'--')
+        pl.hlines(cmpoint[1], pl.xlim()[0]+0.001, pl.xlim()[1] - 0.001, 'r', 
'--')
+
+    def mouse_motion_handler(event):
+        x, y = event.xdata, event.ydata
+        if x is not None and y is not None:
+            for coord, (name, text, rect) in rectangles.items():
+                x0, y0, x1, y1 = coord
+                if x0 < x < x1 and y0 < y < y1:
+                    if FLAME_PLOTTER_VARS['hovered_rect'] == rect:
+                        return
+
+                    if FLAME_PLOTTER_VARS['hovered_rect'] is not None:
+                        
FLAME_PLOTTER_VARS['hovered_rect'].set_alpha(FLAME_PLOTTER_VARS['alpha'])
+                        FLAME_PLOTTER_VARS['hovered_text'].set_color((0, 0, 0, 
0))
+                        FLAME_PLOTTER_VARS['hovered_rect'].set_linewidth(1)
+
+                    FLAME_PLOTTER_VARS['hovered_text'] = text
+                    FLAME_PLOTTER_VARS['hovered_rect'] = rect
+                    FLAME_PLOTTER_VARS['alpha'] = rect.get_alpha()
+                    FLAME_PLOTTER_VARS['hovered_rect'].set_alpha(0.8)
+                    FLAME_PLOTTER_VARS['hovered_rect'].set_linewidth(3)
+                    FLAME_PLOTTER_VARS['hovered_text'].set_color((0, 0, 0, 1))
+                    pl.draw()
+                    return
+
+        if FLAME_PLOTTER_VARS['hovered_rect'] is not None:
+            FLAME_PLOTTER_VARS['hovered_text'].set_color((0, 0, 0, 0))
+            
FLAME_PLOTTER_VARS['hovered_rect'].set_alpha(FLAME_PLOTTER_VARS['alpha'])
+            FLAME_PLOTTER_VARS['hovered_rect'].set_linewidth(1)
+            pl.draw()
+            FLAME_PLOTTER_VARS['hovered_rect'] = None
+            FLAME_PLOTTER_VARS['hovered_text'] = None
+
+    def mouse_click_handler(event):
+        x, y = event.xdata, event.ydata
+        if x is None or y is None:
+            return
+
+        for coord, _ in rectangles.items():
+            x0, y0, x1, y1 = coord
+            if x0 < x < x1 and y0 < y < y1:
+                toolbar = pl.gcf().canvas.toolbar
+                toolbar.push_current()
+                timestamp_ax.set_xlim(x0, x1)
+                timestamp_ax.set_ylim(y0, stack_size + 1)
+                toolbar.push_current()
+                pl.draw()
+                return
+
+    # plot timestamps, if any
+    if len(ts) > 0 and timestamps:
+        func_num = 0
+        f_labels = function_labels(ts.keys())
+        rectangles = {}
+        for f, exec_ts in ts.items():
+            for execution in exec_ts:
+                x0, x1 = execution[:2]
+                y0 = execution[4]
+                y1 = y0 + 1
+                x0 -= global_start
+                x1 -= global_start
+                color = next(colors[y0])
+                rect, text = add_timestamp_rectangle(
+                    timestamp_ax,
+                    x0, x1, y0, y1, f,
+                    color=color
+                )
+                rectangles[(x0, y0, x1, y1)] = (f, text, rect)
+            func_num += 1
+
+        # Disable hovering if there are too many rectangle to prevent slow down
+        if len(rectangles) < 100:
+            pl.gcf().canvas.mpl_connect('motion_notify_event', 
mouse_motion_handler)
+        pl.gcf().canvas.mpl_connect('button_release_event', 
mouse_click_handler)
+
+    if timestamps:
+        pl.hlines(max_mem,
+                  pl.xlim()[0] + 0.001, pl.xlim()[1] - 0.001,
+                  colors="r", linestyles="--")
+        pl.vlines(t[max_mem_ind], bottom, top,
+                  colors="r", linestyles="--")
+
+    pl.sca(ax)
+
+    return mprofile
+
+
+def add_timestamp_rectangle(ax, x0, x1, y0, y1, func_name, color='none'):
+    rect = ax.fill_betweenx((y0, y1), x0, x1, color=color, alpha=0.5, 
linewidth=1)
+    text = ax.text(x0, y1, func_name,
+        horizontalalignment='left',
+        verticalalignment='top',
+        color=(0, 0, 0, 0)
+    )
+    return rect, text
+
+
 def function_labels(dotted_function_names):
     state = {}
 
@@ -501,6 +708,8 @@
                         help="Save plot to file instead of displaying it.")
     parser.add_argument("--window", "-w", dest="xlim", type=xlim_type,
                         help="Plot a time-subset of the data. E.g. to plot 
between 0 and 20.5 seconds: --window 0,20.5")
+    parser.add_argument("--flame", "-f", dest="flame_mode", 
action="store_true",
+                        help="Plot the timestamps as a flame-graph instead of 
the default brackets")
     parser.add_argument("--backend",
                       help="Specify the Matplotlib backend to use")
     parser.add_argument("profiles", nargs="*",
@@ -517,6 +726,7 @@
         print("matplotlib is needed for plotting.")
         print(e)
         sys.exit(1)
+    pl.ioff()
 
     profiles = glob.glob("mprofile_??????????????.dat")
     profiles.sort()
@@ -547,7 +757,10 @@
         sys.exit(-1)
 
     fig = pl.figure(figsize=(14, 6), dpi=90)
-    ax = fig.add_axes([0.1, 0.1, 0.6, 0.75])
+    if not args.flame_mode:
+        ax = fig.add_axes([0.1, 0.1, 0.6, 0.75])
+    else:
+        ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
     if args.xlim is not None:
         pl.xlim(args.xlim[0], args.xlim[1])
 
@@ -555,8 +768,11 @@
         timestamps = False
     else:
         timestamps = True
+    plotter = plot_file
+    if args.flame_mode:
+        plotter = flame_plotter
     for n, filename in enumerate(filenames):
-        mprofile = plot_file(filename, index=n, timestamps=timestamps, 
options=args)
+        mprofile = plotter(filename, index=n, timestamps=timestamps, 
options=args)
     pl.xlabel("time (in seconds)")
     pl.ylabel("memory used (in MiB)")
 
@@ -568,9 +784,11 @@
 
     # place legend within the plot, make partially transparent in
     # case it obscures part of the lineplot
-    leg = ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))
-    leg.get_frame().set_alpha(0.5)
-    pl.grid()
+    if not args.flame_mode:
+        leg = ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))
+        leg.get_frame().set_alpha(0.5)
+        pl.grid()
+
     if args.output:
         pl.savefig(args.output)
     else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memory_profiler-0.55.0/setup.py 
new/memory_profiler-0.57.0/setup.py
--- old/memory_profiler-0.55.0/setup.py 2018-12-13 16:49:08.000000000 +0100
+++ new/memory_profiler-0.57.0/setup.py 2019-11-05 21:56:35.000000000 +0100
@@ -46,7 +46,7 @@
     version=find_version("memory_profiler.py"),
     author='Fabian Pedregosa',
     author_email='[email protected]',
-    url='http://pypi.python.org/pypi/memory_profiler',
+    url='https://github.com/pythonprofilers/memory_profiler',
     py_modules=['memory_profiler', 'mprof'],
     entry_points={
         'console_scripts' : ['mprof = mprof:main'],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memory_profiler-0.55.0/test/test_memory_usage.py 
new/memory_profiler-0.57.0/test/test_memory_usage.py
--- old/memory_profiler-0.55.0/test/test_memory_usage.py        2018-12-13 
16:49:08.000000000 +0100
+++ new/memory_profiler-0.57.0/test/test_memory_usage.py        2019-11-05 
21:56:35.000000000 +0100
@@ -1,4 +1,5 @@
 from memory_profiler import memory_usage
+import os
 
 
 def some_func(*args, **kwargs):
@@ -10,6 +11,36 @@
     mem, ret = memory_usage((some_func, (1, 2), dict(a=1)), retval=True)
     assert ret[0] == (1, 2)
     assert ret[1] == dict(a=1)
+    
+    
+def write_line(filepath):
+    with open(filepath, 'a') as the_file:
+        the_file.write('Testing\n')
+
+def test_max_iterations():
+    # Check that memory_usage works with max_iterations set (for python 
functions).
+    this_dir = os.path.dirname(os.path.realpath(__file__))
+    file = os.path.join(this_dir, 'temp_test_max_iterations_file.txt')
+    mem = memory_usage((write_line, (file, ), dict()), max_usage=True, 
max_iterations=1)
+    n_lines = sum(1 for line in open(file))
+    os.remove(file)
+    assert n_lines == 1
+
+
+def test_return_value_consistency():
+    # Test return values when watching process by PID
+    pid_mem_list = memory_usage(timeout=1)
+    assert type(pid_mem_list) == list, "Memory usage of process should be a 
list"
+    pid_mem_max = memory_usage(timeout=1, max_usage=True)
+    assert type(pid_mem_max) == float, "Max memory usage of process should be 
a number"
+    # Test return values when watching callable
+    func_mem_list = memory_usage((some_func, (42,), dict(a=42)))
+    assert type(func_mem_list) == list, "Memory usage of callable should be a 
list"
+    func_mem_max = memory_usage((some_func, (42,), dict(a=42)), max_usage=True)
+    assert type(func_mem_max) == float, "Max memory usage of callable should 
be a number"
+
 
 if __name__ == "__main__":
     test_memory_usage()
+    test_max_iterations()
+    test_return_value_consistency()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memory_profiler-0.55.0/test/test_stream_unicode.py 
new/memory_profiler-0.57.0/test/test_stream_unicode.py
--- old/memory_profiler-0.55.0/test/test_stream_unicode.py      1970-01-01 
01:00:00.000000000 +0100
+++ new/memory_profiler-0.57.0/test/test_stream_unicode.py      2019-11-05 
21:56:35.000000000 +0100
@@ -0,0 +1,14 @@
+# -*- coding: utf-8  -*-
+
+from memory_profiler import profile
+
+f = open('/dev/null', 'w')
+@profile(stream=f)
+def test_unicode(txt):
+    # test when unicode is present
+    txt = txt.replace (u"ی", u"ي") #Arabic Yah = ي
+    return txt
+
+
+if __name__ == '__main__':
+       test_unicode (u"ایست")


Reply via email to