8000 BUG: deallocate recursive closure in arrayprint.py (1.14 backport) by ahaldane · Pull Request #10622 · numpy/numpy · GitHub
[go: up one dir, main page]

Skip to content

BUG: deallocate recursive closure in arrayprint.py (1.14 backport) #10622

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 90 additions & 87 deletions numpy/core/arrayprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -642,118 +642,121 @@ def _extendLine(s, line, word, line_width, next_line_prefix, legacy):
line += word
return s, line

def _recursive_fmt(param, index, indent, curr_width):
"""
Helper function for _formatArray, to recursively print array elements.

def _formatArray(a, format_function, line_width, next_line_prefix,
separator, edge_items, summary_insert, legacy):
"""formatArray is designed for two modes of operation:
"param" are the values that are invariant under recursion, including
the array to be printed itself. index, indent and curr_width
are updated during recursion.
"""
# unpack parameters
a, format_function, separator, edge_items, summary_insert, legacy = param

1. Full output
axis = len(index)
axes_left = a.ndim - axis

2. Summarized output
if axes_left == 0:
return format_function(a[index])

"""
def recurser(index, hanging_indent, curr_width):
"""
By using this local function, we don't need to recurse with all the
arguments. Since this function is not created recursively, the cost is
not significant
"""
axis = len(index)
axes_left = a.ndim - axis
# when recursing, add a space to align with the [ added, and reduce the
# length of the line by 1
next_indent = indent + ' '
if legacy == '1.13':
next_width = curr_width
else:
next_width = curr_width - len(']')

if axes_left == 0:
return format_function(a[index])
a_len = a.shape[axis]
show_summary = summary_insert and 2*edge_items < a_len
if show_summary:
leading_items = edge_items
trailing_items = edge_items
else:
leading_items = 0
trailing_items = a_len

# when recursing, add a space to align with the [ added, and reduce the
# length of the line by 1
next_hanging_indent = hanging_indent + ' '
if legacy == '1.13':
next_width = curr_width
else:
next_width = curr_width - len(']')
# stringify the array with the hanging indent on the first line too
s = ''

a_len = a.shape[axis]
show_summary = summary_insert and 2*edge_items < a_len
if show_summary:
leading_items = edge_items
trailing_items = edge_items
# last axis (rows) - wrap elements if they would not fit on one line
if axes_left == 1:
# the length up until the beginning of the separator / bracket
if legacy == '1.13':
elem_width = curr_width - len(separator.rstrip())
else:
leading_items = 0
trailing_items = a_len
elem_width = curr_width - max(len(separator.rstrip()), len(']'))

# stringify the array with the hanging indent on the first line too
s = ''
line = indent
for i in range(leading_items):
word = _recursive_fmt(param, index + (i,), next_indent, next_width)
s, line = _extendLine(s, line, word, elem_width, indent, legacy)
line += separator

# last axis (rows) - wrap elements if they would not fit on one line
if axes_left == 1:
# the length up until the beginning of the separator / bracket
if show_summary:
s, line = _extendLine(
s, line, summary_insert, elem_width, indent, legacy)
if legacy == '1.13':
elem_width = curr_width - len(separator.rstrip())
line += ", "
else:
elem_width = curr_width - max(len(separator.rstrip()), len(']'))

line = hanging_indent
for i in range(leading_items):
word = recurser(index + (i,), next_hanging_indent, next_width)
s, line = _extendLine(
s, line, word, elem_width, hanging_indent, legacy)
line += separator

if show_summary:
s, line = _extendLine(
s, line, summary_insert, elem_width, hanging_indent, legacy)
if legacy == '1.13':
line += ", "
else:
line += separator

for i in range(trailing_items, 1, -1):
word = recurser(index + (-i,), next_hanging_indent, next_width)
s, line = _extendLine(
s, line, word, elem_width, hanging_indent, legacy)
line += separator
for i in range(trailing_items, 1, -1):
word = _recursive_fmt(param, index + (-i,), next_indent, next_width)
s, line = _extendLine(s, line, word, elem_width, indent, legacy)
line += separator

if legacy == '1.13':
# width of the separator is not considered on 1.13
elem_width = curr_width
word =_recursive_fmt(param, index + (-1,), next_indent, next_width)
s, line = _extendLine(
s, line, word, elem_width, indent, legacy)

s += line

# other axes - insert newlines between rows
else:
s = ''
line_sep = separator.rstrip() + '\n'*(axes_left - 1)

for i in range(leading_items):
nested =_recursive_fmt(param, index + (i,), next_indent, next_width)
s += indent + nested + line_sep

if show_summary:
if legacy == '1.13':
# width of the seperator is not considered on 1.13
elem_width = curr_width
word = recurser(index + (-1,), next_hanging_indent, next_width)
s, line = _extendLi 8000 ne(
s, line, word, elem_width, hanging_indent, legacy)
# trailing space, fixed nbr of newlines, and fixed separator
s += indent + summary_insert + ", \n"
else:
s += indent + summary_insert + line_sep

s += line
for i in range(trailing_items, 1, -1):
nested = _recursive_fmt(param, index + (-i,), next_indent,
next_width)
s += indent + nested + line_sep

# other axes - insert newlines between rows
else:
s = ''
line_sep = separator.rstrip() + '\n'*(axes_left - 1)
nested =_recursive_fmt(param, index + (-1,), next_indent, next_width)
s += indent + nested

for i in range(leading_items):
nested = recurser(index + (i,), next_hanging_indent, next_width)
s += hanging_indent + nested + line_sep
# remove the hanging indent, and wrap in []
s = '[' + s[len(indent):] + ']'
return s

if show_summary:
if legacy == '1.13':
# trailing space, fixed nbr of newlines, and fixed separator
s += hanging_indent + summary_insert + ", \n"
else:
s += hanging_indent + summary_insert + line_sep
def _formatArray(a, format_function, line_width, next_line_prefix,
separator, edge_items, summary_insert, legacy):
"""_formatArray is designed for two modes of operation:

for i in range(trailing_items, 1, -1):
nested = recurser(index + (-i,), next_hanging_indent, next_width)
s += hanging_indent + nested + line_sep
1. Full output

nested = recurser(index + (-1,), next_hanging_indent, next_width)
s += hanging_indent + nested
2. Summarized output

# remove the hanging indent, and wrap in []
s = '[' + s[len(hanging_indent):] + ']'
return s
"""

# invoke the recursive part with an initial index and prefix
return recurser(
index=(),
hanging_indent=next_line_prefix,
curr_width=line_width)
param = a, format_function, separator, edge_items, summary_insert, legacy
return _recursive_fmt(param, index=(), indent=next_line_prefix,
curr_width=line_width)


def _none_or_positive_arg(x, name):
Expand Down
14 changes: 13 additions & 1 deletion numpy/core/tests/test_arrayprint.py
566E
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from __future__ import division, absolute_import, print_function

import sys
import sys, gc

import numpy as np
from numpy.testing import (
Expand Down Expand Up @@ -355,6 +355,18 @@ def test_wide_element(self):
"[ 'xxxxx']"
)

def test_refcount(self):
# make sure we do not hold references to the array due to a recursive
# closure (gh-10620)
gc.disable()
a = np.arange(2)
r1 = sys.getrefcount(a)
np.array2string(a)
np.array2string(a)
r2 = sys.getrefcount(a)
gc.collect()
gc.enable()
assert_(r1 == r2)

class TestPrintOptions(object):
"""Test getting and setting global print options."""
Expand Down
0