8000 Adds first docs · dry-python/classes@c976b7d · GitHub
[go: up one dir, main page]

Skip to content

Commit c976b7d

Browse files
committed
Adds first docs
1 parent d9292a2 commit c976b7d

File tree

6 files changed

+126
-8
lines changed

6 files changed

+126
-8
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ install: poetry install
1515
script:
1616
- poetry run flake8 .
1717
- poetry run mypy classes tests/**/*.py
18-
- poetry run pytest
18+
- poetry run pytest . docs/pages
1919
- poetry run doc8 -q docs
2020
- poetry check
2121
- poetry run pip check

classes/typeclass.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,7 @@ def __call__(
9292
We don't guarantee the order of types inside groups.
9393
Use correct types, do not rely on our order.
9494
95-
Callbacks
96-
~~~~~~~~~
95+
.. rubric:: Callbacks
9796
9897
Since, we define ``__call__`` method for this class,
9998
it can be used and typechecked everywhere,
@@ -238,8 +237,7 @@ def typeclass(
238237
then it will be called,
239238
otherwise the default implementation will be called instead.
240239
241-
Generics
242-
~~~~~~~~
240+
.. rubric:: Generics
243241
244242
We also support generic, but the support is limited.
245243
We cannot rely on type parameters of the generic type,
@@ -277,6 +275,8 @@ def typeclass(
277275
we would like to improve our support for specific generic instances
278276
like ``MyGeneric[int]`` only. But, that's the best we can do for now.
279277
278+
.. rubric:: Protocols
279+
280280
We also support protocols. It has the same limitation as ``Generic`` types.
281281
It is also dispatched after all regular ``instance``s are checked.
282282

docs/pages/concept.rst

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,70 @@
1-
Typeclass: the concept
2-
======================
1+
The concept
2+
===========
3+
4+
Typeclasses are another form of polymorphism
5+
that is widely used in some functional languages.
6+
7+
What's the point?
8+
9+
Well, we need to do different logic based on input type.
10+
11+
Like ``len()`` function which
12+
works differently for ``"string"`` and ``[1, 2]``.
13+
Or ``+`` operator that works for numbers like "add"
14+
and for strings it works like "concatenate".
15+
16+
Classes and interfaces
17+
~~~~~~~~~~~~~~~~~~~~~~
18+
19+
Traditionally, object oriented languages solve it via classes.
20+
21+
And classes are hard.
22+
They have internal state, inheritance, methods (including static ones),
23+
strong type, structure, class-level constants, life-cycle, and etc.
24+
25+
Magic methods
26+
~~~~~~~~~~~~~
27+
28+
That's why Python is not purely built around this idea.
29+
It also has protocols: ``__len__``, ``__iter__``, ``__add__``, etc.
30+
Which are called "magic mathods" most of the time.
31+
32+
This really helps and keeps the language easy.
33+
But, have some serious problem:
34+
we cannot add new protocols / magic methods to the existing data types.
35+
36+
You cannot add new methods to the ``list`` type (and that's a good thing!),
37+
you cannot also change how ``__len__`` for example work there.
38+
39+
But, sometimes we really need this!
40+
One of the most simple example is ``json`` serialisation and deserialisation.
41+
Each type should be covered, each one works differently, they can nest.
42+
And moreover, it is 100% fine and expected
43+
to add your own types to this process.
44+
45+
So, how does it work?
46+
47+
48+
Steps
49+
-----
50+
51+
To use typeclasses you should understand these steps:
52+
53+
.. mermaid::
54+
:caption: Typeclass steps.
55+
56+
graph LR
57+
F1["Typeclass definition"] --> F2["Instance definition"]
58+
F2 --> F2
59+
F2 --> F3["Calling"]
60+
61+
# TODO: cover each steps
62+
# TODO: json example for simple types
63+
64+
65+
singledispatch
66+
--------------
67+
68+
One may ask, what is the difference
69+
with `singledispatch <https://docs.python.org/3/library/functools.html#functools.singledispatch>`_
70+
function from the standard library?

docs/pages/typeclass.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
Typeclass
22
=========
3+
4+
.. automodule:: classes.typeclass
5+
:members:

docs/pages/typesafety.rst

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,48 @@
1-
Type safety
1+
Type-safety
22
===========
3+
4+
We try to bring as much type safety as possible.
5+
6+
However, there are some limitations.
7+
This section will guide you through both
8+
features and troubles of type-safe typeclasses in Python.
9+
10+
11+
Features
12+
--------
13+
14+
First of all, we always check that the signature is the same for all cases.
15+
16+
.. code:: python
17+
18+
>>> from classes import typeclass
19+
>>> @typeclass
20+
... def example(instance, arg: int, *, keyword: str) -> bool:
21+
... ...
22+
...
23+
>>> @example.instance(str)
24+
... def _example_str(instance: str, arg: int, *, keyword: str) -> bool:
25+
... return instance * arg + keyword
26+
...
27+
28+
Let's look at this example closely:
29+
30+
1. We create a typeclass with the signature that all cases must share:
31+
except for the ``instance`` parameter, which is polymorphic.
32+
2. We check that return type of all cases match the original one:
33+
``bool`` in our particular case
34+
3. We check that ``instance`` has the correct type in ``_example_str``
35+
36+
When calling typeclasses, we also do the type check:
37+
38+
.. code:: python
39+
40+
>>> example('a', 3, keyword='b')
41+
'aaab'
42+
43+
Here are features that we support:
44+
45+
1. Typechecker knows that we allow only defined instances
46+
to be the first (or instance) parameter in a call.
47+
2. We also check that other parameters do exist in the original signature
48+
3. We check the return type: it matches that defined one in the signature

setup.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ norecursedirs = temp *.egg .eggs dist build docs .tox .git __pycache__
5656
# you an overhead. See `docs/template/development-process.rst`.
5757
addopts =
5858
--doctest-modules
59+
--doctest-glob='*.rst'
5960
--cov=classes
6061
--cov-report=term:skip-covered
6162
--cov-report=html

0 commit comments

Comments
 (0)
0