Skip to content

Commit 20e419c

Browse files
author
Sylvain MARIE
committed
Updated index and related test
1 parent 0bc1909 commit 20e419c

File tree

2 files changed

+82
-27
lines changed

2 files changed

+82
-27
lines changed

autoclass/tests/doc/test_readme_index.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ class House(object):
3030
h.nb_floors = 101
3131
assert str(h) == "House(name='mine', nb_floors=100)"
3232

33+
a = House('my_house', 200)
34+
assert str(a) == "House(name='my_house', nb_floors=200)"
35+
assert [att for att in a.keys()] == ['name', 'nb_floors']
36+
assert {a, a} == {a}
37+
assert a == {'name': 'my_house', 'nb_floors': 200}
38+
3339

3440
def test_readme_index_basic():
3541
""" First basic example in the doc """

docs/index.md

Lines changed: 76 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,26 @@
66

77
[![Documentation](https://img.shields.io/badge/doc-latest-blue.svg)](https://smarie.github.io/python-autoclass/) [![PyPI](https://img.shields.io/pypi/v/autoclass.svg)](https://pypi.python.org/pypi/autoclass/) [![Downloads](https://pepy.tech/badge/autoclass)](https://pepy.tech/project/autoclass) [![Downloads per week](https://pepy.tech/badge/autoclass/week)](https://pepy.tech/project/autoclass) [![GitHub stars](https://img.shields.io/github/stars/smarie/python-autoclass.svg)](https://github.com/smarie/python-autoclass/stargazers)
88

9-
!!! warning "`include` and `exclude` have been fixed in `@autodict` and `@autohash`, you do not need to add an underscore anymore when the attribute corresponds to a property. See [#21](https://github.com/smarie/python-autoclass/issues/21)"
9+
!!! success "`autoclass` is now fully compliant with [`pyfields`](https://smarie.github.io/python-pyfields/) ! Check out how you can create very compact classes [here](#pyfields-combo)"
1010

11-
`autoclass` provides tools to automatically generate python classes code. The objective of this library is to reduce the amount of redundancy by automatically generating parts of the code from the information already available somewhere else (typically, in the constructor signature). It is made of several independent features that can be combined:
11+
`autoclass` provides tools to automatically generate python classes code. The objective of this library is to reduce the amount of redundancy by automatically generating parts of the code from the information already available somewhere else (in the constructor signature or in the `pyfields` fields for example). It is made of several independent features that can be combined:
1212

1313
* with `@autoargs` you don't have to write `self.xxx = xxx` in your constructor
14-
* with `@autoprops` all your fields become `properties` and their setter is annotated with the same PEP484 type hints and value validation methods than the corresponding constructor argument
15-
* with `@autohash`, your object is hashable based on the tuple of all fields
14+
* with `@autoprops` all or part your constructor arguments become `properties` and their setter is annotated with the same PEP484 type hints and value validation methods
15+
* with `@autohash`, your object is hashable based on the tuple of all fields (so it can be used as a dictionary key or put in a set)
1616
* with `@autodict`, your object behaves like a dictionary, is comparable with dictionaries, and gets a string representation
17-
* with `@autoclass`, you get all of the above at once
17+
* with `@autorepr`, your object gets a string representation (use either this or `@autodict`, not both at the same time)
18+
* with `@autoclass`, you get all of the above at once (but you can still disable some of them)
1819

19-
The intent is similar to [attrs](https://github.com/python-attrs/attrs) and [PEP557](https://www.python.org/dev/peps/pep-0557): remove boilerplate code. However as opposed to these,
20+
The intent is similar to [attrs](https://github.com/python-attrs/attrs) and [PEP557 dataclasses](https://www.python.org/dev/peps/pep-0557): remove boilerplate code. However as opposed to these,
2021

21-
* this library does not change anything in your coding habits: you still create a `__init__` constructor, and everything else is provided with decorators.
22-
* all decorators can be used independently, for example if you just need to add a dictionary behaviour to an existing class you can use `@autodict` only. Besides, all decorators can be manually applied to already existing classes.
23-
* all created code is not dynamically compiled using `compile`. This obviously leads to poorer performance than `attrs` in highly demanding applications, but for many standard use cases it works well, and provides better debug-ability (you can easily step through the generated functions to understand what's going on)
24-
* as opposed to `attrs`, setters are generated for the fields so validation libraries such as [valid8](https://smarie.github.io/python-valid8/) can wrap them.
22+
* this library can be applied on *any* class. It does not change anything in your coding habits: you can still create a `__init__` constructor, and everything else is provided with decorators.
23+
* if information about fields is available from another library, `autoclass` can easily leverage it : for example you can now use [`pyfields`](https://smarie.github.io/python-pyfields/) to declare the fields, `autoclass` will support it.
24+
* all decorators above can be used independently, for example if you just need to add a dictionary behaviour to an existing class you can use `@autodict` only.
25+
* all created code is simple and readable. You can easily step through the generated functions in debug mode to understand what's going on
26+
* as opposed to `attrs`, setters are generated for the fields so validation libraries such as [valid8](https://smarie.github.io/python-valid8/) can wrap them. Alternatively if you use `pyfields`, it directly provides this feature.
2527

26-
Finally, `autoclass` simply generates the same code that you *would have written* manually. For this reason, in many cases you can use *other* libraries on top of the resulting classes without hassle. A good example is that you can use any PEP484 type checking library of your choice.
28+
In other words, `autoclass` simply generates the same code that you *would have written* manually. For this reason, in many cases you can use *other* libraries on top of the resulting classes without hassle. A good example is that you can use any PEP484 type checking library of your choice.
2729

2830

2931
## Installing
@@ -34,21 +36,21 @@ Finally, `autoclass` simply generates the same code that you *would have written
3436

3537
You may wish to also install
3638

37-
* a PEP484-based type checker: [enforce](https://github.com/RussBaz/enforce) or [pytypes](https://github.com/Stewori/pytypes).
38-
* a value validator: [valid8](https://smarie.github.io/python-valid8/) was originally created in this project and is now independent. It provides the `@validate` annotation (and it also provides the `Boolean` type)
39-
* Alternatively, you may use[PyContracts](https://andreacensi.github.io/contracts/index.html) to perform type and value validation at the same time using `@contract`, but this will not benefit from PEP484 and uses a dedicated syntax. This documentation also shows some examples.
39+
* [`pyfields`](https://smarie.github.io/python-pyfields/) to create compact classes.
40+
* a PEP484-based type checker: [typeguard](https://github.com/agronholm/typeguard) , [pytypes](https://github.com/Stewori/pytypes) or [enforce](https://github.com/RussBaz/enforce).
41+
* a value validator: [valid8](https://smarie.github.io/python-valid8/) was originally created in this project and is now independent.
42+
43+
Alternatively, you may use [PyContracts](https://andreacensi.github.io/contracts/index.html) to perform type and value validation at the same time using `@contract`, but this will not benefit from PEP484 and uses a dedicated syntax. This documentation also shows some examples.
4044

4145

4246
```bash
43-
> pip install enforce
47+
> pip install pyfields
4448
> pip install pytypes
4549
> pip install valid8
4650
> pip install PyContracts
4751
```
4852

49-
## Usage examples
50-
51-
### Basic
53+
## 1. Basic usage
5254

5355
The following code shows how you define a `House` with two attributes `name` and `nb_floors`:
5456

@@ -67,7 +69,7 @@ class House:
6769
>>> obj = House('my_house', 3)
6870

6971
>>> print(obj) # string representation
70-
House({'name': 'my_house', 'nb_floors': 3})
72+
House(name='my_house', nb_floors=3)
7173

7274
>>> [att for att in obj.keys()] # dictionary behaviour
7375
['name', 'nb_floors']
@@ -104,8 +106,50 @@ Set nb_floors to 1
104106
Set nb_floors to 3
105107
```
106108
109+
### `pyfields` combo
110+
111+
If you already use [`pyfields`](https://smarie.github.io/python-pyfields/) to define mandatory/optional fields with type/value validation, simply decorate your class with `@autoclass` and you'll get all of the above (dict view, hashability, string representation, equality...) too:
112+
113+
```python
114+
from pyfields import field
115+
from autoclass import autoclass
116+
from mini_lambda import x
117+
118+
@autoclass
119+
class House:
120+
name: str = field(check_type=True, doc="the name of your house")
121+
nb_floors: int = field(default=1, check_type=True, doc="the nb floors",
122+
validators={
123+
"should be positive": x >= 0,
124+
"should be a multiple of 100": x % 100 == 0
125+
})
126+
127+
```
128+
129+
Indeed behind the scenes, if `autoclass` detects that your class uses `pyfields`, it will automatically use the fields rather than the constructor signature to get the list of fields. You can check that all the features are there:
130+
131+
```bash
132+
>>> obj = House('my_house', 200)
133+
134+
>>> print(obj) # string representation
135+
House(name='my_house', nb_floors=200)
136+
137+
>>> [att for att in obj.keys()] # dictionary behaviour
138+
['name', 'nb_floors']
139+
140+
>>> assert {obj, obj} == {obj} # hashable: can be used in a set or as a dict key
141+
142+
>>> assert obj == House('my_house', 200) # comparison (equality)
143+
>>> assert obj == {'name': 'my_house', 'nb_floors': 200} # comparison with dicts
144+
```
145+
146+
Note: this works with python 2.7, and 3.5+. See [`pyfields` documentation ](https://smarie.github.io/python-pyfields/) for details.
147+
148+
## 2. Type and Value validation
107149
108-
### Type validation with PEP484
150+
If you do not use `pyfields`, then you might be interested to add type and value validation to your fields through another means.
151+
152+
### a- PEP484 Type validation
109153
110154
#### enforce
111155
@@ -154,8 +198,12 @@ class House:
154198
pass
155199
```
156200
201+
#### `typeguard`
202+
203+
TODO
157204
158-
### Simple Type+Value validation
205+
206+
### b- Simple Type+Value validation
159207
160208
#### valid8
161209
@@ -229,9 +277,7 @@ class House:
229277
```
230278
231279
232-
### PEP484 Type+Value validation
233-
234-
#### enforce + valid8
280+
### c- PEP484 Type+Value validation
235281
236282
Finally, in real-world applications you might wish to combine both PEP484 type checking and value validation. This works as expected, for example with `enforce` and `valid8`:
237283
@@ -368,12 +414,15 @@ Really, *"there must be a better way"* : yes there is, and that's what this libr
368414
369415
* **`@autohash`** is a decorator for a whole class. It makes the class hashable by implementing `__hash__` if not already present, where the hash is computed from the tuple of selected fields (all by default, customizable).
370416
417+
* **`@autorepr`** is a decorator for a whole class. It adds a string representation by implementing `__str__` and `__repr__` if not already present.
418+
371419
* Equivalent manual wrapper methods are provided for all decorators in this library:
372420
- `autoargs_decorate(init_func, include, exclude)`
373421
- `autoprops_decorate(cls, include, exclude)`
374422
- `autoprops_override_decorate(func, attribute, is_getter)`
375-
- `autodict_decorate(cls, include, exclude, only_constructor_args, only_public_fields)`
376-
- `autohash_decorate(cls, include, exclude, only_constructor_args, only_public_fields)`
423+
- `autodict_decorate(cls, include, exclude, only_known_fields, only_public_fields)`
424+
- `autohash_decorate(cls, include, exclude, only_known_fields, only_public_fields)`
425+
- `autorepr_decorate(cls, include, exclude, only_known_fields, only_public_fields)`
377426
378427
379428
## See Also
@@ -394,7 +443,7 @@ Really, *"there must be a better way"* : yes there is, and that's what this libr
394443
395444
* The new PEP out there, largely inspired by `attrs`: [PEP557](https://www.python.org/dev/peps/pep-0557). Check it out! There is also a [discussion on python-ideas](https://groups.google.com/forum/#!topic/python-ideas/8vUm84CCb3c).
396445
397-
* [decorator](http://decorator.readthedocs.io) library, which provides everything one needs to create complex decorators easily (signature and annotations-preserving decorators, decorators with class factory) as well as provides some useful decorators (`@contextmanager`, `@blocking`, `@dispatch_on`). We use it to preserve the signature of class constructors and overriden setter methods.
446+
* [decorator](http://decorator.readthedocs.io) library, which provides everything one needs to create complex decorators easily (signature and annotations-preserving decorators, decorators with class factory) as well as provides some useful decorators (`@contextmanager`, `@blocking`, `@dispatch_on`). We used it to preserve the signature of class constructors and overriden setter methods. Now we use [`makefun`](https://smarie.github.io/python-makefun/) instead, which was inspired by it.
398447
399448
* When came the time to find a name for this library I was stuck for a while. In my quest for finding an explicit name that was not already used, I found many interesting libraries on [PyPI](http://pypi.python.org/). I did not test them all but found them 'good to know':
400449
* [decorator-args](https://pypi.python.org/pypi/decorator-args/1.1)

0 commit comments

Comments
 (0)