Catégorie : développement

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

Comment utiliser Hyperfine ?

Comment utiliser Hyperfine pour comparer les performances de rg et ag

Qu’est-ce que Hyperfine ?

Hyperfine est un outil en ligne de commande qui permet de mesurer et de comparer les performances d’autres commandes. Il est particulièrement utile pour évaluer la vitesse d’exécution de différentes commandes ou scripts, en fournissant des statistiques détaillées comme le temps moyen, l’écart-type, et la plage de temps d’exécution.

Présentation de rg (ripgrep)

Ripgrep, souvent abrégé en rg, est un outil de recherche de texte ultra-rapide. Il est conçu pour parcourir rapidement des fichiers et des répertoires à la recherche de motifs spécifiques. Ripgrep est connu pour sa rapidité et sa capacité à ignorer les fichiers non pertinents, comme ceux dans les répertoires .git ou node_modules.

Présentation de ag (The Silver Searcher)

The Silver Searcher, ou ag, est un autre outil de recherche de texte, similaire à ack, mais plus rapide. Il est optimisé pour la recherche dans des projets de code, en ignorant automatiquement les fichiers et répertoires non pertinents. Bien qu’il soit rapide, il est souvent surpassé par rg en termes de performances.

Comparaison des performances avec Hyperfine

Pour comparer les performances de rg et ag, nous pouvons utiliser Hyperfine avec la commande suivante :

hyperfine --warmup 3 'rg -i "Olivier" -g "*php*" .' 'ag -i "Olivier" -G "php"'

Les résultats montrent que rg est significativement plus rapide que ag :

  • rg a un temps moyen d’exécution de 256.6 ms.
  • ag a un temps moyen d’exécution de 910.3 ms.

En résumé, rg est environ 3.55 fois plus rapide que ag dans ce scénario.

Pourquoi utiliser rg plutôt que ag ?

La comparaison effectuée avec Hyperfine démontre clairement que rg est plus performant que ag pour la recherche de texte. Si la vitesse est un critère important pour vous, rg est donc un choix évident. De plus, rg offre une meilleure gestion des fichiers ignorés et une intégration plus fluide avec les outils modernes de développement.

En conclusion, si vous cherchez un outil de recherche de texte rapide et efficace, rg est une excellente option, surtout lorsque vous travaillez sur des projets de grande envergure où chaque milliseconde compte.

Automatiser le nettoyage des branches Git avec un alias : Guide pratique

Automatiser le nettoyage des branches Git avec un alias : Guide pratique

Travailler avec Git implique souvent de gérer de nombreuses branches, locales et distantes. Au fil du temps, il est courant que des branches distantes soient supprimées, laissant des branches locales obsolètes. Pour simplifier le nettoyage de ces branches, vous pouvez créer un alias Git qui automatise ce processus. Dans cet article, nous vous expliquons comment faire, ainsi que les avantages et les inconvénients de cette méthode.

Créer un alias Git pour nettoyer les branches locales

Voici la commande pour créer un alias Git nommé prune-all qui nettoie automatiquement les branches locales obsolètes :

git config --global alias.prune-all '!git fetch --prune && git branch -vv | grep ": gone]" | sed "s/^[[:space:]]*\([^[:space:]]*\).*/\1/" | xargs -r git branch -d'

Une fois cet alias configuré, vous pouvez simplement exécuter :

git prune-all

Cette commande va :

  1. Mettre à jour les références locales et supprimer les branches distantes supprimées (git fetch --prune).
  2. Identifier les branches locales qui n’ont plus de branche distante associée (git branch -vv | grep ": gone]").
  3. Extraire les noms de ces branches (sed).
  4. Supprimer les branches locales (xargs -r git branch -d).

Pourquoi utiliser cet alias ?

Cet alias offre plusieurs avantages :

  • Gain de temps : Plus besoin d’exécuter manuellement plusieurs commandes pour nettoyer les branches locales.
  • Automatisation : Le processus est entièrement automatisé, ce qui réduit les erreurs humaines.
  • Propreté du dépôt : Vous gardez votre dépôt local propre et synchronisé avec le dépôt distant.

Les précautions à prendre

Bien que cet alias soit très utile, il est important de comprendre ses limites et les risques potentiels :

  • Utilisation de git branch -d : L’alias utilise git branch -d pour supprimer les branches locales. Cela signifie que Git refusera de supprimer une branche si elle contient des commits non fusionnés. C’est une sécurité pour éviter de perdre du travail.
  • Risque de suppression accidentelle : Si vous utilisez git branch -D (avec un D majuscule) à la place de -d, les branches seront supprimées de force, même si elles contiennent des commits non fusionnés. Soyez prudent si vous modifiez l’alias pour utiliser -D.
  • Vérification manuelle : Avant d’exécuter l’alias, il peut être utile de vérifier les branches qui seront supprimées en exécutant :
git fetch --prune && git branch -vv | grep ": gone]"

Quand utiliser cet alias ?

Cet alias est particulièrement utile dans les situations suivantes :

  • Vous travaillez sur un projet avec de nombreuses branches, et vous voulez garder votre dépôt local propre.
  • Vous collaborez avec une équipe et les branches distantes sont fréquemment supprimées après fusion.
  • Vous voulez automatiser une tâche répétitive pour gagner du temps.

Conclusion

Créer un alias Git pour nettoyer les branches locales est une excellente façon d’automatiser une tâche fastidieuse et de garder votre dépôt propre. En utilisant git branch -d, vous ajoutez une couche de sécurité pour éviter de perdre du travail non fusionné. Cependant, soyez conscient des risques si vous décidez d’utiliser git branch -D à la place.

N’hésitez pas à essayer cet alias et à l’adapter à vos besoins. Bonne gestion de branches !

Vous avez des questions ou des suggestions ? Laissez un commentaire ci-dessous !

JavaScript hack update

Mise à jour en pur JavaScript hacks

Voici une petite mise à jour en vanilla JS qui fait la même chose que ce que j’ai mis ici.

function emptyBody() {
    document.body.innerHTML = '';
}
function getRandomInt(max) {
    return Math.floor(Math.random() * Math.floor(max));
}
function addNewAvatar() {
    let curr = getRandomInt(5000);
    return function() {
        const img = document.createElement('img');
        img.src = `https://avatars.githubusercontent.com/u/${curr}`;
        img.style.maxWidth = '50px';
        img.style.display = 'inline-block';
        img.style.float = 'left';
        img.style.margin = '0';
        img.style.padding = '0';
        document.body.appendChild(img);
        curr += (1 + getRandomInt(3));
        setTimeout(addNewAvatar(), 100);
    };
}
emptyBody();
setTimeout(addNewAvatar(), 100);

Python : f-string vs str()

Quelle est la différence de performance entre f"{x}" et str(x) ?

Voici mes tests qui m’ont surpris, car je m’attendais à l’inverse :

from typing import Dict

def benchmark() -> None:
  """Main
  function for benchmark.
  """
  t1 = timeit.timeit("f_str()",
                     globals=globals(),
                     number=50000000)
  t2 = timeit.timeit("u_str()",
                     globals=globals(),
                     number=50000000)
  t3 = timeit.timeit("n_str()",
                     globals=globals(),
                     number=50000000)
  d: Dict[str, float] = {
    "f-string": t1,
    "str": t2,
    "no str": t3
  }
  s: Dict[str, float] = {k: v
                         for k, v
                         in sorted(d.items(),
                                   key=lambda i:
                                   i[1])}
  f: float = min(s.values())
  print("Method\tTime\tPerc.")
  print("------\t----\t-----")
  for k, v in s.items():
    p: float = (v / f) * 100
    print(f"{k}\t{v:.2f}\t{p:.2f}%")

if __name__ == "__main__":
  import timeit
  class T:
    def __init__(
            self, l: str) -> None:
      self.l: str = l
  o: T = T("test")
  def f_str() -> str:
    return f"{o.l}"
  def u_str() -> str:
    return str(o.l)
  def n_str() -> str:
    return o.l
  benchmark()

Explications

  • f"{self.label}" utilise le mécanisme d’interpolation de chaînes de caractères de Python qui peut être légèrement plus rapide parce qu’il est optimisé pour concaténer des littéraux de chaîne et des variables ;
  • str(self.label) appelle explicitement le constructeur de la classe str, ce est un peu plus lent en raison de l’appel de fonction.

Panda vs Numpy

Ce qu’il faut retenir

Numpy et Pandas n’ont pas exactement les mêmes objectifs.

Dans la plupart des cas, NumPy peut être légèrement plus rapide que pandas, car NumPy est plus bas niveau et a moins de surcharge. Cependant, pandas offre des structures de données et des fonctionnalités plus avancées, ce qui peut faciliter le travail avec des ensembles de données complexes. Les performances relatives de NumPy et pandas dépendent également des opérations spécifiques effectuées sur les données, de sorte que les différences de performances peuvent varier en fonction des tâches spécifiques. Certaines fonctions n’existent qu’avec pandas, et qui n’ont pas d’équivalents NumPy sont : read_csv, read_excel, groupby, pivot_table, merge, concat, melt, crosstab, cut, qcut, get_dummies et applymap.

Résultats

Résultat : image générée : notez bien que j’ai appelé des fonctions « bas niveau » pour qu’on voie ce que NumPy a dans le ventre et des fonctions qui n’existent que dans pandas, que ré-implémentées en Python pur + NumPy.

Résultats pandas vs NumPy

Code source

Voici le code source que j’ai fait, qui appelle quelques fonctions connues de NumPy et de pandas.

import numpy as np
import pandas as pd
import time
import matplotlib.pyplot as plt

# Générer un grand ensemble de données
data_np = np.random.rand(30_000_000)
data_pd = pd.DataFrame({"values": data_np})

operations = (
    "sum",
    "mean",
    "filter",
    "cum_sum",
    "sort",
    "complex",
    "pivot",
    "group_by",
    "rolling",
)
time_np = []
time_pd = []


# Définir une fonction pour chronométrer et stocker les temps d'exécution
def measure_time(start_time, end_time, time_list):
    time_list.append(end_time - start_time)


# Effectuer les différentes opérations et mesurer les temps d'exécution
for operation in operations:
    # print(f"operation: {operation}")
    print(f"{operation}")
    if operation == "sum":
        start_time_np = time.time()
        result_np = np.sum(data_np)
        end_time_np = time.time()
        measure_time(start_time_np, end_time_np, time_np)

        start_time_pd = time.time()
        result_pd = data_pd["values"].sum()
        end_time_pd = time.time()
        measure_time(start_time_pd, end_time_pd, time_pd)

    elif operation == "mean":
        start_time_np = time.time()
        mean_np = np.mean(data_np)
        end_time_np = time.time()
        measure_time(start_time_np, end_time_np, time_np)

        start_time_pd = time.time()
        mean_pd = data_pd["values"].mean()
        end_time_pd = time.time()
        measure_time(start_time_pd, end_time_pd, time_pd)

    elif operation == "filter":
        start_time_np = time.time()
        filtered_np = data_np[data_np > 0.5]
        end_time_np = time.time()
        measure_time(start_time_np, end_time_np, time_np)

        start_time_pd = time.time()
        filtered_pd = data_pd[data_pd["values"] > 0.5]
        end_time_pd = time.time()
        measure_time(start_time_pd, end_time_pd, time_pd)

    elif operation == "cum_sum":
        start_time_np = time.time()
        cum_sum_np = np.cumsum(data_np)
        end_time_np = time.time()
        measure_time(start_time_np, end_time_np, time_np)

        start_time_pd = time.time()
        cum_sum_pd = data_pd["values"].cumsum()
        end_time_pd = time.time()
        measure_time(start_time_pd, end_time_pd, time_pd)

    elif operation == "sort":
        start_time_np = time.time()
        sorted_np = np.sort(data_np)
        end_time_np = time.time()
        measure_time(start_time_np, end_time_np, time_np)

        start_time_pd = time.time()
        sorted_pd = data_pd["values"].sort_values()
        end_time_pd = time.time()
        measure_time(start_time_pd, end_time_pd, time_pd)
    elif operation == "complex":
        # Générer des données structurées
        data_1 = np.random.randint(0, 1_000_000, (2_000, 2))
        data_2 = np.random.randint(0, 1_000_000, (2_000, 2))

        # Créer des DataFrames pandas
        df_1 = pd.DataFrame(data_1, columns=["id", "value_1"])
        df_2 = pd.DataFrame(data_2, columns=["id", "value_2"])

        # Créer des arrays structurés NumPy
        d_type = np.dtype([("id", int), ("value", int)])
        numpy_data_1 = np.array(
            list(map(tuple, data_1)), dtype=d_type
        )
        numpy_data_2 = np.array(
            list(map(tuple, data_2)), dtype=d_type
        )

        # Jointure avec NumPy
        def numpy_join(data1, data2):
            result = []
            for row1 in data1:
                for row2 in data2:
                    if row1["id"] == row2["id"]:
                        result.append(
                            (row1["id"], row1["value"], row2["value"])
                        )
            return np.array(
                result,
                dtype=[
                    ("id", int),
                    ("value_1", int),
                    ("value_2", int),
                ],
            )

        start_time_np = time.time()
        numpy_result = numpy_join(numpy_data_1, numpy_data_2)
        end_time_np = time.time()
        measure_time(
            start_time_np, end_time_np, time_np
        )  # Ajoutez cette ligne

        # Jointure avec pandas
        start_time_pd = time.time()
        pandas_result = df_1.merge(df_2, on="id")
        end_time_pd = time.time()

        measure_time(start_time_pd, end_time_pd, time_pd)
    elif operation == "pivot":
        # Générer des données structurées
        unique_ids = np.arange(0, 60_000)
        unique_groups = np.arange(0, 3)
        id_col = np.repeat(unique_ids, len(unique_groups))
        group_col = np.tile(unique_groups, len(unique_ids))
        value_col = np.random.randint(0, 100, len(id_col))
        data = np.column_stack((id_col, group_col, value_col))

        # Créer des DataFrames pandas
        df = pd.DataFrame(data, columns=["id", "group", "value"])

        # Créer des arrays structurés NumPy
        d_type = np.dtype(
            [("id", int), ("group", int), ("value", int)]
        )
        numpy_data = np.array(list(map(tuple, data)), dtype=d_type)

        # Pivot avec NumPy
        def numpy_pivot(_data, _id_col, _group_col, _value_col):
            _unique_ids = np.unique(_data[_id_col])
            _unique_groups = np.unique(_data[_group_col])

            pivot_table = np.zeros(
                (len(_unique_ids), len(_unique_groups))
            )


            for row in _data:
                id_index = np.where(_unique_ids == row[_id_col])[0][0]
                group_index = np.where(
                    _unique_groups == row[_group_col]
                )[0][0]
                pivot_table[id_index, group_index] = row[_value_col]

            return pivot_table

        start_time_np = time.time()
        numpy_pivot_table = numpy_pivot(
            numpy_data, "id", "group", "value"
        )
        end_time_np = time.time()
        measure_time(start_time_np, end_time_np, time_np)

        # Pivot avec pandas
        start_time_pd = time.time()
        pandas_pivot_table = df.pivot(
            index="id", columns="group", values="value"
        )
        end_time_pd = time.time()
        measure_time(start_time_pd, end_time_pd, time_pd)

    elif operation == "group_by":
        # Générer des données structurées
        data = np.random.randint(0, 10_000_000, (100_000, 2))

        # Créer des DataFrames pandas
        df = pd.DataFrame(data, columns=["id", "value"])

        # Créer des arrays structurés NumPy
        d_type = np.dtype([("id", int), ("value", int)])
        numpy_data = np.array(list(map(tuple, data)), dtype=d_type)

        # Group_by avec NumPy
        def numpy_group_by_mean(_data):
            _unique_ids, counts = np.unique(
                _data["id"], return_counts=True
            )
            sums = np.zeros_like(_unique_ids, dtype=float)
            for row in _data:
                sums[np.where(_unique_ids == row["id"])[0][0]] += row[
                    "value"
                ]
            return _unique_ids, sums / counts

        start_time_np = time.time()
        numpy_result = numpy_group_by_mean(numpy_data)
        end_time_np = time.time()
        measure_time(start_time_np, end_time_np, time_np)

        # Group_by avec pandas
        start_time_pd = time.time()
        pandas_result = df.groupby("id")["value"].mean()
        end_time_pd = time.time()
        measure_time(start_time_pd, end_time_pd, time_pd)

    elif operation == "rolling":
        # Générer un grand ensemble de données
        data_np = np.random.rand(100_000_000)
        data_pd = pd.DataFrame({"values": data_np})

        window = 100

        def numpy_rolling_mean(arr, _window):
            _cum_sum = np.cumsum(np.insert(arr, 0, 0))
            return (
                _cum_sum[_window:] - _cum_sum[:-_window]
            ) / _window

        start_time_np = time.time()
        numpy_result = numpy_rolling_mean(data_np, window)
        end_time_np = time.time()
        measure_time(start_time_np, end_time_np, time_np)

        # Rolling avec pandas
        start_time_pd = time.time()
        pandas_result = (
            data_pd["values"].rolling(window=window).mean()
        )
        end_time_pd = time.time()
        measure_time(start_time_pd, end_time_pd, time_pd)

# Créer un graphique de comparaison
x = np.arange(len(operations))
width = 0.35

fig, ax = plt.subplots()

rects1 = ax.bar(
    x - width / 2,
    time_np,
    width,
    label="NumPy",
    color="#c9daf8",
    edgecolor="black",
    hatch="//",
    linewidth=1,
)
rects2 = ax.bar(
    x + width / 2,
    time_pd,
    width,
    label="pandas",
    color="#c2e8b8",
    edgecolor="black",
    hatch=".",
    linewidth=1,
    alpha=0.5,
)


# Modification de la taille des marqueurs dans rects2
for rect in rects2:
    rect.set_linewidth(2)

ax.set_yscale("log")
ax.set_ylabel("Temps d'exécution (s) - Échelle logarithmique")
ax.set_title(
    "Comparaison des temps d'exécution entre NumPy et pandas"
)
ax.set_xticks(x)
ax.set_xticklabels(operations)
ax.legend()


def autolabel(rects):
    for _rect in rects:
        height = _rect.get_height()
        ax.annotate(
            "{:.2f}".format(height),
            xy=(_rect.get_x() + _rect.get_width() / 2, height),
            xytext=(0, 3),  # 3 points vertical offset
            textcoords="offset points",
            ha="center",
            va="bottom",
        )


autolabel(rects1)
autolabel(rects2)

fig.tight_layout()
plt.savefig("pandas_vs_numpy.png")

IUT alternants : projet Django / Python à rendre le 12 février minuit au plus tard

A rendre le dimanche 12 février 2023 minuit au plus tard


Projet individuel


Comment le rendre

Faites un fichier README.txt et déposez-le ici
Dans le fichier README.txt, précisez :

  • le sujet choisi
  • l’adresse de votre site
  • un nom d’utilisateur
  • un mot de passe
  • (et plusieurs nom/mot de passe, s’il y a plusieurs niveaux de droits (administrateur/visiteur etc.))
  • si vous avez utilisé des librairies spécifiques que je vous ai autorisées, merci de le re-préciser

Sujet

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


Fonctionnalités obligatoires

  • Nouveaux modèles
  • Nouvelles relations à mettre en oeuvre : ForeignKey, ManyToMany, OneToOne
  • Au moins un formulaire
  • Connexion + déconnexion (vu en cours)
  • Visualisation de tout dans l’interface d’administration

Sujets possibles

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

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

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

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

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


Ce que vous devez rendre

Idéalement

Si vous n’avez pas le choix

Les fichiers source de votre projet


Pour favoriser votre organisation

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


Librairies autorisées


React autorisé

Note pour ceux qui connaissent / font / du React : la librairie est autorisée, mais il me faut le code d’origine, et non pas le code minifié / de production.


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


Retard

Après la date et heure limite

Passé ce délai ce sera 1 pt par 2 heures de retard (mon robot qui analyse les mails prend en compte la date de réception du mail, tout est fait automatiquement).
Pour ceux qui essaient vraiment d’aller jusqu’à la dernière minute, toute heure entamée est comptée comme une heure complète.
Exemple : un point en moins si je le reçois un jour après à la minute près, soit date limite plus 00:01 minute.

N’oubliez pas de me donner le nom et le mot de passe pour se connecter !


Copier-coller

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

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


PDFs

Python Django

Expressions régulières

Regexp hints / aide

Récupéré ici, traduction à finir

Caractères

Caractères Explication Exemple Chaînes qui « matchent »
[abc]
[a-c]
Fait correspondre les caractères / la plage de caractères donné(e)s abc[abc] abca
abcb
abcc
[^abc]
[^ac]
Négation des caractères / la plage de caractères donnés abc[^abc] abcd
abce
abc1
...
. Tout caractère sauf saut de ligne bc. bca
bcd
bc1
b.
...
\d Tout caractère numérique (équivalent à [0-9]) c\d c1
c2
c3
...
\D Tout caractère non numérique (équivalent à [^0-9]) c\D cA
cB
c*
...
\w Tout caractère alphanumérique (équivalent à [A-Za-z0-9_]) a\w aa
a1
a_
...
\W Tout caractère non alphanumérique (équivalent à [^A-Za-z0-9_]) a\W a)
a$
a?
...
\s Généralement utilisé pour les espaces blancs, mais peut être utilisé pour les nouvelles lignes, tabulations, etc. a\s [espace]
\S Tout sauf un espace blanc ou nouvelle ligne ou tabulation. a\S aa
\t Tabulation horizontale t\txy t[tab]xy
\r Correspond à un retour chariot AB\r\nCD AB[\return]CD
\n Correspond à un saut de ligne AB\r\nCD AB[\return]CD
| Correspond à « x » ou « y » aa|bb aa
bb
Chars Définition Ex match
Chars Définition Ex match
Chars Définition Ex match
Commentaires fermés sur Expressions régulières Publié dans

Godot

Objets

Avoir le noeud « racine » owner
Nombre de points (« vertices ») utilisés  
print(
    Performance.get_monitor(
        Performance.RENDER_VERTICES_IN_FRAME
    )
)
Attendre une frame  
yield(get_tree(), "idle_frame")

ou (peut prendre plus d’une frame) :

yield(get_tree(), "physics_frame")

Déplacer
un objet
dans un autre
func _on_barillet_body_shape_entered(
    body_rid, body,
    body_shape_index, local_shape_index
):
    # distant object:
    # body.shape_owner_get_owner(body_shape_index)
    # local object:
    # shape_owner_get_owner(local_shape_index)
    var me = shape_owner_get_owner(
        local_shape_index
    )
    body.get_parent().remove_child(body)
    get_parent().add_child(body)
queue_free()
vs
free()
queue_free() est un raccourci pour détruire un nœud et le supprimer de l’arborescence en toute sécurité à la fin de la frame : le nœud est mis dans une « file d’attente » qui est une liste de « choses à supprimer lorsque le jeu a fini de traiter à cette frame« .. Cela n’arrive pas immédiatement pour éviter certaines situations délicates qui feraient autrement planter le jeu. Pour garder les choses simples, il est recommandé d’utiliser queue_free() pour les nœuds de l’arborescence.

Supprimer les plus vieux fichiers d’un dossier tant qu’on dépasse une certaine taille


Exemples de lancement du script

Notez qu’il faut lancer en utilisant « source« 

  • Supprimer les plus vieux fichiers du dossier courant (./) tant qu’il prend plus de 96Mo :
    source ./clean_custom.sh --path ./ -l 9600000
  • Supprimer les plus vieux fichiers du dossier temporaire (/tmp/) tant qu’il prend plus de 2Go :
    source ./clean_custom.sh --path /tmp/ -l 2000000000

Code du script

#!/usr/bin/env bash                                                              
PATH_TO_CLEAN=                                                                   
NUMBER_FILES_TO_DELETE_EACH_LOOP=1                                               
SIZE_LIMIT=2000000000                                                            
                                                                                 
# ----------------------------------------------------------------------------   
# usage:                                                                         
usage()                                                                          
{                                                                                
    echo "Clean directory: while size of a dir > limit, oldest files first."
    echo "Usage: ${filename} [-p|--path path] [-s|--max-size size] | [-h]"
    echo "    -p|--path: path to clean"            
    echo "    -l|--limit: max size for the folder (must be > 0)"
    echo "    -h|--help this help"                 
}                                                                                
                                                                                 
# ----------------------------------------------------------------------------   
# handling arguments:                                                            
args=("$@")                                                            
filename=$(basename -- "$0" | sed 's/\(.*\)\..*/\1/')        
while [ "$1" != "" ]; do                                     
    case $1 in                                               
        -p | --path ) shift              
                      # stop if path doesn't exist:
                      if [ ! -d "$1" ]; then
                          echo "Path not found: '$1'"
                          usage
                          return 1
                      fi
                      PATH_TO_CLEAN=$1
                      ;;
        -l | --limit ) shift             
                       SIZE_LIMIT=$(echo $1 | bc)
                       if [ $SIZE_LIMIT -le 0 ]
                       then
                           usage
                           return 1
                       fi
                       ;;
        -h | --help ) usage              
                      return
                      ;;
        * ) usage                        
            return 1 
    esac                                                     
    shift                                                    
done                                                                             
[ -z "$PATH_TO_CLEAN" ] && echo "Path empty" && usage && return 1
echo "Cleanin dir: '$PATH_TO_CLEAN', size limit=$SIZE_LIMIT" 
# ----------------------------------------------------------------------------   
# handling arguments:                                                            
while [ 1 ]                                                                      
do                                                                               
    s=$(du -sb $PATH_TO_CLEAN | cut -f1 | bc)                
    if [ $s -gt $SIZE_LIMIT ]                                
    then                                                     
        find $PATH_TO_CLEAN -type f -printf '%T+ %p\n' | \
            sort -nr | \
            tail -$NUMBER_FILES_TO_DELETE_EACH_LOOP | \
            cut -d' ' -f 2- | \
            xargs -I {} rm -f {}
    else                                                     
        break                            
    fi                                                                                                                                                                                                                                                      
done                                                                             
return 0

Django scripting : « AppRegistryNotReady: Apps aren’t loaded yet » solution

Si vous voulez faire un script simple qui veut importer votre application construite sur le framework Django, vous ferez sûrement ce code :

import django
from app.models import MyModel

Vous aurez sûrement cette erreur : django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.

Pas de panique !
La solution est de lancer setup() de votre application avant les imports, comme suit :

import django

if __name__ == '__main__':
    django.setup()
    # import AFTER setup
    from app.models import MyModel
    # je peux maintenant utiliser MyModel!!