Compare commits
6 Commits
e5ceb4ec35
...
9fb5084b98
Author | SHA1 | Date |
---|---|---|
Julien Palard | 9fb5084b98 | |
Julien Palard | ed07e9c2cf | |
Julien Palard | 7b95b3504c | |
Julien Palard | af2344a0d3 | |
Julien Palard | ee621768e2 | |
Julien Palard | c5220012e0 |
|
@ -0,0 +1,384 @@
|
|||
# Traduction de la doc de Python et i18n
|
||||
### J. Palard et C. Revillet
|
||||
|
||||
# L'internationalisa-
|
||||
### tion :(
|
||||
|
||||
## i18n :)
|
||||
|
||||
|
||||
## [Citation du W3C](https://www.w3.org/International/questions/qa-i18n)
|
||||
> “Internationalization is the design and development of a product, application or document content that enables easy localization for target audiences that vary in culture, region, or language.
|
||||
|
||||
## [Citation du W3C](https://www.w3.org/International/questions/qa-i18n)
|
||||
> Localization refers to the adaptation of a product, application or document content to meet the language, cultural and other requirements of a specific target market (a locale).”
|
||||
|
||||
|
||||
## Localisation
|
||||
|
||||
La localisation ne concerne pas que la traduction, mais toutes les
|
||||
spécificités régionales, culturelles, telles que la monnaie, la
|
||||
disposition clavier, les symboles, icones, couleurs, formats
|
||||
numériques, formats de dates, ordre des caractères, lois, …
|
||||
|
||||
|
||||
## i18n vs l10n
|
||||
|
||||
- i18n : Rendre possible la traduction dans n’importe quelle langue
|
||||
- l10n : Ajouter une langue
|
||||
|
||||
Notes:
|
||||
|
||||
C'est de la préparation (~une fois pour toute),
|
||||
donner l'exemple de la traduction de la doc: la partie
|
||||
i18n à été faite par sphinx-doc, la l10n c'est nous.
|
||||
|
||||
## POSIX locale database
|
||||
|
||||
https://docs.python.org/3/library/locale.html
|
||||
|
||||
## POSIX locale database
|
||||
|
||||
Extrait de `/usr/share/i18n/locales/fr_FR` :
|
||||
|
||||
```
|
||||
LC_MONETARY
|
||||
int_curr_symbol "<U0045><U0055><U0052><U0020>"
|
||||
currency_symbol "<U20AC>"
|
||||
mon_decimal_point "<U002C>"
|
||||
mon_thousands_sep "<U0020>"
|
||||
mon_grouping 3
|
||||
positive_sign ""
|
||||
negative_sign "<U002D>"
|
||||
int_frac_digits 2
|
||||
```
|
||||
|
||||
## POSIX locale database
|
||||
|
||||
Liste des sections :
|
||||
|
||||
- LC_CTYPE
|
||||
- LC_COLLATE
|
||||
- LC_MESSAGES
|
||||
- LC_MONETARY
|
||||
- LC_NUMERIC
|
||||
- LC_TIME
|
||||
- LC_ADDRESS
|
||||
- …
|
||||
|
||||
## POSIX locale database
|
||||
|
||||
La traduction est une petite partie de
|
||||
l'internationalisation, définit par
|
||||
POSIX pour donner des idées de "qu'est-ce qu'on couvre
|
||||
quand on localise".
|
||||
Culture / Coutume.
|
||||
|
||||
## POSIX locale database
|
||||
|
||||
Tout est documenté !
|
||||
```
|
||||
man 5 locale
|
||||
```
|
||||
|
||||
## POSIX locale database
|
||||
|
||||
```
|
||||
dpkg-reconfigure locales
|
||||
```
|
||||
|
||||
## POSIX locale database
|
||||
|
||||
```pycon
|
||||
>>> locale.setlocale(locale.LC_ALL, 'fr_FR.utf-8')
|
||||
'fr_FR.utf-8'
|
||||
>>> datetime.datetime.now().strftime("%c")
|
||||
'mer. 13 juil. 2016 00:36:05 '
|
||||
```
|
||||
|
||||
## POSIX locale database
|
||||
|
||||
```pycon
|
||||
>>> locale.setlocale(locale.LC_ALL, 'en_US.utf-8')
|
||||
'en_US.utf-8'
|
||||
>>> datetime.datetime.now().strftime("%c")
|
||||
'Wed 13 Jul 2016 12:36:42 AM '
|
||||
```
|
||||
|
||||
# La traduction
|
||||
|
||||
![](static/2016-translation.png)
|
||||
|
||||
(Image de http://www.sphinx-doc.org/en/stable/intl.html)
|
||||
|
||||
## Préparation (i18n)
|
||||
|
||||
Marquer les chaînes :
|
||||
- Python
|
||||
```
|
||||
print(_('This is a translatable string.'))
|
||||
```
|
||||
- Jinja2
|
||||
```
|
||||
<p>{% trans %}Parts of the documentation:{% endtrans %}</p>
|
||||
```
|
||||
- …
|
||||
|
||||
## Générer le `.po`
|
||||
|
||||
- gettext
|
||||
- pybabel extract
|
||||
- django-admin.py makemessages
|
||||
- sphinx-build -b gettext
|
||||
- …
|
||||
|
||||
## fichier `.pot`
|
||||
|
||||
```po
|
||||
#: ../Doc/tutorial/appendix.rst:11
|
||||
msgid "Interactive Mode"
|
||||
msgstr ""
|
||||
|
||||
#: ../Doc/tutorial/appendix.rst:16
|
||||
msgid "Error Handling"
|
||||
msgstr ""
|
||||
```
|
||||
|
||||
## Traduire ou faire traduire
|
||||
|
||||
- poedit
|
||||
- transifex.com
|
||||
- Vé (Android)
|
||||
- gted
|
||||
- gtranslator
|
||||
- lokalize
|
||||
- betterpoeditor
|
||||
- …
|
||||
|
||||
## fichier `.po` traduit
|
||||
|
||||
```
|
||||
#: ../Doc/tutorial/appendix.rst:11
|
||||
msgid "Interactive Mode"
|
||||
msgstr "Mode interactif"
|
||||
|
||||
#: ../Doc/tutorial/appendix.rst:16
|
||||
msgid "Error Handling"
|
||||
msgstr "Gestion des erreurs"
|
||||
```
|
||||
|
||||
## Compiler le `.po` en `.mo`
|
||||
|
||||
- msgfmt
|
||||
- django-admin compilemessages
|
||||
- …
|
||||
|
||||
Notes:
|
||||
- le _ est une convention: (gettext, django.utils.translation.urgettext as _, ...)
|
||||
- `po` pour `portable object`
|
||||
- `mo` pour `machine object`
|
||||
|
||||
## gettext
|
||||
|
||||
https://docs.python.org/3/library/gettext.html
|
||||
- from gettext import gettext as _
|
||||
- ngettext
|
||||
- pgettext ?
|
||||
- …
|
||||
|
||||
Notes:
|
||||
pgettext: Permet de donner du contexte à une traduction (Voir https://bugs.python.org/issue2504)
|
||||
Basiquement, le genre, l'emplacement (menu, ...), ou n'importe quel autre désambiguation, typiquement "date" pouvant être un fruit ou calendaire, un contexte est necessaire, car ces deux mots peuvent être différents dans d'autres langues.
|
||||
|
||||
|
||||
# potpie
|
||||
|
||||
potpie génère des traductions de test, utiles pour trouver les appels manquants à gettext.
|
||||
```
|
||||
$ pip install potpie
|
||||
```
|
||||
```
|
||||
$ potpie --type unicode 3.5/tutorial.po potpie/tutorial.po
|
||||
```
|
||||
```
|
||||
#: ../Doc/tutorial/appendix.rst:5
|
||||
msgid "Appendix"
|
||||
msgstr "Ȧƥƥḗƞḓīẋ"
|
||||
#: ../Doc/tutorial/appendix.rst:16
|
||||
msgid "Error Handling"
|
||||
msgstr "Ḗřřǿř Ħȧƞḓŀīƞɠ"
|
||||
```
|
||||
|
||||
# Formatage des chaînes
|
||||
|
||||
```
|
||||
_("Hello {name}").format()
|
||||
```
|
||||
ou
|
||||
```
|
||||
_("Hello {name}".format())
|
||||
```
|
||||
> EN : "Hello Guido"
|
||||
> FR : "Bonjour Guido"
|
||||
|
||||
## Formatage des chaînes
|
||||
|
||||
```
|
||||
_("{} likes {}")
|
||||
```
|
||||
ou
|
||||
```
|
||||
_("{0} likes {1}")
|
||||
```
|
||||
> EN : "Guido likes Python"
|
||||
> FR : "Guido aime Python"
|
||||
|
||||
## Formatage des chaînes
|
||||
|
||||
```
|
||||
_("Today is {0} {1}")
|
||||
```
|
||||
ou
|
||||
```
|
||||
_("Today is {month} {day}")
|
||||
```
|
||||
> EN : "Today is October 16"
|
||||
> FR : "Aujourd'hui c'est le 16 Octobre"
|
||||
|
||||
## Formatage des chaînes
|
||||
|
||||
```
|
||||
_("That is a ") + car.color + $(" car")
|
||||
```
|
||||
> EN : "That is a blue car"
|
||||
> FR : "C'est une bleu voiture"
|
||||
|
||||
# Faire, ne pas faire
|
||||
|
||||
> Donner une chaîne formattée à gettext
|
||||
Pas bien:
|
||||
```
|
||||
_("Hello {name}".format())
|
||||
```
|
||||
Bien:
|
||||
```
|
||||
_("Hello {name}").format()
|
||||
```
|
||||
|
||||
## Faire, ne pas faire
|
||||
|
||||
> Penser que le pluriel se gère pareil dans toutes les langues
|
||||
Pas bien:
|
||||
```
|
||||
print(_("{} file{} deleted").format(n, "s" if n > 1 else ""))
|
||||
```
|
||||
Bien:
|
||||
```
|
||||
print(ngettext("{nb} file removed",
|
||||
"{nb} files removed", n).format(n))
|
||||
```
|
||||
|
||||
## Faire, ne pas faire
|
||||
|
||||
> Penser que les traducteurs pourront toujours mettre les mots dans le même ordre
|
||||
Pas bien:
|
||||
```
|
||||
print(_("%s %s %s").format(
|
||||
user_login,
|
||||
gettext("likes"),
|
||||
fav_ingredient));
|
||||
```
|
||||
Bien:
|
||||
```
|
||||
print(_("{username} likes {ingredent}").format(
|
||||
user_login,
|
||||
fav_ingredient));
|
||||
```
|
||||
|
||||
# docs.python.org/fr
|
||||
|
||||
Autres projets de traduction:
|
||||
- http://docs.python.jp/3/
|
||||
- http://docs.python.org.ar/tutorial/3/real-index.html
|
||||
La doc de Python utilise `sphinx-doc`.
|
||||
|
||||
## Historique du projet
|
||||
|
||||
- Projet né en 2012 (ou avant ?)
|
||||
- 2013, 2014 : au point mort
|
||||
- Fin 2015 : Projet relancé
|
||||
- 2016 : On avance pour pousser la traduction sur docs.python.org/fr/ http://bugs.python.org/issue26546
|
||||
|
||||
## Pourquoi
|
||||
|
||||
![](static/2016-helping.jpg)
|
||||
|
||||
## Pourquoi
|
||||
|
||||
- Je m'ennuie dans le RER, alors je traduis…
|
||||
- C'est un outil d'évangélisation
|
||||
- La langue ne devrait pas être un frein pour apprendre le Python, peu importe l'age et le niveau de scolarisation
|
||||
- Il n'y a aucune raison à ce que l'anglais soit un prérequis de Python, au contraire, Python pourrait être un moyen de se familiariser avec l'anglais
|
||||
- Apprendre deux langues en même temps, c'est un peu trop meta.
|
||||
|
||||
## Github
|
||||
|
||||
https://github.com/AFPy/python_doc_fr/
|
||||
![](static/2016-python_doc_fr_github.png)
|
||||
|
||||
## Progression
|
||||
|
||||
- 2016-01: 6%
|
||||
- 2016-02: 11%
|
||||
- 2016-03: 14%
|
||||
- 2016-04: 22%
|
||||
- 2016-05: 23%
|
||||
- 2016-06: Tentative de merge avec docs.python.org
|
||||
12 contributeurs depuis 2012
|
||||
|
||||
## Github
|
||||
|
||||
Progression
|
||||
![](static/2016-progression_100.png)
|
||||
|
||||
## Github
|
||||
|
||||
Progression
|
||||
![](static/2016-progression.png)
|
||||
|
||||
## Comment on fait
|
||||
|
||||
```bash
|
||||
$ git clone https://github.com/AFPy/python_doc_fr.git
|
||||
```
|
||||
…
|
||||
```bash
|
||||
$ poedit 3.5/library.po
|
||||
```
|
||||
…
|
||||
```bash
|
||||
$ make
|
||||
```
|
||||
|
||||
## Comment on fait
|
||||
|
||||
![](static/2016-pyfr.png)
|
||||
|
||||
## docs.python.org/fr/
|
||||
|
||||
En progrès:
|
||||
- https://github.com/python/docsbuild-scripts/pull/1
|
||||
- http://bugs.python.org/issue26546
|
||||
|
||||
## Et après ?
|
||||
|
||||
- https://docs.python.org/jp/
|
||||
- https://docs.python.org/es/
|
||||
|
||||
## Et après ?
|
||||
|
||||
Travailler sur quelques améliorations de
|
||||
sphinx-doc comme "Highlight untranslated paragraphs" :
|
||||
https://github.com/sphinx-doc/sphinx/issues/1246
|
||||
|
||||
# Questions ?
|
|
@ -0,0 +1,108 @@
|
|||
# docs.python.org/fr
|
||||
|
||||
<!-- .slide: data-background="static/background.jpg" -->
|
||||
|
||||
<br/>
|
||||
|
||||
<b>Julien Palard</b>
|
||||
|
||||
|
||||
# Les traductions
|
||||
|
||||
- https://afpy.org/doc/python/3.6
|
||||
- http://docs.python.jp/3/
|
||||
- http://docs.python.org.ar/tutorial/3/real-index.html
|
||||
- http://transifex.com/python-doc/
|
||||
- http://python-lab.ru/documentation/index.html
|
||||
|
||||
|
||||
## Historique du projet
|
||||
|
||||
- 2012 : Naissance du projet
|
||||
- 2013 : ø
|
||||
- 2014 : ø
|
||||
- 2015 : Projet relancé (vers décembre)
|
||||
- 2016 : +20% traduit !!
|
||||
- 2016 : Idée de docs.python.org/fr/ (bpo-26546)
|
||||
- 2016 : Thread "docs.python.org/fr/?" sur python-ideas
|
||||
- 2017 : PEP 545
|
||||
|
||||
|
||||
## Pourquoi
|
||||
|
||||
- Je m'ennuie dans le train, alors je traduis…
|
||||
- L'anglais ne devrait pas être un frein pour apprendre le Python.
|
||||
- Python pourrait au contraire introduire à l'anglais.
|
||||
|
||||
|
||||
## Github
|
||||
|
||||
https://github.com/AFPy/python_doc_fr/
|
||||
![](static/2016-python_doc_fr_github.png)
|
||||
|
||||
|
||||
## Progression
|
||||
|
||||
- 2016-01: 6%
|
||||
- 2016-02: 11%
|
||||
- 2016-03: 14%
|
||||
- 2016-04: 22%
|
||||
- 2016-05: 23%
|
||||
- 2016-06: Tentative de merge avec docs.python.org
|
||||
|
||||
12 contributeurs depuis 2012
|
||||
|
||||
|
||||
## Github
|
||||
|
||||
Progression
|
||||
![](static/2016-progression_100.png)
|
||||
|
||||
## Github
|
||||
Progression
|
||||
![](static/2016-progression.png)
|
||||
|
||||
## Comment on fait
|
||||
```bash
|
||||
$ git clone https://github.com/AFPy/python_doc_fr.git
|
||||
```
|
||||
…
|
||||
```bash
|
||||
$ poedit 3.6/library.po
|
||||
```
|
||||
…
|
||||
```bash
|
||||
$ make
|
||||
```
|
||||
|
||||
## Comment on fait
|
||||
|
||||
![](static/2016-pyfr.png)
|
||||
|
||||
## docs.python.org/fr/
|
||||
|
||||
En progrès :
|
||||
|
||||
- https://bugs.python.org/issue26546
|
||||
- https://www.python.org/dev/peps/pep-0545/
|
||||
|
||||
## Et après ?
|
||||
|
||||
- https://docs.python.org/jp/
|
||||
- https://docs.python.org/es/
|
||||
- https://docs.python.org/zh-cn/
|
||||
- …
|
||||
|
||||
## Et après ?
|
||||
|
||||
Travailler sur quelques améliorations de sphinx-doc comme:
|
||||
|
||||
- Annoncer clairement les paragraphes non-traduits: https://github.com/sphinx-doc/sphinx/issues/1246).
|
||||
- Afficher un avertissement devant les paragraphes pas à jour (fuzzy).
|
||||
|
||||
## Mais, maintenant ?
|
||||
|
||||
- https://www.python.org/dev/peps/pep-0545/
|
||||
|
||||
|
||||
# Questions ?
|
|
@ -0,0 +1,281 @@
|
|||
# asyncio (ou pas)
|
||||
|
||||
## Julien Palard
|
||||
|
||||
- Software Engineer
|
||||
- cPython core dev
|
||||
- Coordinator of docs.python.org/fr/
|
||||
- Python trainer
|
||||
- hackinscience.org
|
||||
|
||||
|
||||
# Coroutine
|
||||
|
||||
Une coroutine est une fonction dont l'exécution peut être suspendue.
|
||||
|
||||
|
||||
## Callback Hell
|
||||
|
||||
```
|
||||
function pong_handler(client)
|
||||
{
|
||||
client.on('data', function (data)
|
||||
{
|
||||
client.on('data_written', function ()
|
||||
{
|
||||
client.close()
|
||||
});
|
||||
client.write(data)
|
||||
client.flush()
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Avec des coroutines
|
||||
|
||||
```python
|
||||
async def pong_handler():
|
||||
client.write(await client.read())
|
||||
await client.flush()
|
||||
client.close()
|
||||
```
|
||||
|
||||
## Les coroutines
|
||||
|
||||
Pour être exhaustif, il existe deux types de coroutines en Python :
|
||||
|
||||
- generator-based coroutines
|
||||
- native coroutines
|
||||
|
||||
|
||||
## Generator-based coroutines
|
||||
|
||||
```pytho
|
||||
import types
|
||||
|
||||
|
||||
@types.coroutine
|
||||
def get_then_print(url):
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
## Native coroutines
|
||||
|
||||
```python
|
||||
async def get_then_print(url):
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
## Coroutines
|
||||
|
||||
Une `coroutine`, renvoie un objet `coroutine` :
|
||||
|
||||
```
|
||||
>>> async def tum():
|
||||
... print("tum")
|
||||
...
|
||||
>>> tum()
|
||||
<coroutine object tum at 0x7fa294538468>
|
||||
```
|
||||
|
||||
|
||||
## Coroutines
|
||||
|
||||
Qu'on peut manipuler :
|
||||
|
||||
|
||||
```
|
||||
>>> async def tum():
|
||||
... print("tum")
|
||||
...
|
||||
>>> a_coroutine_object = tum()
|
||||
>>> a_coroutine_object.send(None)
|
||||
tum
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
StopIteration
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
As you can see, calling `tum()` did not execute the `print("tum")`,
|
||||
but calling `.send(None)` did (see PEP 342).
|
||||
|
||||
L'appel de .send est fait par la main loop (asyncio.run).
|
||||
|
||||
|
||||
## Coroutines
|
||||
|
||||
Une coroutine renvoie juste un objet coroutine, donc à un moment, du code devra appeler la méthode `send` dessus.
|
||||
|
||||
C'est le rôle d'une *main loop*.
|
||||
|
||||
|
||||
## Récupérer un résultat
|
||||
|
||||
Le résultat d'une coroutine est stocké dans l'exception `StopIteration`.
|
||||
|
||||
Notes:
|
||||
|
||||
Dans l'attribut `value`.
|
||||
|
||||
|
||||
## await
|
||||
|
||||
Il existe un mot clé dédié à la récupération de résultat d'une coroutine :
|
||||
|
||||
`await`
|
||||
|
||||
|
||||
## await
|
||||
|
||||
Lorsqu'on lui donne un *awaitable*, `await` essaye d'obtenir son résultat.
|
||||
|
||||
Si l'*awaitable* se suspend, `await` suspends à son tour la coroutine actuelle, récursivemet, jusqu'à l'appel à `send`.
|
||||
|
||||
|
||||
## await
|
||||
|
||||
|
||||
```
|
||||
async def two():
|
||||
return 2
|
||||
|
||||
async def four():
|
||||
return await two() + await two()
|
||||
|
||||
coro = four()
|
||||
coro.send(None)
|
||||
```
|
||||
|
||||
Ce qui donne `StopIteration: 4`, de manière complètement synchrone, malgré le vocabulaire utilisé.
|
||||
|
||||
|
||||
## Suspendre une coroutine.
|
||||
|
||||
Ce n'est pas possible dans une coroutine.
|
||||
|
||||
Mais toute la chaîne d'*await* peut-être suspendue en utilisant un
|
||||
`yield` depuis un *future-like object*.
|
||||
|
||||
|
||||
## Future-like object
|
||||
|
||||
Un `future-like object` est un object implémentant `__await__`, qui a
|
||||
le droit de `yield`. L'expression du yield traversera toute la stack
|
||||
d'`await` jusqu’au `send`.
|
||||
|
||||
|
||||
## Awaitables
|
||||
|
||||
Les [awaitables](https://www.python.org/dev/peps/pep-0492/#await-expression)
|
||||
sont des objets pouvant être « attendus » via un `await`.
|
||||
|
||||
Donc c'est soit une `coroutine` soit un objet implémentant `__await__`.
|
||||
|
||||
|
||||
# Gérer ses coroutines
|
||||
|
||||
Appelons simplement `send`, et attendons-nous à la fameuse `StopIteration` :
|
||||
|
||||
```python
|
||||
async def two():
|
||||
return 2
|
||||
|
||||
async def four():
|
||||
return await two() + await two()
|
||||
|
||||
def coro_manager(coro):
|
||||
try:
|
||||
coro.send(None)
|
||||
except StopIteration as stop:
|
||||
return stop.value
|
||||
|
||||
print(coro_manager(four()))
|
||||
```
|
||||
|
||||
|
||||
## Gérer ses coroutines
|
||||
|
||||
Mais si la coroutine se suspend, notre `coro_manager` ne suffira pas :
|
||||
|
||||
```python
|
||||
class Awaitable:
|
||||
def __await__(self):
|
||||
yield
|
||||
|
||||
async def wont_terminate_here():
|
||||
await Awaitable()
|
||||
print("Terminated")
|
||||
return 42
|
||||
|
||||
print(coro_manager(wont_terminate_here()))
|
||||
```
|
||||
|
||||
## Gérer ses coroutines
|
||||
|
||||
Donc, un gestionnaire de coroutines doit rappeler send, comme celui-ci :
|
||||
|
||||
```python
|
||||
def frenetic_coro_manager(coro):
|
||||
try:
|
||||
while True:
|
||||
coro.send(None)
|
||||
except StopIteration as stop:
|
||||
return stop.value
|
||||
```
|
||||
|
||||
## Gérer ses coroutines
|
||||
|
||||
Mais notre manager frénétique ne sait s'occuper que d'une seule
|
||||
routine, peut-on faire mieux ?
|
||||
|
||||
|
||||
## Gérer ses coroutines
|
||||
|
||||
On pourrait relancer le travail de l'une d'entre elles au hasard :
|
||||
|
||||
```python
|
||||
import random
|
||||
|
||||
|
||||
def frenetic_coros_manager(*coros):
|
||||
coros = list(coros)
|
||||
while coros:
|
||||
coro = random.choice(coros)
|
||||
try:
|
||||
coro.send(None)
|
||||
except StopIteration as stop:
|
||||
coros.remove(coro)
|
||||
```
|
||||
|
||||
|
||||
## Gérer ses coroutines
|
||||
|
||||
Essayons :
|
||||
|
||||
```python
|
||||
async def tum():
|
||||
while True:
|
||||
await Awaitable()
|
||||
print("Tum")
|
||||
|
||||
async def pak():
|
||||
while True:
|
||||
await Awaitable()
|
||||
print("Pak")
|
||||
|
||||
frenetic_coros_manager(tum(), pak())
|
||||
```
|
||||
|
||||
Ohh, deux `while True:` qui coopèrent !
|
||||
|
||||
|
||||
# Questions?
|
||||
|
||||
- mamot.fr/@mdk
|
||||
- github.com/JulienPalard
|
||||
- mdk on #python-fr on libera.chat
|
|
@ -0,0 +1,350 @@
|
|||
![](static/hkis-home.png)
|
||||
|
||||
::: notes
|
||||
|
||||
Remercier ceux qui nous hébergent.
|
||||
|
||||
# HackInScience
|
||||
|
||||
<!-- .slide: data-background="static/background.jpg" -->
|
||||
|
||||
## Hackinscience
|
||||
|
||||
<br/>
|
||||
|
||||
<b>Julien Palard</b>
|
||||
|
||||
<tt>Paris.Py #16</tt>
|
||||
|
||||
|
||||
## Julien Palard
|
||||
|
||||
- Python core dev / freelance
|
||||
- CPython documentation translator (french only)
|
||||
- Python teacher/coach, at
|
||||
- Makina Corpus
|
||||
- Center for Research and Interdisciplinarity
|
||||
- Sup'Internet
|
||||
- …
|
||||
|
||||
julien@python.org, @sizeof, https://mdk.fr
|
||||
|
||||
|
||||
# HackInScience
|
||||
|
||||
Back in 2015, we started a project with the CRI of Paris Descartes: A
|
||||
one-week intensive Python class. ![](descartes-and-cri.jpg)
|
||||
|
||||
::: notes
|
||||
|
||||
"The Center for Research and Interdisciplinarity" en anglais.
|
||||
|
||||
- Ouvert à tous : élèves de l'université, chercheurs, public.
|
||||
|
||||
|
||||
## Pedagogy
|
||||
|
||||
We were aiming for 50 students per week, so we had to adapt,
|
||||
we needed:
|
||||
|
||||
- A short Python introduction (slides and a teacher).
|
||||
- Lots of exercises, sorted by difficulty.
|
||||
- A bot to correct exercises, live.
|
||||
- 2 to 3 highly available teachers in the room.
|
||||
- Short optional lessons about very specific topics.
|
||||
- Rules, teaching best practices.
|
||||
|
||||
::: notes
|
||||
|
||||
Rules like: never touch a student keyboard: they're here to learn.
|
||||
|
||||
|
||||
## 2015: Focus on content
|
||||
|
||||
We started by focusing on exercises (needed to give a course) and the
|
||||
correction bot (needed to scale).
|
||||
|
||||
Workflow from a student point of view:
|
||||
|
||||
- Clone the exercise repo
|
||||
- Do exercises
|
||||
- git push
|
||||
- Receive a mail with the correction
|
||||
|
||||
::: notes
|
||||
|
||||
It was crude, but it worked.
|
||||
|
||||
We automated exercises corrections (like exercises unit tests) using a
|
||||
Python script.
|
||||
|
||||
|
||||
## 2016: Focus on confort
|
||||
|
||||
Antoine Angot developped a website so students do no longer needed to
|
||||
use git. Emails were no longer needed, which is nice too.
|
||||
|
||||
::: notes
|
||||
|
||||
Thx bro!
|
||||
|
||||
Turns out that teaching git took a lot of time over teaching Python...
|
||||
|
||||
And emails were easily marked as spam even with SPF and DKIM configured properly.
|
||||
|
||||
|
||||
## 2017: Focus on content, again
|
||||
|
||||
The year to enhance existing parts, to rely on them, this is also the
|
||||
year of... many repositories:
|
||||
|
||||
- One for the website
|
||||
- One for the exercises (markdown files)
|
||||
- One for our internal documentation
|
||||
- One for the correction bot
|
||||
- One for the ansible playbook
|
||||
|
||||
::: notes
|
||||
|
||||
Exercises had a check.py and a solution.py
|
||||
|
||||
Internal documentation == teaching best practices.
|
||||
|
||||
|
||||
## 2018: Migrating to Django
|
||||
|
||||
Jérôme Schneider started to migrate the website to Django.<br/>
|
||||
(So we could modify it more easily.)
|
||||
|
||||
|
||||
::: notes
|
||||
|
||||
Thx bro :)
|
||||
A nice part was templates: the syntax was almost the same.
|
||||
|
||||
|
||||
# Show me the code!
|
||||
|
||||
So what is it now? 181 lines of Python (first fully working version), it
|
||||
should fit in a few slides ;)
|
||||
|
||||
::: notes
|
||||
|
||||
Today it's more like 700 lines of code, mainly little tweaks
|
||||
and personalisation.
|
||||
|
||||
|
||||
# Django models
|
||||
|
||||
```python
|
||||
class Exercise(models.Model):
|
||||
title = models.CharField(max_length=255)
|
||||
check = models.TextField()
|
||||
solution = models.TextField()
|
||||
wording = models.TextField()
|
||||
```
|
||||
|
||||
::: notes
|
||||
|
||||
Already know Django? Focus on the content.
|
||||
|
||||
|
||||
## Django models
|
||||
|
||||
Helps in generating:
|
||||
|
||||
- DB migrations;
|
||||
- Admin pages;
|
||||
- Forms;
|
||||
- Views (Using class-based views);
|
||||
- API (Using DRF);
|
||||
- Queries ("ORM" as humans say).
|
||||
|
||||
::: notes
|
||||
|
||||
A Django Model makes the code aware of the database structure.
|
||||
|
||||
- Autocompletion
|
||||
- ...
|
||||
|
||||
|
||||
# Django view
|
||||
|
||||
```python
|
||||
class ExerciseListView(LoginRequiredMixin, ListView):
|
||||
model = Exercise
|
||||
template_name = "hkis/exercises.html"
|
||||
|
||||
```
|
||||
|
||||
::: notes
|
||||
|
||||
How to read this Mixin thing?
|
||||
|
||||
Read: ExerciseListView inherite first from LoginRequiredMixin, then on ListView.
|
||||
So LoginRequiredMixin can place its method before ListView, like intercepting them.
|
||||
|
||||
|
||||
## Django view
|
||||
|
||||
|
||||
![](static/hkis-exercises.png)
|
||||
|
||||
|
||||
## Django view
|
||||
|
||||
```python
|
||||
class ExerciseView(LoginRequiredMixin, DetailView):
|
||||
model = Exercise
|
||||
template_name = "hkis/exercise.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
"""Add student answers.
|
||||
"""
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["answers"] = self.object.answers.filter(
|
||||
user=self.request.user
|
||||
).order_by("-id")
|
||||
return context
|
||||
```
|
||||
|
||||
## Django view
|
||||
|
||||
![](static/hkis-exercise.png)
|
||||
|
||||
|
||||
# Need an API now
|
||||
|
||||
```python
|
||||
class ExerciseSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = Exercise
|
||||
fields = '__all__'
|
||||
|
||||
class ExerciseViewSet(viewsets.ModelViewSet):
|
||||
queryset = Exercise.objects.all()
|
||||
serializer_class = ExerciseSerializer
|
||||
|
||||
router = routers.DefaultRouter()
|
||||
router.register('exercises', ExerciseViewSet)
|
||||
```
|
||||
|
||||
::: notes
|
||||
|
||||
Why DRF use a router? Because there's many views in a ViewSet.
|
||||
|
||||
## Need an API now
|
||||
|
||||
|
||||
![](static/hkis-api.png)
|
||||
|
||||
::: notes
|
||||
|
||||
A nice feature: The API replies with HTML when asked for, so
|
||||
it's browsable using a web browser.
|
||||
|
||||
|
||||
# Need an admin interface now
|
||||
|
||||
```python
|
||||
from django.contrib import admin
|
||||
from website.models import Answer, Exercise
|
||||
|
||||
admin.site.register(Answer)
|
||||
admin.site.register(Exercise)
|
||||
```
|
||||
|
||||
## Admin interface
|
||||
|
||||
![](static/hkis-admin.png)
|
||||
|
||||
## Admin interface
|
||||
|
||||
![](static/hkis-admin-markdown.png)
|
||||
|
||||
::: notes
|
||||
|
||||
We're using markdown to redact exercises.
|
||||
|
||||
## Admin interface
|
||||
|
||||
![](static/hkis-admin-check.png)
|
||||
|
||||
::: notes
|
||||
|
||||
This is the Python script used to check an exercise.
|
||||
|
||||
|
||||
# We need lives updates, now!
|
||||
|
||||
So when a student submit an answer, he gets a correction as soon as possible.
|
||||
|
||||
We can use `Django Channels` for this.
|
||||
|
||||
|
||||
## Django Channels
|
||||
|
||||
Need first to setup some kind of high level router:
|
||||
|
||||
```python
|
||||
application = ProtocolTypeRouter(
|
||||
{"websocket": AuthMiddlewareStack(
|
||||
URLRouter(website.routing.websocket_urlpatterns))}
|
||||
)
|
||||
```
|
||||
|
||||
and
|
||||
|
||||
```python
|
||||
websocket_urlpatterns = [
|
||||
url(
|
||||
r"^ws/answers/(?P<user_id>[0-9]+)/(?P<exercise_id>[0-9]+)/$",
|
||||
consumers.AnswerConsumer,
|
||||
)
|
||||
]
|
||||
```
|
||||
|
||||
## Django Channels
|
||||
|
||||
Note the `ws/` prefix, it's usefull once in production:
|
||||
|
||||
- nginx → gunicorn, for HTTP
|
||||
- nginx → daphne, for websockets
|
||||
|
||||
|
||||
## Django Channels
|
||||
|
||||
|
||||
We're disambiguating it nginx side:
|
||||
|
||||
```
|
||||
location /ws {
|
||||
proxy_pass http://unix:/run/hkis-website/daphne.sock;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_pass http://unix:/run/hkis-website/website.sock;
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
```
|
||||
|
||||
# The future
|
||||
|
||||
Display exercises as a tree, with subjects like datascience, web,
|
||||
low-level, and so on as group of leafs of the tree.
|
||||
|
||||
::: notes
|
||||
|
||||
So one could navigate to its preferred subject.
|
||||
|
||||
|
||||
# Questions?
|
||||
|
||||
- julien@python.org
|
||||
- Twitter: @sizeof
|
||||
- IRC: mdk on #python-fr (freenode)
|
||||
- https://mdk.fr
|
||||
- https://hackinscience.org
|
|
@ -0,0 +1,368 @@
|
|||
# The emergence of consensus in Python
|
||||
|
||||
<!-- .slide: data-background="static/background.jpg" -->
|
||||
|
||||
|
||||
<br/>
|
||||
|
||||
<b>Julien Palard</b>
|
||||
|
||||
<tt>PyCon Fr 2018</tt>
|
||||
|
||||
----
|
||||
|
||||
There should be one
|
||||
|
||||
-- and preferably only one --
|
||||
|
||||
obvious way to do it. (Tim Peters)
|
||||
|
||||
|
||||
## The emergence of consensus in Python
|
||||
|
||||
This is a study about undocumented consensus in the Python community,
|
||||
so you don't have to do it.
|
||||
|
||||
|
||||
# Julien Palard
|
||||
|
||||
- Python documentation translator
|
||||
- Teaching Python at
|
||||
- Sup'Internet
|
||||
- CRI-Paris
|
||||
- Makina Corpus
|
||||
- …
|
||||
- julien@python.org, @sizeof, https://mdk.fr
|
||||
- Yes I write Python sometimes too…
|
||||
|
||||
|
||||
## Julien Palard
|
||||
|
||||
![](static/emergence-language-switcher.png)
|
||||
|
||||
|
||||
# Digression
|
||||
|
||||
In one year, we went from 25.7% translated to 30% translated!
|
||||
|
||||
While japanese translation is at 79.2% and korean 14.6%.
|
||||
|
||||
Notes: Want news about the translation?
|
||||
|
||||
Thanks to Christophe, Antoine, Glyg, HS-157, and 27 other translators!
|
||||
|
||||
PLZ HELP
|
||||
|
||||
|
||||
# What did I do?
|
||||
|
||||
Crawled [pypi.org](https://pypi.org) to get some Python projects,
|
||||
cloned their github repo (around 4k repositories at the time of
|
||||
writing).
|
||||
|
||||
Then... played with the data ^^.
|
||||
|
||||
|
||||
## But why?
|
||||
|
||||
To answer all those questions a human or a search engine won't be able to answer.
|
||||
|
||||
Notes:
|
||||
|
||||
- For my README, should I use `rst` or `md`?
|
||||
- unittest, nose, or pytest?
|
||||
- ``setup.py``, ``requirements.txt``, ``Pipfile``, ...?
|
||||
- ...
|
||||
|
||||
|
||||
## Is it data science?
|
||||
|
||||
Hell no! It's biased, I only crawled projects published on *pypi.org* AND
|
||||
hosted on *github.com*, so I'm hitting a very specific subset of the population.
|
||||
|
||||
Note:
|
||||
### I mean
|
||||
- me: Hey consensus is to use the MIT license!
|
||||
- you: You crawled only open source projects...
|
||||
- me: Oh wait...
|
||||
|
||||
|
||||
## Digression
|
||||
|
||||
I used Jupyter, if you still don't have tried it, please take
|
||||
a look at it.
|
||||
|
||||
![](static/emergence-jupyterpreview.png)
|
||||
|
||||
|
||||
## Meta-Digression
|
||||
|
||||
If you're using Jupyter Notebook, and never tried Jupyter Lab, please try it.
|
||||
|
||||
JupyterLab will replace Jupyter notebooks, so maybe start using it.
|
||||
|
||||
```bash
|
||||
pip install jupyterlab
|
||||
jupyter-lab
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
I know you like digressions, so I'm putting digressions in my
|
||||
digression so I can digress while I digress.
|
||||
|
||||
## Meta-Digression
|
||||
|
||||
![](https://jupyterlab.readthedocs.io/en/stable/_images/jupyterlab.png)
|
||||
|
||||
|
||||
# 10 years of data
|
||||
|
||||
I do not have enough data past this so graphs tends to get messy.
|
||||
|
||||
|
||||
```python
|
||||
stats = raw_data.loc['2008-01-01':,:].resample('6M')
|
||||
```
|
||||
|
||||
Notes: While Python is 28 years old (older than git, than github, even than Java).
|
||||
|
||||
## Digression (again)
|
||||
|
||||
I used Pandas, if you never tried it...
|
||||
|
||||
![](static/emergence-pandas.png)
|
||||
|
||||
Notes:
|
||||
It's a matrix of scatter plots.
|
||||
|
||||
# README files
|
||||
|
||||
```python
|
||||
readmes = (stats['file:README.rst',
|
||||
'file:README.md',
|
||||
'file:README',
|
||||
'file:README.txt'].mean().plot())
|
||||
```
|
||||
|
||||
# README files
|
||||
|
||||
![](static/emergence-readme.png)
|
||||
|
||||
Notes:
|
||||
|
||||
## Consensus
|
||||
|
||||
10 years ago, people used ``README`` and ``README.txt``.
|
||||
|
||||
It changed around 2011, now we use ``README.md`` and ``README.rst`` files.
|
||||
|
||||
``Markdown`` won. I bet for its simplicity, readability, and also
|
||||
people may know it from elsewhere.
|
||||
|
||||
|
||||
## Consensus
|
||||
|
||||
But pypi.python.org don't support Markdown!
|
||||
|
||||
Yes, but...
|
||||
|
||||
|
||||
## Consensus
|
||||
|
||||
pypi.org does!
|
||||
|
||||
```python
|
||||
long_description_content_type='text/markdown'
|
||||
```
|
||||
|
||||
See:
|
||||
|
||||
https://pypi.org/project/markdown-description-example/
|
||||
|
||||
So use ``README.md`` files!
|
||||
|
||||
|
||||
# Requirements
|
||||
|
||||
|
||||
```python
|
||||
setups = stats['file:setup.cfg',
|
||||
'file:setup.py',
|
||||
'file:requirements.txt',
|
||||
'file:Pipfile',
|
||||
'file:Pipfile.lock'].mean().plot()
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
![](static/emergence-requirements.png)
|
||||
|
||||
Notes:
|
||||
|
||||
Nothing really interesting here :( We see the rise of Pipfile, but
|
||||
still can't say much about it...
|
||||
|
||||
## Requirements
|
||||
|
||||
For dependency managment I've seen a lot of philosophies. and it
|
||||
really depends on "are you packaging", "is it an app or a library",
|
||||
…
|
||||
|
||||
|
||||
## Digression
|
||||
|
||||
### The future
|
||||
|
||||
PEP 517 and PEP 518
|
||||
|
||||
```
|
||||
[build-system]
|
||||
requires = ["flit"]
|
||||
build-backend = "flit.api:main"
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
are introducing a way to completly remove
|
||||
setuptools and distutils from being a requirement, it make them a
|
||||
choice:
|
||||
|
||||
|
||||
# Tests
|
||||
|
||||
|
||||
```python
|
||||
tests = (raw_data.groupby('test_engine')
|
||||
.resample('Y')['test_engine']
|
||||
.size()
|
||||
.unstack()
|
||||
.T
|
||||
.fillna(0)
|
||||
.apply(lambda line: 100 * line / float(line.sum()), axis=1)
|
||||
.plot())
|
||||
```
|
||||
|
||||
## Tests
|
||||
|
||||
![](static/emergence-tests.png)
|
||||
|
||||
Notes:
|
||||
|
||||
## Sorry nose.
|
||||
|
||||
|
||||
# Documentation directory
|
||||
|
||||
|
||||
```python
|
||||
docs = stats['dir:doc/', 'dir:docs/'].mean().plot()
|
||||
```
|
||||
|
||||
## Documentation directory
|
||||
|
||||
![](static/emergence-docs.png)
|
||||
|
||||
Note: Some of you are not documenting at all!
|
||||
|
||||
Concensus emmerged around 2011 towards **docs/** instead of **doc/**, let's stick to it (please, please, no **Docs/**, I see you, cpython).
|
||||
|
||||
|
||||
# **src/** or not **src/**
|
||||
|
||||
```python
|
||||
src = pd.DataFrame(stats['dir:src/'].mean()).plot()
|
||||
```
|
||||
|
||||
## **src/** or not **src/**
|
||||
|
||||
![](static/emergence-src.png)
|
||||
|
||||
Notes:
|
||||
|
||||
This one was slow, but the concensus is to drop the use of a `src/` directory.
|
||||
|
||||
I used it a lot, convinced it would allow me to spot earlier an import bug ("." being in PYTHONPATH but not "src/"). But that's way overkill for a small win.
|
||||
|
||||
|
||||
# **tests/** or **test/**?
|
||||
|
||||
|
||||
<br/>
|
||||
|
||||
```python
|
||||
has_tests = stats['dir:tests/', 'dir:test/', ].mean().plot()
|
||||
```
|
||||
|
||||
## **tests/** or **test/**?
|
||||
|
||||
![](static/emergence-testdir.png)
|
||||
|
||||
Note: First thing I see... Not everyone is writing tests.
|
||||
|
||||
I'm glad the concensus is as for **docs/** and **doc/**, plural clearly wins. I bet it's semantically better, as the folder does not contain a test, but multiple tests.
|
||||
|
||||
pyproject.toml: to declare dependencies of your setup.py
|
||||
|
||||
|
||||
# Shebangs
|
||||
|
||||
|
||||
```python
|
||||
shebangs = (raw_data.loc['2008-01-01':,raw_data.columns
|
||||
.map(lambda col: col.startswith('shebang:'))].sum())
|
||||
```
|
||||
|
||||
```python
|
||||
top_shebangs = shebangs.sort_values().tail(4).index
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
shebangs_plot = (raw_data.loc['2008-01-01':, top_shebangs]
|
||||
.fillna(value=0).resample('6M').mean().plot())
|
||||
```
|
||||
|
||||
## Shebangs
|
||||
|
||||
![](static/emergence-shebang.png)
|
||||
|
||||
Notes:
|
||||
|
||||
I'm glad there's not so much `#!/usr/bin/env python2.7` here.
|
||||
|
||||
I'm not sure it's a good idea to specify a version in the shebang, but...
|
||||
|
||||
|
||||
# Licenses
|
||||
|
||||
```python
|
||||
top_licenses = raw_data.groupby('license').size().sort_values().tail(10)
|
||||
licenses = (raw_data.groupby('license')
|
||||
.resample('Y')['license']
|
||||
.size()
|
||||
.unstack()
|
||||
.T
|
||||
.fillna(0)
|
||||
.loc[:, list(top_licenses.index)]
|
||||
.apply(lambda line: 100 * line / float(line.sum()), axis=1)
|
||||
.plot())
|
||||
```
|
||||
|
||||
## Licenses
|
||||
|
||||
![](static/emergence-licenses.png)
|
||||
|
||||
|
||||
## Digression
|
||||
|
||||
https://choosealicense.com/
|
||||
|
||||
|
||||
# Questions?
|
||||
|
||||
<br/><br/>
|
||||
|
||||
- julien@python.org
|
||||
- Twitter @sizeof
|
||||
- https://mdk.fr
|
|
@ -0,0 +1,316 @@
|
|||
# Retours sur la PyCon U.S. 2019
|
||||
|
||||
<!-- .slide: data-background="static/background.jpg" -->
|
||||
|
||||
<br/>
|
||||
|
||||
<b>Julien Palard</b>
|
||||
|
||||
<tt>Paris.py #19</tt>
|
||||
|
||||
## Julien Palard
|
||||
|
||||
- Python core dev and documentation expert
|
||||
- Python teacher and coach at
|
||||
- Sup'Internet
|
||||
- CRI-Paris
|
||||
- Makina Corpus
|
||||
- …
|
||||
|
||||
# PyCon US
|
||||
|
||||
![](static/guido-painting.jpg)
|
||||
|
||||
## PyCon US
|
||||
|
||||
- Language summit, Education summit
|
||||
- 2 jours de tutoriels
|
||||
- 3 jours de confs (6 tracks)
|
||||
- Open spaces
|
||||
- 3 jours de sprints
|
||||
- Évènements : PyLadies Auction, dinners, ...
|
||||
- Des gens !
|
||||
|
||||
Notes:
|
||||
|
||||
On ignore ce qu'on ignore, les conférences c'est le bon endroit pour le découvrir.
|
||||
|
||||
Et de la bière :]
|
||||
|
||||
|
||||
# Language Summit
|
||||
|
||||
![](static/capi.jpg)
|
||||
|
||||
Notes:
|
||||
|
||||
Audience variée : Des anciens core devs, des nouveaux, des
|
||||
contributeurs de twisted, Django, BeeWare, on y a parlé de :
|
||||
|
||||
|
||||
## Language Summit
|
||||
|
||||
- L'API C,
|
||||
- la communication,
|
||||
- le mentoring,
|
||||
- les subinterpreters (avec des GIL indépendants),
|
||||
- mypyc,
|
||||
- inclure les time zones dans la stdlib,
|
||||
- [bouger les issues sur github](https://speakerdeck.com/mariatta/pep-581).
|
||||
- Circuit Python
|
||||
|
||||
|
||||
Notes:
|
||||
|
||||
- API C: Victor
|
||||
- La com: Comment tenter de faire mieux que pour le Walrus Operator
|
||||
- Le mentoring: Pablo Galindo Salgado, Emily Morehouse, Lisa Roach, Stéphane Wirtel
|
||||
Appel de Victor sur la ML mentoring pour plus de diversité.
|
||||
- mypyc: Essayez le, c'est pas tout a fait comme cython
|
||||
- TZ: Problem: Time zone changes are far more frequent than Python releases.
|
||||
- Circuit Python est un fork de MicroPython (copy code.py et pouf), API hardware différences
|
||||
|
||||
# Education Summit
|
||||
|
||||
Dr. Charles R. Severance nous a parlé de Coursera et leur tendance à
|
||||
rendre les cours payants, il se bat donc en sortant ses cours et en
|
||||
les hébergant lui même :
|
||||
|
||||
- py4e.com
|
||||
- dj4e.com
|
||||
|
||||
## The Zen of Python
|
||||
### Open Education Resources
|
||||
|
||||
```text
|
||||
- Content matters but not at the expense of logistics.
|
||||
- You should never assume that your user looks like you
|
||||
or thinks like you. Refuse the temptation to design for your
|
||||
youger self.
|
||||
- Access counts.
|
||||
- Accept that you are a UX designer.
|
||||
- Testing in an education environment is better than having a
|
||||
kid related to you test it.
|
||||
- If there are too many Python in-jokes, that's a bad idea,
|
||||
they exclude new users.
|
||||
- If you think soemthing is obvious, explain it anyway,
|
||||
it's a good idea — it wasn't obvious for beginners.
|
||||
- Your contributors always need guidance.
|
||||
- You will fail, and it will still be worth it.
|
||||
- Resources that exist are better than resources that don't.
|
||||
- Resources that can be found are better than resources that can't.
|
||||
- Resource that can be found and used by your target user are even better. Let's do more of that!
|
||||
```
|
||||
By Meg Ray
|
||||
|
||||
Notes:
|
||||
|
||||
Fun fact: deux speakers ont présentés le même "Zen", vu que Meg Ray était présente (keynotter!)
|
||||
|
||||
## Lightning Talks
|
||||
|
||||
Les certifications Python, ça en est où ?
|
||||
|
||||
Notes:
|
||||
Le sujet prédominant était le manque de
|
||||
certification Python, a la louche il en existe deux, elles sont
|
||||
chères, pas forcément bien faites. On pourrait se bouger pour en faire
|
||||
une meilleure, reconnue par la communauté. Enfin pas moi.
|
||||
|
||||
|
||||
# La pause
|
||||
|
||||
![](static/pycon-group.jpg)
|
||||
|
||||
|
||||
# Pleinières
|
||||
|
||||
## Russell Kenth Magee
|
||||
|
||||
Les « Python Black Swans ».
|
||||
|
||||
Notes:
|
||||
réfléchissons a un évènement qui pourrait modifier
|
||||
drastiquement Python, qui nous paraitrait évident s'il survenait. Mais
|
||||
essayons de le prévoir plutôt que le subir. Surtout s'il est dangereux.
|
||||
|
||||
## Russell Kenth Magee
|
||||
|
||||
Python dans les navigateurs ?
|
||||
|
||||
Notes:
|
||||
|
||||
Si oui selon Russell ça se
|
||||
fera via webassembly, c'est donc a nous de le faire. Il nous a fait
|
||||
une démo avec beeware d'un programme Python qui tourne sur Android,
|
||||
iOS, Linux, et dans le navigateur, joli !
|
||||
|
||||
## RIP
|
||||
|
||||
![](static/RIP-python2.jpg)
|
||||
|
||||
|
||||
# Confs
|
||||
|
||||
## Luciano Ramalho
|
||||
|
||||
```python
|
||||
def match(words, search):
|
||||
words = words.split()
|
||||
search = search.split()
|
||||
for to_find in search:
|
||||
for word in words:
|
||||
if to_find == word:
|
||||
break
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
```
|
||||
|
||||
Note:
|
||||
Luciano est pour moi une grande source d'inspiration autour de l'enseignement de Python.
|
||||
|
||||
La conf sur les ensembles, trop peu utilisés ? Ignorés ?
|
||||
|
||||
|
||||
## Luciano Ramalho
|
||||
|
||||
```python
|
||||
def match(words, search):
|
||||
return set(words.split()) >= set(search.split())
|
||||
```
|
||||
from the doc:
|
||||
|
||||
> Test whether every element in other is in the set.
|
||||
|
||||
|
||||
## De Morgan's Law
|
||||
|
||||
```python
|
||||
>>> e = {n for n in range(10) if n % 2 == 0}
|
||||
>>> p = {*range(5)}
|
||||
>>> f = {1, 1, 2, 3, 5, 8}
|
||||
>>> f - (p & e) == (f - p) | (f - e)
|
||||
True
|
||||
```
|
||||
|
||||
Notes: Luciano nous a montré ça aussi.
|
||||
|
||||
|
||||
## De Morgan's Law
|
||||
|
||||
Still not a proof, let's bring pytest and hypothesis!
|
||||
|
||||
```python
|
||||
@given(e=st.sets(st.integers()),
|
||||
p=st.sets(st.integers()),
|
||||
f=st.sets(st.integers()))
|
||||
def test_de_morgan(e, p, f):
|
||||
assert f - (p & e) == (f - p) | (f - e)
|
||||
```
|
||||
|
||||
Notes: On a eu beaucoup de Hypothesis partout, alors testons avec.
|
||||
|
||||
|
||||
## Lightning Talks
|
||||
|
||||
J'ai appris l'existence de pytype, copain de mypy, mais plus orienté inférence.
|
||||
|
||||
|
||||
## Pablo Galindo
|
||||
### Le ramasse-miettes
|
||||
|
||||
Et bah, c'est pas drôle un ramasse miette.
|
||||
|
||||
|
||||
```python
|
||||
>>> x = None
|
||||
>>> class Lazarus:
|
||||
... def __del__(self):
|
||||
... print("I'm going to be resurected!")
|
||||
... global x
|
||||
... x = self
|
||||
...
|
||||
>>> a = Lazarus()
|
||||
>>> del a
|
||||
I'm going to be resurected!
|
||||
>>> x
|
||||
<__main__.Lazarus object at 0x7fd0a02c0978>
|
||||
```
|
||||
|
||||
# Les sprints
|
||||
|
||||
Sujets variés :
|
||||
- cpython
|
||||
- mailman
|
||||
- hypothesis
|
||||
- packaging
|
||||
- pellets (flask, jinja2, click, ...)
|
||||
- mypy / mypyc
|
||||
- Circuit Python
|
||||
- ...
|
||||
|
||||
## Infra avec Ernest W. Durbin III
|
||||
|
||||
2FA sur pypi.org \o/
|
||||
|
||||
Notes:
|
||||
|
||||
Ce n'est pas public pour le moment, demandez moi ou demandez sur
|
||||
#python-infra sur freenode si vous voulez le tester.
|
||||
|
||||
|
||||
## Les sprints
|
||||
|
||||
On a démarré trois nouvelles traductions de la documentation de Python :
|
||||
|
||||
- Italien, avec Alessandro Cucci
|
||||
- Espagnol avec Raul Cumplido
|
||||
- Hindi (hi_IN) avec Sanyam Khurana
|
||||
|
||||
Notes:
|
||||
|
||||
- Ca nous mène à 17 traductions plus ou moins démarrées.
|
||||
- 9 avec une activité non négligable
|
||||
- 5 en production
|
||||
|
||||
## cpython
|
||||
|
||||
J'ai principalement bossé sur cpython (segfaults / memory leaks)
|
||||
|
||||
|
||||
# Ce que j'ai retenu ?
|
||||
|
||||
- Black, black everywhere!
|
||||
- F-string debug mode : `foo=5; print(f"{foo=}")`
|
||||
- Rencontrer les gens !
|
||||
|
||||
Notes:
|
||||
|
||||
Pour ceux sous Windows, VSCode permet maintenant d'utiliser un venv de
|
||||
WSL, cherchez "Remote Development" (need VSCode Insiders).
|
||||
|
||||
## PSF Q2 2019 Fundraiser
|
||||
|
||||
<!-- .slide: data-background="PSF_fundraiser_icon_2019.png" -->
|
||||
|
||||
Notes:
|
||||
|
||||
Ça finance aussi les ateliers de traduction de la doc :)
|
||||
|
||||
Pendant qu'on en parle, vous cotisez à l'AFPy ?
|
||||
|
||||
# Et après ?
|
||||
|
||||
Prochaine PyCon US à Pittsburgh :
|
||||
|
||||
- 15 au 23 avril 2020
|
||||
- 12 au 20 mai 2021
|
||||
|
||||
|
||||
## Et après ?
|
||||
|
||||
En attendant, suivez @pyconfr pour avoir des nouvelles de la prochaine PyCon Fr.
|
||||
|
||||
Secret : Si on la fait ce sera peut être à Bordeaux, peut être du 30
|
||||
octobre au 3 novembre, peut être.
|
After Width: | Height: | Size: 107 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 61 KiB |
After Width: | Height: | Size: 134 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 193 KiB |
After Width: | Height: | Size: 78 KiB |
After Width: | Height: | Size: 63 KiB |
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 73 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 96 KiB |
After Width: | Height: | Size: 177 KiB |
After Width: | Height: | Size: 79 KiB |
After Width: | Height: | Size: 57 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 55 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 774 KiB |
After Width: | Height: | Size: 434 KiB |
After Width: | Height: | Size: 73 KiB |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 65 KiB |
After Width: | Height: | Size: 74 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 769 KiB |
After Width: | Height: | Size: 56 KiB |
After Width: | Height: | Size: 335 KiB |