NAV

Introduction

Bienvenue sur le site dédié à votre examen final de Python. Il devrait contenir toutes les ressources nécessaires à la réalisation de votre projet de groupe. Si vous avez des questions, n’hésitez pas à m’envoyer un mail.

Si vous êtes perdus, ou ne savez pas par où commencer, regardez bien les ressources mises à votre disposition. De plus, je vous recommande d’effectuer vos propres recherches sur internet (comme vous le feriez en entreprise). En informatique, les tutoriels/documentations/aide sur les erreurs sont majoritairement en anglais. Pensez donc à faire vos recherches dans cette langue si cela ne donne rien en français.

Pensez également à faire un tour sur les ressources des autres projets, vous pourriez éventuellement tomber sur des choses intéressantes.

La procédure est la suivante :

Vous devrez présenter votre travail lors d’une soutenance de maximum 10 min par groupe.L’objectif est que chacun des membres présente une partie du travail qu’il a réalisé. Pas besoin de présenter le code en lui-même : il s’agit de présenter les raisonnements qui vous ont conduit à écrire ce code. Par exemple : comment j’ai adapté ce code trouvé sur StackOverflow pour qu’il s’intègre dans celui de mes camarades.

Point sur la triche et objectif du projet

Le but de ce projet est que vous puissiez manipuler du Python à travers une activité qui se veut la plus ludique et utile possible. Je ne m’attends pas à ce que le code soit parfait, et je préfère un groupe qui a passé du temps à rendre un projet fonctionnel à 70% qu’un groupe qui a sous-traité pour présenter un projet “fini”.

D’expérience, ce sont les projets sous-traités qui obtiennent les moins bonnes notes, puisque les développeurs expérimentés ont pour habitude de faire comme ils l’entendent sans respecter les consignes : on se retrouve alors avec un code qui fait plein de chose, mais ne répond pas aux instructions demandées.

Comme en entreprise, je vous autorise à récupérer des morceaux de code disponibles sur internet, d’utiliser ChatGPT… Cependant, merci de ne pas récupérer un projet existant tel quel… (je n’ai aucun intérêt à passer du temps sur un code écrit par d’autres).

Fonctionnement du site

Chaque groupe va travailler sur un sujet qui lui est propre. La liste des sujets (et des groupes associés) est accessible via le menu latéral.

Pour chaque groupe, deux sections sont accessibles :

Crypto

Le but du projet est de réaliser un outil pour chiffrer et déchiffrer des messages avec des algorithmes historiques.

Sujet

En cryptographie, le chiffrement par décalage, aussi connu comme le chiffre de César ou le code de César (voir les différents noms), est une méthode de chiffrement très simple utilisée par Jules César dans ses correspondances secrètes (ce qui explique le nom « chiffre de César ») . Wikipédia

Le chiffre de Vigenère est un système de chiffrement par substitution polyalphabétique dans lequel une même lettre du message clair peut, suivant sa position dans celui-ci, être remplacée par des lettres différentes, contrairement à un système de chiffrement monoalphabétique comme le chiffre de César (qu’il utilise cependant comme composant)

Palier 1

Le palier 1 se concentrera sur l’implémentation du chiffre de César :

  1. Le programme demande à l’utilisateur s’il souhaite chiffrer ou déchiffrer
  2. Le programme demande à l’utilisateur le décalage (nombre >= 0)
  3. Le programme demande à l’utilisateur le message à transformer
  4. Le programme affiche le message

Palier 2

  1. Un menu doit permettre de sélectionner l’algorithme à utiliser :
    • César
    • Vigenère
  2. Implémenter Vigenere

Palier 3

  1. Ajouter une option dans le menu pour lire le message
    • Depuis un fichier texte : l’utilisateur doit rentrer le nom du fichier
    • Depuis un input classique
  2. Ajouter une option dans le menu pour enregistrer le message
    • Dans un fichier texte : l’utilisateur doit rentrer le nom du fichier
    • Avec un print classique

Ressources

Implémenter César

Prenons l’exemple d’une fonction qui permet de réaliser un décalage (shift)

>> > num = ord('y')
121
>> > num + 13  # Décalage
134
>> > chr(134)
'\x86'  # Ce n'est pas un caractère affichable ! On a dépassé le z


def apply_shift(letter, shift):    
    pos_a_in_ascii_table = ord("a")
    letter_as_nb = ord(letter)
    pos_in_alphabet = letter_as_nb - pos_a_in_ascii_table
    # On applique un modulo 26. [1]    
    count = shift % 26    
    # new_letter_code contient la position de la lettre dans l'alphabet [2]    
    new_letter_code = (pos_in_alphabet + count) % 26    
    letter = chr(pos_a_in_ascii_table + new_letter_code)
    return letter

Cette fonction n’est valide que pour les lettres minuscules et pour un décalage positif.

Le principe de l’algorithme est le suivant :

[1] Le modulo va permettre de garder le reste de la division par 26.

Exemple : Si on applique une rotation de 26 à la lettre A, on retombe sur la lettre A. De la même manière, si on applique 11856 rotations à une lettre, on retombera sur cette même lettre (11 856 = 26 * 456). D’un autre côté, si on applique 27 rotations à la lettre A, on tombe sur la lettre B. En effet, on fait un tour complet plus un décalage. On remarque alors qu’il suffit seulement d’utiliser comme décalage le décalage donné, modulo 26 !

[2] Les ordinateurs utilisent une table de correspondance entre les nombres et les caractères. Il s’agit de la table ASCII. Sur le lien, on voit que les premiers caractères… ne sont pas imprimable. Le premier caractère visible est le ‘?’, dont la valeur est 32. La difficulté avec l’algorithme est justement que les lettres minuscules sont comprises entre 97 et 122, et les majuscules entre 65 et 90. Pour faciliter les choses, il vaut mieux se ramener entre 0 et 25, faire les calculs, puis repasser dans l’intervalle voulu.

Implémenter Vigenère

L’implémentation de Vigenère repose sur celle de César : il s’agit de faire un décalage de caractère sur chaque caractère. Ce qui change, c’est qu’au lieu d’avoir un décalage unique, celui-ci change en fonction d’une clef.

Exemple :

Clef m a n d a r i n e m a n d a r i n e m a n
Décalage 12 0 13 3 0 17 8 13 4 12 0 13 3 0 17 8 13 4 12 0 13
Texte clair B o n j o u r m o n n o m e s t J a m e s
Texte chiffré N o a m o l z z s z n b p e j b w e y e f

Structure de l’algo :

Liens utiles

Créer un menu en Python

Exemple d’un menu :

>>> print_menu()
1 - Titre du Menu 1
Description
2 - Titre du Menu 2
Description

>>> menu_nb = input()
2

>>> if menu == '1':
...  # Action
... if menu == '2':
...  # Autre action

Pour plus d’informations, voir les liens utiles

Pour créer un menu, le plus simple est d’afficher des propositions numérotées et de demander à l’utilisateur le numéro du menu auquel il souhaite accéder.

Exemples de code

Ouvrir un fichier

Pour ouvrir un fichier texte nommé my_message.txt

with open('my_message.txt', 'r') as f:
    content = f.read()

Geoguessr

Sujet

Le but de ce sujet est de pouvoir interroger une base de données CSV locale pour récupérer des informations utiles sur certains pays, ou bien de pouvoir retrouver le ou les pays respectant certains critères.

Format de la base de données

Pour la base de données, je vous conseille de respecter le format suivant :

Pays Langue Monnaie
France Français Euro
Royaume-Unis Anglais Livre Sterling

De cette manière, votre donnée sera correctement structurée.

Comment gérer le nom des pays

Les fonction utiles

a = "Bienvenue au cours de PyThOn"
print(a.upper())
>>> BIENVENUE AU COURS DE PYTHON
print(a.lower())
>>> bienvenue au cours de python
print(a.title())
>>> Bienvenue Au Cours De Python

Lorsque l’on doit faire une recherche dans une base de données à partir d’une entrée utilisateur, c’est souvent un challenge. En effet, il faut être capable de faire correspondre “FRANCE” avec “France” ou avec “france”, selon le format dans lequel votre nom de pays est stocké.

Une technique généralement utilisée consiste à toujours traiter des données en minuscule. Ansi, même si l’utilisateur décide de taper “FrAnCe”, une fois converti en minuscule, la recherche sera sur “france”. Ci-dessous quelques fonctions utiles (avec à droite des exemples d’utilisation) :

Palier 1

Exemple d’utilisation

Voici la liste des champs disponibles :
- Langue
- Monnaie
...
Sélectionner le champ souhaité :
>>> Langue
Entrez le nom d'un pays :
>>> Totoland
Désolé, mais ce pays n'est pas dans notre base 
Entrez le nom d'un pays :
>>> France
Le champ Langue pour le pays France vaut Euro

À partir de votre base de données :

  1. Au démarrage, afficher tous les champs disponibles (dans l’exemple ci-dessus, il s’agit du nom des colonnes)
  2. Demander à l’utilisateur d’entrer le nom d’un champ
  3. Demander à l’utilisateur d’entrer le nom d’un pays
  4. Afficher la valeur du champ demandé en (2) pour le pays entré en (3)

Palier 2

Exemple d’utilisation

Menu
1. Obtenir une information sur un pays
2. Obtenir la liste de pays respectant un critère donné
>>> 2

Voici la liste des champs disponibles :
- Langue
- Monnaie
...
Sélectionner le champ souhaité :
>>> Langue
Sélectionner la valeur à recherche :
>>> Anglais
Les pays pour lesquels le champ Langue vaut Français sont : France
  1. Demander à l’utilisateur de sélectionner un champ d’intérêt (par exemple la monnaie)
  2. Demander à l’utilisateur d’entrer une valeur (ex: Euro)
  3. Afficher le ou les pays correspondant à la valeur entrée

Palier 3

Exemple d’utilisation

Menu
1. Obtenir une information sur un pays
2. Obtenir la liste de pays respectant un critère donné
3. Exporter une fiche Pays
>>> 3
Entrez le nom du pays à exporter :
>>> France
Sélectionner le nom du fichier :
>>> France.txt
Le fichier a été correctement exporté

Contenu du fichier

France
======

Langue : Français
Monnaie : Euro

Dans ce palier, il vous faudra ajouter une troisième possibilité au menu : exporter toutes les informations disponibles sur un pays. Le fichier respectera la forme :

Nom du pays

===========

Nom du champ : Valeur du champ

Nom du champ : Valeur du champ …

Pays limitrophes

Le but du projet est de réaliser un outil permettant d’afficher les pays limitrophes d’un pays particulier.

Sujet

Pour ce sujet, vous allez être contraint, dès le premier palier, de manipuler des fichiers. Rançon du talent. Par ailleurs, il vous faudra créer une base de données sur les pays (à voir s’il en existe une).

Palier 1

>> De quel pays souhaitez vous connaître les voisins ?
France

Les voisins de la France sont :
- Belgique
- Luxembourg
- Allemagne
- Suisse
- Italie
- Espagne
-...

Ce premier palier sera dédié aux ‘pays limitrophes’ à proprement parler. Il vous faut créer un fichier CSV de la forme suivante :

France Belgique
Belgique Luxembourg
Luxembourg France
Allemagne France
Suisse Italie
  1. Lire le fichier
  2. Créer un dictionnaire associant chaque pays à la liste de ses pays voisins
  3. Demander à l’utilisateur le pays pour lequel il souhaite avoir la liste des voisins
  4. Afficher la liste

Palier 2

Exemple d’un fichier YAML file.yaml

France:
  population: 67
  capitale: Paris 
Royaume-Uni:
  population: 67
  capitale: Londres 
...

En python, en utilisant la fonction fournie dans les ressources

>> d = load_from_yaml("file.yaml")
>> d['France']
{'population': 67, 'capitale': 'Paris'}
>> d['Royaume-Uni']
{'population': 67, 'capitale': 'Londres'}

Ajoutons un peu d’informations. Vous aurez besoin pour cela d’un second fichier qui comprend la liste des informations sur le pays (monnaie, population, superficie… à vous de voir). Je vous conseille d’utiliser un fichier YAML. Ce format est très simple et permet, comme avec un dictionnaire, d’associer des clefs à des valeurs (voir ci-contre). L’avantage d’utiliser ce type de fichier, c’est qu’il existe une bibliothèque permettant de faire la transformation dict python <=> fichier YAML.

Dans les ressources, vous trouverez un code permettant de lire un fichier YAML, et un autre permettant d’en écrire un.

Palier 3

Code à copier/coller

!!pip install cartopy
import cartopy.crs as ccrs
import cartopy.feature as cf
from matplotlib import pyplot as plt
import cartopy.io.shapereader as shpreader
from cartopy.feature import ShapelyFeature

class Carto:
    def __init__(self):
        self.shpfilename = shpreader.natural_earth(resolution='110m',
                                      category='cultural',
                                      name='admin_0_countries')
        self.reader = shpreader.Reader(self.shpfilename)
        self.proj = ccrs.Miller()
        self.ax = plt.axes(projection=self.proj)
        self.ax.set_extent([-13, 45, 30, 70])
        self.ax.add_feature(cf.COASTLINE, lw=1)
        self.ax.add_feature(cf.BORDERS)
        self.ax.add_feature(cf.OCEAN,facecolor=(0.5,0.5,0.5))

    def color_country(self, country_name, color='lime'):
        try:
            country = next((country for country in self.reader.records() if country.attributes["NAME_LONG"] == country_name))
            shape_feature = ShapelyFeature([country.geometry], ccrs.PlateCarree(), facecolor=color, edgecolor='black', lw=1)
            self.ax.add_feature(shape_feature)
        except StopIteration:
            print(country_name, "not found in cartopy countries")
            
    def show(self):
        plt.show()

Exemple d’utilisation (essayez pour voir le résultat)

c = Carto()
c.color_country("Germany")
c.color_country("Spain")
c.color_country("Italy")
c.color_country("Luxembourg")
c.color_country("Belgium")
c.color_country("Switzerland")
c.color_country("United Kingdom")
c.color_country("France", 'red')
c.show()

Dans ce palier, vous allez pouvoir afficher les pays limitrophes au pays recherché sur une carte !

  1. Vous devez copier/coller le code ci-contre dans votre playbook, tout en haut.
  2. À partir des exemples, vous devriez pouvoir générer les cartes dont vous avez besoin

L’idée étant que lorsque je tape le nom d’un pays européen, ce pays soit colorié en rouge et les pays voisins en vert.

Ressources

Fonctions pour lire/écrire dans un fichier Yaml un dictionnaire d

import yaml
from yaml import Loader, Dumper
def load_from_file(filename):
    with open(filename, "r") as f:
        return yaml.load(f, Loader=Loader)
    
def save_to_file(filename, d):
    with open(filename, "w") as f:
        f.write(yaml.dump(d, Dumper=Dumper))

Liens utiles

Exemples de code


Mots-clés média

Le but du projet est de réaliser un outil capable de récupérer les articles de presse à partir d’une date.

Sujet

Sur internet, tous les sites sont tenus de mettre à disposition de leurs visiteurs un sitemap. Ce document liste l’ensemble des pages présentes sur le site. En théorie, ces documents doivent suivre un format particulier, le xml. En pratique, c’est un peu plus compliqué, et certains d’entre eux s’affranchissent des règles pour proposer leur propre format (Le Figaro par exemple).

Le sitemap est un bon moyen d’automatiser la collecte d’information sur les sites d’actualités : en effet, il ne contient que le strict nécessaire et classent généralement les articles par date.

Palier 1

Exemple avec le site lefigaro.fr

Entrer l'année:
> 2022
Entrer le mois:
> 12
Entrer le jour:
> 31
Les articles publiés le 31/12/2022 sont les suivants :
  - Les 46 soldats ivoiriens condamnés au Mali rentreront «bientôt», selon le président Ouattara
  - Covid-19 : l'UE veut une attitude commune face aux voyageurs de Chine
  - La Corée du Nord tire un missile balistique de courte portée
  - Quatre croisiéristes condamnés à payer plus de 450 millions de dollars pour leurs escales à Cuba
  - La situation dans l'est de la RDC est «pire que jamais», estime Kagame
  - Feu d'artifice du Nouvel an annulé à Rennes en raison de la météo
  - Réforme des retraites, coupures d'électricité, prix de l'énergie... Ce qu'il faut retenir des premiers «vœux aux Français» de «Macron 2»
  [...]

Le premier palier vise à récupérer la liste des articles pour un jour donné sur le figaro. Il s’agit donc de demander à l’utilisateur trois informations (sous la forme de trois nombres) :

  1. L’année
  2. Le mois
  3. Le jour

À partir de ces trois données, il devient possible de déterminer l’URL de la page web contenant les articles qui nous intéressent.

Palier 2

Les jours de la semaine en Python

import datetime

year = 2022
month = 12
day = 31

date = datetime.datetime(year, month, day)
day_of_the_week = date.weekday()
monday_date = date - datetime.timedelta(days=day_of_the_week)
print(monday_date.date())
> 2022 - 12 - 26

Parsing d’une chaine de caractères xml

import xml.etree.ElementTree as ET

# La variable response contient la réponse à la requête HTTP (cf exemple)
content = response.content

tree = ET.fromstring(content)
root = tree.getroot()

Contrairement au Figaro, Le Monde utilise le format XML pour classer les données, et proposer plus de contexte au lecteur.

Palier 3

Le but est de pouvoir récupérer, pour un jour donné, les mots les plus utilisés. Le mieux serait de croiser les données entre les deux sites supportés : est-ce que les mêmes mots sont présents ?

Ressources

Liens utiles

Exemples de code

Récupération d’une page HTML à partir de l’URL

import requests

response = requests.get("https://articles.lefigaro.fr/202212/29/")
if response.status_code != 200:
    print("Error")
else:
    # On affiche le contenu de la page
    print(response.content)

Parsing d’une page web

# Récupération du module de parsing
from bs4 import BeautifulSoup

# Cf exemple précédent
page = response.content

# On parse le contenu de la page téléchargée et on stocke le résultat dans la variable parsed
parsed = BeautifulSoup(page, parser="html.parser")
# On stocke dans l l'ensemble des éléments de la page dont la classe est list-group
l = parsed.find_all(class_="list-group")

Pile ou face

Le but du projet est de réaliser un pile ou face.

Sujet

Palier 1

Exemple d’interaction

>>> Combien de manches ?
4
>>> Choix ?
PPFF

Manche 1 : Pile. C'est gagné !
Manche 2 : Face. Perdu
Manche 3 : Face. C'est gagné !
Manche 4 ! Face. C'est gagné !
Score : 3 points

Pour réaliser ce palier :

  1. Demander à l’utilisateur un nombre de manches
  2. Demander à l’utilisateur de rentrer une chaine de caractère représentant ses choix :
    • P ou p pour pile (les deux doivent fonctionner)
    • F ou f pour face
    • Exemples:
      • Manche en 4 avec Pile, Pile, Face, Face : l’utilisateur rentre “ppff” ou “PpFf” ou “ppFF”…
      • Manche en 2 avec Pile, Face : “pf” ou “PF” ou “pF”…
  3. Pour chaque manche, tirer un nombre aléatoire (0 ou 1, cf Ressources)
    • 0 = Pile
    • 1 = Face
    • Afficher pour le joueur le score manche par manche

Palier 2

>>> Combien de manches ?
4
>>> Choix ?
PPFF
>>> Montant joué
10.50

Manche 1 : Pile. C'est gagné ! Vous avez 21.00€
Manche 2 : Face. Perdu. Il vous reste 7€
Manche 3 : Face. C'est gagné ! Vous avez 14.00€
Manche 4 ! Face. C'est gagné !Vous avez 28.00€
Score : 3 points. Vous avez gagné 18€ par rapport à votre mise initiale, bravo !

Ajoutons un peu d’enjeu à ce pile ou face.

Palier 3

John: 120.52
Loic: 3.00
Etienne: 8.00
>> d = load_from_file("balance.yaml")
>> d["John"]
120.52
>> "Ben" in d
False
>> d["Ben"] = 100.00
>> save_to_file(d)

Dans ce palier, vous allez devoir tenir à jour les comptes des joueurs dans un fichier.

Pour le fichier de suivi des comptes, un conseil est d’utiliser le format YAML. Ce format est très simple et permet, comme avec un dictionnaire, d’associer des clefs à des valeurs (voir ci-contre). L’avantage d’utiliser ce type de fichier, c’est qu’il existe une bibliothèque permettant de faire la transformation dict python <=> fichier YAML.

Dans les ressources, vous trouverez un code permettant de lire un fichier YAML, et un autre permettant d’en écrire un. Le fonctionnement de votre programme doit être le suivant :

Ressources

Fonctions pour lire/écrire dans un fichier Yaml un dictionnaire d

import yaml
from yaml import Loader, Dumper


def load_from_file(filename):
    with open(filename, "r") as f:
        return yaml.load(f, Loader=Loader)


def save_to_file(filename, d):
    with open(filename, "w") as f:
        f.write(yaml.dump(d, Dumper=Dumper))

Liens utiles

Exemples de code

Scraping WW1

Pour rappel, les membres du groupe sont :

Sujet

La mairie de Paris a développé un “mur virtuel” reprenant la liste des parisiens morts durant la première guerre mondiale. La liste est disponible sur le site https://memorial14-18.paris.fr/memorial/jsp/site/Portal.jsp?page=memorial&page_index.

Palier 1

Quelle page ? > 10
AMEDE Emile
	Date de décès: 09/01/1915
	Lieu de décès: BEAUSEJOUR (51) - FRANCE
	Arrondissement d'origine: 18e
AMEIHAUD Pierre Louis
	Date de décès: 18/06/1918
	Lieu de décès: SAUMUR (49) - FRANCE
	Arrondissement d'origine: 13e
...
  1. L’application demande à l’utilisateur un numéro de page
  2. L’application requête le site et récupère la bonne page
  3. Elle affiche, pour chaque nom :
    • Nom
    • Prénom
    • Date de décès
    • Lieu de décès
    • Arrondissement d’origine

Affichage attendu :

Palier 2

Nom de famille ? > AMEDE
AMEDE Emile
	Date de décès: 09/01/1915
	Lieu de décès: BEAUSEJOUR (51) - FRANCE
	Arrondissement d'origine: 18e
...

Cette base est importante : elle regroupe 94 415 noms. Pour cela, il est conseillé de scrapper la base et d’en stocker une copie au format CSV. En cas de difficultés dans la réalisation de cette étape, n’hésitez pas à poser vos questions.

  1. L’application demande à l’utilisateur d’entrer un nom de famille
  2. Rechercher dans la base de données des nom le nom associé
  3. Pour chacun des noms, afficher
    • Nom
    • Prénom
    • Date de décès
    • Lieu de décès
    • Arrondissement d’origine

Palier 3

Proposer à l’utilisateur de sauvegarder les résultats dans un fichier CSV

Nom Prénom Date de décès Lieu de décès Arrondissement
AMEDE Emile 09/01/1915 BEAUSEJOUR (51) - FRANCE 18e

Répertoire national des élus

A partir des fichier RNE, vous allez devoir permettre à un utilisateur d’effectuer des recherches sur les élus français.

Vous allez devoir télécharger plusieurs fichiers :

Palier 1

Ce palier se concentre uniquement sur le répertoire des maires. Dans ce palier, l’utilisateur doit entrer le nom de famille d’un maire. Vous devrez en retour afficher :

Palier 2

Dans ce palier, l’utilisateur doit pouvoir sélectionner la base sur laquelle il souhaite faire la recherche (Maire, Sénateur, Député ou parlementaire européen). Vous devez pour cela recourir à un menu permettant à l’utilisateur de choisir la base de recherche.

Palier 3

Dans ce palier, vous devrez proposer à l’utilisateur d’exporter le résultat de la recherche qu’il vient d’effectuer dans un fichier. Le format du fichier est laissé libre, mais un fichier texte semble le plus approprié