9. De imports
De fout die we in versie 1 van de toepassingsopdracht tegenkwamen, zet ons ertoe aan de rol van de instructie [import] nader te onderzoeken.

9.1. Scripts [import_01]
Het script [imported] wordt geïmporteerd door verschillende scripts (ook wel modules genoemd):

# module geïmporteerd
# deze instructie wordt telkens uitgevoerd wanneer de module wordt geïmporteerd
print("2")
# variabele die bij de geïmporteerde module hoort
x=4
Een module wordt uitgevoerd wanneer deze wordt geïmporteerd. Dus wanneer de module [imported] wordt geïmporteerd:
- wordt de weergave van regel 3 uitgevoerd;
- krijgt de variabele x in regel 5 zijn waarde;
Het script [main_01] is als volgt:
# een geïmporteerde module wordt uitgevoerd
import imported
# gebruik van de variabele x uit de geïmporteerde module
print(imported.x)
- regel 2: de module [imported] wordt geïmporteerd. Dit zorgt ervoor dat deze wordt uitgevoerd:
- de waarde 2 wordt weergegeven;
- de variabele x wordt aangemaakt met de waarde 4;
- regel 4: de variabele x van de geïmporteerde module wordt gebruikt;
In PyCharm wordt een fout gemeld:
In [1] geeft PyCharm aan dat het de module [imported] niet kent. Technisch gezien betekent dit dat de map met de module [imported] niet in het Python-pad van PyCharm staat. Het Python-pad is de verzameling mappen waarin naar geïmporteerde modules wordt gezocht. Om dit probleem op te lossen, volstaat het om aan [Sources root] de map toe te wijzen waarin de module [imported] zich bevindt, in dit geval de map [import/01]:


Na deze handeling wordt de map [import/01] toegevoegd aan het Python Path van PyCharm en verdwijnt de foutmelding:

- in [1] is de map [01] van kleur veranderd;
- in [2-3] is er geen fout meer;
De resultaten van de uitvoering zijn als volgt:
Opmerkingen
- regel 2 is het resultaat van de uitvoering van de geïmporteerde module;
- regel 3 geeft de waarde van de variabele x van de geïmporteerde module weer;
Wat we uit dit voorbeeld kunnen onthouden, is het belangrijke concept dat een geïmporteerde module (of een script) wordt uitgevoerd.
Het script [main_02] is als volgt:
# de variabele x van de geïmporteerde module wordt geïmporteerd
from imported import x
# de variabele wordt weergegeven
print(x)
- In regel 2 zien we een andere syntaxis voor het importeren van [from module import objet1, objet2, …]. Hier wordt de variabele [imported.x] geïmporteerd. Met deze syntaxis wordt de variabele x een variabele van het script [main_02]. Het is niet meer nodig om deze te laten voorafgaan door de module [imported];
- regel 4: de variabele x van [main_02] wordt weergegeven;
De resultaten van de uitvoering zijn als volgt:
Het script [main_03] is als volgt:
# alles wat zichtbaar is uit de geïmporteerde module wordt geïmporteerd
from imported import *
# de variabele x van de geïmporteerde module wordt gebruikt
print(x)
De notatie [import *] in regel 2 betekent dat alle zichtbare objecten van de geïmporteerde module (variabelen, functies) worden geïmporteerd.
De resultaten zijn als volgt:
Het script [main_04] is als volgt:
# de variabele x uit de geïmporteerde module wordt geïmporteerd
# en hernoemen deze naar y
from imported import x as y
# de variabele y wordt weergegeven
print(y)
Regel 3 laat zien dat je een object uit de geïmporteerde module kunt importeren en er een alias aan kunt geven. Hier wordt de variabele [imported.x] de variabele [main_04.y]. De resultaten zijn hetzelfde als eerder.
9.2. Script [import_02]

De geïmporteerde module [module1.py] is hier als volgt:
# een functie
def f1():
print("f1")
De geïmporteerde module definieert een functie, wat vaak voorkomt.
Het script [main_01] is als volgt:
# import
import module1
# uitvoering van f1
module1.f1()
- regel 2: de module wordt geïmporteerd. Deze zal worden uitgevoerd. Hier wordt niets weergegeven;
- regel 4: de functie [f1] van de geïmporteerde module wordt uitgevoerd;
De resultaten van de uitvoering zijn als volgt:
Opmerking: Om te voorkomen dat PyCharm een foutmelding geeft bij het importeren van regel 2, moet de map met [module1] in de map [Sources Root] van PyCharm worden geplaatst:

In [1] is het dossier [02], dat in [Sources Root] is geplaatst, blauw geworden. Opgemerkt moet worden dat de gemelde fout hier de correcte uitvoering van de scripts niet verhindert. Bij de uitvoering van het script [main_0x] wordt de map van het script namelijk automatisch aan het Python Path toegevoegd. Daardoor wordt [module1] gevonden. Als voortaan op een schermafbeelding een map blauw is, betekent dit dat deze is toegevoegd aan de [Sources Root] van PyCharm.
Het script [main_02] is als volgt:
# importeren
from module1 import f1
# uitvoering van f1
f1()
- in regel 2 wordt de functie [f1] uit de module [module1] geïmporteerd;
- in regel 4 wordt de functie f1 gebruikt;
De resultaten zijn identiek aan die van het script [main_01].
9.3. Scripts [import_03]

Opmerking: [03] bevindt zich in de [Sources Root] van het project.
De nieuwe scripts importeren de module [module2], die zich niet in dezelfde map bevindt als de scripts zelf.
Het script [module2] is als volgt:
# een functie
def f2():
print("f2")
Het script definieert dus een functie [f2].
Het script [main_01] is als volgt:
# import van de module Class2
import dir1.module2
# uitvoering f2
dir1.module2.f2()
- regel 2: er wordt een speciale notatie gebruikt om aan te geven hoe de module [module2] kan worden gevonden. [dir1.module2] moet worden gelezen als het pad [dir1/module2]: om [module2] te vinden, begint men bij de map van het huidige script [main_01], gaat vervolgens naar [dir1] en daar vindt men [module2]. Vergeet hierbij niet dat het startpunt van het pad de map is waarin het script zich bevindt;
- regel 4: om de functie [f2] van [module2] uit te voeren;
De resultaten zijn als volgt:
Regel 2, het resultaat van de functie [f2].
Het script [main_02] is als volgt:
# de module dir1.module2 importeren en hernoemen
import dir1.module2 as module2
# uitvoering van f2
module2.f2()
Regel 2: de module [dir1.module] wordt hernoemd om het schrijven van regel 4 te vereenvoudigen.
Het script [main_03] is als volgt:
# de functie f2 uit de module dir1.module2 importeren
from dir1.module2 import f2
# uitvoering van f2
f2()
Deze keer importeren we in regel 2 alleen de functie [f2], die daarmee een functie van het script [main_03] wordt (regel 4).
Al deze scripts werken zowel in de context van PyCharm als in die van een Python-console. De reden hiervoor is dat in beide gevallen de map van het uitgevoerde script, in dit geval de map [03], deel uitmaakt van het Python Path. Daardoor wordt de map [dir1/module2] gevonden.
9.4. Scripts [import_04]

Hier zijn de mappen [dir1] en [dir2] in de map [Sources Root] van het project PyCharm geplaatst.
De eerste geïmporteerde module is [module3]:
# een functie
def f3():
print("f3")
De tweede geïmporteerde module is [module4]:
from module3 import f3
# een functie
def f4():
f3()
print("f4")
- in regel 1 wordt de functie [f3] geïmporteerd vanuit [module3]. Hier is [module3] zichtbaar omdat de bijbehorende map [dir1] in de map [Sources Root] is geplaatst;
- regels 4-6: we definiëren een functie [f4] die de functie [f3] van [module3] aanroept;
Het hoofdscript [main_01] ziet er als volgt uit:
# module4 wordt geïmporteerd
from module4 import f4
# uitvoering f4
f4()
- in regel 2 wordt de module [module4] geïmporteerd. Deze is zichtbaar omdat de bijbehorende map [dir2] is opgenomen in de map [Sources Root] van PyCharm;
- regel 4: uitvoering van de functie [f4] vanuit [module4];
De resultaten van de uitvoering van [main_01] in PyCharm zijn als volgt:
Laten we nu [main_01] uitvoeren in een Python-terminal (console):

De resultaten zijn als volgt:
Wat is er gebeurd? De Python-terminal heeft geen kennis van het Python-pad en van [Sources Root] en PyCharm. Het heeft zijn eigen Python-pad. Daarin staat altijd de map van het script dat wordt uitgevoerd, in dit geval het script [main_01]. Het kent dus de map [import/04]. In het uitgevoerde script vindt het de regel:
from module4 import f4
De Python-interpreter zoekt naar [module4] in de mappen van zijn Python-pad. Maar [module4] bevindt zich niet in [import/04] – dat wel degelijk in het Python Path staat – maar in [import/04/dir2], dat daar niet in staat. Vandaar de foutmelding.
We hebben dus te maken met een probleem dat we al eerder zijn tegengekomen: een script dat correct wordt uitgevoerd in PyCharm kan crashen in de context van een Python-terminal. Dit is een terugkerend probleem dat we zullen moeten oplossen.
9.5. Scripts [import_05]

Opmerking: de mappen [dir1] en [dir2] worden toegevoegd aan het Python-pad. Laten we alvast opmerken dat er hier een conflict is: [module3] en [module4] worden op twee plaatsen in het Python-pad van PyCharm aangetroffen:
- in [import/04/dir1] en [import/05/dir1] voor [module3];
- in [import/04/dir2] en [import/05/dir2] voor [module4];
We kunnen dan [import/04/dir1] en [import/04/dir2] uit de [Sources Root] van het project PyCharm halen. Het blijkt dat [import/05/dir1] hier een kopie is van [import/04/dir1] (hetzelfde geldt voor [dir2]) en dat er dus geen probleem is. Maar let er wel op dat je binnen PyCharm goed moet letten op de lijst met mappen van [Sources Root] om conflicten te voorkomen.
Het script [main_01] ziet er als volgt uit:
import sys
# we wijzigen sys.path om de mappen toe te voegen
# die de te importeren klassen bevatten
sys.path.append(".")
sys.path.append("./dir1")
sys.path.append("./dir2")
# module4 importeren
from module4 import f4
# uitvoering f4
f4()
We proberen het probleem met het Python-pad op te lossen. We willen er een die zowel onder PyCharm als in een Python-terminal goed werkt. Daarom gaan we dit zelf oplossen.
- regels 4-6: we voegen de mappen [., ./dir1, ./dir2] toe aan het Python-pad. Om dit te laten werken, moet de huidige map op het moment van uitvoering de map [import/05] zijn. Dit is het geval in PyCharm, maar niet noodzakelijkerwijs in een Python-terminal, zoals we zullen zien;
- regel 8: we importeren [module4]. Na wat we zojuist hebben gedaan, zou dit in [./dir2] moeten worden gevonden;
De uitvoering in PyCharm levert de volgende resultaten op:
Nu, in een Python-terminal:
(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\import\05>python main_01.py
f3
f4
Regel 1: de uitvoermap is [import/05].
Laten we nu één niveau omhoog gaan in de boomstructuur van [import/05]:
(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\import\05>cd ..
(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\import>python 05/main_01.py
Traceback (most recent call last):
File "05/main_01.py", line 8, in <module>
from module4 import f4
ModuleNotFoundError: No module named 'module4'
- regel 2: wanneer [main_01] wordt uitgevoerd, bevinden we ons niet meer in de map [import/05], maar in [import]. We hebben echter geschreven:
sys.path.append(".")
sys.path.append("./dir1")
sys.path.append("./dir2")
Dit voegt de mappen [import, import/dir1, import/dir2] toe aan het Python-pad, wat helemaal niet de bedoeling is. Merk op dat het toevoegen van mappen aan het Python-pad die niet bestaan (import/dir1, import/dir2) geen fouten veroorzaakt.
We zijn vooruitgegaan, maar dit is nog niet voldoende. We moeten aan het Python-pad geen relatieve paden toevoegen, maar absolute paden.
Het script [main_02] is een variant van [main_01] die gebruikmaakt van een configuratiebestand [config.json]:
{
"dependencies": [
"C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/import/05/dir1",
"C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/import/05/dir2"
]
}
De waarde van de sleutel [dependencies] is de lijst met mappen die aan het Python-pad moeten worden toegevoegd. Let op: hier zijn absolute paden opgegeven en geen relatieve.
Het script [main_02] gebruikt het bestand [config.json] op de volgende manier:
import codecs
import json
import sys
# configuratiebestand
config_filename="C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/import/05/config.json"
# het json-configuratiebestand inlezen
with codecs.open(config_filename, "r", "utf-8") as file:
config = json.load(file)
# wijziging van sys.path
for directory in config['dependencies']:
sys.path.append(directory)
# module4 wordt geïmporteerd
from module4 import f4
# uitvoering van f4
f4()
- regel 6: let op dat de absolute naam van het configuratiebestand is gebruikt;
- regels 8-9: het configuratiebestand wordt ingelezen. Met de inhoud ervan wordt een woordenboek [config] (regel 9) samengesteld;
- regels 11-13: de elementen van de array [config['dependencies']] worden toegevoegd aan het Python-pad. Merk op dat, aangezien we absolute mapnamen in [config.json] hebben opgegeven, we absolute namen aan het Python-pad toevoegen;
- regel 16: [module4] wordt geïmporteerd. Dit zou moeten lukken, aangezien [dir2] zich nu in het Python Path bevindt;
De uitvoering levert dezelfde resultaten op als voor [main_02], behalve dat het script blijft werken wanneer de uitvoermap niet langer [import/05] is:
(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\import>python 05/main_02.py
f3
f4
Regel 1: de uitvoermap is [import].
We zijn een stap verder gekomen. We hebben gezien:
- dat we het Python-pad zelf moesten samenstellen;
- dat we daarin de absolute paden moesten vermelden van alle mappen die de door de applicatie geïmporteerde modules bevatten;
Toch is het vermelden van absolute paden in scripts geen oplossing. Zodra het project naar een andere locatie wordt verplaatst, werkt het niet meer. We moeten iets anders bedenken.
9.6. Scripts [import_06]

Opmerking: de mappen [06, dir1, dir2] zijn geplaatst in de mappen [Sources Root] van het project PyCharm. De mappen [dir1, dir2] zijn identiek aan die in de voorgaande voorbeelden.
Het bestand [config.json] ziet er als volgt uit:
{
"rootDir": "C:/Data/st-2020/dev/python/cours-2020/v-02/imports/06",
"relativeDependencies": [
"dir1",
"dir2"
],
"absoluteDependencies": [
]
}
We introduceren twee soorten paden:
- absolute paden, regels 7-8;
- relatieve paden, regels 3-6. Deze zijn relatief ten opzichte van de root op regel 2. Wanneer het project dus van locatie verandert, hoeft alleen deze regel te worden aangepast;
Het script [utils.py] gebruikt het bestand [config.json] en stelt het Python-pad samen:
# imports
import codecs
import json
import os
import sys
# configuratie van de applicatie
def config_app(config_filename: str) -> dict:
# config_filename: naam van het configuratiebestand
# uitzonderingen doorgeven
# verwerking van het configuratiebestand
with codecs.open(config_filename, "r", "utf-8") as file:
config = json.load(file)
# afhankelijkheden toevoegen aan sys.path
rootDir = config['rootDir']
# de relatieve afhankelijkheden van het project worden toegevoegd aan de syspath
for directory in config['relativeDependencies']:
# de afhankelijkheid wordt aan het begin van de syspath toegevoegd
sys.path.insert(0, f"{rootDir}/{directory}")
# de absolute afhankelijkheden van het project worden aan de syspath toegevoegd
for directory in config['absoluteDependencies']:
# de afhankelijkheid wordt aan het begin van de syspath toegevoegd
sys.path.insert(0, directory)
# het configuratiedictionary wordt aangemaakt
return config
# map van het uitgevoerde script
def get_scriptdir():
return os.path.dirname(os.path.abspath(__file__))
- regel 8: de functie [config_app] ontvangt de naam van het configuratiebestand als parameter;
- regels 12-14: het configuratiebestand wordt gebruikt om het woordenboek [config] aan te maken;
- regel 20: [sys.path] is de lijst met mappen van het Python-pad;
- regels 17-20: de relatieve afhankelijkheden uit het configuratiebestand worden toegevoegd aan het Python Path. Ze worden toegevoegd aan het begin van de array [sys.path], regel 20. Wanneer Python namelijk naar een module zoekt, doorzoekt het de mappen van [sys.path] in volgorde. In dit document bevinden modules met dezelfde naam zich echter in verschillende mappen van de [sys.path]. Door de afhankelijkheden van de applicatie aan het begin van de tabel [sys.path] te plaatsen, zorgen we ervoor dat deze worden doorzocht vóór andere mappen van [sys.path] die modules met dezelfde naam zouden kunnen bevatten;
- regels 21-24: de absolute afhankelijkheden van het configuratiebestand worden toegevoegd aan het Python Path;
- regel 26: de configuratie van de applicatie wordt teruggegeven;
- regels 29-30: de functie [get_scriptdir] retourneert de absolute mapnaam van het script dat momenteel wordt uitgevoerd (de map waarin de functie wordt aangeroepen);
Het hoofdscript [main] ziet er als volgt uit:
# imports
import sys
from utils import config_app
def affiche_path(msg: str):
# bericht
print(f"{msg}------------------------------")
# sys.path
for path in sys.path:
print(path)
# main -------------
try:
# de sys.path is geconfigureerd
affiche_path("avant....")
config = config_app(f"{get_scriptdir()}/config.json")
affiche_path("après....")
# module4 wordt geïmporteerd
from module4 import f4
# uitvoering f4
f4()
except BaseException as erreur:
print(f"L'erreur suivante s'est produite : {erreur}")
finally:
print("done")
- regel 4: de functie [config_app] wordt geïmporteerd. Merk op dat, aangezien [utils] en [main] zich in dezelfde map bevinden, deze [import] altijd werkt. De map van het hoofdscript wordt namelijk automatisch toegevoegd aan het Python-pad;
- regels 7-12: de functie [affiche_path] geeft de lijst met mappen van het Python-pad weer;
- regel 19: we configureren de applicatie. Merk op dat we de absolute naam van het configuratiebestand doorgeven aan de functie [config_app]. Na deze instructie is het Python-pad opnieuw opgebouwd;
- regel 22: we importeren [module4]. Dankzij de heropbouw van het Python-pad zal deze module worden gevonden;
- regel 24: de functie [f4] wordt uitgevoerd;
In de context PyCharm zijn de resultaten van de uitvoering als volgt:
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/import/06/main.py
avant....------------------------------
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\import\06
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\fonctions\shared
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\impots\v01\shared
…
C:\Program Files\Python38\python38.zip
C:\Program Files\Python38\DLLs
C:\Program Files\Python38\lib
C:\Program Files\Python38
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\lib\site-packages
après....------------------------------
C:/Data/st-2020/dev/python/cours-2020/v-02/imports/06/dir2
C:/Data/st-2020/dev/python/cours-2020/v-02/imports/06/dir1
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\import\06
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\fonctions\shared
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\impots\v01\shared
….
C:\Program Files\Python38\python38.zip
C:\Program Files\Python38\DLLs
C:\Program Files\Python38\lib
C:\Program Files\Python38
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\lib\site-packages
f3
f4
done
Process finished with exit code 0
Opmerkingen
- regels 2-13: het Python Path van PyCharm. Hierin staan alle mappen die in de [Sources Root] van het project zijn geplaatst;
- regels 14-29: het Python-pad dat door de functie [config_app] is samengesteld. Op regels 15-16 staan de twee afhankelijkheden die we hebben toegevoegd;
- regels 22-27: de systeemmappen van de Python-interpreter die het script heeft uitgevoerd;
- regels 28-29: de uitvoering verloopt normaal;
Laten we nu eens kijken naar de context die tot nu toe een uitvoeringsfout veroorzaakte:
- we openen een Python-terminal;
- we gaan naar een andere map dan die waarin het uitgevoerde script staat;
(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\import>python 06/main.py
avant....------------------------------
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\import\06
C:\Program Files\Python38\python38.zip
C:\Program Files\Python38\DLLs
C:\Program Files\Python38\lib
C:\Program Files\Python38
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\lib\site-packages
après....------------------------------
C:/Data/st-2020/dev/python/cours-2020/v-02/imports/06/dir2
C:/Data/st-2020/dev/python/cours-2020/v-02/imports/06/dir1
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\import\06
C:\Program Files\Python38\python38.zip
C:\Program Files\Python38\DLLs
C:\Program Files\Python38\lib
C:\Program Files\Python38
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\lib\site-packages
f3
f4
done
Deze keer gaat het goed (regels 20-21). Merk op dat [sys.path] niet dezelfde mappen bevat als wanneer de uitvoering plaatsvindt onder PyCharm.
9.7. Scripts [import_07]
We verbeteren de vorige oplossing op twee manieren:
- we vervangen het configuratiebestand [config.json] door een script [config.py]. Het bestand jSON levert namelijk een groot probleem op: er kunnen geen opmerkingen in worden geplaatst. Het woordenboek [config.json] kan worden vervangen door een Python-woordenboek, dat het voordeel heeft dat er opmerkingen in kunnen worden geplaatst;
- we gebruiken een module die zichtbaar is voor alle Python-projecten op de machine;
9.7.1. Installatie van een module met machinebreed bereik

Hierboven maken we een map [packages/myutils] aan in het project PyCharm (de namen doen er niet toe).
Het script [myutils.py] ziet er als volgt uit:
# import
import sys
import os
def set_syspath(absolute_dependencies: list):
# absolute_dependencies: een lijst met absolute mapnamen
# de absolute afhankelijkheden van het project worden aan de syspath toegevoegd
for directory in absolute_dependencies:
# er wordt gecontroleerd of de map bestaat
existe = os.path.exists(directory) and os.path.isdir(directory)
if not existe:
# er wordt een uitzondering gegenereerd
raise BaseException(f"[set_syspath] le dossier du Python Path [{directory}] n'existe pas")
else:
# de map wordt aan het begin van de syspath toegevoegd
sys.path.insert(0, directory)
- regels 6-18: de functie [set_syspath] maakt een Python Path aan met de lijst van mappen die als parameter wordt doorgegeven;
- regels 12-15: er wordt gecontroleerd of de map die aan het Python Path moet worden toegevoegd, bestaat;
Het script [__init.py__] (twee onderstrepingstekens voor en achter de naam; dit is verplicht) ziet er als volgt uit:
from .myutils import set_syspath
We importeren de functie [set_syspath] uit het script [myutils]. De notatie [.myutils] verwijst naar het pad [./myutils], dus het script [myutils] bevindt zich in dezelfde map als [__init.py]. We hadden ook de notatie [myutils] kunnen gebruiken. We gaan echter een module [myutils] met machinebereik aanmaken. Daardoor zou de notatie [from myutils import set_syspath] dan dubbelzinnig worden. Moet het script [myutils] uit de huidige map worden geïmporteerd of het script [myutils] met machinebereik? De notatie [.myutils] neemt deze dubbelzinnigheid weg.
Het script [setup.py] (ook hier is de naam voorgeschreven) luidt als volgt:
from setuptools import setup
setup(name='myutils',
version='0.1',
description='Utilitaire fixant le Python Path',
url='#',
author='st',
author_email='st@gmail.com',
license='MIT',
packages=['myutils'],
zip_safe=False)
In dit script wordt de module beschreven die we gaan aanmaken. Hier gaan we deze lokaal aanmaken. Maar hetzelfde proces wordt gebruikt om een officieel gedistribueerde module aan te maken (zie |pypi|). De belangrijke punten zijn hier de volgende:
- regel 3: de naam van de aangemaakte module;
- regel 4: de versie van de module;
- regel 5: de beschrijving;
- regels 7-8: de auteur van de module;
Om deze module met een machine-scope te installeren, gaan we als volgt te werk:

Vervolgens voert u in de Python-terminal de volgende opdracht in: [pip install .]:
(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\packages>pip install .
Processing c:\data\st-2020\dev\python\cours-2020\python3-flask-2020\packages
Using legacy setup.py install for myutils, since package 'wheel' is not installed.
Installing collected packages: myutils
Attempting uninstall: myutils
Found existing installation: myutils 0.1
Uninstalling myutils-0.1:
Successfully uninstalled myutils-0.1
Running setup.py install for myutils ... done
Successfully installed myutils-0.1
Vanaf nu kan elk script op de machine de module [myutils] importeren zonder dat deze in de projectcode aanwezig is.
9.7.2. Het script [config.py]

Het script [config.py] zorgt voor de configuratie van de applicatie:
def configure():
import os
# absolute naam van de map van het configuratiescript
script_dir = os.path.dirname(os.path.abspath(__file__))
# absolute paden van de mappen die in de syspath moeten worden opgenomen
absolute_dependencies = [
# lokale mappen
f"{script_dir}/dir1",
f"{script_dir}/dir2",
]
# syspath bijwerken
from myutils import set_syspath
set_syspath(absolute_dependencies)
# de configuratie wordt teruggestuurd
return {}
- regel 1: de functie [configure] zorgt voor de configuratie van de applicatie;
- regels 7-10: het woordenboek dat voorheen in [config.json] stond;
- regels 9-10: omdat we ons in een script bevinden, kunnen we direct de absolute namen van de mappen [dir1, dir2] ophalen;
- regels 12-14: we gebruiken de functie [set_syspath] van de module [myutils] die we zojuist hebben aangemaakt om het Python-pad van de configuratie te definiëren;
- regel 20: we geven het woordenboek van de applicatieconfiguratie terug. Hier is het leeg;
9.7.3. Het script [main.py]
Het hoofdscript [main] ziet er als volgt uit:
# de applicatie configureren
import config
config = config.configure()
# het syspath is geconfigureerd – we kunnen de imports uitvoeren
from module4 import f4
# main -------------
try:
f4()
except BaseException as erreur:
print(f"L'erreur suivante s'est produite : {erreur}")
finally:
print("done")
- regels 2-4: we configureren de applicatie met behulp van de module [config.py]. Deze is toegankelijk omdat hij zich in dezelfde map bevindt als het hoofdscript. De map van het hoofdscript maakt immers altijd deel uit van het Python-pad;
- wanneer we bij regel 6 aankomen, is het Python Path samengesteld met daarin de map van de module [module4]. Deze kunnen we dus importeren op regel 7;
- regels 10-15: nu hoeft alleen nog maar de functie [f4] te worden uitgevoerd;
De resultaten van de uitvoering in PyCharm zijn als volgt:
In een Python-terminal en buiten de map van het hoofdscript zijn de resultaten als volgt:
Voortaan zullen we altijd op dezelfde manier te werk gaan om een applicatie te configureren:
- de aanwezigheid van een script [config.py] in de map van het hoofdscript. Dit script bevat een functie [configure] die twee doelen heeft:
- het Python-pad voor de applicatie samenstellen. Hiervoor geeft [config.py] alle mappen op die de door de applicatie gebruikte modules bevatten en stelt het Python-pad samen met hun absolute namen;
- het [config]-woordenboek met de configuratie van de applicatie samenstellen;
We passen dit schema toe op de tweede versie van de praktijkopdracht. We herinneren ons namelijk dat versie 1 wel werkte in de PyCharm-omgeving, maar niet in een Python-terminal. Het probleem lag bij het Python-pad.