Cleanup: sorted, dict iteration, array.{ndim,size}, ... #7549

Merged
merged 9 commits into from Dec 22, 2016

Conversation

Projects
7 participants
Contributor

anntzer commented Dec 2, 2016 edited

  • Use sorted whereever it improves readbility over list.sort.
  • Iterating over a dict doesn't require calling iterkeys.
  • Use ndarray.size/.ndim whereever appropriate.
  • Une N{...} unicode entities.

tacaswell added this to the 2.1 (next point release) milestone Dec 2, 2016

anntzer changed the title from Cleanup sorted to Cleanup: sorted, dict iteration Dec 2, 2016

anntzer changed the title from Cleanup: sorted, dict iteration to Cleanup: sorted, dict iteration, array.{ndim,size} Dec 2, 2016

anntzer changed the title from Cleanup: sorted, dict iteration, array.{ndim,size} to Cleanup: sorted, dict iteration, array.{ndim,size}, ... Dec 2, 2016

Member

QuLogic commented Dec 2, 2016

Do Unicode entities work in Python 2? I'm not seeing it in the Unicode howto.

Contributor

anntzer commented Dec 2, 2016

codecov-io commented Dec 3, 2016 edited

Current coverage is 61.90% (diff: 60.69%)

Merging #7549 into master will decrease coverage by <.01%

@@             master      #7549   diff @@
==========================================
  Files           173        173          
  Lines         56103      55917   -186   
  Methods           0          0          
  Messages          0          0          
  Branches          0          0          
==========================================
- Hits          34731      34614   -117   
+ Misses        21372      21303    -69   
  Partials          0          0          

Powered by Codecov. Last update 6223155...e809aaf

@thisch

I didn't review the whole PR

lib/matplotlib/afm.py
- line = fh.readline()
- if not line:
- break
+ for line in fh:
line = line.rstrip()
if len(line) == 0:
@thisch

thisch Dec 4, 2016

Contributor

here you could have also used 'if not line'

@@ -135,9 +135,8 @@ def plot_figure(style_label=""):
# Setup a list of all available styles, in alphabetical order but
# the `default` and `classic` ones, which will be forced resp. in
# first and second position.
- style_list = list(plt.style.available) # *new* list: avoids side effects.
+ style_list = sorted(plt.style.available) # *new* list: avoids side effects.
@thisch

thisch Dec 4, 2016

Contributor

please remove the comment

@anntzer

anntzer Dec 4, 2016

Contributor

both are fixed

@QuLogic

It's a behemoth, but I think I managed to get through it all.

lib/matplotlib/__init__.py
def values(self):
"""
Return values in order of sorted keys.
"""
- return [self[k] for k in self.keys()]
+ return [self[k] for k in self]
@QuLogic

QuLogic Dec 4, 2016

Member

Does dropping .keys() and iterating over self correctly preserve the sorted order that the keys method from this subclass produces?

@anntzer

anntzer Dec 4, 2016

Contributor

No. But that also means that iteration on the dict itself (for k in rcparams) happens in a different order right now...

@@ -91,7 +91,7 @@ def _sanity_check(fh):
# do something else with the file.
pos = fh.tell()
try:
- line = fh.readline()
+ line = next(fh)
@QuLogic

QuLogic Dec 4, 2016

Member

Not convinced this is clearer.

@anntzer

anntzer Dec 4, 2016

Contributor

The problem is that the outer loop may be using for line in fh first before passing the handle to the function at some point, and Py2 (not Py3) doesn't allow (raises an exception on) mixing for line in fh and fh.readline due to the fact that the former uses a readahead buffer (https://docs.python.org/2/library/stdtypes.html#file.next).

@QuLogic

QuLogic Dec 7, 2016

Member

But this is called before the iteration, and the next line is a seek, which should flush the readahead buffer anyway.

@anntzer

anntzer Dec 7, 2016

Contributor

I think the gain in legibility with .readline() doesn't compensate the brittleness of only being able to pass in a file with an empty readahead buffer.

@@ -232,20 +225,17 @@ def _parse_kern_pairs(fh):
"""
- line = fh.readline()
+ line = next(fh)
@QuLogic

QuLogic Dec 4, 2016

Member

As above.

@anntzer

anntzer Dec 4, 2016

Contributor

As above.

@QuLogic

QuLogic Dec 7, 2016

Member

This one makes sense though; will need to remain next.

- locs = [ti[1] for ti in tick_tups]
- locs.sort()
- locs = np.array(locs)
- if len(locs):
@QuLogic

QuLogic Dec 4, 2016

Member

I understand this condition is probably not necessary, but I guess it could also be anded onto line 955?

@anntzer

anntzer Dec 4, 2016

Contributor

In fact it's probably needed, otherwise we may end up trying to get the first or last item of an empty array...

lib/matplotlib/backends/backend_gdk.py
-IMAGE_FORMAT = ['eps', 'jpg', 'png', 'ps', 'svg'] + ['bmp'] # , 'raw', 'rgb']
-IMAGE_FORMAT.sort()
-IMAGE_FORMAT_DEFAULT = 'png'
+IMAGE_FORMAT = sorted(['eps', 'jpg', 'png', 'ps', 'svg'] + ['bmp']) # , 'raw', 'rgb']
@QuLogic

QuLogic Dec 4, 2016

Member

Just put 'bmp' at the front?

@anntzer

anntzer Dec 4, 2016

Contributor

Sure, but I'll keep the sorted which makes the intent clear and should be cheap.

lib/matplotlib/backends/backend_ps.py
-
- if len(seq1) != len(seq2): return False
- return np.alltrue(np.equal(seq1, seq2))
+seq_allequal = np.array_equal
@QuLogic

QuLogic Dec 4, 2016

Member

Hrm, is this even public?

@anntzer

anntzer Dec 4, 2016

Contributor

Strictly speaking, it was; in practice I'm 100% sure we can just get rid of it...

@@ -1652,55 +1638,48 @@ def pstoeps(tmpfile, bbox=None, rotated=False):
bbox_info, rotate = None, None
epsfile = tmpfile + '.eps'
- with io.open(epsfile, 'wb') as epsh:
+ with io.open(epsfile, 'wb') as epsh, io.open(tmpfile, 'rb') as tmph:
@QuLogic

QuLogic Dec 4, 2016

Member

Do we even need io. when it's binary?

@anntzer

anntzer Dec 4, 2016

Contributor

What's the difference between io.open and open in Py2?

@QuLogic

QuLogic Dec 7, 2016

Member

I don't think there is one in binary mode, is there?

@anntzer

anntzer Dec 7, 2016

Contributor

I guess...
On the other hand there seems to be an awful lot use of temporary files in backend_ps, most of which could probably just get rewritten using pipes to communicate via the subprocesses' standard streams.
Another great cleanup project :-)

lib/matplotlib/table.py
@@ -331,8 +328,7 @@ def _get_grid_bbox(self, renderer):
Only include those in the range (0,0) to (maxRow, maxCol)"""
boxes = [self._cells[pos].get_window_extent(renderer)
@QuLogic

QuLogic Dec 4, 2016

Member

Since the value is actually used here, it might make sense to use items() below.

@anntzer

anntzer Dec 4, 2016

Contributor

yup

@@ -186,8 +186,8 @@ def set_params(self, **kwargs):
self.den = int(kwargs.pop("nbins"))
if kwargs:
- raise ValueError("Following keys are not processed: %s" % \
- ", ".join([str(k) for k in kwargs.keys()]))
+ raise ValueError("Following keys are not processed: %s"
@QuLogic

QuLogic Dec 4, 2016

Member

I'm going to remove this whole thing in #7545.

- p0, p1 = edges[edgei]
+ p0, p1 = min(self.tunit_edges(),
+ key=lambda edge: proj3d.line2d_seg_dist(
+ edge[0], edge[1], (xd, yd)))
@QuLogic

QuLogic Dec 4, 2016

Member

I prefer to break after edge[1], but that's minor.

lib/mpl_toolkits/mplot3d/proj3d.py
- tis = (vecw[0] >= 0) * (vecw[0] <= 1) * (vecw[1] >= 0) * (vecw[1] <= 1)
- if np.sometrue(tis):
- tis = vecw[1] < 1
+ tis = (vecw[0] >= 0) & (vecw[0] <= 1) & (vecw[1] >= 0) & (vecw[1] <= 1)
@QuLogic

QuLogic Dec 4, 2016

Member

Since you're editing the line already, can you reorder it so that it looks like an implied and?

@anntzer

anntzer Dec 4, 2016

Contributor

done

examples/misc/multiprocess.py
@@ -28,7 +28,7 @@ def terminate(self):
def poll_draw(self):
def call_back():
- while 1:
+ while True:
@Kojoley

Kojoley Dec 4, 2016

Member

Cannot this be while self.pipe.poll(): (and remove if not self.pipe.poll(): break below)?

lib/matplotlib/axes/_base.py
- while 1:
-
- if len(remaining) == 0:
+ while True:
@Kojoley

Kojoley Dec 4, 2016

Member

while args:?

@anntzer

anntzer Dec 4, 2016

Contributor

yup

lib/matplotlib/axes/_base.py
+ if not self.figure.canvas.is_saving():
+ artists = [a for a in artists
+ if not a.get_animated() or a in self.images]
+ artists = sorted(artists, key=lambda artist: artist.get_zorder())
@Kojoley

Kojoley Dec 4, 2016

Member

Is not attrgetter faster than lambda?

@anntzer

anntzer Dec 4, 2016

Contributor

I doubt it matters but sure.

lib/matplotlib/cm.py
- spec = datad[cmapname]
- spec_reversed = _reverse_cmap_spec(spec)
- datad[cmapname + '_r'] = spec_reversed
+ for cmapname, spec in list(six.iteritems(datad)):
@Kojoley

Kojoley Dec 4, 2016

Member

list is redundant

@anntzer

anntzer Dec 4, 2016 edited

Contributor

No because we're modifying the dict at the same time; sidestepped the issue using update.

lib/matplotlib/table.py
@@ -350,8 +346,7 @@ def contains(self, mouseevent):
renderer = self.figure._cachedRenderer
if renderer is not None:
boxes = [self._cells[pos].get_window_extent(renderer)
- for pos in six.iterkeys(self._cells)
- if pos[0] >= 0 and pos[1] >= 0]
+ for pos in self._cells if pos[0] >= 0 and pos[1] >= 0]
@QuLogic

QuLogic Dec 5, 2016

Member

I knew I should have commented the first time, but here's another one that could use items.

@anntzer

anntzer Dec 5, 2016

Contributor

fixed

@Kojoley

Kojoley approved these changes Dec 5, 2016

Contributor

NelleV commented Dec 19, 2016

Can you rebase this PR?

NelleV changed the title from Cleanup: sorted, dict iteration, array.{ndim,size}, ... to [MRG+1] Cleanup: sorted, dict iteration, array.{ndim,size}, ... Dec 19, 2016

- style_list.sort()
- style_list.insert(0, u'default')
- style_list.insert(1, u'classic')
+ style_list = ['default', 'classic'] + sorted(
@NelleV

NelleV Dec 19, 2016

Contributor

👍

- line = fh.readline()
- if not line:
- break
+ for line in fh:
@NelleV

NelleV Dec 19, 2016

Contributor

👍

Contributor

anntzer commented Dec 20, 2016

After Christmas break, probably.

Contributor

anntzer commented Dec 21, 2016

Actually it wasn't that bad.

QuLogic changed the title from [MRG+1] Cleanup: sorted, dict iteration, array.{ndim,size}, ... to Cleanup: sorted, dict iteration, array.{ndim,size}, ... Dec 22, 2016

@QuLogic QuLogic merged commit 7131876 into matplotlib:master Dec 22, 2016

1 of 3 checks passed

continuous-integration/appveyor/pr AppVeyor build failed
Details
coverage/coveralls Coverage decreased (-4.5%) to 62.068%
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details

anntzer deleted the anntzer:cleanup-sorted branch Dec 23, 2016

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