[python-behave] Remove bundled compatibility libraries and add Requires.

Matej Cepl mcepl at fedoraproject.org
Fri May 9 16:41:30 UTC 2014


commit 41ba8230839020ef90ef4677c93e34e29d303a6b
Author: Matěj Cepl <mcepl at redhat.com>
Date:   Fri May 9 18:34:20 2014 +0200

    Remove bundled compatibility libraries and add Requires.
    
    (Fixes RHBZ# 1096220)

 Fix-relpath-imports.patch |  458 +++++++++++++++++++++++++++++++++++++++++++++
 python-behave.spec        |   26 ++-
 2 files changed, 475 insertions(+), 9 deletions(-)
---
diff --git a/Fix-relpath-imports.patch b/Fix-relpath-imports.patch
new file mode 100644
index 0000000..2a33bcf
--- /dev/null
+++ b/Fix-relpath-imports.patch
@@ -0,0 +1,458 @@
+The only package from the ones covered by behave/compat/ libraries which
+are not required in setup.py for particular version is behave/compat/os_path.py
+which is for compatibility with python <= 2.5
+
+
+--- a/behave/formatter/progress.py
++++ b/behave/formatter/progress.py
+@@ -9,9 +9,12 @@ A "dot" character that represents the re
+ executing a scope item.
+ """
+ 
+-from behave.formatter.base import Formatter
+-from behave.compat.os_path import relpath
+ import os
++from behave.formatter.base import Formatter
++try:
++    from os.path import relpath
++except ImportError:
++    from behave.compat.os_path import relpath
+ 
+ # -----------------------------------------------------------------------------
+ # CLASS: ProgressFormatterBase
+--- a/behave/formatter/rerun.py
++++ b/behave/formatter/rerun.py
+@@ -23,9 +23,12 @@ Normally, you put the RerunFormatter int
+ """
+ 
+ from behave.formatter.base import Formatter
+-from behave.compat.os_path import relpath
+ from datetime import datetime
+ import os
++try:
++    from os.path import relpath
++except ImportError:
++    from behave.compat.os_path import relpath
+ 
+ 
+ # -----------------------------------------------------------------------------
+@@ -90,7 +93,7 @@ class RerunFormatter(Formatter):
+         self.stream.write(message % len(self.failed_scenarios))
+         if self.show_timestamp:
+             now = datetime.now().replace(microsecond=0)
+-            self.stream.write("# NOW: %s\n"% now.isoformat(" "))
++            self.stream.write("# NOW: %s\n" % now.isoformat(" "))
+ 
+         # -- SECTION: Textual summary in comments.
+         if self.show_failed_scenarios_descriptions:
+@@ -102,7 +105,7 @@ class RerunFormatter(Formatter):
+                     current_feature = scenario.filename
+                     short_filename = relpath(scenario.filename, os.getcwd())
+                     self.stream.write(u"# %s\n" % short_filename)
+-                self.stream.write(u"#  %4d:  %s\n" % \
++                self.stream.write(u"#  %4d:  %s\n" %
+                                   (scenario.line, scenario.name))
+             self.stream.write("\n")
+ 
+--- a/behave/formatter/sphinx_steps.py
++++ b/behave/formatter/sphinx_steps.py
+@@ -14,11 +14,14 @@ TODO:
+ 
+ from behave.formatter.steps import AbstractStepsFormatter
+ from behave.formatter import sphinx_util
+-from behave.compat.os_path import relpath
+ from behave.model import Table
+ import inspect
+ import os.path
+ import sys
++try:
++    from os.path import relpath
++except ImportError:
++    from behave.compat.os_path import relpath
+ 
+ 
+ # -----------------------------------------------------------------------------
+--- a/behave/model.py
++++ b/behave/model.py
+@@ -1,6 +1,7 @@
+ # -*- coding: utf-8 -*-
+ 
+ from __future__ import with_statement
++import sys
+ import copy
+ import difflib
+ import itertools
+@@ -8,7 +9,10 @@ import os.path
+ import time
+ import traceback
+ from behave import step_registry
+-from behave.compat.os_path import relpath
++try:
++    from os.path import relpath
++except ImportError:
++    from behave.compat.os_path import relpath
+ 
+ 
+ class Argument(object):
+@@ -1313,7 +1317,10 @@ class Row(object):
+         Converts the row and its cell data into a dictionary.
+         :return: Row data as dictionary (without comments, line info).
+         """
+-        from behave.compat.collections import OrderedDict
++        try:
++            from collections import OrderedDict
++        except ImportError:
++            from behave.compat.collections import OrderedDict
+         return OrderedDict(self.items())
+ 
+ 
+--- a/behave/formatter/html.py
++++ b/behave/formatter/html.py
+@@ -2,12 +2,16 @@ from behave.formatter.base import Format
+ import lxml.etree as ET
+ import base64
+ import os.path
+-from behave.compat.collections import Counter
++try:
++    from collections import Counter
++except ImportError:
++    from behave.compat.collections import Counter
++
+ 
+ def _valid_XML_char_ordinal(char):
+     i = ord(char)
+     return ( # conditions ordered by presumed frequency
+-        0x20 <= i <= 0xD7FF 
++        0x20 <= i <= 0xD7FF
+         or i in (0x9, 0xA, 0xD)
+         or 0xE000 <= i <= 0xFFFD
+         or 0x10000 <= i <= 0x10FFFF
+--- a/behave/importer.py
++++ b/behave/importer.py
+@@ -5,7 +5,11 @@ Importer module for lazy-loading/importi
+ REQUIRES: importlib (provided in Python2.7, Python3.2...)
+ """
+ 
+-from behave.compat import importlib
++import sys
++try:
++    import importlib
++except ImportError:
++    from behave.compat import importlib
+ 
+ 
+ class Unknown(object):
+--- a/test/test_model.py
++++ b/test/test_model.py
+@@ -1,11 +1,13 @@
+ from __future__ import with_statement
+ 
+-import re
+ import sys
+ from mock import Mock, patch
+ from nose.tools import *
+ from behave import model
+-from behave.compat.collections import OrderedDict
++try:
++    from collections import OrderedDict
++except ImportError:
++    from behave.compat.collections import OrderedDict
+ from behave import step_registry
+ from behave.configuration import Configuration
+ 
+--- a/behave/compat/__init__.py
++++ /dev/null
+@@ -1,5 +0,0 @@
+-# -*- coding: utf-8 -*-
+-"""
+-Used for behave as compatibility layer between different Python versions
+-and implementations.
+-"""
+\ No newline at end of file
+--- a/behave/compat/collections.py
++++ /dev/null
+@@ -1,205 +0,0 @@
+-# -*- coding: utf-8 -*-
+-"""
+-Compatibility of :module:`collections` between different Python versions.
+-"""
+-
+-from __future__ import absolute_import
+-import warnings
+-
+-try:
+-    # -- SINCE: Python2.7
+-    from collections import OrderedDict
+-except ImportError:     # pragma: no cover
+-    try:
+-        # -- BACK-PORTED FOR: Python 2.4 .. 2.6
+-        from ordereddict import OrderedDict
+-    except ImportError:
+-        message = "collections.OrderedDict is missing: Install 'ordereddict'."
+-        warnings.warn(message)
+-        # -- BACKWARD-COMPATIBLE: Better than nothing (for behave use case).
+-        OrderedDict = dict
+-
+-try:
+-    # -- SINCE: Python2.7
+-    from collections import Counter
+-except ImportError:     # pragma: no cover
+-    class Counter(dict):
+-        '''Dict subclass for counting hashable objects.  Sometimes called a bag
+-        or multiset.  Elements are stored as dictionary keys and their counts
+-        are stored as dictionary values.
+-
+-        >>> Counter('zyzygy')
+-        Counter({'y': 3, 'z': 2, 'g': 1})
+-
+-        '''
+-
+-        def __init__(self, iterable=None, **kwds):
+-            '''Create a new, empty Counter object.  And if given, count elements
+-            from an input iterable.  Or, initialize the count from another mapping
+-            of elements to their counts.
+-
+-            >>> c = Counter()                           # a new, empty counter
+-            >>> c = Counter('gallahad')                 # a new counter from an iterable
+-            >>> c = Counter({'a': 4, 'b': 2})           # a new counter from a mapping
+-            >>> c = Counter(a=4, b=2)                   # a new counter from keyword args
+-
+-            '''
+-            self.update(iterable, **kwds)
+-
+-        def __missing__(self, key):
+-            return 0
+-
+-        def most_common(self, n=None):
+-            '''List the n most common elements and their counts from the most
+-            common to the least.  If n is None, then list all element counts.
+-
+-            >>> Counter('abracadabra').most_common(3)
+-            [('a', 5), ('r', 2), ('b', 2)]
+-
+-            '''
+-            if n is None:
+-                return sorted(self.iteritems(), key=itemgetter(1), reverse=True)
+-            return nlargest(n, self.iteritems(), key=itemgetter(1))
+-
+-        def elements(self):
+-            '''Iterator over elements repeating each as many times as its count.
+-
+-            >>> c = Counter('ABCABC')
+-            >>> sorted(c.elements())
+-            ['A', 'A', 'B', 'B', 'C', 'C']
+-
+-            If an element's count has been set to zero or is a negative number,
+-            elements() will ignore it.
+-
+-            '''
+-            for elem, count in self.iteritems():
+-                for _ in repeat(None, count):
+-                    yield elem
+-
+-        # Override dict methods where the meaning changes for Counter objects.
+-
+-        @classmethod
+-        def fromkeys(cls, iterable, v=None):
+-            raise NotImplementedError(
+-                'Counter.fromkeys() is undefined.  Use Counter(iterable) instead.')
+-
+-        def update(self, iterable=None, **kwds):
+-            '''Like dict.update() but add counts instead of replacing them.
+-
+-            Source can be an iterable, a dictionary, or another Counter instance.
+-
+-            >>> c = Counter('which')
+-            >>> c.update('witch')           # add elements from another iterable
+-            >>> d = Counter('watch')
+-            >>> c.update(d)                 # add elements from another counter
+-            >>> c['h']                      # four 'h' in which, witch, and watch
+-            4
+-
+-            '''
+-            if iterable is not None:
+-                if hasattr(iterable, 'iteritems'):
+-                    if self:
+-                        self_get = self.get
+-                        for elem, count in iterable.iteritems():
+-                            self[elem] = self_get(elem, 0) + count
+-                    else:
+-                        dict.update(self, iterable) # fast path when counter is empty
+-                else:
+-                    self_get = self.get
+-                    for elem in iterable:
+-                        self[elem] = self_get(elem, 0) + 1
+-            if kwds:
+-                self.update(kwds)
+-
+-        def copy(self):
+-            'Like dict.copy() but returns a Counter instance instead of a dict.'
+-            return Counter(self)
+-
+-        def __delitem__(self, elem):
+-            'Like dict.__delitem__() but does not raise KeyError for missing values.'
+-            if elem in self:
+-                dict.__delitem__(self, elem)
+-
+-        def __repr__(self):
+-            if not self:
+-                return '%s()' % self.__class__.__name__
+-            items = ', '.join(map('%r: %r'.__mod__, self.most_common()))
+-            return '%s({%s})' % (self.__class__.__name__, items)
+-
+-        # Multiset-style mathematical operations discussed in:
+-        #       Knuth TAOCP Volume II section 4.6.3 exercise 19
+-        #       and at http://en.wikipedia.org/wiki/Multiset
+-        #
+-        # Outputs guaranteed to only include positive counts.
+-        #
+-        # To strip negative and zero counts, add-in an empty counter:
+-        #       c += Counter()
+-
+-        def __add__(self, other):
+-            '''Add counts from two counters.
+-
+-            >>> Counter('abbb') + Counter('bcc')
+-            Counter({'b': 4, 'c': 2, 'a': 1})
+-
+-
+-            '''
+-            if not isinstance(other, Counter):
+-                return NotImplemented
+-            result = Counter()
+-            for elem in set(self) | set(other):
+-                newcount = self[elem] + other[elem]
+-                if newcount > 0:
+-                    result[elem] = newcount
+-            return result
+-
+-        def __sub__(self, other):
+-            ''' Subtract count, but keep only results with positive counts.
+-
+-            >>> Counter('abbbc') - Counter('bccd')
+-            Counter({'b': 2, 'a': 1})
+-
+-            '''
+-            if not isinstance(other, Counter):
+-                return NotImplemented
+-            result = Counter()
+-            for elem in set(self) | set(other):
+-                newcount = self[elem] - other[elem]
+-                if newcount > 0:
+-                    result[elem] = newcount
+-            return result
+-
+-        def __or__(self, other):
+-            '''Union is the maximum of value in either of the input counters.
+-
+-            >>> Counter('abbb') | Counter('bcc')
+-            Counter({'b': 3, 'c': 2, 'a': 1})
+-
+-            '''
+-            if not isinstance(other, Counter):
+-                return NotImplemented
+-            _max = max
+-            result = Counter()
+-            for elem in set(self) | set(other):
+-                newcount = _max(self[elem], other[elem])
+-                if newcount > 0:
+-                    result[elem] = newcount
+-            return result
+-
+-        def __and__(self, other):
+-            ''' Intersection is the minimum of corresponding counts.
+-
+-            >>> Counter('abbb') & Counter('bcc')
+-            Counter({'b': 1})
+-
+-            '''
+-            if not isinstance(other, Counter):
+-                return NotImplemented
+-            _min = min
+-            result = Counter()
+-            if len(self) < len(other):
+-                self, other = other, self
+-            for elem in ifilter(self.__contains__, other):
+-                newcount = _min(self[elem], other[elem])
+-                if newcount > 0:
+-                    result[elem] = newcount
+-            return result
+--- a/behave/compat/importlib.py
++++ /dev/null
+@@ -1,46 +0,0 @@
+-# -*- coding: utf-8 -*-
+-"""
+-importlib was introduced in python2.7, python3.2...
+-"""
+-
+-try:
+-    from importlib import import_module
+-except ImportError:
+-    """Backport of importlib.import_module from 3.x."""
+-    # While not critical (and in no way guaranteed!), it would be nice to keep this
+-    # code compatible with Python 2.3.
+-    import sys
+-
+-    def _resolve_name(name, package, level):
+-        """Return the absolute name of the module to be imported."""
+-        if not hasattr(package, 'rindex'):
+-            raise ValueError("'package' not set to a string")
+-        dot = len(package)
+-        for x in xrange(level, 1, -1):
+-            try:
+-                dot = package.rindex('.', 0, dot)
+-            except ValueError:
+-                raise ValueError("attempted relative import beyond top-level "
+-                                  "package")
+-        return "%s.%s" % (package[:dot], name)
+-
+-
+-    def import_module(name, package=None):
+-        """Import a module.
+-
+-        The 'package' argument is required when performing a relative import. It
+-        specifies the package to use as the anchor point from which to resolve the
+-        relative import to an absolute import.
+-
+-        """
+-        if name.startswith('.'):
+-            if not package:
+-                raise TypeError("relative imports require the 'package' argument")
+-            level = 0
+-            for character in name:
+-                if character != '.':
+-                    break
+-                level += 1
+-            name = _resolve_name(name[level:], package, level)
+-        __import__(name)
+-        return sys.modules[name]
+--- a/behave/compat/os_path.py
++++ /dev/null
+@@ -1,27 +0,0 @@
+-# -*- coding: utf-8 -*-
+-"""
+-Compatibility of :module:`os.path` between different Python versions.
+-"""
+-
+-import os.path
+-
+-relpath = getattr(os.path, "relpath", None)
+-if relpath is None: # pragma: no cover
+-    # -- Python2.5 doesn't know about relpath
+-    def relpath(path, start=os.path.curdir):
+-        """
+-        Return a relative version of a path
+-        BASED-ON: Python2.7
+-        """
+-        if not path:
+-            raise ValueError("no path specified")
+-
+-        start_list = [x for x in os.path.abspath(start).split(os.path.sep) if x]
+-        path_list  = [x for x in os.path.abspath(path).split(os.path.sep) if x]
+-        # Work out how much of the filepath is shared by start and path.
+-        i = len(os.path.commonprefix([start_list, path_list]))
+-
+-        rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:]
+-        if not rel_list:
+-            return os.path.curdir
+-        return os.path.join(*rel_list)
diff --git a/python-behave.spec b/python-behave.spec
index c174c88..fbf4cce 100644
--- a/python-behave.spec
+++ b/python-behave.spec
@@ -12,7 +12,7 @@
 
 Name:               python-%{modname}
 Version:            1.2.3
-Release:            12%{?dist}
+Release:            13%{?dist}
 Summary:            Tools for the behavior-driven development, Python style
 
 License:            BSD
@@ -27,24 +27,27 @@ Patch1: html-formatter-strip-incorrect-chars-from-error-mess.patch
 Patch2: Embedding-support-link-caption-and-video-tags.patch
 # Fix for RHBZ#
 Patch3: Don-t-crash-on-invalid-XML-chars-in-embed.patch
+# Fix for unnecessary relpath compatibility library
+Patch4: Fix-relpath-imports.patch
 BuildArch:          noarch
 
 Requires:           python-setuptools
+BuildRequires:      python-parse
+BuildRequires:      python-setuptools
+BuildRequires:      python2-devel
+Requires:           python-parse
+
 %if %{with testsuite}
 BuildRequires:      python-mock
 BuildRequires:      python-nose
 %endif
-BuildRequires:      python-parse
-BuildRequires:      python-setuptools
+
 %{?el6:BuildRequires:      python-ordereddict}
+%{?el6:Requires:    python-ordereddict}
 %{?el6:BuildRequires:      python-argparse}
-%{?el6:BuildRequires:      python-simplejson}
-BuildRequires:      python2-devel
-
 %{?el6:Requires:    python-argparse}
-%{?el6:Requires:    python-ordereddict}
-Requires:           python-parse
-%{?el6:Requires:    python-simplejson}
+%{?el6:BuildRequires:    python-importlib}
+%{?el6:Requires:    python-importlib}
 
 
 %description
@@ -84,6 +87,7 @@ brief feature-examples.
 %patch1 -p1 -b .HTMLformatterFixUTF8
 %patch2 -p1 -b .EmbeddedVideo
 %patch3 -p1 -b .NoCrash
+%patch4 -p1 -b .relpath
 
 # Remove bundled egg-info in case it exists
 rm -rf %{modname}*.egg-info
@@ -153,6 +157,10 @@ nosetests -v
 
 
 %changelog
+* Fri May 09 2014 Matěj Cepl <mcepl at redhat.com> - 1.2.3-13
+- Remove bundled compatibility libraries and add Requires
+  (fix #1096220).
+
 * Mon Apr 07 2014 Matěj Cepl <mcepl at redhat.com> - 1.2.3-12
 - Add python-setuptools dependency (fix #1084996)
 


More information about the scm-commits mailing list