Add features to strings with s()

ww contains convenient wrappers around strings. The Most important one is StringWrapper, that you will mostly use as the “s()” object.

It behaves like unicode strings (the API is compatible), but make small improvements to the existing methods and add some new methods.

It doesn’t accept bytes as an input. If you do so and it works, you must know it’s not a supported behavior and may change in the future. Only pass:

  • unicode objects in Python 2;
  • str objects in Python 3.

Example

Import:

>>> from ww import s

You always have the more explicit import at your disposal:

>>> from ww.wrappers.strings import StringWrapper

s is just an alias of StringWrapper, but it’s what most people will want to use most of the time. Hence it’s what we will use in the examples.

Basic usages:

>>> string = s("this is a test")
>>> string
u'this is a test'
>>> type(string)
<class 'ww.wrappers.strings.StringWrapper'>
>>> string.upper() # regular string methods are all there
u'THIS IS A TEST'
>>> string[:4] + "foo" # same behaviors you expect from a string
u'thisfoo'

Some existing methods, while still compatible with the previous behavior, have been improved:

>>> string.replace('e', 'a') # just as before
u'this is a tast'
>>> string.replace(('e', 'i'), ('a', 'o')) # and a little more
u'thos os a tast'
>>> s('-').join(range(10))  # join() autocast to string
u'0-1-2-3-4-5-6-7-8-9'
>>> s('-').join(range(10), template="{:.2f}")
u'0.00-1.00-2.00-3.00-4.00-5.00-6.00-7.00-8.00-9.00'

Some methods have been added:

>>> print(s('''
... This should be over indented.
... But it will not be.
... Because dedent() calls textwrap.dedent() on the string.
... ''').dedent())

This should be over indented.
But it will not be.
Because dedent() calls textwrap.dedent() on the string.

By overriding operators, we can provide some interesting syntaxic sugar, such as this shortcut for writting long dedented text:

>>> print(s >> '''
... Calling dedent() is overrated.
... Overriding __rshift__ is much more fun.
... ''')

Calling dedent() is overrated.
Overriding __rshift__ is much more fun.

Also we hacked something that looks like Python 3.6 f-string, but that works in Python 2.7 and 3.3+:

>>> from ww import f
>>> a = 1
>>> f('Sweet, I can print locals: {a}')
u'Sweet, I can print locals: 1'
>>> print(f >> '''
... Yes it works with long string too.
... And globals, if you are into that kind
... of things.
... But we have only {a} for now.
... ''')

Yes it works with long string too.
And globals, if you are into that kind
of things.
But we have only 1 for now.

Warning

Remember that, while f-strings are interpreted at parsing time, our implementation is executed at run-time, making it vulnerable to code injection. This makes it a dangerous feature to put in production.

There is much, much more to play with. Check it out :)

You’ll find bellow the detailed documentation for each method of StringWrapper. Go have a look, there is some great stuff here!

class ww.wrappers.strings.StringWrapper[source]

Convenience wrappers around strings behaving like unicode strings, but make small improvements to the existing methods and add some new methods.

It doesn’t accept bytes as an input. If you do so and it works, you must know it’s not a supported behavior and may change in the future. Only pass:

  • unicode objects in Python 2;
  • str objects in Python 3.

Basic usages:

>>> from ww import s
>>> string = s("this is a test")
>>> string
u'this is a test'
>>> type(string)
<class 'ww.wrappers.strings.StringWrapper'>
>>> string.upper() # regular string methods are all there
u'THIS IS A TEST'
>>> string[:4] + "foo" # same behaviors you expect from a string
u'thisfoo'
>>> string.split(u'a', u'i', u'e')  # lots of features are improved
<IterableWrapper generator>
>>> string.split(u'a', u'i', u'e').list()
[u'th', u's ', u's a t', u'st']
__add__(other)[source]

Concatenate the 2 strings, but wraps it in s().

Parameters:other – The other string to concatenate with the current one.
Raises:TypeError – raised one of the concatenated objects is not a string.
Returns:The concatenated string wrapped in StringWrapper.

Example

>>> from ww import s
>>> s(u'a') + u'b'
u'ab'
>>> type(s(u'a') + u'b')
<class 'ww.wrappers.strings.StringWrapper'>
__getitem__(index)[source]

Make indexing/slicing return s() objects.

Returns:

The result of the indexing/slicing, wrapped in StringWrapper

Raises:
  • IndexError – if the index if greater than the string length.
  • TypeError – if the index is not an integer.

Example

>>> from ww import s
>>> s('Foo')[0]
u'F'
>>> type(s('Foo')[0])
<class 'ww.wrappers.strings.StringWrapper'>
__radd__(other)[source]

Concatenate the 2 strings, s() being on the right of the equation.

Parameters:other – The other string to concatenate with the current one.
Raises:TypeError – raised one of the concatenated objects is not a string.
Returns:The concatenated string wrapped in StringWrapper.

Example

>>> from ww import s
>>> u'b' + s(u'a')
u'ba'
>>> type(u'b' + s(u'a'))
<class 'ww.wrappers.strings.StringWrapper'>
__repr__()[source]

Strings repr always prefixeds with ‘u’ even in Python 3

__weakref__

list of weak references to the object (if defined)

dedent()[source]

Call texwrap.dedent() on the string, removing useless indentation

Returns:The strings without indentation and wrapped with StringWrapper.

Example

>>> from ww import s
>>> print(s('''
...     This should be indented
...     but it will not be
... ''').dedent())

This should be indented
but it will not be
format(*args, **kwargs)[source]

Like str.format(), with f-string features. Returns StringWrapper

s().format() is like str.format() (or unicode.format() in Python 2.7), but returns a StringWrapper.

However, if you don’t pass any argument to it, it will act like f-strings, and look for the variables from the current local context to fill in the markers.

Parameters:
  • *args – elements used to replace {} markers.
  • **kwargs – named element used to replace {name} markers.
Returns:

The formatted string, wrapped in StringWrapper

Example

>>> from ww import s
>>> print(s('Dis ize me, {} !').format('Mario'))
Dis ize me, Mario !
>>> name = 'Mario'
>>> print(s('Dis ize me, {name} !').format())
Dis ize me, Mario !
classmethod from_bytes(byte_string, encoding=None, errors='strict')[source]

Convenience proxy to byte.decode().

This let you decode bytes from the StringWrapper class the same way you would decode it from the bytes class, and wraps the result in StringWrapper.

Parameters:
  • byte_string – encoded text you wish to decode.
  • encoding – the name of the character set you want to use to attempt decoding.
  • errors – the policy to use when encountering error while trying to decode the text. ‘strict’, the default, will raise an exception. ‘ignore’ will skip the faulty bits. ‘replace’ will replace them with ‘?’.
Returns:

The decoded strings wrapped in StringWrapper.

Example

>>> from ww import s
>>> utf8_text = u'Père Noël'.encode('utf8')
>>> print(s.from_bytes(utf8_text, 'utf8'))
Père Noël
>>> type(s.from_bytes(utf8_text, 'utf8'))
<class 'ww.wrappers.strings.StringWrapper'>
>>> print(s.from_bytes(utf8_text, 'ascii', 'replace'))
P��re No��l
>>> print(s.from_bytes(utf8_text, 'ascii', 'ignore'))
Pre Nol
join(iterable, formatter=<function StringWrapper.<lambda>>, template='{}')[source]

Join every item of the iterable into a string.

This is just like the join() method on str() but with auto cast to a string. If you dislike auto cast, formatter and template let you control how to format each element.

Parameters:
  • iterable – the iterable with elements you wish to join.
  • formatter

    a the callable returning a representation of the current element as a string. It will be called on each element, with the element being past as the first parameter and the value of template as the second parameter. The default value is to return:

    template.format(element)
    
  • template

    a string template using the .format() syntax to be used by the formatter callable. The default value is “{}”, so that the formatter can just return:

    "{}".format(element)
    
Returns:

The joined elements as StringWrapper

Example

>>> from ww import s
>>> s('|').join(range(3))
u'0|1|2'
>>> to_string = lambda s, t: str(s) * s
>>> print(s(',').join(range(1, 4), formatter=to_string))
1,22,333
>>> print(s('\n').join(range(3), template='- {}'))
- 0
- 1
- 2
replace(patterns, substitutions, maxreplace=0, flags=0)[source]

Like unicode.replace() but accept several substitutions and regexes

Parameters:
  • patterns – a string, or an iterable of strings to be replaced.
  • substitutions – a string or an iterable of string to use as a replacement. You can pass either one string, or an iterable containing the same number of sustitutions that you passed as patterns. You can also pass a callable instead of a string. It should expact a match object as a parameter.
  • maxreplace – the max number of replacement to make. 0 is no limit, which is the default.
  • flags

    flags you wish to pass if you use regexes. You should pass them as a string containing a combination of:

    • ‘m’ for re.MULTILINE
    • ‘x’ for re.VERBOSE
    • ‘v’ for re.VERBOSE
    • ‘s’ for re.DOTALL
    • ‘.’ for re.DOTALL
    • ‘d’ for re.DEBUG
    • ‘i’ for re.IGNORECASE
    • ‘u’ for re.UNICODE
    • ‘l’ for re.LOCALE
Returns:

The string with replaced bits, wrapped with StringWrapper.

Raises:

ValueError – if you pass the wrong number of substitution.

Example

>>> from __future__ import unicode_literals
>>> from ww import s
>>> s('a,b;c/d').replace((',', ';', '/'), ',')
u'a,b,c,d'
>>> s('a1b33c-d').replace('\d+', ',')
u'a,b,c-d'
>>> s('a-1,b-3,3c-d').replace('[,-]', '', maxreplace=3)
u'a1b3,3c-d'
>>> def upper(match):
...     return match.group().upper()
...
>>> s('a-1,b-3,3c-d').replace('[ab]', upper)
u'A-1,B-3,3c-d'
split(*separators, **kwargs)[source]

Like unicode.split, but accept several separators and regexes

Parameters:
  • separators – strings you can split on. Each string can be a regex.
  • maxsplit – max number of time you wish to split. default is 0, which means no limit.
  • flags

    flags you wish to pass if you use regexes. You should pass them as a string containing a combination of:

    • ‘m’ for re.MULTILINE
    • ‘x’ for re.VERBOSE
    • ‘v’ for re.VERBOSE
    • ‘s’ for re.DOTALL
    • ‘.’ for re.DOTALL
    • ‘d’ for re.DEBUG
    • ‘i’ for re.IGNORECASE
    • ‘u’ for re.UNICODE
    • ‘l’ for re.LOCALE
Returns:

An iterable of substrings.

Raises:
  • ValueError – if you pass a flag without separators.
  • TypeError – if you pass something else than unicode strings.

Example

>>> from ww import s
>>> string = s(u'fat     black cat, big bad dog')
>>> string.split().list()
[u'fat', u'black', u'cat,', u'big', u'bad', u'dog']
>>> string = s(u'a,b;c/d=a,b;c/d')
>>> string.split(u',', u';', u'[/=]', maxsplit=4).list()
[u'a', u'b', u'c', u'd', u'a,b;c/d']
to_bool(default=None)[source]

Take a string with a binary meaning, and turn it into a boolean.

The following strings will be converted:

  • ‘1’ => True,
  • ‘0’ => False,
  • ‘true’ => True,
  • ‘false’ => False,
  • ‘on’ => True,
  • ‘off’ => False,
  • ‘yes’ => True,
  • ‘no’ => False,
  • ‘’ => False
Parameters:default – the value to return if the string can’t be converted.
Returns:A boolean matching the meaning of the string.

Example

>>> from ww import s
>>> s('true').to_bool()
True
>>> s('Off').to_bool()
False
upper()[source]

Call str.upper() on the string, making it uppercase.

Returns:The upper cased string, wrapped in StringWrapper.

Example

>>> from ww import s
>>> print(s('Foo').upper())
FOO
>>> type(s('Foo').upper())
<class 'ww.wrappers.strings.StringWrapper'>

Most of those features are just wrappers around pure functions. We exposed them in “Functional tools for strings” in case you want to use them directly on regular Python strings.