Commits

Lucian Brănescu-Mihăilă committed 79ed350

Switch to a tipfy structure. Not working yet.

Comments (0)

Files changed (622)

+Tipfy Installation
+==================
+Tipfy is a small but powerful framework made specifically for Google App
+Engine. Here are some quick instructions to get started with it. More details
+are available in tipfy's wiki:
+
+  http://www.tipfy.org/wiki/guide/installation/
+
+Our goal gere is to provide a smooth installation process so that you can see
+a tipfy application up and running in a few minutes. If you have any problems,
+please post a message to the discussion group:
+
+  http://groups.google.com/group/tipfy
+
+
+All-in-one installation
+-----------------------
+If you downloaded the all-in-one pack, all you need to do is to start the
+development server pointing to the /app dir inside the uncompressed archive:
+
+- Run the dev_appserver tool from the App Engine SDK (or the App Engine
+  Launcher) pointing to the /app directory inside the uncompressed archive:
+
+    dev_appserver.py /path/to/project/app
+
+- Open a browser and test the URLs:
+
+    http://localhost:8080/
+    http://localhost:8080/pretty
+
+You should see a Hello, World! message. If you do, that's all. Now you have
+a project environment to start developing your app.
+
+
+Do-it-yourself installation
+---------------------------
+If you downloaded the do-it-yourself pack, you need to first install the
+needed libraries before running de development server. Here's how:
+
+- Access the project directory and call the bootstrap script using your
+  Python 2.5 interpreter. We pass the command --distribute because it
+  is preferable to the default setuptools. This will prepare buildout to run:
+
+    python bootstrap.py --distribute
+
+- Build the project calling bin/buildout. This will download and setup
+  tipfy and all libraries inside the /app directory. It may take a while.
+
+    bin/buildout
+
+- Start the development server calling bin/dev_appserver. It will use the
+  application from /app by default:
+
+    bin/dev_appserver
+
+- Open a browser and test the URLs:
+
+    http://localhost:8080/
+    http://localhost:8080/pretty
+
+You should see a Hello, World! message. If you do, that's all. Now you have
+a project environment to start developing your app.
+application: my-app
+version: 1
+runtime: python
+api_version: 1
+
+derived_file_type:
+- python_precompiled
+
+handlers:
+- url: /(robots\.txt|favicon\.ico)
+  static_files: static/\1
+  upload: static/(.*)
+
+- url: /remote_api
+  script: $PYTHON_LIB/google/appengine/ext/remote_api/handler.py
+  login: admin
+
+- url: /_ah/queue/deferred
+  script: main.py
+  login: admin
+
+- url: /.*
+  script: main.py

app/apps/__init__.py

+

app/apps/hello_world/__init__.py

+

app/apps/hello_world/handlers.py

+# -*- coding: utf-8 -*-
+"""
+    handlers
+    ~~~~~~~~
+
+    Hello, World!: the simplest tipfy app.
+
+    :copyright: 2009 by tipfy.org.
+    :license: BSD, see LICENSE for more details.
+"""
+from tipfy import RequestHandler, Response
+from tipfy.ext.jinja2 import render_response
+
+
+class HelloWorldHandler(RequestHandler):
+    def get(self):
+        """Simply returns a Response object with an enigmatic salutation."""
+        return Response('Hello, World!')
+
+
+class PrettyHelloWorldHandler(RequestHandler):
+    def get(self):
+        """Simply returns a rendered template with an enigmatic salutation."""
+        return render_response('hello_world.html', message='Hello, World!')

app/apps/hello_world/urls.py

+# -*- coding: utf-8 -*-
+"""
+    urls
+    ~~~~
+
+    URL definitions.
+
+    :copyright: 2009 by tipfy.org.
+    :license: BSD, see LICENSE.txt for more details.
+"""
+from tipfy import Rule
+
+
+def get_rules(app):
+    """Returns a list of URL rules for the Hello, World! application.
+
+    :param app:
+        The WSGI application instance.
+    :return:
+        A list of class:`tipfy.Rule` instances.
+    """
+    rules = [
+        Rule('/', endpoint='hello-world', handler='apps.hello_world.handlers.HelloWorldHandler'),
+        Rule('/pretty', endpoint='hello-world-pretty', handler='apps.hello_world.handlers.PrettyHelloWorldHandler'),
+    ]
+
+    return rules

app/apps/mousebuster/main.py

+#!/usr/bin/env python
+#
+# Copyright 2007 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+from google.appengine.ext import webapp
+from google.appengine.ext.webapp import util
+
+
+class MainHandler(webapp.RequestHandler):
+    def get(self):
+        self.response.out.write('Hello world!')
+
+
+def main():
+    application = webapp.WSGIApplication([('/', MainHandler)],
+                                         debug=True)
+    util.run_wsgi_app(application)
+
+
+if __name__ == '__main__':
+    main()
+# -*- coding: utf-8 -*-
+"""
+    config
+    ~~~~~~
+
+    Configuration settings.
+
+    :copyright: 2009 by tipfy.org.
+    :license: BSD, see LICENSE for more details.
+"""
+config = {}
+
+# Configurations for the 'tipfy' module.
+config['tipfy'] = {
+    # Enable debugger. It will be loaded only in development.
+    'middleware': [
+        'tipfy.ext.debugger.DebuggerMiddleware',
+    ],
+    # Enable the Hello, World! app example.
+    'apps_installed': [
+        'apps.hello_world',
+    ],
+}

app/distlib/README.txt

+Warning!
+========
+
+This directory is removed every time the buildout tool runs, so don't place
+or edit things here because any changes will be lost!
+
+Use a different directory for extra libraries instead of this one.

app/distlib/babel/__init__.py

+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2007-2008 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://babel.edgewall.org/wiki/License.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://babel.edgewall.org/log/.
+
+"""Integrated collection of utilities that assist in internationalizing and
+localizing applications.
+
+This package is basically composed of two major parts:
+
+ * tools to build and work with ``gettext`` message catalogs
+ * a Python interface to the CLDR (Common Locale Data Repository), providing
+   access to various locale display names, localized number and date
+   formatting, etc.
+
+:see: http://www.gnu.org/software/gettext/
+:see: http://docs.python.org/lib/module-gettext.html
+:see: http://www.unicode.org/cldr/
+"""
+
+from babel.core import *
+
+__docformat__ = 'restructuredtext en'
+try:
+    from pkg_resources import get_distribution, ResolutionError
+    try:
+        __version__ = get_distribution('Babel').version
+    except ResolutionError:
+        __version__ = None # unknown
+except ImportError:
+    __version__ = None # unknown

app/distlib/babel/core.py

+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2007 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://babel.edgewall.org/wiki/License.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://babel.edgewall.org/log/.
+
+"""Core locale representation and locale data access."""
+
+import os
+import pickle
+
+from babel import localedata
+
+__all__ = ['UnknownLocaleError', 'Locale', 'default_locale', 'negotiate_locale',
+           'parse_locale']
+__docformat__ = 'restructuredtext en'
+
+_global_data = None
+
+def get_global(key):
+    """Return the dictionary for the given key in the global data.
+    
+    The global data is stored in the ``babel/global.dat`` file and contains
+    information independent of individual locales.
+    
+    >>> get_global('zone_aliases')['UTC']
+    'Etc/GMT'
+    >>> get_global('zone_territories')['Europe/Berlin']
+    'DE'
+    
+    :param key: the data key
+    :return: the dictionary found in the global data under the given key
+    :rtype: `dict`
+    :since: version 0.9
+    """
+    global _global_data
+    if _global_data is None:
+        dirname = os.path.join(os.path.dirname(__file__))
+        filename = os.path.join(dirname, 'global.dat')
+        fileobj = open(filename, 'rb')
+        try:
+            _global_data = pickle.load(fileobj)
+        finally:
+            fileobj.close()
+    return _global_data.get(key, {})
+
+
+LOCALE_ALIASES = {
+    'ar': 'ar_SY', 'bg': 'bg_BG', 'bs': 'bs_BA', 'ca': 'ca_ES', 'cs': 'cs_CZ', 
+    'da': 'da_DK', 'de': 'de_DE', 'el': 'el_GR', 'en': 'en_US', 'es': 'es_ES', 
+    'et': 'et_EE', 'fa': 'fa_IR', 'fi': 'fi_FI', 'fr': 'fr_FR', 'gl': 'gl_ES', 
+    'he': 'he_IL', 'hu': 'hu_HU', 'id': 'id_ID', 'is': 'is_IS', 'it': 'it_IT', 
+    'ja': 'ja_JP', 'km': 'km_KH', 'ko': 'ko_KR', 'lt': 'lt_LT', 'lv': 'lv_LV', 
+    'mk': 'mk_MK', 'nl': 'nl_NL', 'nn': 'nn_NO', 'no': 'nb_NO', 'pl': 'pl_PL', 
+    'pt': 'pt_PT', 'ro': 'ro_RO', 'ru': 'ru_RU', 'sk': 'sk_SK', 'sl': 'sl_SI', 
+    'sv': 'sv_SE', 'th': 'th_TH', 'tr': 'tr_TR', 'uk': 'uk_UA'
+}
+
+
+class UnknownLocaleError(Exception):
+    """Exception thrown when a locale is requested for which no locale data
+    is available.
+    """
+
+    def __init__(self, identifier):
+        """Create the exception.
+        
+        :param identifier: the identifier string of the unsupported locale
+        """
+        Exception.__init__(self, 'unknown locale %r' % identifier)
+        self.identifier = identifier
+
+
+class Locale(object):
+    """Representation of a specific locale.
+    
+    >>> locale = Locale('en', 'US')
+    >>> repr(locale)
+    '<Locale "en_US">'
+    >>> locale.display_name
+    u'English (United States)'
+    
+    A `Locale` object can also be instantiated from a raw locale string:
+    
+    >>> locale = Locale.parse('en-US', sep='-')
+    >>> repr(locale)
+    '<Locale "en_US">'
+    
+    `Locale` objects provide access to a collection of locale data, such as
+    territory and language names, number and date format patterns, and more:
+    
+    >>> locale.number_symbols['decimal']
+    u'.'
+    
+    If a locale is requested for which no locale data is available, an
+    `UnknownLocaleError` is raised:
+    
+    >>> Locale.parse('en_DE')
+    Traceback (most recent call last):
+        ...
+    UnknownLocaleError: unknown locale 'en_DE'
+    
+    :see: `IETF RFC 3066 <http://www.ietf.org/rfc/rfc3066.txt>`_
+    """
+
+    def __init__(self, language, territory=None, script=None, variant=None):
+        """Initialize the locale object from the given identifier components.
+        
+        >>> locale = Locale('en', 'US')
+        >>> locale.language
+        'en'
+        >>> locale.territory
+        'US'
+        
+        :param language: the language code
+        :param territory: the territory (country or region) code
+        :param script: the script code
+        :param variant: the variant code
+        :raise `UnknownLocaleError`: if no locale data is available for the
+                                     requested locale
+        """
+        self.language = language
+        self.territory = territory
+        self.script = script
+        self.variant = variant
+        self.__data = None
+
+        identifier = str(self)
+        if not localedata.exists(identifier):
+            raise UnknownLocaleError(identifier)
+
+    def default(cls, category=None, aliases=LOCALE_ALIASES):
+        """Return the system default locale for the specified category.
+        
+        >>> for name in ['LANGUAGE', 'LC_ALL', 'LC_CTYPE']:
+        ...     os.environ[name] = ''
+        >>> os.environ['LANG'] = 'fr_FR.UTF-8'
+        >>> Locale.default('LC_MESSAGES')
+        <Locale "fr_FR">
+
+        :param category: one of the ``LC_XXX`` environment variable names
+        :param aliases: a dictionary of aliases for locale identifiers
+        :return: the value of the variable, or any of the fallbacks
+                 (``LANGUAGE``, ``LC_ALL``, ``LC_CTYPE``, and ``LANG``)
+        :rtype: `Locale`
+        :see: `default_locale`
+        """
+        return cls(default_locale(category, aliases=aliases))
+    default = classmethod(default)
+
+    def negotiate(cls, preferred, available, sep='_', aliases=LOCALE_ALIASES):
+        """Find the best match between available and requested locale strings.
+        
+        >>> Locale.negotiate(['de_DE', 'en_US'], ['de_DE', 'de_AT'])
+        <Locale "de_DE">
+        >>> Locale.negotiate(['de_DE', 'en_US'], ['en', 'de'])
+        <Locale "de">
+        >>> Locale.negotiate(['de_DE', 'de'], ['en_US'])
+        
+        You can specify the character used in the locale identifiers to separate
+        the differnet components. This separator is applied to both lists. Also,
+        case is ignored in the comparison:
+        
+        >>> Locale.negotiate(['de-DE', 'de'], ['en-us', 'de-de'], sep='-')
+        <Locale "de_DE">
+        
+        :param preferred: the list of locale identifers preferred by the user
+        :param available: the list of locale identifiers available
+        :param aliases: a dictionary of aliases for locale identifiers
+        :return: the `Locale` object for the best match, or `None` if no match
+                 was found
+        :rtype: `Locale`
+        :see: `negotiate_locale`
+        """
+        identifier = negotiate_locale(preferred, available, sep=sep,
+                                      aliases=aliases)
+        if identifier:
+            return Locale.parse(identifier, sep=sep)
+    negotiate = classmethod(negotiate)
+
+    def parse(cls, identifier, sep='_'):
+        """Create a `Locale` instance for the given locale identifier.
+        
+        >>> l = Locale.parse('de-DE', sep='-')
+        >>> l.display_name
+        u'Deutsch (Deutschland)'
+        
+        If the `identifier` parameter is not a string, but actually a `Locale`
+        object, that object is returned:
+        
+        >>> Locale.parse(l)
+        <Locale "de_DE">
+        
+        :param identifier: the locale identifier string
+        :param sep: optional component separator
+        :return: a corresponding `Locale` instance
+        :rtype: `Locale`
+        :raise `ValueError`: if the string does not appear to be a valid locale
+                             identifier
+        :raise `UnknownLocaleError`: if no locale data is available for the
+                                     requested locale
+        :see: `parse_locale`
+        """
+        if isinstance(identifier, basestring):
+            return cls(*parse_locale(identifier, sep=sep))
+        return identifier
+    parse = classmethod(parse)
+
+    def __eq__(self, other):
+        return str(self) == str(other)
+
+    def __repr__(self):
+        return '<Locale "%s">' % str(self)
+
+    def __str__(self):
+        return '_'.join(filter(None, [self.language, self.script,
+                                      self.territory, self.variant]))
+
+    def _data(self):
+        if self.__data is None:
+            self.__data = localedata.LocaleDataDict(localedata.load(str(self)))
+        return self.__data
+    _data = property(_data)
+
+    def get_display_name(self, locale=None):
+        """Return the display name of the locale using the given locale.
+        
+        The display name will include the language, territory, script, and
+        variant, if those are specified.
+        
+        >>> Locale('zh', 'CN', script='Hans').get_display_name('en')
+        u'Chinese (Simplified Han, China)'
+        
+        :param locale: the locale to use
+        :return: the display name
+        """
+        if locale is None:
+            locale = self
+        locale = Locale.parse(locale)
+        retval = locale.languages.get(self.language)
+        if self.territory or self.script or self.variant:
+            details = []
+            if self.script:
+                details.append(locale.scripts.get(self.script))
+            if self.territory:
+                details.append(locale.territories.get(self.territory))
+            if self.variant:
+                details.append(locale.variants.get(self.variant))
+            details = filter(None, details)
+            if details:
+                retval += ' (%s)' % u', '.join(details)
+        return retval
+
+    display_name = property(get_display_name, doc="""\
+        The localized display name of the locale.
+        
+        >>> Locale('en').display_name
+        u'English'
+        >>> Locale('en', 'US').display_name
+        u'English (United States)'
+        >>> Locale('sv').display_name
+        u'svenska'
+        
+        :type: `unicode`
+        """)
+
+    def english_name(self):
+        return self.get_display_name(Locale('en'))
+    english_name = property(english_name, doc="""\
+        The english display name of the locale.
+        
+        >>> Locale('de').english_name
+        u'German'
+        >>> Locale('de', 'DE').english_name
+        u'German (Germany)'
+        
+        :type: `unicode`
+        """)
+
+    #{ General Locale Display Names
+
+    def languages(self):
+        return self._data['languages']
+    languages = property(languages, doc="""\
+        Mapping of language codes to translated language names.
+        
+        >>> Locale('de', 'DE').languages['ja']
+        u'Japanisch'
+        
+        :type: `dict`
+        :see: `ISO 639 <http://www.loc.gov/standards/iso639-2/>`_
+        """)
+
+    def scripts(self):
+        return self._data['scripts']
+    scripts = property(scripts, doc="""\
+        Mapping of script codes to translated script names.
+        
+        >>> Locale('en', 'US').scripts['Hira']
+        u'Hiragana'
+        
+        :type: `dict`
+        :see: `ISO 15924 <http://www.evertype.com/standards/iso15924/>`_
+        """)
+
+    def territories(self):
+        return self._data['territories']
+    territories = property(territories, doc="""\
+        Mapping of script codes to translated script names.
+        
+        >>> Locale('es', 'CO').territories['DE']
+        u'Alemania'
+        
+        :type: `dict`
+        :see: `ISO 3166 <http://www.iso.org/iso/en/prods-services/iso3166ma/>`_
+        """)
+
+    def variants(self):
+        return self._data['variants']
+    variants = property(variants, doc="""\
+        Mapping of script codes to translated script names.
+        
+        >>> Locale('de', 'DE').variants['1901']
+        u'Alte deutsche Rechtschreibung'
+        
+        :type: `dict`
+        """)
+
+    #{ Number Formatting
+
+    def currencies(self):
+        return self._data['currency_names']
+    currencies = property(currencies, doc="""\
+        Mapping of currency codes to translated currency names.
+        
+        >>> Locale('en').currencies['COP']
+        u'Colombian Peso'
+        >>> Locale('de', 'DE').currencies['COP']
+        u'Kolumbianischer Peso'
+        
+        :type: `dict`
+        """)
+
+    def currency_symbols(self):
+        return self._data['currency_symbols']
+    currency_symbols = property(currency_symbols, doc="""\
+        Mapping of currency codes to symbols.
+        
+        >>> Locale('en', 'US').currency_symbols['USD']
+        u'$'
+        >>> Locale('es', 'CO').currency_symbols['USD']
+        u'US$'
+        
+        :type: `dict`
+        """)
+
+    def number_symbols(self):
+        return self._data['number_symbols']
+    number_symbols = property(number_symbols, doc="""\
+        Symbols used in number formatting.
+        
+        >>> Locale('fr', 'FR').number_symbols['decimal']
+        u','
+        
+        :type: `dict`
+        """)
+
+    def decimal_formats(self):
+        return self._data['decimal_formats']
+    decimal_formats = property(decimal_formats, doc="""\
+        Locale patterns for decimal number formatting.
+        
+        >>> Locale('en', 'US').decimal_formats[None]
+        <NumberPattern u'#,##0.###'>
+        
+        :type: `dict`
+        """)
+
+    def currency_formats(self):
+        return self._data['currency_formats']
+    currency_formats = property(currency_formats, doc=r"""\
+        Locale patterns for currency number formatting.
+        
+        >>> print Locale('en', 'US').currency_formats[None]
+        <NumberPattern u'\xa4#,##0.00'>
+        
+        :type: `dict`
+        """)
+
+    def percent_formats(self):
+        return self._data['percent_formats']
+    percent_formats = property(percent_formats, doc="""\
+        Locale patterns for percent number formatting.
+        
+        >>> Locale('en', 'US').percent_formats[None]
+        <NumberPattern u'#,##0%'>
+        
+        :type: `dict`
+        """)
+
+    def scientific_formats(self):
+        return self._data['scientific_formats']
+    scientific_formats = property(scientific_formats, doc="""\
+        Locale patterns for scientific number formatting.
+        
+        >>> Locale('en', 'US').scientific_formats[None]
+        <NumberPattern u'#E0'>
+        
+        :type: `dict`
+        """)
+
+    #{ Calendar Information and Date Formatting
+
+    def periods(self):
+        return self._data['periods']
+    periods = property(periods, doc="""\
+        Locale display names for day periods (AM/PM).
+        
+        >>> Locale('en', 'US').periods['am']
+        u'AM'
+        
+        :type: `dict`
+        """)
+
+    def days(self):
+        return self._data['days']
+    days = property(days, doc="""\
+        Locale display names for weekdays.
+        
+        >>> Locale('de', 'DE').days['format']['wide'][3]
+        u'Donnerstag'
+        
+        :type: `dict`
+        """)
+
+    def months(self):
+        return self._data['months']
+    months = property(months, doc="""\
+        Locale display names for months.
+        
+        >>> Locale('de', 'DE').months['format']['wide'][10]
+        u'Oktober'
+        
+        :type: `dict`
+        """)
+
+    def quarters(self):
+        return self._data['quarters']
+    quarters = property(quarters, doc="""\
+        Locale display names for quarters.
+        
+        >>> Locale('de', 'DE').quarters['format']['wide'][1]
+        u'1. Quartal'
+        
+        :type: `dict`
+        """)
+
+    def eras(self):
+        return self._data['eras']
+    eras = property(eras, doc="""\
+        Locale display names for eras.
+        
+        >>> Locale('en', 'US').eras['wide'][1]
+        u'Anno Domini'
+        >>> Locale('en', 'US').eras['abbreviated'][0]
+        u'BC'
+        
+        :type: `dict`
+        """)
+
+    def time_zones(self):
+        return self._data['time_zones']
+    time_zones = property(time_zones, doc="""\
+        Locale display names for time zones.
+        
+        >>> Locale('en', 'US').time_zones['Europe/London']['long']['daylight']
+        u'British Summer Time'
+        >>> Locale('en', 'US').time_zones['America/St_Johns']['city']
+        u"St. John's"
+        
+        :type: `dict`
+        """)
+
+    def meta_zones(self):
+        return self._data['meta_zones']
+    meta_zones = property(meta_zones, doc="""\
+        Locale display names for meta time zones.
+        
+        Meta time zones are basically groups of different Olson time zones that
+        have the same GMT offset and daylight savings time.
+        
+        >>> Locale('en', 'US').meta_zones['Europe_Central']['long']['daylight']
+        u'Central European Summer Time'
+        
+        :type: `dict`
+        :since: version 0.9
+        """)
+
+    def zone_formats(self):
+        return self._data['zone_formats']
+    zone_formats = property(zone_formats, doc=r"""\
+        Patterns related to the formatting of time zones.
+        
+        >>> Locale('en', 'US').zone_formats['fallback']
+        u'%(1)s (%(0)s)'
+        >>> Locale('pt', 'BR').zone_formats['region']
+        u'Hor\xe1rio %s'
+        
+        :type: `dict`
+        :since: version 0.9
+        """)
+
+    def first_week_day(self):
+        return self._data['week_data']['first_day']
+    first_week_day = property(first_week_day, doc="""\
+        The first day of a week, with 0 being Monday.
+        
+        >>> Locale('de', 'DE').first_week_day
+        0
+        >>> Locale('en', 'US').first_week_day
+        6
+        
+        :type: `int`
+        """)
+
+    def weekend_start(self):
+        return self._data['week_data']['weekend_start']
+    weekend_start = property(weekend_start, doc="""\
+        The day the weekend starts, with 0 being Monday.
+        
+        >>> Locale('de', 'DE').weekend_start
+        5
+        
+        :type: `int`
+        """)
+
+    def weekend_end(self):
+        return self._data['week_data']['weekend_end']
+    weekend_end = property(weekend_end, doc="""\
+        The day the weekend ends, with 0 being Monday.
+        
+        >>> Locale('de', 'DE').weekend_end
+        6
+        
+        :type: `int`
+        """)
+
+    def min_week_days(self):
+        return self._data['week_data']['min_days']
+    min_week_days = property(min_week_days, doc="""\
+        The minimum number of days in a week so that the week is counted as the
+        first week of a year or month.
+        
+        >>> Locale('de', 'DE').min_week_days
+        4
+        
+        :type: `int`
+        """)
+
+    def date_formats(self):
+        return self._data['date_formats']
+    date_formats = property(date_formats, doc="""\
+        Locale patterns for date formatting.
+        
+        >>> Locale('en', 'US').date_formats['short']
+        <DateTimePattern u'M/d/yy'>
+        >>> Locale('fr', 'FR').date_formats['long']
+        <DateTimePattern u'd MMMM yyyy'>
+        
+        :type: `dict`
+        """)
+
+    def time_formats(self):
+        return self._data['time_formats']
+    time_formats = property(time_formats, doc="""\
+        Locale patterns for time formatting.
+        
+        >>> Locale('en', 'US').time_formats['short']
+        <DateTimePattern u'h:mm a'>
+        >>> Locale('fr', 'FR').time_formats['long']
+        <DateTimePattern u'HH:mm:ss z'>
+        
+        :type: `dict`
+        """)
+
+    def datetime_formats(self):
+        return self._data['datetime_formats']
+    datetime_formats = property(datetime_formats, doc="""\
+        Locale patterns for datetime formatting.
+        
+        >>> Locale('en').datetime_formats[None]
+        u'{1} {0}'
+        >>> Locale('th').datetime_formats[None]
+        u'{1}, {0}'
+        
+        :type: `dict`
+        """)
+
+
+def default_locale(category=None, aliases=LOCALE_ALIASES):
+    """Returns the system default locale for a given category, based on
+    environment variables.
+    
+    >>> for name in ['LANGUAGE', 'LC_ALL', 'LC_CTYPE']:
+    ...     os.environ[name] = ''
+    >>> os.environ['LANG'] = 'fr_FR.UTF-8'
+    >>> default_locale('LC_MESSAGES')
+    'fr_FR'
+
+    The "C" or "POSIX" pseudo-locales are treated as aliases for the
+    "en_US_POSIX" locale:
+
+    >>> os.environ['LC_MESSAGES'] = 'POSIX'
+    >>> default_locale('LC_MESSAGES')
+    'en_US_POSIX'
+
+    :param category: one of the ``LC_XXX`` environment variable names
+    :param aliases: a dictionary of aliases for locale identifiers
+    :return: the value of the variable, or any of the fallbacks (``LANGUAGE``,
+             ``LC_ALL``, ``LC_CTYPE``, and ``LANG``)
+    :rtype: `str`
+    """
+    varnames = (category, 'LANGUAGE', 'LC_ALL', 'LC_CTYPE', 'LANG')
+    for name in filter(None, varnames):
+        locale = os.getenv(name)
+        if locale:
+            if name == 'LANGUAGE' and ':' in locale:
+                # the LANGUAGE variable may contain a colon-separated list of
+                # language codes; we just pick the language on the list
+                locale = locale.split(':')[0]
+            if locale in ('C', 'POSIX'):
+                locale = 'en_US_POSIX'
+            elif aliases and locale in aliases:
+                locale = aliases[locale]
+            return '_'.join(filter(None, parse_locale(locale)))
+
+def negotiate_locale(preferred, available, sep='_', aliases=LOCALE_ALIASES):
+    """Find the best match between available and requested locale strings.
+    
+    >>> negotiate_locale(['de_DE', 'en_US'], ['de_DE', 'de_AT'])
+    'de_DE'
+    >>> negotiate_locale(['de_DE', 'en_US'], ['en', 'de'])
+    'de'
+    
+    Case is ignored by the algorithm, the result uses the case of the preferred
+    locale identifier:
+    
+    >>> negotiate_locale(['de_DE', 'en_US'], ['de_de', 'de_at'])
+    'de_DE'
+    
+    >>> negotiate_locale(['de_DE', 'en_US'], ['de_de', 'de_at'])
+    'de_DE'
+    
+    By default, some web browsers unfortunately do not include the territory
+    in the locale identifier for many locales, and some don't even allow the
+    user to easily add the territory. So while you may prefer using qualified
+    locale identifiers in your web-application, they would not normally match
+    the language-only locale sent by such browsers. To workaround that, this
+    function uses a default mapping of commonly used langauge-only locale
+    identifiers to identifiers including the territory:
+    
+    >>> negotiate_locale(['ja', 'en_US'], ['ja_JP', 'en_US'])
+    'ja_JP'
+    
+    Some browsers even use an incorrect or outdated language code, such as "no"
+    for Norwegian, where the correct locale identifier would actually be "nb_NO"
+    (Bokmål) or "nn_NO" (Nynorsk). The aliases are intended to take care of
+    such cases, too:
+    
+    >>> negotiate_locale(['no', 'sv'], ['nb_NO', 'sv_SE'])
+    'nb_NO'
+    
+    You can override this default mapping by passing a different `aliases`
+    dictionary to this function, or you can bypass the behavior althogher by
+    setting the `aliases` parameter to `None`.
+    
+    :param preferred: the list of locale strings preferred by the user
+    :param available: the list of locale strings available
+    :param sep: character that separates the different parts of the locale
+                strings
+    :param aliases: a dictionary of aliases for locale identifiers
+    :return: the locale identifier for the best match, or `None` if no match
+             was found
+    :rtype: `str`
+    """
+    available = [a.lower() for a in available if a]
+    for locale in preferred:
+        ll = locale.lower()
+        if ll in available:
+            return locale
+        if aliases:
+            alias = aliases.get(ll)
+            if alias:
+                alias = alias.replace('_', sep)
+                if alias.lower() in available:
+                    return alias
+        parts = locale.split(sep)
+        if len(parts) > 1 and parts[0].lower() in available:
+            return parts[0]
+    return None
+
+def parse_locale(identifier, sep='_'):
+    """Parse a locale identifier into a tuple of the form::
+    
+      ``(language, territory, script, variant)``
+    
+    >>> parse_locale('zh_CN')
+    ('zh', 'CN', None, None)
+    >>> parse_locale('zh_Hans_CN')
+    ('zh', 'CN', 'Hans', None)
+    
+    The default component separator is "_", but a different separator can be
+    specified using the `sep` parameter:
+    
+    >>> parse_locale('zh-CN', sep='-')
+    ('zh', 'CN', None, None)
+    
+    If the identifier cannot be parsed into a locale, a `ValueError` exception
+    is raised:
+    
+    >>> parse_locale('not_a_LOCALE_String')
+    Traceback (most recent call last):
+      ...
+    ValueError: 'not_a_LOCALE_String' is not a valid locale identifier
+    
+    Encoding information and locale modifiers are removed from the identifier:
+    
+    >>> parse_locale('it_IT@euro')
+    ('it', 'IT', None, None)
+    >>> parse_locale('en_US.UTF-8')
+    ('en', 'US', None, None)
+    >>> parse_locale('de_DE.iso885915@euro')
+    ('de', 'DE', None, None)
+    
+    :param identifier: the locale identifier string
+    :param sep: character that separates the different components of the locale
+                identifier
+    :return: the ``(language, territory, script, variant)`` tuple
+    :rtype: `tuple`
+    :raise `ValueError`: if the string does not appear to be a valid locale
+                         identifier
+    
+    :see: `IETF RFC 4646 <http://www.ietf.org/rfc/rfc4646.txt>`_
+    """
+    if '.' in identifier:
+        # this is probably the charset/encoding, which we don't care about
+        identifier = identifier.split('.', 1)[0]
+    if '@' in identifier:
+        # this is a locale modifier such as @euro, which we don't care about
+        # either
+        identifier = identifier.split('@', 1)[0]
+
+    parts = identifier.split(sep)
+    lang = parts.pop(0).lower()
+    if not lang.isalpha():
+        raise ValueError('expected only letters, got %r' % lang)
+
+    script = territory = variant = None
+    if parts:
+        if len(parts[0]) == 4 and parts[0].isalpha():
+            script = parts.pop(0).title()
+
+    if parts:
+        if len(parts[0]) == 2 and parts[0].isalpha():
+            territory = parts.pop(0).upper()
+        elif len(parts[0]) == 3 and parts[0].isdigit():
+            territory = parts.pop(0)
+
+    if parts:
+        if len(parts[0]) == 4 and parts[0][0].isdigit() or \
+                len(parts[0]) >= 5 and parts[0][0].isalpha():
+            variant = parts.pop()
+
+    if parts:
+        raise ValueError('%r is not a valid locale identifier' % identifier)
+
+    return lang, territory, script, variant

app/distlib/babel/dates.py

+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2007 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://babel.edgewall.org/wiki/License.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://babel.edgewall.org/log/.
+
+"""Locale dependent formatting and parsing of dates and times.
+
+The default locale for the functions in this module is determined by the
+following environment variables, in that order:
+
+ * ``LC_TIME``,
+ * ``LC_ALL``, and
+ * ``LANG``
+"""
+
+from datetime import date, datetime, time, timedelta, tzinfo
+import re
+
+from babel.core import default_locale, get_global, Locale
+from babel.util import UTC
+
+__all__ = ['format_date', 'format_datetime', 'format_time',
+           'get_timezone_name', 'parse_date', 'parse_datetime', 'parse_time']
+__docformat__ = 'restructuredtext en'
+
+LC_TIME = default_locale('LC_TIME')
+
+# Aliases for use in scopes where the modules are shadowed by local variables
+date_ = date
+datetime_ = datetime
+time_ = time
+
+def get_period_names(locale=LC_TIME):
+    """Return the names for day periods (AM/PM) used by the locale.
+    
+    >>> get_period_names(locale='en_US')['am']
+    u'AM'
+    
+    :param locale: the `Locale` object, or a locale string
+    :return: the dictionary of period names
+    :rtype: `dict`
+    """
+    return Locale.parse(locale).periods
+
+def get_day_names(width='wide', context='format', locale=LC_TIME):
+    """Return the day names used by the locale for the specified format.
+    
+    >>> get_day_names('wide', locale='en_US')[1]
+    u'Tuesday'
+    >>> get_day_names('abbreviated', locale='es')[1]
+    u'mar'
+    >>> get_day_names('narrow', context='stand-alone', locale='de_DE')[1]
+    u'D'
+    
+    :param width: the width to use, one of "wide", "abbreviated", or "narrow"
+    :param context: the context, either "format" or "stand-alone"
+    :param locale: the `Locale` object, or a locale string
+    :return: the dictionary of day names
+    :rtype: `dict`
+    """
+    return Locale.parse(locale).days[context][width]
+
+def get_month_names(width='wide', context='format', locale=LC_TIME):
+    """Return the month names used by the locale for the specified format.
+    
+    >>> get_month_names('wide', locale='en_US')[1]
+    u'January'
+    >>> get_month_names('abbreviated', locale='es')[1]
+    u'ene'
+    >>> get_month_names('narrow', context='stand-alone', locale='de_DE')[1]
+    u'J'
+    
+    :param width: the width to use, one of "wide", "abbreviated", or "narrow"
+    :param context: the context, either "format" or "stand-alone"
+    :param locale: the `Locale` object, or a locale string
+    :return: the dictionary of month names
+    :rtype: `dict`
+    """
+    return Locale.parse(locale).months[context][width]
+
+def get_quarter_names(width='wide', context='format', locale=LC_TIME):
+    """Return the quarter names used by the locale for the specified format.
+    
+    >>> get_quarter_names('wide', locale='en_US')[1]
+    u'1st quarter'
+    >>> get_quarter_names('abbreviated', locale='de_DE')[1]
+    u'Q1'
+    
+    :param width: the width to use, one of "wide", "abbreviated", or "narrow"
+    :param context: the context, either "format" or "stand-alone"
+    :param locale: the `Locale` object, or a locale string
+    :return: the dictionary of quarter names
+    :rtype: `dict`
+    """
+    return Locale.parse(locale).quarters[context][width]
+
+def get_era_names(width='wide', locale=LC_TIME):
+    """Return the era names used by the locale for the specified format.
+    
+    >>> get_era_names('wide', locale='en_US')[1]
+    u'Anno Domini'
+    >>> get_era_names('abbreviated', locale='de_DE')[1]
+    u'n. Chr.'
+    
+    :param width: the width to use, either "wide", "abbreviated", or "narrow"
+    :param locale: the `Locale` object, or a locale string
+    :return: the dictionary of era names
+    :rtype: `dict`
+    """
+    return Locale.parse(locale).eras[width]
+
+def get_date_format(format='medium', locale=LC_TIME):
+    """Return the date formatting patterns used by the locale for the specified
+    format.
+    
+    >>> get_date_format(locale='en_US')
+    <DateTimePattern u'MMM d, yyyy'>
+    >>> get_date_format('full', locale='de_DE')
+    <DateTimePattern u'EEEE, d. MMMM yyyy'>
+    
+    :param format: the format to use, one of "full", "long", "medium", or
+                   "short"
+    :param locale: the `Locale` object, or a locale string
+    :return: the date format pattern
+    :rtype: `DateTimePattern`
+    """
+    return Locale.parse(locale).date_formats[format]
+
+def get_datetime_format(format='medium', locale=LC_TIME):
+    """Return the datetime formatting patterns used by the locale for the
+    specified format.
+    
+    >>> get_datetime_format(locale='en_US')
+    u'{1} {0}'
+    
+    :param format: the format to use, one of "full", "long", "medium", or
+                   "short"
+    :param locale: the `Locale` object, or a locale string
+    :return: the datetime format pattern
+    :rtype: `unicode`
+    """
+    patterns = Locale.parse(locale).datetime_formats
+    if format not in patterns:
+        format = None
+    return patterns[format]
+
+def get_time_format(format='medium', locale=LC_TIME):
+    """Return the time formatting patterns used by the locale for the specified
+    format.
+    
+    >>> get_time_format(locale='en_US')
+    <DateTimePattern u'h:mm:ss a'>
+    >>> get_time_format('full', locale='de_DE')
+    <DateTimePattern u'HH:mm:ss v'>
+    
+    :param format: the format to use, one of "full", "long", "medium", or
+                   "short"
+    :param locale: the `Locale` object, or a locale string
+    :return: the time format pattern
+    :rtype: `DateTimePattern`
+    """
+    return Locale.parse(locale).time_formats[format]
+
+def get_timezone_gmt(datetime=None, width='long', locale=LC_TIME):
+    """Return the timezone associated with the given `datetime` object formatted
+    as string indicating the offset from GMT.
+    
+    >>> dt = datetime(2007, 4, 1, 15, 30)
+    >>> get_timezone_gmt(dt, locale='en')
+    u'GMT+00:00'
+    
+    >>> from pytz import timezone
+    >>> tz = timezone('America/Los_Angeles')
+    >>> dt = datetime(2007, 4, 1, 15, 30, tzinfo=tz)
+    >>> get_timezone_gmt(dt, locale='en')
+    u'GMT-08:00'
+    >>> get_timezone_gmt(dt, 'short', locale='en')
+    u'-0800'
+    
+    The long format depends on the locale, for example in France the acronym
+    UTC string is used instead of GMT:
+    
+    >>> get_timezone_gmt(dt, 'long', locale='fr_FR')
+    u'UTC-08:00'
+    
+    :param datetime: the ``datetime`` object; if `None`, the current date and
+                     time in UTC is used
+    :param width: either "long" or "short"
+    :param locale: the `Locale` object, or a locale string
+    :return: the GMT offset representation of the timezone
+    :rtype: `unicode`
+    :since: version 0.9
+    """
+    if datetime is None:
+        datetime = datetime_.utcnow()
+    elif isinstance(datetime, (int, long)):
+        datetime = datetime_.utcfromtimestamp(datetime).time()
+    if datetime.tzinfo is None:
+        datetime = datetime.replace(tzinfo=UTC)
+    locale = Locale.parse(locale)
+
+    offset = datetime.tzinfo.utcoffset(datetime)
+    seconds = offset.days * 24 * 60 * 60 + offset.seconds
+    hours, seconds = divmod(seconds, 3600)
+    if width == 'short':
+        pattern = u'%+03d%02d'
+    else:
+        pattern = locale.zone_formats['gmt'] % '%+03d:%02d'
+    return pattern % (hours, seconds // 60)
+
+def get_timezone_location(dt_or_tzinfo=None, locale=LC_TIME):
+    """Return a representation of the given timezone using "location format".
+    
+    The result depends on both the local display name of the country and the
+    city assocaited with the time zone:
+    
+    >>> from pytz import timezone
+    >>> tz = timezone('America/St_Johns')
+    >>> get_timezone_location(tz, locale='de_DE')
+    u"Kanada (St. John's)"
+    >>> tz = timezone('America/Mexico_City')
+    >>> get_timezone_location(tz, locale='de_DE')
+    u'Mexiko (Mexiko-Stadt)'
+    
+    If the timezone is associated with a country that uses only a single
+    timezone, just the localized country name is returned:
+    
+    >>> tz = timezone('Europe/Berlin')
+    >>> get_timezone_name(tz, locale='de_DE')
+    u'Deutschland'
+    
+    :param dt_or_tzinfo: the ``datetime`` or ``tzinfo`` object that determines
+                         the timezone; if `None`, the current date and time in
+                         UTC is assumed
+    :param locale: the `Locale` object, or a locale string
+    :return: the localized timezone name using location format
+    :rtype: `unicode`
+    :since: version 0.9
+    """
+    if dt_or_tzinfo is None or isinstance(dt_or_tzinfo, (int, long)):
+        dt = None
+        tzinfo = UTC
+    elif isinstance(dt_or_tzinfo, (datetime, time)):
+        dt = dt_or_tzinfo
+        if dt.tzinfo is not None:
+            tzinfo = dt.tzinfo
+        else:
+            tzinfo = UTC
+    else:
+        dt = None
+        tzinfo = dt_or_tzinfo
+    locale = Locale.parse(locale)
+
+    if hasattr(tzinfo, 'zone'):
+        zone = tzinfo.zone
+    else:
+        zone = tzinfo.tzname(dt or datetime.utcnow())
+
+    # Get the canonical time-zone code
+    zone = get_global('zone_aliases').get(zone, zone)
+
+    info = locale.time_zones.get(zone, {})
+
+    # Otherwise, if there is only one timezone for the country, return the
+    # localized country name
+    region_format = locale.zone_formats['region']
+    territory = get_global('zone_territories').get(zone)
+    if territory not in locale.territories:
+        territory = 'ZZ' # invalid/unknown
+    territory_name = locale.territories[territory]
+    if territory and len(get_global('territory_zones').get(territory, [])) == 1:
+        return region_format % (territory_name)
+
+    # Otherwise, include the city in the output
+    fallback_format = locale.zone_formats['fallback']
+    if 'city' in info:
+        city_name = info['city']
+    else:
+        metazone = get_global('meta_zones').get(zone)
+        metazone_info = locale.meta_zones.get(metazone, {})
+        if 'city' in metazone_info:
+            city_name = metainfo['city']
+        elif '/' in zone:
+            city_name = zone.split('/', 1)[1].replace('_', ' ')
+        else:
+            city_name = zone.replace('_', ' ')
+
+    return region_format % (fallback_format % {
+        '0': city_name,
+        '1': territory_name
+    })
+
+def get_timezone_name(dt_or_tzinfo=None, width='long', uncommon=False,
+                      locale=LC_TIME):
+    r"""Return the localized display name for the given timezone. The timezone
+    may be specified using a ``datetime`` or `tzinfo` object.
+