Dedupicating Makefiles.
This commit is contained in:
parent
675d7b7778
commit
d6cabd6284
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -11,7 +11,7 @@ jobs:
|
||||
matrix:
|
||||
directory:
|
||||
- python-initiation
|
||||
- python-avance
|
||||
- python-avancé
|
||||
- drf-initiation
|
||||
- django-initiation
|
||||
- python-perfs
|
||||
|
1
.github/workflows/deploy.yml
vendored
1
.github/workflows/deploy.yml
vendored
@ -21,6 +21,7 @@ jobs:
|
||||
python-version: '3.10'
|
||||
cache: pip
|
||||
- run: sudo apt-get install -y cutycapt
|
||||
- run: python3 -m pip install -r requirements.txt
|
||||
- run: make -C ${{ inputs.directory }} test
|
||||
- name: Publish
|
||||
env:
|
||||
|
34
Makefile
Normal file
34
Makefile
Normal file
@ -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
|
||||
@ -74,3 +84,76 @@ Souci : Jour 1 pytest nécessite Jour 2 pip...
|
||||
- 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>.
|
||||
|
||||
# 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`.
|
1
culture-unix/Makefile
Symbolic link
1
culture-unix/Makefile
Symbolic link
@ -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/
|
1
django-initiation/Makefile
Symbolic link
1
django-initiation/Makefile
Symbolic link
@ -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` :
|
||||
|
||||
```python
|
||||
```bash
|
||||
python -m pip install django
|
||||
```
|
||||
|
||||
@ -43,7 +43,7 @@ python -m pip install django
|
||||
|
||||
Pour démarrer un projet, une commande :
|
||||
|
||||
```python
|
||||
```bash
|
||||
django-admin startproject project
|
||||
```
|
||||
|
||||
@ -51,7 +51,7 @@ django-admin startproject project
|
||||
|
||||
Une fois dans le projet, pour créer une application, une commande :
|
||||
|
||||
```python
|
||||
```bash
|
||||
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
|
||||
|
||||
urlpatterns = [
|
||||
...
|
||||
...
|
||||
...,
|
||||
...,
|
||||
path("", views.index, name="index"),
|
||||
]
|
||||
```
|
||||
@ -721,7 +721,7 @@ fichier doit commencer par `test` pour être trouvé.
|
||||
|
||||
Les tests s'exécutent via :
|
||||
|
||||
```python
|
||||
```bash
|
||||
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)
|
152
doddling/find_sum.py
Normal file
152
doddling/find_sum.py
Normal file
@ -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])
|
127
doddling/sudoku.py
Normal file
127
doddling/sudoku.py
Normal file
@ -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/
|
1
drf-initiation/Makefile
Symbolic link
1
drf-initiation/Makefile
Symbolic link
@ -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/
|
1
git-initiation/Makefile
Symbolic link
1
git-initiation/Makefile
Symbolic link
@ -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.
|
1
python-avancé/Makefile
Symbolic link
1
python-avancé/Makefile
Symbolic link
@ -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/
|
1
python-initiation/Makefile
Symbolic link
1
python-initiation/Makefile
Symbolic link
@ -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/
|
1
python-perfs/Makefile
Symbolic link
1
python-perfs/Makefile
Symbolic link
@ -0,0 +1 @@
|
||||
../Makefile
|
Loading…
Reference in New Issue
Block a user