Skip to content
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

correct labels for dicts #50

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open

Conversation

graingert
Copy link

Fixes #49

@graingert graingert force-pushed the patch-2 branch 3 times, most recently from 94428ef to 9e2b378 Compare August 17, 2020 23:51
@graingert
Copy link
Author

@mgedmin can I get a review

Copy link
Owner

@mgedmin mgedmin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, this is excellent!

I have only a couple of minor comments that I'll leave to your discretion. Also, would you like to add a changelog entry for this fix?

(Apologies for a late reply, I was on vacation and was pretending computers didn't exist.)

edges = edge_func(target)
counts = collections.Counter(id(v) for v in edges)
neighbours = list({id(v): v for v in edges}.values())
del edges
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So AFAIU neighbours is edges without duplicates, and counts is the count of duplicates. This took me a while to understand, maybe a comment would be helpful?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for a comment if we can add more_itertools:

https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.unique_everseen

neighbours = more_itertools.unique_everseen(edges, key=id)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather not; I like that objgraph is a single file library with no external dependencies I can copy over into any random location on my python path and start using immediately.

objgraph.py Outdated
if target is source.f_globals:
return ' [label="f_globals",weight=10]'
return [' [label="f_globals",weight=10]']
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if there are any frames where frame.f_locals is frame.f_globals and we'd have the same problem with two arrows having the same label?

I wonder if it wouldn't be a good idea to use yield here for easier handling of multiple return values.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried using yield but it breaks the control flow around return

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh I see yes that might be much better

Copy link
Owner

@mgedmin mgedmin Aug 19, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would require replacing all return statements with yield, and then adding return with no arguments for short-circuiting the control flow (or rewriting the series of top-level 'if/if/if' into 'if/elif/elif').

Not worth it. When I first suggested yield, I thought there would be more places with possible duplicate labels, but it looks like just this one place.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol I already did it

objgraph.py Outdated
' [label="%s",weight=10]' % _quote(k)
for k in dir(source)
if target is getattr(source, k)
]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

objgraph.py Outdated Show resolved Hide resolved
objgraph.py Outdated Show resolved Hide resolved
tests.py Outdated
@skipIf(
sys.version_info < (3, 6),
"Python < 3.6 dicts have random iteration order",
)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm tempted to do a quick hack with

lines = output.readlines()
self.assertEqual(
    ''.join(lines[:5] + sorted(lines[5:-3]) + lines[-3:]),
    textwrap.dedent(...)
)

so this test can run on all Python versions.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but the test looks so beautiful without it

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rest of the test will continue to look beautiful, and the sorted(lines[5:-3]) will inspire awe in the unwary reader. ;)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Python 3.5 reached End Of Life recently, so the point is moot.

objgraph.py Show resolved Hide resolved
fillvalue='',
):
f.write(' %s -> %s%s;\n' % (_obj_node_id(srcnode),
_obj_node_id(tgtnode), elabel))
if id(source) not in depth:
depth[id(source)] = tdepth + 1
queue.append(source)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of lines down from here there's a del neighbours, and I think you might want to add del counts in there.

It probably doesn't matter, counts holds only ints, and I doubt anyone expects specific refcounts for those, and also they won't be causing problems with memory usage.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah I figured it wasn't worth it, could wrap this whole thing in a def so everything is automatically deleted

objgraph.py Outdated
zip_longest = itertools.izip_longest
except AttributeError: # pragma: PY3
# Python 3.x compatibility
zip_longest = itertools.zip_longest
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use six.moves.zip_longest instead?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want to introduce non-optional dependencies outside Python's stdlib yet.

should detect cases where frame.f_locals is frame.f_globals
objgraph.py Outdated Show resolved Hide resolved
if _isinstance(k, basestring) and _is_identifier(k):
yield ' [label="%s",weight=2]' % _quote(k)
else:
yield ' [label="%s"]' % _quote(tn(k) + "\n" + _safe_repr(k))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for adding max-line-length = 80 to setup.cfg's flake8 section to avoid this line too long error.

Copy link
Author

@graingert graingert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3.6 support is dropped

objgraph.py Outdated Show resolved Hide resolved
objgraph.py Show resolved Hide resolved
objgraph.py Outdated Show resolved Hide resolved
tests.py Outdated Show resolved Hide resolved
objgraph.py Outdated Show resolved Hide resolved
@graingert graingert requested a review from mgedmin March 28, 2022 11:02
objgraph.py Outdated Show resolved Hide resolved
Co-authored-by: Marius Gedminas <marius@gedmin.as>
elabel = _edge_label(srcnode, tgtnode, shortnames)
f.write(' %s -> %s%s;\n' % (_obj_node_id(srcnode),
_obj_node_id(tgtnode), elabel))
for elabel, _ in itertools.zip_longest(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't work on Python 2.7.

I'd have to stop and think whether I want to drop Python 2.7 compatibility at this point.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

incorrect labes for dict keys
2 participants