[Python-modules-commits] [python-attrs] 01/06: Import python-attrs_16.0.0.orig.tar.gz

Tristan Seligmann mithrandi at moszumanska.debian.org
Sun Jun 26 18:00:16 UTC 2016


This is an automated email from the git hooks/post-receive script.

mithrandi pushed a commit to branch master
in repository python-attrs.

commit 3d518ce7a5493e4ff32fb21ce0e1ae29d9b60d21
Author: Tristan Seligmann <mithrandi at mithrandi.net>
Date:   Thu Jun 23 19:50:02 2016 +0200

    Import python-attrs_16.0.0.orig.tar.gz
---
 .coveragerc                     |  12 ++
 .travis.yml                     |  16 ++-
 docs/license.rst => AUTHORS.rst |  13 +-
 CHANGELOG.rst                   |  50 +++++--
 CODE_OF_CONDUCT.rst             |  62 ++++++---
 CONTRIBUTING.rst                |   6 +-
 README.rst                      |  12 +-
 dev-requirements.txt            |   5 +
 docs/api.rst                    |   2 +-
 docs/contributing.rst           |   2 +
 docs/examples.rst               |  86 +++++++++++-
 docs/extending.rst              |   2 +-
 docs/license.rst                |  18 +--
 docs/why.rst                    |   8 +-
 setup.cfg                       |   2 +-
 setup.py                        |  22 ++-
 src/attr/__init__.py            |   4 +-
 src/attr/_compat.py             |  16 +++
 src/attr/_funcs.py              |  18 ++-
 src/attr/_make.py               |  86 +++++++++---
 src/attr/filters.py             |   5 +-
 src/attr/validators.py          |   6 +-
 tests/__init__.py               |  39 +++++-
 tests/test_dark_magic.py        |  68 +++++++--
 tests/test_dunders.py           | 163 ++++++++++++++++------
 tests/test_funcs.py             |  61 ++++++--
 tests/test_make.py              |  16 ++-
 tests/test_slots.py             | 300 ++++++++++++++++++++++++++++++++++++++++
 tox.ini                         |  20 ++-
 29 files changed, 918 insertions(+), 202 deletions(-)

diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 0000000..d17a6aa
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,12 @@
+[run]
+branch = True
+source = attr
+
+[paths]
+source =
+   src/attr
+   .tox/*/lib/python*/site-packages/attr
+   .tox/pypy/site-packages/attr
+
+[report]
+show_missing = True
diff --git a/.travis.yml b/.travis.yml
index 2a70928..088f7dd 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,12 +8,8 @@ language: python
 
 matrix:
   include:
-    - python: "2.6"  # these are just to make travis's UI a bit prettier
-      env: TOXENV=py26
     - python: "2.7"
       env: TOXENV=py27
-    - python: "3.3"
-      env: TOXENV=py33
     - python: "3.4"
       env: TOXENV=py34
     - python: "3.5"
@@ -24,24 +20,30 @@ matrix:
     # Meta
     - python: "3.5"
       env: TOXENV=flake8
-    - python: "2.7"
+    - python: "3.5"
       env: TOXENV=manifest
-    - python: "2.7"
+    - python: "3.5"
       env: TOXENV=docs
+    - python: "3.5"
+      env: TOXENV=readme
 
 
 install:
   - pip install tox
 
+
 script:
-  - tox --hashseed 0
+  - tox
+
 
 before_install:
   - pip install codecov
 
+
 after_success:
   - tox -e coverage-report
   - codecov
 
+
 notifications:
   email: false
diff --git a/docs/license.rst b/AUTHORS.rst
similarity index 62%
copy from docs/license.rst
copy to AUTHORS.rst
index 01d0003..79dba74 100644
--- a/docs/license.rst
+++ b/AUTHORS.rst
@@ -1,12 +1,5 @@
-License and Hall of Fame
-========================
-
-``attrs`` is licensed under the `MIT <http://choosealicense.com/licenses/mit/>`_ license.
-The full license text can be also found in the `source code repository <https://github.com/hynek/attrs/blob/master/LICENSE>`_.
-
-
-Authors
--------
+Credits
+=======
 
 ``attrs`` is written and maintained by `Hynek Schlawack <https://hynek.me/>`_.
 
@@ -14,5 +7,5 @@ The development is kindly supported by `Variomedia AG <https://www.variomedia.de
 
 A full list of contributors can be found in `GitHub's overview <https://github.com/hynek/attrs/graphs/contributors>`_.
 
-It’s the spiritual successor of `characteristic <https://characteristic.readthedocs.org/>`_ and aspires to fix some of it clunkiness and unfortunate decisions.
+It’s the spiritual successor of `characteristic <https://characteristic.readthedocs.io/>`_ and aspires to fix some of it clunkiness and unfortunate decisions.
 Both were inspired by Twisted’s `FancyEqMixin <https://twistedmatrix.com/documents/current/api/twisted.python.util.FancyEqMixin.html>`_ but both are implemented using class decorators because `sub-classing is bad for you <https://www.youtube.com/watch?v=3MNVP9-hglc>`_, m’kay?
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index af64f6c..ebccfda 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -5,39 +5,73 @@ Versions are year-based with a strict backwards compatibility policy.
 The third digit is only for regressions.
 
 
-15.2.0 (2015-12-08)
+16.0.0 (2016-05-23)
 -------------------
 
+Backward-incompatible changes:
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Python 3.3 and 2.6 aren't supported anymore.
+  They may work by chance but any effort to keep them working has ceased.
+
+  The last Python 2.6 release was on October 29, 2013 and isn't supported by the CPython core team anymore.
+  Major Python packages like Django and Twisted dropped Python 2.6 a while ago already.
+
+  Python 3.3 never had a significant user base and wasn't part of any distribution's LTS release.
+
+Changes:
+^^^^^^^^
+
+- ``__slots__`` have arrived!
+  Classes now can automatically be `slots <https://docs.python.org/3.5/reference/datamodel.html#slots>`_-style (and save your precious memory) just by passing ``slots=True``.
+  `#35 <https://github.com/hynek/attrs/issues/35>`_
+- Allow the case of initializing attributes that are set to ``init=False``.
+  This allows for clean initializer parameter lists while being able to initialize attributes to default values.
+  `#32 <https://github.com/hynek/attrs/issues/32>`_
+- ``attr.asdict`` can now produce arbitrary mappings instead of Python ``dict``\ s when provided with a ``dict_factory`` argument.
+  `#40 <https://github.com/hynek/attrs/issues/40>`_
+- Multiple performance improvements.
+
+
+----
+
+
+15.2.0 (2015-12-08)
+-------------------
 
 Changes:
 ^^^^^^^^
 
 - Add a ``convert`` argument to ``attr.ib``, which allows specifying a function to run on arguments.
   This allows for simple type conversions, e.g. with ``attr.ib(convert=int)``.
-  `[26] <https://github.com/hynek/attrs/issues/26>`_
+  `#26 <https://github.com/hynek/attrs/issues/26>`_
 - Speed up object creation when attribute validators are used.
-  `[28] <https://github.com/hynek/attrs/issues/28>`_
+  `#28 <https://github.com/hynek/attrs/issues/28>`_
+
+
+----
 
 
 15.1.0 (2015-08-20)
 -------------------
 
-
 Changes:
 ^^^^^^^^
 
 - Add ``attr.validators.optional`` that wraps other validators allowing attributes to be ``None``.
-  `[16] <https://github.com/hynek/attrs/issues/16>`_
+  `#16 <https://github.com/hynek/attrs/issues/16>`_
 - Fix multi-level inheritance.
-  `[24] <https://github.com/hynek/attrs/issues/24>`_
+  `#24 <https://github.com/hynek/attrs/issues/24>`_
 - Fix ``__repr__`` to work for non-redecorated subclasses.
-  `[20] <https://github.com/hynek/attrs/issues/20>`_
+  `#20 <https://github.com/hynek/attrs/issues/20>`_
+
+
+----
 
 
 15.0.0 (2015-04-15)
 -------------------
 
-
 Changes:
 ^^^^^^^^
 
diff --git a/CODE_OF_CONDUCT.rst b/CODE_OF_CONDUCT.rst
index 1623397..fa8b5bb 100644
--- a/CODE_OF_CONDUCT.rst
+++ b/CODE_OF_CONDUCT.rst
@@ -1,37 +1,55 @@
-Contributor Code of Conduct
-===========================
+Contributor Covenant Code of Conduct
+====================================
 
-As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
+Our Pledge
+----------
 
-We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
+In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
+
+Our Standards
+-------------
+
+Examples of behavior that contributes to creating a positive environment include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
 
 Examples of unacceptable behavior by participants include:
 
-* The use of sexualized language or imagery
-* Personal attacks
-* Trolling or insulting/derogatory comments
+* The use of sexualized language or imagery and unwelcome sexual attention or advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
 * Public or private harassment
-* Publishing other's private information, such as physical or electronic
-  addresses, without explicit permission
-* Other unethical or unprofessional conduct
+* Publishing others' private information, such as a physical or electronic address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a professional setting
+
+Our Responsibilities
+--------------------
+
+Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
 
 Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
 
-By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project.
-Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
+Scope
+-----
 
 This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
+Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
+Representation of a project may be further defined and clarified by project maintainers.
+
+Enforcement
+-----------
 
-Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting a project maintainer at hs at ox.cx.
-All complaints will be reviewed and investigated and will result in a response that
-is deemed necessary and appropriate to the circumstances.
-Maintainers are obligated to maintain confidentiality with regard to the reporter of an
-incident.
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hs at ox.cx.
+all complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances.
+The project team is obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
 
+Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
 
-This Code of Conduct is adapted from the `Contributor Covenant <homepage>`_,
-version 1.3.0, available at
-`http://contributor-covenant.org/version/1/3/0/ <version>`_.
+Attribution
+-----------
 
-.. _homepage: http://contributor-covenant.org
-.. _version: http://contributor-covenant.org/version/1/3/0/
+This Code of Conduct is adapted from the `Contributor Covenant <http://contributor-covenant.org>`_, version 1.4, available at http://contributor-covenant.org/version/1/4.
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index 482934d..f24cd9e 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -24,18 +24,18 @@ Here are a few guidelines to get you started:
 
 Please note that this project is released with a Contributor `Code of Conduct`_.
 By participating in this project you agree to abide by its terms.
-Please report any harm to `Hynek Schlawack <me>`_ in any way you find appropriate.
+Please report any harm to `Hynek Schlawack`_ in any way you find appropriate.
 
 Thank you for considering to contribute to ``attrs``!
 
 
-.. _me: https://hynek.me/about/
+.. _`Hynek Schlawack`: https://hynek.me/about/
 .. _`PEP 8`: https://www.python.org/dev/peps/pep-0008/
 .. _`PEP 257`: https://www.python.org/dev/peps/pep-0257/
 .. _`good test docstrings`: https://jml.io/pages/test-docstrings.html
 .. _`Code of Conduct`: https://github.com/hynek/attrs/blob/master/CODE_OF_CONDUCT.rst
 .. _changelog: https://github.com/hynek/attrs/blob/master/CHANGELOG.rst
-.. _`backward compatibility`: https://attrs.readthedocs.org/en/latest/backward-compatibility.html
+.. _`backward compatibility`: https://attrs.readthedocs.io/en/latest/backward-compatibility.html
 .. _`tox`: https://testrun.org/tox/
 .. _`Travis CI`: https://travis-ci.org/
 .. _pyenv: https://github.com/yyuu/pyenv
diff --git a/README.rst b/README.rst
index b79b1fd..8abc731 100644
--- a/README.rst
+++ b/README.rst
@@ -2,6 +2,10 @@
 attrs: Attributes without boilerplate.
 ======================================
 
+.. image:: https://readthedocs.org/projects/attrs/badge/?version=stable
+   :target: http://attrs.readthedocs.io/en/stable/?badge=stable
+   :alt: Documentation Status
+
 .. image:: https://travis-ci.org/hynek/attrs.svg
    :target: https://travis-ci.org/hynek/attrs
    :alt: CI status
@@ -51,9 +55,5 @@ This gives you the power to use actual classes with actual types in your code in
 
 So put down that type-less data structures and welcome some class into your life!
 
-.. note::
-   I wrote an `explanation <https://attrs.readthedocs.org/en/latest/why.html#characteristic>`_ on why I forked my own ``characteristic``.
-   It's not dead but ``attrs`` will have more new features.
-
-``attrs``\ ’s documentation lives at `Read the Docs <https://attrs.readthedocs.org/>`_, the code on `GitHub <https://github.com/hynek/attrs>`_.
-It’s rigorously tested on Python 2.6, 2.7, 3.3+, and PyPy.
+``attrs``\ ’s documentation lives at `Read the Docs <https://attrs.readthedocs.io/>`_, the code on `GitHub <https://github.com/hynek/attrs>`_.
+It’s rigorously tested on Python 2.7, 3.4+, and PyPy.
diff --git a/dev-requirements.txt b/dev-requirements.txt
new file mode 100644
index 0000000..1729667
--- /dev/null
+++ b/dev-requirements.txt
@@ -0,0 +1,5 @@
+coverage
+pytest
+zope.interface
+pympler
+hypothesis
diff --git a/docs/api.rst b/docs/api.rst
index 995166f..3c682d1 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -18,7 +18,7 @@ What follows is the API explanation, if you'd like a more hands-on introduction,
 Core
 ----
 
-.. autofunction:: attr.s(these=None, repr_ns=None, repr=True, cmp=True, hash=True, init=True)
+.. autofunction:: attr.s(these=None, repr_ns=None, repr=True, cmp=True, hash=True, init=True, slots=False)
 
    .. note::
 
diff --git a/docs/contributing.rst b/docs/contributing.rst
index 4628182..1d519c3 100644
--- a/docs/contributing.rst
+++ b/docs/contributing.rst
@@ -1,3 +1,5 @@
 .. _contributing:
 
 .. include:: ../CONTRIBUTING.rst
+
+.. include:: ../CODE_OF_CONDUCT.rst
diff --git a/docs/examples.rst b/docs/examples.rst
index 2e1b4ad..6ab21c9 100644
--- a/docs/examples.rst
+++ b/docs/examples.rst
@@ -71,6 +71,20 @@ For private attributes, ``attrs`` will strip the leading underscores for keyword
    >>> C(x=1)
    C(_x=1)
 
+If you want to initialize your private attributes yourself, you can do that too:
+
+.. doctest::
+
+   >>> @attr.s
+   ... class C(object):
+   ...     _x = attr.ib(init=False, default=42)
+   >>> C()
+   C(_x=42)
+   >>> C(23)
+   Traceback (most recent call last):
+      ...
+   TypeError: __init__() takes exactly 1 argument (2 given)
+
 An additional way (not unlike ``characteristic``) of defining attributes is supported too.
 This is useful in times when you want to enhance classes that are not yours (nice ``__repr__`` for Django models anyone?):
 
@@ -189,7 +203,7 @@ For the common case where you want to :func:`include <attr.filters.include>` or
    ...     y = attr.ib()
    ...     z = attr.ib()
    >>> attr.asdict(C("foo", "2", 3), filter=attr.filters.include(int, C.x))
-   {'x': 'foo', 'z': 3}
+   {'z': 3, 'x': 'foo'}
 
 
 Defaults
@@ -219,11 +233,11 @@ And sometimes you even want mutable objects as default values (ever used acciden
    ...             return self.pool.pop()
    ...         except IndexError:
    ...             if self.debug:
-   ...                 print "New connection!"
+   ...                 print("New connection!")
    ...             return Connection.connect(self.db_string)
    ...     def free_connection(self, conn):
    ...         if self.debug:
-   ...             print "Connection returned!"
+   ...             print("Connection returned!")
    ...         self.pool.appendleft(conn)
    ...
    >>> cp = ConnectionPool("postgres://localhost")
@@ -363,6 +377,72 @@ Converters are run *before* validators, so you can use validators to check the f
     ValueError: x must be be at least 0.
 
 
+.. _slots:
+
+Slots
+-----
+
+By default, instances of classes have a dictionary for attribute storage.
+This wastes space for objects having very few instance variables.
+The space consumption can become significant when creating large numbers of instances.
+
+Normal Python classes can avoid using a separate dictionary for each instance of a class by `defining <https://docs.python.org/3.5/reference/datamodel.html#slots>`_ ``__slots__``.
+For ``attrs`` classes it's enough to set ``slots=True``:
+
+.. doctest::
+
+   >>> @attr.s(slots=True)
+   ... class Coordinates(object):
+   ...     x = attr.ib()
+   ...     y = attr.ib()
+
+
+.. note::
+
+    ``attrs`` slot classes can inherit from other classes just like non-slot classes, but some of the benefits of slot classes are lost if you do that.
+    If you must inherit from other classes, try to inherit only from other slot classes.
+
+Slot classes are a little different than ordinary, dictionary-backed classes:
+
+- Assigning to a non-existent attribute of an instance will result in an ``AttributeError`` being raised.
+  Depending on your needs, this might be a good thing since it will let you catch typos early.
+  This is not the case if your class inherits from any non-slot classes.
+
+  .. doctest::
+
+     >>> @attr.s(slots=True)
+     ... class Coordinates(object):
+     ...     x = attr.ib()
+     ...     y = attr.ib()
+     ...
+     >>> c = Coordinates(x=1, y=2)
+     >>> c.z = 3
+     Traceback (most recent call last):
+         ...
+     AttributeError: 'Coordinates' object has no attribute 'z'
+
+- Slot classes cannot share attribute names with their instances, while non-slot classes can.
+  The following behaves differently if slot classes are used:
+
+  .. doctest::
+
+    >>> @attr.s
+    ... class C(object):
+    ...     x = attr.ib()
+    >>> C.x
+    Attribute(name='x', default=NOTHING, validator=None, repr=True, cmp=True, hash=True, init=True, convert=None)
+    >>> @attr.s(slots=True)
+    ... class C(object):
+    ...     x = attr.ib()
+    >>> C.x
+    <member 'x' of 'C' objects>
+
+- Since non-slot classes cannot be turned into slot classes after they have been created, ``attr.s(.., slots=True)`` will *replace* the class it is applied to with a copy.
+  In almost all cases this isn't a problem, but we mention it for the sake of completeness.
+
+All in all, setting ``slots=True`` is usually a very good idea.
+
+
 Other Goodies
 -------------
 
diff --git a/docs/extending.rst b/docs/extending.rst
index fecf394..5394371 100644
--- a/docs/extending.rst
+++ b/docs/extending.rst
@@ -12,7 +12,7 @@ So it is fairly simple to build your own decorators on top of ``attrs``:
 
    >>> import attr
    >>> def print_attrs(cl):
-   ...     print cl.__attrs_attrs__
+   ...     print(cl.__attrs_attrs__)
    >>> @print_attrs
    ... @attr.s
    ... class C(object):
diff --git a/docs/license.rst b/docs/license.rst
index 01d0003..e74ac47 100644
--- a/docs/license.rst
+++ b/docs/license.rst
@@ -1,18 +1,8 @@
-License and Hall of Fame
-========================
+===================
+License and Credits
+===================
 
 ``attrs`` is licensed under the `MIT <http://choosealicense.com/licenses/mit/>`_ license.
 The full license text can be also found in the `source code repository <https://github.com/hynek/attrs/blob/master/LICENSE>`_.
 
-
-Authors
--------
-
-``attrs`` is written and maintained by `Hynek Schlawack <https://hynek.me/>`_.
-
-The development is kindly supported by `Variomedia AG <https://www.variomedia.de/>`_.
-
-A full list of contributors can be found in `GitHub's overview <https://github.com/hynek/attrs/graphs/contributors>`_.
-
-It’s the spiritual successor of `characteristic <https://characteristic.readthedocs.org/>`_ and aspires to fix some of it clunkiness and unfortunate decisions.
-Both were inspired by Twisted’s `FancyEqMixin <https://twistedmatrix.com/documents/current/api/twisted.python.util.FancyEqMixin.html>`_ but both are implemented using class decorators because `sub-classing is bad for you <https://www.youtube.com/watch?v=3MNVP9-hglc>`_, m’kay?
+.. include:: ../AUTHORS.rst
diff --git a/docs/why.rst b/docs/why.rst
index 4e6c7c7..ec10556 100644
--- a/docs/why.rst
+++ b/docs/why.rst
@@ -64,7 +64,7 @@ The difference between :func:`collections.namedtuple`\ s and classes decorated b
    ... class C1(object):
    ...     a = attr.ib()
    ...     def print_a(self):
-   ...        print self.a
+   ...        print(self.a)
    >>> @attr.s
    ... class C2(object):
    ...     a = attr.ib()
@@ -181,17 +181,13 @@ But if you ever get sick of the repetitiveness, ``attrs`` will be waiting for yo
 …characteristic
 ---------------
 
-`characteristic <https://characteristic.readthedocs.org/en/stable/>`_ is a very similar and fairly popular project of mine.
+`characteristic <https://characteristic.readthedocs.io/>`_ is a very similar and fairly popular project of mine.
 So why the self-fork?
 Basically after nearly a year of usage I ran into annoyances and regretted certain decisions I made early-on to make too many people happy.
 In the end, *I* wasn't happy using it anymore.
 
 So I learned my lesson and ``attrs`` is the result of that.
 
-.. note::
-   Nevertheless, ``characteristic`` is **not** dead.
-   A lot of software uses it and I will keep maintaining it.
-
 
 Reasons For Forking
 ^^^^^^^^^^^^^^^^^^^
diff --git a/setup.cfg b/setup.cfg
index e0cb483..c0474af 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -5,5 +5,5 @@ addopts = -ra
 testpaths = tests
 
 
-[wheel]
+[bdist_wheel]
 universal = 1
diff --git a/setup.py b/setup.py
index 4298a1f..68b26e9 100644
--- a/setup.py
+++ b/setup.py
@@ -19,10 +19,8 @@ CLASSIFIERS = [
     "Operating System :: OS Independent",
     "Programming Language :: Python",
     "Programming Language :: Python :: 2",
-    "Programming Language :: Python :: 2.6",
     "Programming Language :: Python :: 2.7",
     "Programming Language :: Python :: 3",
-    "Programming Language :: Python :: 3.3",
     "Programming Language :: Python :: 3.4",
     "Programming Language :: Python :: 3.5",
     "Programming Language :: Python :: Implementation :: CPython",
@@ -61,19 +59,33 @@ def find_meta(meta):
     raise RuntimeError("Unable to find __{meta}__ string.".format(meta=meta))
 
 
+VERSION = find_meta("version")
+URI = find_meta("uri")
+LONG = (
+    read("README.rst") + "\n\n" +
+    "Release Information\n" +
+    "===================\n\n" +
+    re.search("(\d+.\d.\d \(.*?\)\n.*?)\n\n\n----\n\n\n",
+              read("CHANGELOG.rst"), re.S).group(1) +
+    "\n\n`Full changelog " +
+    "<{uri}en/stable/changelog.html>`_.\n\n".format(uri=URI) +
+    read("AUTHORS.rst")
+)
+
+
 if __name__ == "__main__":
     setup(
         name=NAME,
         description=find_meta("description"),
         license=find_meta("license"),
-        url=find_meta("uri"),
-        version=find_meta("version"),
+        url=URI,
+        version=VERSION,
         author=find_meta("author"),
         author_email=find_meta("email"),
         maintainer=find_meta("author"),
         maintainer_email=find_meta("email"),
         keywords=KEYWORDS,
-        long_description=read("README.rst") + "\n\n" + read("CHANGELOG.rst"),
+        long_description=LONG,
         packages=PACKAGES,
         package_dir={"": "src"},
         zip_safe=False,
diff --git a/src/attr/__init__.py b/src/attr/__init__.py
index a3f96f1..cf991e8 100644
--- a/src/attr/__init__.py
+++ b/src/attr/__init__.py
@@ -23,11 +23,11 @@ from . import filters
 from . import validators
 
 
-__version__ = "15.2.0"
+__version__ = "16.0.0"
 
 __title__ = "attrs"
 __description__ = "Attributes without boilerplate."
-__uri__ = "https://attrs.readthedocs.org/"
+__uri__ = "https://attrs.readthedocs.io/"
 
 __author__ = "Hynek Schlawack"
 __email__ = "hs at ox.cx"
diff --git a/src/attr/_compat.py b/src/attr/_compat.py
index a394a2f..36f0ef2 100644
--- a/src/attr/_compat.py
+++ b/src/attr/_compat.py
@@ -8,6 +8,13 @@ PY2 = sys.version_info[0] == 2
 
 
 if PY2:
+    import types
+
+    # We 'bundle' isclass instead of using inspect as importing inspect is
+    # fairly expensive (order of 10-15 ms for a modern machine in 2016)
+    def isclass(klass):
+        return isinstance(klass, (type, types.ClassType))
+
     # TYPE is used in exceptions, repr(int) is different on Python 2 and 3.
     TYPE = "type"
 
@@ -16,7 +23,13 @@ if PY2:
 
     def iteritems(d):
         return d.iteritems()
+
+    def iterkeys(d):
+        return d.iterkeys()
 else:
+    def isclass(klass):
+        return isinstance(klass, type)
+
     TYPE = "class"
 
     def exec_(code, locals_, globals_):
@@ -24,3 +37,6 @@ else:
 
     def iteritems(d):
         return d.items()
+
+    def iterkeys(d):
+        return d.keys()
diff --git a/src/attr/_funcs.py b/src/attr/_funcs.py
index 15daae6..07cc7bf 100644
--- a/src/attr/_funcs.py
+++ b/src/attr/_funcs.py
@@ -6,26 +6,32 @@ from ._compat import iteritems
 from ._make import Attribute, NOTHING, fields
 
 
-def asdict(inst, recurse=True, filter=None):
+def asdict(inst, recurse=True, filter=None, dict_factory=dict):
     """
     Return the ``attrs`` attribute values of *i* as a dict.  Optionally recurse
     into other ``attrs``-decorated classes.
 
     :param inst: Instance of a ``attrs``-decorated class.
 
-    :param recurse: Recurse into classes that are also ``attrs``-decorated.
-    :type recurse: bool
+    :param bool recurse: Recurse into classes that are also
+        ``attrs``-decorated.
 
-    :param filter: A callable whose return code deteremines whether an
+    :param callable filter: A callable whose return code deteremines whether an
         attribute or element is included (``True``) or dropped (``False``).  Is
         called with the :class:`attr.Attribute` as the first argument and the
         value as the second argument.
-    :type filer: callable
+
+    :param callable dict_factory: A callable to produce dictionaries from. For
+        example, to produce ordered dictionaries instead of normal Python
+        dictionaries, pass in ``collections.OrderedDict``.
 
     :rtype: :class:`dict`
+
+    .. versionadded:: 16.0.0
+        *dict_factory*
     """
     attrs = fields(inst.__class__)
-    rv = {}
+    rv = dict_factory()
     for a in attrs:
         v = getattr(inst, a.name)
         if filter is not None and not filter(a, v):
diff --git a/src/attr/_make.py b/src/attr/_make.py
index d5cc3fe..55e7fbc 100644
--- a/src/attr/_make.py
+++ b/src/attr/_make.py
@@ -2,10 +2,9 @@ from __future__ import absolute_import, division, print_function
 
 import copy
 import hashlib
-import inspect
 import linecache
 
-from ._compat import exec_, iteritems
+from ._compat import exec_, iteritems, isclass, iterkeys
 from . import _config
 
 
@@ -22,7 +21,7 @@ class _Nothing(object):
         return self
 
     def __eq__(self, other):
-        return self.__class__ == _Nothing
+        return other.__class__ == _Nothing
 
     def __ne__(self, other):
         return not self == other
@@ -52,10 +51,10 @@ def attr(default=NOTHING, validator=None,
         :func:`attr.s`!
 
     :param default: Value that is used if an ``attrs``-generated
-        ``__init__`` is used and no value is passed while instantiating.  If
-        the value an instance of :class:`Factory`, it callable will be use to
-        construct a new value (useful for mutable datatypes like lists or
-        dicts).
+        ``__init__`` is used and no value is passed while instantiating or the
+        attribute is excluded using ``init=False``.  If the value an instance
+        of :class:`Factory`, it callable will be use to construct a new value
+        (useful for mutable datatypes like lists or dicts).
     :type default: Any value.
 
     :param callable validator: :func:`callable` that is called by
@@ -79,7 +78,9 @@ def attr(default=NOTHING, validator=None,
         method.
 
     :param bool init: Include this attribute in the generated ``__init__``
-        method.
+        method.  It is possible to set this to ``False`` and set a default
+        value.  In that case this attributed is unconditionally initialized
+        with the specified default value or factory.
 
     :param callable convert: :func:`callable` that is called by
         ``attrs``-generated ``__init__`` methods to convert attribute's value
@@ -130,18 +131,20 @@ def _transform_attrs(cl, these):
     for a in cl.__attrs_attrs__:
         if these is None and a not in super_cls:
             setattr(cl, a.name, a)
-        if had_default is True and a.default is NOTHING:
+        if had_default is True and a.default is NOTHING and a.init is True:
             raise ValueError(
                 "No mandatory attributes allowed after an attribute with a "
                 "default value or factory.  Attribute in question: {a!r}"
                 .format(a=a)
             )
-        elif had_default is False and a.default is not NOTHING:
+        elif had_default is False and \
+                a.default is not NOTHING and \
+                a.init is not False:
             had_default = True
 
 
 def attributes(maybe_cl=None, these=None, repr_ns=None,
-               repr=True, cmp=True, hash=True, init=True):
+               repr=True, cmp=True, hash=True, init=True, slots=False):
     """
     A class decorator that adds `dunder
     <https://wiki.python.org/moin/DunderAlias>`_\ -methods according to the
@@ -177,10 +180,25 @@ def attributes(maybe_cl=None, these=None, repr_ns=None,
     :param init: Create a ``__init__`` method that initialiazes the ``attrs``
         attributes.  Leading underscores are stripped for the argument name.
     :type init: bool
+
+    :param slots: Create a slots_-style class that's more memory-efficient.
+        See :ref:`slots` for further ramifications.
+    :type slots: bool
+
+    .. _slots: https://docs.python.org/3.5/reference/datamodel.html#slots
     """
     def wrap(cl):
         if getattr(cl, "__class__", None) is None:
             raise TypeError("attrs only works with new-style classes.")
+        if slots:
+            # Only need this later if we're using slots.
+            if these is None:
+                ca_list = [name
+                           for name, attr
+                           in cl.__dict__.items()
+                           if isinstance(attr, _CountingAttr)]
+            else:
+                ca_list = list(iterkeys(these))
         _transform_attrs(cl, these)
         if repr is True:
             cl = _add_repr(cl, ns=repr_ns)
@@ -190,6 +208,21 @@ def attributes(maybe_cl=None, these=None, repr_ns=None,
             cl = _add_hash(cl)
         if init is True:
             cl = _add_init(cl)
+        if slots:
+            cl_dict = dict(cl.__dict__)
+            cl_dict["__slots__"] = tuple(ca_list)
+            for ca_name in ca_list:
+                # It might not actually be in there, e.g. if using 'these'.
+                cl_dict.pop(ca_name, None)
+            cl_dict.pop('__dict__', None)
+
+            if repr_ns is None:
+                cl_name = getattr(cl, "__qualname__", cl.__name__)
+            else:
+                cl_name = cl.__name__
+
+            cl = type(cl_name, cl.__bases__, cl_dict)
+
         return cl
 
     # attrs_or class type depends on the usage of the decorator.  It's a class
@@ -333,7 +366,8 @@ def _add_repr(cl, ns=None, attrs=None):
 
 
 def _add_init(cl):
-    attrs = [a for a in cl.__attrs_attrs__ if a.init]
+    attrs = [a for a in cl.__attrs_attrs__
+             if a.init or a.default is not NOTHING]
 
     # We cache the generated init methods for the same kinds of attributes.
     sha1 = hashlib.sha1()
@@ -376,7 +410,7 @@ def fields(cl):
 
     :rtype: tuple of :class:`attr.Attribute`
     """
-    if not inspect.isclass(cl):
+    if not isclass(cl):
         raise TypeError("Passed object must be a class.")
     attrs = getattr(cl, "__attrs_attrs__", None)
     if attrs is None:
@@ -386,6 +420,15 @@ def fields(cl):
     return copy.deepcopy(attrs)
 
 
+def _fast_attrs_iterate(inst):
+    """
+    Fast internal iteration over the attr descriptors.
+
+    Using fields to iterate is slow because it involves deepcopy.
+    """
+    return inst.__class__.__attrs_attrs__
+
+
 def validate(inst):
     """
     Validate all attributes on *inst* that have a validator.
@@ -397,7 +440,7 @@ def validate(inst):
     if _config._run_validators is False:
         return
 
-    for a in inst.__class__.__attrs_attrs__:
+    for a in _fast_attrs_iterate(inst):
         if a.validator is not None:
             a.validator(inst, a, getattr(inst, a.name))
 
@@ -410,7 +453,7 @@ def _convert(inst):
 
     :param inst: Instance of a class with ``attrs`` attributes.
     """
-    for a in fields(inst.__class__):
+    for a in _fast_attrs_iterate(inst):
         if a.convert is not None:
             setattr(inst, a.name, a.convert(getattr(inst, a.name)))
 
@@ -430,7 +473,18 @@ def _attrs_to_script(attrs):
             has_convert = True
         attr_name = a.name
         arg_name = a.name.lstrip("_")
-        if a.default is not NOTHING and not isinstance(a.default, Factory):
+        if a.init is False:
+            if isinstance(a.default, Factory):
+                lines.append("""\
+self.{attr_name} = attr_dict["{attr_name}"].default.factory()""".format(
+                    attr_name=attr_name,
+                ))
+            else:
+                lines.append("""\
+self.{attr_name} = attr_dict["{attr_name}"].default""".format(
+                    attr_name=attr_name,
+                ))
+        elif a.default is not NOTHING and not isinstance(a.default, Factory):
             args.append(
                 "{arg_name}=attr_dict['{attr_name}'].default".format(
                     arg_name=arg_name,
diff --git a/src/attr/filters.py b/src/attr/filters.py
index c5faaa3..4e60183 100644
--- a/src/attr/filters.py
+++ b/src/attr/filters.py
@@ -4,8 +4,7 @@ Commonly useful filters for :func:`attr.asdict`.
 
 from __future__ import absolute_import, division, print_function
 
-import inspect
-
+from ._compat import isclass
 from ._make import Attribute
 
 
@@ -14,7 +13,7 @@ def _split_what(what):
     Returns a tuple of `frozenset`s of classes and attributes.
     """
     return (
-        frozenset(cl for cl in what if inspect.isclass(cl)),
+        frozenset(cl for cl in what if isclass(cl)),
         frozenset(cl for cl in what if isinstance(cl, Attribute)),
     )
 
diff --git a/src/attr/validators.py b/src/attr/validators.py
index 01b7b10..13a9366 100644
--- a/src/attr/validators.py
+++ b/src/attr/validators.py
@@ -35,13 +35,13 @@ def instance_of(type):
     """
     A validator that raises a :exc:`TypeError` if the initializer is called
     with a wrong type for this particular attribute (checks are perfomed using
-    :func:`isinstance`).
+    :func:`isinstance` therefore it's also valid to pass a tuple of types).
 
     :param type: The type to check for.
-    :type type: type
+    :type type: type or tuple of types
 
     The :exc:`TypeError` is raised with a human readable error message, the
-    attribute (of type :class:`attr.Attribute`), the expected type and the
+    attribute (of type :class:`attr.Attribute`), the expected type, and the
     value it got.
     """
     return _InstanceOfValidator(type)
diff --git a/tests/__init__.py b/tests/__init__.py
index d80ff61..49b0648 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -1,16 +1,21 @@
 from __future__ import absolute_import, division, print_function
 
+import string
+
+from hypothesis import strategies as st
+
+import attr
 from attr import Attribute
 from attr._make import NOTHING, make_class
... 1074 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-attrs.git



More information about the Python-modules-commits mailing list