diff --git a/grin-1.2.1-argparse.patch b/grin-1.2.1-argparse.patch deleted file mode 100644 index 5f261bb..0000000 --- a/grin-1.2.1-argparse.patch +++ /dev/null @@ -1,31 +0,0 @@ ---- grin-1.2.1/setup.py~ 2010-08-08 01:44:07.000000000 +0200 -+++ grin-1.2.1/setup.py 2011-05-09 15:37:19.024527713 +0200 -@@ -1,4 +1,5 @@ - import os -+import sys - from setuptools import setup - - kwds = {} -@@ -9,6 +10,11 @@ - kwds['long_description'] = f.read() - f.close() - -+# argparse part of python 2.7 and 3.2 -+if sys.version_info < (2, 7, 0): -+ install_requires = ['argparse >= 1.1'] -+else: -+ install_requires = [] - - setup( - name = 'grin', -@@ -34,9 +40,7 @@ - "grind = grin:grind_main", - ], - ), -- install_requires = [ -- 'argparse >= 1.1', -- ], -+ install_requires = install_requires, - tests_require = [ - 'nose >= 0.10', - ], diff --git a/grin-1.2.1-git-8dd4b5.patch b/grin-1.2.1-git-8dd4b5.patch new file mode 100644 index 0000000..d4d3e15 --- /dev/null +++ b/grin-1.2.1-git-8dd4b5.patch @@ -0,0 +1,206 @@ +diff --git a/.gitignore b/.gitignore +new file mode 100644 +index 0000000..ac42661 +--- /dev/null ++++ b/.gitignore +@@ -0,0 +1,3 @@ ++build/ ++dist/ ++grin.egg-info/ +diff --git a/README.txt b/README.rst +similarity index 87% +rename from README.txt +rename to README.rst +index 3529c02..170fa70 100644 +--- a/README.txt ++++ b/README.rst +@@ -64,25 +64,13 @@ directories, I would have this line in my bashrc:: + Installation + ------------ + +-grin uses setuptools_ to find and install its dependency on argparse_. grin is +-easy_installable:: ++Install using pip_:: + +- $ easy_install grin ++ $ pip install grin + +-Alternatively, download and unpack the tarball and install:: ++Running the unittests requires the nose_ framework:: + +- $ tar zxf grin-1.2.tar.gz +- $ python setup.py install +- +-On UNIX systems, use sudo for the latter command if you need to install the +-scripts to a directory that requires root privileges:: +- +- $ sudo python setup.py install +- +-Running the unittests requires the nose_ framework, which can also be +-easy_installed:: +- +- $ easy_install "nose >= 0.10" ++ $ pip install nose + ... + $ nosetests + ......................... +@@ -94,9 +82,9 @@ easy_installed:: + running test + ... etc. + +-The development Subversion repository can be checked out anonymously:: ++The development sources are hosted on Github: + +- $ svn co https://svn.enthought.com/svn/sandbox/grin/trunk/ grin ++ https://github.com/rkern/grin + + There is one little tweak to the installation that you may want to consider. By + default, setuptools installs scripts indirectly; the scripts installed to +@@ -108,9 +96,8 @@ response of grin to be snappier, I recommend installing custom scripts that just + import the grin module and run the appropriate main() function. See the files + examples/grin and examples/grind for examples. + +-.. _setuptools : http://pypi.python.org/pypi/setuptools +-.. _argparse : http://argparse.python-hosting.com +-.. _nose : http://www.somethingaboutorange.com/mrl/projects/nose ++.. _pip : https://pip.pypa.io/en/stable/ ++.. _nose : https://nose.readthedocs.org/en/latest/ + + + Using grin +@@ -246,13 +233,12 @@ To Do + + * Figure out the story for grepping UTF-8, UTF-16 and UTF-32 Unicode text files. + ++* Python 3 ++ + + Bugs and Such + ------------- + +-If you find a bug, or a missing feature you really want added, please post to +-the enthought-dev_ mailing list or email the author at +-. +- +-.. _enthought-dev : https://mail.enthought.com/mailman/listinfo/enthought-dev ++Please make a new issue at the Github issue tracker. + ++ https://github.com/rkern/grin +diff --git a/examples/grinimports.py b/examples/grinimports.py +index ef7cacb..b6d48ff 100755 +--- a/examples/grinimports.py ++++ b/examples/grinimports.py +@@ -21,7 +21,7 @@ def normalize_From(node): + """ + statements = [] + children = node.getChildren() +- module = children[0] ++ module = '.'*node.level + node.modname + for name, asname in children[1]: + line = 'from %s import %s' % (module, name) + if asname is not None: +diff --git a/grin.py b/grin.py +index de9703d..bf42dc0 100755 +--- a/grin.py ++++ b/grin.py +@@ -906,12 +906,15 @@ def get_grind_arg_parser(parser=None): + def get_recognizer(args): + """ Get the file recognizer object from the configured options. + """ ++ # Make sure we have empty sets when we have empty strings. ++ skip_dirs = set([x for x in args.skip_dirs.split(',') if x]) ++ skip_exts = set([x for x in args.skip_exts.split(',') if x]) + fr = FileRecognizer( + skip_hidden_files=args.skip_hidden_files, + skip_backup_files=args.skip_backup_files, + skip_hidden_dirs=args.skip_hidden_dirs, +- skip_dirs=set(args.skip_dirs.split(',')), +- skip_exts=set(args.skip_exts.split(',')), ++ skip_dirs=skip_dirs, ++ skip_exts=skip_exts, + skip_symlink_files=not args.follow_symlinks, + skip_symlink_dirs=not args.follow_symlinks, + ) +@@ -1029,7 +1032,7 @@ def grin_main(argv=None): + sys.stdout.write(report) + except KeyboardInterrupt: + raise SystemExit(0) +- except IOError as e: ++ except IOError, e: + if 'Broken pipe' in str(e): + # The user is probably piping to a pager like less(1) and has exited + # it. Just exit. +@@ -1070,7 +1073,7 @@ def grind_main(argv=None): + output(filename) + except KeyboardInterrupt: + raise SystemExit(0) +- except IOError as e: ++ except IOError, e: + if 'Broken pipe' in str(e): + # The user is probably piping to a pager like less(1) and has exited + # it. Just exit. +diff --git a/setup.py b/setup.py +index abf95d9..3d1f1eb 100644 +--- a/setup.py ++++ b/setup.py +@@ -1,23 +1,24 @@ + import os ++ + from setuptools import setup + + kwds = {} + + # Read the long description from the README.txt + thisdir = os.path.abspath(os.path.dirname(__file__)) +-f = open(os.path.join(thisdir, 'README.txt')) +-kwds['long_description'] = f.read() +-f.close() ++with open(os.path.join(thisdir, 'README.rst')) as f: ++ kwds['long_description'] = f.read() + + + setup( +- name = 'grin', +- version = '1.2.1', +- author = 'Robert Kern', +- author_email = 'robert.kern@enthought.com', +- description = "A grep program configured the way I like it.", +- license = "BSD", +- classifiers = [ ++ name='grin', ++ version='1.2.1', ++ author='Robert Kern', ++ author_email='robert.kern@enthought.com', ++ description="A grep program configured the way I like it.", ++ license="BSD", ++ url='https://github.com/rkern/grin', ++ classifiers=[ + "License :: OSI Approved :: BSD License", + "Development Status :: 5 - Production/Stable", + "Environment :: Console", +@@ -26,20 +27,16 @@ setup( + "Programming Language :: Python", + "Topic :: Utilities", + ], +- +- py_modules = ["grin"], +- entry_points = dict( +- console_scripts = [ ++ py_modules=["grin"], ++ entry_points=dict( ++ console_scripts=[ + "grin = grin:grin_main", + "grind = grin:grind_main", + ], + ), +- install_requires = [ +- 'argparse >= 1.1', +- ], +- tests_require = [ ++ tests_require=[ + 'nose >= 0.10', + ], +- test_suite = 'nose.collector', ++ test_suite='nose.collector', + **kwds + ) diff --git a/grin-1.2.1-python3.patch b/grin-1.2.1-python3.patch new file mode 100644 index 0000000..755f9df --- /dev/null +++ b/grin-1.2.1-python3.patch @@ -0,0 +1,615 @@ +diff --git a/examples/grinimports.py b/examples/grinimports.py +index b6d48ff..fa4917f 100755 +--- a/examples/grinimports.py ++++ b/examples/grinimports.py +@@ -2,10 +2,9 @@ + # -*- coding: UTF-8 -*- + """ Transform Python files into normalized import statements for grepping. + """ +- + import compiler + from compiler.visitor import ASTVisitor, walk +-from cStringIO import StringIO ++from io import StringIO + import os + import shlex + import sys +@@ -70,7 +69,7 @@ def normalize_file(filename, *args): + """ + try: + ast = compiler.parseFile(filename) +- except Exception, e: ++ except Exception as e: + return StringIO('') + ip = ImportPuller() + walk(ast, ip) +diff --git a/examples/grinpython.py b/examples/grinpython.py +index 31e23ee..a9e1395 100755 +--- a/examples/grinpython.py ++++ b/examples/grinpython.py +@@ -3,7 +3,7 @@ + """ Transform Python code by omitting strings, comments, and/or code. + """ + +-from cStringIO import StringIO ++from io import BytesIO + import os + import shlex + import string +@@ -55,7 +55,7 @@ class Transformer(object): + """ Open a file and convert it to a filelike object with transformed + contents. + """ +- g = StringIO() ++ g = BytesIO() + f = open(filename, mode) + try: + gen = tokenize.generate_tokens(f.readline) +diff --git a/grin.py b/grin.py +index bf42dc0..9781432 100755 +--- a/grin.py ++++ b/grin.py +@@ -1,6 +1,7 @@ + #!/usr/bin/env python + """ grin searches text files. + """ ++from __future__ import print_function + + import bisect + import fnmatch +@@ -11,9 +12,16 @@ import re + import shlex + import stat + import sys ++from io import UnsupportedOperation + + import argparse + ++if sys.version_info[0] > 2: ++ to_str = lambda s : s.decode('latin1') ++ ints2bytes = bytes ++else: ++ to_str = str ++ ints2bytes = lambda ints : ''.join(map(chr, ints)) + + #### Constants #### + __version__ = '1.2.1' +@@ -24,8 +32,8 @@ MATCH = 0 + POST = 1 + + # Use file(1)'s choices for what's text and what's not. +-TEXTCHARS = ''.join(map(chr, [7,8,9,10,12,13,27] + range(0x20, 0x100))) +-ALLBYTES = ''.join(map(chr, range(256))) ++TEXTCHARS = ints2bytes([7,8,9,10,12,13,27] + list(range(0x20, 0x100))) ++ALLBYTES = ints2bytes(range(256)) + + COLOR_TABLE = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', + 'white', 'default'] +@@ -35,12 +43,11 @@ COLOR_STYLE = { + } + + # gzip magic header bytes. +-GZIP_MAGIC = '\037\213' ++GZIP_MAGIC = b'\037\213' + + # Target amount of data to read into memory at a time. + READ_BLOCKSIZE = 16 * 1024 * 1024 + +- + def is_binary_string(bytes): + """ Determine if a string is classified as binary rather than text. + +@@ -54,7 +61,8 @@ def is_binary_string(bytes): + """ + nontext = bytes.translate(ALLBYTES, TEXTCHARS) + return bool(nontext) +- ++ ++ + def get_line_offsets(block): + """ Compute the list of offsets in DataBlock 'block' which correspond to + the beginnings of new lines. +@@ -80,7 +88,8 @@ def get_line_offsets(block): + # Keep track of the count of lines within the "current block" + if next_newline >= block.start and next_newline < block.end: + line_count += 1 +- ++ ++ + def colorize(s, fg=None, bg=None, bold=False, underline=False, reverse=False): + """ Wraps a string with ANSI color escape sequences corresponding to the + style parameters given. +@@ -207,7 +216,7 @@ class GrepText(object): + def read_block_with_context(self, prev, fp, fp_size): + """ Read a block of data from the file, along with some surrounding + context. +- ++ + Parameters + ---------- + prev : DataBlock, or None +@@ -216,23 +225,23 @@ class GrepText(object): + + fp : filelike object + The source of block data. +- ++ + fp_size : int or None + Size of the file in bytes, or None if the size could not be + determined. +- ++ + Returns + ------- + A DataBlock representing the "current" block along with context. + """ + if fp_size is None: + target_io_size = READ_BLOCKSIZE +- block_main = fp.read(target_io_size) ++ block_main = to_str(fp.read(target_io_size)) + is_last_block = len(block_main) < target_io_size + else: + remaining = max(fp_size - fp.tell(), 0) + target_io_size = min(READ_BLOCKSIZE, remaining) +- block_main = fp.read(target_io_size) ++ block_main = to_str(fp.read(target_io_size)) + is_last_block = target_io_size == remaining + + if prev is None: +@@ -271,12 +280,13 @@ class GrepText(object): + before_lines = prev.data[before_start:prev.end] + # Using readline() to force this block out to a newline boundary... + curr_block = (prev.data[prev.end:] + block_main + +- ('' if is_last_block else fp.readline())) ++ ('' if is_last_block else to_str(fp.readline()))) + # Read in some lines of 'after' context. + if is_last_block: + after_lines = '' + else: +- after_lines_list = [fp.readline() for i in range(self.options.after_context)] ++ after_lines_list = [to_str(fp.readline()) ++ for i in range(self.options.after_context)] + after_lines = ''.join(after_lines_list) + + result = DataBlock( +@@ -308,13 +318,15 @@ class GrepText(object): + fp_size = None # gzipped data is usually longer than the file + else: + try: +- status = os.fstat(fp.fileno()) ++ file_no = fp.fileno() ++ except (AttributeError, UnsupportedOperation): # doesn't support fileno() ++ fp_size = None ++ else: ++ status = os.fstat(file_no) + if stat.S_ISREG(status.st_mode): + fp_size = status.st_size + else: + fp_size = None +- except AttributeError: # doesn't support fileno() +- fp_size = None + + block = self.read_block_with_context(None, fp, fp_size) + while block.end > block.start: +@@ -457,7 +469,7 @@ class GrepText(object): + color_substring = colorize(old_substring, **style) + line = line[:start] + color_substring + line[end:] + total_offset += len(color_substring) - len(old_substring) +- ++ + ns = dict( + lineno = i+1, + sep = {PRE: '-', POST: '+', MATCH: ':'}[kind], +@@ -495,8 +507,8 @@ class GrepText(object): + f = sys.stdin + filename = '' + else: +- # 'r' does the right thing for both open ('rt') and gzip.open ('rb') +- f = opener(filename, 'r') ++ # Always open in binary mode ++ f = opener(filename, 'rb') + try: + unique_context = self.do_grep(f) + finally: +@@ -587,7 +599,7 @@ class FileRecognizer(object): + """ + try: + bytes = f.read(self.binary_bytes) +- except Exception, e: ++ except Exception as e: + # When trying to read from something that looks like a gzipped file, + # it may be corrupt. If we do get an error, assume that the file is binary. + return True +@@ -1032,7 +1044,7 @@ def grin_main(argv=None): + sys.stdout.write(report) + except KeyboardInterrupt: + raise SystemExit(0) +- except IOError, e: ++ except IOError as e: + if 'Broken pipe' in str(e): + # The user is probably piping to a pager like less(1) and has exited + # it. Just exit. +@@ -1040,7 +1052,7 @@ def grin_main(argv=None): + raise + + def print_line(filename): +- print filename ++ print(filename) + + def print_null(filename): + # Note that the final filename will have a trailing NUL, just like +@@ -1073,7 +1085,7 @@ def grind_main(argv=None): + output(filename) + except KeyboardInterrupt: + raise SystemExit(0) +- except IOError, e: ++ except IOError as e: + if 'Broken pipe' in str(e): + # The user is probably piping to a pager like less(1) and has exited + # it. Just exit. +diff --git a/tests/test_file_recognizer.py b/tests/test_file_recognizer.py +index 70b7f5a..a085ce1 100644 +--- a/tests/test_file_recognizer.py ++++ b/tests/test_file_recognizer.py +@@ -1,5 +1,6 @@ + """ Test the file recognizer capabilities. + """ ++from __future__ import print_function + + import gzip + import os +@@ -9,7 +10,7 @@ import sys + + import nose + +-from grin import FileRecognizer ++from grin import FileRecognizer, ints2bytes, GZIP_MAGIC + + def empty_file(filename, open=open): + f = open(filename, 'wb') +@@ -17,13 +18,13 @@ def empty_file(filename, open=open): + + def binary_file(filename, open=open): + f = open(filename, 'wb') +- f.write(''.join(map(chr, range(256)))) ++ f.write(ints2bytes(range(255))) + f.close() + + def text_file(filename, open=open): +- lines = ['foo\n', 'bar\n'] * 100 +- lines.append('baz\n') +- lines.extend(['foo\n', 'bar\n'] * 100) ++ lines = [b'foo\n', b'bar\n'] * 100 ++ lines.append(b'baz\n') ++ lines.extend([b'foo\n', b'bar\n'] * 100) + f = open(filename, 'wb') + f.writelines(lines) + f.close() +@@ -32,10 +33,9 @@ def fake_gzip_file(filename, open=open): + """ Write out a binary file that has the gzip magic header bytes, but is not + a gzip file. + """ +- GZIP_MAGIC = '\037\213' + f = open(filename, 'wb') + f.write(GZIP_MAGIC) +- f.write(''.join(map(chr, range(256)))) ++ f.write(ints2bytes(range(255))) + f.close() + + def binary_middle(filename, open=open): +@@ -43,7 +43,7 @@ def binary_middle(filename, open=open): + bytes, then 100 text bytes to test that the recognizer only reads some of + the file. + """ +- text = 'a'*100 + '\0'*100 + 'b'*100 ++ text = b'a'*100 + b'\0'*100 + b'b'*100 + f = open(filename, 'wb') + f.write(text) + f.close() +@@ -56,25 +56,25 @@ def unreadable_file(filename): + """ Write a file that does not have read permissions. + """ + text_file(filename) +- os.chmod(filename, 0200) ++ os.chmod(filename, 0o200) + + def unreadable_dir(filename): + """ Make a directory that does not have read permissions. + """ + os.mkdir(filename) +- os.chmod(filename, 0300) ++ os.chmod(filename, 0o300) + + def unexecutable_dir(filename): + """ Make a directory that does not have execute permissions. + """ + os.mkdir(filename) +- os.chmod(filename, 0600) ++ os.chmod(filename, 0o600) + + def totally_unusable_dir(filename): + """ Make a directory that has neither read nor execute permissions. + """ + os.mkdir(filename) +- os.chmod(filename, 0100) ++ os.chmod(filename, 0o100) + + def setup(): + # Make files to test individual recognizers. +@@ -135,22 +135,14 @@ def setup(): + text_file('tree/.skip_hidden_file') + os.mkdir('tree/unreadable_dir') + text_file('tree/unreadable_dir/text') +- os.chmod('tree/unreadable_dir', 0300) ++ os.chmod('tree/unreadable_dir', 0o300) + os.mkdir('tree/unexecutable_dir') + text_file('tree/unexecutable_dir/text') +- os.chmod('tree/unexecutable_dir', 0600) ++ os.chmod('tree/unexecutable_dir', 0o600) + os.mkdir('tree/totally_unusable_dir') + text_file('tree/totally_unusable_dir/text') +- os.chmod('tree/totally_unusable_dir', 0100) ++ os.chmod('tree/totally_unusable_dir', 0o100) + +-def ensure_deletability(arg, dirname, fnames): +- """ os.path.walk() callback function which will make sure every directory is +- readable and executable so that it may be easily deleted. +- """ +- for fn in fnames: +- fn = os.path.join(dirname, fn) +- if os.path.isdir(fn): +- os.chmod(fn, 0700) + + def teardown(): + files_to_delete = ['empty', 'binary', 'binary_middle', 'text', 'text~', +@@ -168,10 +160,13 @@ def teardown(): + os.unlink(filename) + else: + os.rmdir(filename) +- except Exception, e: +- print >>sys.stderr, 'Could not delete %s: %s' % (filename, e) ++ except Exception as e: ++ print('Could not delete %s: %s' % (filename, e), file=sys.stderr) + os.unlink('socket_test') +- os.path.walk('tree', ensure_deletability, None) ++ for dirpath, dirnames, filenames in os.walk('tree'): ++ # Make sure every directory can be deleted ++ for dirname in dirnames: ++ os.chmod(os.path.join(dirpath, dirname), 0o700) + shutil.rmtree('tree') + + +diff --git a/tests/test_grep.py b/tests/test_grep.py +index aa367f2..f5ee62f 100644 +--- a/tests/test_grep.py ++++ b/tests/test_grep.py +@@ -4,52 +4,52 @@ r''' + Set up + + >>> import grin +- >>> from cStringIO import StringIO ++ >>> from io import BytesIO + >>> import re +- >>> +- >>> all_foo = """\ ++ >>> ++ >>> all_foo = b"""\ + ... foo + ... foo + ... foo + ... foo + ... foo + ... """ +- >>> first_foo = """\ ++ >>> first_foo = b"""\ + ... foo + ... bar + ... bar + ... bar + ... bar + ... """ +- >>> last_foo = """\ ++ >>> last_foo = b"""\ + ... bar + ... bar + ... bar + ... bar + ... foo + ... """ +- >>> second_foo = """\ ++ >>> second_foo = b"""\ + ... bar + ... foo + ... bar + ... bar + ... bar + ... """ +- >>> second_last_foo = """\ ++ >>> second_last_foo = b"""\ + ... bar + ... bar + ... bar + ... foo + ... bar + ... """ +- >>> middle_foo = """\ ++ >>> middle_foo = b"""\ + ... bar + ... bar + ... foo + ... bar + ... bar + ... """ +- >>> small_gap = """\ ++ >>> small_gap = b"""\ + ... bar + ... bar + ... foo +@@ -58,8 +58,8 @@ Set up + ... bar + ... bar + ... """ +- >>> no_eol = "foo" +- >>> middle_of_line = """\ ++ >>> no_eol = b"foo" ++ >>> middle_of_line = b"""\ + ... bar + ... bar + ... barfoobar +@@ -70,111 +70,111 @@ Set up + Test the basic defaults, no context. + + >>> gt_default = grin.GrepText(re.compile('foo')) +- >>> gt_default.do_grep(StringIO(all_foo)) ++ >>> gt_default.do_grep(BytesIO(all_foo)) + [(0, 0, 'foo\n', [(0, 3)]), (1, 0, 'foo\n', [(0, 3)]), (2, 0, 'foo\n', [(0, 3)]), (3, 0, 'foo\n', [(0, 3)]), (4, 0, 'foo\n', [(0, 3)])] +- >>> gt_default.do_grep(StringIO(first_foo)) ++ >>> gt_default.do_grep(BytesIO(first_foo)) + [(0, 0, 'foo\n', [(0, 3)])] +- >>> gt_default.do_grep(StringIO(last_foo)) ++ >>> gt_default.do_grep(BytesIO(last_foo)) + [(4, 0, 'foo\n', [(0, 3)])] +- >>> gt_default.do_grep(StringIO(second_foo)) ++ >>> gt_default.do_grep(BytesIO(second_foo)) + [(1, 0, 'foo\n', [(0, 3)])] +- >>> gt_default.do_grep(StringIO(second_last_foo)) ++ >>> gt_default.do_grep(BytesIO(second_last_foo)) + [(3, 0, 'foo\n', [(0, 3)])] +- >>> gt_default.do_grep(StringIO(middle_foo)) ++ >>> gt_default.do_grep(BytesIO(middle_foo)) + [(2, 0, 'foo\n', [(0, 3)])] +- >>> gt_default.do_grep(StringIO(small_gap)) ++ >>> gt_default.do_grep(BytesIO(small_gap)) + [(2, 0, 'foo\n', [(0, 3)]), (4, 0, 'foo\n', [(0, 3)])] +- >>> gt_default.do_grep(StringIO(no_eol)) ++ >>> gt_default.do_grep(BytesIO(no_eol)) + [(0, 0, 'foo', [(0, 3)])] +- >>> gt_default.do_grep(StringIO(middle_of_line)) ++ >>> gt_default.do_grep(BytesIO(middle_of_line)) + [(2, 0, 'barfoobar\n', [(3, 6)])] + + Symmetric 1-line context. + + >>> gt_context_1 = grin.GrepText(re.compile('foo'), options=grin.Options(before_context=1, after_context=1)) +- >>> gt_context_1.do_grep(StringIO(all_foo)) ++ >>> gt_context_1.do_grep(BytesIO(all_foo)) + [(0, 0, 'foo\n', [(0, 3)]), (1, 0, 'foo\n', [(0, 3)]), (2, 0, 'foo\n', [(0, 3)]), (3, 0, 'foo\n', [(0, 3)]), (4, 0, 'foo\n', [(0, 3)])] +- >>> gt_context_1.do_grep(StringIO(first_foo)) ++ >>> gt_context_1.do_grep(BytesIO(first_foo)) + [(0, 0, 'foo\n', [(0, 3)]), (1, 1, 'bar\n', None)] +- >>> gt_context_1.do_grep(StringIO(last_foo)) ++ >>> gt_context_1.do_grep(BytesIO(last_foo)) + [(3, -1, 'bar\n', None), (4, 0, 'foo\n', [(0, 3)])] +- >>> gt_context_1.do_grep(StringIO(second_foo)) ++ >>> gt_context_1.do_grep(BytesIO(second_foo)) + [(0, -1, 'bar\n', None), (1, 0, 'foo\n', [(0, 3)]), (2, 1, 'bar\n', None)] +- >>> gt_context_1.do_grep(StringIO(second_last_foo)) ++ >>> gt_context_1.do_grep(BytesIO(second_last_foo)) + [(2, -1, 'bar\n', None), (3, 0, 'foo\n', [(0, 3)]), (4, 1, 'bar\n', None)] +- >>> gt_context_1.do_grep(StringIO(middle_foo)) ++ >>> gt_context_1.do_grep(BytesIO(middle_foo)) + [(1, -1, 'bar\n', None), (2, 0, 'foo\n', [(0, 3)]), (3, 1, 'bar\n', None)] +- >>> gt_context_1.do_grep(StringIO(small_gap)) ++ >>> gt_context_1.do_grep(BytesIO(small_gap)) + [(1, -1, 'bar\n', None), (2, 0, 'foo\n', [(0, 3)]), (3, 1, 'bar\n', None), (4, 0, 'foo\n', [(0, 3)]), (5, 1, 'bar\n', None)] +- >>> gt_context_1.do_grep(StringIO(no_eol)) ++ >>> gt_context_1.do_grep(BytesIO(no_eol)) + [(0, 0, 'foo', [(0, 3)])] +- >>> gt_context_1.do_grep(StringIO(middle_of_line)) ++ >>> gt_context_1.do_grep(BytesIO(middle_of_line)) + [(1, -1, 'bar\n', None), (2, 0, 'barfoobar\n', [(3, 6)]), (3, 1, 'bar\n', None)] + + Symmetric 2-line context. + + >>> gt_context_2 = grin.GrepText(re.compile('foo'), options=grin.Options(before_context=2, after_context=2)) +- >>> gt_context_2.do_grep(StringIO(all_foo)) ++ >>> gt_context_2.do_grep(BytesIO(all_foo)) + [(0, 0, 'foo\n', [(0, 3)]), (1, 0, 'foo\n', [(0, 3)]), (2, 0, 'foo\n', [(0, 3)]), (3, 0, 'foo\n', [(0, 3)]), (4, 0, 'foo\n', [(0, 3)])] +- >>> gt_context_2.do_grep(StringIO(first_foo)) ++ >>> gt_context_2.do_grep(BytesIO(first_foo)) + [(0, 0, 'foo\n', [(0, 3)]), (1, 1, 'bar\n', None), (2, 1, 'bar\n', None)] +- >>> gt_context_2.do_grep(StringIO(last_foo)) ++ >>> gt_context_2.do_grep(BytesIO(last_foo)) + [(2, -1, 'bar\n', None), (3, -1, 'bar\n', None), (4, 0, 'foo\n', [(0, 3)])] +- >>> gt_context_2.do_grep(StringIO(second_foo)) ++ >>> gt_context_2.do_grep(BytesIO(second_foo)) + [(0, -1, 'bar\n', None), (1, 0, 'foo\n', [(0, 3)]), (2, 1, 'bar\n', None), (3, 1, 'bar\n', None)] +- >>> gt_context_2.do_grep(StringIO(second_last_foo)) ++ >>> gt_context_2.do_grep(BytesIO(second_last_foo)) + [(1, -1, 'bar\n', None), (2, -1, 'bar\n', None), (3, 0, 'foo\n', [(0, 3)]), (4, 1, 'bar\n', None)] +- >>> gt_context_2.do_grep(StringIO(middle_foo)) ++ >>> gt_context_2.do_grep(BytesIO(middle_foo)) + [(0, -1, 'bar\n', None), (1, -1, 'bar\n', None), (2, 0, 'foo\n', [(0, 3)]), (3, 1, 'bar\n', None), (4, 1, 'bar\n', None)] +- >>> gt_context_2.do_grep(StringIO(small_gap)) ++ >>> gt_context_2.do_grep(BytesIO(small_gap)) + [(0, -1, 'bar\n', None), (1, -1, 'bar\n', None), (2, 0, 'foo\n', [(0, 3)]), (3, 1, 'bar\n', None), (4, 0, 'foo\n', [(0, 3)]), (5, 1, 'bar\n', None), (6, 1, 'bar\n', None)] +- >>> gt_context_2.do_grep(StringIO(no_eol)) ++ >>> gt_context_2.do_grep(BytesIO(no_eol)) + [(0, 0, 'foo', [(0, 3)])] +- >>> gt_context_2.do_grep(StringIO(middle_of_line)) ++ >>> gt_context_2.do_grep(BytesIO(middle_of_line)) + [(0, -1, 'bar\n', None), (1, -1, 'bar\n', None), (2, 0, 'barfoobar\n', [(3, 6)]), (3, 1, 'bar\n', None), (4, 1, 'bar\n', None)] + + 1 line of before-context, no lines after. + + >>> gt_before_context_1 = grin.GrepText(re.compile('foo'), options=grin.Options(before_context=1, after_context=0)) +- >>> gt_before_context_1.do_grep(StringIO(all_foo)) ++ >>> gt_before_context_1.do_grep(BytesIO(all_foo)) + [(0, 0, 'foo\n', [(0, 3)]), (1, 0, 'foo\n', [(0, 3)]), (2, 0, 'foo\n', [(0, 3)]), (3, 0, 'foo\n', [(0, 3)]), (4, 0, 'foo\n', [(0, 3)])] +- >>> gt_before_context_1.do_grep(StringIO(first_foo)) ++ >>> gt_before_context_1.do_grep(BytesIO(first_foo)) + [(0, 0, 'foo\n', [(0, 3)])] +- >>> gt_before_context_1.do_grep(StringIO(last_foo)) ++ >>> gt_before_context_1.do_grep(BytesIO(last_foo)) + [(3, -1, 'bar\n', None), (4, 0, 'foo\n', [(0, 3)])] +- >>> gt_before_context_1.do_grep(StringIO(second_foo)) ++ >>> gt_before_context_1.do_grep(BytesIO(second_foo)) + [(0, -1, 'bar\n', None), (1, 0, 'foo\n', [(0, 3)])] +- >>> gt_before_context_1.do_grep(StringIO(second_last_foo)) ++ >>> gt_before_context_1.do_grep(BytesIO(second_last_foo)) + [(2, -1, 'bar\n', None), (3, 0, 'foo\n', [(0, 3)])] +- >>> gt_before_context_1.do_grep(StringIO(middle_foo)) ++ >>> gt_before_context_1.do_grep(BytesIO(middle_foo)) + [(1, -1, 'bar\n', None), (2, 0, 'foo\n', [(0, 3)])] +- >>> gt_before_context_1.do_grep(StringIO(small_gap)) ++ >>> gt_before_context_1.do_grep(BytesIO(small_gap)) + [(1, -1, 'bar\n', None), (2, 0, 'foo\n', [(0, 3)]), (3, -1, 'bar\n', None), (4, 0, 'foo\n', [(0, 3)])] +- >>> gt_before_context_1.do_grep(StringIO(no_eol)) ++ >>> gt_before_context_1.do_grep(BytesIO(no_eol)) + [(0, 0, 'foo', [(0, 3)])] +- >>> gt_before_context_1.do_grep(StringIO(middle_of_line)) ++ >>> gt_before_context_1.do_grep(BytesIO(middle_of_line)) + [(1, -1, 'bar\n', None), (2, 0, 'barfoobar\n', [(3, 6)])] + + 1 line of after-context, no lines before. + + >>> gt_after_context_1 = grin.GrepText(re.compile('foo'), options=grin.Options(before_context=0, after_context=1)) +- >>> gt_after_context_1.do_grep(StringIO(all_foo)) ++ >>> gt_after_context_1.do_grep(BytesIO(all_foo)) + [(0, 0, 'foo\n', [(0, 3)]), (1, 0, 'foo\n', [(0, 3)]), (2, 0, 'foo\n', [(0, 3)]), (3, 0, 'foo\n', [(0, 3)]), (4, 0, 'foo\n', [(0, 3)])] +- >>> gt_after_context_1.do_grep(StringIO(first_foo)) ++ >>> gt_after_context_1.do_grep(BytesIO(first_foo)) + [(0, 0, 'foo\n', [(0, 3)]), (1, 1, 'bar\n', None)] +- >>> gt_after_context_1.do_grep(StringIO(last_foo)) ++ >>> gt_after_context_1.do_grep(BytesIO(last_foo)) + [(4, 0, 'foo\n', [(0, 3)])] +- >>> gt_after_context_1.do_grep(StringIO(second_foo)) ++ >>> gt_after_context_1.do_grep(BytesIO(second_foo)) + [(1, 0, 'foo\n', [(0, 3)]), (2, 1, 'bar\n', None)] +- >>> gt_after_context_1.do_grep(StringIO(second_last_foo)) ++ >>> gt_after_context_1.do_grep(BytesIO(second_last_foo)) + [(3, 0, 'foo\n', [(0, 3)]), (4, 1, 'bar\n', None)] +- >>> gt_after_context_1.do_grep(StringIO(middle_foo)) ++ >>> gt_after_context_1.do_grep(BytesIO(middle_foo)) + [(2, 0, 'foo\n', [(0, 3)]), (3, 1, 'bar\n', None)] +- >>> gt_after_context_1.do_grep(StringIO(small_gap)) ++ >>> gt_after_context_1.do_grep(BytesIO(small_gap)) + [(2, 0, 'foo\n', [(0, 3)]), (3, 1, 'bar\n', None), (4, 0, 'foo\n', [(0, 3)]), (5, 1, 'bar\n', None)] +- >>> gt_after_context_1.do_grep(StringIO(no_eol)) ++ >>> gt_after_context_1.do_grep(BytesIO(no_eol)) + [(0, 0, 'foo', [(0, 3)])] +- >>> gt_after_context_1.do_grep(StringIO(middle_of_line)) ++ >>> gt_after_context_1.do_grep(BytesIO(middle_of_line)) + [(2, 0, 'barfoobar\n', [(3, 6)]), (3, 1, 'bar\n', None)] + + ''' diff --git a/grin.spec b/grin.spec index 3dd939e..ca3ca19 100644 --- a/grin.spec +++ b/grin.spec @@ -1,21 +1,17 @@ -%if 0%{?rhel} && 0%{?rhel} < 7 -%global argparse 1 -%endif - Summary: Grep-like tool for source code Name: grin Version: 1.2.1 -Release: 20%{?dist} +Release: 21%{?dist} License: BSD URL: http://pypi.python.org/pypi/grin -Source0: http://pypi.python.org/packages/source/g/grin/grin-%{version}.tar.gz -Patch0: grin-1.2.1-argparse.patch -Requires: python2-setuptools -%{?argparse:Requires: python-argparse} +Source0: https://files.pythonhosted.org/packages/source/g/grin/grin-%{version}.tar.gz +Patch1: grin-1.2.1-git-8dd4b5.patch +Patch2: grin-1.2.1-python3.patch +Requires: python3-setuptools BuildArch: noarch -BuildRequires: python2-devel -BuildRequires: python2-setuptools -BuildRequires: python2-nose +BuildRequires: python3-devel +BuildRequires: python3-setuptools +BuildRequires: python3-nose %description grin is a similar in function to GNU grep, however it is has modified @@ -36,28 +32,33 @@ Some features grin feature are: %prep %setup -q -%patch0 -p1 +%patch1 -p1 +%patch2 -p1 chmod 0644 examples/* sed -i -e '1d' grin.py %build -%{py2_build} +%{py3_build} %install -%{py2_install} +%{py3_install} %check nosetests %files %license LICENSE.txt -%doc ANNOUNCE.txt examples LICENSE.txt README.txt THANKS.txt +%doc ANNOUNCE.txt examples LICENSE.txt README.rst THANKS.txt %{_bindir}/grin %{_bindir}/grind -%{python2_sitelib}/grin.py* -%{python2_sitelib}/grin-*-py*.egg-info/ +%{python3_sitelib}/grin.py* +%{python3_sitelib}/grin-*-py*.egg-info/ +%{python3_sitelib}/__pycache__/grin.* %changelog +* Mon Aug 05 2019 Terje Rosten - 1.2.1-21 +- Convert to Python 3 + * Thu Jul 25 2019 Fedora Release Engineering - 1.2.1-20 - Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild