Skip to content

Commit 58503e5

Browse files
Byron Boultondanvk
authored andcommitted
Python3 compatible!
* Replace None with '' for added/deleted files Let mylist = ['b', 'a', 'c', None]. In Python2 `sorted(mylist)` returns `[None, 'a', 'b', 'c']. In Python3 `sorted(mylist)` errors out because you can't compare a `None` to strings. Because of this difference I chose to replace `None` with `''` for files which have been added or deleted. It still makes sense logically because the path to the file is non-existent so `''` and the name of the file is `''`. * Had to add mode='rb' to file `open()` * Using binaryornot package because it handles the python2/python3 differences in how to specify the characters to remove when checking if file is binary * Some general code clean up of shadowed variables, unused modules/variables etc.
1 parent 00ee1bb commit 58503e5

File tree

10 files changed

+71
-74
lines changed

10 files changed

+71
-74
lines changed

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ nose
33
PyGithub==1.25.2
44
pillow
55
requests
6+
binaryornot

tests/pair_test.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def test_pairing():
2727
pairs.sort()
2828

2929
eq_(
30-
[(None, 'testing.cfg'),
30+
[('', 'testing.cfg'),
3131
('TODO', 'TODO'),
3232
('app.py', 'app.py'),
3333
('static/js/file_diff.js', 'static/js/file_diff.js'),
@@ -47,7 +47,7 @@ def test_pairing_with_move():
4747
},
4848
{
4949
'a': 'file.json',
50-
'b': None,
50+
'b': '',
5151
'type': 'delete',
5252
}], [diff.get_thin_dict(d) for d in diffs])
5353

@@ -62,7 +62,7 @@ def test_is_image_diff():
6262
assert diff.is_image_diff(TinyDiff('foo.png', 'bar.png'))
6363
assert not diff.is_image_diff(TinyDiff('foo.png.gz', 'bar.png.gz'))
6464
assert not diff.is_image_diff(TinyDiff('foo.txt', 'bar.txt'))
65-
assert diff.is_image_diff(TinyDiff('foo.png', None))
66-
assert not diff.is_image_diff(TinyDiff('foo.txt', None))
67-
assert diff.is_image_diff(TinyDiff(None, 'foo.png'))
68-
assert not diff.is_image_diff(TinyDiff(None, 'foo.txt'))
65+
assert diff.is_image_diff(TinyDiff('foo.png', ''))
66+
assert not diff.is_image_diff(TinyDiff('foo.txt', ''))
67+
assert diff.is_image_diff(TinyDiff('', 'foo.png'))
68+
assert not diff.is_image_diff(TinyDiff('', 'foo.txt'))

webdiff/app.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
For usage, see README.md.
55
'''
66

7+
from __future__ import print_function
8+
from binaryornot.check import is_binary
79
import logging
810
import mimetypes
911
import os
@@ -17,9 +19,9 @@
1719
from flask import (Flask, render_template, send_from_directory, send_file,
1820
request, jsonify, Response)
1921

20-
import diff
21-
import util
22-
import argparser
22+
from webdiff import diff
23+
from webdiff import util
24+
from webdiff import argparser
2325

2426
VERSION = '0.12.1'
2527

@@ -32,8 +34,8 @@ def determine_path():
3234
root = os.path.realpath (root)
3335
return os.path.dirname (os.path.abspath (root))
3436
except:
35-
print "I'm sorry, but something is wrong."
36-
print "There is no __file__ variable. Please contact the author."
37+
print("I'm sorry, but something is wrong.")
38+
print("There is no __file__ variable. Please contact the author.")
3739
sys.exit()
3840

3941
def is_hot_reload():
@@ -101,8 +103,7 @@ def get_contents(side):
101103
abs_path = d.a_path if side == 'a' else d.b_path
102104

103105
try:
104-
is_binary = util.is_binary_file(abs_path)
105-
if is_binary:
106+
if is_binary(abs_path):
106107
size = os.path.getsize(abs_path)
107108
contents = "Binary file (%d bytes)" % size
108109
else:
@@ -134,7 +135,7 @@ def get_image(side, path):
134135
abs_path = d.a_path if side == 'a' else d.b_path
135136

136137
try:
137-
contents = open(abs_path).read()
138+
contents = open(abs_path, mode='rb').read()
138139
return Response(contents, mimetype=mime_type)
139140
except Exception:
140141
return error('read-error', 'Unable to read %s' % abs_path)
@@ -208,6 +209,7 @@ def seriouslykill():
208209

209210
@app.route('/kill', methods=['POST'])
210211
def kill():
212+
global PORT
211213
if 'STAY_RUNNING' in app.config:
212214
return 'Will stay running.'
213215

@@ -251,7 +253,7 @@ def pick_a_port(args):
251253
return port
252254

253255

254-
def abs_path(path):
256+
def abs_path_from_rel(path):
255257
'''Changes relative paths to be abs w/r/t/ the original cwd.'''
256258
if os.path.isabs(path):
257259
return path
@@ -261,7 +263,7 @@ def abs_path(path):
261263

262264
def is_webdiff_from_head():
263265
'''Was webdiff invoked as `git webdiff` with no other non-flag args?'''
264-
return os.environ.get('WEBDIFF_FROM_HEAD') != None
266+
return os.environ.get('WEBDIFF_FROM_HEAD') is not None
265267

266268

267269
def run():

webdiff/argparser.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
import os
44
import re
55

6-
import dirdiff
7-
import githubdiff
8-
import github_fetcher
9-
from localfilediff import LocalFileDiff
6+
from webdiff import dirdiff
7+
from webdiff import githubdiff
8+
from webdiff import github_fetcher
9+
from webdiff.localfilediff import LocalFileDiff
1010

1111
class UsageError(Exception):
1212
pass
@@ -20,7 +20,7 @@ class UsageError(Exception):
2020
''')
2121

2222
# e.g. https://github.com/danvk/dygraphs/pull/292
23-
PULL_REQUEST_RE = re.compile(r'http[s]://(?:www.)?github.com\/([^/]+)/([^/]+)/pull/([0-9]+)(?:/.*)?')
23+
PULL_REQUEST_RE = re.compile(r'http[s]://(?:www.)?github.com/([^/]+)/([^/]+)/pull/([0-9]+)(?:/.*)?')
2424
PULL_REQUEST_NUM_RE = re.compile(r'^#([0-9]+)$')
2525

2626
def parse(args, version=None):

webdiff/diff.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import mimetypes
1414
import os
1515

16-
import util
16+
from webdiff import util
1717

1818
def get_thin_dict(diff):
1919
'''Returns a dict containing minimal data on the diff.
@@ -55,7 +55,7 @@ def get_thin_list(diffs, thick_idx=None):
5555
'''Convert a list of diffs to dicts. This adds an 'idx' field.'''
5656
ds = [get_thin_dict(d) for d in diffs]
5757
if thick_idx is not None:
58-
ds[thick_idx] = get_thick_dict(ds[idx])
58+
ds[thick_idx] = get_thick_dict(ds[thick_idx])
5959
for i, d in enumerate(ds):
6060
d['idx'] = i
6161
return ds
@@ -73,7 +73,8 @@ def is_image_diff(diff):
7373
This uses the a_path and b_path properties of the diff object.
7474
'''
7575
def is_image(path):
76-
if path is None: return False
76+
if path == '':
77+
return False
7778
mime_type, enc = mimetypes.guess_type(path)
7879
return (mime_type and mime_type.startswith('image/') and enc is None)
7980

@@ -82,9 +83,9 @@ def is_image(path):
8283

8384
if left_img and right_img:
8485
return True
85-
elif left_img and diff.b_path is None:
86+
elif left_img and diff.b_path == '':
8687
return True
87-
elif right_img and diff.a_path is None:
88+
elif right_img and diff.a_path == '':
8889
return True
8990
return False
9091

@@ -96,7 +97,8 @@ def find_diff_index(diffs, side, path):
9697
'''
9798
assert side in ('a', 'b')
9899
def norm(p):
99-
if p is None: return None
100+
if p == '':
101+
return ''
100102
return os.path.normpath(p)
101103

102104
path = norm(path)

webdiff/dirdiff.py

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
import copy
55
import os
66

7-
from localfilediff import LocalFileDiff
8-
import util
7+
from webdiff.localfilediff import LocalFileDiff
8+
from webdiff import util
99

1010

1111
def diff(a_dir, b_dir):
@@ -17,7 +17,7 @@ def diff(a_dir, b_dir):
1717
[LocalFileDiff(a_dir, a, b_dir, b, True) for a, b in moves])
1818

1919
# sort "change" before "delete" in a move, which is easier to understand.
20-
diffs.sort(key=lambda diff: (diff.a_path, 0 if diff.b else 1))
20+
diffs.sort(key=lambda d: (d.a_path, 0 if d.b else 1))
2121

2222
return diffs
2323

@@ -27,27 +27,26 @@ def find_diff(a, b):
2727
2828
Returns a list of pairs of full paths to matched a/b files.
2929
'''
30-
a_files = []
31-
b_files = []
32-
def accum(arg, dirname, fnames):
33-
for fname in fnames:
34-
path = os.path.join(dirname, fname)
35-
if not os.path.isdir(path):
36-
arg.append(path)
30+
31+
def list_files(top_dir):
32+
file_list = []
33+
for root, _, files in os.walk(top_dir):
34+
root = os.path.relpath(root, start=top_dir)
35+
for name in files:
36+
file_list.append(os.path.join(root, name))
37+
return file_list
3738

3839
assert os.path.isdir(a)
3940
assert os.path.isdir(b)
4041

41-
os.path.walk(a, accum, a_files)
42-
os.path.walk(b, accum, b_files)
43-
44-
a_files = [os.path.relpath(x, start=a) for x in a_files]
45-
b_files = [os.path.relpath(x, start=b) for x in b_files]
42+
a_files = list_files(a)
43+
b_files = list_files(b)
4644

4745
pairs = pair_files(a_files, b_files)
4846

4947
def safejoin(d, p):
50-
if p is None: return None
48+
if p == '':
49+
return ''
5150
return os.path.join(d, p)
5251

5352
return [(safejoin(a, arel),
@@ -65,10 +64,10 @@ def pair_files(a_files, b_files):
6564
del a_files[i]
6665
del b_files[j]
6766
else:
68-
pairs.append((f, None)) # delete
67+
pairs.append((f, '')) # delete
6968

7069
for f in b_files:
71-
pairs.append((None, f)) # add
70+
pairs.append(('', f)) # add
7271

7372
return pairs
7473

webdiff/github_fetcher.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010
import os
1111
import re
1212
import subprocess
13+
import sys
1314

1415
from github import Github, UnknownObjectException
1516

16-
from util import memoize
17+
from webdiff.util import memoize
1718

1819

1920
@memoize
@@ -84,7 +85,7 @@ def get_pr_repo(num):
8485
owner = remote['owner']
8586
repo = remote['repo']
8687
try:
87-
pr = g.get_user(owner).get_repo(repo).get_pull(num)
88+
g.get_user(owner).get_repo(repo).get_pull(num)
8889
return (owner, repo, num)
8990
except UnknownObjectException:
9091
pass
@@ -133,6 +134,6 @@ def _parse_remotes(remote_lines):
133134

134135
def _get_remotes():
135136
remote_lines = subprocess.Popen(
136-
['git', 'remote', '-v'], stdout=subprocess.PIPE).communicate()[0].split('\n')
137+
['git', 'remote', '-v'], stdout=subprocess.PIPE).communicate()[0].split(b'\n')
137138
return _parse_remotes(remote_lines)
138139

webdiff/githubdiff.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
import tempfile
1010
import sys
1111

12-
from util import memoize
13-
from github_fetcher import github
12+
from webdiff.util import memoize
13+
from webdiff.github_fetcher import github
1414

1515

1616
class GitHubDiff(object):
@@ -25,22 +25,22 @@ def __init__(self, pr, github_file):
2525
'added': 'add',
2626
'removed': 'delete'
2727
}[github_file.status]
28-
self._a_path = None
29-
self._b_path = None
28+
self._a_path = ''
29+
self._b_path = ''
3030

3131
@property
3232
def a(self):
3333
if self.type == 'move':
3434
return self._file.raw_data['previous_filename']
3535
elif self.type == 'add':
36-
return None
36+
return ''
3737
else:
3838
return self._file.filename
3939

4040
@property
4141
def b(self):
4242
if self.type == 'delete':
43-
return None
43+
return ''
4444
else:
4545
return self._file.filename
4646

@@ -72,7 +72,8 @@ def fetch_pull_request(owner, repo, num):
7272

7373
@memoize
7474
def fetch(repo, filename, sha):
75-
if filename is None: return None
75+
if filename == '':
76+
return ''
7677
data = repo.get_file_contents(filename, sha).decoded_content
7778
_, ext = os.path.splitext(filename)
7879
fd, path = tempfile.mkstemp(suffix=ext)

webdiff/localfilediff.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
11
'''This class represents the diff between two files on local disk.'''
22

33
import os
4-
import mimetypes
5-
import util
4+
65

76
class LocalFileDiff(object):
87
def __init__(self, a_root, a_path, b_root, b_path, is_move):
98
'''A before/after file pair on local disk
109
1110
Args:
1211
a_path, b_path: full paths to the files on disk. Either (but not
13-
both) may be None.
12+
both) may be empty.
1413
a_root, b_root: Paths to the root of diff.
1514
is_move: Is this a pure move between the two files?
1615
'''
17-
assert (a_path is not None) or (b_path is not None)
16+
assert (a_path != '') or (b_path != '')
1817
self.a_path = a_path
1918
self.b_path = b_path
2019
self.a_root = a_root
@@ -23,19 +22,21 @@ def __init__(self, a_root, a_path, b_root, b_path, is_move):
2322

2423
@property
2524
def a(self):
26-
if self.a_path is None: return None
25+
if self.a_path == '':
26+
return ''
2727
return os.path.relpath(self.a_path, self.a_root)
2828

2929
@property
3030
def b(self):
31-
if self.b_path is None: return None
31+
if self.b_path == '':
32+
return ''
3233
return os.path.relpath(self.b_path, self.b_root)
3334

3435
@property
3536
def type(self):
36-
if self.a_path is None:
37+
if self.a_path == '':
3738
return 'add'
38-
elif self.b_path is None:
39+
elif self.b_path == '':
3940
return 'delete'
4041
elif self.is_move:
4142
return 'move'

0 commit comments

Comments
 (0)