Catégorie : développement

Tout ce qui concerne le développement en général, que ce soit des choses générales, ou des choses bien précises. Cela va de la gestion de projet à la recherche du fonctionnement de pointeurs en C.

Django : un modèle sur mesure : DaysField étape 1/3

Le principe

Je voulais un modèle de données qui stocke les jours d’une semaine que l’utilisateur désire, et qui les stocke sous forme de chaîne simple, avec des numéros qui correspondent aux jours de la semaine.
J’ai appelé ce modèle DaysField.
Les valeurs sont stockées par rapport aux jours choisis. Par exemple, 1,3 signifie que l’utilisateur a choisi lundi et mercredi parmi les jours. 6,7 correspondent à samedi et dimanche. Pour finir, tous les jours de la semaine cochés serait donc : 1,2,3,4,5,6,7

Toujours descendre d’un modèle classique

J’ai retenu ces principes et cela semble suffire pour fonctionner : on descend du modèle qu’on veut écrire en base de données. Ici, je voulais écrire une chaîne de caractères dans la base ⇒ on descend de CharField(), en modifiant la description au passage :
class DaysField(models.CharField):
    description = _("Comma-separated integers between 1 and 7")

Conversion de « sources » différentes en données Python

Pour résumer : les modèles ont deux « arrivées » de données :

  • quand on les données viennent de la base = from_db_value() ;
  • quand on les données viennent d’un formulaire (ou autre, mais en gros quand ça vient pas de la base de données mais du code Python lui-même) = to_python().

Il faut donc gérer ces deux cas, qui, dans les deux cas, doivent renvoyer quelque chose au format Python qui nous intéresse.
Ici, c’est un tableau d’entiers compris entre 1 et 7 qui correspond aux jours de la semaine.

J’ai centralisé la gestion des deux « arrivées » (base et Python) dans une seule fonction : value_to_array() :

    @staticmethod
    def value_to_array(value):
        if value is None:
            return None
        try:
            if isinstance(value, list):
                return [int(a) for a in value]
            elif isinstance(value, str):
                return [int(a) for a in value.split(',')]
        except (TypeError, ValueError):
            raise ValidationError(_("Unexpected value"))
        raise ValidationError(_("Unexpected value"))
    @staticmethod
    def from_db_value(value, expression, connection):
        return DaysField.value_to_array(value)
    def to_python(self, value):
        return DaysField.value_to_array(value)

Peut-être existe-t-il des cas où la provenance du code Python doit être gérée différemment de la provenance de la base de données… ici ce n’est pas le cas – et si vous avez des exemples de gestion différentes pour des entrées de base et de code, laissez-moi un commentaire, car je n’en vois pas…

Conversion de données Python ⇒ données pour la base

C’est la fonction get_prep_value().

Dans le cas DaysField, c’est très simple :
    def get_prep_value(self, value):
        return ','.join([str(a) for a in value]) \
            if value is not None else None

On prend toutes les valeurs du tableau, on les concatène avec la virgule , comme séparateur. C’est plus long de l’expliquer que de le coder !

Gitlab Continuous Integration

gitlab CI

Gitlab CI (Continuous Integration)

Layer A set of read-only files or commands that describe how to set up the underlying system beneath the container. Layers are built on top of each other, and each one represents a change to the filesystem.
Image An immutable layer that forms the base of the container.
Container An instance of the image that can be executed as an independent application. The container has a mutable layer that lies on top of the image and that is separate from the underlying layers.
Registry A storage and content delivery system used for distributing Docker images.
Repository A collection of related Docker images, often different versions of the same application.

Django rest framework : Got AttributeError when attempting to get a value for field `my_field` on serializer `UserSerializer`.

Si vous voulez faire un mapping avec un modèle c’est ultra simple. Si vous voulez ajouter un champ custom, là ça devient compliqué…

Aucune réponse viable sur stackoverflow, vous risquez de chercher longtemps.

Si vous avez fait un code comme cela, pour rajouter un champ « custom » :

class UserSerializer(serializers.ModelSerializer):
    my_field = serializers.CharField(allow_blank=True)
    class Meta:
        model = User
        fields = ['url', 'email', 'password', 'my_field']

Eh bien cela ne marchera jamais, avec une erreur qui ne vous met absolument pas sur la voie :

Got AttributeError when attempting to get a value for field `my_field` on serializer `UserSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `User` instance.
Original exception text was: 'User' object has no attribute 'my_field'.

Voici la solution : autoriser le null :

class UserSerializer(serializers.ModelSerializer):
    my_field = serializers.CharField(allow_blank=True, allow_null=True)
    class Meta:
        model = User
        fields = ['url', 'email', 'password', 'my_field']

git : exemple de fichier

Voici un exemple de fichier de configuration qui ignore la plupart des fichiers qui posent problème :

# --------------------------------------
# git cleanup if too many files / or / problems:
# git reflog expire --expire=now --all && git repack -ad && git prune
# --------------------------------------
# PyCharm
.idea/
# --------------------------------------
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# --------------------------------------
# C extensions
*.so
# Distribution / packaging
bin/
build/
develop-eggs/
dist/
eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# --------------------------------------
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# --------------------------------------
# Unit test / coverage reports
.tox/
.coverage
.cache
nosetests.xml
coverage.xml
# --------------------------------------
# Translations
*.mo
# --------------------------------------
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
# --------------------------------------
# Rope
.ropeproject
# --------------------------------------
# Django stuff:
*.log
*.pot
# --------------------------------------
# Sphinx documentation
docs/_build/
# --------------------------------------
# git
objects/
# --------------------------------------
# swap files
*.swp
*.swo

Bootstrap : classes utilitaires

Vous allez peut-être trouver du code qui ressemble à cela :
<p class="mb-0">Texte dans un paragraphe</p>

Bootstrap >= 4 a mis en place plein de possibilités pour faire du padding et des marges « responsives ».
Elles fonctionnent pour tous les breakpoints :

  • xs (<=576px)
  • sm (>=576px)
  • md (>=768px)
  • lg (>=992px)
  • xl (>=1200px)

<p class="{propriété}{côtés}-{taille}">texte</p>

propriété :

  • m – les marges
  • p – le padding

côtés :

  • tmargin-top or padding-top
  • bmargin-bottom or padding-bottom
  • lmargin-left or padding-left
  • rmargin-right or padding-right
  • x*-left and *-right
  • y*-top and *-bottom
  • blank – les 4 côtés à la fois

taille :

  • 0 – supprimer les marges ou mettre le padding à 0
  • 1 – $spacer *0.25
  • 2 – $spacer *0.5
  • 3 – $spacer
  • 4 – $spacer *1.5
  • 5 – $spacer *3
  • auto – margin à auto

Python : hints & cheats

Son propre fichier basique de log

import datetime
msg = u"Test de log"
dt = datetime.datetime.now()
with open("monlogfile.log", 'a+') as f:
    f.write(u'{:02}:{:02} - {}\n'.format(dt.hour, dt.minute, msg))

Teaching Python

Here

Découpages Python : formation

Checkio

Demystifying Two Factor Auth

Two-factor auth

Python Open Source Projects of the Year

Here!

Thanks to Dan Bader

  • Python Parallel Computing (in 60 Seconds or less): here
  • Python Decorators: A Step-By-Step Introduction: here
  • Interfacing Python and C: Advanced “ctypes” Features: here
  • Working with Random Numbers in Python » ici
  • Face detection
  • Différentes manières de testers plusieurs flags en même temps en Python :
    x, y, z = 0, 1, 0
    if x == 1 or y == 1 or z == 1:
        print('ok')
    if 1 in (x, y, z):
        print('ok')
    # si l'un d'eux n'est pas vide:
    if x or y or z:
        print('ok')
    if any((x, y, z)):
        print('ok')
  • Comment trier un dictionnaire Python par ses valeurs :
    »»» xs = {'a': 4, 'b': 3, 'c': 2, 'd': 1}
    »»» sorted(xs.items(), key=lambda x: x[1])

    ou bien :
    »»» import operator
    »»» sorted(xs.items(), key=operator.itemgetter(1))
  • Mesurer le temps d’exécution de petits morceaux de code Python :
    »»» import timeit
    »»» timeit.timeit('"-".join(str(n) for n in range(100))',
                      number=10000)
    0.3412662749997253
    »»» timeit.timeit('"-".join([str(n)
                                 for n in range(100)])',
                      number=10000)
    0.2996307989997149
    »»» timeit.timeit('"-".join(map(str, range(100)))',
                      number=10000)
    0.24581470699922647
  • Comment utiliser la classe namedtuples :
    # namedtup1e est une classe :
    »»» from collections import namedtuple
    »»» Car = namedtup1e('Car' , 'color mileage')
    # Our new "Car" class works as expected:
    »»» my_car = Car('red', 3812.4)
    »»» my_car.color
    'red'
    »»» my_car.mileage
    3812.4
    # Une belle représentation repr avec :
    »»» my_car
    Car(color='red' , mileage=3812.4)
    # Comme les tuples, les namedtuples sont immuables :
    »»» my_car.color = 'blue'
    AttributeError: "can't set attribute"
  • « is » vs « == » :
    »»» a = [1, 2, 3]
    »»» b = a
    »»» a is b
    True
    »»» a == b
    True
    »»» c = list(a)
    »»» a == c
    True
    »»» a is c
    False

    is est True si deux variables pointent vers le même objet ;
    == est True si les variables contenues dans les objets sont identiques.

  • Titre Titre  :
    »»» Code code code

Learning Python in minutes
https://learnxinyminutes.com/docs/python3/

How to Send an Email With Python
https://dbader.org/blog/python-send-email

Python Decorators From the Ground Up
https://pabloariasal.github.io/python-decorators-from-the-ground-up/

How — and why — you should use Python Generators
https://medium.freecodecamp.org/how-and-why-you-should-use-python-generators-f6fb56650888

Download information on all your gmail emails and the body text to either csv or json. I developed this to download my 100K + emails stored over several years on gmail.
https://teklern.blogspot.fr/2017/11/download-all-your-email-information.html

Memoization in Python: How to Cache Function Results
https://dbader.org/blog/python-memoization

Implementing a Neural Network from Scratch in Python – An Introduction
https://www.datasciencecentral.com/profiles/blogs/implementing-a-neural-network-from-scratch-in-python-an

—–

Mailtrap – Sending Emails

—–

Introduction to NumPy and Pandas – A Simple Tutorial

https://cloudxlab.com/blog/numpy-pandas-introduction

Fastest way to uniquify a list in Python >=3.6

https://www.peterbe.com/plog/fastest-way-to-uniquify-a-list-in-python-3.6

8 Python Modules For Files Handling
http://devarea.com/8-python-modules-for-files-handling/

How do async for loops work in Python? Using asynchronous for loops in Python
https://quentin.pradet.me/blog/using-asynchronous-for-loops-in-python.html

How to use Python and Flask to build a web app — an in-depth tutorial
https://medium.freecodecamp.org/how-to-use-python-and-flask-to-build-a-web-app-an-in-depth-tutorial-437dbfe9f1c6

Framework ultra simple pour faire des micro-services en Json
Falcon is a bare-metal Python web API framework for building very fast app backends and microservices.
http://falconframework.org

How to break a CAPTCHA system in 15 minutes with Machine Learning
https://medium.com/@ageitgey/how-to-break-a-captcha-system-in-15-minutes-with-machine-learning-dbebb035a710

Python Exceptions: An Introduction
https://realpython.com/python-exceptions/

Python Metaclasses
https://realpython.com/python-metaclasses/

Building a Simple Web App with Bottle, SQLAlchemy, and the Twitter API
https://realpython.com/blog/python/building-a-simple-web-app-with-bottle-sqlalchemy-twitter-api/

Python – Regular Expressions Practical Guide
http://devarea.com/python-regular-expressions-practical-guide/#.Wki2nN_iZhE

A fast high-level screen scraping and web crawling framework.
https://scrapy.org

A fast high-level screen scraping and web crawling framework.
https://pyfiddle.io/

IUT : projet JavaScript – jQuery à rendre

A rendre pour le 2 avril au plus tard


Comment le rendre

Faites un fichier README.txt et déposez-le ici


Sujet

Ce que vous voulez tant que c’est dans le cadre de ce que l’on a vu. Vous avez tout le Web comme inspiration !
N’oubliez pas de me donner le nom et le mot de passe pour se connecter !
Si vous gérez des profils différents (admin / user ou autre), donnez moi les noms et mots de passe de différents profils !


Fonctionnalités obligatoires

  • Connexion + déconnexion (vu en cours)
  • Effets jQuery sur les éléments
  • Appels JSON : au moins deux appels en plus de ceux vus en cours

Sujets possibles

  1. Site de partage de photos
  2. Site de cocktails (cf ci-dessus)
  3. e-rated : site d’appréciations (selon des sujets, à définir)
  4. Ask-a-question : site où l’on pose des questions sur des sujets divers, et des gens répondent
  5. Write-a-book-together : site où l’on se connecte et où on peut écrire un livre à plusieurs
  6. Wedding-couple-site : site où l’on uploade + partage des photos de mariage + livre de commandes
  7. Playing-cards-collection : site où on scanne + échange des cartes (Magic the gathering)
  8. Polls-and-surveys : site de création de sondages (= QCM, exemple très beau ici : quipoquiz)
  9. Poems-generator : faire un cadavre exquis qui génère des poèmes + possibilité pour les utilisateurs de les noter / d’ajouter des mots
  10. The-future-of-post-it : faire un carnet de choses à faire pour les utilisateurs, qui envoie des mails de rappels de ces choses à des dates données
  11. Gift-ideas : un site où l’on va faire des idées de cadeaux / suggérer des idées de cadeaux + les noter (les meilleurs ressortent en premier)
  12. Le-bon-recoin : refaire le bon coin en plus simple
  13. Suggest-crawlers : site de suggestions : on clique sur un mot, il en suggère plein d’autres avec + définitions / liens de sites pour chacuns
  14. Tv-fans : site de présentations + notes d’émissions télé
  15. Faire le jeu SokoBan vu en cours, avec la possibilité de login, enregistrement. Pour les appels JSON supplémentaires, lorsque l’utilisateur choisit un tableau, s’en souvenir (= AJAX) et lorsqu’il se reconnecte, le remettre directement. Puis enregistrer son score lorsqu’il a terminé un niveau + montrer les meilleurs scores.

Pour les sujets qui suivent, ils sont possibles mais plutôt complexes et demandent plus d’investissement. Si vous êtes motivés, demandez-moi plus d’informations, je vous expliquerai les difficultés que vous allez rencontrer.

  1. Turn-by-turn : faire un jeu multijoueurs en tour par tour (jeu de cartes, de poker, ou de plateau etc)
  2. Chat-with-someone : site de chat/discussion
  3. A-maze-ing : site où l’on peut se ballader dans un labyrinthe et essayer d’en trouver la sortie

Sujet imposé si vous n’avez pas d’idée

Cocktails : on se connecte, on a une liste d’éléments (récupérés en JSON) disponibles, on coche ceux qui nous intéressent, on valide, c’est envoyé, et le retour en JSON affiche les cocktails qu’il est possible de faire avec ce que l’on a coché.


Ce que vous devez rendre

Idéalement

Une Url vers un site Web (utilisez Alwaysdata par exemple)

Si vous n’avez pas le choix

Les fichiers source de votre projet


Pour favoriser votre organisation

Utilisez ce que l’on a vu en cours (Google boilerplate)


Librairies autorisées

Interdiction d’utiliser une librairie JavaScript qui ne vienne pas des sites autorisés précédemment


Retard

Après le mardi 2 avril minuit

Passé ce délai ce sera 1 pt par 2 heures de retard (je prendrai en compte la date de réception du mail).
Pour ceux qui essaient vraiment d’aller jusqu’à la dernière minute, toute heure entamée est comptée comme une heure complète. Exemple : un point en moins si je le reçois le 3 avril à 00:01.
N’oubliez pas de me donner le nom et le mot de passe pour se connecter !


Copier-coller

  • Copie sur une autre personne (« je se savais pas comment implémenter telle ou telle fonctionnalité dont j’avais besoin pour aller plus loin, je l’ai copiée sur un autre ») :
    • si la personne est clairement nommée : note pour la fonctionnalité divisée par 2 (uniquement la moitié du travail a été faite) ;
    • 0 aux deux personnes sinon ;
  • Si je m’aperçois que vous avez bêtement copié collé des sources Internet, je vous convoquerai pour vous demander de m’expliquer la fonctionnalité, et :
    • si vous ne savez pas m’expliquer le code alors 0 ;
    • si vous savez m’expliquer tout le code alors votre note totale sera divisée par vous + le nombre de contributeurs à ce projet, ce qui se rapprochera certainement de 0 aussi.

Voici un exemple de ce que vous pouvez faire, si vous choisissez le projet cocktails.


PDFs

JavaScript
jQuery

Nginx

Nginx hints / aide

Mon objectif était :

  • Si on tape l’URL sans le / à la fin, il redirige en ajoutant le / à la fin
  • Si on tape l’URL avec le / à la fin, tout doit fonctionner
  • Tout ne doit être que statique et les fichiers doivent obligatoirement exister, sauf index.html et index.htm
  • J’en suis donc arrivé à ces règles, plus « proches » de la configuration possible dans Nginx :

    1. Filtre « custom » avec / à la fin. Si oui, n’accepter que index.html ou index.htm
    2. Filtre « custom » en ignorant le / à la fin. Si oui, le nom, qui doit être forcément un fichier, sinon, rediriger en ajoutant un / pour qu’il reboucle au début
      location ~* ^/unity/(?<p>.+)/$ {
        root /web/htdocs/unity;
        try_files /$p/index.html /$p/index.htm /$p =403;
        access_log off;
        expires 1h;
      }
      location ~* ^/unity/(?<p>.+) {
        root /web/htdocs/unity;
        try_files /$p $p @redirect_with_slash_at_the_end;
        access_log off;
        expires 1h;
      }
      location @redirect_with_slash_at_the_end {
        return 301 $scheme://www.mywebsite.com$request_uri/;
      }
    

Python : faire un « beep » sur Debian

Le code est simple, il fautt avoir paplay d’installé (je ne sais pas si c’est installé par défaut dans Debian).

A partir de là voici un exemple de code qui joue un fichier ogg :

# python3
>>> import subprocess
>>> subprocess.Popen([
... "paplay",
... "/home/olivier/.local/blah/Mission_Failed.ogg"
... ]).poll()
>>>

git / gitlab

gitlab hints / aide

Git

Git global setup
Sur PC dev
git config --global user.name "Olivier Pons"
git config --global user.email "monmail@mail.com"
Clone gitlab » dev
Push dev » gitlab
git clone git@gitlab.com:olivier.pons/ajeter.git
cd ajeter
touch README.md
git add README.md
git commit -m "add README"
git push -u origin master
Init. projet pas vide:
Clone dev » gitlab
cd existing_folder
git init
git remote add origin git@gitlab.com:olivier.pons/ajeter.git
git add .
git commit -m "Initial commit"
git push -u origin master
Git existant sur dev
Clone dev » gitlab
cd existing_repo
git remote rename origin old-origin
git remote add origin git@gitlab.com:olivier.pons/ajeter.git
git push -u origin --all
git push -u origin --tags
Autre Git existant sur gitlab
Clone gitlab » dev
git clone git@gitlab.com:adresse/repo/sur/gitlab/monprojet.git
Cloning into 'monprojet'...
remote: Enumerating objects: 308, done.
remote: Counting objects: 100% (308/308), done.
remote: Compressing objects: 100% (192/192), done.
Receiving objects: 63% (195/308)
Receiving objects: 100% (308/308), 93.34 KiB | 463.00 KiB/s, done.
Resolving deltas: 100% (169/169), done.
cd monprojet
git checkout -b nom-de-la-branche remotes/origin/nom-de-la-branche
Donc en local, on a en local nom-de-la-branche liée à la branche distante remotes/origin/nom-de-la-branche.
A partir de là commit, push et pull fonctionnent.
Si des branches ont été ajoutées au remote :
Synchroniser le git local avec le remote
 git remote update origin --prune
Commentaires fermés sur git / gitlab Publié dans Mots-clé , ,