Initial commit

This commit is contained in:
2025-07-04 19:26:39 +02:00
commit c8682d4801
248 changed files with 12519 additions and 0 deletions

View File

@ -0,0 +1,40 @@
def base_conversions():
"""
Conversions entre types via les fonctions de base de python.
"""
# Convertir une chaîne en valeur entière
print(int("26"))
print(float("36.5"))
# Convertir une valeur en chaîne
print(str(36.5))
# Convertir une valeur complexe en chaîne
print(str([1, 2, 3, 4, 5]))
# Convertir un entier en valeur hexadécimale
print(hex(571))
# Conversions mathématiques
print(round(2.5))
print(round(2.45678, 1))
print(round(2.45678, 2))
# Les valeurs dites fausses
print("Conversions booléennes qui renvoient faux")
print(bool(None))
print(bool(0))
print(bool(""))
print(bool(False))
print(bool([]))
# Les valeurs dites vraies (autres que les valeurs fausses)
print("Conversions booléennes qui renvoient vrai")
print(bool(1)) # nombre non nul
print(bool(-1)) # nombre non nul
print(bool("Bonjour")) # chaîne non vide
print(bool(True))
print(bool([1, 3, 5, 7, 9])) # liste non vide
if __name__ == "__main__":
base_conversions()

View File

@ -0,0 +1,3 @@
seq = [25, 40, 55, 19]
for idx, number in enumerate(seq, start=1):
print(f"Itération {idx} : {number}.")

View File

@ -0,0 +1,30 @@
def builtin_introspection():
"""
Test des fonctions natives d'introspection de Python.
Ici on teste les fonctions accessibles sans faire d'import,
et qui permettent d'en savoir plus sur l'état du programme ou de
ses variables.
"""
data1 = "chaîne de caractères"
# Fonction pour vérifier le type d'une variable
print(isinstance(data1, str))
print(issubclass(str, object))
print(issubclass(str, int))
print(type(data1))
# Fonction pour accéder aux attributs d'une variable
print(hasattr(data1, "manger"))
print(hasattr(data1, "upper"))
print(getattr(data1, "upper"))
# Fonctions pour accéder à toutes les variables locales ou globales
print(locals())
print(globals())
# Fonction qui affiche le texte d'aide pour une fonction, méthode etc.
print(help(data1))
print(help(data1.upper))
if __name__ == "__main__":
builtin_introspection()

View File

@ -0,0 +1,34 @@
def base_iterable_tests():
"""
Fonctions de base de python utilisables sur les itérables.
"""
# Tester any, all
iterable1 = [0, 1, 0, 1, 0, 1]
iterable2 = [0, 0, 0, 0, 0, 0]
iterable3 = [1, 1, 1, 1, 1, 1]
iterable4 = [0, 1, 2, 3, 4, 5]
iterable5 = ["a", "b", "c", "d", "e", "f"]
# Vérifier que toutes les valeurs sont "vraies"
print(all(iterable1))
print(all(iterable3))
# Vérifier qu'au moins une valeur est vraie
print(any(iterable1))
print(any(iterable2))
print(any(iterable4))
# Vérifier la longueur de l'itérable
print(len(iterable1))
# Calculer la somme des éléments
print(sum(iterable1))
print(sum(iterable4))
# Trouver la valeur minimale/maximale des éléments
print(min(iterable4))
print(max(iterable4))
print(min(iterable5))
print(max(iterable5))
if __name__ == "__main__":
base_iterable_tests()

View File

@ -0,0 +1,16 @@
"""Example module for variable declaration."""
if __name__ == '__main__':
# Define simple variables
integer1 = 15 # integer value
float1 = 15.0 # floating value
text1 = "Simple text" # string value
boolean1 = True # boolean value
undefined1 = None # special None value
# Display variable contents
print(integer1)
print(float1)
print(text1)
print(boolean1)
print(undefined1)

View File

@ -0,0 +1,62 @@
def base_exception_handling():
"""Code de base pour gérer une exception."""
try:
15 / 0
except ZeroDivisionError:
print("Nous avons eu une erreur de division par zéro !")
except Exception:
print("Exception non prise en charge !")
def exception_with_else():
"""
Gérer une exception, avec la clause else.
La clause else contient du code qui est exécuté si tout se passe
bien.
"""
try:
15 / 1
except ZeroDivisionError:
print("Division par zéro !")
else:
print("Tout s'est bien passé !")
def exception_with_finally():
"""
Gérer une exception, avec la clause finally.
Le bloc de la clause finally est toujours exécuté,
quand une exception est levée ou que tout se passe bien.
le bloc finally est même exécuté si vous essayez de faire un
`return` dans votre bloc `try`, alors que pourtant la directive
`return` interrompt normalement l'exécution de la fonction.
Cas de figure : fermer un fichier ouvert quoi qu'il arrive.
"""
try:
15 / 0
except ZeroDivisionError:
print("Division par zéro !")
return None
finally:
print("Pas si vite, monsieur return !")
def raise_exception():
"""
Lever manuellement une exception simple.
Si vous voyez une erreur dans la console, c'est normal.
"""
raise ValueError("Valeur incorrecte.")
if __name__ == "__main__":
base_exception_handling()
exception_with_else()
exception_with_finally()
raise_exception()

View File

View File

@ -0,0 +1,56 @@
from datetime import date, datetime, timezone
def base_dates():
"""
Gérer des dates de base.
"""
# Créer deux dates
today = date.today()
before = date(2018, 7, 15) # 15 juillet 2018
# Afficher la date du jour, et aussi la formater
print(f"Aujourd'hui nous sommes le {today}")
print(f"Aujourd'hui nous sommes le (formaté) {today:%d/%m/%Y}")
# Afficher la date initialisée manuellement
print(f"La finale de Coupe du monde de football a eu lieu le {before}")
def base_datetimes():
"""
Gérer des dates avec heure.
"""
# Créer deux moments dans le temps
now = datetime.now()
before = datetime(2018, 7, 15, 20, 0) # 15 juillet 2018 à 20h
# Afficher la date du jour, et aussi la formater
print(f"Maintenant nous sommes le {now}")
print(f"Maintenant nous sommes le (formaté) {now:%d/%m/%Y %H:%M:%S}")
# Afficher la date initialisée manuellement
print(f"La finale de Coupe du monde de football a eu lieu à {before}")
def timezone_datetimes():
"""
Gérer des dates avec heure, et avec fuseau horaire.
"""
now = datetime.now(timezone.utc)
before = datetime(2018, 7, 15, 20, 0, tzinfo=timezone.utc) # 15 juillet 2018 à 20h
# Afficher la date du jour, et aussi la formater
# Voir https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes
print(f"Maintenant nous sommes le {now}")
print(f"Maintenant nous sommes le (formaté) {now:%d/%m/%Y %H:%M:%S (%Z)}")
# Afficher la date initialisée manuellement
print(f"La finale de Coupe du monde de football a eu lieu à {before}")
if __name__ == "__main__":
# Lancer la fonction qui teste des dates
base_dates()
# Lancer la fonction qui teste des dates avec heure
base_datetimes()
# Lancer la fonction qui teste des dates avec heure et fuseau horaire
timezone_datetimes()

View File

@ -0,0 +1,21 @@
from datetime import datetime, timedelta
def base_datetime_timedelta():
"""
Gérer des dates avec heure et ajouter des intervalles de temps.
"""
# Créer deux moments dans le temps
now: datetime = datetime.now()
interval: timedelta = timedelta(hours=6)
in_six_hours: datetime = now + interval
# Afficher la date du jour, et aussi la formater
print(f"Dans 6 heures on sera le (formaté) {in_six_hours:%d/%m/%Y %H:%M:%S}")
# Afficher la représentation texte de l'intervalle
print(f"L'intervalle de temps est {interval}")
if __name__ == "__main__":
# Lancer la fonction qui teste des dates
base_datetime_timedelta()

View File

@ -0,0 +1,115 @@
from typing import List, Set
class User(object):
"""
Classe représentant un utilisateur.
"""
name: str = None
first_name: str = None
email: str = None
password: str = None
def __init__(self, name, first_name, email, password):
"""
Initialiser un nouvel utilisateur.
Args:
name: nom
first_name: prénom
email: email
password: mot de passe
"""
self.name = name
self.first_name = first_name
self.email = email
self.password = password
def __repr__(self):
"""
Texte affiché pour l'objet quand on le passe dans `print()` ou surtout
que sa représentation textuelle est demandée.
Returns:
Le nom de l'utilisateur.
"""
return self.name
class Group(object):
"""
Classe de groupe d'utilisateurs.
"""
name: str = None
description: str = None
# Ici on a un attribut qui est une liste d'objets d'une autre classe.
# C'est ce qu'on appelle l'agrégation.
# Si on supprime le groupe, les objets utilisateurs existent toujours indépendamment,
# on a ici simplement un lien vers des utilisateurs.
users: Set[User] = None
def __init__(self, name, description=None):
"""
Initialiser un nouveau groupe d'utilisateurs.
Args:
name: nom du groupe
description: texte descriptif, facultatif
"""
self.name = name
self.description = description
def __repr__(self):
"""
Texte affiché pour l'objet quand on le passe dans `print()`
Returns:
Le nom du groupe.
"""
return self.name
def add_user(self, user: User):
"""
Ajouter un utilisateur au groupe.
Args:
user: instance d'utilisateur à ajouter
"""
self.users = self.users or set()
self.users.add(user)
def get_users(self):
"""
Renvoie la liste des utilisateurs dans le groupe.
Returns:
La liste des utilisateurs ajoutés au groupe.
"""
return self.users
if __name__ == "__main__":
# Créer quelques utilisateurs
user1 = User("Martin", "Jacques", "jmartin@example.com", "jmartin")
user2 = User("Carletti", "Audrey", "acarletti@example.com", "acarletti")
user3 = User("Richard", "Luc", "lrichard@example.com", "lrichard")
user4 = User("Havel", "Vaclav", "vhavel@example.com", "vhavel")
# Créer un groupe ou deux
group1 = Group("Amicale des amateurs de froid")
group2 = Group("Amicale des amateurs de chaud")
# Ajouter des utilisateurs aux groupes
group1.add_user(user1)
group1.add_user(user2)
group1.add_user(user3)
group2.add_user(user4)
# Afficher les utilisateurs pour chaque groupe
print(f"Utilisateurs du groupe {group1.name} : {group1.get_users()}")
print(f"Utilisateurs du groupe {group2.name} : {group2.get_users()}")

View File

@ -0,0 +1,64 @@
from typing import Optional
class Animal(object):
"""
Classe de base pour tous les animaux.
"""
pattes: int = None
vertebre: Optional[bool] = None
def manger(self):
"""
Méthode de base pour que l'animal mange.
On ne définit aucun comportement particulier ici.
"""
print("Je suis un animal et je mange.")
class Chien(Animal):
"""
Classe pour le chien.
"""
pattes: int = 4
vertebre = True
def manger(self):
"""
Méthode pour faire manger le chien.
"""
super().manger() # Exécute le code ligne 19
print("Je dirais même plus *wouf* ! Je suis un chien qui mange.")
class Escargot(Animal):
"""
Classe pour l'escargot.
"""
pattes: int = 0
vertebre = False
def manger(self):
"""
Méthode pour faire manger l'escargot.
"""
print("Slurp *mange, mais on ne sait pas comment*")
if __name__ == "__main__":
# Créer des nouvelles instances d'animaux
escargot = Escargot()
chien = Chien()
# Et voir comment ça se comporte quand on appelle la méthode `manger`.
# Le fait que plusieurs classes héritant d'une autre classe ont des comportements
# différents pour les mêmes méthodes s'appelle du polymorphisme.
# Les méthodes peuvent aussi avoir des arguments différents mais le même nom.
print(escargot.manger())
print(chien.manger())

View File

@ -0,0 +1,92 @@
class Person(object):
"""
Classe représentant une personne.
"""
nom: str = None
prenom: str = None
age: int = None
def __init__(self, *_args, **kwargs):
"""
Initialiser les valeurs d'une nouvelle personne.
Args:
*_args: Liste d'arguments non positionnels
**kwargs: Arguments nommés, utilisés pour initialiser les attributs de notre objet.
"""
self.nom = kwargs.get("nom", None)
self.prenom = kwargs.get("prenom", None)
self.age = kwargs.get("age", None)
def set_nom_complet(self, nom, prenom):
"""
Méthode pour définir les noms et prénom de l'individu.
Args:
nom: Nom de famille à attribuer
prenom: Prénom à attribuer à l'objet
"""
self.prenom = prenom
self.nom = nom
def get_nom_complet(self):
"""
Méthode pour retrouver d'un coup le nom complet de l'individu.
Returns:
Nom complet, sous la forme "<prenom> <nom>"
"""
if self.prenom and self.nom:
return f"{self.prenom} {self.nom}"
else:
return "Nom complet non renseigné"
class Professional(Person):
"""
Classe représentant un professionel, héritant de `Person`.
"""
telephone_pro: str = None
job: str = None
def __init__(self, *_args, **kwargs):
"""
Initialiser les données d'un nouveau professionel.
On peut également initialiser le prénom, nom et âge.
Args:
*_args: Liste d'arguments non positionnels
**kwargs: Liste d'arguments nommés, utilisés pour initialiser les attributs de notre objet.
"""
super().__init__(*_args, **kwargs)
self.telephone_pro = kwargs.get("telephone_pro", None)
self.job = kwargs.get("job", None)
def get_nom_complet(self):
"""
Méthode pour retrouver d'un coup le nom complet de l'individu.
Returns:
Nom complet, sous la forme "<prenom> <nom>"
"""
base_nom = super().get_nom_complet()
return f"{base_nom} ({self.job})"
if __name__ == "__main__":
# Ici on se crée plusieurs objets, 2 professionnels et une personne
pro1 = Professional(nom="Mario", prenom="Mario", age=38, telephone_pro="0799999999", job="Jardinier")
pro2 = Professional(nom="Mario", prenom="Luigi", age=37, telephone_pro="0799999999", job="Plombier")
mec = Person(nom="Bertrand", prenom="Julien", age=30)
# Les deux classe Person et Professional ont des méthodes `get_nom_complet()` différentes, tester
print(mec.get_nom_complet())
print(pro1.get_nom_complet())

View File

@ -0,0 +1,42 @@
import pdir
def use_dir():
"""
Découvrir l'introspection via la fonction `dir()`
Nécessite pdir2 pour montrer une sortie plus sympa aux étudiants.
"""
# En python, tout est un objet, et a donc des attributs et des méthodes.
# Le truc bien, c'est qu'en Python, on peut aussi manipuler et retrouver les
# propriétés de ces attributs et méthodes.
chaine = "Bonjour"
# À la place de `pdir` on pouvait utiliser `dir` qui fait partie de python,
# mais qui affiche la liste des attributs de l'objet de façon beaucoup moins
# lisible.
print(pdir(chaine))
def check_attrs():
"""
Via l'introspection, accéder à des attributs d'objets programmatiquement.
"""
chaine = "Bonjour"
# Une chaîne a toujours une méthode `capitalize`, donc ça va fonctionner
if hasattr(chaine, "capitalize"):
print("L'objet a bien une fonction `capitalize`.")
print(getattr(chaine, "capitalize"))
# Mais une chaîne n'a pas d'attribut `doesnotexist`.
if hasattr(chaine, "doesnotexist"):
print("L'objet a un attribut `doesnotexist`.")
else:
print("L'objet n'a pas d'attribut `doesnotexist`.")
if __name__ == "__main__":
print("Utilisation de la fonction `dir` :")
use_dir()
print("Utilisation de l'introspection d'attributs :")
check_attrs()

View File

View File

@ -0,0 +1,11 @@
class DelTest:
def __del__(self):
print("Suppression.")
a = DelTest()
b = a
# On s'attend à afficher Suppression avant d'afficher la référence de b.
del a
print(b)

View File

@ -0,0 +1,6 @@
import csv
with open("demo-file-985.csv", "r", encoding="utf-8") as f:
reader = csv.reader(f)
for row in reader: # row sera une séquence, contenant un élement par colonne de la ligne en cours
print(row) # Affiche la ligne courante du CSV séparée dans une liste.

File diff suppressed because one or more lines are too long

View File

View File

@ -0,0 +1,42 @@
def write_file():
"""
Écrire un fichier binaire très simple.
En Python, on ne peut pas tout simplement écrire des chaînes dans un
fichier dit binaire. Dans Python 3, on fait la différence entre binaire et texte.
Quand on manipule des fichiers texte, on peut y écrire des données `str`.
Par contre, quand on manipule des fichiers binaires, on manipule des données plus
brutes, de type `bytes` (ou `bytearray`)
"""
f = open("demo.bin", "wb")
f.write(bytearray([32, 33, 34, 35, 36, 37, 38, 39, 40])) # (9)
f.write(b"Bonjour les amis") # (16) ça passe car les caractères sont ASCII et leur code tient dans un byte
f.write("Bonjour les héros, ça va bien ?".encode("utf-8")) # (33)
f.close()
def read_file():
"""
Lire dans un fichier binaire très simple.
"""
f = open("demo.bin", "rb")
tableau = f.read(9)
chaine1 = f.read(16)
chaine2 = f.read(33).decode("utf-8")
f.seek(0)
data = f.read()
f.close()
# Afficher les données lues dans le fichier
print(tableau)
print(chaine1)
print(chaine2)
# Pour tester, revenir au début du fichier et tout lire d'une traite
print(data)
if __name__ == "__main__":
write_file()
read_file()

View File

@ -0,0 +1 @@
!"#$%&'(Bonjour les amisBonjour les héros, ça va bien ?

View File

@ -0,0 +1 @@
Contenu de notre fichier texte de démo !

View File

@ -0,0 +1,43 @@
with open("demo.txt", "r", encoding="utf-8") as f:
pass
# écrire un manager
class File(object):
def __init__(self, file_name, method):
self.file_obj = open(file_name, method)
def __enter__(self):
return self.file_obj
def __exit__(self, type, value, traceback):
self.file_obj.close()
# Just by defining __enter__ and __exit__ methods we can use our new class in a with statement. Lets try:
#
# with File('demo.txt', 'w') as opened_file:
# opened_file.write('Hola!')
#
# Our __exit__ method accepts three arguments. They are required by every __exit__ method which is a part of a Context Manager class. Lets talk about what happens under-the-hood.
#
# The with statement stores the __exit__ method of the File class.
# It calls the __enter__ method of the File class.
# The __enter__ method opens the file and returns it.
# The opened file handle is passed to opened_file.
# We write to the file using .write().
# The with statement calls the stored __exit__ method.
# The __exit__ method closes the file.
# We did not talk about the type, value and traceback arguments of the __exit__ method. Between the 4th and 6th step, if an exception occurs, Python passes the type, value and traceback of the exception to the __exit__ method. It allows the __exit__ method to decide how to close the file and if any further steps are required. In our case we are not paying any attention to them.
#
# What if our file object raises an exception? We might be trying to access a method on the file object which it does not supports. For instance:
#
# with File('demo.txt', 'w') as opened_file:
# opened_file.undefined_function('Hola!')
#
# Lets list the steps which are taken by the with statement when an error is encountered:
#
# It passes the type, value and traceback of the error to the __exit__ method.
# It allows the __exit__ method to handle the exception.
# If __exit__ returns True then the exception was gracefully handled.
# If anything other than True is returned by the __exit__ method then the exception is raised by the with statement.

View File

@ -0,0 +1,12 @@
import os, glob
# traverse root directory, and list directories as dirs and files as files
for root, dirs, files in os.walk("/home/steve/Code/python/initiation"):
for filename in files:
path = os.path.join(root, filename)
print(path)
# https://docs.python.org/fr/3/library/glob.html
files = glob.glob("/home/steve/Code/python/initiation/**/*.py", recursive=True)
print(files)

View File

@ -0,0 +1,25 @@
def write_file():
"""
Écrire un fichier texte très simple.
"""
f = open("demo.txt", "w")
f.write("Contenu de notre fichier texte de démo e!")
f.close()
def read_file():
"""
Lire dans un fichier texte très simple.
"""
f = open("demo.txt", "r")
data = f.read()
f.close()
print(data)
if __name__ == "__main__":
write_file()
read_file()

View File

View File

@ -0,0 +1,25 @@
{
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": [
"GML",
"XML"
]
},
"GlossSee": "markup"
}
}
}
}
}

View File

@ -0,0 +1,12 @@
import json
from os.path import dirname, join
# N'exécute le code que si vous avez spécifiquement exécuté ce module python
if __name__ == "__main__":
saisie = input("Saisissez un truc")
current_folder = dirname(__file__)
# Ouvre le fichier demo.json en lecture
f = open(join(current_folder, "demo.json"), "r", encoding="utf-8")
data = json.load(f) # Va manipuler le descripteur de fichier et renvoyer les données converties
print(type(data)) # Vérifier que le type de la donnée n'est plus juste du texte
f.close()

View File

@ -0,0 +1,26 @@
from json import dumps
# N'exécute le code que si vous avez spécifiquement exécuté ce module python
if __name__ == "__main__":
data = {
"users": [
{
"name": "Jean",
"age": 25
},
{
"name": "Denis",
"age": 30
},
{
"name": "Alice",
"age": 35
},
{
"name": "Achour",
"age": 40
}
]
}
chaine = dumps(data)
print(type(chaine))

View File

@ -0,0 +1,25 @@
DON DIÈGUE
Ô rage ! ô désespoir ! ô vieillesse ennemie !
Nai-je donc tant vécu que pour cette infamie ?
Et ne suis-je blanchi dans les travaux guerriers
Que pour voir en un jour flétrir tant de lauriers ?
Mon bras quavec respect tout lEspagne admire,
Mon bras, qui tant de fois a sauvé cet empire,
Tant de fois affermi le trône de son roi,
Trahit donc ma querelle, et ne fait rien pour moi ?
Ô cruel souvenir de ma gloire passée !
Œuvre de tant de jours en un jour effacée !
Nouvelle dignité fatale à mon bonheur !
Précipice élevé doù tombe mon honneur !
Faut-il de votre éclat voir triompher le comte,
Et mourir sans vengeance, ou vivre dans la honte ?
Comte, sois de mon prince à présent gouverneur ;
Ce haut rang nadmet point un homme sans honneur ;
Et ton jaloux orgueil par cet affront insigne
Malgré le choix du roi, men a su rendre indigne.
Et toi, de mes exploits glorieux instrument,
Mais dun corps tout de glace inutile ornement,
Fer, jadis tant à craindre, et qui, dans cette offense,
Mas servi de parade, et non pas de défense,
Va, quitte désormais le derniers des humains,
Passe, pour me venger, en de meilleurs mains.

View File

@ -0,0 +1,18 @@
"""
Base file reading example.
This example uses:
- classic open/close of file
- while loop with walrus operator (Python 3.8).
"""
if __name__ == '__main__':
file = open("../files/don-diego.txt", "r", encoding="utf-8")
# Read the file contents line by line using the walrus operator
# (introduced in Python 3.8)
# While the line read is not empty, you're not at the end of file.
while line := file.readline().strip():
# Lines contain caret return. Using `.strip()`
# removes spaces and caret returns at the start and end.
print(f"{line}")
file.close()

View File

@ -0,0 +1,16 @@
"""
Base file reading example.
This example uses:
- context manager (with ... as)
- iterator (for ... in object).
"""
if __name__ == '__main__':
with open("../files/don-diego.txt", "r", encoding="utf-8") as file:
# Read the file contents line by line
for count, line in enumerate(file):
# Lines contain caret return. Using `strip`
# removes spaces and caret returns at the start and end
# of the string.
print(f"{count} : {line.strip()}")

View File

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<users>
<user data-id="101">
<nom>Zorro</nom>
<metier>Danseur</metier>
</user>
<user data-id="102">
<nom>Hulk</nom>
<metier>Footballeur</metier>
</user>
<user data-id="103">
<nom>Zidane</nom>
<metier>Star</metier>
</user>
<user data-id="104">
<nom>Beans</nom>
<metier>Epicier</metier>
</user>
<user data-id="105">
<nom>Batman</nom>
<metier>Veterinaire</metier>
</user>
<user data-id="106">
<nom>Spiderman</nom>
<metier>Veterinaire</metier>
</user>
</users>

View File

@ -0,0 +1,51 @@
from typing import List
from lxml import etree
if __name__ == "__main__":
# Balise principale
base = etree.Element("FastDMU", {"version": "2.0"})
# Balise Search system
root = etree.Element("SearchSystem")
# Deux champs pour Search System
root_title = etree.Element("Title")
root_mode = etree.Element("Mode")
root_title.text = "01"
root_mode.text = "AssembliesOnly"
root.append(root_title)
root.append(root_mode)
# Liste des items à ajouter
items: List[str] = ["A", "B", "C"]
for item in items:
# Création des éléments
search_item = etree.Element("SearchItem")
item_mode = etree.Element("Mode")
item_type = etree.Element("Type")
item_value = etree.Element("Value")
item_field = etree.Element("Field")
item_field_name = etree.Element("FieldName")
item_title = etree.Element("Title")
# Définition du texte
item_mode.text = "Add"
item_type.text = "Wildcard"
item_value.text = item
item_field.text = "PARTNUMBER"
item_field_name.text = "PARTNUMBER"
item_title.text = "Partnumber"
# Ajout des éléments au parent
search_item.append(item_mode)
search_item.append(item_type)
search_item.append(item_value)
search_item.append(item_field)
search_item.append(item_field_name)
search_item.append(item_title)
# Ajout du searchitem à la balise SearchSystem
root.append(search_item)
# Ajout de la balise SearchSystem à la balise FastDMU
base.append(root)
# J'aurais peut-être préféré faire ça avec BeautifulSoup4
# Ou peut-être gagner du temps en convertissant du texte directement
# en éléments XML.
print(etree.tostring(base, pretty_print=True, xml_declaration=True, encoding="iso8859-1",
doctype="<!DOCTYPE FastDMU>"))

View File

View File

@ -0,0 +1,17 @@
# Installer d'abord lxml avec pip install lxml
from lxml import etree
# Read content from XML file
with open("demo.xml", "rb") as file:
text = file.read()
# Read structure into Element object
structure = etree.fromstring(text)
print(type(structure))
print(structure.text)
print(structure.attrib)
for child in structure:
print(child, type(child), child.attrib)
print(structure.find("user"))

Binary file not shown.

View File

@ -0,0 +1,28 @@
import sqlite3
if __name__ == "__main__":
# Il existe dans Python une API unifiée, où les mêmes opérations
# s'effectuent avec les mêmes fonctions et méthodes, quelle que
# soit la base de données relationnelle SQL à laquelle on accède.
# Pour SQLite en l'occurrence, la méthode `.connect` ne prend qu'un seul
# paramètre, le nom de fichier, car SQLite est une base de données
# embarquée sans sécurité et n'a donc pas besoin de mot de passe ou de nom
# d'utilisateur.
connection = sqlite3.connect("database.sqlite3", isolation_level=None)
# Ici on crée une nouvelle table dans notre base de données si elle n'existe pas déjà.
# Cette fonction de la base de données renvoie un seul résultat pour dire que tout
# est OK.
connection.execute("CREATE TABLE IF NOT EXISTS person (nom varchar(30), prenom varchar(20), age int)")
# Insérer quelques nouvelles lignes de données dans notre nouvelle table.
connection.execute("INSERT INTO person VALUES ('Bouquet','Carole',62)")
connection.execute("INSERT INTO person VALUES ('Connery','Sean',85)")
connection.execute("INSERT INTO person VALUES ('Kotto','Yaphet',76)")
connection.execute("INSERT INTO person VALUES ('Zhang','Zhang',39)")
# Valider l'ajout et les nouvelles modifications en bloc (lorsque la base de données le permet)
connection.commit()
values = connection.execute("SELECT * FROM person WHERE age > 50")
print(values.fetchall())
# Ne pas oublier à la fin, lorsqu'on en a plus besoin, de fermer la connexion à la base (ou au fichier
# pour le cas de SQLite).
connection.close()

View File

View File

@ -0,0 +1,69 @@
import sys
from PySide6.QtGui import QIcon
from PySide6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QMenuBar, QMenu, QAction, \
QMainWindow, QWidget
class Window(QMainWindow):
"""
Classe définissant notre fenêtre principale.
"""
def __init__(self, parent=None):
"""
Initialiser chaque nouvelle instance de notre fenêtre.
Args:
parent: Widget qui va contenir notre boîte de dialogue.
"""
super().__init__(parent=parent)
self.setWindowTitle("Ma nouvelle fenêtre")
# Create widgets
self.icon = QIcon.fromTheme("scanner")
self.basewidget = QWidget(self)
self.edit = QLineEdit("Zone de texte")
self.button = QPushButton("Appuyez ici !")
self.menubar = QMenuBar(self)
self.menu = QMenu(self.menubar, title="Élément de menu principal")
self.menuentry = QAction(QIcon.fromTheme("network-wired"), "&Action")
self.menu.addAction(self.menuentry)
self.menubar.addAction(self.menu.menuAction())
# Insérer un objet de mise en page dans notre fenêtre,
# et y ajouter nos champ de texte et bouton
self.setCentralWidget(self.basewidget)
layout = QVBoxLayout(self)
self.basewidget.setLayout(layout)
self.setMenuBar(self.menubar)
layout.addWidget(self.edit)
layout.addWidget(self.button)
self.setMinimumSize(640, 128)
# Connecter le clic du bouton à la méthode "validate_button"
self.button.clicked.connect(self.validate_button)
def validate_button(self):
"""
On définit cette méthode pour répondre au clic sur un bouton.
Il faut que l'on configure notre bouton pour que lorsqu'on clique
dessus, cette méthode soit exécutée.
"""
print(f"Vous avez saisi {self.edit.text()}")
if __name__ == "__main__":
# Créer une instance qui définit une application Qt
# Via la variable "sys.argv", qui correspond aux arguments passés en ligne de commande
# dans une liste de chaînes (ex. python programme.py arg1 arg2 arg3)
# on peut configurer le comportement de notre application...
# Également : notre application est un Singleton
application = QApplication(sys.argv)
# Ajouter notre boîte de dialogue
window = Window()
window.show()
# Lancer la boucle Qt, qui ferme le programme quand on ferme toutes les fenêtres
application.exec_()
sys.exit()

View File

@ -0,0 +1,27 @@
import sys
from PySide6.QtCore import QFile, QObject
QObject
# Exemple avec QT Designer
if __name__ == "__main__":
# Créer une instance qui définit une application Qt
# Via la variable "sys.argv", qui correspond aux arguments en ligne de commande
# on peut configurer le comportement de notre application...
# Également : notre application est un Singleton
application = QApplication(sys.argv)
# Utiliser Qt pour ouvrir le fichier Qt Designer qu'on a créé
file = QFile("files/base-ui.ui")
file.open(QFile.ReadOnly)
# Utiliser une classe de Qt qui est capable de créer des interfaces depuis des fichiers
loader = QUiLoader()
window = loader.load(file)
file.close()
# Ici on teste que l'on a bien accès aux variables membres du fichier qu'on a chargé
window.lineEdit: QLineEdit = window.lineEdit
window.lineEdit.setText("Bonjour les amis")
# Afficher notre fenêtre chargée
window.show()
# Lancer la boucle Qt, qui ferme le programme quand on ferme toutes les fenêtres
sys.exit(application.exec_())

View File

@ -0,0 +1,34 @@
import sys
from PySide2.QtWidgets import QDialog, QApplication
class Dialog(QDialog):
"""
Classe définissant notre fenêtre principale.
"""
def __init__(self, parent=None):
"""
Initialiser chaque nouvelle instance de notre fenêtre.
Args:
parent: Widget qui va contenir notre boîte de dialogue.
"""
super().__init__(parent=parent)
self.setWindowTitle("Ma nouvelle fenêtre")
if __name__ == "__main__":
# Créer une instance qui définit une application Qt
# Via la variable "sys.argv", qui correspond aux arguments en ligne de commande
# on peut configurer le comportement de notre application...
# Également : notre application est un Singleton
application = QApplication(sys.argv)
# Ajouter notre boîte de dialogue
dialog = Dialog()
dialog.show()
# Lancer la boucle Qt, qui ferme le programme quand on ferme toutes les fenêtres
sys.exit(application.exec_())

View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>575</width>
<height>317</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<item>
<widget class="QLineEdit" name="lineEdit"/>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_2"/>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>575</width>
<height>31</height>
</rect>
</property>
<widget class="QMenu" name="menuMenu_principal">
<property name="title">
<string>Menu principal</string>
</property>
<addaction name="actionAction_1"/>
<addaction name="actionAction_2"/>
<addaction name="separator"/>
<addaction name="actionAction_3"/>
</widget>
<addaction name="menuMenu_principal"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionAction_1">
<property name="icon">
<iconset theme="input-tablet">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>Action 1</string>
</property>
</action>
<action name="actionAction_2">
<property name="icon">
<iconset theme="network-wired">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>Action 2</string>
</property>
</action>
<action name="actionAction_3">
<property name="icon">
<iconset theme="scanner">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>Action 3</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Window</class>
<widget class="QMainWindow" name="Window">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Window</string>
</property>
<widget class="QWidget" name="centralwidget"/>
<widget class="QMenuBar" name="menubar"/>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,28 @@
# This Python file uses the following encoding: utf-8
import sys
import os
from PySide2.QtWidgets import QApplication, QMainWindow
from PySide2.QtCore import QFile
from PySide2.QtUiTools import QUiLoader
class Window(QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.load_ui()
def load_ui(self):
loader = QUiLoader()
path = os.path.join(os.path.dirname(__file__), "form.ui")
ui_file = QFile(path)
ui_file.open(QFile.ReadOnly)
loader.load(ui_file, self)
ui_file.close()
if __name__ == "__main__":
app = QApplication([])
widget = Window()
widget.show()
sys.exit(app.exec_())

View File

@ -0,0 +1,3 @@
{
"files": ["main.py", "form.ui"]
}

View File

@ -0,0 +1,196 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.14.0, 2021-02-25T10:34:49. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{f52a1091-6a1a-4c8e-9bfd-fca585155f33}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap">
<valuemap type="QVariantMap" key="AutoTest.ActiveFrameworks">
<value type="bool" key="AutoTest.Framework.Boost">true</value>
<value type="bool" key="AutoTest.Framework.Catch">true</value>
<value type="bool" key="AutoTest.Framework.GTest">true</value>
<value type="bool" key="AutoTest.Framework.QtQuickTest">true</value>
<value type="bool" key="AutoTest.Framework.QtTest">true</value>
</valuemap>
<valuemap type="QVariantMap" key="AutoTest.CheckStates"/>
<value type="int" key="AutoTest.RunAfterBuild">0</value>
<value type="bool" key="AutoTest.UseGlobal">true</value>
<valuelist type="QVariantList" key="ClangCodeModel.CustomCommandLineKey"/>
<value type="bool" key="ClangCodeModel.UseGlobalConfig">true</value>
<value type="QString" key="ClangCodeModel.WarningConfigId">Builtin.Questionable</value>
<valuemap type="QVariantMap" key="ClangTools">
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
<value type="int" key="ClangTools.ParallelJobs">6</value>
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
</valuemap>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="DeviceType">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{d044ec2e-da82-4493-a678-1f0961b658b1}</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">-1</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="QString" key="Analyzer.Perf.CallgraphMode">dwarf</value>
<valuelist type="QVariantList" key="Analyzer.Perf.Events">
<value type="QString">cpu-cycles</value>
</valuelist>
<valuelist type="QVariantList" key="Analyzer.Perf.ExtraArguments"/>
<value type="int" key="Analyzer.Perf.Frequency">250</value>
<valuelist type="QVariantList" key="Analyzer.Perf.RecordArguments">
<value type="QString">-e</value>
<value type="QString">cpu-cycles</value>
<value type="QString">--call-graph</value>
<value type="QString">dwarf,4096</value>
<value type="QString">-F</value>
<value type="QString">250</value>
</valuelist>
<value type="QString" key="Analyzer.Perf.SampleMode">-F</value>
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
<value type="int" key="Analyzer.Perf.StackSize">4096</value>
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="QString" key="Analyzer.Valgrind.KCachegrindExecutable">kcachegrind</value>
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<valuelist type="QVariantList" key="CustomOutputParsers"/>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">main</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">PythonEditor.RunConfiguration./home/steve/Code/python/initiation/source/gui/files/qtcreatordemo/basewindow/main.py</value>
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">/home/steve/Code/python/initiation/source/gui/files/qtcreatordemo/basewindow/main.py</value>
<value type="QString" key="PythonEditor.RunConfiguation.Interpreter">{9e6235fb-9067-40a7-be7d-a5b33f406c75}</value>
<value type="QString" key="PythonEditor.RunConfiguation.Script">/home/steve/Code/python/initiation/source/gui/files/qtcreatordemo/basewindow/main.py</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
<value type="QString" key="RunConfiguration.WorkingDirectory.default">/home/steve/Code/python/initiation/source/gui/files/qtcreatordemo/basewindow</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">22</value>
</data>
<data>
<variable>Version</variable>
<value type="int">22</value>
</data>
</qtcreator>

View File

@ -0,0 +1,20 @@
"""
Example code to select file using a file dialog.
Needs a Qt Application object and then a File dialog object.
The `getOpenFileName()` method on the file dialog object opens
a dialog for loading a single file. It returns a tuple, containing
the selected file name (str) and the filter (str).
If no file was selected (cancelled), you get empty strings in the tuple.
"""
from PySide6.QtWidgets import QFileDialog, QApplication
application = QApplication()
# You don't need application.exec() here because the method blocks the python script execution.
dialog = QFileDialog(directory="/home/steve", caption="Sélectionnez un fichier", filter="Text files (*.txt);; All files (*.*)")
selection: tuple[str, str] = dialog.getOpenFileName()
print(selection)
with open("/home/steve/Code/training/python/beginner/documentation/12-logging.md", "r") as file:
lines = file.readlines()
print(lines)

View File

@ -0,0 +1,86 @@
import sys
from PySide2.QtGui import QIcon
from PySide2.QtWidgets import QApplication, QLineEdit, QPushButton, QVBoxLayout, QAction, \
QMainWindow, QWidget
class Dialog(QMainWindow):
"""
Classe définissant notre fenêtre principale.
"""
def __init__(self, parent=None):
"""
Initialiser chaque nouvelle instance de notre fenêtre.
Args:
parent: Widget qui va contenir notre boîte de dialogue.
"""
super().__init__(parent=parent)
# Changer le titre de la fenêtre et changer la position et taille
self.setWindowTitle("Ma nouvelle fenêtre")
self.setGeometry(50, 50, 640, 480)
# Définir l'icône pour la fenêtre
self.setWindowIcon(QIcon.fromTheme("exit"))
# On crée manuellement des contrôles dans notre fenêtre et des menus
self.edit = QLineEdit("Zone de texte")
self.button = QPushButton("Appuyez ici !")
self.menuentry1 = QAction(QIcon.fromTheme("exit"), "&Fin")
self.menuentry2 = QAction(QIcon.fromTheme("sleep"), "&Dodo")
self.filemenu = self.menuBar().addMenu("&File")
self.filemenu.addAction(self.menuentry1)
self.filemenu.addSeparator()
self.filemenu.addAction(self.menuentry2)
# Insérer un objet de mise en page dans notre fenêtre,
# et y ajouter nos champ de texte et bouton
frame = QWidget()
layout = QVBoxLayout()
layout.addWidget(self.edit)
layout.addWidget(self.button)
# Ajouter la mise en page au widget
frame.setLayout(layout)
# Définir le widget comme le contenu de la fenêtre
self.setCentralWidget(frame)
# Connecter le clic du bouton à la méthode "validate_button"
self.button.clicked.connect(self.button_clicked)
# Connecter la validation du menu1 à la même méthode
self.menuentry1.triggered.connect(self.button_clicked)
# Connecter la modification du champ de texte à une méthode
self.edit.textEdited.connect(self.text_modified)
def button_clicked(self):
"""
On définit cette méthode pour répondre au clic sur un bouton.
Il faut que l'on configure notre bouton pour que lorsqu'on clique
dessus, cette méthode soit exécutée.
"""
print(f"Vous avez saisi {self.edit.text()}")
def text_modified(self):
"""
On définit cette méthode pour répondre à la modification du champ texte.
Cette méthode n'est pas spécifique à Qt, c'est juste qu'on peut lier
des événements de contrôles Qt à des fonctions arbitraires. Et on
va lier l'édition du champ de texte à cette méthode-ci.
"""
print(f"{self.edit.text()}")
if __name__ == "__main__":
# Créer une instance qui définit une application Qt
# Via la variable "sys.argv", qui correspond aux arguments en ligne de commande
# on peut configurer le comportement de notre application...
# Également : notre application est un Singleton
application = QApplication(sys.argv)
# Ajouter notre boîte de dialogue
dialog = Dialog()
dialog.show()
# Lancer la boucle Qt, qui ferme le programme quand on ferme toutes les fenêtres
sys.exit(application.exec_())

View File

View File

@ -0,0 +1,45 @@
import logging
import sys
def logging_without_formatting():
"""
La base de la journalisation.
"""
logger = logging.getLogger("noformat")
logger.debug("This is a debug message")
logger.info("This is an info message")
logger.warning("This is a warning message")
logger.error("This is an error message")
logger.critical("This is a critical message")
def logging_with_formatting():
"""
Configurer un peu notre journalisation pour mettre en forme nos messages.
"""
logger = logging.getLogger("withformat")
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# Créer une nouvelle configuration qui sort les messages de journal dans la console
handler = logging.StreamHandler(sys.stdout)
# Configurer cet objet pour utiliser notre format
handler.setFormatter(formatter)
# Configurer le handler pour afficher aussi les messages DEBUG et INFO
handler.setLevel(logging.DEBUG)
# Assigner notre configuration à notre logger
# On doit faire tout ça parce qu'il n'y a pas de méthode
# pour facilement définir une chaîne de formatage pour un logger
logger.addHandler(handler)
logger.warning("Message d'avertissement")
if __name__ == "__main__":
# Par défaut, Python n'affiche des messages de journalisation
# que s'ils excèdent une certaine sévérité.
# Dans la plupart des langages, par défaut, c'est la sévérité
# WARNING (en-dessous, on n'indique généralement pas de problème)
# qui est la plus basse prise en compte
logging_without_formatting()
logging_with_formatting()

View File

@ -0,0 +1,43 @@
import logging
def logging_with_formatting():
"""
Configurer un peu notre journalisation pour mettre en forme nos messages.
Nous devons utiliser un logger et le configurer pour savoir comment afficher nos
messages.
Un logger peut utiliser plusieurs handlers à la fois, et chacun a pour rôle
de transporter le message original vers une destination (fichier, console etc.)
Les handlers sont configurés en deux étapes : d'abord on choisit le type de
handler (fichier, console, etc.), et ensuite on lui associe un "formateur" pour
savoir comment stocker le message.
Notez : les loggers peuvent avoir un nom, et peuvent ainsi être retrouvés n'importe où
via leur nom pendant l'exécution de votre script, en utilisant la fonction `getLogger`.
"""
logger = logging.getLogger("withformat")
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# Créer une nouvelle configuration qui sort les messages de journal dans la console
handler = logging.FileHandler("demo.log")
# Configurer cet objet pour utiliser notre format
handler.setFormatter(formatter)
# Et accessoirement, changer le niveau minimal de sévérité
handler.setLevel(logging.INFO)
# Assigner notre configuration à notre logger
# On doit faire tout ça parce qu'il n'y a pas de méthode
# pour facilement définir une chaîne de formatage pour un logger
logger.addHandler(handler)
logger.warning("Message d'avertissement")
if __name__ == "__main__":
# Par défaut, Python n'affiche des messages de journalisation
# que s'ils excèdent une certaine sévérité.
# Dans la plupart des langages, par défaut, c'est la sévérité
# WARNING (en-dessous, on n'indique généralement pas de problème)
# qui est la plus basse prise en compte
logging_with_formatting()

View File

@ -0,0 +1,7 @@
- hosts: localhost
connection: local
gather_facts: yes
vars:
my_name: a_b_c
tasks:
- debug: msg={{ my_name|replace('_', '-') }}

View File

@ -0,0 +1,683 @@
{
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"172.17.0.1",
"192.168.31.36",
"192.168.31.165"
],
"ansible_all_ipv6_addresses": [
"fe80::9fb5:601b:d3e9:a68e"
],
"ansible_apparmor": {
"status": "disabled"
},
"ansible_architecture": "x86_64",
"ansible_bios_date": "09/12/2022",
"ansible_bios_vendor": "Dell Inc.",
"ansible_bios_version": "1.19.0",
"ansible_board_asset_tag": "NA",
"ansible_board_name": "00K2XV",
"ansible_board_serial": "NA",
"ansible_board_vendor": "Dell Inc.",
"ansible_board_version": "A00",
"ansible_chassis_asset_tag": "NA",
"ansible_chassis_serial": "NA",
"ansible_chassis_vendor": "Dell Inc.",
"ansible_chassis_version": "NA",
"ansible_cmdline": {
"BOOT_IMAGE": "/boot/vmlinuz-6.9-x86_64",
"apparmor": "0",
"fsck.mode": "skip",
"intel_pstate": "active",
"loglevel": "3",
"nvidia-drm.modeset": "1",
"quiet": true,
"ro": true,
"root": "UUID=ae7bbe2b-e356-4f63-bdf6-a6a3463bf1a8",
"splash": true,
"udev.log_level": "3",
"udev.log_priority": "1",
"vga": "current"
},
"ansible_date_time": {
"date": "2024-07-11",
"day": "11",
"epoch": "1720705695",
"epoch_int": "1720705695",
"hour": "15",
"iso8601": "2024-07-11T13:48:15Z",
"iso8601_basic": "20240711T154815266191",
"iso8601_basic_short": "20240711T154815",
"iso8601_micro": "2024-07-11T13:48:15.266191Z",
"minute": "48",
"month": "07",
"second": "15",
"time": "15:48:15",
"tz": "CEST",
"tz_dst": "CEST",
"tz_offset": "+0200",
"weekday": "jeudi",
"weekday_number": "4",
"weeknumber": "28",
"year": "2024"
},
"ansible_default_ipv4": {
"address": "192.168.31.36",
"alias": "eno2",
"broadcast": "192.168.31.255",
"gateway": "192.168.31.1",
"interface": "eno2",
"macaddress": "a4:bb:6d:ef:9d:84",
"mtu": 1500,
"netmask": "255.255.255.0",
"network": "192.168.31.0",
"prefix": "24",
"type": "ether"
},
"ansible_default_ipv6": {},
"ansible_device_links": {
"ids": {
"mmcblk0": [
"mmc-00000_0x15cdb40e"
],
"mmcblk0p1": [
"mmc-00000_0x15cdb40e-part1"
],
"nvme0n1": [
"nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L",
"nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L_1",
"nvme-eui.00000000000000018ce38e030035c0c1"
],
"nvme0n1p1": [
"nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L-part1",
"nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L_1-part1",
"nvme-eui.00000000000000018ce38e030035c0c1-part1"
],
"nvme0n1p2": [
"nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L-part2",
"nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L_1-part2",
"nvme-eui.00000000000000018ce38e030035c0c1-part2"
],
"nvme0n1p3": [
"nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L-part3",
"nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L_1-part3",
"nvme-eui.00000000000000018ce38e030035c0c1-part3"
]
},
"labels": {
"mmcblk0p1": [
"CLEANED"
]
},
"masters": {},
"uuids": {
"mmcblk0p1": [
"588B-5CCE"
],
"nvme0n1p1": [
"7D05-E937"
],
"nvme0n1p2": [
"ae7bbe2b-e356-4f63-bdf6-a6a3463bf1a8"
],
"nvme0n1p3": [
"d626c980-e737-484f-ab18-6324704f4d74"
]
}
},
"ansible_devices": {
"mmcblk0": {
"holders": [],
"host": "Unassigned class [ff00]: Realtek Semiconductor Co., Ltd. RTS5260 PCI Express Card Reader (rev 01)",
"links": {
"ids": [
"mmc-00000_0x15cdb40e"
],
"labels": [],
"masters": [],
"uuids": []
},
"model": null,
"partitions": {
"mmcblk0p1": {
"holders": [],
"links": {
"ids": [
"mmc-00000_0x15cdb40e-part1"
],
"labels": [
"CLEANED"
],
"masters": [],
"uuids": [
"588B-5CCE"
]
},
"sectors": "125794304",
"sectorsize": 512,
"size": "59.98 GB",
"start": "32768",
"uuid": "588B-5CCE"
}
},
"removable": "0",
"rotational": "0",
"sas_address": null,
"sas_device_handle": null,
"scheduler_mode": "mq-deadline",
"sectors": "125827072",
"sectorsize": "512",
"serial": "0x15cdb40e",
"size": "60.00 GB",
"support_discard": "4194304",
"vendor": null,
"virtual": 1
},
"nvme0n1": {
"holders": [],
"host": "Non-Volatile memory controller: Toshiba Corporation XG6 NVMe SSD Controller",
"links": {
"ids": [
"nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L",
"nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L_1",
"nvme-eui.00000000000000018ce38e030035c0c1"
],
"labels": [],
"masters": [],
"uuids": []
},
"model": "KXG60ZNV512G NVMe KIOXIA 512GB",
"partitions": {
"nvme0n1p1": {
"holders": [],
"links": {
"ids": [
"nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L-part1",
"nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L_1-part1",
"nvme-eui.00000000000000018ce38e030035c0c1-part1"
],
"labels": [],
"masters": [],
"uuids": [
"7D05-E937"
]
},
"sectors": "614400",
"sectorsize": 512,
"size": "300.00 MB",
"start": "4096",
"uuid": "7D05-E937"
},
"nvme0n1p2": {
"holders": [],
"links": {
"ids": [
"nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L-part2",
"nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L_1-part2",
"nvme-eui.00000000000000018ce38e030035c0c1-part2"
],
"labels": [],
"masters": [],
"uuids": [
"ae7bbe2b-e356-4f63-bdf6-a6a3463bf1a8"
]
},
"sectors": "981133465",
"sectorsize": 512,
"size": "467.84 GB",
"start": "618496",
"uuid": "ae7bbe2b-e356-4f63-bdf6-a6a3463bf1a8"
},
"nvme0n1p3": {
"holders": [],
"links": {
"ids": [
"nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L-part3",
"nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L_1-part3",
"nvme-eui.00000000000000018ce38e030035c0c1-part3"
],
"labels": [],
"masters": [],
"uuids": [
"d626c980-e737-484f-ab18-6324704f4d74"
]
},
"sectors": "18454939",
"sectorsize": 512,
"size": "8.80 GB",
"start": "981751961",
"uuid": "d626c980-e737-484f-ab18-6324704f4d74"
}
},
"removable": "0",
"rotational": "0",
"sas_address": null,
"sas_device_handle": null,
"scheduler_mode": "none",
"sectors": "1000215216",
"sectorsize": "512",
"serial": "40LA75CBK81L",
"size": "476.94 GB",
"support_discard": "512",
"vendor": null,
"virtual": 1
}
},
"ansible_distribution": "Archlinux",
"ansible_distribution_file_path": "/etc/arch-release",
"ansible_distribution_file_variety": "Archlinux",
"ansible_distribution_major_version": "24",
"ansible_distribution_release": "Wynsdey",
"ansible_distribution_version": "24.0.3",
"ansible_dns": {
"nameservers": [
"192.168.31.1"
],
"search": [
"toulouse.dawan.fr"
]
},
"ansible_docker0": {
"active": false,
"device": "docker0",
"id": "8000.0242ec8e49bf",
"interfaces": [],
"ipv4": {
"address": "172.17.0.1",
"broadcast": "172.17.255.255",
"netmask": "255.255.0.0",
"network": "172.17.0.0",
"prefix": "16"
},
"macaddress": "02:42:ec:8e:49:bf",
"mtu": 1500,
"promisc": false,
"speed": -1,
"stp": false,
"type": "bridge"
},
"ansible_domain": "",
"ansible_effective_group_id": 1000,
"ansible_effective_user_id": 1000,
"ansible_eno2": {
"active": true,
"device": "eno2",
"ipv4": {
"address": "192.168.31.36",
"broadcast": "192.168.31.255",
"netmask": "255.255.255.0",
"network": "192.168.31.0",
"prefix": "24"
},
"macaddress": "a4:bb:6d:ef:9d:84",
"module": "e1000e",
"mtu": 1500,
"pciid": "0000:00:1f.6",
"promisc": false,
"speed": 1000,
"type": "ether"
},
"ansible_env": {
"AUTOJUMP_ERROR_PATH": "/home/steve/.local/share/autojump/errors.log",
"AUTOJUMP_SOURCED": "1",
"DBUS_SESSION_BUS_ADDRESS": "unix:path=/run/user/1000/bus",
"DEBUGINFOD_URLS": "https://debuginfod.archlinux.org ",
"DESKTOP_SESSION": "gnome",
"DESKTOP_STARTUP_ID": "gnome-shell/PyCharm Professional Edition/4132-3-skdell_TIME4966895",
"DISPLAY": ":1",
"EDITOR": "/usr/bin/micro",
"GDMSESSION": "gnome",
"GDM_LANG": "fr_FR.UTF-8",
"GIO_LAUNCHED_DESKTOP_FILE": "/home/steve/.local/share/applications/jetbrains-pycharm.desktop",
"GIO_LAUNCHED_DESKTOP_FILE_PID": "111302",
"GJS_DEBUG_OUTPUT": "stderr",
"GJS_DEBUG_TOPICS": "JS ERROR;JS LOG",
"GNUPGHOME": "/home/steve/.local/share/gnupg",
"GTK3_MODULES": "xapp-gtk3-module",
"HOME": "/home/steve",
"INVOCATION_ID": "0dadf7989e324b038ebd153569baec41",
"IPYTHONDIR": "/home/steve/.local/share/ipython",
"JEDITERM_SOURCE_ARGS": "",
"JOURNAL_STREAM": "9:12207",
"LANG": "fr_FR.UTF-8",
"LOGNAME": "steve",
"MAIL": "/var/spool/mail/steve",
"MANAGERPID": "3884",
"MEMORY_PRESSURE_WATCH": "/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/session.slice/org.gnome.Shell@x11.service/memory.pressure",
"MEMORY_PRESSURE_WRITE": "c29tZSAyMDAwMDAgMjAwMDAwMAA=",
"MOTD_SHOWN": "pam",
"NODE_PATH": "/home/steve/.local/share/node",
"NODE_REPL_HISTORY": "/home/steve/.cache/node_history",
"OMF_CONFIG": "/home/steve/.config/omf",
"OMF_PATH": "/home/steve/.local/share/omf",
"PATH": "/home/steve/Code/python/environments/ansible/bin:/home/steve/.pyenv/shims:/home/steve/.local/bin:~/.pyenv/bin:/usr/local/bin:~/.pyenv/bin:/usr/bin:~/.pyenv/bin:/usr/local/sbin:~/.pyenv/bin:/var/lib/flatpak/exports/bin:~/.pyenv/bin:/usr/lib/jvm/default/bin:~/.pyenv/bin:/usr/bin/site_perl:~/.pyenv/bin:/usr/bin/vendor_perl:~/.pyenv/bin:/usr/bin/core_perl:~/.pyenv/bin",
"PWD": "/home/steve/Code/training/python/beginner/source/99-ansible-test",
"PYENV_SHELL": "fish",
"QT_AUTO_SCREEN_SCALE_FACTOR": "1",
"QT_IM_MODULE": "ibus",
"QT_STYLE_OVERRIDE": "qt6ct",
"SESSION_MANAGER": "local/skdell:@/tmp/.ICE-unix/4103,unix/skdell:/tmp/.ICE-unix/4103",
"SHELL": "/usr/bin/fish",
"SHLVL": "2",
"SSH_AUTH_SOCK": "/run/user/1000/gcr/ssh",
"SYSTEMD_EXEC_PID": "4132",
"TERM": "xterm-256color",
"TERMINAL_EMULATOR": "JetBrains-JediTerm",
"TERM_SESSION_ID": "017aefd1-69ab-4952-8dd0-0333292a71e6",
"USER": "steve",
"USERNAME": "steve",
"VIRTUAL_ENV": "/home/steve/Code/python/environments/ansible",
"VIRTUAL_ENV_DISABLE_PROMPT": "1",
"VIRTUAL_ENV_PROMPT": "ansible",
"VSCODE_EXTENSIONS": "/home/steve/.local/share/vscode/extensions",
"WINDOWPATH": "2",
"WINEPREFIX": "/home/steve/.local/share/wine",
"XAUTHORITY": "/run/user/1000/gdm/Xauthority",
"XDG_ACTIVATION_TOKEN": "gnome-shell/PyCharm Professional Edition/4132-3-skdell_TIME4966895",
"XDG_CURRENT_DESKTOP": "GNOME",
"XDG_DATA_DIRS": "/home/steve/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:/usr/local/share/:/usr/share/",
"XDG_MENU_PREFIX": "gnome-",
"XDG_RUNTIME_DIR": "/run/user/1000",
"XDG_SESSION_CLASS": "user",
"XDG_SESSION_DESKTOP": "gnome",
"XDG_SESSION_TYPE": "x11",
"XMODIFIERS": "@im=ibus",
"_": "/home/steve/Code/python/environments/ansible/bin/python",
"_OLD_VIRTUAL_PATH": "/home/steve/.pyenv/shims:/home/steve/.local/bin:~/.pyenv/bin:/usr/local/bin:~/.pyenv/bin:/usr/bin:~/.pyenv/bin:/usr/local/sbin:~/.pyenv/bin:/var/lib/flatpak/exports/bin:~/.pyenv/bin:/usr/lib/jvm/default/bin:~/.pyenv/bin:/usr/bin/site_perl:~/.pyenv/bin:/usr/bin/vendor_perl:~/.pyenv/bin:/usr/bin/core_perl:~/.pyenv/bin"
},
"ansible_fibre_channel_wwn": [],
"ansible_fips": false,
"ansible_form_factor": "Notebook",
"ansible_fqdn": "skdell",
"ansible_hostname": "skdell",
"ansible_hostnqn": "",
"ansible_interfaces": [
"lo",
"eno2",
"docker0",
"wlo1"
],
"ansible_is_chroot": false,
"ansible_iscsi_iqn": "",
"ansible_kernel": "6.9.8-1-MANJARO",
"ansible_kernel_version": "#1 SMP PREEMPT_DYNAMIC Sat Jul 6 05:51:22 UTC 2024",
"ansible_lo": {
"active": true,
"device": "lo",
"ipv4": {
"address": "127.0.0.1",
"broadcast": "",
"netmask": "255.0.0.0",
"network": "127.0.0.0",
"prefix": "8"
},
"ipv6": [
{
"address": "::1",
"prefix": "128",
"scope": "host"
}
],
"mtu": 65536,
"promisc": false,
"type": "loopback"
},
"ansible_loadavg": {
"15m": 2.26904296875,
"1m": 2.1435546875,
"5m": 2.521484375
},
"ansible_local": {},
"ansible_locally_reachable_ips": {
"ipv4": [
"127.0.0.0/8",
"127.0.0.1",
"172.17.0.1",
"192.168.31.36",
"192.168.31.165"
],
"ipv6": [
"::1",
"fe80::9fb5:601b:d3e9:a68e"
]
},
"ansible_lsb": {
"codename": "Wynsdey",
"description": "Manjaro Linux",
"id": "ManjaroLinux",
"major_release": "24",
"release": "24.0.3"
},
"ansible_lvm": "N/A",
"ansible_machine": "x86_64",
"ansible_machine_id": "a1c1d092794f4871a548c9775dd5337c",
"ansible_memfree_mb": 389,
"ansible_memory_mb": {
"nocache": {
"free": 11746,
"used": 20055
},
"real": {
"free": 389,
"total": 31801,
"used": 31412
},
"swap": {
"cached": 0,
"free": 9010,
"total": 9011,
"used": 1
}
},
"ansible_memtotal_mb": 31801,
"ansible_mounts": [
{
"block_available": 42256932,
"block_size": 4096,
"block_total": 120436125,
"block_used": 78179193,
"device": "/dev/nvme0n1p2",
"dump": 0,
"fstype": "ext4",
"inode_available": 28418923,
"inode_total": 30662656,
"inode_used": 2243733,
"mount": "/",
"options": "rw,noatime",
"passno": 0,
"size_available": 173084393472,
"size_total": 493306368000,
"uuid": "ae7bbe2b-e356-4f63-bdf6-a6a3463bf1a8"
},
{
"block_available": 57918,
"block_size": 4096,
"block_total": 76646,
"block_used": 18728,
"device": "/dev/nvme0n1p1",
"dump": 0,
"fstype": "vfat",
"inode_available": 0,
"inode_total": 0,
"inode_used": 0,
"mount": "/boot/efi",
"options": "rw,relatime,fmask=0077,dmask=0077,codepage=437,iocharset=ascii,shortname=mixed,utf8,errors=remount-ro",
"passno": 0,
"size_available": 237232128,
"size_total": 313942016,
"uuid": "7D05-E937"
},
{
"block_available": 1964168,
"block_size": 32768,
"block_total": 1965055,
"block_used": 887,
"device": "/dev/mmcblk0p1",
"dump": 0,
"fstype": "vfat",
"inode_available": 0,
"inode_total": 0,
"inode_used": 0,
"mount": "/run/media/steve/CLEANED",
"options": "rw,nosuid,nodev,relatime,uid=1000,gid=1000,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,showexec,utf8,flush,errors=remount-ro",
"passno": 0,
"size_available": 64361857024,
"size_total": 64390922240,
"uuid": "588B-5CCE"
}
],
"ansible_nodename": "skdell",
"ansible_os_family": "Archlinux",
"ansible_pkg_mgr": "pacman",
"ansible_proc_cmdline": {
"BOOT_IMAGE": "/boot/vmlinuz-6.9-x86_64",
"apparmor": "0",
"fsck.mode": "skip",
"intel_pstate": "active",
"loglevel": "3",
"nvidia-drm.modeset": "1",
"quiet": true,
"ro": true,
"root": "UUID=ae7bbe2b-e356-4f63-bdf6-a6a3463bf1a8",
"splash": true,
"udev.log_level": "3",
"udev.log_priority": "1",
"vga": "current"
},
"ansible_processor": [
"0",
"GenuineIntel",
"Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz",
"1",
"GenuineIntel",
"Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz",
"2",
"GenuineIntel",
"Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz",
"3",
"GenuineIntel",
"Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz",
"4",
"GenuineIntel",
"Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz",
"5",
"GenuineIntel",
"Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz",
"6",
"GenuineIntel",
"Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz",
"7",
"GenuineIntel",
"Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz",
"8",
"GenuineIntel",
"Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz",
"9",
"GenuineIntel",
"Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz",
"10",
"GenuineIntel",
"Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz",
"11",
"GenuineIntel",
"Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz"
],
"ansible_processor_cores": 6,
"ansible_processor_count": 1,
"ansible_processor_nproc": 12,
"ansible_processor_threads_per_core": 2,
"ansible_processor_vcpus": 12,
"ansible_product_name": "Precision 7750",
"ansible_product_serial": "NA",
"ansible_product_uuid": "NA",
"ansible_product_version": "NA",
"ansible_python": {
"executable": "/home/steve/Code/python/environments/ansible/bin/python",
"has_sslcontext": true,
"type": "cpython",
"version": {
"major": 3,
"micro": 4,
"minor": 12,
"releaselevel": "final",
"serial": 0
},
"version_info": [
3,
12,
4,
"final",
0
]
},
"ansible_python_version": "3.12.4",
"ansible_real_group_id": 1000,
"ansible_real_user_id": 1000,
"ansible_selinux": {
"status": "Missing selinux Python library"
},
"ansible_selinux_python_present": false,
"ansible_service_mgr": "systemd",
"ansible_ssh_host_key_dsa_public": "AAAAB3NzaC1kc3MAAACBAOLJ7UDNOsYU1QL6qk+fSxD8fZDG0miFVd1qcYusCRxCPJwEi7ClIcrTosPusubxC3Vvo7FtYqRpCjwmZaSiI+K+BmhkSK7LKN63XsHSAW+pK5Q5gnmARBrzTCF1pDm3uh/AYS0SISMbgc4+I7EXBKOJ94RQg1FliBpiNiv17zg5AAAAFQDU0YgWYQ55gfCr7ZehXDtm0axs4QAAAIEAlAfHG9dyqSmhAwS1s3mSFLTuG2MU8DruNCzX0dub7ObW8iQS4+FDahSdxCMY+PWwZEJ27SgAzWd5wCpAKFoFgoiOVeVCiRt7QyIkQHR4ENDRxEpzUEBvLLp31vQGwLf9mzHRSWxqfKX7h/ZoRpJpj4LTFcfvI0l1P82aszA11uMAAACAQZMqDsYbX2plxDw9ysbcyqP1hCh8WBwJik2wY/LCiV78JjljlVlkoat1HR1dJOQ+qKxA+EI6wEBhsrB9+waUVwdAJ4Aj1yQZnPUbDnFi+MwtAz0V9M6eNKi6SoxyBpaPPewKk24PF0igsyHPR+P+diQHO+momtiWK1SEO+bcnyQ=",
"ansible_ssh_host_key_dsa_public_keytype": "ssh-dss",
"ansible_ssh_host_key_ecdsa_public": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHHzABDnum37ZKXtsmf1FJlIxkdCkj31DnFMlyM34MT52YUqstoXA6+AjbWQZ4q5nDP961ubepBjSXQIk4sNCkA=",
"ansible_ssh_host_key_ecdsa_public_keytype": "ecdsa-sha2-nistp256",
"ansible_ssh_host_key_ed25519_public": "AAAAC3NzaC1lZDI1NTE5AAAAIM54ly57FFU5JCOPN+G57sTJ4VfJuptq235TAfsFIy6v",
"ansible_ssh_host_key_ed25519_public_keytype": "ssh-ed25519",
"ansible_ssh_host_key_rsa_public": "AAAAB3NzaC1yc2EAAAADAQABAAABgQDsgT8vRhNuBEmevRRUgsrtJfDXyqvaiShBn4UFUUv/2SS1qcme0UIEoBklQlbIAyUACa3+ZxAw08YXt9UuG/Sd/ykUfXtzsrDMKxQlb1VLFaXLpJ3wQYIbJi3gA3lrXfae+sKPOFl0c2+iuXF8B+zwKednu7qtHZbGsWxL3bRkmoQ1nBYcZwLU/s1EFU3/xRVAoo39aLYN3cB1RT7e2eWgPSB0Kv4emeGZHLjB3DNv36K8rwi8yYAXpiawbhxar5asiJ6S6/AchMofcbUo0wGX+/ArLTAysCu/rlUyA5+mh0hMFvqMc8mDHfg/elHf5K8PpphPKCixGpo5GfAzgeV7OjQOTibI2mKB6RAEYBK7/whNzcM0P2kt0xK2U84g3ppNdlOpqC1c3oOwiHxaHP2/BRkO2vntabcpLRjjWhm6hqMrBPgtRS67fChkrsW6hyQtuS9FGpyCDJpqsPhezve8KNy1A+OHwf4tPZTGflIMNnybYEe2B74Mdhn0aRWFP80=",
"ansible_ssh_host_key_rsa_public_keytype": "ssh-rsa",
"ansible_swapfree_mb": 9010,
"ansible_swaptotal_mb": 9011,
"ansible_system": "Linux",
"ansible_system_capabilities": [
""
],
"ansible_system_capabilities_enforced": "True",
"ansible_system_vendor": "Dell Inc.",
"ansible_uptime_seconds": 29357,
"ansible_user_dir": "/home/steve",
"ansible_user_gecos": "Steve Kossouho",
"ansible_user_gid": 1000,
"ansible_user_id": "steve",
"ansible_user_shell": "/usr/bin/fish",
"ansible_user_uid": 1000,
"ansible_userspace_architecture": "x86_64",
"ansible_userspace_bits": "64",
"ansible_virtualization_role": "host",
"ansible_virtualization_tech_guest": [],
"ansible_virtualization_tech_host": [
"kvm",
"virtualbox"
],
"ansible_virtualization_type": "kvm",
"ansible_wlo1": {
"active": true,
"device": "wlo1",
"ipv4": {
"address": "192.168.31.165",
"broadcast": "192.168.31.255",
"netmask": "255.255.255.0",
"network": "192.168.31.0",
"prefix": "24"
},
"ipv6": [
{
"address": "fe80::9fb5:601b:d3e9:a68e",
"prefix": "64",
"scope": "link"
}
],
"macaddress": "94:e7:0b:b6:cc:81",
"module": "iwlwifi",
"mtu": 1500,
"pciid": "0000:00:14.3",
"promisc": false,
"type": "ether"
},
"gather_subset": [
"all"
],
"module_setup": true
},
"changed": false
}

2
source/TODO.txt Normal file
View File

@ -0,0 +1,2 @@
08 csv
09 sqlite mettre à jour l'exemple

View File

@ -0,0 +1,44 @@
"""
Fausse bataille avec les mauvaises règles.
Ce n'est absolument pas comme ça qu'on joue à la bataille en
temps normal, mais je n'y avais pas joué depuis 30 ans.
Ceci étant, avec des règles simples, on arrive à un truc...exécutable.
"""
from source.cardgame.cards import Deck, Card
def main():
full_deck: Deck = Deck(full=True, shuffled=True)
player1_deck: Deck = Deck()
player2_deck: Deck = Deck()
player1_score: int = 0 # dégueulasse
player2_score: int = 0
# Choice was to distribute cards from one deck to player hands.
# Could be any strategy (and could be better).
while full_deck:
full_deck.pop_to(player1_deck)
full_deck.pop_to(player2_deck)
while player1_deck:
# Show available cards to pick
selected_index: int = player1_deck.pick_input()
selected_card: Card = player1_deck.pop(selected_index)
opponent_card: Card = player2_deck.pop(0)
print(f"Player 1 plays {selected_card.full_name}")
print(f"Player 2 plays {opponent_card.full_name}")
if selected_card < opponent_card:
player2_score += 1
print("Computer wins this round.")
elif selected_card > opponent_card:
player1_score += 1
print("You won this round.")
print(f"Player 1 final score: {player1_score}")
print(f"Player 2 final score: {player2_score}")
if player1_score == player2_score:
print("Pathetic!")
if __name__ == '__main__':
main()

127
source/cardgame/cards.py Normal file
View File

@ -0,0 +1,127 @@
from __future__ import annotations
from random import shuffle
from typing import Literal
import inquirer
class Card:
"""
Standard poker card.
Attributes:
value:
Absolute card value, between 2 and 14 (for the ace).
symbol (int):
Symbol of the card, as an integer.
0 is hearts; 1 is diamonds, 2 is clubs and 3 is spades.
"""
SYMBOLS: dict[int, str] = {0: "Hearts", 1: "Diamonds", 2: "Clubs", 3: "Spades"}
VALUES: dict[int, str] = {11: "Jack", 12: "Queen", 13: "King", 14: "Ace"}
value: int = 2
symbol: Literal[0, 1, 2, 3] = 0
def __init__(self, value: int, symbol: Literal[0, 1, 2, 3]):
self.symbol = symbol
self.value = value
def __lt__(self, other: Card):
if isinstance(other, Card):
return self.value < other.value
raise TypeError(f"Can't compare {type(other)}")
def __eq__(self, other: Card):
if isinstance(other, Card):
return self.value < other.value
raise TypeError(f"Can't compare {type(other)}")
def __str__(self):
return f"{self.name} de {self.symbol_name}"
@property
def name(self):
"""Get the name of this card."""
return self.VALUES.get(self.value, str(self.value))
@property
def symbol_name(self):
"""Get the name of the symbol of this card."""
return self.SYMBOLS.get(self.symbol, "N/A")
@property
def full_name(self) -> str:
"""Get the full name of this card, value and symbol."""
return f"{self.name} of {self.symbol_name}"
class Deck:
"""A deck of cards."""
_cards: list[Card] = None
def __init__(self, full: bool = False, shuffled: bool = False):
"""
Initialize a deck with cards.
Args:
full: If True, fill with all possible cards.
shuffled: If True, shuffle the content of the deck directly.
"""
self._cards = []
if full is True:
for value in range(2, 15):
for symbol in range(0, 4):
self._cards.append(Card(value, symbol)) # noqa
if shuffled is True:
self.shuffle()
def __bool__(self) -> bool:
"""
Tell if the deck is empty or not.
Returns:
True: if not empty
False: otherwise.
"""
return bool(self._cards)
def shuffle(self):
"""Shuffle the deck so the cards are not ordered by value."""
shuffle(self._cards)
def pop_to(self, other: Deck) -> None:
"""Remove last card from deck and add to another deck."""
other._cards.append(self._cards.pop())
def pop(self, index: int) -> Card:
"""Get card at index in deck and remove from the deck."""
return self._cards.pop(index)
def display_cards(self) -> None:
"""Show available cards with their respective index in the deck."""
for index, card in enumerate(self._cards):
print(f"{index:02}: {card.full_name}", end=" / ")
print()
def pick_input(self) -> int:
"""
Ask the user to pick a card from the deck.
Returns:
The selected index for a card.
"""
q = [inquirer.List("selection", message="Pick a card", choices=self.card_selection, default=0)]
return inquirer.prompt(q)["selection"]
@property
def card_selection(self) -> list[tuple[str, int]]:
"""
Get available cards with their respective index in the deck.
Returns:
A list of tuples, where each tuple contains two elements:
- The first element being the card name
- The second element being the card index
"""
return [(c.full_name, index) for index, c in enumerate(self._cards)]

4
source/requirements.txt Normal file
View File

@ -0,0 +1,4 @@
py2puml # conversion Python vers PlantUML
pdir2 # pretty printing avancé
ipython # console Python avancée
pyside6 # Qt Framework