base

This module defines base classes for python-textops3

activate_debug

textops.activate_debug()

Activate debug logging on console

This function is useful when playing with python-textops3 through a python console. It is not recommended to use this function in a real application : use standard logging functions instead.

add_textop

textops.add_textop(class_or_func)

Decorator to declare custom function or custom class as a new textops op

the custom function/class will receive the whole raw input text at once.

Examples

>>> @add_textop
... def repeat(text, n, *args,**kwargs):
...     return text * n
>>> 'hello' | repeat(3)
'hellohellohello'
>>> @add_textop
... class cool(TextOp):
...     @classmethod
...     def op(cls, text, *args,**kwargs):
...         return text + ' is cool.'
>>> 'textops' | cool()
'textops is cool.'

add_textop_iter

textops.add_textop_iter(func)

Decorator to declare custom ITER function as a new textops op

An ITER function is a function that will receive the input text as a LIST of lines. One have to iterate over this list and generate a result (it can be a list, a generator, a dict, a string, an int …)

Examples

>>> @add_textop_iter
... def odd(lines, *args,**kwargs):
...     for i,line in enumerate(lines):
...         if not i % 2:
...             yield line
>>> s = '''line 1
... line 2
... line 3'''
>>> s >> odd()
['line 1', 'line 3']
>>> s | odd().tolist()
['line 1', 'line 3']
>>> @add_textop_iter
... def sumsize(lines, *args,**kwargs):
...     sum = 0
...     for line in lines:
...         sum += int(re.search(r'\d+',line).group(0))
...     return sum
>>> '''1492 file1
... 1789 file2
... 2015 file3''' | sumsize()
5296

dictmerge

textops.dictmerge(*dict_args)

Merge as many dicts you want

Given any number of dicts, shallow copy and merge into a new dict, precedence goes to key value pairs in latter dicts.

Parameters:*dict_args (dict) – List of dicts
Returns:a new merged dict
Return type:dict

Examples

>>> dictmerge({'a':1,'b':2},{'b':3,'c':4})
{'a': 1, 'b': 3, 'c': 4}

dformat

textops.dformat(format_str, dct, defvalue='-')

Formats a dictionary, manages unkown keys

It works like string.Formatter.vformat() except that it accepts only a dict for values and a defvalue for not matching keys. Defvalue can be a callable that will receive the requested key as argument and return a string

Parameters:
  • format_string (str) – Same format string as for str.format()
  • dct (dict) – the dict to format
  • defvalue (str or callable) – the default value to display when the data is not in the dict

Examples

>>> d = {'count': '32591', 'soft': 'textops'}
>>> dformat('{soft} : {count} dowloads',d)
'textops : 32591 dowloads'
>>> dformat('{software} : {count} dowloads',d,'N/A')
'N/A : 32591 dowloads'
>>> dformat('{software} : {count} dowloads',d,lambda k:'unknown_tag_%s' % k)
'unknown_tag_software : 32591 dowloads'

eformat

textops.eformat(format_str, lst, dct, defvalue='-')

Formats a list and a dictionary, manages unkown keys

It works like string.Formatter.vformat() except that it accepts a defvalue for not matching keys. Defvalue can be a callable that will receive the requested key as argument and return a string

Parameters:
  • format_string (str) – Same format string as for str.format()
  • lst (dict) – the list to format
  • dct (dict) – the dict to format
  • defvalue (str or callable) – the default value to display when the data is not in the dict

Examples

>>> d = {'count': '32591', 'soft': 'textops'}
>>> l = ['Eric','Guido']
>>> eformat('{0} => {soft} : {count} dowloads',l,d)
'Eric => textops : 32591 dowloads'
>>> eformat('{2} => {software} : {count} dowloads',l,d,'N/A')
'N/A => N/A : 32591 dowloads'
>>> eformat('{2} => {software} : {count} dowloads',l,d,lambda k:'unknown_tag_%s' % k)
'unknown_tag_2 => unknown_tag_software : 32591 dowloads'

vformat

DictExt

class textops.DictExt(*args, **kwargs)

Extend dict class with new features

New features are :

  • Access to textops operations with attribute notation
  • All dict values (dict, list, str, bytes) are extended on-the-fly when accessed
  • Access to dict values with attribute notation
  • Add a key:value in the dict with attribute notation (one level at a time)
  • Returns NoAttr object when a key is not in the Dict
  • add modification on-the-fly amend() and rendering to string render()

Note

NoAttr is a special object that returns always NoAttr when accessing to any attribute. it behaves like False for testing, [] in foor-loops. The goal is to be able to use very long expression with dotted notation without being afraid to get an exception.

Examples

>>> {'a':1,'b':2}.items().grep('a')
Traceback (most recent call last):
    ...
AttributeError: 'dict_items' object has no attribute 'grep'
>>> DictExt({'a':1,'b':2}).items().grep('a')
[('a', 1)]
>>> d = DictExt({ 'this' : { 'is' : { 'a' : {'very deep' : { 'dict' : 'yes it is'}}}}})
>>> print(d.this['is'].a['very deep'].dict)
yes it is
>>> d.not_a_valid_key
NoAttr
>>> d['not_a_valid_key']
NoAttr
>>> d.not_a_valid_key.and_i.can.put.things.after.without.exception
NoAttr
>>> for obj in d.not_a_valid_key.objects:
...     do_things(obj)
... else:
...     print('no object')
no object
>>> d = DictExt()
>>> d.a = DictExt()
>>> d.a.b = 'this is my logging data'
>>> print(d)
{'a': {'b': 'this is my logging data'}}
>>> d = { 'mykey' : 'myval' }
>>> d['mykey']
'myval'
>>> type(d['mykey'])
<class 'str'>
>>> d = DictExt(d)
>>> d['mykey']
'myval'
>>> type(d['mykey'])
<class 'textops.base.StrExt'>
>>> d=DictExt()
>>> d[0]=[]
>>> d
{0: []}
>>> d[0].append(3)
>>> d
{0: [3]}
>>> type(d[0])
<class 'textops.base.ListExt'>
amend(*args, **kwargs)

Modify on-the-fly a dictionary

The method will generate a new extended dictionary and update it with given params

Examples

>>> s = '''soft:textops
... count:32591'''
>>> s | parse_indented()
{'soft': 'textops', 'count': '32591'}
>>> s | parse_indented().amend(date='2015-11-19')
{'soft': 'textops', 'count': '32591', 'date': '2015-11-19'}
as_list

Convert to ListExt object

render(format_string, defvalue='-')

Render a DictExt as a string

It uses the fonction dformat() to format the dictionary

Parameters:
  • format_string (str) – Same format string as for str.format()
  • defvalue (str or callable) – the default value to display when the data is not in the dict

Examples

>>> d = DictExt({'count': '32591', 'date': '2015-11-19', 'soft': 'textops'})
>>> d.render('On {date}, "{soft}" has been downloaded {count} times')
'On 2015-11-19, "textops" has been downloaded 32591 times'
>>> d.render('On {date}, "{not_in_dict}" has been downloaded {count} times','?')
'On 2015-11-19, "?" has been downloaded 32591 times'

ListExt

class textops.ListExt

Extend list class to gain access to textops as attributes

In addition, all list items (dict, list, str, bytes) are extended on-the-fly when accessed

Examples

>>> ['normal','list'].grep('t')
Traceback (most recent call last):
    ...
AttributeError: 'list' object has no attribute 'grep'
>>> ListExt(['extended','list']).grep('t')
['extended', 'list']
as_list

Convert to ListExt object

StrExt

class textops.StrExt

Extend str class to gain access to textops as attributes

Examples

>>> 'normal string'.cut()
Traceback (most recent call last):
    ...
AttributeError: 'str' object has no attribute 'cut'
>>> StrExt('extended string').cut()
['extended', 'string']
as_list

Convert to ListExt object

TextOp

class textops.TextOp(*args, **kwargs)

Base class for text operations

All operations must be derived from this class. Subclasses must redefine an op() method that will be called when the operations will be triggered by an input text.

f

Execute operations, returns a float.

Examples

>>> echo('1789').f
1789.0
>>> echo('3.14').f
3.14
>>> echo('Tea for 2').f
0.0
g

Execute operations, return a generator when possible or a list otherwise

This is to be used ONLY when the input text has be set as the first argument of the first operation.

Examples

>>> echo('hello')
echo('hello')
>>> echo('hello').g
['hello']
>>> def mygen(): yield 'hello'
>>> cut(mygen(),'l')                                # doctest: +ELLIPSIS
cut(<generator object mygen at ...>,'l')
>>> cut(mygen(),'l').g                              # doctest: +ELLIPSIS
<generator object extend_type_gen at ...>
>>> def mygen(): yield None
>>> type(echo(None).g)                              # doctest: +ELLIPSIS
<class 'NoneType'>
ge

Execute operations, return a generator when possible or a list otherwise, ( [] if the result is None ).

This works like g except it returns an empty list if the execution result is None.

Examples

>>> echo(None).ge                                    # doctest: +ELLIPSIS
[]
i

Execute operations, returns an int.

Examples

>>> echo('1789').i
1789
>>> echo('3.14').i
3
>>> echo('Tea for 2').i
0
j

Execute operations, return a string (join = ‘’)

This works like s except that joins will be done with an empty string

Examples

>>> echo(['hello','world']).j
'helloworld'
>>> type(echo(None).j)
<class 'NoneType'>
je

Execute operations, returns a string ( ‘’ if the result is None, join=’’).

This works like j except it returns an empty string if the execution result is None.

Examples

>>> echo(None).je
''
l

Execute operations, return a list

This is to be used ONLY when the input text has be set as the first argument of the first operation.

Examples

>>> echo('hello')
echo('hello')
>>> echo('hello').l
['hello']
>>> type(echo(None).g)
<class 'NoneType'>
le

Execute operations, returns a list ( [] if the result is None ).

This works like l except it returns an empty list if the execution result is None.

Examples

>>> echo(None).le
[]
n

Execute operations, do not convert, do not return anything

If _process() returns a generator, it is consumed

Examples

>>> echo('1789').length().n
classmethod op(text, *args, **kwargs)

This method must be overriden in derived classes

pp

Execute operations, return Prettyprint version of the result

Examples:

>>> s = '''
... a:val1
... b:
...     c:val3
...     d:
...         e ... : val5
...         f ... :val6
...     g:val7
... f: val8'''
>>> print(parse_indented(s).r)
{'a': 'val1', 'b': {'c': 'val3', 'd': {'e': 'val5', 'f': 'val6'}, 'g': 'val7'}, 'f': 'val8'}
>>> print(parse_indented(s).pp)
{   'a': 'val1',
    'b': {'c': 'val3', 'd': {'e': 'val5', 'f': 'val6'}, 'g': 'val7'},
    'f': 'val8'}
r

Execute operations, do not convert.

Examples

>>> echo('1789').length().l
[4]
>>> echo('1789').length().s
'4'
>>> echo('1789').length().r
4
s

Execute operations, return a string (join = newline)

This is to be used ONLY when the input text has be set as the first argument of the first operation. If the result is a list or a generator, it is converted into a string by joinning items with a newline.

Examples

>>> echo('hello')
echo('hello')
>>> echo('hello').s
'hello'
>>> echo(['hello','world']).s
'hello\nworld'
>>> type(echo(None).s)
<class 'NoneType'>
se

Execute operations, returns a string ( ‘’ if the result is None ).

This works like s except it returns an empty string if the execution result is None.

Examples

>>> echo(None).se
''

BytesExt

class textops.BytesExt

Extend bytes class to gain access to textops as attributes

Examples

>>> b'normal bytes'.cut()
Traceback (most recent call last):
    ...
AttributeError: 'bytes' object has no attribute 'cut'
>>> BytesExt(b'extended bytes').cut()
[b'extended', b'bytes']
as_list

Convert to ListExt object