Data & AI-uddannelsesguide 2021
Download GoDataDriven-brochuren for at få en komplet oversigt over tilgængelige træningssessioner og læringsrejser for datateknikere, datavidenskab, dataanalytikere og analytik-oversættere.
Når du bruger python professionelt, kan det betale sig at opsætte dine projekter
på en konsekvent måde. Dette hjælper dine samarbejdspartnere til hurtigt at forstå
strukturen i et projekt og gør det lettere for dem at opsætte projektet
på deres maskine. Nøglen til opsætning af dit projekt er setup.py
-filen.
I denne blog vil jeg gå i detaljer med denne fil.
Hvor vi starter
Her går jeg ud fra, at du allerede har en pakke, som du vil opsætte.
Dette behøver ikke at være en færdig pakke – ideelt set bør du oprettesetup.py
længe før dit projekt er færdigt. Det kan endda være en tom pakke;
du skal blot sørge for, at pakkemappen eksisterer
og indeholder en fil med navnet init.py
(som kan være tom).
Hvis du følger min kollega Henks struktur
for dit projekt, bør din udgangssituation se nogenlunde sådan ud:
example_project/├── exampleproject/ Python package with source code.│ ├── __init__.py Make the folder a package.│ └── example.py Example module.└── README.md README with info of the project.
Du kan have andre filer eller mapper i din struktur, f.eks.
mapper med navnet notebooks/
, tests/
eller data/
, men disse er ikke nødvendige.
Sagen om en setup.py
Når du har oprettet en pakke som denne, så er det sandsynligt, at du
vil bruge noget af koden andre steder. Du kan f.eks. ønske
at gøre dette i en notesbog:
from exampleproject.example import example_function
Dette ville fungere, hvis din nuværende arbejdskatalog er example_project/
, men i
alle andre tilfælde vil python give dig output som f.eks:
ModuleNotFoundError: No module named 'exampleproject'
Du kunne fortælle python, hvor python skal lede efter pakken ved at indstille PYTHONPATH
omgivelsesvariablen eller tilføje stien til sys.path
,
men det er langt fra ideelt: det ville kræve forskellige handlinger på forskellige
platforme, og den sti, du skal indstille, afhænger af placeringen af din kode.
En langt bedre måde er at installere din pakke ved hjælp af en setup.py
og pip
,
da pip
er standardmåden at installere alle andre pakker på, og den er bundet
til at fungere ens på alle platforme.
Et minimalt eksempel
Så hvordan ser en setup.py
-fil ud? Her er et minimalt eksempel0:
from setuptools import setup, find_packagessetup( name='example', version='0.1.0', packages=find_packages(include=))
Her angiver vi tre ting:
- Navnet på pakken, som er det navn, som
pip
vil bruge til din pakke.
Dette behøver ikke at være det samme som navnet på den mappe, pakken bor
i, selvom det kan være forvirrende, hvis det ikke er det. Et eksempel på, hvor pakke
navnet og mappen ikke passer sammen, er Scikit-Learn: du installerer den
ved hjælp afpip install scikit-learn
, mens du bruger den ved at importere frasklearn
. - Versionen af din pakke. Dette er den version
pip
vil rapportere, og bruges
for eksempel når du udgiver din pakke på PyPI1. - Hvilke pakker du skal inkludere; i vores tilfælde er dette bare
exampleproject/
.
Her lader visetuptools
regne dette ud
automatisk2. Mens du i princippet kunne brugefind_packages()
uden argumenter, kan dette potentielt resultere i, at uønskede pakker bliver
inkluderet. Dette kan f.eks. ske,
hvis du inkluderede en__init__.py
i dintests/
mappe. Alternativt kan du også brugeexclude
-argumentet for at eksplicit
forhindre medtagelsen af tests i pakken, men dette er lidt
mindre robust.
Nu er alt, hvad du skal gøre for at installere din pakke, at køre følgende
fra inde i example_project/
mappen3:
pip install -e .
Den .
her henviser til den aktuelle arbejdskatalog, som jeg antager er den mappe
, hvor setup.py
kan findes. Flaget -e
angiver, at vi ønsker at installere
i redigerbar tilstand, hvilket betyder
at når vi redigerer filerne i vores pakke, behøver vi ikke at geninstallere
pakken, før ændringerne træder i kraft. Du skal dog enten genstarte
python eller genindlæse pakken!
Når du redigerer oplysninger i selve setup.py
, skal du i de fleste tilfælde geninstallere
pakken, og også hvis du tilføjer nye (under)pakker.
Når du er i tvivl, kan det aldrig skade at geninstallere. Du skal bare køre pip install -e .
igen.
Krav
De fleste projekter har nogle afhængigheder. Du har højst sandsynligt brugt
en requirements.txt
fil før, eller en environment.yml
hvis du bruger conda
. Nu, hvor du opretter en setup.py
, kan du angive dine
afhængigheder i install_requires
-argumentet.
For eksempel kan du for et typisk datalogiprojekt have:
setup( name='example', version='0.1.0', packages=find_packages(include=), install_requires=)
Du kan angive krav uden en version (PyYAML
), fastgøre en version (pandas==0.23.3
), angive en minimum
version ('numpy>=1.14.5
) eller angive et versionsinterval (matplotlib>=2.2.0,<3.0.0
). Disse
krav vil automatisk blive installeret af pip
, når du installerer din pakke.
Extras-require
I nogle tilfælde kan du have afhængigheder, som kun er påkrævet i visse situationer. Som datavidenskabsmand
laver jeg ofte pakker, som jeg bruger til at træne en model. Når jeg arbejder interaktivt
på en sådan model, kan jeg have brug for at have matplotlib
og jupyter
installeret for interaktivt at arbejde med
dataene og for at oprette visualiseringer
af modellens ydeevne. På den anden side, hvis modellen kører i produktion, ønsker jeg ikke
at installere matplotlib
eller jupyter
på den maskine (eller container), hvor jeg træner
eller foretager inferens. Heldigvis giver setuptools
mulighed for at angive valgfrie afhængigheder i extras_require
:
setup( name='example', version='0.1.0', packages=find_packages(include=), install_requires=, extras_require={ 'interactive': , })
Nu, hvis vi installerer pakken normalt (pip install example
fra PyPI eller pip install -e .
lokalt)
, vil den kun installere afhængighederne PyYAML
, pandas
og numpy
. Men når vi angiver
at vi ønsker de valgfrie interactive
afhængigheder (pip install example
eller pip install -e .
),
så vil matplotlib
og jupyter
også blive installeret.
Skripter og indgangspunkter
Den vigtigste brugssituation for de fleste pythonpakker, som du installerer fra PyPI, er at levere funktionalitet
, som kan bruges i anden pythonkode. Med andre ord kan du import
fra disse pakker.
Som datalog laver jeg ofte pakker, der ikke er beregnet til at blive brugt af anden pythonkode, men
som skal gøre noget, f.eks. træne en model. Som sådan har jeg ofte et pythonscript, som
jeg ønsker at udføre fra kommandolinjen.
Den bedste måde4 at eksponere funktionaliteten i din pakke til kommandolinjen er at definere
en entry_point
som følger:
setup( # ..., entry_points={ 'console_scripts': })
Nu kan du bruge kommandoen my-command
fra kommandolinjen, som igen vil udføre main
funktionen inde i exampleproject/example.py
. Glem ikke at geninstallere – ellers vil kommandoen
ikke blive registreret.
Tests
Når du skriver kode, vil jeg kraftigt opfordre dig til også at skrive tests for denne kode. Til test
med python foreslår jeg, at du bruger pytest
. Selvfølgelig skal du ikke tilføje pytest
til dine afhængigheder
i install_requires
: det er ikke påkrævet af brugerne af din pakke. For at få det installeret
automatisk, når du kører tests, kan du tilføje følgende til din setup.py
:
setup( # ..., setup_requires=, tests_require=,)
Dertil skal du oprette en fil ved navn setup.cfg
med følgende indhold:
test=pytest
Nu kan du blot køre python setup.py test
, og setuptools
vil sikre, at de nødvendige afhængigheder
er installeret, og køre pytest
for dig! Tag et kig her, hvis
du vil angive argumenter eller indstille konfigurationsindstillinger for pytest
.
Hvis du har yderligere krav til testning (f.eks. pytest-flask
), kan du tilføje dem til tests_require
.
Flake8
Personligt synes jeg, at det er en god idé at køre Flake8 for at
kontrollere formateringen af din kode. Ligesom med pytest
skal du ikke tilføje flake8
tilinstall_requires
-afhængighederne: Det behøver ikke at være installeret for at kunne bruge din
pakke. I stedet kan du tilføje den til setup_requires
:
setup( # ..., setup_requires=)
Nu kan du blot køre python setup.py flake8
. Du kan selvfølgelig også fastgøre versionen
af flake8
(eller en hvilken som helst anden pakke) i setup_requires
.
Hvis du ønsker at ændre nogle af konfigurationsparametrene for Flake8 kan du tilføje et afsnit til
din setup.cfg
. For eksempel:
max-line-length=120
Pakkedata
I nogle tilfælde ønsker du måske at inkludere nogle ikke-pythonfiler i din pakke. Disse
kan f.eks. være skemafiler eller en lille opslagstabel. Vær opmærksom på, at sådanne filer
vil blive pakket sammen med din kode, så det er generelt en dårlig idé at inkludere
alle store filer.
Sæt, at vi har en schema.json
i vores projekt, som vi placerer i exampleproject/data/schema.json
.
Hvis vi ønsker at inkludere denne i vores pakke, skal vi bruge package_data
-argumentet i setup
:
setup( # ..., package_data={'exampleproject': })
Dette vil sikre, at filen inkluderes i pakken. Vi kan også vælge at inkludere
alle filer baseret på et mønster, for eksempel:
setup( # ..., package_data={'': })
Dette vil tilføje alle *.json
filer i enhver pakke, som den støder på.
Vend nu ikke selv at forsøge at finde ud af de installerede filers placering, dapkg_resources
har nogle meget praktiske bekvemmelighedsfunktioner:
-
pkg_resources.resource_stream
giver dig en stream af filen, ligesom det
objekt, du får, når du kalderopen()
, -
pkg_resources.resource_string
giver dig indholdet af filen som en streng, -
pkg_resources.resource_filename
vil give dig filnavnet på filen (og udpakke
den til en midlertidig hvis den er inkluderet i en zippet pakke) for hvis de to muligheder
ovenfor ikke passer til dine behov.
For eksempel kunne vi læse vores skema ind ved hjælp af:
from json import loadfrom pkg_resources import resource_streamschema = load(resource_stream('exampleproject', 'data/schema.json'))
Metadata
Hvis du vil udgive din pakke, så vil du sandsynligvis give dine
potentielle brugere nogle flere oplysninger om din pakke, herunder en beskrivelse,
navnet på forfatteren eller vedligeholderen og url’en til pakkens hjemmeside.
Du kan finde en komplet liste over alle tilladte metadata i setuptools
docs.
Dertil kommer, at hvis du vil udgive til PyPI, så vil du måske
automatisk indlæse indholdet af din README.md
i long_description
,
og levere klassifikatorer for at fortælle pip
endnu
mere om din pakke.
Vejledning
Denne blog skulle være et godt udgangspunkt for at opsætte de fleste af dine python-projekter.
Hvis du vil læse mere om python-pakning, så kig
på dokumentationen. Her er et eksempel setup.py
som kombinerer alle dele vist i denne blog:
from setuptools import setup, find_packagessetup( name='example', version='0.1.0', description='Setting up a python package', author='Rogier van der Geer', author_email='[email protected]', url='https://blog.godatadriven.com/setup-py', packages=find_packages(include=), install_requires=, extras_require={'plotting': }, setup_requires=, tests_require=, entry_points={ 'console_scripts': }, package_data={'exampleproject': })
og den tilhørende setup.cfg
:
test=pytestmax-line-length=120
Forbedre dine Python-færdigheder, lær af eksperterne!
På GoDataDriven tilbyder vi et væld af Python-kurser fra nybegynder til ekspert, undervist af de allerbedste fagfolk på området. Deltag hos os, og få et højere niveau i dit Python-spil:
- Python Essentials – Perfekt, hvis du lige er begyndt med Python.
- Certified Data Science with Python Foundation – Vil du tage skridtet fra dataanalyse og visualisering til ægte datavidenskab? Dette er det rigtige kursus.
- Advanced Data Science with Python – Lær at producere dine modeller som en professionel og bruge Python til maskinlæring.
Fodnoter
0: I denne blog har jeg brugt setuptools
til at opsætte mit eksempelprojekt. Alternativt
kan du også bruge distutils,
som er standardværktøjet til pakning i python, men det mangler funktioner
som f.eks. funktionen find_packages()
og entry_points
.
Da brugen af setuptools er meget almindelig i dag, og mange af dets funktioner
kan være særligt nyttige, foreslår jeg, at du bruger setuptools.
1: Hvis du ønsker, at versionen af din pakke også skal være tilgængelig inde i python,
så tag et kig her.
2: Du kunne også liste dine pakker manuelt, men dette er særligt fejlbehæftet.
3: Alternativt kunne du køre python setup.py install
, men at bruge pip
har
mange fordele, blandt andet automatisk installation af afhængigheder og den
mulighed for at afinstallere eller opdatere din pakke.
4: Du kunne også bruge scripts
-argumentet (se for
eksempel her)
men da dette kræver, at du opretter et python-shell-script, fungerer det måske ikke
så godt (eller slet ikke) på Windows.