flufl.enum-3.3.2/ 0000775 0001750 0001750 00000000000 11744104775 014066 5 ustar barry barry 0000000 0000000 flufl.enum-3.3.2/setup.py 0000664 0001750 0001750 00000004236 11744103336 015575 0 ustar barry barry 0000000 0000000 # Copyright (C) 2004-2012 by Barry A. Warsaw
#
# This file is part of flufl.enum.
#
# flufl.enum is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# flufl.enum is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
# for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with flufl.enum. If not, see .
import distribute_setup
distribute_setup.use_setuptools()
from setup_helpers import (
description, get_version, long_description, require_python)
from setuptools import setup, find_packages
require_python(0x20600f0)
__version__ = get_version('flufl/enum/__init__.py')
setup(
name='flufl.enum',
version=__version__,
namespace_packages=['flufl'],
packages=find_packages(),
include_package_data=True,
maintainer='Barry Warsaw',
maintainer_email='barry@python.org',
description=description('README.rst'),
long_description=long_description('README.rst', 'flufl/enum/NEWS.rst'),
license='LGPLv3',
url='http://launchpad.net/flufl.enum',
download_url='https://launchpad.net/flufl.enum/+download',
test_suite='flufl.enum.tests',
classifiers=[
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'License :: OSI Approved :: '
'GNU Lesser General Public License v3 or later (LGPLv3+)',
'Operating System :: POSIX',
'Operating System :: Microsoft :: Windows',
'Operating System :: MacOS :: MacOS X',
'Programming Language :: Python',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Topic :: Software Development :: Libraries',
'Topic :: Software Development :: Libraries :: Python Modules',
]
)
flufl.enum-3.3.2/setup.cfg 0000664 0001750 0001750 00000000221 11744104775 015702 0 ustar barry barry 0000000 0000000 [build_sphinx]
source_dir = flufl/enum
[upload_docs]
upload_dir = build/sphinx/html
[egg_info]
tag_build =
tag_date = 0
tag_svn_revision = 0
flufl.enum-3.3.2/setup_helpers.py 0000664 0001750 0001750 00000012042 11744104324 017307 0 ustar barry barry 0000000 0000000 # Copyright (C) 2009-2012 by Barry A. Warsaw
#
# This file is part of flufl.enum
#
# flufl.enum is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# flufl.enum is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
# for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with flufl.enum. If not, see .
"""setup.py helper functions."""
from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
'description',
'find_doctests',
'get_version',
'long_description',
'require_python',
]
import os
import re
import sys
DEFAULT_VERSION_RE = re.compile(r'(?P\d+\.\d+(?:\.\d+)?)')
EMPTYSTRING = ''
__version__ = '2.1'
def require_python(minimum):
"""Require at least a minimum Python version.
The version number is expressed in terms of `sys.hexversion`. E.g. to
require a minimum of Python 2.6, use::
>>> require_python(0x206000f0)
:param minimum: Minimum Python version supported.
:type minimum: integer
"""
if sys.hexversion < minimum:
hversion = hex(minimum)[2:]
if len(hversion) % 2 != 0:
hversion = '0' + hversion
split = list(hversion)
parts = []
while split:
parts.append(int(''.join((split.pop(0), split.pop(0))), 16))
major, minor, micro, release = parts
if release == 0xf0:
print('Python {0}.{1}.{2} or better is required'.format(
major, minor, micro))
else:
print('Python {0}.{1}.{2} ({3}) or better is required'.format(
major, minor, micro, hex(release)[2:]))
sys.exit(1)
def get_version(filename, pattern=None):
"""Extract the __version__ from a file without importing it.
While you could get the __version__ by importing the module, the very act
of importing can cause unintended consequences. For example, Distribute's
automatic 2to3 support will break. Instead, this searches the file for a
line that starts with __version__, and extract the version number by
regular expression matching.
By default, two or three dot-separated digits are recognized, but by
passing a pattern parameter, you can recognize just about anything. Use
the `version` group name to specify the match group.
:param filename: The name of the file to search.
:type filename: string
:param pattern: Optional alternative regular expression pattern to use.
:type pattern: string
:return: The version that was extracted.
:rtype: string
"""
if pattern is None:
cre = DEFAULT_VERSION_RE
else:
cre = re.compile(pattern)
with open(filename) as fp:
for line in fp:
if line.startswith('__version__'):
mo = cre.search(line)
assert mo, 'No valid __version__ string found'
return mo.group('version')
raise AssertionError('No __version__ assignment found')
def find_doctests(start='.', extension='.rst'):
"""Find separate-file doctests in the package.
This is useful for Distribute's automatic 2to3 conversion support. The
`setup()` keyword argument `convert_2to3_doctests` requires file names,
which may be difficult to track automatically as you add new doctests.
:param start: Directory to start searching in (default is cwd)
:type start: string
:param extension: Doctest file extension (default is .txt)
:type extension: string
:return: The doctest files found.
:rtype: list
"""
doctests = []
for dirpath, dirnames, filenames in os.walk(start):
doctests.extend(os.path.join(dirpath, filename)
for filename in filenames
if filename.endswith(extension))
return doctests
def long_description(*filenames):
"""Provide a long description."""
res = ['']
for filename in filenames:
with open(filename) as fp:
for line in fp:
res.append(' ' + line)
res.append('')
res.append('\n')
return EMPTYSTRING.join(res)
def description(filename):
"""Provide a short description."""
# This ends up in the Summary header for PKG-INFO and it should be a
# one-liner. It will get rendered on the package page just below the
# package version header but above the long_description, which ironically
# gets stuff into the Description header. It should not include reST, so
# pick out the first single line after the double header.
with open(filename) as fp:
for lineno, line in enumerate(fp):
if lineno < 3:
continue
line = line.strip()
if len(line) > 0:
return line
flufl.enum-3.3.2/flufl/ 0000775 0001750 0001750 00000000000 11744104775 015176 5 ustar barry barry 0000000 0000000 flufl.enum-3.3.2/flufl/enum/ 0000775 0001750 0001750 00000000000 11744104775 016142 5 ustar barry barry 0000000 0000000 flufl.enum-3.3.2/flufl/enum/docs/ 0000775 0001750 0001750 00000000000 11744104775 017072 5 ustar barry barry 0000000 0000000 flufl.enum-3.3.2/flufl/enum/docs/using.rst 0000664 0001750 0001750 00000026464 11706071514 020755 0 ustar barry barry 0000000 0000000 ============================
Using the flufl.enum library
============================
The ``flufl.enum`` package provides yet another enumeration data type for
Python. While this is similar intent to the reject `PEP 354`_, this package
defines an alternative syntax and semantics.
An enumeration is a set of symbolic names bound to unique, constant integer
values. Within an enumeration, the values can be compared by identity, and
the enumeration itself can be iterated over. Enumeration items can be
converted to and from their integer equivalents, supporting use cases such as
storing enumeration values in a database.
Motivation
==========
[Lifted from PEP 354]
The properties of an enumeration are useful for defining an immutable, related
set of constant values that have a defined sequence but no inherent semantic
meaning. Classic examples are days of the week (Sunday through Saturday) and
school assessment grades ('A' through 'D', and 'F'). Other examples include
error status values and states within a defined process.
It is possible to simply define a sequence of values of some other basic type,
such as ``int`` or ``str``, to represent discrete arbitrary values. However,
an enumeration ensures that such values are distinct from any others, and that
operations without meaning ("Wednesday times two") are not defined for these
values.
Creating an Enum
================
Enumerations are created using the class syntax, which makes them easy to read
and write. Every enumeration value must have a unique integer value and the
only restriction on their names is that they must be valid Python identifiers.
To define an enumeration, derive from the Enum class and add attributes with
assignment to their integer values.
>>> from flufl.enum import Enum
>>> class Colors(Enum):
... red = 1
... green = 2
... blue = 3
Enumeration values are compared by identity.
>>> Colors.red is Colors.red
True
>>> Colors.blue is Colors.blue
True
>>> Colors.red is not Colors.blue
True
>>> Colors.blue is Colors.red
False
Enumeration values have nice, human readable string representations...
>>> print(Colors.red)
Colors.red
...while their repr has more information.
>>> print(repr(Colors.red))
The enumeration value names are available through the class members.
>>> for member in Colors.__members__:
... print(member)
red
green
blue
Let's say you wanted to encode an enumeration value in a database. You might
want to get the enumeration class object from an enumeration value.
>>> cls = Colors.red.enum
>>> print(cls.__name__)
Colors
Enums also have a property that contains just their item name.
>>> print(Colors.red.name)
red
>>> print(Colors.green.name)
green
>>> print(Colors.blue.name)
blue
The str and repr of the enumeration class also provides useful information.
>>> print(Colors)
>>> print(repr(Colors))
You can extend previously defined Enums by subclassing.
>>> class MoreColors(Colors):
... pink = 4
... cyan = 5
When extended in this way, the base enumeration's values are identical to the
same named values in the derived class.
>>> Colors.red is MoreColors.red
True
>>> Colors.blue is MoreColors.blue
True
However, these are not doing comparisons against the integer equivalent
values, because if you define an enumeration with similar item names and
integer values, they will not be identical.
>>> class OtherColors(Enum):
... red = 1
... blue = 2
... yellow = 3
>>> Colors.red is OtherColors.red
False
>>> Colors.blue is not OtherColors.blue
True
These enumeration values are not equal, nor do they hash equally.
>>> Colors.red == OtherColors.red
False
>>> len(set((Colors.red, OtherColors.red)))
2
Ordered comparisons between enumeration values are *not* supported. Enums are
not integers!
>>> Colors.red < Colors.blue
Traceback (most recent call last):
...
NotImplementedError
>>> Colors.red <= Colors.blue
Traceback (most recent call last):
...
NotImplementedError
>>> Colors.blue > Colors.green
Traceback (most recent call last):
...
NotImplementedError
>>> Colors.blue >= Colors.green
Traceback (most recent call last):
...
NotImplementedError
Equality comparisons are defined though.
>>> Colors.blue == Colors.blue
True
>>> Colors.green != Colors.blue
True
Enumeration values do not support ordered comparisons.
>>> Colors.red < Colors.blue
Traceback (most recent call last):
...
NotImplementedError
>>> Colors.red < 3
Traceback (most recent call last):
...
NotImplementedError
>>> Colors.red <= 3
Traceback (most recent call last):
...
NotImplementedError
>>> Colors.blue > 2
Traceback (most recent call last):
...
NotImplementedError
>>> Colors.blue >= 2
Traceback (most recent call last):
...
NotImplementedError
While equality comparisons are allowed, comparisons against non-enumeration
values will always compare not equal.
>>> Colors.green == 2
False
>>> Colors.blue == 3
False
>>> Colors.green != 3
True
>>> Colors.green == 'green'
False
If you really want the integer equivalent values, you can convert enumeration
values explicitly using the ``int()`` built-in. This is quite convenient for
storing enums in a database for example.
>>> int(Colors.red)
1
>>> int(Colors.green)
2
>>> int(Colors.blue)
3
You can also convert back to the enumeration value by calling the Enum class,
passing in the integer value for the item you want.
>>> Colors(1)
>>> Colors(2)
>>> Colors(3)
>>> Colors(1) is Colors.red
True
The Enum class also accepts the string name of the enumeration value.
>>> Colors('red')
>>> Colors('blue') is Colors.blue
True
You get exceptions though, if you try to use invalid arguments.
>>> Colors('magenta')
Traceback (most recent call last):
...
ValueError: magenta
>>> Colors(99)
Traceback (most recent call last):
...
ValueError: 99
The Enum base class also supports getitem syntax, exactly equivalent to the
class's call semantics.
>>> Colors[1]
>>> Colors[2]
>>> Colors[3]
>>> Colors[1] is Colors.red
True
>>> Colors['red']
>>> Colors['blue'] is Colors.blue
True
>>> Colors['magenta']
Traceback (most recent call last):
...
ValueError: magenta
>>> Colors[99]
Traceback (most recent call last):
...
ValueError: 99
The integer equivalent values serve another purpose. You may not define two
enumeration values with the same integer value.
>>> class Bad(Enum):
... cartman = 1
... stan = 2
... kyle = 3
... kenny = 3 # Oops!
... butters = 4
Traceback (most recent call last):
...
TypeError: Multiple enum values: 3
You also may not duplicate values in derived enumerations.
>>> class BadColors(Colors):
... yellow = 4
... chartreuse = 2 # Oops!
Traceback (most recent call last):
...
TypeError: Multiple enum values: 2
The Enum class support iteration. Enumeration values are returned in the
sorted order of their integer equivalent values.
>>> [v.name for v in MoreColors]
['red', 'green', 'blue', 'pink', 'cyan']
>>> [int(v) for v in MoreColors]
[1, 2, 3, 4, 5]
Enumeration values are hashable, so they can be used in dictionaries and sets.
>>> apples = {}
>>> apples[Colors.red] = 'red delicious'
>>> apples[Colors.green] = 'granny smith'
>>> for color in sorted(apples, key=int):
... print(color.name, '->', apples[color])
red -> red delicious
green -> granny smith
Pickling
========
Enumerations created with the class syntax can also be pickled and unpickled:
>>> from flufl.enum.tests.fruit import Fruit
>>> from pickle import dumps, loads
>>> Fruit.tomato is loads(dumps(Fruit.tomato))
True
Alternative API
===============
You can also create enumerations using the convenience function `make()`,
which takes an iterable object or dictionary to provide the item names and
values. `make()` is a static method.
.. note::
The `make_enum()` function from earlier releases is deprecated. Use
`make()` instead.
The first argument to `make()` is the name of the enumeration, and it returns
the so-named `Enum` subclass. The second argument is a `source` which can be
either an iterable or a dictionary. In the most basic usage, `source` returns
a sequence of strings which name the enumeration items. In this case, the
values are automatically assigned starting from 1::
>>> from flufl.enum import make
>>> make('Animals', ('ant', 'bee', 'cat', 'dog'))
The items in source can also be 2-tuples, where the first item is the
enumeration value name and the second is the integer value to assign to the
value. If 2-tuples are used, all items must be 2-tuples.
>>> def enumiter():
... start = 1
... while True:
... yield start
... start <<= 1
>>> make('Flags', zip(list('abcdefg'), enumiter()))
Differences from PEP 354
========================
Unlike PEP 354, enumeration values are not defined as a sequence of strings,
but as attributes of a class. This design was chosen because it was felt that
class syntax is more readable.
Unlike PEP 354, enumeration values require an explicit integer value. This
difference recognizes that enumerations often represent real-world values, or
must interoperate with external real-world systems. For example, to store an
enumeration in a database, it is better to convert it to an integer on the way
in and back to an enumeration on the way out. Providing an integer value also
provides an explicit ordering. However, there is no automatic conversion to
and from the integer values, because explicit is better than implicit.
Unlike PEP 354, this implementation does use a metaclass to define the
enumeration's syntax, and allows for extended base-enumerations so that the
common values in derived classes are identical (a singleton model). While PEP
354 dismisses this approach for its complexity, in practice any perceived
complexity, though minimal, is hidden from users of the enumeration.
Unlike PEP 354, enumeration values can only be tested by identity comparison.
This is to emphasis the fact that enumeration values are singletons, much like
``None``.
Acknowledgments
===============
The ``flufl.enum`` implementation is based on an example by Jeremy Hylton. It
has been modified and extended by Barry Warsaw for use in the `GNU Mailman`_
project. Ben Finney is the author of the earlier enumeration PEP 354.
.. _`PEP 354`: http://www.python.org/dev/peps/pep-0354/
.. _enum: http://cheeseshop.python.org/pypi/enum/
.. _`GNU Mailman`: http://www.list.org
flufl.enum-3.3.2/flufl/enum/docs/__init__.py 0000664 0001750 0001750 00000000000 11624413056 021161 0 ustar barry barry 0000000 0000000 flufl.enum-3.3.2/flufl/enum/NEWS.rst 0000664 0001750 0001750 00000004554 11744104714 017451 0 ustar barry barry 0000000 0000000 ===================
NEWS for flufl.enum
===================
3.3.2 (2012-04-19)
==================
* Add classifiers to setup.py and make the long description more compatible
with the Cheeseshop.
* Other changes to make the Cheeseshop page look nicer. (LP: #680136)
* setup_helper.py version 2.1.
3.3.1 (2012-01-19)
==================
* Fix Python 3 compatibility with Sphinx's conf.py ($python setup.py install).
3.3 (2012-01-19)
================
* Remove the dependency on 2to3 for Python 3 support; support Python 3
directly with a single code base.
* flufl.enum.make_enum() is deprecated in favor of flufl.enum.make() which
provides a better API. (LP: #839529)
* Updated to distribute 0.6.19.
* Moved all documentation to .rst suffix.
* Make test_deprecations() compatible with Python 3 and Python 2.
* Removed markup for pylint.
* Improve documentation to illustrate that enum values with similar names and
integer representations still do not hash equally. (Found by Jeroen
Vermeulen).
3.2 (2011-08-19)
================
* make_enum() accepts an optional `iterable` argument to provide the values
for the enums.
* The .enumclass and .enumname attributes are deprecated. Use .enum and
.name instead, respectively.
* Improve the documentation regarding ordered comparisons and equality
tests. (LP: #794853)
* make_enum() now enforces the use of valid Python identifiers. (LP: #803570)
3.1 (2011-03-01)
================
* New convenience function `make_enum()`. (Contributed by Michael Foord)
* Fix `from flufl.enum import *`.
* Enums created with the class syntax can be pickled and unpickled.
(Suggestion and basic implementation idea by Phillip Eby).
3.0.1 (2010-06-07)
==================
* Fixed typo which caused the package to break.
3.0 (2010-04-24)
================
* Package renamed to flufl.enum.
2.0.2 (2010-01-29)
==================
* Fixed some test failures when running under 2to3.
2.0.1 (2010-01-08)
==================
* Fix the manifest and clarify license.
2.0 (2010-01-07)
================
* Use Sphinx to build the documentation.
* Updates to better package Debian/Ubuntu.
* Use distribute_setup instead of ez_setup.
* Rename pep-xxxx.txt; this won't be submitted as a PEP.
* Remove dependencies on nose and setuptools_bzr
* Support Python 3 via 2to3.
Earlier
=======
Try `bzr log lp:flufl.enum` for details.
flufl.enum-3.3.2/flufl/enum/__init__.py 0000664 0001750 0001750 00000001646 11744077111 020253 0 ustar barry barry 0000000 0000000 # Copyright (C) 2004-2012 by Barry A. Warsaw
#
# This file is part of flufl.enum
#
# flufl.enum is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# flufl.enum is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
# for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with flufl.enum. If not, see .
"""Package init."""
from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
'Enum',
'__version__',
'make_enum',
]
__version__ = '3.3.2'
from ._enum import Enum, make, make_enum
flufl.enum-3.3.2/flufl/enum/conf.py 0000664 0001750 0001750 00000015331 11706107317 017435 0 ustar barry barry 0000000 0000000 # -*- coding: utf-8 -*-
#
# flufl.enum documentation build configuration file, created by
# sphinx-quickstart on Thu Jan 7 18:41:30 2010.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
from __future__ import print_function
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.append(os.path.abspath('.'))
# -- General configuration -----------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['../../_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8'
# The master toctree document.
master_doc = 'README'
# General information about the project.
project = 'flufl.enum'
copyright = '2004-2012, Barry A. Warsaw'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
from flufl.enum import __version__
# The short X.Y version.
version = __version__
# The full version, including alpha/beta/rc tags.
release = __version__
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of documents that shouldn't be included in the build.
#unused_docs = []
# List of directories, relative to source directory, that shouldn't be searched
# for source files.
exclude_trees = ['_build', 'build', 'flufl.enum.egg-info', 'distribute-0.6.10']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# " v documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['../../_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_use_modindex = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = ''
# Output file base name for HTML help builder.
htmlhelp_basename = 'fluflenumdoc'
# -- Options for LaTeX output --------------------------------------------------
# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('README.rst', 'fluflenum.tex', 'flufl.enum Documentation',
'Barry A. Warsaw', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_use_modindex = True
import errno
def index_html():
cwd = os.getcwd()
try:
os.chdir('build/sphinx/html')
try:
os.symlink('README.html', 'index.html')
except OSError as error:
if error.errno != errno.EEXIST:
raise
print('index.html -> README.html')
finally:
os.chdir(cwd)
import atexit
atexit.register(index_html)
flufl.enum-3.3.2/flufl/enum/_enum.py 0000664 0001750 0001750 00000021704 11706071514 017613 0 ustar barry barry 0000000 0000000 # Copyright (C) 2004-2012 by Barry A. Warsaw
#
# This file is part of flufl.enum
#
# flufl.enum is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# flufl.enum is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
# for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with flufl.enum. If not, see .
"""Python enumerations."""
from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
'Enum',
'make_enum',
]
import re
import warnings
COMMASPACE = ', '
SPACE = ' '
IDENTIFIER_RE = r'[a-zA-Z_][a-zA-Z0-0_]*'
class EnumMetaclass(type):
"""Meta class for Enums."""
def __init__(cls, name, bases, attributes):
"""Create an Enum class.
:param cls: The class being defined.
:param name: The name of the class.
:param bases: The class's base classes.
:param attributes: The class attributes.
"""
super(EnumMetaclass, cls).__init__(name, bases, attributes)
# Store EnumValues here for easy access.
cls._enums = {}
# Figure out the set of enum values on the base classes, to ensure
# that we don't get any duplicate values (which would screw up
# conversion from integer).
for basecls in cls.__mro__:
if hasattr(basecls, '_enums'):
cls._enums.update(basecls._enums)
# For each class attribute, create an EnumValue and store that back on
# the class instead of the int. Skip Python reserved names. Also add
# a mapping from the integer to the instance so we can return the same
# object on conversion.
for attr in attributes:
if not (attr.startswith('__') and attr.endswith('__')):
intval = attributes[attr]
enumval = EnumValue(cls, intval, attr)
if intval in cls._enums:
raise TypeError('Multiple enum values: %s' % intval)
# Store as an attribute on the class, and save the attr name
setattr(cls, attr, enumval)
cls._enums[intval] = attr
def __getattr__(cls, name):
if name == '__members__':
return cls._enums.values()
raise AttributeError(name)
def __repr__(cls):
enums = ['{0}: {1:d}'.format(
cls._enums[k], k) for k in sorted(cls._enums)]
return '<{0} {{{1}}}>'.format(cls.__name__, COMMASPACE.join(enums))
def __iter__(cls):
for i in sorted(cls._enums):
yield getattr(cls, cls._enums[i])
def __getitem__(cls, i):
# i can be an integer or a string
attr = cls._enums.get(i)
if attr is None:
# It wasn't an integer -- try attribute name
try:
return getattr(cls, i)
except (AttributeError, TypeError):
raise ValueError(i)
return getattr(cls, attr)
# Support both MyEnum[i] and MyEnum(i)
__call__ = __getitem__
class EnumValue:
"""Class to represent an enumeration value.
EnumValue('Color', 'red', 12) prints as 'Color.red' and can be converted
to the integer 12.
"""
def __init__(self, cls, value, name):
self._enum = cls
self._value = value
self._name = name
def __repr__(self):
return ''.format(
self._enum.__name__, self._name, self._value)
def __str__(self):
return '{0}.{1}'.format(self._enum.__name__, self._name)
def __int__(self):
return self._value
def __reduce__(self):
return getattr, (self._enum, self._name)
@property
def enum(self):
"""Return the class associated with the enum value."""
return self._enum
@property
def name(self):
"""Return the name of the enum value."""
return self._name
@property
def enumclass(self):
"""Return the class associated with the enum value."""
warnings.warn('.enumclass is deprecated; use .enum instead',
DeprecationWarning)
return self._enum
@property
def enumname(self):
"""Return the name of the enum value."""
warnings.warn('.enumname is deprecated; use .name instead',
DeprecationWarning)
return self._name
# Support only comparison by identity and equality. Ordered comparisions
# are not supported.
def __eq__(self, other):
return self is other
def __ne__(self, other):
return self is not other
def __lt__(self, other):
raise NotImplementedError
__gt__ = __lt__
__le__ = __lt__
__ge__ = __lt__
__hash__ = object.__hash__
# Define the Enum class using metaclass syntax compatible with both Python 2
# and Python 3.
Enum = EnumMetaclass(str('Enum'), (), {
'__doc__': 'The public API Enum class.',
})
def make(name, source):
"""Return an Enum class from a name and source.
This is a convenience function for defining a new enumeration given an
existing sequence. When an sequence is used, it is iterated over to get
the enumeration value items. The sequence iteration can either return
strings or 2-tuples. When strings are used, values are automatically
assigned starting from 1. When 2-tuples are used, the first item of the
tuple is a string and the second item is the integer value.
`source` must be homogeneous. You cannot mix string-only and 2-tuple
items in the sequence.
:param name: The resulting enum's class name.
:type name: byte string (or ASCII-only unicode string)
:param source: An object giving the enumeration value items.
:type source: A sequence of strings or 2-tuples.
:return: The new enumeration class.
:rtype: instance of `EnumMetaClass`
:raises ValueError: when a heterogeneous source is given, or when
non-identifiers are used as enumeration value names.
"""
namespace = {}
illegals = []
have_strings = None
try:
# Python 2
string_type = basestring
except NameError:
# Python 3
string_type = str
for i, item in enumerate(source, start=1):
if isinstance(item, string_type):
if have_strings is None:
have_strings = True
elif not have_strings:
raise ValueError('heterogeneous source')
namespace[item] = i
if re.match(IDENTIFIER_RE, item) is None:
illegals.append(item)
else:
if have_strings is None:
have_strings = False
elif have_strings:
raise ValueError('heterogeneous souce')
item_name, item_value = item
namespace[item_name] = item_value
if re.match(IDENTIFIER_RE, item_name) is None:
illegals.append(item_name)
if len(illegals) > 0:
raise ValueError('non-identifiers: {0}'.format(SPACE.join(illegals)))
return EnumMetaclass(str(name), (Enum,), namespace)
def make_enum(name, value_string, iterable=None):
"""Return an Enum class from a name and a value string.
*This function is deprecated; use `make()` instead.*
This is a convenience function for defining a new enumeration when you
don't care about the values of the items. The values are automatically
created by splitting the value string on spaces.
Normally, values are assigned to sequentially increasing integers starting
at one. With optional `iterable`, integer values are extracted one at a
time and assigned to the values.
:param name: The resulting enum's class name.
:type name: byte string (or ASCII-only unicode string)
:param value_string: A string of enumeration item names, separated by
spaces, e.g. 'one two three'.
:type value_string: byte string (or ASCII-only unicode string)
:param iterable: A sequence of integers.
:type iterable: iterator over int
:return: The new enumeration class.
:rtype: instance of `EnumMetaClass`
"""
warnings.warn('make_enum() is deprecated; use make() instead',
DeprecationWarning)
value_names = value_string.split()
illegals = [value for value in value_names
if re.match(IDENTIFIER_RE, value) is None]
if len(illegals) > 0:
raise ValueError('non-identifiers: {0}'.format(SPACE.join(illegals)))
if iterable is None:
namespace = dict((str(value), i)
for i, value in enumerate(value_names, 1))
else:
namespace = dict((str(value), i)
for i, value in zip(iterable, value_names))
return EnumMetaclass(str(name), (Enum,), namespace)
flufl.enum-3.3.2/flufl/enum/README.rst 0000664 0001750 0001750 00000005250 11706107435 017625 0 ustar barry barry 0000000 0000000 =========================================
flufl.enum - A Python enumeration package
=========================================
This package is called ``flufl.enum``. It is yet another Python enumeration
package, but with a slightly different take on syntax and semantics than
earlier such packages.
The goals of ``flufl.enum`` are to produce simple, specific, concise semantics
in an easy to read and write syntax. ``flufl.enum`` has just enough of the
features needed to make enumerations useful, but without a lot of extra
baggage to weigh them down. This work grew out of the Mailman 3.0 project and
it is the enum package used there. Until version 3.0, this package was called
``munepy``.
Requirements
============
``flufl.enum`` requires Python 2.6 or newer, and is compatible with Python 3.
Documentation
=============
A `simple guide`_ to using the library is available within this package, in
the form of doctests. The manual is also available online in the Cheeseshop
at:
http://package.python.org/flufl.enum
Project details
===============
The project home page is:
http://launchpad.net/flufl.enum
You should report bugs at:
http://bugs.launchpad.net/flufl.enum
You can download the latest version of the package either from the Cheeseshop:
http://pypi.python.org/pypi/flufl.enum
or from the Launchpad page above. Of course you can also just install it with
``pip`` or ``easy_install`` from the command line::
% sudo pip flufl.enum
% sudo easy_install flufl.enum
You can grab the latest development copy of the code using Bazaar, from the
Launchpad home page above. See http://bazaar-vcs.org for details on the
Bazaar distributed revision control system. If you have Bazaar installed, you
can grab your own branch of the code like this::
bzr branch lp:flufl.enum
You may contact the author via barry@python.org.
Copyright
=========
Copyright (C) 2004-2012 Barry A. Warsaw
This file is part of flufl.enum.
flufl.enum is free software: you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option) any
later version.
flufl.enum is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License along
with flufl.enum. If not, see .
Table of Contents
=================
.. toctree::
docs/using.rst
NEWS.rst
.. _`simple guide`: docs/using.html
flufl.enum-3.3.2/flufl/enum/tests/ 0000775 0001750 0001750 00000000000 11744104775 017304 5 ustar barry barry 0000000 0000000 flufl.enum-3.3.2/flufl/enum/tests/fruit.py 0000664 0001750 0001750 00000001656 11706071514 021007 0 ustar barry barry 0000000 0000000 # Copyright (C) 2010-2012 by Barry A. Warsaw
#
# This file is part of flufl.enum
#
# flufl.enum is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# flufl.enum is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
# for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with flufl.enum. If not, see .
"""A class for testing pickling."""
from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
'Fruit',
]
from flufl.enum import Enum
class Fruit(Enum):
kiwi = 1
banana = 2
tomato = 3
flufl.enum-3.3.2/flufl/enum/tests/__init__.py 0000664 0001750 0001750 00000000000 11624413056 021373 0 ustar barry barry 0000000 0000000 flufl.enum-3.3.2/flufl/enum/tests/test_enum.py 0000664 0001750 0001750 00000010220 11706071514 021644 0 ustar barry barry 0000000 0000000 # Copyright (C) 2011-2012 by Barry A. Warsaw
#
# This file is part of flufl.enum.
#
# flufl.enum is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# flufl.enum is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
# for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with flufl.enum. If not, see .
"""Additional package tests."""
from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
'TestEnum',
]
import unittest
import warnings
from flufl.enum import Enum, make, make_enum
class TestEnum(unittest.TestCase):
"""Additional unit tests."""
def test_deprecations(self):
# Enum.enumclass and Enum.enumname are deprecated.
class Animals(Enum):
ant = 1
bee = 2
cat = 3
with warnings.catch_warnings(record=True) as seen:
# Cause all warnings to always be triggered.
warnings.simplefilter('always')
Animals.ant.enumclass
self.assertEqual(len(seen), 1)
self.assertTrue(issubclass(seen[0].category, DeprecationWarning))
self.assertEqual(seen[0].message.args[0],
'.enumclass is deprecated; use .enum instead')
with warnings.catch_warnings(record=True) as seen:
# Cause all warnings to always be triggered.
warnings.simplefilter('always')
Animals.ant.enumname
self.assertEqual(len(seen), 1)
self.assertTrue(issubclass(seen[0].category, DeprecationWarning))
self.assertEqual(seen[0].message.args[0],
'.enumname is deprecated; use .name instead')
def test_make_enum_identifiers_bug_803570(self):
# LP: #803570 describes that make_enum() allows non-identifiers as
# enum value names.
try:
make_enum('Foo', '1 2 3')
except ValueError as exc:
self.assertEqual(exc.args[0], 'non-identifiers: 1 2 3')
else:
raise AssertionError('Expected a ValueError')
def test_make_enum_deprecated(self):
# LP: #839529: deprecate the make_enum() API and use the much better
# make() API.
with warnings.catch_warnings(record=True) as seen:
# Cause all warnings to always be triggered.
warnings.simplefilter('always')
make_enum('Foo', 'a b c')
self.assertEqual(len(seen), 1)
self.assertTrue(issubclass(seen[0].category, DeprecationWarning))
self.assertEqual(seen[0].message.args[0],
'make_enum() is deprecated; use make() instead')
def test_enum_make_not_all_2_tuples(self):
# If 2-tuples are used, all items must be 2-tuples.
self.assertRaises(ValueError, make, 'Animals', (
('ant', 1),
('bee', 2),
'cat',
('dog', 4),
))
self.assertRaises(ValueError, make, 'Animals', (
('ant', 1),
('bee', 2),
('cat',),
('dog', 4),
))
self.assertRaises(ValueError, make, 'Animals', (
('ant', 1),
('bee', 2),
('cat', 3, 'oops'),
('dog', 4),
))
def test_make_identifiers(self):
# Ensure that the make() interface also enforces identifiers.
try:
make('Foo', ('1', '2', '3'))
except ValueError as exc:
self.assertEqual(exc.args[0], 'non-identifiers: 1 2 3')
else:
raise AssertionError('Expected a ValueError')
try:
make('Foo', (('ant', 1), ('bee', 2), ('3', 'cat')))
except ValueError as exc:
self.assertEqual(exc.args[0], 'non-identifiers: 3')
else:
raise AssertionError('Expected a ValueError')
flufl.enum-3.3.2/flufl/enum/tests/test_documentation.py 0000664 0001750 0001750 00000005061 11706071514 023560 0 ustar barry barry 0000000 0000000 # Copyright (C) 2004-2012 by Barry A. Warsaw
#
# This file is part of flufl.enum.
#
# flufl.enum is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# flufl.enum is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
# for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with flufl.enum. If not, see .
"""Test harness for doctests."""
from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
'additional_tests',
]
import os
import atexit
import doctest
import unittest
from pkg_resources import (
resource_filename, resource_exists, resource_listdir, cleanup_resources)
COMMASPACE = ', '
DOT = '.'
DOCTEST_FLAGS = (
doctest.ELLIPSIS |
doctest.NORMALIZE_WHITESPACE |
doctest.REPORT_NDIFF)
def stop():
"""Call into pdb.set_trace()"""
# Do the import here so that you get the wacky special hacked pdb instead
# of Python's normal pdb.
import pdb
pdb.set_trace()
def setup(testobj):
"""Test setup."""
# Make sure future statements in our doctests match the Python code. When
# run with 2to3, the future import gets removed and these names are not
# defined.
try:
testobj.globs['absolute_import'] = absolute_import
testobj.globs['print_function'] = print_function
testobj.globs['unicode_literals'] = unicode_literals
except NameError:
pass
testobj.globs['stop'] = stop
def additional_tests():
"Run the doc tests (README.rst and docs/*, if any exist)"
doctest_files = [
os.path.abspath(resource_filename('flufl.enum', 'README.rst'))]
if resource_exists('flufl.enum', 'docs'):
for name in resource_listdir('flufl.enum', 'docs'):
if name.endswith('.rst'):
doctest_files.append(
os.path.abspath(
resource_filename('flufl.enum', 'docs/%s' % name)))
kwargs = dict(module_relative=False,
optionflags=DOCTEST_FLAGS,
setUp=setup,
)
atexit.register(cleanup_resources)
return unittest.TestSuite((
doctest.DocFileSuite(*doctest_files, **kwargs)))
flufl.enum-3.3.2/flufl/__init__.py 0000664 0001750 0001750 00000001566 11706071514 017307 0 ustar barry barry 0000000 0000000 # Copyright (C) 2004-2012 by Barry A. Warsaw
#
# This file is part of flufl.enum.
#
# flufl.enum is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# flufl.enum is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with flufl.enum. If not, see .
# this is a namespace package
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)
flufl.enum-3.3.2/distribute_setup.py 0000664 0001750 0001750 00000036615 11643700345 020042 0 ustar barry barry 0000000 0000000 #!python
"""Bootstrap distribute installation
If you want to use setuptools in your package's setup.py, just include this
file in the same directory with it, and add this to the top of your setup.py::
from distribute_setup import use_setuptools
use_setuptools()
If you want to require a specific version of setuptools, set a download
mirror, or use an alternate download directory, you can do so by supplying
the appropriate options to ``use_setuptools()``.
This file can also be run as a script to install or upgrade setuptools.
"""
import os
import sys
import time
import fnmatch
import tempfile
import tarfile
from distutils import log
try:
from site import USER_SITE
except ImportError:
USER_SITE = None
try:
import subprocess
def _python_cmd(*args):
args = (sys.executable,) + args
return subprocess.call(args) == 0
except ImportError:
# will be used for python 2.3
def _python_cmd(*args):
args = (sys.executable,) + args
# quoting arguments if windows
if sys.platform == 'win32':
def quote(arg):
if ' ' in arg:
return '"%s"' % arg
return arg
args = [quote(arg) for arg in args]
return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
DEFAULT_VERSION = "0.6.19"
DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
SETUPTOOLS_FAKED_VERSION = "0.6c11"
SETUPTOOLS_PKG_INFO = """\
Metadata-Version: 1.0
Name: setuptools
Version: %s
Summary: xxxx
Home-page: xxx
Author: xxx
Author-email: xxx
License: xxx
Description: xxx
""" % SETUPTOOLS_FAKED_VERSION
def _install(tarball):
# extracting the tarball
tmpdir = tempfile.mkdtemp()
log.warn('Extracting in %s', tmpdir)
old_wd = os.getcwd()
try:
os.chdir(tmpdir)
tar = tarfile.open(tarball)
_extractall(tar)
tar.close()
# going in the directory
subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
os.chdir(subdir)
log.warn('Now working in %s', subdir)
# installing
log.warn('Installing Distribute')
if not _python_cmd('setup.py', 'install'):
log.warn('Something went wrong during the installation.')
log.warn('See the error message above.')
finally:
os.chdir(old_wd)
def _build_egg(egg, tarball, to_dir):
# extracting the tarball
tmpdir = tempfile.mkdtemp()
log.warn('Extracting in %s', tmpdir)
old_wd = os.getcwd()
try:
os.chdir(tmpdir)
tar = tarfile.open(tarball)
_extractall(tar)
tar.close()
# going in the directory
subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
os.chdir(subdir)
log.warn('Now working in %s', subdir)
# building an egg
log.warn('Building a Distribute egg in %s', to_dir)
_python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
finally:
os.chdir(old_wd)
# returning the result
log.warn(egg)
if not os.path.exists(egg):
raise IOError('Could not build the egg.')
def _do_download(version, download_base, to_dir, download_delay):
egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg'
% (version, sys.version_info[0], sys.version_info[1]))
if not os.path.exists(egg):
tarball = download_setuptools(version, download_base,
to_dir, download_delay)
_build_egg(egg, tarball, to_dir)
sys.path.insert(0, egg)
import setuptools
setuptools.bootstrap_install_from = egg
def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
to_dir=os.curdir, download_delay=15, no_fake=True):
# making sure we use the absolute path
to_dir = os.path.abspath(to_dir)
was_imported = 'pkg_resources' in sys.modules or \
'setuptools' in sys.modules
try:
try:
import pkg_resources
if not hasattr(pkg_resources, '_distribute'):
if not no_fake:
_fake_setuptools()
raise ImportError
except ImportError:
return _do_download(version, download_base, to_dir, download_delay)
try:
pkg_resources.require("distribute>="+version)
return
except pkg_resources.VersionConflict:
e = sys.exc_info()[1]
if was_imported:
sys.stderr.write(
"The required version of distribute (>=%s) is not available,\n"
"and can't be installed while this script is running. Please\n"
"install a more recent version first, using\n"
"'easy_install -U distribute'."
"\n\n(Currently using %r)\n" % (version, e.args[0]))
sys.exit(2)
else:
del pkg_resources, sys.modules['pkg_resources'] # reload ok
return _do_download(version, download_base, to_dir,
download_delay)
except pkg_resources.DistributionNotFound:
return _do_download(version, download_base, to_dir,
download_delay)
finally:
if not no_fake:
_create_fake_setuptools_pkg_info(to_dir)
def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
to_dir=os.curdir, delay=15):
"""Download distribute from a specified location and return its filename
`version` should be a valid distribute version number that is available
as an egg for download under the `download_base` URL (which should end
with a '/'). `to_dir` is the directory where the egg will be downloaded.
`delay` is the number of seconds to pause before an actual download
attempt.
"""
# making sure we use the absolute path
to_dir = os.path.abspath(to_dir)
try:
from urllib.request import urlopen
except ImportError:
from urllib2 import urlopen
tgz_name = "distribute-%s.tar.gz" % version
url = download_base + tgz_name
saveto = os.path.join(to_dir, tgz_name)
src = dst = None
if not os.path.exists(saveto): # Avoid repeated downloads
try:
log.warn("Downloading %s", url)
src = urlopen(url)
# Read/write all in one block, so we don't create a corrupt file
# if the download is interrupted.
data = src.read()
dst = open(saveto, "wb")
dst.write(data)
finally:
if src:
src.close()
if dst:
dst.close()
return os.path.realpath(saveto)
def _no_sandbox(function):
def __no_sandbox(*args, **kw):
try:
from setuptools.sandbox import DirectorySandbox
if not hasattr(DirectorySandbox, '_old'):
def violation(*args):
pass
DirectorySandbox._old = DirectorySandbox._violation
DirectorySandbox._violation = violation
patched = True
else:
patched = False
except ImportError:
patched = False
try:
return function(*args, **kw)
finally:
if patched:
DirectorySandbox._violation = DirectorySandbox._old
del DirectorySandbox._old
return __no_sandbox
def _patch_file(path, content):
"""Will backup the file then patch it"""
existing_content = open(path).read()
if existing_content == content:
# already patched
log.warn('Already patched.')
return False
log.warn('Patching...')
_rename_path(path)
f = open(path, 'w')
try:
f.write(content)
finally:
f.close()
return True
_patch_file = _no_sandbox(_patch_file)
def _same_content(path, content):
return open(path).read() == content
def _rename_path(path):
new_name = path + '.OLD.%s' % time.time()
log.warn('Renaming %s into %s', path, new_name)
os.rename(path, new_name)
return new_name
def _remove_flat_installation(placeholder):
if not os.path.isdir(placeholder):
log.warn('Unkown installation at %s', placeholder)
return False
found = False
for file in os.listdir(placeholder):
if fnmatch.fnmatch(file, 'setuptools*.egg-info'):
found = True
break
if not found:
log.warn('Could not locate setuptools*.egg-info')
return
log.warn('Removing elements out of the way...')
pkg_info = os.path.join(placeholder, file)
if os.path.isdir(pkg_info):
patched = _patch_egg_dir(pkg_info)
else:
patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO)
if not patched:
log.warn('%s already patched.', pkg_info)
return False
# now let's move the files out of the way
for element in ('setuptools', 'pkg_resources.py', 'site.py'):
element = os.path.join(placeholder, element)
if os.path.exists(element):
_rename_path(element)
else:
log.warn('Could not find the %s element of the '
'Setuptools distribution', element)
return True
_remove_flat_installation = _no_sandbox(_remove_flat_installation)
def _after_install(dist):
log.warn('After install bootstrap.')
placeholder = dist.get_command_obj('install').install_purelib
_create_fake_setuptools_pkg_info(placeholder)
def _create_fake_setuptools_pkg_info(placeholder):
if not placeholder or not os.path.exists(placeholder):
log.warn('Could not find the install location')
return
pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1])
setuptools_file = 'setuptools-%s-py%s.egg-info' % \
(SETUPTOOLS_FAKED_VERSION, pyver)
pkg_info = os.path.join(placeholder, setuptools_file)
if os.path.exists(pkg_info):
log.warn('%s already exists', pkg_info)
return
log.warn('Creating %s', pkg_info)
f = open(pkg_info, 'w')
try:
f.write(SETUPTOOLS_PKG_INFO)
finally:
f.close()
pth_file = os.path.join(placeholder, 'setuptools.pth')
log.warn('Creating %s', pth_file)
f = open(pth_file, 'w')
try:
f.write(os.path.join(os.curdir, setuptools_file))
finally:
f.close()
_create_fake_setuptools_pkg_info = _no_sandbox(_create_fake_setuptools_pkg_info)
def _patch_egg_dir(path):
# let's check if it's already patched
pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
if os.path.exists(pkg_info):
if _same_content(pkg_info, SETUPTOOLS_PKG_INFO):
log.warn('%s already patched.', pkg_info)
return False
_rename_path(path)
os.mkdir(path)
os.mkdir(os.path.join(path, 'EGG-INFO'))
pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
f = open(pkg_info, 'w')
try:
f.write(SETUPTOOLS_PKG_INFO)
finally:
f.close()
return True
_patch_egg_dir = _no_sandbox(_patch_egg_dir)
def _before_install():
log.warn('Before install bootstrap.')
_fake_setuptools()
def _under_prefix(location):
if 'install' not in sys.argv:
return True
args = sys.argv[sys.argv.index('install')+1:]
for index, arg in enumerate(args):
for option in ('--root', '--prefix'):
if arg.startswith('%s=' % option):
top_dir = arg.split('root=')[-1]
return location.startswith(top_dir)
elif arg == option:
if len(args) > index:
top_dir = args[index+1]
return location.startswith(top_dir)
if arg == '--user' and USER_SITE is not None:
return location.startswith(USER_SITE)
return True
def _fake_setuptools():
log.warn('Scanning installed packages')
try:
import pkg_resources
except ImportError:
# we're cool
log.warn('Setuptools or Distribute does not seem to be installed.')
return
ws = pkg_resources.working_set
try:
setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools',
replacement=False))
except TypeError:
# old distribute API
setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools'))
if setuptools_dist is None:
log.warn('No setuptools distribution found')
return
# detecting if it was already faked
setuptools_location = setuptools_dist.location
log.warn('Setuptools installation detected at %s', setuptools_location)
# if --root or --preix was provided, and if
# setuptools is not located in them, we don't patch it
if not _under_prefix(setuptools_location):
log.warn('Not patching, --root or --prefix is installing Distribute'
' in another location')
return
# let's see if its an egg
if not setuptools_location.endswith('.egg'):
log.warn('Non-egg installation')
res = _remove_flat_installation(setuptools_location)
if not res:
return
else:
log.warn('Egg installation')
pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO')
if (os.path.exists(pkg_info) and
_same_content(pkg_info, SETUPTOOLS_PKG_INFO)):
log.warn('Already patched.')
return
log.warn('Patching...')
# let's create a fake egg replacing setuptools one
res = _patch_egg_dir(setuptools_location)
if not res:
return
log.warn('Patched done.')
_relaunch()
def _relaunch():
log.warn('Relaunching...')
# we have to relaunch the process
# pip marker to avoid a relaunch bug
if sys.argv[:3] == ['-c', 'install', '--single-version-externally-managed']:
sys.argv[0] = 'setup.py'
args = [sys.executable] + sys.argv
sys.exit(subprocess.call(args))
def _extractall(self, path=".", members=None):
"""Extract all members from the archive to the current working
directory and set owner, modification time and permissions on
directories afterwards. `path' specifies a different directory
to extract to. `members' is optional and must be a subset of the
list returned by getmembers().
"""
import copy
import operator
from tarfile import ExtractError
directories = []
if members is None:
members = self
for tarinfo in members:
if tarinfo.isdir():
# Extract directories with a safe mode.
directories.append(tarinfo)
tarinfo = copy.copy(tarinfo)
tarinfo.mode = 448 # decimal for oct 0700
self.extract(tarinfo, path)
# Reverse sort directories.
if sys.version_info < (2, 4):
def sorter(dir1, dir2):
return cmp(dir1.name, dir2.name)
directories.sort(sorter)
directories.reverse()
else:
directories.sort(key=operator.attrgetter('name'), reverse=True)
# Set correct owner, mtime and filemode on directories.
for tarinfo in directories:
dirpath = os.path.join(path, tarinfo.name)
try:
self.chown(tarinfo, dirpath)
self.utime(tarinfo, dirpath)
self.chmod(tarinfo, dirpath)
except ExtractError:
e = sys.exc_info()[1]
if self.errorlevel > 1:
raise
else:
self._dbg(1, "tarfile: %s" % e)
def main(argv, version=DEFAULT_VERSION):
"""Install or upgrade setuptools and EasyInstall"""
tarball = download_setuptools()
_install(tarball)
if __name__ == '__main__':
main(sys.argv[1:])
flufl.enum-3.3.2/PKG-INFO 0000664 0001750 0001750 00000013063 11744104775 015166 0 ustar barry barry 0000000 0000000 Metadata-Version: 1.1
Name: flufl.enum
Version: 3.3.2
Summary: A Python enumeration package.
Home-page: http://launchpad.net/flufl.enum
Author: Barry Warsaw
Author-email: barry@python.org
License: LGPLv3
Download-URL: https://launchpad.net/flufl.enum/+download
Description: ==========
flufl.enum
==========
A Python enumeration package.
The ``flufl.enum`` library is yet another Python enumeration package. Its
goal is to provide simple, specific, concise semantics in an easy to read and
write syntax. ``flufl.enum`` has just enough of the features needed to make
enumerations useful, but without a lot of extra baggage to weigh them down.
This work grew out of the Mailman 3.0 project.
License
=======
This file is part of flufl.enum.
flufl.enum is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, version 3 of the License.
flufl.enum is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with flufl.enum. If not, see .
===================
NEWS for flufl.enum
===================
3.3.2 (2012-04-19)
==================
* Add classifiers to setup.py and make the long description more compatible
with the Cheeseshop.
* Other changes to make the Cheeseshop page look nicer. (LP: #680136)
* setup_helper.py version 2.1.
3.3.1 (2012-01-19)
==================
* Fix Python 3 compatibility with Sphinx's conf.py ($python setup.py install).
3.3 (2012-01-19)
================
* Remove the dependency on 2to3 for Python 3 support; support Python 3
directly with a single code base.
* flufl.enum.make_enum() is deprecated in favor of flufl.enum.make() which
provides a better API. (LP: #839529)
* Updated to distribute 0.6.19.
* Moved all documentation to .rst suffix.
* Make test_deprecations() compatible with Python 3 and Python 2.
* Removed markup for pylint.
* Improve documentation to illustrate that enum values with similar names and
integer representations still do not hash equally. (Found by Jeroen
Vermeulen).
3.2 (2011-08-19)
================
* make_enum() accepts an optional `iterable` argument to provide the values
for the enums.
* The .enumclass and .enumname attributes are deprecated. Use .enum and
.name instead, respectively.
* Improve the documentation regarding ordered comparisons and equality
tests. (LP: #794853)
* make_enum() now enforces the use of valid Python identifiers. (LP: #803570)
3.1 (2011-03-01)
================
* New convenience function `make_enum()`. (Contributed by Michael Foord)
* Fix `from flufl.enum import *`.
* Enums created with the class syntax can be pickled and unpickled.
(Suggestion and basic implementation idea by Phillip Eby).
3.0.1 (2010-06-07)
==================
* Fixed typo which caused the package to break.
3.0 (2010-04-24)
================
* Package renamed to flufl.enum.
2.0.2 (2010-01-29)
==================
* Fixed some test failures when running under 2to3.
2.0.1 (2010-01-08)
==================
* Fix the manifest and clarify license.
2.0 (2010-01-07)
================
* Use Sphinx to build the documentation.
* Updates to better package Debian/Ubuntu.
* Use distribute_setup instead of ez_setup.
* Rename pep-xxxx.txt; this won't be submitted as a PEP.
* Remove dependencies on nose and setuptools_bzr
* Support Python 3 via 2to3.
Earlier
=======
Try `bzr log lp:flufl.enum` for details.
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)
Classifier: Operating System :: POSIX
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development :: Libraries :: Python Modules
flufl.enum-3.3.2/template.py 0000664 0001750 0001750 00000001466 11706071514 016252 0 ustar barry barry 0000000 0000000 # Copyright (C) 2011-2012 by Barry A. Warsaw
#
# This file is part of flufl.enum
#
# flufl.enum is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# flufl.enum is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
# for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with flufl.enum. If not, see .
"""Module contents."""
from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
]
flufl.enum-3.3.2/README.rst 0000664 0001750 0001750 00000002034 11744101644 015544 0 ustar barry barry 0000000 0000000 ==========
flufl.enum
==========
A Python enumeration package.
The ``flufl.enum`` library is yet another Python enumeration package. Its
goal is to provide simple, specific, concise semantics in an easy to read and
write syntax. ``flufl.enum`` has just enough of the features needed to make
enumerations useful, but without a lot of extra baggage to weigh them down.
This work grew out of the Mailman 3.0 project.
License
=======
This file is part of flufl.enum.
flufl.enum is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, version 3 of the License.
flufl.enum is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with flufl.enum. If not, see .
flufl.enum-3.3.2/flufl.enum.egg-info/ 0000775 0001750 0001750 00000000000 11744104775 017633 5 ustar barry barry 0000000 0000000 flufl.enum-3.3.2/flufl.enum.egg-info/SOURCES.txt 0000664 0001750 0001750 00000001113 11744104775 021513 0 ustar barry barry 0000000 0000000 README.rst
distribute_setup.py
setup.cfg
setup.py
setup_helpers.py
template.py
flufl/__init__.py
flufl.enum.egg-info/PKG-INFO
flufl.enum.egg-info/PKG-INFO~
flufl.enum.egg-info/SOURCES.txt
flufl.enum.egg-info/dependency_links.txt
flufl.enum.egg-info/namespace_packages.txt
flufl.enum.egg-info/top_level.txt
flufl/enum/NEWS.rst
flufl/enum/README.rst
flufl/enum/__init__.py
flufl/enum/_enum.py
flufl/enum/conf.py
flufl/enum/docs/__init__.py
flufl/enum/docs/using.rst
flufl/enum/tests/__init__.py
flufl/enum/tests/fruit.py
flufl/enum/tests/test_documentation.py
flufl/enum/tests/test_enum.py flufl.enum-3.3.2/flufl.enum.egg-info/top_level.txt 0000664 0001750 0001750 00000000006 11744104775 022361 0 ustar barry barry 0000000 0000000 flufl
flufl.enum-3.3.2/flufl.enum.egg-info/dependency_links.txt 0000664 0001750 0001750 00000000001 11744104775 023701 0 ustar barry barry 0000000 0000000
flufl.enum-3.3.2/flufl.enum.egg-info/namespace_packages.txt 0000664 0001750 0001750 00000000006 11744104775 024162 0 ustar barry barry 0000000 0000000 flufl
flufl.enum-3.3.2/flufl.enum.egg-info/PKG-INFO 0000664 0001750 0001750 00000013063 11744104775 020733 0 ustar barry barry 0000000 0000000 Metadata-Version: 1.1
Name: flufl.enum
Version: 3.3.2
Summary: A Python enumeration package.
Home-page: http://launchpad.net/flufl.enum
Author: Barry Warsaw
Author-email: barry@python.org
License: LGPLv3
Download-URL: https://launchpad.net/flufl.enum/+download
Description: ==========
flufl.enum
==========
A Python enumeration package.
The ``flufl.enum`` library is yet another Python enumeration package. Its
goal is to provide simple, specific, concise semantics in an easy to read and
write syntax. ``flufl.enum`` has just enough of the features needed to make
enumerations useful, but without a lot of extra baggage to weigh them down.
This work grew out of the Mailman 3.0 project.
License
=======
This file is part of flufl.enum.
flufl.enum is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, version 3 of the License.
flufl.enum is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with flufl.enum. If not, see .
===================
NEWS for flufl.enum
===================
3.3.2 (2012-04-19)
==================
* Add classifiers to setup.py and make the long description more compatible
with the Cheeseshop.
* Other changes to make the Cheeseshop page look nicer. (LP: #680136)
* setup_helper.py version 2.1.
3.3.1 (2012-01-19)
==================
* Fix Python 3 compatibility with Sphinx's conf.py ($python setup.py install).
3.3 (2012-01-19)
================
* Remove the dependency on 2to3 for Python 3 support; support Python 3
directly with a single code base.
* flufl.enum.make_enum() is deprecated in favor of flufl.enum.make() which
provides a better API. (LP: #839529)
* Updated to distribute 0.6.19.
* Moved all documentation to .rst suffix.
* Make test_deprecations() compatible with Python 3 and Python 2.
* Removed markup for pylint.
* Improve documentation to illustrate that enum values with similar names and
integer representations still do not hash equally. (Found by Jeroen
Vermeulen).
3.2 (2011-08-19)
================
* make_enum() accepts an optional `iterable` argument to provide the values
for the enums.
* The .enumclass and .enumname attributes are deprecated. Use .enum and
.name instead, respectively.
* Improve the documentation regarding ordered comparisons and equality
tests. (LP: #794853)
* make_enum() now enforces the use of valid Python identifiers. (LP: #803570)
3.1 (2011-03-01)
================
* New convenience function `make_enum()`. (Contributed by Michael Foord)
* Fix `from flufl.enum import *`.
* Enums created with the class syntax can be pickled and unpickled.
(Suggestion and basic implementation idea by Phillip Eby).
3.0.1 (2010-06-07)
==================
* Fixed typo which caused the package to break.
3.0 (2010-04-24)
================
* Package renamed to flufl.enum.
2.0.2 (2010-01-29)
==================
* Fixed some test failures when running under 2to3.
2.0.1 (2010-01-08)
==================
* Fix the manifest and clarify license.
2.0 (2010-01-07)
================
* Use Sphinx to build the documentation.
* Updates to better package Debian/Ubuntu.
* Use distribute_setup instead of ez_setup.
* Rename pep-xxxx.txt; this won't be submitted as a PEP.
* Remove dependencies on nose and setuptools_bzr
* Support Python 3 via 2to3.
Earlier
=======
Try `bzr log lp:flufl.enum` for details.
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)
Classifier: Operating System :: POSIX
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development :: Libraries :: Python Modules
flufl.enum-3.3.2/flufl.enum.egg-info/PKG-INFO~ 0000664 0001750 0001750 00000012552 11744103671 021125 0 ustar barry barry 0000000 0000000 Metadata-Version: 1.1
Name: flufl.enum
Version: 3.3.2
Summary: A Python enumeration package.
Home-page: http://launchpad.net/flufl.enum
Author: Barry Warsaw
Author-email: barry@python.org
License: LGPLv3
Download-URL: https://launchpad.net/flufl.enum/+download
Description:
==========
flufl.enum
==========
A Python enumeration package.
The ``flufl.enum`` library is yet another Python enumeration package. Its
goal is to provide simple, specific, concise semantics in an easy to read and
write syntax. ``flufl.enum`` has just enough of the features needed to make
enumerations useful, but without a lot of extra baggage to weigh them down.
This work grew out of the Mailman 3.0 project.
License
=======
This file is part of flufl.enum.
flufl.enum is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, version 3 of the License.
flufl.enum is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with flufl.enum. If not, see .
===================
NEWS for flufl.enum
===================
3.3.2 (2012-04-19)
==================
* Add classifiers to setup.py and make the long description more compatible
with the Cheeseshop.
3.3.1 (2012-01-19)
==================
* Fix Python 3 compatibility with Sphinx's conf.py ($python setup.py install).
3.3 (2012-01-19)
================
* Remove the dependency on 2to3 for Python 3 support; support Python 3
directly with a single code base.
* flufl.enum.make_enum() is deprecated in favor of flufl.enum.make() which
provides a better API. (LP: #839529)
* Updated to distribute 0.6.19.
* Moved all documentation to .rst suffix.
* Make test_deprecations() compatible with Python 3 and Python 2.
* Removed markup for pylint.
* Improve documentation to illustrate that enum values with similar names and
integer representations still do not hash equally. (Found by Jeroen
Vermeulen).
3.2 (2011-08-19)
================
* make_enum() accepts an optional `iterable` argument to provide the values
for the enums.
* The .enumclass and .enumname attributes are deprecated. Use .enum and
.name instead, respectively.
* Improve the documentation regarding ordered comparisons and equality
tests. (LP: #794853)
* make_enum() now enforces the use of valid Python identifiers. (LP: #803570)
3.1 (2011-03-01)
================
* New convenience function `make_enum()`. (Contributed by Michael Foord)
* Fix `from flufl.enum import *`.
* Enums created with the class syntax can be pickled and unpickled.
(Suggestion and basic implementation idea by Phillip Eby).
3.0.1 (2010-06-07)
==================
* Fixed typo which caused the package to break.
3.0 (2010-04-24)
================
* Package renamed to flufl.enum.
2.0.2 (2010-01-29)
==================
* Fixed some test failures when running under 2to3.
2.0.1 (2010-01-08)
==================
* Fix the manifest and clarify license.
2.0 (2010-01-07)
================
* Use Sphinx to build the documentation.
* Updates to better package Debian/Ubuntu.
* Use distribute_setup instead of ez_setup.
* Rename pep-xxxx.txt; this won't be submitted as a PEP.
* Remove dependencies on nose and setuptools_bzr
* Support Python 3 via 2to3.
Earlier
=======
Try `bzr log` for details.
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)
Classifier: Operating System :: POSIX
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development :: Libraries :: Python Modules