Dedupicating Makefiles.
This commit is contained in:
parent
675d7b7778
commit
d6cabd6284
|
@ -11,7 +11,7 @@ jobs:
|
||||||
matrix:
|
matrix:
|
||||||
directory:
|
directory:
|
||||||
- python-initiation
|
- python-initiation
|
||||||
- python-avance
|
- python-avancé
|
||||||
- drf-initiation
|
- drf-initiation
|
||||||
- django-initiation
|
- django-initiation
|
||||||
- python-perfs
|
- python-perfs
|
||||||
|
|
|
@ -21,6 +21,7 @@ jobs:
|
||||||
python-version: '3.10'
|
python-version: '3.10'
|
||||||
cache: pip
|
cache: pip
|
||||||
- run: sudo apt-get install -y cutycapt
|
- run: sudo apt-get install -y cutycapt
|
||||||
|
- run: python3 -m pip install -r requirements.txt
|
||||||
- run: make -C ${{ inputs.directory }} test
|
- run: make -C ${{ inputs.directory }} test
|
||||||
- name: Publish
|
- name: Publish
|
||||||
env:
|
env:
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
SRCS := $(sort $(wildcard *.md))
|
||||||
|
DEST := $(notdir $(PWD))
|
||||||
|
|
||||||
|
.PHONY: static
|
||||||
|
static: output/index.html
|
||||||
|
|
||||||
|
%.html: %.md
|
||||||
|
sed 's/#!//e;' perfs.md | mdtoreveal /dev/stdin --output $@
|
||||||
|
|
||||||
|
output/index.md: $(SRCS)
|
||||||
|
mkdir -p output
|
||||||
|
cat $(SRCS) > output/index.md
|
||||||
|
|
||||||
|
.PHONY: rsync
|
||||||
|
rsync: static
|
||||||
|
rsync -vah --delete output/ mdk_fr@mdk.fr:/var/www/mdk.fr/$DEST/
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -fr output
|
||||||
|
|
||||||
|
.PHONY: entr
|
||||||
|
entr:
|
||||||
|
ls -1 *.md | entr $(MAKE) static
|
||||||
|
|
||||||
|
.PHONY: serve
|
||||||
|
serve: static
|
||||||
|
python3 -m http.server -d output/
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test:
|
||||||
|
if [ -f test.py ]; then \
|
||||||
|
python test.py *.md; \
|
||||||
|
fi
|
87
README.md
87
README.md
|
@ -1,6 +1,16 @@
|
||||||
# Python Introduction Slides
|
# The slides I use while teaching
|
||||||
|
|
||||||
https://mdk.fr/python-initiation/
|
Each directory contains a Makefile that builds the slides using
|
||||||
|
[mdtoreveal](https://pypi.org/project/mdtoreveal/).
|
||||||
|
|
||||||
|
Each directory is also uploaded to mdk.fr:
|
||||||
|
|
||||||
|
- https://mdk.fr/python-initiation
|
||||||
|
- https://mdk.fr/python-avancé
|
||||||
|
- https://mdk.fr/drf-initiation
|
||||||
|
- https://mdk.fr/django-initiation
|
||||||
|
- https://mdk.fr/python-perfs
|
||||||
|
- https://mdk.fr/git-initiation
|
||||||
|
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
@ -74,3 +84,76 @@ Souci : Jour 1 pytest nécessite Jour 2 pip...
|
||||||
- jupyter
|
- jupyter
|
||||||
|
|
||||||
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />Ce(tte) œuvre est mise à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Licence Creative Commons Attribution 4.0 International</a>.
|
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />Ce(tte) œuvre est mise à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Licence Creative Commons Attribution 4.0 International</a>.
|
||||||
|
|
||||||
|
# DRF
|
||||||
|
|
||||||
|
Side project : https://github.com/JulienPalard/drf-demos
|
||||||
|
|
||||||
|
- Revue des bases et consolidation Python et Django
|
||||||
|
- Présentation des types d'API, approfondissement de REST/HATEOAS
|
||||||
|
- Rappels autour de la sémantique HTTP
|
||||||
|
- django-rest-framework: La sérialisation
|
||||||
|
- django-rest-framework: Les différents types de vues
|
||||||
|
- django-rest-framework: Les permissions
|
||||||
|
- django-rest-framework: Les relations
|
||||||
|
- Les tests et la maintenabilité
|
||||||
|
|
||||||
|
|
||||||
|
# Objectifs pédagogiques
|
||||||
|
|
||||||
|
- Pouvoir démarrer rapidement un projet DRF.
|
||||||
|
- Savoir designer une API.
|
||||||
|
- Implémenter un service headless en utilisant DRF.
|
||||||
|
|
||||||
|
|
||||||
|
# TP
|
||||||
|
|
||||||
|
- Projet 1 : API « Horloge parlante ».
|
||||||
|
- Projet 2 : API « memcached ».
|
||||||
|
- Projet 3 : API « file system ».
|
||||||
|
- Projet 4 : API « uptime manager ».
|
||||||
|
|
||||||
|
|
||||||
|
# Formation Initiation Linux (2 jours)
|
||||||
|
|
||||||
|
Cette formation est destinée à toute personne souhaitant utiliser
|
||||||
|
Linux, pour du développement, de l'administration système, ou pour un
|
||||||
|
usage quotidien.
|
||||||
|
|
||||||
|
|
||||||
|
## Stagiaires
|
||||||
|
|
||||||
|
Maximum 5 par sessions, pour commencer, peut monter à 7.
|
||||||
|
|
||||||
|
|
||||||
|
## Pré-requis
|
||||||
|
|
||||||
|
Aucun.
|
||||||
|
|
||||||
|
|
||||||
|
## Objectifs pédagogiques
|
||||||
|
|
||||||
|
- Pouvoir utiliser une machine sous Linux au quotidien.
|
||||||
|
- Être à l'aise avec les interfaces en ligne de commande.
|
||||||
|
- Savoir installer et utiliser des logiciels.
|
||||||
|
- Manipuler des fichiers, des données.
|
||||||
|
|
||||||
|
|
||||||
|
## Plan
|
||||||
|
|
||||||
|
### Jour 1
|
||||||
|
|
||||||
|
- Présentation de l'environnement Linux.
|
||||||
|
- Maniement de l'émulateur de terminal.
|
||||||
|
- Approche des commandes classiques :
|
||||||
|
- `man`, `cd`, `ls`, `pwd`, `mv`, `cp`, `rm`, `less`, …
|
||||||
|
- Installer, désinstaller des applications depuis le gestionnaire de paquets.
|
||||||
|
|
||||||
|
|
||||||
|
### Jour 2
|
||||||
|
|
||||||
|
- L'accès à l'extérieur avec `ssh`, `rsync`, `curl`, et gestion des sauvegardes.
|
||||||
|
- Introduction à la gestion de sources en utilisant `git`.
|
||||||
|
- Manipulation de données en utilisant `awk`, `sed`, `grep`, `find`.
|
||||||
|
- L'édition de texte depuis un terminal en utilisant `emacs`.
|
||||||
|
- Approche du système de fichier : les droits, la sécurité, `mount`.
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
# Formation Initiation Linux (2 jours)
|
|
||||||
|
|
||||||
Cette formation est destinée à toute personne souhaitant utiliser
|
|
||||||
Linux, pour du développement, de l'administration système, ou pour un
|
|
||||||
usage quotidien.
|
|
||||||
|
|
||||||
|
|
||||||
## Stagiaires
|
|
||||||
|
|
||||||
Maximum 5 par sessions, pour commencer, peut monter à 7.
|
|
||||||
|
|
||||||
|
|
||||||
## Pré-requis
|
|
||||||
|
|
||||||
Aucun.
|
|
||||||
|
|
||||||
|
|
||||||
## Objectifs pédagogiques
|
|
||||||
|
|
||||||
- Pouvoir utiliser une machine sous Linux au quotidien.
|
|
||||||
- Être à l'aise avec les interfaces en ligne de commande.
|
|
||||||
- Savoir installer et utiliser des logiciels.
|
|
||||||
- Manipuler des fichiers, des données.
|
|
||||||
|
|
||||||
|
|
||||||
## Plan
|
|
||||||
|
|
||||||
### Jour 1
|
|
||||||
|
|
||||||
- Présentation de l'environnement Linux.
|
|
||||||
- Maniement de l'émulateur de terminal.
|
|
||||||
- Approche des commandes classiques :
|
|
||||||
- `man`, `cd`, `ls`, `pwd`, `mv`, `cp`, `rm`, `less`, …
|
|
||||||
- Installer, désinstaller des applications depuis le gestionnaire de paquets.
|
|
||||||
|
|
||||||
|
|
||||||
### Jour 2
|
|
||||||
|
|
||||||
- L'accès à l'extérieur avec `ssh`, `rsync`, `curl`, et gestion des sauvegardes.
|
|
||||||
- Introduction à la gestion de sources en utilisant `git`.
|
|
||||||
- Manipulation de données en utilisant `awk`, `sed`, `grep`, `find`.
|
|
||||||
- L'édition de texte depuis un terminal en utilisant `emacs`.
|
|
||||||
- Approche du système de fichier : les droits, la sécurité, `mount`.
|
|
|
@ -0,0 +1 @@
|
||||||
|
../Makefile
|
|
@ -1,33 +0,0 @@
|
||||||
.PHONY: help
|
|
||||||
help:
|
|
||||||
@echo "Usage:"
|
|
||||||
@echo " make static # to build static version."
|
|
||||||
@echo " make test # to run tests."
|
|
||||||
@echo " make rsync # rsync to prod"
|
|
||||||
@echo " make clean"
|
|
||||||
|
|
||||||
.PHONY: static
|
|
||||||
static: output/index.html
|
|
||||||
|
|
||||||
.PHONY: check
|
|
||||||
test:
|
|
||||||
python test.py *.md
|
|
||||||
|
|
||||||
%.html: %.md
|
|
||||||
mdtoreveal $< --output $@
|
|
||||||
|
|
||||||
output/index.md: django.md
|
|
||||||
mkdir -p output
|
|
||||||
cat $< > $@
|
|
||||||
|
|
||||||
.PHONY: rsync
|
|
||||||
rsync: static
|
|
||||||
rsync -vah --delete output/ mdk_fr@mdk.fr:/var/www/mdk.fr/django-initiation/
|
|
||||||
|
|
||||||
.PHONY: clean
|
|
||||||
clean:
|
|
||||||
rm -fr output/
|
|
||||||
|
|
||||||
.PHONY: serve
|
|
||||||
serve:
|
|
||||||
python -m http.server -d output/
|
|
|
@ -0,0 +1 @@
|
||||||
|
../Makefile
|
|
@ -1,27 +0,0 @@
|
||||||
# Contenu
|
|
||||||
|
|
||||||
Side project : https://github.com/JulienPalard/drf-demos
|
|
||||||
|
|
||||||
- Revue des bases et consolidation Python et Django
|
|
||||||
- Présentation des types d'API, approfondissement de REST/HATEOAS
|
|
||||||
- Rappels autour de la sémantique HTTP
|
|
||||||
- django-rest-framework: La sérialisation
|
|
||||||
- django-rest-framework: Les différents types de vues
|
|
||||||
- django-rest-framework: Les permissions
|
|
||||||
- django-rest-framework: Les relations
|
|
||||||
- Les tests et la maintenabilité
|
|
||||||
|
|
||||||
|
|
||||||
# Objectifs pédagogiques
|
|
||||||
|
|
||||||
- Pouvoir démarrer rapidement un projet DRF.
|
|
||||||
- Savoir designer une API.
|
|
||||||
- Implémenter un service headless en utilisant DRF.
|
|
||||||
|
|
||||||
|
|
||||||
# TP
|
|
||||||
|
|
||||||
- Projet 1 : API « Horloge parlante ».
|
|
||||||
- Projet 2 : API « memcached ».
|
|
||||||
- Projet 3 : API « file system ».
|
|
||||||
- Projet 4 : API « uptime manager ».
|
|
|
@ -35,7 +35,7 @@ Dans Django on va avoir principalement des `models`, des `vues`, des
|
||||||
|
|
||||||
On travaillera toujours dans un `venv` :
|
On travaillera toujours dans un `venv` :
|
||||||
|
|
||||||
```python
|
```bash
|
||||||
python -m pip install django
|
python -m pip install django
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ python -m pip install django
|
||||||
|
|
||||||
Pour démarrer un projet, une commande :
|
Pour démarrer un projet, une commande :
|
||||||
|
|
||||||
```python
|
```bash
|
||||||
django-admin startproject project
|
django-admin startproject project
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ django-admin startproject project
|
||||||
|
|
||||||
Une fois dans le projet, pour créer une application, une commande :
|
Une fois dans le projet, pour créer une application, une commande :
|
||||||
|
|
||||||
```python
|
```bash
|
||||||
python manage.py startapp watch
|
python manage.py startapp watch
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -307,8 +307,8 @@ Dans `project/urls.py` on va se rajouter une URL pour la page d'accueil :
|
||||||
from watch import views
|
from watch import views
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
...
|
...,
|
||||||
...
|
...,
|
||||||
path("", views.index, name="index"),
|
path("", views.index, name="index"),
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
@ -721,7 +721,7 @@ fichier doit commencer par `test` pour être trouvé.
|
||||||
|
|
||||||
Les tests s'exécutent via :
|
Les tests s'exécutent via :
|
||||||
|
|
||||||
```python
|
```bash
|
||||||
python manage.py test
|
python manage.py test
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
from string import ascii_letters, digits
|
|
||||||
import re
|
|
||||||
import doctest
|
|
||||||
from tempfile import NamedTemporaryFile
|
|
||||||
import importlib.util
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("file", nargs="+")
|
|
||||||
parser.add_argument("-v", "--verbose", action="store_true")
|
|
||||||
parser.add_argument("-d", "--debug", action="store_true")
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
for file_to_test in args.file:
|
|
||||||
with open(file_to_test) as f:
|
|
||||||
source = f.read()
|
|
||||||
|
|
||||||
with NamedTemporaryFile(mode="w", suffix=".py") as f:
|
|
||||||
for example_match in re.finditer("```python.*?```", source, re.S):
|
|
||||||
example = example_match.group()
|
|
||||||
example = "\n".join(example.split("\n")[1:-1])
|
|
||||||
lineno = source[:example_match.start()].count("\n") + 1
|
|
||||||
function_name = ''.join(letter if letter in ascii_letters + digits else '_' for letter in file_to_test[:-3]) + "_line_" + str(lineno)
|
|
||||||
if example.startswith(">>> "):
|
|
||||||
if '"""' in example:
|
|
||||||
f.write(f"""def _{function_name}():\n r'''""" + example + """\n'''\n\n""")
|
|
||||||
else:
|
|
||||||
f.write(f'''def _{function_name}():\n r"""''' + example + '''\n"""\n\n''')
|
|
||||||
else:
|
|
||||||
f.write(example + "\n\n")
|
|
||||||
f.flush()
|
|
||||||
if args.debug:
|
|
||||||
with open(f.name) as py_source:
|
|
||||||
print(py_source.read())
|
|
||||||
spec = importlib.util.spec_from_file_location("to_test", f.name)
|
|
||||||
to_test = importlib.util.module_from_spec(spec)
|
|
||||||
spec.loader.exec_module(to_test)
|
|
||||||
doctest.testmod(to_test, verbose=args.verbose)
|
|
|
@ -0,0 +1,152 @@
|
||||||
|
def find_sum1(n, l):
|
||||||
|
"""Gros nombre non trouvé : pour 10**4 elements : 10s
|
||||||
|
Petit nombre non trouvé : pour 10**4 elements : 10s
|
||||||
|
"""
|
||||||
|
for i in range(len(l)):
|
||||||
|
for j in range(len(l)):
|
||||||
|
if i == j:
|
||||||
|
continue
|
||||||
|
if l[i] + l[j] == n:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def find_sum2(n, l):
|
||||||
|
"""Gros nombre non trouvé : pour 10**4 elements : 12s
|
||||||
|
Petit nombre non trouvé : 0s
|
||||||
|
"""
|
||||||
|
|
||||||
|
for i in range(len(l)):
|
||||||
|
if l[i] > n:
|
||||||
|
continue
|
||||||
|
for j in range(len(l)):
|
||||||
|
if i == j:
|
||||||
|
continue
|
||||||
|
if l[j] > n:
|
||||||
|
continue
|
||||||
|
if l[i] + l[j] == n:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def find_sum3(n, l):
|
||||||
|
"""Gros nombre non trouvé : pour 10**4 elements : 8s
|
||||||
|
Petit nombre non trouvé : pour 10**4 elements : 0s
|
||||||
|
"""
|
||||||
|
for i in range(len(l)):
|
||||||
|
if l[i] > n:
|
||||||
|
return False
|
||||||
|
for j in range(i + 1, len(l)):
|
||||||
|
if l[i] + l[j] == n:
|
||||||
|
return True
|
||||||
|
if l[i] + l[j] > n:
|
||||||
|
break
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def find_sum3(n, l):
|
||||||
|
"""Gros nombre non trouvé : pour 10**4 elements : 8s
|
||||||
|
Petit nombre non trouvé : pour 10**4 elements : 0s
|
||||||
|
"""
|
||||||
|
for i in range(len(l)):
|
||||||
|
if l[i] > n:
|
||||||
|
return False
|
||||||
|
for j in range(i + 1, len(l)):
|
||||||
|
if l[i] + l[j] == n:
|
||||||
|
return True
|
||||||
|
if l[i] + l[j] > n:
|
||||||
|
break
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def find_sum4(n, l):
|
||||||
|
"""Gros nombre non trouvé : pour 10**4 elements : 8s
|
||||||
|
Petit nombre non trouvé : pour 10**4 elements : 5s
|
||||||
|
"""
|
||||||
|
if len(l) <= 1:
|
||||||
|
return False
|
||||||
|
i = 0
|
||||||
|
j = len(l) - 1
|
||||||
|
while True:
|
||||||
|
if l[i] + l[j] == n:
|
||||||
|
return True
|
||||||
|
i += 1
|
||||||
|
if i == j or l[i] + l[j] > n:
|
||||||
|
if l[i] + l[j] < n:
|
||||||
|
return False
|
||||||
|
i = 0
|
||||||
|
j -= 1
|
||||||
|
if j == 0:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def find_sum5(n, l):
|
||||||
|
if len(l) <= 1:
|
||||||
|
return False
|
||||||
|
i = 0
|
||||||
|
j = len(l) - 1
|
||||||
|
while True:
|
||||||
|
print(f"Searching at {i}+{j} ({l[i]+l[j]})")
|
||||||
|
if l[i] + l[j] == n:
|
||||||
|
return True
|
||||||
|
if l[i] + l[j] > n:
|
||||||
|
j -= 1
|
||||||
|
if l[i] + l[j] < n:
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
|
||||||
|
find_sum5(12, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
|
||||||
|
|
||||||
|
exit(0)
|
||||||
|
|
||||||
|
find_sum4(2, [10, 10, 10])
|
||||||
|
from time import perf_counter
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
|
k = 4
|
||||||
|
seed = list(range(10, 10 ** 5))
|
||||||
|
print(f"Testing small int a list of length {10 ** k}...")
|
||||||
|
to_find = seed[: 10 ** k]
|
||||||
|
begin = perf_counter()
|
||||||
|
find_sum4(2, to_find)
|
||||||
|
end = perf_counter()
|
||||||
|
print(f"Done in {end - begin}s")
|
||||||
|
|
||||||
|
print(f"Testing big int a list of length {10 ** k}...")
|
||||||
|
to_find = seed[: 10 ** k]
|
||||||
|
begin = perf_counter()
|
||||||
|
find_sum4(2 ** 32, to_find)
|
||||||
|
end = perf_counter()
|
||||||
|
print(f"Done in {end - begin}s")
|
||||||
|
|
||||||
|
|
||||||
|
assert find_sum1(2, [1, 1])
|
||||||
|
assert find_sum1(5, [1, 2, 3, 4, 5])
|
||||||
|
assert not find_sum1(5, [1, 3, 6])
|
||||||
|
assert not find_sum1(4, [2, 3, 4, 5, 6])
|
||||||
|
assert find_sum1(10, [2, 3, 5, 6, 7, 9])
|
||||||
|
|
||||||
|
assert find_sum2(2, [1, 1])
|
||||||
|
assert find_sum2(5, [1, 2, 3, 4, 5])
|
||||||
|
assert not find_sum2(5, [1, 3, 6])
|
||||||
|
assert not find_sum2(4, [2, 3, 4, 5, 6])
|
||||||
|
assert find_sum2(10, [2, 3, 5, 6, 7, 9])
|
||||||
|
|
||||||
|
assert find_sum3(2, [1, 1])
|
||||||
|
assert find_sum3(5, [1, 2, 3, 4, 5])
|
||||||
|
assert not find_sum3(5, [1, 3, 6])
|
||||||
|
assert not find_sum3(4, [2, 3, 4, 5, 6])
|
||||||
|
assert find_sum3(10, [2, 3, 5, 6, 7, 9])
|
||||||
|
|
||||||
|
|
||||||
|
assert find_sum4(2, [1, 1])
|
||||||
|
assert find_sum4(5, [1, 2, 3, 4, 5])
|
||||||
|
assert not find_sum4(5, [1, 3, 6])
|
||||||
|
assert not find_sum4(4, [2, 3, 4, 5, 6])
|
||||||
|
assert find_sum4(10, [2, 3, 5, 6, 7, 9])
|
||||||
|
|
||||||
|
assert find_sum5(2, [1, 1])
|
||||||
|
assert find_sum5(5, [1, 2, 3, 4, 5])
|
||||||
|
assert not find_sum5(5, [1, 3, 6])
|
||||||
|
assert not find_sum5(4, [2, 3, 4, 5, 6])
|
||||||
|
assert find_sum5(10, [2, 3, 5, 6, 7, 9])
|
|
@ -0,0 +1,127 @@
|
||||||
|
import numpy as np
|
||||||
|
from collections import Counter
|
||||||
|
|
||||||
|
|
||||||
|
def is_done(grid):
|
||||||
|
for square in (
|
||||||
|
grid[0:3, 0:3],
|
||||||
|
grid[0:3, 3:6],
|
||||||
|
grid[0:3, 6:9],
|
||||||
|
grid[3:6, 0:3],
|
||||||
|
grid[3:6, 3:6],
|
||||||
|
grid[3:6, 6:9],
|
||||||
|
grid[6:9, 0:3],
|
||||||
|
grid[6:9, 3:6],
|
||||||
|
grid[6:9, 6:9],
|
||||||
|
):
|
||||||
|
if set(square.ravel()) != {1, 2, 3, 4, 5, 6, 7, 8, 9}:
|
||||||
|
return False
|
||||||
|
for line in grid:
|
||||||
|
if set(line) != {1, 2, 3, 4, 5, 6, 7, 8, 9}:
|
||||||
|
return False
|
||||||
|
for line in grid.T:
|
||||||
|
if set(line) != {1, 2, 3, 4, 5, 6, 7, 8, 9}:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def is_valid(grid):
|
||||||
|
for square in (
|
||||||
|
grid[0:3, 0:3],
|
||||||
|
grid[0:3, 3:6],
|
||||||
|
grid[0:3, 6:9],
|
||||||
|
grid[3:6, 0:3],
|
||||||
|
grid[3:6, 3:6],
|
||||||
|
grid[3:6, 6:9],
|
||||||
|
grid[6:9, 0:3],
|
||||||
|
grid[6:9, 3:6],
|
||||||
|
grid[6:9, 6:9],
|
||||||
|
):
|
||||||
|
c = Counter(square.ravel())
|
||||||
|
if 0 in c:
|
||||||
|
del c[0]
|
||||||
|
try:
|
||||||
|
value, occurences = c.most_common(1)[0]
|
||||||
|
if occurences > 1:
|
||||||
|
return False
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
for line in grid:
|
||||||
|
c = Counter(line)
|
||||||
|
if 0 in c:
|
||||||
|
del c[0]
|
||||||
|
try:
|
||||||
|
value, occurences = c.most_common(1)[0]
|
||||||
|
if occurences > 1:
|
||||||
|
return False
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
for line in grid.T:
|
||||||
|
c = Counter(line)
|
||||||
|
if 0 in c:
|
||||||
|
del c[0]
|
||||||
|
try:
|
||||||
|
value, occurences = c.most_common(1)[0]
|
||||||
|
if occurences > 1:
|
||||||
|
return False
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
grid = np.zeros((9, 9), dtype=int)
|
||||||
|
grid = np.array(
|
||||||
|
[
|
||||||
|
[0, 0, 0, 1, 1, 1, 2, 2, 2],
|
||||||
|
[0, 0, 0, 1, 1, 1, 2, 2, 2],
|
||||||
|
[0, 0, 0, 1, 1, 1, 2, 2, 2],
|
||||||
|
[3, 3, 3, 4, 4, 4, 5, 5, 5],
|
||||||
|
[3, 3, 3, 4, 4, 4, 5, 5, 5],
|
||||||
|
[3, 3, 3, 4, 4, 4, 5, 5, 5],
|
||||||
|
[6, 6, 6, 7, 7, 7, 8, 8, 8],
|
||||||
|
[6, 6, 6, 7, 7, 7, 8, 8, 8],
|
||||||
|
[6, 6, 6, 7, 7, 7, 8, 8, 8],
|
||||||
|
]
|
||||||
|
)
|
||||||
|
is_valid(grid)
|
||||||
|
|
||||||
|
|
||||||
|
def find_first_blank(grid):
|
||||||
|
i, j = 0, 0
|
||||||
|
for i in range(9):
|
||||||
|
for j in range(9):
|
||||||
|
if grid[i, j] == 0:
|
||||||
|
return i, j
|
||||||
|
|
||||||
|
|
||||||
|
def solve(grid):
|
||||||
|
print(grid)
|
||||||
|
if is_done(grid):
|
||||||
|
print(grid)
|
||||||
|
exit(0)
|
||||||
|
try:
|
||||||
|
my_i, my_j = find_first_blank(grid)
|
||||||
|
except TypeError:
|
||||||
|
return
|
||||||
|
for i in range(1, 10):
|
||||||
|
grid[my_i, my_j] = i
|
||||||
|
if is_valid(grid):
|
||||||
|
solve(grid.copy())
|
||||||
|
|
||||||
|
|
||||||
|
grid = np.array(
|
||||||
|
[
|
||||||
|
[0, 0, 0, 7, 3, 0, 6, 0, 0],
|
||||||
|
[0, 7, 0, 0, 8, 0, 1, 5, 0],
|
||||||
|
[2, 3, 0, 5, 0, 0, 0, 0, 0],
|
||||||
|
[0, 0, 0, 6, 0, 2, 4, 0, 5],
|
||||||
|
[6, 4, 0, 0, 0, 0, 0, 8, 2],
|
||||||
|
[5, 0, 9, 3, 0, 8, 0, 0, 0],
|
||||||
|
[0, 0, 0, 0, 0, 5, 0, 4, 8],
|
||||||
|
[0, 9, 4, 0, 2, 0, 0, 7, 0],
|
||||||
|
[0, 0, 5, 0, 7, 6, 0, 0, 0],
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
solve(grid)
|
|
@ -1,33 +0,0 @@
|
||||||
.PHONY: help
|
|
||||||
help:
|
|
||||||
@echo "Usage:"
|
|
||||||
@echo " make static # to build static version."
|
|
||||||
@echo " make test # to run tests."
|
|
||||||
@echo " make rsync # rsync to prod"
|
|
||||||
@echo " make clean"
|
|
||||||
|
|
||||||
.PHONY: static
|
|
||||||
static: output/index.html
|
|
||||||
|
|
||||||
.PHONY: check
|
|
||||||
test:
|
|
||||||
python test.py *.md
|
|
||||||
|
|
||||||
%.html: %.md
|
|
||||||
mdtoreveal $< --output $@
|
|
||||||
|
|
||||||
output/index.md: drf.md
|
|
||||||
mkdir -p output
|
|
||||||
cat $< > $@
|
|
||||||
|
|
||||||
.PHONY: rsync
|
|
||||||
rsync: static
|
|
||||||
rsync -vah --delete output/ mdk_fr@mdk.fr:/var/www/mdk.fr/drf-initiation/
|
|
||||||
|
|
||||||
.PHONY: clean
|
|
||||||
clean:
|
|
||||||
rm -fr output/
|
|
||||||
|
|
||||||
.PHONY: serve
|
|
||||||
serve:
|
|
||||||
python -m http.server -d output/
|
|
|
@ -0,0 +1 @@
|
||||||
|
../Makefile
|
|
@ -1,27 +0,0 @@
|
||||||
# Contenu
|
|
||||||
|
|
||||||
Side project : https://github.com/JulienPalard/drf-demos
|
|
||||||
|
|
||||||
- Revue des bases et consolidation Python et Django
|
|
||||||
- Présentation des types d'API, approfondissement de REST/HATEOAS
|
|
||||||
- Rappels autour de la sémantique HTTP
|
|
||||||
- django-rest-framework: La sérialisation
|
|
||||||
- django-rest-framework: Les différents types de vues
|
|
||||||
- django-rest-framework: Les permissions
|
|
||||||
- django-rest-framework: Les relations
|
|
||||||
- Les tests et la maintenabilité
|
|
||||||
|
|
||||||
|
|
||||||
# Objectifs pédagogiques
|
|
||||||
|
|
||||||
- Pouvoir démarrer rapidement un projet DRF.
|
|
||||||
- Savoir designer une API.
|
|
||||||
- Implémenter un service headless en utilisant DRF.
|
|
||||||
|
|
||||||
|
|
||||||
# TP
|
|
||||||
|
|
||||||
- Projet 1 : API « Horloge parlante ».
|
|
||||||
- Projet 2 : API « memcached ».
|
|
||||||
- Projet 3 : API « file system ».
|
|
||||||
- Projet 4 : API « uptime manager ».
|
|
|
@ -1,40 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
from string import ascii_letters, digits
|
|
||||||
import re
|
|
||||||
import doctest
|
|
||||||
from tempfile import NamedTemporaryFile
|
|
||||||
import importlib.util
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("file", nargs="+")
|
|
||||||
parser.add_argument("-v", "--verbose", action="store_true")
|
|
||||||
parser.add_argument("-d", "--debug", action="store_true")
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
for file_to_test in args.file:
|
|
||||||
with open(file_to_test) as f:
|
|
||||||
source = f.read()
|
|
||||||
|
|
||||||
with NamedTemporaryFile(mode="w", suffix=".py") as f:
|
|
||||||
for example_match in re.finditer("```python.*?```", source, re.S):
|
|
||||||
example = example_match.group()
|
|
||||||
example = "\n".join(example.split("\n")[1:-1])
|
|
||||||
lineno = source[:example_match.start()].count("\n") + 1
|
|
||||||
function_name = ''.join(letter if letter in ascii_letters + digits else '_' for letter in file_to_test[:-3]) + "_line_" + str(lineno)
|
|
||||||
if example.startswith(">>> "):
|
|
||||||
if '"""' in example:
|
|
||||||
f.write(f"""def _{function_name}():\n r'''""" + example + """\n'''\n\n""")
|
|
||||||
else:
|
|
||||||
f.write(f'''def _{function_name}():\n r"""''' + example + '''\n"""\n\n''')
|
|
||||||
else:
|
|
||||||
f.write(example + "\n\n")
|
|
||||||
f.flush()
|
|
||||||
if args.debug:
|
|
||||||
with open(f.name) as py_source:
|
|
||||||
print(py_source.read())
|
|
||||||
spec = importlib.util.spec_from_file_location("to_test", f.name)
|
|
||||||
to_test = importlib.util.module_from_spec(spec)
|
|
||||||
spec.loader.exec_module(to_test)
|
|
||||||
doctest.testmod(to_test, verbose=args.verbose)
|
|
|
@ -1,34 +0,0 @@
|
||||||
.PHONY: help
|
|
||||||
help:
|
|
||||||
@echo "Usage:"
|
|
||||||
@echo " make static # to build static version."
|
|
||||||
@echo " make test # to run tests."
|
|
||||||
@echo " make rsync # rsync to prod"
|
|
||||||
@echo " make clean"
|
|
||||||
|
|
||||||
.PHONY: static
|
|
||||||
static: output/index.html
|
|
||||||
cp -a static/ output/
|
|
||||||
|
|
||||||
.PHONY: check
|
|
||||||
test:
|
|
||||||
python test.py *.md
|
|
||||||
|
|
||||||
%.html: %.md
|
|
||||||
mdtoreveal $< --output $@
|
|
||||||
|
|
||||||
output/index.md: git.md
|
|
||||||
mkdir -p output
|
|
||||||
cat $< > $@
|
|
||||||
|
|
||||||
.PHONY: rsync
|
|
||||||
rsync: static
|
|
||||||
rsync -vah --delete output/ mdk_fr@mdk.fr:/var/www/mdk.fr/git-initiation/
|
|
||||||
|
|
||||||
.PHONY: clean
|
|
||||||
clean:
|
|
||||||
rm -fr output/
|
|
||||||
|
|
||||||
.PHONY: serve
|
|
||||||
serve:
|
|
||||||
python -m http.server -d output/
|
|
|
@ -0,0 +1 @@
|
||||||
|
../Makefile
|
|
@ -1 +0,0 @@
|
||||||
# GIT
|
|
|
@ -1,40 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
from string import ascii_letters, digits
|
|
||||||
import re
|
|
||||||
import doctest
|
|
||||||
from tempfile import NamedTemporaryFile
|
|
||||||
import importlib.util
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("file", nargs="+")
|
|
||||||
parser.add_argument("-v", "--verbose", action="store_true")
|
|
||||||
parser.add_argument("-d", "--debug", action="store_true")
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
for file_to_test in args.file:
|
|
||||||
with open(file_to_test) as f:
|
|
||||||
source = f.read()
|
|
||||||
|
|
||||||
with NamedTemporaryFile(mode="w", suffix=".py") as f:
|
|
||||||
for example_match in re.finditer("```python.*?```", source, re.S):
|
|
||||||
example = example_match.group()
|
|
||||||
example = "\n".join(example.split("\n")[1:-1])
|
|
||||||
lineno = source[:example_match.start()].count("\n") + 1
|
|
||||||
function_name = ''.join(letter if letter in ascii_letters + digits else '_' for letter in file_to_test[:-3]) + "_line_" + str(lineno)
|
|
||||||
if example.startswith(">>> "):
|
|
||||||
if '"""' in example:
|
|
||||||
f.write(f"""def _{function_name}():\n r'''""" + example + """\n'''\n\n""")
|
|
||||||
else:
|
|
||||||
f.write(f'''def _{function_name}():\n r"""''' + example + '''\n"""\n\n''')
|
|
||||||
else:
|
|
||||||
f.write(example + "\n\n")
|
|
||||||
f.flush()
|
|
||||||
if args.debug:
|
|
||||||
with open(f.name) as py_source:
|
|
||||||
print(py_source.read())
|
|
||||||
spec = importlib.util.spec_from_file_location("to_test", f.name)
|
|
||||||
to_test = importlib.util.module_from_spec(spec)
|
|
||||||
spec.loader.exec_module(to_test)
|
|
||||||
doctest.testmod(to_test, verbose=args.verbose)
|
|
|
@ -1,31 +0,0 @@
|
||||||
SRCS := $(sort $(wildcard *-*.md))
|
|
||||||
|
|
||||||
.PHONY: help
|
|
||||||
help:
|
|
||||||
@echo "Usage:"
|
|
||||||
@echo " make static # to build static version."
|
|
||||||
@echo " make test # to run tests."
|
|
||||||
@echo " make rsync # rsync to prod"
|
|
||||||
@echo " make clean"
|
|
||||||
|
|
||||||
.PHONY: check
|
|
||||||
test:
|
|
||||||
python test.py *.md
|
|
||||||
|
|
||||||
.PHONY: static
|
|
||||||
static: output/index.html
|
|
||||||
|
|
||||||
%.html: %.md
|
|
||||||
mdtoreveal $< --output $@
|
|
||||||
|
|
||||||
output/index.md: $(SRCS)
|
|
||||||
mkdir -p output
|
|
||||||
cat $(SRCS) > output/index.md
|
|
||||||
|
|
||||||
.PHONY: rsync
|
|
||||||
rsync: static
|
|
||||||
rsync -vah --delete output/ mdk_fr@mdk.fr:/var/www/mdk.fr/python-avancé/
|
|
||||||
|
|
||||||
.PHONY: clean
|
|
||||||
clean:
|
|
||||||
rm -fr output
|
|
|
@ -1,3 +0,0 @@
|
||||||
# TODO
|
|
||||||
|
|
||||||
- [ ] Ajouter les nombres imaginaires.
|
|
|
@ -0,0 +1 @@
|
||||||
|
../Makefile
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 108 KiB |
|
@ -1,30 +0,0 @@
|
||||||
.PHONY: static
|
|
||||||
static: output/index.html
|
|
||||||
|
|
||||||
.PHONY: help
|
|
||||||
help:
|
|
||||||
@echo "Usage:"
|
|
||||||
@echo " make static"
|
|
||||||
@echo " make test"
|
|
||||||
@echo " make rsync"
|
|
||||||
@echo " make clean"
|
|
||||||
|
|
||||||
.PHONY: check
|
|
||||||
test:
|
|
||||||
python test.py *.md
|
|
||||||
|
|
||||||
output/index.html: initiation.md
|
|
||||||
mdtoreveal $< --output $@
|
|
||||||
cp -a static output
|
|
||||||
|
|
||||||
.PHONY: rsync
|
|
||||||
rsync: static
|
|
||||||
rsync -vah --delete output/ mdk_fr@mdk.fr:/var/www/mdk.fr/python-initiation/
|
|
||||||
|
|
||||||
.PHONY: clean
|
|
||||||
clean:
|
|
||||||
rm -f $(HTML)
|
|
||||||
|
|
||||||
.PHONY: serve
|
|
||||||
serve:
|
|
||||||
python3 -m http.server -d output/
|
|
|
@ -0,0 +1 @@
|
||||||
|
../Makefile
|
|
@ -1,20 +0,0 @@
|
||||||
# TODO
|
|
||||||
|
|
||||||
Lors de la présentation des fonctions natives dans un REPL, il y a une
|
|
||||||
ambiguité (`print` vs `return`):
|
|
||||||
|
|
||||||
>>> int("42")
|
|
||||||
42
|
|
||||||
>>> print("42")
|
|
||||||
42
|
|
||||||
|
|
||||||
On pourrait passer par une variable peut-être :
|
|
||||||
|
|
||||||
>>> quarante_deux = int("42")
|
|
||||||
>>> quarante_deux
|
|
||||||
42
|
|
||||||
|
|
||||||
>>> result = print("42")
|
|
||||||
42
|
|
||||||
>>> print(result)
|
|
||||||
None
|
|
|
@ -1,38 +0,0 @@
|
||||||
export PATH := $(PATH):bin
|
|
||||||
|
|
||||||
# Only run watch with -j2 so entr and serve are run in parallel.
|
|
||||||
.PHONY: watch
|
|
||||||
watch: entr serve
|
|
||||||
|
|
||||||
.PHONY: static
|
|
||||||
static: output/index.html
|
|
||||||
cp -a .cache/*.png output/
|
|
||||||
|
|
||||||
.PHONY: help
|
|
||||||
help:
|
|
||||||
@echo "Usage:"
|
|
||||||
@echo " make static"
|
|
||||||
@echo " make test"
|
|
||||||
@echo " make rsync"
|
|
||||||
@echo " make clean"
|
|
||||||
|
|
||||||
.PHONY: entr
|
|
||||||
entr:
|
|
||||||
ls -1 *.md include/*.py | entr $(MAKE) static
|
|
||||||
|
|
||||||
output/index.html: perfs.md
|
|
||||||
mkdir -p .cache
|
|
||||||
sed 's/#!//e;' perfs.md | mdtoreveal /dev/stdin --output $@
|
|
||||||
if [ -d static ]; then cp -a static output; fi
|
|
||||||
|
|
||||||
.PHONY: rsync
|
|
||||||
rsync: static
|
|
||||||
rsync -vah --delete output/ mdk_fr@mdk.fr:/var/www/mdk.fr/python-perfs/
|
|
||||||
|
|
||||||
.PHONY: clean
|
|
||||||
clean:
|
|
||||||
rm -f $(HTML)
|
|
||||||
|
|
||||||
.PHONY: serve
|
|
||||||
serve:
|
|
||||||
python3 -m http.server -d output/
|
|
|
@ -0,0 +1 @@
|
||||||
|
../Makefile
|
Loading…
Reference in New Issue