Tämä ohje on kopio kurssin Ohjelmistotekniikka Poetry-ohjeesta ohjeesta muutamin lisäyksin

Laajoissa ja monimutkaisissa ohjelmistoprojekteissa kaiken koodin tuottaminen itse ei ole enää käytännöllistä. Ei ole esimerkiksi järkevää, että jokaisessa ohjelmistoprojektissa toteutetaan oma ohjelmointirajapinta tietokantaoperaatioille, tai sovelluskehys koodin testaamiseen. Jotta pyörää ei tarvitsisi aina keksiä uudelleen, ovat ohjelmistokehittäjät kehittäneet valtavan määrän avoimen lähdekoodin kirjastoja, joita jokainen voi hyödyntää projekteissaan.

Kirjastojen lähdekoodi on usein luettavissa versionhallinta-alustoilla, kuten GitHubissa. Usein kirjastoja päivitetään jatkuvasti ja nämä päivitykset synnyttävät kirjastoista uusia versioita. Kirjastojen versioita julkaistaan erilaisiin rekistereihin, joista ne ovat helposti asennettavissa. The Python Package Index (PyPI) on eräs tämän kaltainen, Python-kirjastoille tarkoitettu rekisteri.

Projektissa käytettävät kirjastojen versiot ovat projektin riippuvuuksia. Riippuvuuksia asennetaan Python-projekteissa tyypillisesti projektikohtaisiin virtuaaliympäristöihin, jottei samalla tietokoneella olevien projektien riippuvuuksissa syntyisi ristiriitoja. Jotta riippuvuuksien hallinta virtuaaliympäristöissä sujuisi helposti, käytämme kurssilla Poetry-komentorivityökalua.

Huomioita komennoista

Monilla tietokoneilla Python-version kolme komennot suoritetaan python3-komennolla komennon python sijaan. Tarkista käytössä oleva versio komennolla:

python3 --version

Jos komentoa python3 ei jostain syystä löydy, tarkista python-komennon käyttämä versio komennolla:

python --version

Jos molemmissa tapauksissa versio on alle 3.10, asenna tietokoneellesi uusin Python-versio. Muista varmistaa asennuksen jälkeen, että oikea versio on käytössä. Muussa tapauksessa käytä komentoa, jonka käyttämä versio on vähintään 3.10.

Kurssilla käytetään Poetryn versiota 1.6.1. Jos koneellasi on vanhempi versio, se on syytä päivittää!

Asennus

Ennen kuin pääsemme tutustumaan Poetryn käyttöön tarkemmin, tulee se ensin asentaa. Seuraa alla olevista ohjeista tietokoneesi käyttöjärjestelmälle sopivaa asennusohjetta, kannattaa toki vilkaista myös Poetryn virallinen asennusohje.

HUOM: kaikki asennustavat saattavat vaatia terminaali-ikkunan sulkemisen ja uudelleen avaamisen, jotta Poetryn komennot alkavat toimia. Joissain tapauksissa on vaadittu jopa tietokoneen uudelleenkäynnistys.

Linux- ja macOS-asennus

Asenna Poetry suorittamalla terminaalissa seuraava komento:

curl -sSL https://install.python-poetry.org | POETRY_HOME=$HOME/.local python3 -

HUOM: jos python3-komentoa ei löydy, käytä sen sijaan komennon lopussa python-komentoa. Varmista kuitenkin, että Python-versio on oikea edellisen ohjeen mukaisesti.

HUOM: jos törmäät macOS-tietokoneella virheeseen SSL: CERTIFICATE_VERIFY_FAILED, avaa Python-asennuksen hakemisto komenolla open /Applications/Python\ 3.9 (korvaa “3.9” käytössä olevalla Python-versiolla) ja klikkaa hakemistossa olevaa tiedostoa Install Certificates.command. Odota, että operaatio valmistuu ja suorita tämän jälkeen edellä mainittu asennus-komento uudestaan.

Asennuksen jälkeen Poetry-binäärin polku tulee asettaa PATH-muuttujaan. Tämä onnistuu lisäämällä kotihakemiston .bashrc-tiedoston loppuun seuraava rivi:

export PATH="$HOME/.local/bin:$PATH"

Lisääminen onnistuu esimerkiksi muokkaamalla tiedostoa nano-editorin avulla, tai suorittamalla seuraava komento:

echo "export PATH=\"\$HOME/.local/bin:\$PATH\"" >> $HOME/.bashrc

HUOM: jos käytössäsi on zsh-komentorivi, on oikea konfiguraatiotiedosto .bashrc-tiedoston sijaan .zshrc-tiedosto. Voit tarkistaa käytössä olevan komentirivin komennolla echo $SHELL. Käytä tässä tapauksessa edellisessä komennossa käytetyn $HOME/.bashrc-polun sijaan polkua $HOME/.zshrc.

HUOM: jos käytössäsi on macOS-käyttöjärjestelmä ja bash-komentorivi, käytä edellisessä komennossa käytetyn $HOME/.bashrc-polun sijaan polkua $HOME/.bash_profile.

HUOM: käytä melkki-palvelimella edellisessä komennossa käytetyn $HOME/.bashrc-polun sijaan polkua $HOME/.profile.

Käynnistä terminaali uudestaan ja varmista, että asennus onnistui suorittamalla komento poetry --version. Komennon pitäisi tulostaa asennettu versio.

Windows-asennus

Asenna Poetry suorittamalla terminaalissa seuraava komento:

(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | py -

Asennuksen jälkeen Poetry-binäärin polku tulee asettaa PATH-muuttujaan. Lisää tämän ohjeen mukaisesti PATH-muuttujaan polku %APPDATA%\Python\Scripts.

Käynnistä terminaali uudestaan ja varmista, että asennus onnistui suorittamalla komento poetry --version. Komennon pitäisi tulostaa asennettu versio.

Poetry ja Docker

HUOM: Poetrya ei ole pakko asentaa Dockerilla. Jos käytät fuksiläppäriä, Poetry on todennäköisesti jo asennettu koneellesi.

Ehkä paras tapa Poetryllä tapahtuvaan sovelluskehitykeen on Dockerin käyttö. Tällöin et tarvitse koneellesi muuta kuin Dockerin, mitään varsinaista asennusta ei tarvita sillä voit käyttää kurssia varten konfiguroitua Docker imagea mluukkai/poetry, ks myös GitHub-repositorio.

Poetryn käyttö tapahtuu seuraavasti. Mene hakemistoon, missä haluat suorittaa Poetry-komentoja. Joudut (todennäköisesti) antamaan hakemiston sisältöön kirjoitus- lukuoikeudet Dockerille komennolla:

chmod  o=rw .

Anna komento

docker run -it --volume="$PWD:/mydir" mluukkai/poetry:intel

Jos koneesi on M1 mac, komennon muoto on seuraava:

docker run -it --volume="$PWD:/mydir" mluukkai/poetry:m1

Komento avaa komentotulkin Docker-konttiin, missä kaikki Poetry-komennot, esim. poetry init, poetry add, poetry shell ym. ovat käytettävissä. Kontti näkee kaikki käynnistyshakemistossa olevat tiedostot. Voit editoida tiedostoja normaaliin tapaan tekstieditorilla kontin ulkopuolella. Docker-kontissa oleva komentotulkki sulkeutuu komennolla exit.

Lisää Dockerista kurssilla Devops with Docker.

Docker ja Robot-testit

Web-sovelluksia testatessa käytä imagen mluukkai/poetry sijaan imagea mluukkai/poetry-robot. Image toimii ainoastaan intelin prosessoriarkkitehtuurilla varustetuilla koneilla, eli M1 käyttäjät joutuvat etsimään jonkun muun ratkaisun…

Jotta kontissa suoritettu web-sovellus näkyisi isäntäkoneelle, tulee konttia käynnistettäessä julkaista kontin portti 5001 (missä sovellus toimii) isäntäkoneen porttiin. Tämä tapahtuu seuraavasti:

docker run -it -p 5001:5001 --volume="$PWD:/mydir" mluukkai/poetry-robot

Robot-testit suoritetaan menemällä komennolla docker exec samaan kontiin, missä sovellus on jo päällä:

docker exec -it kontainerintunnistetahan bash

Kontainerin tunniste selviää komennolla docker ps.

Testit toimivat valitettavasti ainoastaan ns. headless modessa, jonka saat päälle tehtävän 7 alussa neuvotulla tavalla.

Testit on mahdollista saada toimimaan myös siten että testejä suorittava selain näytetään. Tämä vaatii kuitenkin erinäistä säätöä, googlaa jos kiinnostaa esim. hakusanoilla linux docker gui apps.

Ongelmia Poetryn asennuksessa?

Tämän sivun lopussa on ohjeita muutamiin ongelmatilanteisiin.

Asetusten hienosäätö

Ennen kuin aloitamme Poetryn käytön, tehdään pieni muutos konfiguraatioihin.

Näemme käytössä olevat konfiguraatiot komennolla poetry config --list, jonka tulostus näyttää seuraavalta

cache-dir = "/Users/mluukkai/Library/Caches/pypoetry"
experimental.system-git-client = false
installer.max-workers = null
installer.modern-installation = true
installer.no-binary = null
installer.parallel = true
virtualenvs.create = true
virtualenvs.in-project = false
virtualenvs.options.always-copy = false
virtualenvs.options.no-pip = false
virtualenvs.options.no-setuptools = false
virtualenvs.options.system-site-packages = false
virtualenvs.path = "{cache-dir}/virtualenvs"  # /Users/mluukkai/Library/Caches/pypoetry/virtualenvs
virtualenvs.prefer-active-python = false
virtualenvs.prompt = "{project_name}-py{python_version}"

Konfiguraatioissa on pari meitä kiinnostava kohtaa. cache-dir ja virtualenvs.path kertovat yhdessä, että jokaisen projektin virtuaaliympäristo, eli talletetaan oletusarvoisesti kansion /Users/mluukkai/Library/Caches/pypoetry alle. Tämä voi olla ok ratkaisu, mutta ainakin omaan makuun parempi on jos kunkin projektin virtuaaliympäristö talletetaan projektin hakemistoon. Tämä on yleinen käytäntö esimerkiksi JavaScritp-ekosysteemissä. Konfiguraatio tapahtuu seuraavasti

poetry config virtualenvs.in-project true

Komennon poetry config --list tulostuksessa pitäisi nyt olla seuraava rivi:

virtualenvs.in-project = true

Projektin alustaminen

Harjoitellaan Poetryn käyttöä tekemällä pieni esimerkkiprojekti. Luo hakemisto poetry-testi haluamaasi hakemistoon. Hakemiston ei tarvitse löytyä Labtooliin rekisteröimästäsi repositoriosta. Avaa hakemisto terminaalissa ja suorita siellä komento:

poetry init --python "^3.10"

Komennon yhteydessä annettu --python "^3.10"-asetus asettaa projektin Python-version vaatimukseksi vähintään version 3.10. Komennon suorittaminen alkaa kysymään kysymyksiä. Voit vastata kysymyksiin haluamallasi tavalla ja kaikkien kohtien vastauksia voi myös muokata myöhemmin. Tämän vuoksi kysymysten ohittaminen Enter-painiketta painamalla on täysin hyvä vaihtoehto.

Kun viimeiseen kysymykseen on vastattu, katso hakemiston sisältöä. Hakemistoon pitäisi ilmestyä pyproject.toml-tiedosto, jonka sisältö on kutakuinkin seuraava:

[tool.poetry]
name = "poetry-testi"
version = "0.1.0"
description = ""
authors = ["Matti Luukkainen <matti.luukkainen@helsinki.fi>"]
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.10"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

Tiedoston [tool.poetry]-osio sisältää projektiin liittyviä yleistietoja, kuten sen nimen, kuvauksen ja ylläpitäjät. Osion alapuolella on osioita, jotka listaavat projektin riippuvuuksia. Osiossa [tool.poetry.dependencies] näemme poetry init-komennon suorituksen yhteydessä asettamamme Python-version vaatimuksen, joka on muotoa python = "^3.10". ^3.10-merkintä tarkoittaa, että projektin käyttö vaatii vähintään Python-version 3.10.

Kun pyproject.toml-tiedosto on tullut tutuksi, viimeistellään projektin alustaminen suorittamalla komento:

poetry install

Komennon suorittaminen tekee projektille vaadittavat alustustoimenpiteet, kuten virtuaaliympäristön alustamisen ja riippuvuuksien asentamisen. Tämän vuoksi komento tulee suorittaa aina ennen kuin uutta projektia aletaan käyttämään.

Komennon suorittaminen saattaa johtaa seuraavaan ilmoitukseen:

Installing the current project: poetry-testi (0.1.0)
The current project could not be installed: [Errno 2] No such file or directory: '~/poetry-testi/README.md'
If you do not want to install the current project use --no-root

Tämä johtuu siitä, että Poetry yrittää asentaa myös nykyistä projektia, eikä projektissa ole poetry-testi-nimistä moduulia. Kyseessä ei ole tekstin ulkonäöstä huolimatta virhe vaan pikemminkin varoitus. Projektin alustaminen on kyllä mennyt läpi, mutta jos et halua varoitusta, voit käyttää komennosta muotoa:

poetry install --no-root

Virtuaaliympäristön alustamisen lisäksi tämä komento asentaa ainoastaan projektin riippuvuudet, ei projektia itseään.

Komennon suorittamisen poetry install jälkeen hakemistoon pitäisi ilmestyä tiedosto poetry.lock. Tiedosto sisältää kaikkien asennettujen riippuvuuksien versiotiedot. Sen tietojen avulla Poetry pystyy aina asentamaan poetry install -komennolla riippuvuuksista täsmälleen oikeat versiot. Tästä syystä tiedosto tulee lisätä versionhallintaan.

Tekemiemme asetusten muutosten takia hakemistoon tulee myös tiedosto .venv johon Poetry tallentaa projektin virtuaaliympäristön riippuvuuksineen. Tätä tiedostoa ei tule tallentaa versionhallintaan, eli se on syytä lisätä heti tiedostoon .gitignore.

Kannattaa huomata, että hakemistoa .venv ei oletusarvoisesti näe komennolla ls, sillä Unix-tyyppisissä käyttöjärjestelmissä pisteellä alkavat ovat piilotiedostoja. Komento ls -a tuo näkyviin myös piilotiedostot/hakemistot. Vielä parempi muoto voi olla, ls -la, joka tulostaa tiedot hieman laajemmassa muodossa:

Riippuvuuksien asentaminen

Varoitus: pip

Olet saattanut asentaa Pythonin tarvitsemia riippuvuuksia pip-komennolla. Älä käytä pipiä tällä kurssilla sillä jos teet niin, teet 99.9% todennäköisyydellä jotain väärin.

Tällä kurssilla riippuvuudet asennetaan poetryllä.

Asennetaan seuraavaksi projektiimme ensimmäisen riippuvuus. Riippuvuuksien löytäminen onnistuu helpoiten Googlettamalla ja etsimällä hakutuloksista sopivia GitHub-repositorioita, tai PyPI-sivuja. Asennetaan esimerkkinä projektiimme cowsay-kirjasto. Tämä onnistu projektin juurihakemistossa (samassa hakemistossa, missä pyproject.toml-tiedosto sijaitsee) komennolla:

poetry add cowsay

Asennuksen komento on siis muotoa poetry add <kirjasto>. Komennon suorittamisen jälkeen huomaamme, että pyproject.toml-tiedoston [tool.poetry.dependencies]-osion alla on uutta sisältöä:

[tool.poetry.dependencies]
python = "^3.10"
cowsay = "^2.0.3"

poetry add-komento asentaa oletusarvoisesti kirjaston uusimman version, joka oli komennon suoritushetkellä 2.0.3. Usein tämä on juuri se, mitä haluamme tehdä. Voimme kuitenkin asentaa halutessamme esimerkiksi cowsay-kirjaston version 1.0 komennolla:

poetry add cowsay==1.0

Jos haluaisimme poistaa kirjaston projektimme riippuvuuksien joukosta, se onnistuisi komennolla:

poetry remove cowsay

Pidetään kuitenkin cowsay-kirjasto toistaiseksi asennettuna.

Komentojen suorittaminen virtuaaliympäristössä

Lisätään seuraavaksi poetry-testi-hakemistoon hakemisto src ja sinne tiedosto index.py. Lisätään tiedostoon seuraavat koodirivit:

import cowsay

cowsay.tux("Poetry is awesome!")

Koodissa käyttämme import-lausetta saadaksemme cowsay-kirjaston käyttöömme. Jos suoritamme tiedoston terminaalissa komennolla:

python3 src/index.py

On lopputuloksena seuravaa virheilmoitus:

ModuleNotFoundError: No module named 'cowsay'

Tämä johtuu siitä, että emme ole projektin virtuaaliympäristön sisällä, jonka vuoksi Python ei löydä projektimme riippuvuuksia. Asia korjaantuu käyttämällä run komentoa:

poetry run python3 src/index.py

poetry run-komento siis suorittaa annetun komennon virtuaaliympäristössä, jonka sisällä Python löytää riippuvuutemme.

Kun projektia kehitetään aktiivisesti ja komentoja suoritetaan terminaalissa jatkuvasti, on kätevintä olla koko ajan virtuaaliympäristön sisällä. Voimme siirtyä virtuaaliympäristön sisään kommennolla shell:

poetry shell

Kun olemme virtuaaliympäristössä, komentorivin syöterivin edessä on suluissa virtuaaliympäristön nimi:

$ (poetry-testi-IhtScY6W-py3.9)

Virtuaaliympäristön sisällä voimme suorittaa komennon “normaalisti”, eli ilman run-komentoa:

python3 src/index.py

Voimme lähteä virtuaaliympäristöstä komennolla exit.

Poetry:n tuodut riippuvuudet ovat vain virtuaalisessa ympäristössä saatavilla, VS Code:in sisäänrakennettu “debugging mode” (F5 oletuksena) ei välttämättä toimi. Koita ensin poetry shell ja vasta sen jälkeen käynnistä VS Code code /path/to/projekt komennolla.

Kehityksen aikaiset riippuvuudet

Poetryn avulla riippuvuuksia on mahdollista ryhmitellä niiden käyttötarkoituksen mukaan. Melko yleinen tapa ryhmitellä riippuuvuuksia on ryhmitellä ne kehityksen ja suorituksen aikaisiksi riippuvuuksiksi. Kehityksen aikaisia riippuvuuksia tarvitaan ohjelmiston kehityksen aikana, mutta ne eivät ole välttämättömiä ohjelman suorituksessa.

Komennon poetry add suorittaminen asentaa oletusarvoisesti riippuvuudet [tool.poetry.dependencies]-osion alle. Näiden riippuvuuksien lisäksi voimme asentaa projektiimme riippuvuuksia, joita tarvitsemme vain kehityksen aikana. Näitä riippuvuuksia ovat kaikki ne, joita itse sovelluksen käynnistäminen (esimerkiksi python3 src/index.py-komennon suorittaminen) ei tarvitse.

Kehityksen aikaisten riippuvuuksien asentaminen onnistuu antamalla poetry add-komennolle --group dev-flagi. Esimerkiksi pian tutuksi tulevan pytest-kirjaston voi asentaa kehityksen aikaiseksi riippuvuudeksi seuraavalla komennolla:

poetry add pytest --group dev

Komennon suorittaminen lisää pytest-kirjaston riippuvuudeksi [tool.poetry.group.dev.dependencies]-osion alle:

[tool.poetry.group.dev.dependencies]
pytest = "^7.4.2"

Kehityksen aikaisten riippuvuuksien määritteleminen on kätevää, koska se vähentää asennettavien riippuvuuksien määrää tapauksessa, jossa haluamme vain suorittaa sovelluksen. Tässä tilanteessa riippuvuuksien asentamisen voi tehdä komennolla poetry install --without dev.

Varoitus: pip

Olet saattanut asentaa Pythonin tarvitsemia riippuvuuksia pip-komennolla. Älä käytä pipiä tällä kurssilla sillä jos teet niin, teet 99.9% todennäköisyydellä jotain väärin.

Tällä kurssilla riippuvuudet asennetaan poetryllä.

Ratkaisuja yleisiin ongelmiin

Muistithan, että ennen kuin voit suorittaa komennon, esim.

pytest src/tests

tulee aktivoida virtuaaliympäristö, eli antaa komento

poetry shell

Jos tästä huolimatta tulee valitus siitä, että ohjelman käyttämä kirjasto ei löydy (ja kirjasto on varmuudella asennettu), asenna riippuvuudet ja virtuaaliympäristö uudelleen, eli anna komennot:

rm -rf .venv
rm poetry.lock
poetry install

Yritä tämän jälkeen uudelleen!

muita ongelmia

Usein Poetry-ongelmat ratkeavat seuraavilla toimenpiteillä:

  1. Varmista, että Poetrysta on asennettu uusin versio suorittamalla komento poetry self update
  2. Varmista, että pyproject.toml-tiedostossa on oikea Python version vaatimus:

    [tool.poetry.dependencies]
    python = "^3.10"
    

    Jos versio on väärä, muuta se oikeaksi ja suorita komento poetry update

  3. Tyhjennä välimuisti suorittamalla komennot poetry cache clear pypi --all ja poetry cache clear PyPi --all

  4. Listaa projektissa käytössä olevat virtuaaliympäristöt komennolla poetry env list ja poista ne kaikki yksitellen komennolla poetry env remove <nimi>. Esimerkiksi seuraavasti:

    $ poetry env list
    unicafe-jLeQYxxf-py3.9 (Activated)
    $ poetry env remove unicafe-jLeQYxxf-py3.9
    Deleted virtualenv: /Users/kalleilv/Library/Caches/pypoetry/virtualenvs/unicafe-jLeQYxxf-py3.9
    

    Kun virtuaaliympäristöt on poistettu, suorita komento poetry install

Kun kaikki toimenpiteet on suoritettu, yritä suorittaa epäonnistunut Poetry-komento uudestaan.

Keyring-ongelma

Jos poetry install-komennon suorittaminen pyytää keyring-salasanaa, ongelma pitäisi ratketa suorittamalla terminaalissa export PYTHON_KEYRING_BACKEND=keyring.backends.fail.Keyring ja sen jälkeen suorittamalla komento poetry install uudestaan. Kyseisen rivin voi laittaa .bashrc (tai vastaavaan) tiedostoon, jotta sitä ei tarvitse suorittaa jokaisen terminaali-istunnon aluksi.