Data & AI Training Guide 2021
Download de GoDataDriven-brochure voor een volledig overzicht van de beschikbare trainingen en de leertrajecten voor data-engineering, datawetenschap, data-analist en analytics-vertaler.
Wanneer u python op professionele wijze gebruikt, loont het de moeite om uw projecten
op een consistente manier op te zetten. Dit helpt uw medewerkers om snel de
structuur van een project te begrijpen, en maakt het gemakkelijker voor hen om het project
op hun machine op te zetten. De sleutel tot het opzetten van uw project is het setup.py
bestand.
In deze blog ga ik in op de details van dit bestand.
Waar we beginnen
Hierbij ga ik ervan uit dat u al een package heeft die u wilt opzetten.
Dit hoeft geen afgerond package te zijn – idealiter maakt u hetsetup.py
lang voordat uw project af is. Het kan zelfs een leeg pakket zijn;
zorg er alleen voor dat de pakketmap bestaat
en een bestand bevat met de naam init.py
(dat leeg mag zijn).
Als u de structuur
van mijn collega Henk voor uw project volgt, zou uw beginsituatie er ongeveer zo uit moeten zien:
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.
U mag andere bestanden of mappen in uw structuur hebben, bijvoorbeeld
mappen met de namen notebooks/
, tests/
of data/
, maar deze zijn niet vereist.
Het geval voor een setup.py
Als u eenmaal een pakket als dit hebt gemaakt, dan
zal u waarschijnlijk een deel van de code op andere plaatsen gebruiken. U zou bijvoorbeeld
dit kunnen doen in een notebook:
Dit zou werken als uw huidige werkdirectory example_project/
is, maar in
alle andere gevallen zal python u uitvoer geven zoals:
ModuleNotFoundError: No module named 'exampleproject'
Je zou python kunnen vertellen waar het pakket gezocht moet worden door de PYTHONPATH
omgevingsvariabele in te stellen of het pad toe te voegen aan sys.path
,
maar dat is verre van ideaal: het zou verschillende acties vereisen op verschillende
platforms, en het pad dat je moet instellen is afhankelijk van de locatie van je code.
Een veel betere manier is om uw pakket te installeren met een setup.py
en pip
,
sinds pip
de standaard manier is om alle andere pakketten te installeren, en het is gebonden
het werkt hetzelfde op alle platforms.
Een minimaal voorbeeld
Zo hoe ziet een setup.py
bestand er uit? Hier is een minimaal voorbeeld0:
from setuptools import setup, find_packagessetup( name='example', version='0.1.0', packages=find_packages(include=))
Hier specificeren we drie dingen:
- De naam van het pakket, dat is de naam die
pip
zal gebruiken voor uw pakket.
Dit hoeft niet hetzelfde te zijn als de mapnaam waarin het pakket
leeft, hoewel het verwarrend kan zijn als het dat niet is. Een voorbeeld van waar de package
naam en de directory niet overeenkomen is Scikit-Learn: u installeert het
metpip install scikit-learn
, terwijl u het gebruikt door te importeren uitsklearn
. - De versie van uw package. Dit is de versie die
pip
zal rapporteren, en wordt gebruikt
bij voorbeeld wanneer u uw pakket publiceert op PyPI1. - Welke pakketten u moet includen; in ons geval is dat gewoon
exampleproject/
.
Hier laten wesetuptools
dit
automatisch uitzoeken2. Hoewel ufind_packages()
in principe zonder argumenten zou kunnen gebruiken, kan dit er mogelijk toe leiden dat ongewenste pakketten
worden opgenomen. Dit kan bijvoorbeeld gebeuren
als u een__init__.py
in uwtests/
directory hebt opgenomen. U kunt ook hetexclude
-argument gebruiken om expliciet
te voorkomen dat tests in het pakket worden opgenomen, maar dit is iets
minder robuust.
Het enige dat u nu nog hoeft te doen om uw pakket te installeren, is het volgende
uitvoeren vanuit de example_project/
directory3:
pip install -e .
De .
hier verwijst naar de huidige werkdirectory, waarvan ik aanneem dat het de directory
is waar de setup.py
te vinden is. De -e
vlag geeft aan dat we
in bewerkbare modus willen installeren, wat betekent
dat wanneer we de bestanden in ons pakket bewerken, we het
pakket niet opnieuw hoeven te installeren voordat de wijzigingen van kracht worden. U moet
python wel opnieuw opstarten of het pakket opnieuw laden!
Wanneer u informatie in de setup.py
zelf wijzigt, moet u het pakket in de meeste gevallen opnieuw
installeren, en ook als u nieuwe (sub)pakketten toevoegt.
Wanneer u twijfelt, kan het nooit kwaad om opnieuw te installeren. Voer pip install -e .
gewoon opnieuw uit.
Requirements
De meeste projecten hebben enkele dependencies. U hebt waarschijnlijk al eerder een requirements.txt
bestand gebruikt, of een environment.yml
als u conda
gebruikt. Nu u een setup.py
maakt, kunt u uw
afhankelijkheden opgeven in het install_requires
argument.
Voor een typisch data science project hebt u bijvoorbeeld:
setup( name='example', version='0.1.0', packages=find_packages(include=), install_requires=)
U kunt vereisten opgeven zonder een versie (PyYAML
), een versie vastpinnen (pandas==0.23.3
), een minimum
versie opgeven ('numpy>=1.14.5
) of een bereik van versies instellen (matplotlib>=2.2.0,<3.0.0
). Deze
vereisten worden automatisch door pip
geïnstalleerd wanneer u uw pakket installeert.
Extras-require
Soms kunt u afhankelijkheden hebben die alleen in bepaalde situaties vereist zijn. Als data scientist
maak ik vaak pakketten die ik gebruik om een model te trainen. Als ik interactief
aan zo’n model werk, kan het zijn dat ik matplotlib
en jupyter
geïnstalleerd moet hebben om interactief met de
gegevens te kunnen werken en
visualisaties
van de prestaties van het model te kunnen maken. Aan de andere kant, als het model in productie
draait, wil ik matplotlib
noch jupyter
installeren op de machine (of container) waar ik
train of inferentie doe. Gelukkig staat setuptools
toe om optionele afhankelijkheden op te geven in extras_require
:
setup( name='example', version='0.1.0', packages=find_packages(include=), install_requires=, extras_require={ 'interactive': , })
Nu als we het pakket normaal installeren (pip install example
van PyPI of pip install -e .
lokaal)
zal het alleen de afhankelijkheden PyYAML
, pandas
en numpy
installeren. Wanneer we echter
specificeren dat we de optionele interactive
afhankelijkheden willen (pip install example
of pip install -e .
),
dan zullen matplotlib
en jupyter
ook worden geinstalleerd.
Scripts en toegangspunten
Het belangrijkste gebruik van de meeste python pakketten die u installeert van PyPI is om functionaliteit
te bieden die kan worden gebruikt in andere python code. Met andere woorden, je kunt import
van die pakketten gebruikmaken.
Als datawetenschapper maak ik vaak pakketten die niet bedoeld zijn om door andere python-code te worden gebruikt, maar
bedoeld zijn om iets te doen, bijvoorbeeld om een model te trainen. Als zodanig heb ik vaak een python-script dat
ik vanaf de opdrachtregel wil uitvoeren.
De beste manier4 om functionaliteit van je pakket aan de opdrachtregel bloot te stellen, is om
een entry_point
als volgt te definiëren:
setup( # ..., entry_points={ 'console_scripts': })
Nu kun je het commando my-command
vanaf de opdrachtregel gebruiken, dat op zijn beurt de main
functie in exampleproject/example.py
zal uitvoeren. Vergeet niet opnieuw te installeren – anders wordt het commando
niet geregistreerd.
Tests
Wanneer u code schrijft, moedig ik u sterk aan om ook tests voor deze code te schrijven. Voor het testen
met python stel ik voor dat u pytest
gebruikt. Natuurlijk wilt u pytest
niet toevoegen aan uw dependencies
in install_requires
: het is niet nodig voor de gebruikers van uw pakket. Om het
automatisch te laten installeren wanneer u tests uitvoert, kunt u het volgende toevoegen aan uw setup.py
:
setup( # ..., setup_requires=, tests_require=,)
Extra moet u een bestand met de naam setup.cfg
maken met de volgende inhoud:
test=pytest
Nu kunt u gewoon python setup.py test
uitvoeren en setuptools
zal ervoor zorgen dat de nodige afhankelijkheden
worden geïnstalleerd en pytest
voor u uitvoeren! Kijk hier als
u argumenten wilt geven of configuratie opties wilt instellen voor pytest
.
Als u extra vereisten hebt voor het testen (b.v. pytest-flask
) kunt u ze toevoegen aan tests_require
.
Flake8
Persoonlijk denk ik dat het een goed idee is om Flake8 te draaien om
de opmaak van uw code te controleren. Net als met pytest
, wilt u flake8
niet toevoegen aan deinstall_requires
afhankelijkheden: het hoeft niet geïnstalleerd te zijn om uw
pakket te kunnen gebruiken. In plaats daarvan kunt u het toevoegen aan setup_requires
:
setup( # ..., setup_requires=)
Nu kunt u gewoon python setup.py flake8
uitvoeren. Natuurlijk kunt u ook de versie
van flake8
(of een ander pakket) in setup_requires
.
Als u enkele configuratieparameters van Flake8 wilt wijzigen, kunt u een sectie toevoegen aan
uw setup.cfg
. Bijvoorbeeld:
max-line-length=120
Pakketgegevens
Soms kan het zijn dat u enkele niet-python bestanden in uw pakket wilt opnemen. Dit
kunnen bijvoorbeeld schema-bestanden zijn of een kleine opzoektabel. Wees u ervan bewust dat dergelijke bestanden
samen met uw code zullen worden verpakt, dus het is in het algemeen een slecht idee om
alle grote bestanden op te nemen.
Voorstel dat we een schema.json
in ons project hebben, die we in exampleproject/data/schema.json
plaatsen.
Als we dit in ons pakket willen opnemen, moeten we het package_data
-argument van setup
gebruiken:
setup( # ..., package_data={'exampleproject': })
Dit zal ervoor zorgen dat het bestand in het pakket wordt opgenomen. We kunnen er ook voor kiezen om
alle bestanden op te nemen op basis van een patroon, bijvoorbeeld:
setup( # ..., package_data={'': })
Dit zal alle *.json
bestanden toevoegen in elk pakket dat het tegenkomt.
Probeer nu niet zelf uit te zoeken waar de geïnstalleerde bestanden zich bevinden, wantpkg_resources
heeft enkele zeer handige handige functies:
-
pkg_resources.resource_stream
geeft u een stream van het bestand, vergelijkbaar met het
object dat u krijgt wanneer uopen()
aanroept, -
pkg_resources.resource_string
geeft u de inhoud van het bestand als een string, -
pkg_resources.resource_filename
geeft u de bestandsnaam van het bestand (en pakt
het uit in een tijdelijk als het in een gezipt pakket zit) voor als de twee opties
hierboven niet aan uw behoeften voldoen.
Zo zouden we bijvoorbeeld ons schema kunnen inlezen met:
from json import loadfrom pkg_resources import resource_streamschema = load(resource_stream('exampleproject', 'data/schema.json'))
Metadata
Als u uw pakket gaat publiceren, dan wilt u uw
potentiële gebruikers waarschijnlijk wat meer informatie geven over uw pakket, waaronder een beschrijving,
de naam van de auteur of de onderhouder, en de url naar de homepage van het pakket.
Een volledige lijst van alle toegestane metagegevens is te vinden in de setuptools
documenten.
Aanvullend, als u gaat publiceren naar PyPI, dan wilt u wellicht
automatisch de inhoud van uw README.md
in de long_description
laden,
en classifiers meegeven om pip
nog
meer over uw pakket te vertellen.
Wrap-up
Deze blog zou een goed startpunt moeten zijn om de meeste van uw python projecten op te zetten.
Als u meer wilt lezen over python packaging kijk dan
in de docs. Hier is een voorbeeld setup.py
waarin alle onderdelen uit deze blog zijn gecombineerd:
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': })
en de bijbehorende setup.cfg
:
test=pytestmax-line-length=120
Verbeter uw Python vaardigheden, leer van de experts!
Bij GoDataDriven bieden we een groot aantal Python cursussen aan van beginner tot expert, gegeven door de allerbeste professionals in het veld. Doe mee en verbeter je Python-spel:
- Python Essentials – Geweldig als je net begint met Python.
- Certified Data Science with Python Foundation – Wil je de stap maken van data-analyse en visualisatie naar echte data science? Dan is dit de juiste cursus.
- Advanced Data Science with Python – Leer als een pro je modellen te produceren en Python te gebruiken voor machine learning.
Footnotes
0: In deze blog heb ik setuptools
gebruikt om mijn voorbeeldproject op te zetten. Als alternatief
kunt u ook distutils gebruiken,
dat is de standaard tool voor het verpakken in python, maar het mist functies
zoals de find_packages()
functie en entry_points
.
Omdat het gebruik van setuptools tegenwoordig heel gewoon is en veel van zijn functies
bijzonder nuttig kunnen zijn, stel ik voor dat u setuptools gebruikt.
1: Als u wilt dat de versie van uw pakket ook in python beschikbaar is,
kijk dan hier.
2: U zou uw pakketten ook handmatig kunnen inventariseren, maar dit is bijzonder foutgevoelig.
3: Als alternatief zou u python setup.py install
kunnen uitvoeren, maar het gebruik van pip
heeft
veel voordelen, waaronder de automatische installatie van afhankelijkheden en de
mogelijkheid om uw pakket te verwijderen of te updaten.
4: U zou ook het scripts
argument kunnen gebruiken (zie voor
voorbeeld hier)
maar aangezien dit vereist dat u een python shell script maakt, werkt het misschien niet
zo goed (of helemaal niet) op Windows.