# HG changeset patch # User Thierry Florac # Date 1592909586 -7200 # Node ID 4504a27af426610bef45a550e09bfe7a57ac75e6 # Parent 7f256d281e84ad17ed05c79349b09b36810f0e5c Updated tests diff -r 7f256d281e84 -r 4504a27af426 src/pyams_utils/doctests/README.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_utils/doctests/README.rst Tue Jun 23 12:53:06 2020 +0200 @@ -0,0 +1,10 @@ +=================== +pyams_utils package +=================== + +Introduction +------------ + +This package is composed of a set of utility functions, usable into any Pyramid application. + +Associated files provide additional automated doctests. diff -r 7f256d281e84 -r 4504a27af426 src/pyams_utils/doctests/README.txt --- a/src/pyams_utils/doctests/README.txt Wed Nov 27 16:46:35 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -=================== -pyams_utils package -=================== - -Introduction ------------- - -This package is composed of a set of utility functions, usable into any Pyramid application. - -Associated files provide additional automated doctests. \ No newline at end of file diff -r 7f256d281e84 -r 4504a27af426 src/pyams_utils/doctests/dates.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_utils/doctests/dates.rst Tue Jun 23 12:53:06 2020 +0200 @@ -0,0 +1,59 @@ + +Dates functions +--------------- + +Dates functions are used to convert dates from/to string representation: + + >>> import pytz + >>> from datetime import datetime + >>> from pyams_utils import date + >>> gmt = pytz.timezone('GMT') + >>> now = datetime.fromtimestamp(1205000000, gmt) + >>> now + datetime.datetime(2008, 3, 8, 18, 13, 20, tzinfo=) + +You can get an unicode representation of a date in ASCII format using 'unidate' fonction ; date is +converted to GMT: + + >>> udate = date.unidate(now) + >>> udate + '2008-03-08T18:13:20+00:00' + +'parse_date' can be used to convert ASCII format into datetime: + + >>> ddate = date.parse_date(udate) + >>> ddate + datetime.datetime(2008, 3, 8, 18, 13, 20, tzinfo=) + +'date_to_datetime' can be used to convert a 'date' type to a 'datetime' value ; if a 'datetime' value +is used as argument, it is returned 'as is': + + >>> ddate.date() + datetime.date(2008, 3, 8) + >>> date.date_to_datetime(ddate) + datetime.datetime(2008, 3, 8, 18, 13, 20, tzinfo=) + >>> date.date_to_datetime(ddate.date()) + datetime.datetime(2008, 3, 8, 0, 0) + + +Timezones handling +------------------ + +Timezones handling gave me headaches at first. I finally concluded that the best way (for me !) to handle +TZ data was to store every datetime value in GMT timezone. +As far as I know, there is no easy way to know the user's timezone from his request settings. So you can: +- store this timezone in user's profile, +- define a static server's timezone +- create and register a ServerTimezoneUtility to handle server default timezone. + +My current default user's timezone is set to 'Europe/Paris' ; you should probably update this setting in +'timezone.py' if you are located elsewhere. + + >>> from pyams_utils import timezone + >>> timezone.tztime(ddate) + datetime.datetime(2008, 3, 8, 18, 13, 20, tzinfo=) + +'gmtime' function can be used to convert a datetime to GMT: + + >>> timezone.gmtime(now) + datetime.datetime(2008, 3, 8, 18, 13, 20, tzinfo=) diff -r 7f256d281e84 -r 4504a27af426 src/pyams_utils/doctests/dates.txt --- a/src/pyams_utils/doctests/dates.txt Wed Nov 27 16:46:35 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ - -Dates functions ---------------- - -Dates functions are used to convert dates from/to string representation: - - >>> import pytz - >>> from datetime import datetime - >>> from pyams_utils import date - >>> gmt = pytz.timezone('GMT') - >>> now = datetime.fromtimestamp(1205000000, gmt) - >>> now - datetime.datetime(2008, 3, 8, 18, 13, 20, tzinfo=) - -You can get an unicode representation of a date in ASCII format using 'unidate' fonction ; date is -converted to GMT: - - >>> udate = date.unidate(now) - >>> udate - '2008-03-08T18:13:20+00:00' - -'parse_date' can be used to convert ASCII format into datetime: - - >>> ddate = date.parse_date(udate) - >>> ddate - datetime.datetime(2008, 3, 8, 18, 13, 20, tzinfo=) - -'date_to_datetime' can be used to convert a 'date' type to a 'datetime' value ; if a 'datetime' value -is used as argument, it is returned 'as is': - - >>> ddate.date() - datetime.date(2008, 3, 8) - >>> date.date_to_datetime(ddate) - datetime.datetime(2008, 3, 8, 18, 13, 20, tzinfo=) - >>> date.date_to_datetime(ddate.date()) - datetime.datetime(2008, 3, 8, 0, 0) - - -Timezones handling ------------------- - -Timezones handling gave me headaches at first. I finally concluded that the best way (for me !) to handle -TZ data was to store every datetime value in GMT timezone. -As far as I know, there is no easy way to know the user's timezone from his request settings. So you can: -- store this timezone in user's profile, -- define a static server's timezone -- create and register a ServerTimezoneUtility to handle server default timezone. - -My current default user's timezone is set to 'Europe/Paris' ; you should probably update this setting in -'timezone.py' if you are located elsewhere. - - >>> from pyams_utils import timezone - >>> timezone.tztime(ddate) - datetime.datetime(2008, 3, 8, 18, 13, 20, tzinfo=) - -'gmtime' function can be used to convert a datetime to GMT: - - >>> timezone.gmtime(now) - datetime.datetime(2008, 3, 8, 18, 13, 20, tzinfo=) diff -r 7f256d281e84 -r 4504a27af426 src/pyams_utils/doctests/request.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_utils/doctests/request.rst Tue Jun 23 12:53:06 2020 +0200 @@ -0,0 +1,78 @@ + +Managing requests +----------------- + +PyAMS_utils package provides some useful functions to handle requests. + +The "check_request" function can be used when you have to be sure that a request is active in +the current execution thread; if no "real" request is active, a new one is created: + + >>> from pyams_utils.request import query_request, check_request + >>> request = query_request() + >>> request is None + True + >>> request = check_request() + >>> request + + +If a new request is created "from scratch", it's registry is assigned to global registry: + + >>> request.registry + + +A request context can be used to activate a request into execution thread: + + >>> from pyramid.threadlocal import RequestContext + >>> with RequestContext(request) as context_request: + ... context_request is request + True + >>> with RequestContext(request): + ... context_request = check_request() + ... context_request is request + True + +Requests can now support annotations to set and retrieve any information to a given request: + + >>> from zope.annotation.interfaces import IAttributeAnnotatable, IAnnotations + >>> from zope.annotation.attribute import AttributeAnnotations + >>> from pyams_utils.registry import get_global_registry + >>> registry = get_global_registry() + >>> registry.registerAdapter(AttributeAnnotations, (IAttributeAnnotatable, ), IAnnotations) + + >>> from pyams_utils.request import get_request_data, set_request_data + >>> set_request_data(request, 'test', 'This is request data') + >>> get_request_data(request, 'test') + 'This is request data' + +Annotations can be used to automatically reify a given property into request annotations: + + >>> from pyams_utils.request import request_property + >>> class RequestPropertyTestClass(object): + ... + ... @request_property(key='My property') + ... def my_property(self): + ... print("This is my property") + ... return 1 + ... + >>> with RequestContext(request): + ... instance = RequestPropertyTestClass() + ... instance.my_property() + This is my property + 1 + +As property value is cached into request annotations, other property calls will just return +cached value: + + >>> with RequestContext(request): + ... instance.my_property() + 1 + +The "copy_request" function is used to clone another request. All request methods and properties +defined via "add_request_method()" are kept, as "registry" and "root" attributes: + + >>> from pyams_utils.request import copy_request + >>> request2 = copy_request(request) + >>> request2.registry is request.registry + True + >>> request2.root is None + True diff -r 7f256d281e84 -r 4504a27af426 src/pyams_utils/doctests/request.txt --- a/src/pyams_utils/doctests/request.txt Wed Nov 27 16:46:35 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ - -Managing requests ------------------ - -PyAMS_utils package provides some useful functions to handle requests. - -The "check_request" function can be used when you have to be sure that a request is active in -the current execution thread; if no "real" request is active, a new one is created: - - >>> from pyams_utils.request import query_request, check_request - >>> request = query_request() - >>> request is None - True - >>> request = check_request() - >>> request - - -If a new request is created "from scratch", it's registry is assigned to global registry: - - >>> request.registry - - -A request context can be used to activate a request into execution thread: - - >>> from pyramid.threadlocal import RequestContext - >>> with RequestContext(request) as context_request: - ... context_request is request - True - >>> with RequestContext(request): - ... context_request = check_request() - ... context_request is request - True - -Requests can now support annotations to set and retrieve any information to a given request: - - >>> from zope.annotation.interfaces import IAttributeAnnotatable, IAnnotations - >>> from zope.annotation.attribute import AttributeAnnotations - >>> from pyams_utils.registry import get_global_registry - >>> registry = get_global_registry() - >>> registry.registerAdapter(AttributeAnnotations, (IAttributeAnnotatable, ), IAnnotations) - - >>> from pyams_utils.request import get_request_data, set_request_data - >>> set_request_data(request, 'test', 'This is request data') - >>> get_request_data(request, 'test') - 'This is request data' - -Annotations can be used to automatically reify a given property into request annotations: - - >>> from pyams_utils.request import request_property - >>> class RequestPropertyTestClass(object): - ... - ... @request_property(key='My property') - ... def my_property(self): - ... print("This is my property") - ... return 1 - ... - >>> with RequestContext(request): - ... instance = RequestPropertyTestClass() - ... instance.my_property() - This is my property - 1 - -As property value is cached into request annotations, other property calls will just return -cached value: - - >>> with RequestContext(request): - ... instance.my_property() - 1 - -The "copy_request" function is used to clone another request. All request methods and properties -defined via "add_request_method()" are kept, as "registry" and "root" attributes: - - >>> from pyams_utils.request import copy_request - >>> request2 = copy_request(request) - >>> request2.registry is request.registry - True - >>> request2.root is None - True diff -r 7f256d281e84 -r 4504a27af426 src/pyams_utils/doctests/unicode.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_utils/doctests/unicode.rst Tue Jun 23 12:53:06 2020 +0200 @@ -0,0 +1,80 @@ + +Unicode functions +----------------- + +While working with extended characters sets containing accentuated characters, it's necessary to +convert strings to UTF8 so that they can be used without any conversion problem. + + >>> from pyams_utils import unicode + +'translate_string' is a utility function which can be used, for example, to generate an object's id +without space and with accentuated characters converted to their unaccentuated version: + + >>> sample = 'Mon titre accentué' + >>> unicode.translate_string(sample) + 'mon titre accentue' + +Results are lower-cased by default ; this can be avoided by setting the 'force_lower' argument +to False: + + >>> unicode.translate_string(sample, force_lower=False) + 'Mon titre accentue' + >>> unicode.translate_string(sample, force_lower=True, spaces='-') + 'mon-titre-accentue' + + >>> sample = 'Texte accentué avec "ponctuation" !' + >>> unicode.translate_string(sample, force_lower=True, spaces=' ') + 'texte accentue avec ponctuation' + >>> unicode.translate_string(sample, force_lower=True, remove_punctuation=False, spaces=' ') + 'texte accentue avec "ponctuation" !' + >>> unicode.translate_string(sample, force_lower=True, remove_punctuation=False, spaces='-') + 'texte-accentue-avec-"ponctuation"-!' + >>> unicode.translate_string(sample, force_lower=True, remove_punctuation=True, spaces='-') + 'texte-accentue-avec-ponctuation' + >>> unicode.translate_string(sample, force_lower=True, remove_punctuation=True, spaces=' ', keep_chars='!') + 'texte accentue avec ponctuation !' + + +If input string can contain 'slashes' (/) or 'backslashes' (\), they are normally removed ; +by using the 'escape_slashes' parameter, the input string is splitted and only the last element is +returned ; this is handy to handle filenames on Windows platform: + + >>> sample = 'Autre / chaîne / accentuée' + >>> unicode.translate_string(sample) + 'autre chaine accentuee' + >>> unicode.translate_string(sample, escape_slashes=True) + 'accentuee' + >>> sample = 'C:\\Program Files\\My Application\\test.txt' + >>> unicode.translate_string(sample) + 'cprogram filesmy applicationtest.txt' + >>> unicode.translate_string(sample, escape_slashes=True) + 'test.txt' + +To remove remaining spaces or convert them to another character, you can use the "spaces" parameter +which can contain any string to be used instead of initial spaces: + + >>> sample = 'C:\\Program Files\\My Application\\test.txt' + >>> unicode.translate_string(sample, spaces=' ') + 'cprogram filesmy applicationtest.txt' + >>> unicode.translate_string(sample, spaces='-') + 'cprogram-filesmy-applicationtest.txt' + +Spaces replacement is made in the last step, so using it with "escape_slashes" parameter only affects +the final result: + + >>> unicode.translate_string(sample, escape_slashes=True, spaces='-') + 'test.txt' + +Unicode module also provides encoding and decoding functions: + + >>> var = b'Cha\xeene accentu\xe9e' + >>> unicode.decode(var, 'latin1') + 'Chaîne accentuée' + >>> unicode.encode(unicode.decode(var, 'latin1'), 'latin1') == var + True + + >>> utf = 'Chaîne accentuée' + >>> unicode.encode(utf, 'latin1') + b'Cha\xeene accentu\xe9e' + >>> unicode.decode(unicode.encode(utf, 'latin1'), 'latin1') == utf + True diff -r 7f256d281e84 -r 4504a27af426 src/pyams_utils/doctests/unicode.txt --- a/src/pyams_utils/doctests/unicode.txt Wed Nov 27 16:46:35 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ - -Unicode functions ------------------ - -While working with extended characters sets containing accentuated characters, it's necessary to -convert strings to UTF8 so that they can be used without any conversion problem. - - >>> from pyams_utils import unicode - -'translate_string' is a utility function which can be used, for example, to generate an object's id -without space and with accentuated characters converted to their unaccentuated version: - - >>> sample = 'Mon titre accentué' - >>> unicode.translate_string(sample) - 'mon titre accentue' - -Results are lower-cased by default ; this can be avoided by setting the 'force_lower' argument -to False: - - >>> unicode.translate_string(sample, force_lower=False) - 'Mon titre accentue' - >>> unicode.translate_string(sample, force_lower=True, spaces='-') - 'mon-titre-accentue' - - >>> sample = 'Texte accentué avec "ponctuation" !' - >>> unicode.translate_string(sample, force_lower=True, spaces=' ') - 'texte accentue avec ponctuation' - >>> unicode.translate_string(sample, force_lower=True, remove_punctuation=False, spaces=' ') - 'texte accentue avec "ponctuation" !' - >>> unicode.translate_string(sample, force_lower=True, remove_punctuation=False, spaces='-') - 'texte-accentue-avec-"ponctuation"-!' - >>> unicode.translate_string(sample, force_lower=True, remove_punctuation=True, spaces='-') - 'texte-accentue-avec-ponctuation' - >>> unicode.translate_string(sample, force_lower=True, remove_punctuation=True, spaces=' ', keep_chars='!') - 'texte accentue avec ponctuation !' - - -If input string can contain 'slashes' (/) or 'backslashes' (\), they are normally removed ; -by using the 'escape_slashes' parameter, the input string is splitted and only the last element is -returned ; this is handy to handle filenames on Windows platform: - - >>> sample = 'Autre / chaîne / accentuée' - >>> unicode.translate_string(sample) - 'autre chaine accentuee' - >>> unicode.translate_string(sample, escape_slashes=True) - 'accentuee' - >>> sample = 'C:\\Program Files\\My Application\\test.txt' - >>> unicode.translate_string(sample) - 'cprogram filesmy applicationtest.txt' - >>> unicode.translate_string(sample, escape_slashes=True) - 'test.txt' - -To remove remaining spaces or convert them to another character, you can use the "spaces" parameter -which can contain any string to be used instead of initial spaces: - - >>> sample = 'C:\\Program Files\\My Application\\test.txt' - >>> unicode.translate_string(sample, spaces=' ') - 'cprogram filesmy applicationtest.txt' - >>> unicode.translate_string(sample, spaces='-') - 'cprogram-filesmy-applicationtest.txt' - -Spaces replacement is made in the last step, so using it with "escape_slashes" parameter only affects -the final result: - - >>> unicode.translate_string(sample, escape_slashes=True, spaces='-') - 'test.txt' - -Unicode module also provides encoding and decoding functions: - - >>> var = b'Cha\xeene accentu\xe9e' - >>> unicode.decode(var, 'latin1') - 'Chaîne accentuée' - >>> unicode.encode(unicode.decode(var, 'latin1'), 'latin1') == var - True - - >>> utf = 'Chaîne accentuée' - >>> unicode.encode(utf, 'latin1') - b'Cha\xeene accentu\xe9e' - >>> unicode.decode(unicode.encode(utf, 'latin1'), 'latin1') == utf - True diff -r 7f256d281e84 -r 4504a27af426 src/pyams_utils/tests/__init__.py --- a/src/pyams_utils/tests/__init__.py Wed Nov 27 16:46:35 2019 +0100 +++ b/src/pyams_utils/tests/__init__.py Tue Jun 23 12:53:06 2020 +0200 @@ -14,13 +14,14 @@ ############################################################################## """ -Generic Test case for ztfy.utils doctest +Generic test case for pyams_utils """ -__docformat__ = 'restructuredtext' import os import sys +__docformat__ = 'restructuredtext' + def get_package_dir(value): """Get package directory""" diff -r 7f256d281e84 -r 4504a27af426 src/pyams_utils/tests/test_utilsdocs.py --- a/src/pyams_utils/tests/test_utilsdocs.py Wed Nov 27 16:46:35 2019 +0100 +++ b/src/pyams_utils/tests/test_utilsdocs.py Tue Jun 23 12:53:06 2020 +0200 @@ -14,23 +14,23 @@ ############################################################################## """ -Generic Test case for ztfy.utils doctest +Generic test case for pyams_utils doctests """ -__docformat__ = 'restructuredtext' - import doctest import os import unittest from pyams_utils.tests import get_package_dir +__docformat__ = 'restructuredtext' + CURRENT_DIR = os.path.abspath(os.path.dirname(__file__)) def doc_suite(test_dir, setUp=None, tearDown=None, globs=None): # pylint: disable=invalid-name - """Returns a test suite, based on doctests found in /doctest.""" + """Returns a test suite, based on doctests found in /doctests""" suite = [] if globs is None: globs = globals() @@ -43,7 +43,7 @@ # filtering files on extension docs = [os.path.join(doctest_dir, doc) for doc in - os.listdir(doctest_dir) if doc.endswith('.txt')] + os.listdir(doctest_dir) if doc.endswith('.txt') or doc.endswith('.rst')] for test in docs: suite.append(doctest.DocFileSuite(test, optionflags=flags, diff -r 7f256d281e84 -r 4504a27af426 src/pyams_utils/tests/test_utilsdocstrings.py --- a/src/pyams_utils/tests/test_utilsdocstrings.py Wed Nov 27 16:46:35 2019 +0100 +++ b/src/pyams_utils/tests/test_utilsdocstrings.py Tue Jun 23 12:53:06 2020 +0200 @@ -14,17 +14,17 @@ ############################################################################## """ -Generic Test case for pyams_utils doc strings +Generic test case for pyams_utils docstrings """ -__docformat__ = 'restructuredtext' - import doctest import os import unittest from pyams_utils.tests import get_package_dir +__docformat__ = 'restructuredtext' + CURRENT_DIR = os.path.abspath(os.path.dirname(__file__))