Poetry¶
In de vorige hoofdstukken heb je gewerkt met een eigen conda environment zodat je jouw pythonomgeving mooi gescheiden kan houden van andere studenten die op dezelfde computer werken en voor het isoleren van de verschillende projecten waar je aan werkt. Dit is echt de oplossing voor alle problemen waarbij volledige Pythoninstallaties onbruikbaar kunnen worden — waarna je alles opnieuw moet installeren.
Opnieuw beginnen of nieuwe environments aanmaken heeft wel een nadeel: je moet alle packages die je nodig hebt opnieuw installeren. Welke waren dat ook alweer? Vast numpy
, en matplotlib
, en…? Niet handig. Als je code gaat delen met elkaar krijg je regelmatig te maken met een ImportError
waarna je weer één of ander package moet installeren.
Nu pythondaq netjes is uitgesplitst in een MVC-structuur en de wijzigingen met Git worden bijgehouden, ga je er een package van maken zodat je het ook met anderen kan delen.
Packages op PyPI (de standaardplek waar Python packages gepubliceerd worden) geven altijd hun dependencies op. Dat zijn de packages die verder nog nodig zijn om alles te laten werken. Installeer je matplotlib
, dan krijg je er six, python-dateutil, pyparsing, pillow, numpy, kiwisolver, cycler
automatisch bij. Maar alleen de namen van packages zijn niet genoeg. Welke versies van numpy
werken met de huidige versie van matplotlib
? Allemaal zaken die je — als je een package schrijft — zelf moet bijhouden. Het voordeel is dat jouw gebruikers alleen maar jouw pakket hoeven te installeren — de rest gaat vanzelf.
En… hoe test je je package zodat je zeker weet dat hij het bij een ander ook doet? Heel vaak werkt het bij jou wel, maar vergeet je een bestand mee te sturen dat wel echt nodig is.1 Of: bij jou werkt import my_new_cool_app.gui
wel, maar bij een ander geeft hij een ImportError
. De bestanden zijn er wel, maar worden verkeerd geïmporteerd.
Hoe krijg je eigenlijk je code bij iemand anders? Liefst als één bestand, of zelfs met pip install my_new_cool_app
; dat zou wel mooi zijn.
En daar is Poetry.
Er zijn meerdere tools ontwikkeld om dezelfde problemen op te lossen. Poetry is heel populair geworden. Het richt zich op het officiële ecosysteem: standaard Python packages, ofwel PyPI en pip
; niet conda
(zie meer hierover in paragraaf pip vs conda). Jammer, maar dit zorgt er wel voor dat iedereen mét of zónder Anaconda je package kan installeren. Dat is dan wel weer fijn. Wij gaan Anaconda gebruiken om een virtual environment met alleen Python te maken. Vervolgens installeren we alles dat we nodig hebben met pip
. Dat werkt prima, want we mengen verder geen conda
met pip
packages. Het maken van conda packages valt daarmee buiten het bestek van deze cursus, al is dat een relatief kleine stap als je je standaard Python package af hebt.
Werken in een terminal
Poetry is een tool die je enkel en alleen in de terminal kunt gebruiken. Het heeft alleen een command-line interface (CLI). Ben je nog niet zo bekend met het navigeren in een terminal dan kun je als oefening de Terminal Adventure Game spelen.
Poetry installeren
Om Poetry te installeren gaan we gebruik maken van pipx
, zie voor meer informatie paragraaf pipx.
Eerst moeten we pipx
installeren
- Open een Anaconda Prompt.
- Maak een nieuwe environment en installeer pipx via pip
- Zorg ervoor dat de map waarin pipx apps opslaat, is opgenomen in je PATH omgevingsvariabele.
- Sluit de Anaconda Prompt en open een nieuwe.
- Test of pipx nu werkt met:
Nu kunnen we Poetry
installeren met pipx
.
- Installeer Poetry met behulp van pipx.
- Test of poetry nu werkt met:
- Activeer een andere environment en test of Poetry ook daar werkt.
We gaan Poetry bedienen door commando's te geven in de terminal van Visual Studio Code. We laten de terminal weten welk programma wij willen gaan besturen, door poetry
in te typen. En daarachter wat we willen dat Poetry gaat doen. We kunnen informatie over Poetry opvragen met het commando about
.
(ecpc) > poetry about
Poetry - Package Management for Python
Version: 1.8.4
Poetry-Core Version: 1.9.1
Poetry is a dependency manager tracking local dependencies of your projects and libraries.
See https://github.com/python-poetry/poetry for more information.
Poetry about
Open een terminal en vraag informatie over Poetry op met het commando poetry about
. Lees de tekst die Poetry aan je teruggeeft, waar kan je meer informatie vinden?
Nieuw Poetry project¶
Info
We gaan werken met modules en packages. Ben je daar nog niet zo bekend mee, zorg dan dat je paragraaf Modules en paragraaf packages gemaakt hebt.
Stel je wilt een package schrijven met wat handige functies om veelgebruikte statistische berekeningen makkelijk uit te voeren. Je noemt het easystat
. Het doel is eerst om het in al je eigen analyses makkelijk te kunnen gebruiken (import easystat
) maar je wilt het ook op GitHub zetten en wie weet vinden anderen het ook handig! Je wilt het dus ook netjes doen. En niet later van anderen horen: leuk, maar bij mij werkt het niet!
Easystat Poetry project aanmaken
Een project stop je altijd in een map , als je aan Poetry vraagt om een project te maken zal er een nieuwe (project)map worden aangemaakt.
Je denkt na over een geschikte locatie en besluit dat de projectmap in de ECPC
map moet komen te staan. Je opent Visual Studio Code en opent de map ECPC
. Je opent een terminal en controleert dat de terminal ook in de map ECPC
is.
Je geeft Poetry de opdracht om een nieuw project met de naam easystat
aan te maken in de src-layout10 met het commando poetry new --src easystat
. Je bekijkt de nieuw gemaakte mappenstructuur en ziet dat het overeenkomt met de mappenstructuur zoals hieronder weergegeven:
ECPC
├── oefenopdrachten
├── pythondaq
├── easystat
├── src
└── easystat
└── __init__.py
├── tests
└── __init__.py
├── pyproject.toml
└── readme.md
└── •••
src-layout
Door het project in een source layout (src-layout) te bouwen maken we het expres iets moeilijker om vanuit een script je package te importeren. Je kunt dat dan alleen nog maar doen door het package zelf ook te installeren (zoals andere gebruikers ook moeten doen) en daardoor loop je zelf tegen eventuele problemen aan. Werkt het uiteindelijk bij jou? Dan werkt het ook bij andere mensen.
Testcode
(ecpc) > poetry new --src easystat
Created package easystat in easystat
Checkpunten:
- De projectmap
easystat
staat in de mapECPC
. - In de projectmap
easystat
staat een mapsrc
. - In de map
src
staat een package mapeasystat
Projecttraject
- Easystat Poetry project aanmaken
- Easystat conda environment aanmaken
- Easystat shortcuts.py en try_shortcuts.py aanmaken
- Easystat try_shortcuts.py testen
- Easystat Poetry install
- Easystat dependencies toevoegen
Bekijk nog eens de mappenstructuur. Allereerst is er een projectmap easystat
(waar de map src
in staat) aangemaakt . Je kunt nu in GitHub Desktop deze map easystat
toevoegen als nieuwe repository, zoals we gedaan hebben in opdracht Repository toevoegen.
Laten we één voor één kijken welke mappen en bestanden Poetry heeft aangemaakt. We zien een README.md
in de projectmap staan. Hierin komt een algemene beschrijving van ons project.2
Daarna is er een map tests
. Goede software wordt getest. In deze map komen bestanden te staan die delen van de code runnen en resultaten vergelijken met verwachte resultaten — zoals je kunt doen in opdracht Packages.3
Dan komt de src
-map. Daarin komt ons nieuwe package easystat
4 te staan. Er is alvast voor ons een __init__.py
aangemaakt. Handig!
En als laatste… een pyproject.toml
5 waarin alle informatie over je project wordt bijgehouden. Ook staat er in dit bestand informatie voor de verschillende tools die je kunt gebruiken. De inhoud van het bestand ziet er ongeveer zo uit:
[tool.poetry]
name = "easystat"
version = "0.1.0"
description = ""
authors = ["David Fokkema <davidfokkema@icloud.com>"]
readme = "README.md"
packages = [{include = "easystat", from = "src"}]
[tool.poetry.dependencies]
python = "^3.13"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
Het bestand is in het TOML-formaat.11 Tussen de vierkante haken staan de koppen van de verschillende secties in dit configuratiebestand. Overal zie je poetry
terugkomen, want dat is de tool die wij gebruiken. In de eerste sectie staat informatie over ons project. Je kunt daar bijvoorbeeld een beschrijving toevoegen of het versienummer aanpassen. De tweede sectie bevat de dependencies. Dit zijn alle Pythonpackages die ons project nodig heeft. Op dit moment is dat alleen maar Python. Ook het versienummer van Python is belangrijk. Hier is dat 3.13 en het dakje geeft aan dat nieuwere versies 3.14, 3.15, enz. ook prima zijn, maar 3.12 (te oud) en 4.0 (te nieuw) niet. Dit kan belangrijk zijn. Gebruikers met een iets oudere versie van Python — bijvoorbeeld versie 3.11 — kunnen nu het package niet installeren. Als je niet per se de nieuwste snufjes van Python 3.13 nodig hebt kun je aangeven dat een iets oudere versie van Python ook prima is. Op dit moment — herfst 2024 — is Python 3.13 de nieuwste versie. Het is dus prima om minimaal 3.12 te vragen — die versie is inmiddels een jaar oud.
Conda environment aanmaken¶
Bij het schrijven van een nieuw package is het zéker belangrijk om een conda environment te gebruiken. Anders loop je het risico dat je package lijkt te werken maar bij iemand anders crasht. Immers, het kan best zijn dat jij NumPy gebruikt en al eerder geïnstalleerd had. Bij iemand die NumPy nog niet geïnstalleerd had gaat het dan mis.
Easystat conda environment aanmaken
Je voegt de projectmap easystat
toe als existing/local repository in GitHub . Vanuit GitHub Desktop open je de repository easystat
in Visual Studio Code. Je maakt in Anaconda Prompt een nieuwe conda environment aan met de naam easystat
en daarin python=3.12
. Uiteraard selecteer je het nieuwe environment in Visual Studio Code.
Testcode
(easystat) > conda list
# packages in environment at C:\easystat:
#
# Name Version Build Channel
bzip2 1.0.8 h2bbff1b_6
ca-certificates 2024.7.2 haa95532_0
libffi 3.4.4 hd77b12b_1
openssl 3.0.15 h827c3e9_0
pip 24.2 py310haa95532_0
python 3.12.7 h99e199e_0
setuptools 72.1.0 py310haa95532_0
sqlite 3.45.3 h2bbff1b_0
tk 8.6.14 h0416ee5_0
tzdata 2024a h04d1e81_0
vc 14.40 h2eaa2aa_1
vs2015_runtime 14.40.33807 h98bb1dd_1
wheel 0.43.0 py310haa95532_0
xz 5.4.6 h8cc25b3_1
zlib 1.2.13 h8cc25b3_1
Checkpunten:
- De projectmap
easystat
is geopend in Visual Studio Code. - Python is geïnstalleerd in de conda environment
easystat
. - In Visual Studio Code is de conda environment
easystat
geactiveerd.
Projecttraject
- Easystat Poetry project aanmaken
- Easystat conda environment aanmaken
- Easystat shortcuts.py en try_shortcuts.py aanmaken
- Easystat try_shortcuts.py testen
- Easystat Poetry install
- Easystat dependencies toevoegen
conda-forge
Merk op dat we nu niet gebruik hoeven te maken van de conda-forge
channel. Python zelf staat in alle kanalen en we gaan verder geen software installeren met conda, dus ook niet uit conda-forge
.
Maken van de easystat-package¶
We starten met ons package. Stel, we berekenen vaak de standaarddeviatie van het gemiddelde en maken daarvoor een handige shortcut
in shortcuts.py
. Nu willen we deze shortcut ook in een ander script gebruiken. Dit kunnen we doen door package easystat
te importeren in dit nieuwe script zodat we de functie stdev_of_mean
daar ook kunnen gebruiken. We maken een script try_shortcuts.py
om dit te testen.
Easystat shortcuts.py en try_shortcuts.py aanmaken
Maak zoals hieronder aangegeven de bestanden shortcuts.py
en try_shortcuts.py
aan:
easystat
├──
src
├──
easystat
├──
__init__.py
└──
shortcuts.py
├──
tests
├──
__init__.py
└──
try_shortcuts.py
├──
pyproject.toml
└──
readme.md
Import numpy could not be resolved
Misschien is het je al opgevallen dat VS Code een oranje kringeltje onder numpy
zet in de eerste regel. Als je daar je muiscursor op plaatst krijg je een popup met de melding Import numpy could not be resolved
. Daar moeten we misschien wat mee en dat gaan we straks ook doen.
In de eerste regel van test_shortcuts.py
importeren we de functie uit het nieuwe package om uit te proberen. In de laatste regel gebruiken we een handige functie van f-strings.6
Easystat try_shortcuts.py testen
Je bent heel benieuwd of je package al werkt. Je runt het bestand try_shortcuts.py
en krijgt een foutmelding...
Testcode
(easystat) > python try_shortcuts.py
Traceback (most recent call last):
File "c:\ECPC\easystat\tests\try_shortcuts.py", line 1, in < module >
from easystat.shortcuts import stdev_of_mean
ModuleNotFoundError: No module named 'easystat'
Checkpunten:
- Je hebt de juiste conda environment geactiveerd.
- Je runt het bestand
try_shortcuts.py
uit de maptests
. - Je krijgt een foutmelding
ModuleNotFoundError: No module named 'easystat'
Projecttraject
- Easystat Poetry project aanmaken
- Easystat conda environment aanmaken
- Easystat shortcuts.py en try_shortcuts.py aanmaken
- Easystat try_shortcuts.py testen
- Easystat Poetry install
- Easystat dependencies toevoegen
Dit konden we verwachten. We hebben onze package immers nog niet geïnstalleerd. Als we onze package gaan delen met andere mensen verwachten wij dat zij onze package ook gaan installeren, door dezelfde stappen te doorlopen als andere gebruikers komen we erachter of alles wel goed werkt.
Installeren van een package¶
Het installeren van de package kan makkelijk met Poetry:
(easystat) > poetry install
Updating dependencies
Resolving dependencies... (0.1s)
Writing lock file
Installing the current project: easystat (0.1.0)
Poetry is even bezig en ons package is geïnstalleerd.
Easystat Poetry install
Je gaat het project easystat
installeren in de conda environment easystat
met het commando poetry install
. Waarschijnlijk krijg je een error (zie info-blok hieronder) maar door rustig te lezen los je die op. Je installeert alsnog het project easystat
draai je opnieuw tests/try_shortcuts.py
en zie je een nieuwe error verschijnen ModuleNotFoundError: No module named 'numpy'
. Hoera de eerste error is met succes opgelost en je kunt door met de volgende opdracht.
Current Python version is not allowed by the project
Waarschijnlijk krijg je in dikke rode letters de error:
Current Python version (3.12.7) is not allowed by the project (^3.13).
Please change python executable via the "env use" command.
pyproject.toml
staat bij de Python dependency dat er minstens versie 3.13 of hoger (^3.13) nodig is voor dit project7. En de conda environment easystat
heeft Python 3.12 geïnstalleerd. Je kunt nu twee dingen doen:
- Je bedenkt dat voor dit project een lagere versie van Python ook voldoende is en past de Python versie dependency aan in de
pyproject.toml
naar ^3.12. - Je vindt dat het project minstens versie 3.13 moet gebruiken en upgrade Python in de
easystat
environment metconda install python=3.13
.
Testcode
(easystat) > conda list
# packages in environment at C:\easystat:
#
# Name Version Build Channel
bzip2 1.0.8 h2bbff1b_6
ca-certificates 2024.7.2 haa95532_0
easystat 0.1.0 pypi_0 pypi
libffi 3.4.4 hd77b12b_1
openssl 3.0.15 h827c3e9_0
pip 24.2 py310haa95532_0
python 3.10.14 he1021f5_1
setuptools 72.1.0 py310haa95532_0
sqlite 3.45.3 h2bbff1b_0
tk 8.6.14 h0416ee5_0
tzdata 2024a h04d1e81_0
vc 14.40 h2eaa2aa_1
vs2015_runtime 14.40.33807 h98bb1dd_1
wheel 0.43.0 py310haa95532_0
xz 5.4.6 h8cc25b3_1
zlib 1.2.13 h8cc25b3_1
Checkpunten:
- Je hebt de juiste conda environment geactiveerd.
- Nadat je
poetry install
hebt gedaan krijg je de meldingInstalling the current project: easystat (0.1.0)
. - Je runt het bestand
tests/try_shortcuts.py
. - Je krijgt een foutmelding
ModuleNotFoundError: No module named 'numpy'
Projecttraject
- Easystat Poetry project aanmaken
- Easystat conda environment aanmaken
- Easystat shortcuts.py en try_shortcuts.py aanmaken
- Easystat try_shortcuts.py testen
- Easystat Poetry install
- Easystat dependencies toevoegen
Als we het testscript nu draaien krijgen we wéér een foutmelding:
Ons package heeft NumPy nodig en dat hebben we nog niet geïnstalleerd. Dat kunnen we handmatig doen maar dan hebben andere gebruikers een probleem. Veel beter is het om netjes aan te geven dat ons package NumPy nodig heeft — als dependency.Dependencies toevoegen¶
Om een dependency aan te geven vertellen we Poetry dat hij deze moet toevoegen met:
(easystat) > poetry add numpy
Using version ^1.23.2 for numpy
Updating dependencies
Resolving dependencies...
Writing lock file
Package operations: 1 install, 0 updates, 0 removals
• Installing numpy (1.23.2)
Easystat dependencies toevoegen
Je voegt Numpy
als dependency toe aan het project easystat
met het commando poetry add numpy
. Je kijkt in de pyproject.toml
en warempel daar staat Numpy
nu bij de dependencies! Je vraagt je af of Numpy
nu ook in de conda environment easystat
is geïnstalleerd en controleert dit met conda list
en waarachtig Numpy
staat in de lijst . Weer ga je tests/try_shortcuts.py
draaien en ditmaal krijg je een uitkomst!
Testcode
Checkpunten:
- Je hebt de juiste conda environment geacitveerd.
- Je hebt
Numpy
als dependency toegevoegd. - Je krijgt een uitkomst als je het bestand
tests/try_shortcuts.py
runt.
Projecttraject
- Easystat Poetry project aanmaken
- Easystat conda environment aanmaken
- Easystat shortcuts.py en try_shortcuts.py aanmaken
- Easystat try_shortcuts.py testen
- Easystat Poetry install
- Easystat dependencies toevoegen
Fijn! Het verwijderen van dependency PACKAGE
gaat met poetry remove PACKAGE
. Poetry heeft Numpy nu toegevoegd aan de environment easystat
.Gewone package managers als Pip en Conda zullen geen packages toevoegen aan je Poetry project als je pip/conda install package
aanroept. Gebruik daarom altijd poetry add package
als je met Poetry aan een package werkt.
Info
Als we de code in ons package aanpassen dan hoeven we het niet opnieuw te installeren met Poetry, maar als we met de hand iets wijzigen in de pyproject.toml
dan moet dat wel. Als je een ImportError
krijgt voor je eigen package — bijvoorbeeld als je nieuwe mappen of bestanden hebt aangemaakt — probeer dan eerst voor de zekerheid poetry install
.
Poetry.lock
Poetry.lock¶
Na het toevoegen van Numpy is er ook een bestand poetry.lock
bijgekomen. Hierin staan de exacte versies van alle geïnstalleerde packages. Vaak wordt dit bestand gecommit zodat collega-ontwikkelaars exact dezelfde versies installeren zodra ze poetry install
aanroepen. Om dat te proberen maken we even een schone conda environment:
Schone environment
- Maak een schone conda environment met
conda create --name easystat python=3.12
- Kies voor ja als Conda een waarschuwing geeft dat deze environment al bestaat en vraagt of je het bestaande environment wilt verwijderen.
- Draai
tests/try_shortcuts.py
en bekijk de foutmelding.
We krijgen meteen foutmeldingen. Immers, we hebben nog niets geïnstalleerd.
Poetry.lock
- Installeer de
easystat
package metpoetry
. - Waarvoor gebruikt Poetry de lock file (
poetry.lock)
? - Draai
tests/try_shortcuts.py
en bekijk de uitkomst.
Wheels
Wheels¶
Wanneer we klaar zijn om ons package te delen met andere gebruikers gebruiken we het commando build
om wheels te bouwen.
Bouw een wheel
- Bouw het wheel van easystat met
poetry build
. - Bekijk de namen van de bestanden in de nieuwe map
easystat/dist
, welke extensie hebben ze?
(ecpc) > poetry build
Building easystat (0.1.0)
- Building sdist
- Built easystat-0.1.0.tar.gz
- Building wheel
- Built easystat-0.1.0-py3-none-any.whl
Een sdistis een source distribution. Een
.tar.gz
-bestand is een soort zipbestand met daarin de broncode van ons pakket. De tests worden daar niet in meegenomen. Een wheelis een soort bestand dat direct geïnstalleerd kan worden met
pip
. Zogenaamde pure-python packages bevatten alleen Pythoncode — en geen C-code die gecompileerd moet worden voor verschillende besturingssystemen of hardwareplatforms. Je herkent ze aan none-any
in de bestandsnaam. Nonevoor
niet-OS-specifieken
anyvoor
draait op elk hardwareplatform. We kunnen dit bestand als download neerzetten op een website of aan anderen mailen.
Test wheel
Laten we het wheel uitproberen. We gaan straks een nieuwe conda environment aanmaken, installeren het wheel en proberen het testscript te runnen — één keer vóór het installeren van het wheel en één keer ná het installeren, als volgt:
- Maak een nieuwe conda environment aan met de naam
test-wheel
en activeer deze. - Draai
tests/try_shortcuts.py
en bekijk de foutmelding. - Installeer het wheel met
pip install dist/easystat-0.1.0-py3-none-any.whl
. - Draai
tests/try_shortcuts.py
en bekijk de uitkomst.
Het werkt! Je ziet dat pip install
niet alleen ons package easystat
installeert, maar ook de dependency numpy
. Dat is precies wat we willen.
Het is belangrijk om de wheels niet in je GitHub repository te committen. Je repository is voor broncode, waarmee wheels gebouwd kunnen worden. Als je de stappen voor het aanmaken van de repository netjes gevolgd hebt dan heb je een .gitignore
toegevoegd met Python-specifieke bestandsnamen en directories die genegeerd worden door Git en GitHub.
Poetry gebruiken voor een bestaand project¶
Met poetry new
start je een nieuw project en maakt Poetry voor jou bestanden en mappen aan waarmee je aan de slag kunt. Maar vaak ben je al bezig met een project en wil je dat niet overschrijven. Ook is het een gedoe om een nieuw project te maken en daar je bestaande code in te kopieëren. Gelukkig kun je Poetry ook vertellen dat je al bezig bent en dat Poetry alleen een pyproject.toml
-bestand moet aanmaken. Run dan in de map van je project:
poetry init
de opdracht om Poetry alleen te initialiseren en --no-interaction
voorkomt je dat je eerst honderd vragen krijgt over je project. Meestal kies je toch de standaardantwoorden.8
Info
Vergeet niet — waar nodig — de __init__.py
bestanden toe te voegen aan de packages. Meer informatie over de __init__.py
bestanden vind je in paragraaf packages.
Info
Als je al bezig bent met een project dan werk je als het goed is al in een conda environment. Daar heb je dan met conda install
al packages geïnstalleerd die je nodig hebt. Het gebeurt dan makkelijk dat je vergeet om dat aan te geven met poetry add
. Dat betekent alleen dat als iemand anders je package installeert dat er dependencies missen en dat jouw code dus niet werkt! Dit is makkelijk op te lossen. Zodra je Poetry gaat gebruiken wis dan je environment en maak een nieuwe aan met alleen Python. Dat gaat het makkelijkst als volgt. Stel dat je bezig bent in het environment pythondaq
. We maken dan een nieuw environment met dezelfde naam:
(ecpc) > conda create --name pythondaq python=3.12
WARNING: A conda environment already exists at '/Users/david/opt/anaconda3/envs/pythondaq'
Remove existing environment (y/[n])? y
...
Je overschrijft dus je huidige environment met een nieuwe, lege. Je kunt daarna met poetry add
packages toevoegen net zo lang tot je geen ImportError
meer krijgt.
Poetry flashingLED
Pythondaq
besluit je deze als oefenpackage te gebruiken. Je maakt een nieuwe repository flasher
aan en opent deze in Visual Studio Code. Je maakt zelf in de repository flasher
de src-layout van mappen en bestanden, zoals hier rechts is weergegeven. Het bestand flashingLED
heb je gekopieerd uit je repository oefenopdrachten
. Nu het oefenpackage klaar staat (commit) maak je een nieuwe conda environment met de naam flasher
met daarin python=3.12
. Je activeert de environment flasher
en voegt Poetry toe . Je installeert het pakket en daarna voeg je de benodigde dependencies toe (in ieder geval pyvisa-py
maar wat nog meer?) net zolang tot het scriptje weer werkt .
ECPC
├──
oefenopdrachten
├──
pythondaq
├──
flasher
└──
src
└──
flasher
├──
__init__.py
└──
flashingLED.py
└── •••
No module named 'serial'
Waarschijnlijk krijg je onder andere de foutmelding:
Super handig dat iemand daarboven heeft opgeschreven wat je moet doen om dit probleem op te lossen. Maar waarom moeten we nu ineensPySerial
installeren9? Dat komt omdat we eerst pyvisa-py
met conda uit de conda-forge channel installeerde en daar komt PySerial
als dependencie mee. Nu installeerd Poetry met behulp van pip pyvisa-py
en daar komt PySerial
niet automatisch mee. En dus moeten we het nu zelf handmatig toevoegen.
Testcode
import pyvisa
import numpy as np
import time
rm = pyvisa.ResourceManager("@py")
ports = rm.list_resources()
print(ports)
device = rm.open_resource(
"ASRL3::INSTR", read_termination="\r\n", write_termination="\n"
)
for value in np.arange(0, 10):
device.query(f"OUT:CH0 {0}")
time.sleep(1)
device.query(f"OUT:CH0 {1023}")
time.sleep(1)
(ecpc) > python flasherLED.py
()
Traceback (most recent call last):
File "c:\ECPC\flasher\src\flasher\flashingLED.py", line 8, in
device = rm.open_resource(
File "C:\envs\flasher\lib\site-packages\pyvisa\highlevel.py", line 3292, in open_resource
res.open(access_mode, open_timeout)
File "C:\envs\flasher\lib\site-packages\pyvisa\resources\resource.py", line 281, in open
self.session, status = self._resource_manager.open_bare_resource(
File "C:\envs\flasher\lib\site-packages\pyvisa\highlevel.py", line 3217, in open_bare_resource
return self.visalib.open(self.session, resource_name, access_mode, open_timeout)
File "C:\envs\flasher\lib\site-packages\pyvisa_py\highlevel.py", line 168, in open
sess = cls(session, resource_name, parsed, open_timeout)
File "C:\envs\flasher\lib\site-packages\pyvisa_py\sessions.py", line 861, in init
raise ValueError(self.session_issue)
ValueError: Please install PySerial (>=3.0) to use this resource type.
No module named 'serial'
Checkpunten:
- Je hebt een repository
flasher
met daarin een src-layout. - Je hebt de juiste conda environment geactiveerd.
- Poetry is toegevoegd aan het project.
- Alle benodigde dependencies staan in het
pyproject.toml
en zijn geïnstalleerd in de conda environment. - Het runnen van
flashingLED
laat het LED knipperen.
Projecttraject
- Communicatie met een meetinstrument: flashingLED
- Versiebeheer met GitHub: Repository toevoegen
- Poetry flashingLED
Poetry gebruiken voor pythondaq¶
Natuurlijk willen we Poetry ook gaan gebruiken bij pythondaq
. Daarvoor moeten we twee dingen doen. Als eerste gaan we de pythondaq
repository in een src
-structuur zetten en daarna gaan we Poetry initialiseren.
Pythondaq: src-layout
pythondaq
is zo tof aan het worden dat je het met Poetry gaat beheren zodat jij en andere het gemakkelijk kunnen installeren en gebruiken. Om te beginnen zet je de repository om in een src-layout zoals hiernaast:
pythondaq
├──
src
└──
pythondaq
├──
__init__.py
├──
arduino_device.py
├──
diode_experiment.py
└──
view.py
└──
README.md
Pythondaq: poetry
Nu de repository pythondaq
in de src-layout staat voeg je Poetry toe om het project te beheren . Nadat alles gelukt is test je het project door een nieuwe conda environment aan te maken met de naam pythondaq
met daarin alleen python=3.12
. Daarna installeer je het Poetry project en wanneer je view.py
runt zie je als vanouds een lampje branden en een plot verschijnen.
Pseudo-code
(ecpc) > poetry install
Installing dependencies from lock file
Package operations: x installs, 0 updates, 0 removals
- Installing xxx (1.2.3)
- Installing xxx (1.2.3)
- Installing xxx (1.2.3): Pending...
- Installing xxx (1.2.3): Installing...
- Installing xxx (1.2.3)
Installing the current project: pythondaq (0.1.0)
Checkpunten:
- Je hebt Poetry geïnitialiseerd in de Pythondaq project map.
- Na het initialiseren van Poetry is er een
pyproject.toml
in de projectmap aangemaakt. - Wanneer met
poetry install
in een nieuwe conda environment met alleen python=3.12 het pakket wordt geïnstalleerd werktview.py
daarna in die nieuwe omgeving naar behoren.
Projecttraject
- Pythondaq: Docstring
- Pythondaq: src-layout
- Pythondaq: poetry
- Pythondaq: test imports
- Pythondaq: applicatie
Pythondaq: test imports
tests
-map met __init__.py
en test_imports.py
in de repository pythondaq
.
Je runt het bestand test_imports.py
en lost de errors op. Daarna werkt je package ook als je het aanroept van buiten de map met broncode. Je pythondaq
-repository is nu een volledig project dat je met andere gebruikers van Python kunt delen, bijvoorbeeld via een wheel.
pythondaq
├──
src
└──
pythondaq
├──
__init__.py
├──
arduino_device.py
├──
diode_experiment.py
└──
view.py
├──
tests
├──
__init__.py
└──
test_imports.py
├──
pyproject.toml
└──
README.md
Pseudocode
Testcode
(ecpc) > python test_imports.py
Traceback (most recent call last):
File "c:\pythondaq\tests\test_imports.py", line 1, in < module >
import pythondaq.view
File "C:\pythondaq\src\pythondaq\view.py", line 4, in < module >
from diode_experiment import DiodeExperiment
ModuleNotFoundError: No module named 'diode_experiment'
Checkpunten:
- Er is een map
tests
in de repositorypythondaq
. - Er is een bestand
__init__.py
in de maptests
. - De import statements in de modules in het package
pythondaq
zijn aangepast zodat het bestandtest_imports
runt zonder problemen.
Projecttraject
- Pythondaq: Docstring
- Pythondaq: src-layout
- Pythondaq: poetry
- Pythondaq: test imports
- Pythondaq: applicatie
Model, view, controller packages
In grotere projecten is het gebruikelijk om model, view, controller niet alleen uit te splitsen in verschillende scripts, maar ook in aparte packages te zetten.
- Maak 3 extra packages in de
pythondaq
package.models
,views
encontrollers
. - Zet de modules in de juiste packages.
- Test je code zodat alle imports weer werken.
Van script naar applicatie¶
Om onze python code te testen heb je tot nu toe waarschijnlijk op de run
-knop in Visual Studio Code gedrukt. Of je hebt in de terminal aan python gevraagd om het script.py
te runnen:
run
-knop gebruikt moet wel het bestandje open hebben staan dat je wilt runnen. Kortom, best een beetje gedoe. Maar als we programma's zoals Poetry, Conda of Python willen gebruiken hoeven we helemaal niet het juiste bestandje op te zoeken en te runnen. We hoeven alleen maar een commando in de terminal te geven — bijvoorbeeld python
of conda
— en de computer start automatisch het juiste programma op.
Dat willen wij ook voor onze programma's! En omdat we Poetry gebruiken kunnen we dat heel eenvoudig doen. We gaan even in een andere test-repository een commando toevoegen om de module uit te voeren waarvan je de code in paragraaf Modules kunt vinden. De twee bestanden square.py
en count_count.py
hebben we voor jullie netjes in een package geplaats in de repository AnneliesVlaar/just_count
met de volgende structuur:
just_count/
src/
just_count/
__init__.py
square.py
count_count.py
tests/
__init__.py
pyproject.toml
README.md
De bestanden square.py
en count_count.py
zien er hetzelfde uit als in paragraaf Modules:
We kunnen Poetry niet vragen om een script te runnen, maar wel om een functie uit te voeren.
Main functie toevoegen
Je cloned de repository just_count in GitHub desktop en opent het daarna vanuit GitHub Desktop in Visual Studio Code. Je ziet een pyproject.toml
in de repository staan. Dus installeer je het pakket met Poetry in een nieuwe conda environment (met alleen python=3.12) . Je opent het hoofdbestand count_count.py
en zet de body
van de module in een functie main()
. Daarna pas je het bestand aan zodat de functie nog steeds wordt uitgevoerd wanneer je het bestand count_count.py
runt.
Testcode
Checkpunten:
- Er is een functie
main()
in het bestandcount_count.py
- Het runnen van het bestand
count_count.py
geeft de outputThe square of 5 is 25
Projecttraject
- main functie toevoegen
- commando toevoegen
- commando testen
In pyproject.toml
kunnen we nu het commando toe gaan voegen. Met de scripts
-tool van Poetry kunnen we aangeven met welk commando een functie uit een script wordt uitgevoerd. Om een commando toe te voegen ga je naar pyproject.toml
en voeg je een extra kopje toe:
pyproject.toml
door te voeren moet je de package opnieuw installeren.
commando toevoegen
Je voegt in de pyproject.toml
het kopje [tool.poetry.scripts]
toe. Je voegt vervolgens het commando square
toe. Deze verwijst naar de functie main()
welke in de module count_count.py
staat die ondergebracht is in de package just_count
. Omdat je handmatig het toml-bestand hebt aangepast installeer je het package opnieuw met Poetry .
Checkpunten:
- De naam van het commando is
square
. - De verwijzing na het = teken begint met twee aanhalingstekens gevolgd door het package
just_count
gevolgt door een punt. - Na de punt staat de naam van de module
count_count.py
zonder de extensie.py
gevolgd door een dubbele punt. - Na de dubbele punt staat de naam van de functie
main()
zonder haakjes()
. - Achter de functie staan weer dubble aanhalingstekens om de verwijzing te sluiten.
- Na het opslaan van de
pyproject.toml
is het pakket opnieuw geïnstalleerd.
Projecttraject
- main functie toevoegen
- commando toevoegen
- commando testen
Commando testen
Nu je het commando square
hebt aangemaakt ga je deze testen in een terminal je ziet de tekst The square of 5 is 25
verschijnen. Je vraagt je af of het commando ook werkt als de terminal in een andere map zit. Met het commando cd..
ga je naar een bovenliggende map. Je test het commando square
en ziet weer de tekst The square of 5 is 25
verschijnen. Je concludeert dat het commando nu overal werkt zolang het juiste conda environment is geactiveerd. Dat test je uit door een ander conda environment te activeren en het commando square
nogmaal te proberen. Je krijgt een error en hebt daarmee je vermoeden bewezen. Tevreden ga je door naar de volgende opdracht.
Pseudo-code
(ecpc) > square
The square of 5 is 25
Checkpunten:
- Het commando
square
werkt als het juiste conda environment is geactiveerd. - Het commando
square
werkt nog steeds nadat je met het commandocd..
naar een bovenliggende map bent gegaan. - Het commando
square
werkt niet als een andere conda environment is geactiveerd.
Projecttraject
- main functie toevoegen
- commando toevoegen
- commando testen
Error analysis
Als extra oefening gaan we met Poetry een commando maken om een ander script uit te laten voeren. De package is al aangemaakt, maar werkt nog niet naar behoren. Los in de volgende opdrachten de errors op om het script data_analysis.py
te laten runnen.
- Ga naar GitHub en clone
AnneliesVlaar/erroranalysis
in GitHub Desktop en open de repository daarna in Visual Studio Code. - Natuurlijk maak je gelijk een nieuwe Conda environment aan , voordat we dit package gaan testen.
- Snuffel door de bestanden en mappen, en open
src/erroranalysis/data_analysis.py
. Dit is het script wat moet kunnen runnen. - Run het script
data_analysis.py
en los de errors één voor één op.
Om erachter te komen of de problemen die we hierboven hadden écht zijn opgelost maak je een nieuwe Conda environment aan , installeer je het package en run je het script. Werkt alles? Mooi! Dan gaan we nu een commando aanmaken om de functie table()
aan te roepen.
- Open
pyproject.toml
en voeg een kopje toe voor scripts. pas de regel aan zodat jouw commando de functietable()
aanroept insrc/erroranalysis/data_analysis.py
. Je mag de naam van het commando zelf kiezen. - Ga naar de terminal en kijk of het werkt!
(ecpc) > naam_commando Area of the kitchen table is: 1.8386 ± 0.0049 m
Pythondaq: applicatie
Je maakt een commando om het script view.py
uit de repository pythondaq
te starten . Wanneer je het commando aanroept gaat het LED-lampje branden, en verschijnt er even later een IU-plot op het scherm. Je test of het commando ook buiten Visual Studio Code werkt door een Anaconda prompt
te openen. Je activeert het juiste conda environment en ziet dat ook dan het commando werkt. Wat een feest! Je hebt nu een applicatie geschreven die een Arduino aanstuurt om een ledje te laten branden. En je kunt je applicatie gewoon vanuit de terminal aanroepen!
Pseudo-code
Checkpunten:
- De functie in
view.py
bevat alle code die uitgevoerd moet worden om een meting te starten. - Het commando in de
pyproject.toml
verwijst op de correcte manier naar de functie inview.py
. - Het aanroepen van het commando zorgt ervoor dat een meting gestart wordt.
- Het commando werkt ook in een
Anaconda prompt
zolang het juiste conda environment actief is.
Projecttraject
- Pythondaq: Docstring
- Pythondaq: src-layout
- Pythondaq: poetry
- Pythondaq: test imports
- Pythondaq: applicatie
Versie 2.0.0
In de pyproject.toml
kan je ook de versie aangeven van je package. Maar wanneer hoog je nu welk cijfertje op? Wanneer wordt iets versie 2.0.0? Daar zijn conventies voor. Bug fixes gaan op het laatste cijfer, wijzigingen en nieuwe features gaan op het middelste cijfer. Wanneer de applicatie dusdanig verandert dat je bijvoorbeeld bestanden die je met oude versie hebt gemaakt niet met de nieuwe versie kunt openen, dan verander je het eerste cijfer. Je start vaak met versie 0.1.0 en blijft tijdens het bouwen van je project ophogen naar 0.2.0 en soms zelfs 0.83.0. Wanneer je project min of meer klaar is voor eerste gebruik, dan kies je er vaak voor om versie 1.0.0 te releasen.
-
Echt gebeurd: meerdere studenten leverden hun grafische applicatie in voor een beoordeling. We konden het niet draaien, want er misten bestanden. Bij de student werkte het wel, maar bij ons echt niet. ↩
-
Wanneer de repository op GitHub wordt geplaatst wordt deze README automatisch op de hoofdpagina van de repository getoond, onder de code. ↩
-
Python heeft een ingebouwde module
unittest
die deze tests kan vinden, kan runnen en daarna een handige weergave geeft van welke tests geslaagd zijn en welke faalden. Ook het packagepytest
is erg bekend. Op deze manier weet je altijd zeker dat wanneer je aanpassingen doet in je code, dat de rest van de code nog steeds is blijven werken — zónder dat je zelf uitvoerig alles hebt hoeven uitproberen. Je draait gewoon even snel alle tests. Helaas, helaas — in deze cursus is te weinig tijd om het schrijven van tests te behandelen. ↩ -
Ja er is een map
easystat
met daarin een mapsrc
met daarin weer een mapeasystat
— dat kan nog wel eens verwarrend zijn. Het is conventie om de projectmap dezelfde naam te geven als je package. Het pad is dus eigenlijkproject/src/package
en dat wordt dan, in ons geval,easystat/src/easystat
. ↩ -
Vroeger was er een
setup.py
maar Python schakelt nu langzaam over naar dit nieuwe bestand. ↩ -
In f-strings kunnen tussen de accolades variabelen of functieaanroepen staan. Voeg daar het
=
-teken aan toe en je krijgt niet alleen de waarde, maar ook de variabele of aanroep zelf te zien. Bijvoorbeeld: als je definieertname = "Alice"
, dan geeftprint(f"{name}")
als uitkomstAlice
. Maar voeg je het=
-teken toe zoals inprint(f"{name=")}
wordt de uitvoername='Alice'
. Je ziet dan dus ook meteen de naam van de variabele en dat kan handig zijn. ↩ -
Dit is bij het aanmaken standaard ingevuld op basis van de Python versie die in de base environment zit, kijk maar met
conda list
in de base environment welke versie van Python daarin zit. ↩ -
Het is eenvoudig om zelf de
pyproject.toml
te openen en daar wat in aan te passen voor zover nodig. ↩ -
PySerial is een package die we gebruiken om te communiceren over USB poorten. ↩
-
Hynek Schlawack. Testing & packaging. URL: https://hynek.me/articles/testing-packaging/. ↩
-
Tom Preston-Werner, Pradyun Gedam, and others. Tom's obvious, minimal language. URL: https://github.com/toml-lang/toml. ↩