Coverage for lino/utils/__init__.py : 82%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# -*- coding: UTF-8 -*- # Copyright 2009-2016 Luc Saffre # License: BSD (see file COPYING for details)
function for general use. It has also many subpackages and submodules.
This is a tested document. To test it, run::
$ python setup.py test -s tests.DocsTests.test_utils
.. autosummary:: :toctree:
addressable ajax appy_pod choosers code config demonames daemoncommand dataserializer dbfreader dblogger diag djangotest dpy editing html2odf html2text html2xhtml mytidylib htmlgen instantiator jinja jscompressor jsgen latex log mdbtools media memo mldbc mti odsreader pythontest pyuca quantities ranges requests restify screenshots sendchanges sqllog ssin test textfields ucsv xmlgen
>>> from __future__ import print_function >>> from __future__ import unicode_literals >>> from lino.utils import * >>> from builtins import chr >>> from builtins import hex >>> from builtins import next >>> from builtins import map >>> from builtins import str >>> from builtins import range >>> from builtins import object
:func:`str2hex` and :func:`hex2str` -----------------------------------
>>> str2hex('-L') '2d4c'
>>> hex2str('2d4c') '-L'
>>> hex2str('') '' >>> str2hex('') ''
:func:`join_words` ------------------
>>> print (join_words('This','is','a','test')) This is a test
>>> print (join_words('This','is','','another','test')) This is another test
>>> print (join_words(None,None,None,'Third','test')) Third test
"""
#~ import logging #~ logger = logging.getLogger(__name__)
# encapsulate where they come from:
"Returns `True` if the specified object is iterable." try: iter(x) except TypeError: return False return True
""" Remove any empty item (None or ''), call unicode on each and join the remaining word using a single space. """
""" Examples: >>> join_elems([1, 2, 3]) [1, ' ', 2, ' ', 3] >>> join_elems([1, 2, 3],' / ') [1, ' / ', 2, ' / ', 3] >>> join_elems([]) []
"""
"Supports also dates before 1900." return "%04d-%02d-%02d" % (d.year, d.month, d.day)
return value
""" Doesn't work. See `20110914`. """ s = super(cls, self) m = getattr(s, 'name', None) if m is not None: return m(*args, **kw)
""" Doesn't work. See `20110914`. This is necessary because we want to call `setup_report` on the model and all base classes of the model. We cannot use super() for this because the `setup_report` method is optional. """ for b in cls.__bases__: call_on_bases(b, name, *args, **kw) if True: m = getattr(cls, name, None) # getattr will also return the classmethod defined on a base class, # which has already been called. if m is not None and m.__self__.__class__ is cls: m(cls, *args, **kw)
"""Note: the following algorithm worked in Python 2.7 but not in 2.6, a classmethod object in 2.6 has no attribute `im_func` """
#~ m = cls.__dict__.get(name) #~ if m: #~ func = getattr(m,'im_func',None) #~ if func is None: #~ raise Exception("Oops, %r in %s (%r) has no im_func" % (name,cls,m)) #~ func(cls,*args,**kw) # ~ # m.__func__(cls,*args,**kw)
"""Convert a string to its hexadecimal representation."""
"""Convert the hexadecimal representation of a string to the original string.""" raise Exception("hex2str got value %r" % value)
# http://snippets.dzone.com/posts/show/2375 lambda *p, **n:\ func(*args + p, **dict(list(kw.items()) + list(n.items())))
""" Naive representation of a potentially incomplete gregorian date.
Once upon a time in the year 2011: >>> print (IncompleteDate(2011, 0, 0).strftime("%d.%m.%Y")) 00.00.2011
>>> print (IncompleteDate(1532, 0, 0)) 1532-00-00 >>> print (IncompleteDate(1990, 0, 1)) 1990-00-01 >>> print (IncompleteDate(0, 6, 1)) 0000-06-01
W.A. Mozart's birth date:
>>> print (IncompleteDate(1756, 1, 27)) 1756-01-27
Christ's birth date:
>>> print (IncompleteDate(-7, 12, 25)) -7-12-25 >>> print (IncompleteDate(-7, 12, 25).strftime("%d.%m.%Y")) 25.12.-7
Note that you cannot convert all incomplete dates to real datetime.date objects:
>>> IncompleteDate(-7, 12, 25).as_date() Traceback (most recent call last): ... ValueError: year is out of range
>>> IncompleteDate(1756, 1, 27).as_date() datetime.date(1756, 1, 27)
An IncompleteDate is allowed to be complete:
>>> d = IncompleteDate.parse('2011-11-19') >>> print (d) 2011-11-19 >>> d.is_complete() True >>> print (repr(d.as_date())) datetime.date(2011, 11, 19)
>>> d = IncompleteDate.parse('2008-03-24') >>> d.get_age(i2d(20131224)) 5 >>> d.get_age(i2d(20140323)) 5 >>> d.get_age(i2d(20140324)) 6 >>> d.get_age(i2d(20140325)) 6 >>> d.get_age(i2d(20141025)) 6
Note that IncompleteDate can store invalid dates:
>>> d = IncompleteDate(2009, 2, 30) >>> d.get_age(i2d(20160202)) 6
>>> IncompleteDate(2009, 2, 32) IncompleteDate('2009-02-32')
>>> IncompleteDate(2009, 32, 123) IncompleteDate('2009-32-123')
"""
def parse(cls, s): bc = True s = s[1:] else: y = - y
def from_date(cls, date): return cls(date.year, date.month, date.day)
return False
return str(self) == str(other)
return str(self) != str(other)
return len(str(self))
#~ s = fmt.replace("%Y",iif(self.bc,'-','')+str(self.year)) else: # year might be negative
self.year or 1900, self.month or 6, self.day or 15)
"Return age in years as integer."
#~ class Warning(Exception): #~ """ #~ An Exception whose message is meant to be #~ understandable by the user. #~ """
# unmodified copy from http://docs.python.org/library/decimal.html#recipes pos='', neg='-', trailneg=''): """ Convert Decimal to a money formatted string.
| places: required number of places after the decimal point | curr: optional currency symbol before the sign (may be blank) | sep: optional grouping separator (comma, period, space, or blank) | dp: decimal point indicator (comma or period) | only specify as blank when places is zero | pos: optional sign for positive numbers: '+', space or blank | neg: optional sign for negative numbers: '-', '(', space or blank | trailneg: optional trailing minus indicator: '-', ')', space or blank
>>> d = Decimal('-1234567.8901') >>> print(moneyfmt(d, curr='$')) -$1,234,567.89 >>> print(moneyfmt(d, places=0, sep='.', dp='', neg='', trailneg='-')) 1.234.568- >>> print(moneyfmt(d, curr='$', neg='(', trailneg=')')) ($1,234,567.89) >>> print(moneyfmt(Decimal(123456789), sep=' ')) 123 456 789.00 >>> print(moneyfmt(Decimal('-0.02'), neg='<', trailneg='>')) <0.02>
"""
""" When we want unicode strings (e.g. translated exception messages) to appear in an Exception, we must first encode them using a non-strict errorhandler. Because the message of an Exception may not be a unicode string.
""" return str(x).encode(sys.getdefaultencoding(), 'backslashreplace') # Python 2.6.6 said "Error in formatting: encode() takes no keyword arguments" #~ return unicode(x).encode(errors='backslashreplace')
""" Return the number of workdays (Monday to Friday) between the given two dates. Is not aware of holidays.
Both dates start and end are included. For example if you specify a Monday as start and Monday of the following week as end, then you get 6 (not 5).
Examples: >>> examples = [ ... (20121130,20121201,1), ... (20121130,20121224,17), ... (20121130,20121130,1), ... (20121201,20121201,0), ... (20121201,20121202,0), ... (20121201,20121203,1), ... (20121130,20121207,6), ... ] >>> for start,end,expected in examples: ... a = i2d(start) ... b = i2d(end) ... if workdays(a,b) != expected: ... print ("Got %d instead of %d for (%s,%s)" % (workdays(a,b),expected,a,b))
""" #~ for d in range(start,end,ONE_DAY): #~ if d.isoweekday() <= 5: #~ n += 1
""" >>> camelize("ABC DEF") 'Abc Def' >>> camelize("ABC def") 'Abc def' >>> camelize("eID") 'eID'
"""
"""
Thanks to `nickl <http://stackoverflow.com/users/1522117/nickl>`_ in `Stackoverflow <http://stackoverflow.com/questions/1175208>`_
>>> from lino.utils import uncamel >>> uncamel('EventsByClient') 'events_by_client' >>> uncamel('Events') 'events' >>> uncamel('HTTPResponseCodeXYZ') 'http_response_code_xyz'
"""
"""A simplistic replacement for the `puts` function of `clint` which has the problem of not supporting `unicode strings <https://github.com/kennethreitz/clint/issues/48>`__.
This method is meant for issuing to the interactive console messages which do not need to be logged because they just give information about what's going on.
Currently this just prints the string to stdout using ``print``. I prefer to use this over a plain ``print`` statement because I guess that there will be problems (mainly thinking about the fact that writing to stdout is considered an error in a wsgi application).
""" # if isinstance(s, unicode): # print s.encode(locale.getpreferredencoding()) print(s)
"""A dictionary of sums to be collected using an arbitrary key.
Usage examples:
>>> sc = SumCollector() >>> sc.collect("a", 12) >>> sc.collect("a", None) >>> sc.collect("a", 5) >>> sc.a 17
>>> sc = SumCollector() >>> sc.collect("a", 12) >>> sc.collect("b", 23) >>> sc.collect("a", 34) >>> from future.utils import iteritems >>> sorted(list(iteritems(sc))) [('a', 46), ('b', 23)]
This is also included in the default context used by the Jinja renderer (:mod:`lino.modlib.jinja`) when rendering templates, which makes it a more complete solution for a problem asked also elsewhere, e.g. on `Stackoverflow <http://stackoverflow.com/questions/7537439/how-to-increment-a-variable-on-a-for-loop-in-jinja-template>`__.
"""
"""This returns an empty string """ else:
return str(self._sums)
return repr(self._sums)
import doctest doctest.testmod()
_test() |