more comment in all modules (except GUI)
This commit is contained in:
parent
88e89209ac
commit
f6f2e1ed52
32 changed files with 142 additions and 98 deletions
5
NOTE.md
5
NOTE.md
|
@ -1,8 +1,5 @@
|
|||
A faire :
|
||||
|
||||
|
||||
1. Principal :
|
||||
- Documenter (Docstring, README, ...)
|
||||
- Documenter (Docstring, ...)
|
||||
- mode d'emploi (video + pdf) expliquant le fonctionnement
|
||||
|
||||
2. Bonus :
|
||||
|
|
7
main.pyw
7
main.pyw
|
@ -6,13 +6,13 @@ from source.gui.scene import MainMenu
|
|||
from source.gui.window import GameWindow
|
||||
|
||||
|
||||
from source.path import path_font
|
||||
from source.path import path_font, path_image
|
||||
from source.gui.better_pyglet import Label
|
||||
|
||||
|
||||
# Change la police par défaut utilisé pour le Century Gothic
|
||||
pyglet.font.add_directory(path_font)
|
||||
Label.default_kwargs["font_name"] = "Century Gothic" # NOQA: Label à un "default_kwargs" avec la metaclass
|
||||
Label.default_kwargs["font_name"] = "Century Gothic"
|
||||
|
||||
# Créer une nouvelle fenêtre
|
||||
window = GameWindow(
|
||||
|
@ -21,7 +21,8 @@ window = GameWindow(
|
|||
option_path=Path("./option.json")
|
||||
)
|
||||
|
||||
try: window.set_icon(pyglet.image.load("./assets/image/icon/icon.png"))
|
||||
# Change l'icône de cette fenêtre
|
||||
try: window.set_icon(pyglet.image.load(path_image / "/icon/icon.png"))
|
||||
except: pass # NOQA E722
|
||||
|
||||
window.set_minimum_size(720, 480)
|
||||
|
|
6
setup.py
6
setup.py
|
@ -1,5 +1,7 @@
|
|||
from cx_Freeze import setup, Executable
|
||||
|
||||
from source.path import path_image, path_assets
|
||||
|
||||
setup(
|
||||
name='Bataille Navale',
|
||||
description='Bataille Navale',
|
||||
|
@ -8,7 +10,7 @@ setup(
|
|||
|
||||
options={
|
||||
"build_exe": {
|
||||
"include_files": ["./assets"],
|
||||
"include_files": [path_assets],
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -17,7 +19,7 @@ setup(
|
|||
executables=[
|
||||
Executable(
|
||||
"main.pyw",
|
||||
icon="./assets/image/icon/icon.ico",
|
||||
icon=path_image / "/icon/icon.ico",
|
||||
base="win32gui",
|
||||
target_name="Bataille Navale.exe",
|
||||
shortcut_name="Bataille Navale",
|
||||
|
|
|
@ -3,35 +3,36 @@ from typing import Callable
|
|||
|
||||
class Listener:
|
||||
"""
|
||||
The Listener can be subclassed to allow the subclass to add, remove and call event easily.
|
||||
Les classes héritant de Listener permettent d'ajouter, retirer et appeler facilement des événements.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
# dictionnaire des événements et de leurs fonctions associées
|
||||
self._events_listener: dict[str, set[Callable]] = {}
|
||||
|
||||
def add_listener(self, name: str, callback: Callable):
|
||||
"""
|
||||
Add a function to an event name
|
||||
:param name: the name of the event to react
|
||||
:param callback: the function to call
|
||||
Ajoute une fonction à un événement
|
||||
:param name: le nom de l'événement
|
||||
:param callback: la fonction à appeler
|
||||
"""
|
||||
if name not in self._events_listener: self._events_listener[name] = set()
|
||||
self._events_listener[name].add(callback)
|
||||
|
||||
def remove_listener(self, name: str, callback: Callable):
|
||||
"""
|
||||
Remove a function from an event name
|
||||
:param name: the event name where to remove the callback
|
||||
:param callback: the callback function to remove
|
||||
Retire une fonction d'un événement
|
||||
:param name: le nom de l'événement
|
||||
:param callback: la fonction à retirer
|
||||
"""
|
||||
self._events_listener[name].remove(callback)
|
||||
|
||||
def trigger_event(self, name: str, *args, **kwargs):
|
||||
"""
|
||||
Call all the callback attached to an event
|
||||
:param name: the name of the event to call
|
||||
:param args: the args of the callbacks
|
||||
:param kwargs: the kwargs of the callbacks
|
||||
Appelle les fonctions associées à un événement
|
||||
:param name: le nom de l'événement
|
||||
:param args: les arguments des fonctions
|
||||
:param kwargs: les arguments à clé des fonctions
|
||||
"""
|
||||
|
||||
# .copy() pour que si le listener supprime un de ses événements, la liste de la boucle de change pas de taille
|
||||
|
|
|
@ -3,5 +3,7 @@ from typing import Any
|
|||
|
||||
|
||||
class Element(ABC):
|
||||
default_kwargs: dict[str, Any]
|
||||
|
||||
def __init_subclass__(cls, **kwargs):
|
||||
cls.default_kwargs: dict[str, Any] = {} # all subclasses will have their own "default_kwargs" dict
|
||||
cls.default_kwargs = {} # all subclasses will have their own "default_kwargs" dict
|
||||
|
|
|
@ -16,7 +16,7 @@ if TYPE_CHECKING:
|
|||
|
||||
class Client(StoppableThread):
|
||||
"""
|
||||
The thread executed on the person who join a room.
|
||||
Ce thread est utilisé pour la personne qui rejoint la salle.
|
||||
"""
|
||||
|
||||
def __init__(self, window: "Window",
|
||||
|
@ -39,9 +39,10 @@ class Client(StoppableThread):
|
|||
try:
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as connection:
|
||||
try:
|
||||
# Se connecte à l'opposant
|
||||
connection.connect((self.ip_address, self.port))
|
||||
except ConnectionRefusedError:
|
||||
# Appelle l'événement lorsque la connexion échoue
|
||||
# Appelle la fonction prévue lorsque la connexion échoue
|
||||
if self.on_connexion_refused is not None:
|
||||
in_pyglet_context(self.on_connexion_refused)
|
||||
return
|
||||
|
@ -91,13 +92,14 @@ class Client(StoppableThread):
|
|||
with open(path_old_save, "r", encoding="utf-8") as file:
|
||||
save_data = json.load(file)
|
||||
|
||||
# paramètres & jeu
|
||||
# paramètres et jeu
|
||||
|
||||
settings = PacketSettings.from_connection(connection)
|
||||
PacketUsername(username=self.username).send_data_connection(connection)
|
||||
enemy_username = PacketUsername.from_connection(connection).username
|
||||
|
||||
if load_old_save:
|
||||
# si les joueurs utilise une ancienne sauvegarde, créer la scène du jeu à partir des données
|
||||
game_scene = in_pyglet_context(
|
||||
self.window.set_scene,
|
||||
scene.Game.from_json, # depuis le fichier json
|
||||
|
@ -109,6 +111,7 @@ class Client(StoppableThread):
|
|||
)
|
||||
|
||||
else:
|
||||
# s'il n'y a pas de sauvegarde à utiliser, initialise une nouvelle scène
|
||||
game_scene = in_pyglet_context(
|
||||
self.window.set_scene,
|
||||
scene.Game,
|
||||
|
@ -124,6 +127,7 @@ class Client(StoppableThread):
|
|||
my_turn=not settings.host_start
|
||||
)
|
||||
|
||||
# commence la partie réseau du jeu
|
||||
game_network(
|
||||
thread=self,
|
||||
connection=connection,
|
||||
|
|
|
@ -18,7 +18,7 @@ if TYPE_CHECKING:
|
|||
|
||||
class Host(StoppableThread):
|
||||
"""
|
||||
The thread executed on the person who create a room.
|
||||
Le thread utilisé lorsqu'un joueur créer une salle
|
||||
"""
|
||||
|
||||
def __init__(self, window: "Window", port: int, username: str, settings: "PacketSettings", **kw):
|
||||
|
@ -29,6 +29,7 @@ class Host(StoppableThread):
|
|||
self.settings = settings
|
||||
self.port = port
|
||||
|
||||
# condition utilisée lorsque l'on attend la décision de charger une partie ou non
|
||||
self.condition_load = Condition()
|
||||
self.accept_load: bool = False
|
||||
|
||||
|
@ -54,7 +55,7 @@ class Host(StoppableThread):
|
|||
|
||||
path_old_save: Optional[Path] = None
|
||||
|
||||
for file in path_save.iterdir(): # cherche une ancienne sauvegarde correspondant à l'ip de l'adversaire
|
||||
for file in path_save.iterdir(): # cherche une ancienne sauvegarde correspondant à l'IP de l'adversaire
|
||||
if file.stem.startswith(ip_address):
|
||||
path_old_save = file
|
||||
break
|
||||
|
@ -72,7 +73,8 @@ class Host(StoppableThread):
|
|||
from source.gui.scene import GameLoad
|
||||
in_pyglet_context(self.window.set_scene, GameLoad, path=path_old_save, thread_host=self)
|
||||
|
||||
with self.condition_load: self.condition_load.wait() # attend que l'utilisateur choisisse l'option
|
||||
# attend que l'utilisateur choisisse l'option
|
||||
with self.condition_load: self.condition_load.wait()
|
||||
|
||||
PacketLoadOldSave(value=self.accept_load).send_data_connection(connection)
|
||||
|
||||
|
@ -89,6 +91,7 @@ class Host(StoppableThread):
|
|||
PacketUsername(username=self.username).send_data_connection(connection)
|
||||
|
||||
if self.accept_load:
|
||||
# si une sauvegarde doit être chargée
|
||||
game_scene = in_pyglet_context(
|
||||
self.window.set_scene,
|
||||
scene.Game.from_json, # depuis le fichier json
|
||||
|
@ -100,6 +103,7 @@ class Host(StoppableThread):
|
|||
)
|
||||
|
||||
else:
|
||||
# s'il n'y a pas de sauvegarde à charger
|
||||
game_scene = in_pyglet_context(
|
||||
self.window.set_scene,
|
||||
scene.Game,
|
||||
|
@ -115,6 +119,7 @@ class Host(StoppableThread):
|
|||
my_turn=self.settings.host_start
|
||||
)
|
||||
|
||||
# commence la partie réseau du jeu
|
||||
game_network(
|
||||
thread=self,
|
||||
connection=connection,
|
||||
|
|
|
@ -9,8 +9,15 @@ if TYPE_CHECKING:
|
|||
|
||||
|
||||
def handle_error(window: "Window", exception: Exception):
|
||||
"""
|
||||
Fonction permettant d'afficher le bon message d'erreur du au réseau.
|
||||
:param window: la fenêtre du jeu
|
||||
:param exception: l'erreur qui s'est produite
|
||||
"""
|
||||
|
||||
message: str = "Erreur :\n"
|
||||
|
||||
# récupère le message d'erreur selon le type de l'erreur
|
||||
match type(exception):
|
||||
case builtins.ConnectionResetError:
|
||||
message += "Perte de connexion avec l'adversaire."
|
||||
|
|
|
@ -18,12 +18,13 @@ def game_network(
|
|||
game_scene: "Game",
|
||||
):
|
||||
"""
|
||||
Run the networking to make the game work and react with the other player
|
||||
:param game_scene: the scene of the game
|
||||
:param thread: the thread where this function is called.
|
||||
:param connection: the connection with the other player
|
||||
Partie réseau permettant au jeu de fonctionner et de réagir avec l'autre joueur
|
||||
:param game_scene: la scène du jeu
|
||||
:param thread: le thread dans lequel la fonction est appelé
|
||||
:param connection: la connexion avec l'autre joueur
|
||||
"""
|
||||
|
||||
# associe le type de packet avec la fonction correspondante
|
||||
game_methods: dict[Type["Packet"], Callable] = {
|
||||
packet.PacketChat: game_scene.network_on_chat,
|
||||
packet.PacketBoatPlaced: game_scene.network_on_boat_placed,
|
||||
|
@ -35,16 +36,19 @@ def game_network(
|
|||
}
|
||||
|
||||
while True:
|
||||
# récupère le type de packet reçu
|
||||
data_type = Packet.type_from_connection(connection)
|
||||
|
||||
if data_type is None:
|
||||
if thread.stopped: return # vérifie si le thread n'est pas censé s'arrêter
|
||||
# s'il n'y a pas de donnée reçue, vérifie si le thread devrait s'arrêter, sinon ignore
|
||||
if thread.stopped: return
|
||||
continue
|
||||
|
||||
# récupère les données du packet
|
||||
data = data_type.from_connection(connection)
|
||||
|
||||
in_pyglet_context(
|
||||
game_methods[data_type], data # récupère la methode relié ce type de donnée
|
||||
game_methods[data_type], data # récupère la methode relié à ce type de donnée
|
||||
) # Appelle la méthode.
|
||||
|
||||
if thread.stopped: return # vérifie si le thread n'est pas censé s'arrêter
|
||||
|
|
|
@ -6,5 +6,5 @@ from source.network.packet.abc import SignalPacket
|
|||
@dataclass
|
||||
class PacketAskSave(SignalPacket):
|
||||
"""
|
||||
A packet that is sent when the player wish to save the game.
|
||||
Un packet envoyé quand le joueur souhaite sauvegarder
|
||||
"""
|
||||
|
|
|
@ -6,5 +6,5 @@ from source.network.packet.abc import SignalPacket
|
|||
@dataclass
|
||||
class PacketBoatPlaced(SignalPacket):
|
||||
"""
|
||||
A packet that signal that all the boat of the player have been placed
|
||||
Un packet signalant que tous les bateaux du joueur ont été placé
|
||||
"""
|
||||
|
|
|
@ -9,6 +9,9 @@ from source.network.packet.abc import Packet
|
|||
|
||||
@dataclass
|
||||
class PacketBoatsData(Packet):
|
||||
"""
|
||||
Un packet contenant les données de la position de tous les bateaux
|
||||
"""
|
||||
|
||||
boats: np.array = field()
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ from source.type import Point2D
|
|||
@dataclass
|
||||
class PacketBombPlaced(SimplePacket):
|
||||
"""
|
||||
A packet that signal that a bomb have been placed on the board
|
||||
Un packet qui signale qu'une bombe à été placé sur la grille
|
||||
"""
|
||||
|
||||
position: Point2D = field()
|
||||
|
|
|
@ -9,7 +9,7 @@ from source.type import Point2D
|
|||
@dataclass
|
||||
class PacketBombState(SimplePacket):
|
||||
"""
|
||||
A packet that signal how a bomb exploded on the board
|
||||
Un packet qui signale qu'une bombe à explosé sur la grille
|
||||
"""
|
||||
|
||||
position: Point2D = field()
|
||||
|
|
|
@ -6,7 +6,7 @@ from source.network.packet.abc import VariableLengthPacket
|
|||
@dataclass
|
||||
class PacketChat(VariableLengthPacket):
|
||||
"""
|
||||
A packet that represent a message from the chat
|
||||
Un packet qui représente un message du chat
|
||||
"""
|
||||
|
||||
message: str = field()
|
||||
|
|
|
@ -7,7 +7,7 @@ from source.network.packet.abc import SimplePacket
|
|||
@dataclass
|
||||
class PacketHaveSaveBeenFound(SimplePacket):
|
||||
"""
|
||||
A packet that is sent when the player accept or refuse a requested save.
|
||||
Un packet indiquant si le joueur à trouvé un ancien fichier de sauvegarde avec l'opposant
|
||||
"""
|
||||
|
||||
value: bool = field() # True si requête accepter, sinon False
|
||||
|
|
|
@ -7,7 +7,7 @@ from source.network.packet.abc import SimplePacket
|
|||
@dataclass
|
||||
class PacketLoadOldSave(SimplePacket):
|
||||
"""
|
||||
A packet that is sent when the player accept or refuse a requested save.
|
||||
Un packet qui est envoyé lorsque l'hôte accepte ou refuse de charger une ancienne sauvegarde
|
||||
"""
|
||||
|
||||
value: bool = field() # True si requête accepter, sinon False
|
||||
|
|
|
@ -6,5 +6,5 @@ from source.network.packet.abc import SignalPacket
|
|||
@dataclass
|
||||
class PacketQuit(SignalPacket):
|
||||
"""
|
||||
A packet that is sent when the player wish to quit a game.
|
||||
Un packet envoyé lorsque le joueur souhaite quitter la partie
|
||||
"""
|
||||
|
|
|
@ -7,7 +7,7 @@ from source.network.packet.abc import SimplePacket
|
|||
@dataclass
|
||||
class PacketResponseSave(SimplePacket):
|
||||
"""
|
||||
A packet that is sent when the player accept or refuse a requested save.
|
||||
Un packet qui est envoyé lorsque le joueur accepte ou refuse une demande de sauvegarde
|
||||
"""
|
||||
|
||||
value: bool = field() # True si requête accepter, sinon False
|
||||
|
|
|
@ -7,6 +7,10 @@ from source.network.packet.abc import Packet
|
|||
|
||||
@dataclass
|
||||
class PacketSettings(Packet):
|
||||
"""
|
||||
Un packet contenant tous les paramètres de la partie
|
||||
"""
|
||||
|
||||
grid_width: int = field()
|
||||
grid_height: int = field()
|
||||
host_start: bool = field()
|
||||
|
|
|
@ -5,6 +5,10 @@ from source.network.packet.abc import VariableLengthPacket
|
|||
|
||||
@dataclass
|
||||
class PacketUsername(VariableLengthPacket):
|
||||
"""
|
||||
Un packet contenant le nom d'utilisateur de l'opposant
|
||||
"""
|
||||
|
||||
username: str = field()
|
||||
|
||||
@property
|
||||
|
|
|
@ -9,10 +9,8 @@ T = TypeVar("T", bound="Packet")
|
|||
|
||||
class Packet(ABC):
|
||||
"""
|
||||
A packet that can be sent on a socket.
|
||||
Multiple subtype of packet can be sent and received in an easier way.
|
||||
|
||||
The to_bytes and from_connection method need to be defined.
|
||||
Un packet pouvant être envoyé dans un socket.
|
||||
Permet aux sous-classes de ce packet d'être envoyé et reçu d'une manière beaucoup plus simple.
|
||||
"""
|
||||
|
||||
packet_types: set[T] = set()
|
||||
|
|
|
@ -10,8 +10,8 @@ T = TypeVar("T", bound="SignalPacket")
|
|||
|
||||
class SignalPacket(Packet, ABC):
|
||||
"""
|
||||
A packet that has for only usage to send a signal thanks to the type of the class.
|
||||
It does not hold any other data.
|
||||
Un packet ne contenant aucune donnée.
|
||||
Permet de réagir à des événements seulement avec le type de la classe.
|
||||
"""
|
||||
|
||||
def to_bytes(self) -> bytes:
|
||||
|
|
|
@ -11,8 +11,8 @@ T = TypeVar("T", bound="SimplePacket")
|
|||
|
||||
class SimplePacket(Packet, ABC):
|
||||
"""
|
||||
A packet with a simple packet format.
|
||||
Only the from_bytes and to_bytes method need to be implemented.
|
||||
Un packet avec un format plus simple.
|
||||
Se base sur le "packet_format" pour envoyé et reservoir les données.
|
||||
"""
|
||||
|
||||
packet_format: str = ">"
|
||||
|
@ -21,9 +21,9 @@ class SimplePacket(Packet, ABC):
|
|||
@abstractmethod
|
||||
def from_bytes(cls, data: bytes) -> T:
|
||||
"""
|
||||
Convert a bytes object into a packet.
|
||||
:param data: the data to convert into a packet. Should be "packet_size" long.
|
||||
:return: a packet corresponding to the bytes.
|
||||
Convertie un objet bytes en un SimplePacket
|
||||
:param data: les données à charger, doit être "packet_size" de long
|
||||
:return: un SimplePacket correspondant à ces données
|
||||
"""
|
||||
pass
|
||||
|
||||
|
|
|
@ -11,8 +11,7 @@ T = TypeVar("T", bound="VariableLengthPacket")
|
|||
|
||||
class VariableLengthPacket(Packet, ABC):
|
||||
"""
|
||||
A Packet that represent a single value that can be encoded with a variable length.
|
||||
The property "data" and the method "from_bytes" need to be defined.
|
||||
Un packet représentant une seule valeur avec une longueur variable qui peut être encodé, comme une chaîne.
|
||||
"""
|
||||
|
||||
packet_format: str = ">I"
|
||||
|
@ -20,6 +19,11 @@ class VariableLengthPacket(Packet, ABC):
|
|||
@property
|
||||
@abstractmethod
|
||||
def data(self) -> bytes:
|
||||
"""
|
||||
Donnée à envoyer sur le réseau
|
||||
:return: la donnée sous la forme d'un objet bytes
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
def to_bytes(self) -> bytes:
|
||||
|
|
|
@ -9,6 +9,10 @@ if TYPE_CHECKING:
|
|||
|
||||
|
||||
class Option:
|
||||
"""
|
||||
Cette classe permet de modifier, sauvegarder et charger les options.
|
||||
"""
|
||||
|
||||
def __init__(self, window: "GameWindow",
|
||||
volume_ambient: float = 0.1,
|
||||
volume_fx: float = 0.1,
|
||||
|
@ -24,7 +28,7 @@ class Option:
|
|||
self.set_fps_limit(fps_limit)
|
||||
self.set_vsync(vsync)
|
||||
|
||||
# propriété
|
||||
# propriétés
|
||||
|
||||
@staticmethod
|
||||
def get_volume_ambient() -> float: return media.SoundAmbient.get_volume()
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from typing import Union, Callable
|
||||
|
||||
|
||||
Point2D = tuple[int, int] # a 2D point
|
||||
BBox = tuple[int, int, int, int] # a boundary box
|
||||
ColorRGB = tuple[int, int, int] # a RGB Color
|
||||
ColorRGBA = tuple[int, int, int, int] # a RGBA Color
|
||||
Point2D = tuple[int, int] # un point 2D
|
||||
BBox = tuple[int, int, int, int] # une boîte de collision
|
||||
ColorRGB = tuple[int, int, int] # une couleur RGB
|
||||
ColorRGBA = tuple[int, int, int, int] # une couleur RGBA
|
||||
|
||||
DistanceFunc = Callable[["BoxWidget"], int] # a function that return a position / distance
|
||||
Distance = Union[int, DistanceFunc] # a position / distance, represented by a number or a function
|
||||
DistanceFunc = Callable[["BoxWidget"], int] # une fonction renvoyant une position / distance
|
||||
Distance = Union[int, DistanceFunc] # une position / distance sous la forme d'un nombre ou d'une fonction
|
||||
|
|
|
@ -3,10 +3,10 @@ from source.type import Point2D, BBox
|
|||
|
||||
def in_bbox(point: Point2D, bbox: BBox) -> bool:
|
||||
"""
|
||||
Return true if a point is inside a bounding box
|
||||
:param point: the point to check
|
||||
:param bbox: the bbox where to check the point
|
||||
:return: True if the point is inside the bbox, False otherwise
|
||||
Indique si un point est dans un rectangle
|
||||
:param point: le point à vérifier
|
||||
:param bbox: la bbox à vérifier
|
||||
:return: True si le point est dans la bbox, sinon Faux
|
||||
"""
|
||||
|
||||
point_x, point_y = point
|
||||
|
|
|
@ -3,17 +3,15 @@ from typing import Callable, Any
|
|||
|
||||
def dict_filter(filter_func: Callable[[Any, Any], bool], dictionary: dict[Any, Any]) -> dict[Any, Any]:
|
||||
"""
|
||||
Filter a dict object with the filter function given.
|
||||
:param filter_func: the function to filter with
|
||||
:param dictionary: the dictionary to filter
|
||||
:return: the filtered dictionary
|
||||
Filtre les objets d'un dictionnaire avec la fonction de filtre donnée.
|
||||
:param filter_func: La fonction utilisée pour le filtre. Reçois l'argument clé et valeur
|
||||
:param dictionary: Le dictionnaire à filtrer
|
||||
:return: Le dictionnaire filtrer
|
||||
|
||||
Example :
|
||||
Exemple :
|
||||
filter_func = lambda key, value: key.startswith("valeur")
|
||||
dictionary = {"valeur1": 1, "valeur2": 2, "clé1": None}
|
||||
|
||||
result = {"valeur1": 1, "valeur2": 2}
|
||||
|
||||
-> {"valeur1": 1, "valeur2": 2}
|
||||
"""
|
||||
|
||||
return {
|
||||
|
@ -26,16 +24,15 @@ def dict_filter(filter_func: Callable[[Any, Any], bool], dictionary: dict[Any, A
|
|||
|
||||
def dict_filter_prefix(prefix: str, dictionary: dict[str, Any]) -> dict[str, Any]:
|
||||
"""
|
||||
Take only the keys that start with the prefix, and remove this prefix from the keys.
|
||||
:param prefix: the prefix to use
|
||||
:param dictionary: the dictionary to filter
|
||||
:return: the dictionary with the prefix
|
||||
Ne garde que les clés qui commencent avec ce préfixe dans le dictionnaire et retire leur préfixe.
|
||||
:param prefix: le préfixe à utiliser
|
||||
:param dictionary: le dictionnaire à filtrer
|
||||
:return: le dictionnaire avec le préfixe
|
||||
|
||||
Example:
|
||||
Exemple :
|
||||
prefix = "button"
|
||||
dictionary = {"button1": 1, "button2": 2, "label1": None}
|
||||
|
||||
result = {"1": 1, "2": 2}
|
||||
-> {"1": 1, "2": 2}
|
||||
"""
|
||||
|
||||
return {
|
||||
|
@ -48,10 +45,10 @@ def dict_filter_prefix(prefix: str, dictionary: dict[str, Any]) -> dict[str, Any
|
|||
|
||||
def dict_add_prefix(prefix: str, dictionary: dict[str, Any]) -> dict[str, Any]:
|
||||
"""
|
||||
Add a prefix to every key of the dictionary
|
||||
:param prefix: the prefix to add
|
||||
:param dictionary: the dictionary to modify
|
||||
:return: the dictionary with the prefix at the start of the keys
|
||||
Ajoute un préfixe à toute les clés d'un dictionnaire
|
||||
:param prefix: le préfixe à ajouter
|
||||
:param dictionary: le dictionnaire à modifier
|
||||
:return: le dictionnaire avec le préfixe à chaque clé
|
||||
"""
|
||||
|
||||
return {
|
||||
|
|
|
@ -5,10 +5,10 @@ from source.type import Point2D
|
|||
|
||||
def copy_array_offset(src: np.array, dst: np.array, offset: Point2D) -> None:
|
||||
"""
|
||||
Copy a numpy array into another one with an offset
|
||||
:param src: source array
|
||||
:param dst: destination array
|
||||
:param offset: the offset where to copy the array
|
||||
Copie une matrice dans une autre matrice avec un décalage.
|
||||
:param src: la matrice source
|
||||
:param dst: la matrice de destination
|
||||
:param offset: le décalage avec lequel copier la matrice
|
||||
"""
|
||||
column, row = offset
|
||||
width, height = src.shape
|
||||
|
|
|
@ -2,5 +2,10 @@ from datetime import datetime
|
|||
from pathlib import Path
|
||||
|
||||
|
||||
def path_ctime_str(path: Path):
|
||||
def path_ctime_str(path: Path) -> str:
|
||||
"""
|
||||
Un raccourci permettant d'obtenir la représentation de la date de création d'un fichier
|
||||
:param path: le chemin du fichier
|
||||
:return: la date correspondante sous la forme d'un texte
|
||||
"""
|
||||
return datetime.fromtimestamp(path.lstat().st_ctime).strftime('%d/%m/%Y %H:%M:%S')
|
||||
|
|
|
@ -7,8 +7,9 @@ import pyglet
|
|||
|
||||
class StoppableThread(Thread):
|
||||
"""
|
||||
A thread that can be stopped.
|
||||
The run method need to check for the "self._stop" variable and return manually if it is true.
|
||||
Un thread pouvant être arrêté.
|
||||
La méthode "run" doit souvent vérifier la variable self.stopped et faire un return manuellement si cette variable
|
||||
est vrai.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -16,17 +17,18 @@ class StoppableThread(Thread):
|
|||
self.stopped = False
|
||||
|
||||
def stop(self) -> None:
|
||||
# indique que le thread devrait s'arrêter dès que possible
|
||||
self.stopped = True
|
||||
|
||||
|
||||
def in_pyglet_context(func: Callable, *args, **kwargs) -> Any:
|
||||
"""
|
||||
This function can be call in a thread. It will call the "func" in the pyglet event loop, avoiding
|
||||
some operation that are not allowed outside of the pyglet context, and return its result
|
||||
:param func: the function to call in the pyglet context
|
||||
:param args: the args of the function
|
||||
:param kwargs: the kwargs of the function
|
||||
:return: the result of the function
|
||||
Cette fonction doit être appelée dans un thread. Elle appellera une fonction dans la boucle d'événement de pyglet,
|
||||
ce qui permet d'éviter certaines opérations illégales en dehors de ce contexte et renvoie le résultat.
|
||||
:param func: la fonction à appeler
|
||||
:param args: les arguments de la fonction
|
||||
:param kwargs: les arguments à clé de la fonction
|
||||
:return: le résultat de la fonction
|
||||
"""
|
||||
|
||||
queue = Queue()
|
||||
|
|
Loading…
Reference in a new issue