Compare commits

...

6 Commits

Author SHA1 Message Date
Julien Palard 9fb5084b98
Import: paris.py #13. 2023-02-10 17:35:25 +01:00
Julien Palard ed07e9c2cf
Import: PyConFr 2016. 2023-02-10 17:29:16 +01:00
Julien Palard 7b95b3504c
Import: Paris.py #14. 2023-02-10 16:13:20 +01:00
Julien Palard af2344a0d3
Import: PyConFr 2018. 2023-02-10 15:48:57 +01:00
Julien Palard ee621768e2
Import: Paris.py #16 2023-02-10 15:29:09 +01:00
Julien Palard c5220012e0
Import: Paris.py #19. 2023-02-07 22:46:44 +01:00
38 changed files with 1807 additions and 0 deletions

384
2016-pyconfr-i18n.md Normal file
View File

@ -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 nimporte 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 ?

108
2017-paris.py-13-i18n.md Normal file
View File

@ -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 ?

281
2018-paris.py-14-asyncio.md Normal file
View File

@ -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` jusquau `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

View File

@ -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

368
2018-pycon-fr-emergence.md Normal file
View File

@ -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

316
2019-paris.py.md Normal file
View File

@ -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.

BIN
static/2016-helping.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

BIN
static/2016-progression.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
static/2016-pyfr.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

BIN
static/2016-translation.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
static/RIP-python2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

BIN
static/capi.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

BIN
static/emergence-docs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

BIN
static/emergence-pandas.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

BIN
static/emergence-readme.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
static/emergence-src.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

BIN
static/emergence-tests.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

BIN
static/guido-painting.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 774 KiB

BIN
static/guido-puzzle.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 KiB

BIN
static/hkis-CRI.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

BIN
static/hkis-admin-check.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
static/hkis-admin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
static/hkis-api.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

BIN
static/hkis-exercise.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
static/hkis-exercises.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
static/hkis-home.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 769 KiB

BIN
static/hkis-stats.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
static/pycon-group.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 KiB