[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