Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] First class type support #215

Closed
hynek opened this issue Jun 26, 2017 · 59 comments
Closed

[RFC] First class type support #215

hynek opened this issue Jun 26, 2017 · 59 comments
Labels

Comments

@hynek
Copy link
Member

hynek commented Jun 26, 2017

This is kind of part of #214 but it stands for itself too.

Something like:

@attr.s(check_types=True)
class C:
    x = attr.ib(type=int)

ought to work.

Regardless of checking the type, the type information has to be accessible somewhere so we can have first-class deserialization support.

@yunstanford
Copy link

+1

@toumorokoshi
Copy link

This would be awesome! Is the goal to enable type checking within attrs itself? and to support types as listed in typing.py? There's a few caveats that we've discovered, diving in.

1 is there's no standardized type checking behavior for collections in typing. From my understanding, this is still an area that needs more work:

python/typing#136

Most people have been writing their own type validation libraries to compensate:

https://pypi.python.org/pypi/typeguard

All in all, I'm a huge fan of this direction. Just wondering what the choice is for type checker.

@hynek
Copy link
Member Author

hynek commented Jun 29, 2017

We don’t have concrete plans yet! Mostly because we want to make types & serialization first class concepts in attrs while doing this. :)

@hynek
Copy link
Member Author

hynek commented Jun 29, 2017

Wait, wrong ticket! :) Yeah, no still no idea yet!

@toumorokoshi
Copy link

I have a couple thoughts on this, if you're looking for ideas.

The type parameters should probably be equivalent to adding two behavior: validate and convert:

new_style = attr.ib(type=int)
old_style = attr.ib(validator=validators.instance_of(int), converter=int)

This works pretty well for primitive types. There's some nastiness with more complex types, which attrs probably shouldn't solve. For example, I'd expect to be able to do something like:

from datetime import daytime

@attr.s
class X:
    date = attr.ib(type=datetime)

# epoch
x = X(date=1092183940129)
# ISO 8601 string
x = X(date="2017-06-30T14:14:57Z")

but these would fail, because the datetime constructor takes none of these.

I would argue probably just not handling this case, and letting people override with whatever complex converters they prefer:

attr.ib(type=datetime, converter=my_complex_converter)

The other part is using or supporting typing modules. this will require some choices in behavior (e.g. validating types recursively, or just validating the top level collection for collection types). I prefer recursive validation and conversion, personally.

@hynek
Copy link
Member Author

hynek commented Jun 30, 2017

Yes, feel free to dump all your thoughts. The more input we get beforehand, the less mistakes we’re likely to make. :)

@Tinche
Copy link
Member

Tinche commented Jul 4, 2017

OK, let's split the proposal into sub-features for easier commenting.

Create the type metadata

  1. Adding a type parameter to attr.ib().
@attr.s
class C:
    x = attr.ib(type=int)

Presumably fields(C).x.type would be int then. I'm generally in favor of this. I already have a system like this in place for cattrs, except it uses metadata. I think this should be the backup though, for Pythons before 3.6. The 3.6 syntax reads much better for me.

@attr.s
class C:
    x: int = attr.ib()

So basically like #214, but with the type argument for older Pythons.

So what do we do with this data?

Static checks

My personal opinion is that static analysis is the future here. This means writing a MyPy plugin (which coincidentally I kinda promised to do, but I won't get around to until my main vacation at the end of July, probably), and maybe getting other vendors (flake8, pylint, pycharm...) in this space to cooperate too.

Static analysis has two major advantages. The first is that some types are impossible or exceedingly difficult to check for in runtime - think Iterator[int]. The other is performance. Generics in general are problematic.

@attr.s
class C:
    x: List[int] = attr.ib()

inst = C(list(range(1000)))  # Do what - iterate over the entire list?
inst.x.append('a string')  # No one will complain in the runtime here.

Even if you have simple type annotations, without generics, the isinstance calls are kinda heavy. IIRC for ints it's actually less expensive to use a convert=int than validator=instance_of(int), even though they aren't exactly the same.

This isn't me getting into static vs dynamic typing, just stating the fact that static types are a tool with advantages over doing it in runtime. We're getting them in Python and it's exciting!

We will still need validators since validators can check the values of types, and MyPy can't. So you will always need a validator to ensure your int is positive, for example.

Now, as I mentioned, this is probably the future. We can't really rely on this today since MyPy doesn't even support the easy cases of attrs classes.

Runtime checks

There is still value in runtime checking, of course. Not everyone will be able or willing to run MyPy over their code base, or maybe you want checks in the REPL, so us having a nice API for this would be good. This will require a little logic in our type validation, since not all types from typing can be used with isinstance.

The runtime type checks should be opt-in. I'm not sure if the opt-in should be on the class level (I feel like we'd need an opt-out at the attribute level) or at the attribute level, or both.

Let's experiment with some ideas for attribute-level opt-in.

from attr.validators import validate_type

def positive(_, __, val):
    if val <= 0:
        raise ValueError

@attr.s
class C: 
    x: int = attr.ib(validator=validate_type)  # Magic! Requires additional support in attrs.
    y: int = attr.ib(validator=[validate_type, positive])
    z: int = attr.ib(validator=validate_type(positive))

@toumorokoshi
Copy link

I agree that at least, introducing the type attribute and doing nothing but attaching it to the field would be great. It's a fantastic building block to build off of.

It would also be great to fold in the type definition into the attr.ib object, if possible, so

x = attr.ib(type=int)

and

x: int = attr.ib()

are functionally equal (if both are declared, attr.ib(type=foo) could take precedence).

I know there's an existing PR around attrs support for MyPy, so that'll handle the static checks at some point.

Personally, I'm more interested in the dynamic checks. I'd like to integrate it as a serializer for an API validation library I've been working on (http://transmute-core.readthedocs.io/en/latest/), and attrs has a great philosophy with performance as a feature.

Regarding the way validation is declared, validate_type seems syntactically the nicest. Although the complexities of type validation is definitely a larger ordeal. A lot of choices as @Tinche points out. validate_type could do shallow or deep validation, and that's control you may want to leave to the user.

Providing simple integrations with existing runtime type checking / conversion tooling might be better. e.g. typeguard or cattrs.

@hynek
Copy link
Member Author

hynek commented Jul 6, 2017

I'm drinking Aperol Spritz by Lake Como right now but briefly:

  • Yes, I want .type as a building block and a dedicated validator that doesn't take further arguments. Everything just composes nicely. We may add a specific argument to attr.s that implicitly adds the validator to all fields. We'll see. As it should be obvious by now, I'm very anti runtime costs. :)
  • I think declaring two types should blow up.

More when I'm back after EP. Although I may sprint on it.

@hynek
Copy link
Member Author

hynek commented Jul 22, 2017

Turns out I didn’t and went to San Marino instead!


Anyhow, so far we seem to have a consensus that:

  • we add a new field to the Attribute class called type
  • which can be set using x = attr.ib(type=int) if your life sucks and you can’t use Python 3.6
  • using x: int = attr.ib() if life is wonderful.
  • Additionally we’ll add a validator called check_type which will look at the type attribute and check.

Correct?

So far that seems rather straightforward.

I’d just like to make 100% sure that it won’t paint us in a corner re: deserialization? I’d like explicit comments from the two who built deserialization on top of attrs: @glyph and @Tinche

@Tinche
Copy link
Member

Tinche commented Jul 22, 2017

I'm 100% on board with what you wrote FWIW.

@glyph
Copy link
Contributor

glyph commented Jul 23, 2017

FYI this is a very busy weekend for me but this is definitely in my queue to look at soon.

@hynek
Copy link
Member Author

hynek commented Jul 23, 2017

Cool, but don't overthink it. This is but a first building block. :)

@hynek
Copy link
Member Author

hynek commented Jul 29, 2017

👊 @glyph

(that’s a fist bump, not an attempt of intimidation thru violence :))

@wsanchez
Copy link

wsanchez commented Aug 2, 2017

That (type attribute) seems like a solid first step.

@wsanchez
Copy link

wsanchez commented Aug 2, 2017

@Tinche I'm thinking about your validate_type examples and I think it has legs.

But I'm wondering if it could also have global (ew?) switch of some sort. Since type validation, as you note, can be expensive, it's nice to do it statically if possible, but…

The runtime case I'd want to check is when unit testing, I think, just in case the static analysis toolchain is missing something. At least today, there are a lot of cases where mypy let's things slip, because it was hard to annotate something correctly so someone used Any, or you are getting a value from a library with no type hints or your code is only partly hinted, etc.

So I think there's a use case for: do validation when unit testing but not otherwise.

Perhaps I'm asking for a more fine-grained version of attr.set_run_validators

@glyph
Copy link
Contributor

glyph commented Aug 2, 2017

Personally I'd rather have validation turned on all the time by default; I care more about correctness than speed. I want to rely on this to validate types when constructing them from wire formats. On PyPy, these isinstance checks will be no-opped out on the loops where they pass anyway, won't they?

@hynek
Copy link
Member Author

hynek commented Aug 2, 2017

@wsanchez fun fact: the reason behind attr.set_run_validators is precisely your use case. :) Because I want more checks at tests and less at runtime. attrs grew since its introduction, so things are more complicated now…

@glyph I agree on correctness > speed, however adding an implicit handbrake like this makes me uneasy. The big question is: has static type checking a future in Python or not? IOW: there will be a check_types in any case, but we’ll have to decide it’s default.

I personally tend to False, especially because we’ll most likely need to introduce a dependency on something like type guard, to do it properly.

@wsanchez
Copy link

wsanchez commented Aug 2, 2017

@glyph I'm mostly in your camp, just trying to be sympathetic to the argument that sometimes, the validation is expensive overkill. That is, I might have a model object that, when I deserialize to it from JSON, I totally wan't validation, but when I read it from the database that I'm confident only have valid data, I might want to skip the validation, because I can test that pretty thoroughly.

I don't know what magic PyPy does to be smarter than me, and perhaps I should never optimize anything because PyPy will always do it better. Though I can't use PyPy yet, because at this point, I'm entered the "if it's not >=Py3.6, it's BULLSHIT" phase of my life. :-)

@hynek
Copy link
Member Author

hynek commented Aug 3, 2017

It's a good phase of life – enjoying not myself too.

In seriousness: unless someone comes up with a magical solution to validating types that goes beyond isinstance and doesn't introduce a new dependency, the default is settled.

@glyph
Copy link
Contributor

glyph commented Aug 3, 2017

I am using isinstance in my thing, but I'm not using the type directly. Specifically, here's a relevant function, which isn't complete:

def appropriate_type(T):
    if isunion(T):
        return tuple(appropriate_type(arg) for arg in T.__args__)
    if issubclass(T, typing.List):
        return list
    if issubclass(T, typing.Dict):
        return dict
    if issubclass(T, typing.Set):
        return set
    return T

@hynek
Copy link
Member Author

hynek commented Aug 8, 2017

FWIW, the relevant function seems to be https://github.com/agronholm/typeguard/blob/master/typeguard.py#L348

Also the pkg is by @agronholm and I have a hunch he may be open to persuasion to donate a validator to us. :)

I’m still against adding a handbrake by default – it just feels wrong. :|

@glyph
Copy link
Contributor

glyph commented Aug 8, 2017

How would you feel if we added an alternate, non-type-checked classmethod constructor? Foo.raw for example?

@toumorokoshi
Copy link

a nocheck argument is a nice piece in general. great to just instantiate things as fast as possible if you're really confident the data is valid.

I'm +1 for no default type checking. It's a big change from the existing assumption that the validation is explicit, and I really like attrs because it's a nice syntax around creating classes, and keeps the classes lean.

@glyph
Copy link
Contributor

glyph commented Aug 8, 2017

If you don't want this type of type checking, don't pass type=?

@wsanchez
Copy link

wsanchez commented Aug 9, 2017

@glyph I thought the idea was that type= is superfluous:

   x: int = attribute()   # Implies type=int

@hynek
Copy link
Member Author

hynek commented Aug 26, 2017

That's certainly the plan.

Only open question to me is whether it makes any sense to artificially set __annotations__ if a user supplies .ib(type) in order to be backward compatible. Opinions @ambv?

@Tinche
Copy link
Member

Tinche commented Aug 26, 2017

Only open question to me is whether it makes any sense to artificially set annotations if a user supplies .ib(type)

This is the first step, the second being copying from __annotations__ to Attribute.type? If so, I'd say no, if you want it in __annotations__, use a type annotation.

@agronholm
Copy link

Please don't modify __annotations__. You will want to have real annotations present for static code analysis tools like mypy or PyCharm.

@chadrik
Copy link
Contributor

chadrik commented Aug 27, 2017

Please don't modify annotations. You will want to have real annotations present for static code analysis tools like mypy or PyCharm.

Modifying __annotations__ at runtime has no effect on static type analysis, which by definition never imports or runs your code. That said, my initial reaction is that I think __annotations__ should be copied to Attribute.type and not the other way around.

@agronholm
Copy link

Modifying annotations at runtime has no effect on static type analysis, which by definition never imports or runs your code. That said, my initial reaction is that I think annotations should be copied to Attribute.type and not the other way around.

The examples I've seen so far would forego the annotations and instead pass the type off to attr.ib() and have that used for run-time type checking. Therefore I agree with you.

@chadrik
Copy link
Contributor

chadrik commented Aug 28, 2017

I just added a PR for the parts we all seem to agree on. Pop on by and let me know what you think.

@chadrik
Copy link
Contributor

chadrik commented Aug 28, 2017

Two more thoughts:

  1. I like the suggestion from @Tinche for opt-in validation:

    from attr.validators import validate_type
    
    @attr.s
    class C: 
        x: int = attr.ib(validator=validate_type)
  2. We can also automatically handle defaults to some degree. e.g.:

    • int -> int()
    • str -> str()
    • typing.List[str] -> Factory(list) (the real class can be retrieved from typing.List.__extra__)
    • typing.Dict[str, int] -> Factory(dict) (same as above)

    A way of specifying this using something similar to 1 would be great:

    @attr.s
    class C: 
        x: int = attr.ib(default=default_from_type)
  3. Same goes for conversion. It should also be opt-in.

For convenience, we could combine all 3 in one go by providing a dict with each of the type-aware keyword arguments:

import attr
from attr import use_type

@attr.s
class C: 
    x: int = attr.ib(**use_type)

@agronholm
Copy link

Sounds good to me.

@hynek
Copy link
Member Author

hynek commented Aug 28, 2017

FTR, the reason why I’m thinking about modifying __annotations__ is that IIUC, on Python 2, people are gonna have to write:

@attr.s
class C(object):
    x = attr.ib(type=int)  # type: int

Although I concur, that it should be probably solved in mypy.

The use_type magic goes a bit too far for attrs proper but we can revisit that topic once the groundwork is done.

@chadrik
Copy link
Contributor

chadrik commented Aug 28, 2017

FTR, the reason why I’m thinking about modifying __annotations__ is that IIUC, on Python 2, people are gonna have to write:

@attr.s
class C(object):
    x = attr.ib(type=int)  # type: int

Static analysis and type annotations are pretty new, so before proceeding I should make a few non-obvious things clear so that we're all on the same page:

  • the __annotations__ attribute is provided for runtime access to annotations:
    • it is available on function objects (for inspecting argument types) as of python 3.4 (PEP 3107)
    • it is available on any object with attributes (for inspecting attribute types) as of python 3.6 (PEP 526)
  • type comments do not affect __annotations__ (the attribute is not present prior to python 3.4). __annotations__ are a direct corollary to (or bi-product of?) syntax support.
  • the __annotations__ attribute does not affect static type checking. thus modifying it at runtime would have no affect on mypy.

Getting back to the original point: we can avoid the need for type comments in python 2.7 by providing pyi stubs with an overload specific to signatures that include the type argument. Here's a sketch:

from typing import Any, Mapping, Type, TypeVar, overload
T = TypeVar('T')

@overload
def attr(default: Any = ..., metadata: Mapping = ...) -> Any: ...
@overload
def attr(default: Any = ..., metadata: Mapping = ..., type: Type[T] = ...) -> T: ...

This says that if attr receives a type argument the function will return an instance of type. Otherwise, it returns Any (i.e. unknown).

That makes clear to static type-checkers that in your example x is an int without the need for type comments. So this is fine again:

@attr.s
class C(object):
     x = attr.ib(type=int)

@agronholm
Copy link

Hm, that actually looks quite clever!

@aldanor
Copy link

aldanor commented Sep 20, 2017

I'll throw my 2c in here -- I've written a little PoC library a while ago that codegens runtime type checkers in an efficient fashion given the type annotations: http://github.com/aldanor/typo. It can handle most basic type classes, but also things like Tuple[T, Dict[U, T]] with type vars and bounds.

Compared to other similar libraries, specifying x: int literally results in if isinstance(x, int) at runtime and doesn't involve a gazillion closures and lookups and decorators around it, which for simple type checks like the latter is an important thing to have. TLDR: it's very fast.

It gets pretty complicated with generic type vars though (specifically, with union-type ones) since you have to generate some pretty complicated code to deal with generics inside sum-types (not going into further details but it's fairly hairy). If you ban generics inside sum-types then it becomes very simple and straightforward -- e.g. constraints like Tuple[T, Dict[U, T]] are handled quite easily.

Maybe some pieces could be reused or partially reused in here, saving everyone a bit of time :)

@hynek
Copy link
Member Author

hynek commented Sep 20, 2017

We have recently merged generic type support, maybe you'd like to play with it a bit and give feedback?

I'm don't think we'll rush adding the actual checking anytime soon. Maybe we'll even point at external solution, so feel free to experiment.

@hynek
Copy link
Member Author

hynek commented Sep 26, 2017

First class support is in thanks to #239, we can open new issues on what to do with those type now.

@hynek hynek closed this as completed Sep 26, 2017
@glyph
Copy link
Contributor

glyph commented Nov 15, 2017

I was trying to find https://github.com/aldanor/typo today but instead I ran across https://github.com/RussBaz/enforce which looks like it may be a fairly full-featured version of the same thing.

@chadrik
Copy link
Contributor

chadrik commented Nov 15, 2017 via email

bors-fusion bot added a commit to fusionapp/fusion-index that referenced this issue Nov 15, 2017
167: Scheduled weekly dependency update for week 46 r=mithrandi




## Updates
Here's a list of all the updates bundled in this pull request. I've added some links to make it easier for you to find all the information you need.
<table align="center">

<tr>
<td><b>attrs</b></td>
<td align="center">17.2.0</td>
<td align="center">&raquo;</td>
<td align="center">17.3.0</td>
<td>
     <a href="https://pypi.python.org/pypi/attrs">PyPI</a> | <a href="https://pyup.io/changelogs/attrs/">Changelog</a> | <a href="http://www.attrs.org/">Homepage</a> 

</td>

<tr>
<td><b>cryptography</b></td>
<td align="center">2.1.2</td>
<td align="center">&raquo;</td>
<td align="center">2.1.3</td>
<td>
     <a href="https://pypi.python.org/pypi/cryptography">PyPI</a> | <a href="https://pyup.io/changelogs/cryptography/">Changelog</a> | <a href="https://github.com/pyca/cryptography">Repo</a> 

</td>

<tr>
<td><b>hypothesis</b></td>
<td align="center">3.33.0</td>
<td align="center">&raquo;</td>
<td align="center">3.37.0</td>
<td>
     <a href="https://pypi.python.org/pypi/hypothesis">PyPI</a> | <a href="https://pyup.io/changelogs/hypothesis/">Changelog</a> | <a href="https://github.com/HypothesisWorks/hypothesis/issues">Repo</a> 

</td>

</tr>
</table>



## Changelogs


### attrs 17.2.0 -> 17.3.0

>### 17.3.0

>-------------------

>Backward-incompatible Changes
>^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

>- Attributes are not defined on the class body anymore.

>  This means that if you define a class ``C`` with an attribute ``x``, the class will *not* have an attribute ``x`` for introspection anymore.
>  Instead of ``C.x``, use ``attr.fields(C).x`` or look at ``C.__attrs_attrs__``.
>  The old behavior has been deprecated since version 16.1.
>  (`253 &lt;https://github.com/python-attrs/attrs/issues/253&gt;`_)


>Changes
>^^^^^^^

>- ``super()`` and ``__class__`` now work on Python 3 when ``slots=True``.
>  (`102 &lt;https://github.com/python-attrs/attrs/issues/102&gt;`_, `226 &lt;https://github.com/python-attrs/attrs/issues/226&gt;`_, `269 &lt;https://github.com/python-attrs/attrs/issues/269&gt;`_, `270 &lt;https://github.com/python-attrs/attrs/issues/270&gt;`_, `272 &lt;https://github.com/python-attrs/attrs/issues/272&gt;`_)
>- Added ``type`` argument to ``attr.ib()`` and corresponding ``type`` attribute to ``attr.Attribute``.

>  This change paves the way for automatic type checking and serialization (though as of this release ``attrs`` does not make use of it).
>  In Python 3.6 or higher, the value of ``attr.Attribute.type`` can alternately be set using variable type annotations
>  (see `PEP 526 &lt;https://www.python.org/dev/peps/pep-0526/&gt;`_). (`151 &lt;https://github.com/python-attrs/attrs/issues/151&gt;`_, `214 &lt;https://github.com/python-attrs/attrs/issues/214&gt;`_, `215 &lt;https://github.com/python-attrs/attrs/issues/215&gt;`_, `239 &lt;https://github.com/python-attrs/attrs/issues/239&gt;`_)
>- The combination of ``str=True`` and ``slots=True`` now works on Python 2.
>  (`198 &lt;https://github.com/python-attrs/attrs/issues/198&gt;`_)
>- ``attr.Factory`` is hashable again. (`204
>  &lt;https://github.com/python-attrs/attrs/issues/204&gt;`_)
>- Subclasses now can overwrite attribute definitions of their superclass.

>  That means that you can -- for example -- change the default value for an attribute by redefining it.
>  (`221 &lt;https://github.com/python-attrs/attrs/issues/221&gt;`_, `229 &lt;https://github.com/python-attrs/attrs/issues/229&gt;`_)
>- Added new option ``auto_attribs`` to ``attr.s`` that allows to collect annotated fields without setting them to ``attr.ib()``.

>  Setting a field to an ``attr.ib()`` is still possible to supply options like validators.
>  Setting it to any other value is treated like it was passed as ``attr.ib(default=value)`` -- passing an instance of ``attr.Factory`` also works as expected.
>  (`262 &lt;https://github.com/python-attrs/attrs/issues/262&gt;`_, `277 &lt;https://github.com/python-attrs/attrs/issues/277&gt;`_)
>- Instances of classes created using ``attr.make_class()`` can now be pickled.
>  (`282 &lt;https://github.com/python-attrs/attrs/issues/282&gt;`_)


>----








### hypothesis 3.33.0 -> 3.37.0

>### 3.37.0

>-------------------

>This is a deprecation release for some health check related features.

>The following are now deprecated:

>* Passing :attr:`~hypothesis.HealthCheck.exception_in_generation` to
>  :attr:`~hypothesis.settings.suppress_health_check`. This no longer does
>  anything even when passed -  All errors that occur during data generation
>  will now be immediately reraised rather than going through the health check
>  mechanism.
>* Passing :attr:`~hypothesis.HealthCheck.random_module` to
>  :attr:`~hypothesis.settings.suppress_health_check`. This hasn&#39;t done anything
>  for a long time, but was never explicitly deprecated. Hypothesis always seeds
>  the random module when running given tests, so this is no longer an error
>  and suppressing it doesn&#39;t do anything.
>* Passing non-:class:`~hypothesis.HealthCheck` values in
>  :attr:`~hypothesis.settings.suppress_health_check`. This was previously
>  allowed but never did anything useful.

>In addition, passing a non-iterable value as :attr:`~hypothesis.settings.suppress_health_check`
>will now raise an error immediately (it would never have worked correctly, but
>it would previously have failed later). Some validation error messages have
>also been updated.

>This work was funded by `Smarkets &lt;https://smarkets.com/&gt;`_.

>-------------------


>### 3.36.1

>-------------------

>This is a yak shaving release, mostly concerned with our own tests.

>While :func:`~python:inspect.getfullargspec` was documented as deprecated
>in Python 3.5, it never actually emitted a warning.  Our code to silence
>this (nonexistent) warning has therefore been removed.

>We now run our tests with ``DeprecationWarning`` as an error, and made some
>minor changes to our own tests as a result.  This required similar upstream
>updates to :pypi:`coverage` and :pypi:`execnet` (a test-time dependency via
>:pypi:`pytest-xdist`).

>There is no user-visible change in Hypothesis itself, but we encourage you
>to consider enabling deprecations as errors in your own tests.

>-------------------


>### 3.36.0

>-------------------

>This release adds a setting to the public API, and does some internal cleanup:

>- The :attr:`~hypothesis.settings.derandomize` setting is now documented (:issue:`890`)
>- Removed - and disallowed - all &#39;bare excepts&#39; in Hypothesis (:issue:`953`)
>- Documented the :attr:`~hypothesis.settings.strict` setting as deprecated, and
>  updated the build so our docs always match deprecations in the code.

>-------------------


>### 3.35.0

>-------------------

>This minor release supports constraining :func:`~hypothesis.strategies.uuids`
>to generate :class:`~python:uuid.UUID`s of a particular version.
>(:issue:`721`)

>Thanks to Dion Misic for this feature.

>-------------------


>### 3.34.1

>-------------------

>This patch updates the documentation to suggest
>:func:`builds(callable) &lt;hypothesis.strategies.builds&gt;` instead of
>:func:`just(callable()) &lt;hypothesis.strategies.just&gt;`.

>-------------------


>### 3.34.0

>-------------------

>Hypothesis now emits deprecation warnings if you apply
>:func:`given &lt;hypothesis.given&gt;` more than once to a target.

>Applying :func:`given &lt;hypothesis.given&gt;` repeatedly wraps the target multiple
>times. Each wrapper will search the space of of possible parameters separately.
>This is equivalent but will be much more inefficient than doing it with a
>single call to :func:`given &lt;hypothesis.given&gt;`.

>For example, instead of
>``given(booleans()) given(integers())``, you could write
>``given(booleans(), integers())``

>-------------------


>### 3.33.1

>-------------------

>This is a bugfix release:

>- :func:`~hypothesis.strategies.builds` would try to infer a strategy for
>  required positional arguments of the target from type hints, even if they
>  had been given to :func:`~hypothesis.strategies.builds` as positional
>  arguments (:issue:`946`).  Now it only infers missing required arguments.
>- An internal introspection function wrongly reported ``self`` as a required
>  argument for bound methods, which might also have affected
>  :func:`~hypothesis.strategies.builds`.  Now it knows better.

>-------------------









That's it for now!

Happy merging! 🤖
bors-fusion bot added a commit to fusionapp/entropy that referenced this issue Nov 15, 2017
161: Scheduled weekly dependency update for week 46 r=mithrandi




## Updates
Here's a list of all the updates bundled in this pull request. I've added some links to make it easier for you to find all the information you need.
<table align="center">

<tr>
<td><b>attrs</b></td>
<td align="center">17.2.0</td>
<td align="center">&raquo;</td>
<td align="center">17.3.0</td>
<td>
     <a href="https://pypi.python.org/pypi/attrs">PyPI</a> | <a href="https://pyup.io/changelogs/attrs/">Changelog</a> | <a href="http://www.attrs.org/">Homepage</a> 

</td>

<tr>
<td><b>cryptography</b></td>
<td align="center">2.1.2</td>
<td align="center">&raquo;</td>
<td align="center">2.1.3</td>
<td>
     <a href="https://pypi.python.org/pypi/cryptography">PyPI</a> | <a href="https://pyup.io/changelogs/cryptography/">Changelog</a> | <a href="https://github.com/pyca/cryptography">Repo</a> 

</td>

<tr>
<td><b>lxml</b></td>
<td align="center">4.1.0</td>
<td align="center">&raquo;</td>
<td align="center">4.1.1</td>
<td>
     <a href="https://pypi.python.org/pypi/lxml">PyPI</a> | <a href="https://pyup.io/changelogs/lxml/">Changelog</a> | <a href="http://lxml.de/">Homepage</a> | <a href="https://bugs.launchpad.net/lxml">Bugtracker</a> 

</td>

<tr>
<td><b>pytz</b></td>
<td align="center">2017.2</td>
<td align="center">&raquo;</td>
<td align="center">2017.3</td>
<td>
     <a href="https://pypi.python.org/pypi/pytz">PyPI</a> | <a href="http://pythonhosted.org/pytz">Homepage</a> | <a href="http://pythonhosted.org/pytz/">Docs</a> 

</td>

</tr>
</table>



## Changelogs


### attrs 17.2.0 -> 17.3.0

>### 17.3.0

>-------------------

>Backward-incompatible Changes
>^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

>- Attributes are not defined on the class body anymore.

>  This means that if you define a class ``C`` with an attribute ``x``, the class will *not* have an attribute ``x`` for introspection anymore.
>  Instead of ``C.x``, use ``attr.fields(C).x`` or look at ``C.__attrs_attrs__``.
>  The old behavior has been deprecated since version 16.1.
>  (`253 &lt;https://github.com/python-attrs/attrs/issues/253&gt;`_)


>Changes
>^^^^^^^

>- ``super()`` and ``__class__`` now work on Python 3 when ``slots=True``.
>  (`102 &lt;https://github.com/python-attrs/attrs/issues/102&gt;`_, `226 &lt;https://github.com/python-attrs/attrs/issues/226&gt;`_, `269 &lt;https://github.com/python-attrs/attrs/issues/269&gt;`_, `270 &lt;https://github.com/python-attrs/attrs/issues/270&gt;`_, `272 &lt;https://github.com/python-attrs/attrs/issues/272&gt;`_)
>- Added ``type`` argument to ``attr.ib()`` and corresponding ``type`` attribute to ``attr.Attribute``.

>  This change paves the way for automatic type checking and serialization (though as of this release ``attrs`` does not make use of it).
>  In Python 3.6 or higher, the value of ``attr.Attribute.type`` can alternately be set using variable type annotations
>  (see `PEP 526 &lt;https://www.python.org/dev/peps/pep-0526/&gt;`_). (`151 &lt;https://github.com/python-attrs/attrs/issues/151&gt;`_, `214 &lt;https://github.com/python-attrs/attrs/issues/214&gt;`_, `215 &lt;https://github.com/python-attrs/attrs/issues/215&gt;`_, `239 &lt;https://github.com/python-attrs/attrs/issues/239&gt;`_)
>- The combination of ``str=True`` and ``slots=True`` now works on Python 2.
>  (`198 &lt;https://github.com/python-attrs/attrs/issues/198&gt;`_)
>- ``attr.Factory`` is hashable again. (`204
>  &lt;https://github.com/python-attrs/attrs/issues/204&gt;`_)
>- Subclasses now can overwrite attribute definitions of their superclass.

>  That means that you can -- for example -- change the default value for an attribute by redefining it.
>  (`221 &lt;https://github.com/python-attrs/attrs/issues/221&gt;`_, `229 &lt;https://github.com/python-attrs/attrs/issues/229&gt;`_)
>- Added new option ``auto_attribs`` to ``attr.s`` that allows to collect annotated fields without setting them to ``attr.ib()``.

>  Setting a field to an ``attr.ib()`` is still possible to supply options like validators.
>  Setting it to any other value is treated like it was passed as ``attr.ib(default=value)`` -- passing an instance of ``attr.Factory`` also works as expected.
>  (`262 &lt;https://github.com/python-attrs/attrs/issues/262&gt;`_, `277 &lt;https://github.com/python-attrs/attrs/issues/277&gt;`_)
>- Instances of classes created using ``attr.make_class()`` can now be pickled.
>  (`282 &lt;https://github.com/python-attrs/attrs/issues/282&gt;`_)


>----








### lxml 4.1.0 -> 4.1.1

>### 4.1.1

>==================

>* Rebuild with Cython 0.27.3 to improve support for Py3.7.











That's it for now!

Happy merging! 🤖
bors-fusion bot added a commit to fusionapp/documint that referenced this issue Nov 17, 2017
118: Update attrs to 17.3.0 r=mithrandi


There's a new version of [attrs](https://pypi.python.org/pypi/attrs) available.
You are currently using **17.2.0**. I have updated it to **17.3.0**



These links might come in handy:  <a href="https://pypi.python.org/pypi/attrs">PyPI</a> | <a href="https://pyup.io/changelogs/attrs/">Changelog</a> | <a href="http://www.attrs.org/">Homepage</a> 



### Changelog
> 
>### 17.3.0

>-------------------

>Backward-incompatible Changes
>^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

>- Attributes are not defined on the class body anymore.

>  This means that if you define a class ``C`` with an attribute ``x``, the class will *not* have an attribute ``x`` for introspection anymore.
>  Instead of ``C.x``, use ``attr.fields(C).x`` or look at ``C.__attrs_attrs__``.
>  The old behavior has been deprecated since version 16.1.
>  (`253 &lt;https://github.com/python-attrs/attrs/issues/253&gt;`_)


>Changes
>^^^^^^^

>- ``super()`` and ``__class__`` now work on Python 3 when ``slots=True``.
>  (`102 &lt;https://github.com/python-attrs/attrs/issues/102&gt;`_, `226 &lt;https://github.com/python-attrs/attrs/issues/226&gt;`_, `269 &lt;https://github.com/python-attrs/attrs/issues/269&gt;`_, `270 &lt;https://github.com/python-attrs/attrs/issues/270&gt;`_, `272 &lt;https://github.com/python-attrs/attrs/issues/272&gt;`_)
>- Added ``type`` argument to ``attr.ib()`` and corresponding ``type`` attribute to ``attr.Attribute``.

>  This change paves the way for automatic type checking and serialization (though as of this release ``attrs`` does not make use of it).
>  In Python 3.6 or higher, the value of ``attr.Attribute.type`` can alternately be set using variable type annotations
>  (see `PEP 526 &lt;https://www.python.org/dev/peps/pep-0526/&gt;`_). (`151 &lt;https://github.com/python-attrs/attrs/issues/151&gt;`_, `214 &lt;https://github.com/python-attrs/attrs/issues/214&gt;`_, `215 &lt;https://github.com/python-attrs/attrs/issues/215&gt;`_, `239 &lt;https://github.com/python-attrs/attrs/issues/239&gt;`_)
>- The combination of ``str=True`` and ``slots=True`` now works on Python 2.
>  (`198 &lt;https://github.com/python-attrs/attrs/issues/198&gt;`_)
>- ``attr.Factory`` is hashable again. (`204
>  &lt;https://github.com/python-attrs/attrs/issues/204&gt;`_)
>- Subclasses now can overwrite attribute definitions of their superclass.

>  That means that you can -- for example -- change the default value for an attribute by redefining it.
>  (`221 &lt;https://github.com/python-attrs/attrs/issues/221&gt;`_, `229 &lt;https://github.com/python-attrs/attrs/issues/229&gt;`_)
>- Added new option ``auto_attribs`` to ``attr.s`` that allows to collect annotated fields without setting them to ``attr.ib()``.

>  Setting a field to an ``attr.ib()`` is still possible to supply options like validators.
>  Setting it to any other value is treated like it was passed as ``attr.ib(default=value)`` -- passing an instance of ``attr.Factory`` also works as expected.
>  (`262 &lt;https://github.com/python-attrs/attrs/issues/262&gt;`_, `277 &lt;https://github.com/python-attrs/attrs/issues/277&gt;`_)
>- Instances of classes created using ``attr.make_class()`` can now be pickled.
>  (`282 &lt;https://github.com/python-attrs/attrs/issues/282&gt;`_)


>----








*Got merge conflicts? Close this PR and delete the branch. I'll create a new PR for you.*

Happy merging! 🤖
@anthrotype
Copy link

First class support is in thanks to #239, we can open new issues on what to do with those type now.

Where is the discussion about runtime automatic type checking happening?

@hynek
Copy link
Member Author

hynek commented Nov 28, 2017

There is none so far. I believe a good first step would be to add generic class-wide validators (@attr.s(validator=whatever)) and then make type checking a special case of it, possibly with some syntactic sugar.

@anthrotype
Copy link

Thanks. Shall we open a separate issue or re-open this one?

@hynek
Copy link
Member Author

hynek commented Nov 28, 2017

I think a new one would be best.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

10 participants