Browse files

Compatible with Python 2.4.

  • Loading branch information...
1 parent 8c97e6d commit a58ca4c3ee470a5fda1ac7aea6175667668135d5 @florentx committed Sep 22, 2010
Showing with 87 additions and 30 deletions.
  1. +3 −2 README
  2. +6 −5 setup.py
  3. +37 −10 stringformat.py
  4. +36 −9 stringformat_lite.py
  5. +5 −4 tests.py
View
5 README
@@ -1,8 +1,9 @@
StringFormat
============
-StringFormat is an independent port of the Python 3 advanced string formatting
-to Python 2.5. This implementation is pure Python.
+StringFormat is an independent port of the Python 3 advanced string
+formatting, compatible with Python 2.4 through 2.7.
+This implementation is pure Python.
The advanced string formatting is officially included in the language
View
11 setup.py
@@ -1,10 +1,11 @@
# -*- coding: utf-8 -*-
"""
StringFormat
-------------
+============
-StringFormat is an independent port of the Python 3 advanced string formatting
-to Python 2.5. This implementation is pure Python.
+StringFormat is an independent port of the Python 3 advanced string
+formatting, compatible with Python 2.4 through 2.7.
+This implementation is pure Python.
The advanced string formatting is officially included in the language
@@ -19,12 +20,12 @@
setup(
name='StringFormat',
- version='0.2',
+ version='0.3',
license='BSD',
url='http://github.com/florentx/stringformat',
author='Florent Xicluna',
author_email='florent.xicluna@gmail.com',
- description='Advanced String Formatting for Python >= 2.5',
+ description='Advanced String Formatting for Python >= 2.4',
long_description=__doc__,
classifiers=[
'Development Status :: 5 - Production/Stable',
View
47 stringformat.py
@@ -1,13 +1,24 @@
# -*- coding: utf-8 -*-
-"""String formatting for Python 2.5.
+"""Advanced string formatting for Python >= 2.4.
-This is an implementation of the advanced string formatting (PEP 3101).
+An implementation of the advanced string formatting (PEP 3101).
Author: Florent Xicluna
"""
import re
+if hasattr(str, 'partition'):
+ def partition(s, sep):
+ return s.partition(sep)
+else: # Python 2.4
+ def partition(s, sep):
+ try:
+ left, right = s.split(sep, 1)
+ except ValueError:
+ return s, '', ''
+ return left, sep, right
+
_format_str_re = re.compile(
r'((?<!{)(?:{{)+' # '{{'
r'|(?:}})+(?!})' # '}}
@@ -27,6 +38,22 @@
r'(?(1)(?:\]|$)([^.[]+)?)' # ']' and invalid tail
)
+if hasattr(re, '__version__'):
+ _format_str_sub = _format_str_re.sub
+else:
+ # Python 2.4 fails to preserve the Unicode type
+ def _format_str_sub(repl, s):
+ if isinstance(s, unicode):
+ return unicode(_format_str_re.sub(repl, s))
+ return _format_str_re.sub(repl, s)
+
+if hasattr(int, '__index__'):
+ def _is_integer(value):
+ return hasattr(value, '__index__')
+else: # Python 2.4
+ def _is_integer(value):
+ return isinstance(value, (int, long))
+
def _strformat(value, format_spec=""):
"""Internal string formatter.
@@ -38,13 +65,13 @@ def _strformat(value, format_spec=""):
raise ValueError('Invalid conversion specification')
align, sign, prefix, width, comma, precision, conversion = m.groups()
is_numeric = hasattr(value, '__float__')
- is_integer = is_numeric and hasattr(value, '__index__')
+ is_integer = is_numeric and _is_integer(value)
if prefix and not is_integer:
raise ValueError('Alternate form (#) not allowed in %s format '
- 'specifier' % ('float' if is_numeric else 'string'))
+ 'specifier' % (is_numeric and 'float' or 'string'))
if is_numeric and conversion == 'n':
# Default to 'd' for ints and 'g' for floats
- conversion = 'd' if is_integer else 'g'
+ conversion = is_integer and 'd' or 'g'
elif sign:
if not is_numeric:
raise ValueError("Sign not allowed in string format specifier")
@@ -82,7 +109,7 @@ def _strformat(value, format_spec=""):
return rv
fill, align = align[:-1], align[-1:]
if not fill:
- fill = '0' if zero else ' '
+ fill = zero and '0' or ' '
if align == '^':
padding = width - len(rv)
# tweak the formatting if the padding is odd
@@ -116,7 +143,7 @@ def _format_field(value, parts, conv, spec, want_bytes=False):
else:
value = getattr(value, part)
if conv:
- value = ('%r' if (conv == 'r') else '%s') % (value,)
+ value = ((conv == 'r') and '%r' or '%s') % (value,)
if hasattr(value, '__format__'):
value = value.__format__(spec)
elif hasattr(value, 'strftime') and spec:
@@ -147,7 +174,7 @@ def __init__(self, format_string):
self._nested = {}
self.format_string = format_string
- self._string = _format_str_re.sub(self._prepare, format_string)
+ self._string = _format_str_sub(self._prepare, format_string)
def __eq__(self, other):
if isinstance(other, FormattableString):
@@ -163,8 +190,8 @@ def _prepare(self, match):
assert part == part[0] * len(part)
return part[:len(part) // 2]
repl = part[1:-1]
- field, _, format_spec = repl.partition(':')
- literal, sep, conversion = field.partition('!')
+ field, _, format_spec = partition(repl, ':')
+ literal, sep, conversion = partition(field, '!')
if sep and not conversion:
raise ValueError("end of format while looking for "
"conversion specifier")
View
45 stringformat_lite.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
-"""String formatting for Python 2.5.
+"""Advanced string formatting for Python >= 2.4.
-This is an implementation of the advanced string formatting (PEP 3101).
+An implementation of the advanced string formatting (PEP 3101).
CAUTION: this module is a stripped version, without strict error checking.
@@ -10,6 +10,17 @@
import re
+if hasattr(str, 'partition'):
+ def partition(s, sep):
+ return s.partition(sep)
+else: # Python 2.4
+ def partition(s, sep):
+ try:
+ left, right = s.split(sep, 1)
+ except ValueError:
+ return s, '', ''
+ return left, sep, right
+
_format_str_re = re.compile(
r'((?<!{)(?:{{)+' # '{{'
r'|(?:}})+(?!})' # '}}
@@ -29,6 +40,22 @@
r'(?(1)(?:\]|$)([^.[]+)?)' # ']' and invalid tail
)
+if hasattr(re, '__version__'):
+ _format_str_sub = _format_str_re.sub
+else:
+ # Python 2.4 fails to preserve the Unicode type
+ def _format_str_sub(repl, s):
+ if isinstance(s, unicode):
+ return unicode(_format_str_re.sub(repl, s))
+ return _format_str_re.sub(repl, s)
+
+if hasattr(int, '__index__'):
+ def _is_integer(value):
+ return hasattr(value, '__index__')
+else: # Python 2.4
+ def _is_integer(value):
+ return isinstance(value, (int, long))
+
def _strformat(value, format_spec=""):
"""Internal string formatter.
@@ -40,10 +67,10 @@ def _strformat(value, format_spec=""):
raise ValueError('Invalid conversion specification')
align, sign, prefix, width, comma, precision, conversion = m.groups()
is_numeric = hasattr(value, '__float__')
- is_integer = is_numeric and hasattr(value, '__index__')
+ is_integer = is_numeric and _is_integer(value)
if is_numeric and conversion == 'n':
# Default to 'd' for ints and 'g' for floats
- conversion = 'd' if is_integer else 'g'
+ conversion = is_integer and 'd' or 'g'
if conversion == 'c':
conversion = 's'
value = chr(value % 256)
@@ -62,7 +89,7 @@ def _strformat(value, format_spec=""):
return rv
fill, align = align[:-1], align[-1:]
if not fill:
- fill = '0' if zero else ' '
+ fill = zero and '0' or ' '
if align == '^':
padding = width - len(rv)
# tweak the formatting if the padding is odd
@@ -93,7 +120,7 @@ def _format_field(value, parts, conv, spec):
else:
value = getattr(value, part)
if conv:
- value = ('%r' if (conv == 'r') else '%s') % (value,)
+ value = ((conv == 'r') and '%r' or '%s') % (value,)
if hasattr(value, '__format__'):
value = value.__format__(spec)
elif hasattr(value, 'strftime') and spec:
@@ -122,7 +149,7 @@ def __init__(self, format_string):
self._nested = {}
self.format_string = format_string
- self._string = _format_str_re.sub(self._prepare, format_string)
+ self._string = _format_str_sub(self._prepare, format_string)
def __eq__(self, other):
if isinstance(other, FormattableString):
@@ -138,8 +165,8 @@ def _prepare(self, match):
assert part == part[0] * len(part)
return part[:len(part) // 2]
repl = part[1:-1]
- field, _, format_spec = repl.partition(':')
- literal, sep, conversion = field.partition('!')
+ field, _, format_spec = partition(repl, ':')
+ literal, sep, conversion = partition(field, '!')
name_parts = _field_part_re.findall(literal)
if literal[:1] in '.[':
# Auto-numbering
View
9 tests.py
@@ -476,7 +476,7 @@ def _format_field(value, parts, conv, spec, want_bytes=False):
else:
value = getattr(value, part)
if conv:
- value = ('%r' if (conv == 'r') else '%s') % (value,)
+ value = ((conv == 'r') and '%r' or '%s') % (value,)
format_value = getattr(value, '__format__', None)
if format_value and (hasattr(value, 'strftime') or
not isinstance(format_value, builtin_function_or_method)):
@@ -497,9 +497,10 @@ def _format_field(value, parts, conv, spec, want_bytes=False):
except Exception, exc:
s1 = repr(exc)
try:
- s2 = repr(f(string).format(*args, **kwargs))
- except Exception, exc:
- s2 = repr(exc)
+ try:
+ s2 = repr(f(string).format(*args, **kwargs))
+ except Exception, exc:
+ s2 = repr(exc)
finally:
mod._format_field = original_format_field
return s1, s2

0 comments on commit a58ca4c

Please sign in to comment.