Si vous avez des problèmes de lambdas AWS qui excèdent la limite de 250Mo, voici une astuce qui pourrait vous aider.
Continue reading “Minimiser la taille de ses lambdas en évitant d’avoir boto3 et ses stubs dans le paquet à déployer”Archives
bookmark_borderExplications et astuces d’utilisation de poetry
Pour ceux qui sont habitués à utiliser un environnement virtuel «de base» avec virtualenv, poetry peut être déroutant. Voici quelques éclaircissements et certains trucs avec l’utilisation de poetry.
Continue reading “Explications et astuces d’utilisation de poetry”bookmark_borderJavaScript / Jest – Comment gérer les mocks
Pour faciliter les explications, voici une fonction triviale, qu’on peut supposer être une fonction importante à mocker.
exports.bob = () => {
// fonction très TRÈS complexe...
return "real";
}
Problème: Les mocks ne se réinitialisent pas automatiquement après chaque test. Il faut le faire manuellement et il y a deux méthodes équivalentes.
const index = require("./index")
test("test 1", () => {
const original = index.bob;
index.bob = jest.fn(() => 0);
expect(index.bob(0)).toBe("mocked");
index.bob = original; // <-- on remet la fonction originale en place
});
Ou encore
test("test 1", () => {
const bob = jest.spyOn(index, "bob");
bob.mockImplementation(() => "mocked");
expect(index.bob(0)).toBe("mocked");
addMock.mockRestore(); // <-- on remet la fonction originale en place
});
Oui, ça fonctionne, le hic c’est que si un test plante avant de réinitialiser le mock, les autres tests qui dépendent de ladite fonction planteront. Par exemple:
test("test 1", () => {
original = index.bob;
index.bob = jest.fn(() => 0);
expect(index.bob(0)).toBe("mocked");
throw "erreur"; // oups!
index.bob = original; // ça n'arrive pas
});
test("test 2", () => {
expect(index.bob(7)).toBe("real"); // va échouer car bob retourne encore 0
})
Solution 1 – try / finally
test("test 1", () => {
original = index.bob;
try {
index.bob = jest.fn(() => "mocked");
expect(index.bob(10)).toBe("mocked");
throw "erreur"; // oups!
} finally {
index.bob = original;
}
});
test("test 2", () => {
expect(index.bob(7)).toBe("real");
})
C’est n’est pas tellement élégant car ça indente le code. C’est aussi facile d’oublier de mettre l’étape de réinitialisation dans un finally
.
Solution 2 – Une fonction router / proxy
const original_bob = index.bob;
index.bob = jest.fn((arg) => {
// un ou plusieurs if/else pour diriger les mocks
if (arg === 0) {
// mock pour "test 1"
return "mocked";
}
// si rien ne correspond, on appelle la fonction originale
return original_bob(arg);
});
test("test 1", () => {
expect(index.bob(0)).toBe("mocked");
});
test("test 2", () => {
expect(index.bob(10)).toBe("real");
})
Gros défaut: Ça ne fonctionne pas pour les fonctions qui n’ont pas d’argument. Autre inconvénient, la fonction peut rapidement devenir lourde s’il y a beaucoup de if
/ else
. Pour ne pas perdre le fil, ça demande d’écrire des commentaires pour garder une trace de l’association entre chaque mock et test. Si on renomme un test sans mettre à jour le commentaire dans le mock, le lien est rompu.
De l’autre côté, cette approche a l’avantage de pouvoir réutiliser les mocks entre les tests sans devoir les reconfigurer à chaque test. De plus, elle n’exige pas au programmeur de devoir se rappeler à chaque fois d’encapsuler le mock dans un bloc try
/ finally
et elle ne crée pas d’indentation du code.
Conclusion
Je théorise que la source du problème est probablement attribuable à l’absence de destructeurs en JavaScript, ce qui empêche d’encapsuler les mocks dans des objets et d’utiliser la technique resource acquisition is initialization, aussi connue sous RAII.
Merci JavaScript. Merci.
Références
bookmark_borderPièges de la fonction pour JavaScript Array Sort
Ah JavaScript, tu ne cesses de me surprendre par tes pièges. La fonction sort
en a plus d’un. Commençons avec sa description.
La méthode sort()
trie les éléments d’un tableau, dans ce même tableau, et renvoie le tableau. Par défaut, le tri s’effectue sur les éléments du tableau convertis en chaînes de caractères et triées selon les valeurs des unités de code UTF-16 des caractères. [Réf]
Emphase sur «convertis en chaînes de caractères». Il s’avère donc que le code suivant
data = [1, 2, 3, 20, 10]
data.sort();
console.log(data)
retourne
[ 1, 10, 2, 20, 3 ]
Il faut donc fournir sa propre fonction de tri. Mais, il y a encore un piège. Allons-y avec l’implémentation naïve.
data = [1,2,3,20,10]
data.sort((left, right) => left < right);
console.log(data)
retourne
[ 1, 2, 3, 20, 10 ]
Regardez où se situe le 20. Pas là où on s’attendrait. Le problème est que la fonction passée en argument à sort
ne doit pas retourner un booléen, elle doit retourner un entier < 0
, = 0
ou > 0
. Donc, la bonne solution pour trier des entiers en ordre croissant est
data = [1, 2, 3, 20, 10]
data.sort((left, right) => left - right);
console.log(data)
ce qui retourne
[ 1, 2, 3, 10, 20 ]
Merci JavaScript. Merci.
Mise à jour 2022-02-20
Nicolas Kruchten m’a fait remarquer que Python, jusqu’à la version 2.4, avait le même design questionnable de la fonction passée à sort. Ils en gardent d’ailleurs la trace dans la documentation de la version courrante.
bookmark_borderComment intégrer mypy dans un projet existant
Voici tout simplement comment je m’y suis pris pour intégrer mypy dans quelques projets. Ce billet suppose que vous utilisez git et que vous avez un système de tests en place.
Continue reading “Comment intégrer mypy dans un projet existant”bookmark_borderUsing Selenium to Roll Out Changes to Gihub Settings
Your company is rolling out a new policy and need you to change settings across many repositories? That sounds like a very repetitive task that can be easily automated. I just did it with Selenium. Here is the recipe.
Continue reading “Using Selenium to Roll Out Changes to Gihub Settings”bookmark_borderPython Poetry Index Error – list index out of range
You run poetry and get this (undescriptive) error message.
[IndexError]
list index out of range
So far I’ve identified two things that you need to check.
- Credentials: If you are installing packages from a private repository, make sure poetry credentials are right.
- Presence of all required files in local packages: If you are installing a package from local files, make sure all files mentioned in the
packages
section of itspyproject.toml
file are present. (I mostly got this error while building on Docker when forgetting to add them all in theDockerfile
.
bookmark_borderpython poetry 1.0.0 private repo issue fix
On December 12th 2019, poetry v1.0.0 was released. With it, came a bad surprise for me: My CI/CD jobs as well as my Docker image builds started failing.
After investigating, I’ve found out that the password key/value was now missing from the .config/pypoetry/auth.toml
file. Digging some more, I’ve found out that poetry relies on a library called keyring to manage passwords.
Here is what I did to fix the problem.
First, I’ve noticed that poetry falls back to the previous method if keyring returns RuntimeError
when it is called. Nice. It turns out that keyring comes with a backend aptly named “fail” which does that whatever the call is. So, it’s only a matter of configuring it.
As the keyring documentation states it, run python -c "import keyring.util.platform_; print(keyring.util.platform_.config_root())"
to find where to put the configuration file. Then, in that directory, create keyringrc.cfg
and put the following content in it:
[backend]
default-keyring=keyring.backends.fail.Keyring
That’s it. Now you can call poetry config http-basic....
the same way you used to and the password will be stored in auth.toml
like before.
bookmark_borderOpset – a python configuration library
Last week, my team open sourced the configuration library we have streamlined for the software components that we work on.
Opset – A library for simplifying the configuration of Python applications at all stages of deployment. [github] [pypi]
Continue reading “Opset – a python configuration library”bookmark_borderRecipe: GPG-agent forwarding
This is heavily inspired by https://wiki.gnupg.org/AgentForwarding but is going to be friendlier
Continue reading “Recipe: GPG-agent forwarding”