Monday, March 16, 2020

Effective Python Exercise Answer: Virtual Environments and Modules

Let's get to answering the exercise problems from the last post.

Step 1: Virtual Environments

We'll start off with creating our projects folder:
mkdir projects
cd projects/
And after that we can create myproject using venv:
python3 -m venv myproject
cd myproject/
We can then activate our new virtual environment by doing this:
source bin/activate
Once we're in the virtual environment, we can install Flask and PyTest:
python3 -m pip install flask
python3 -m pip install pytest
And at this point if we run:
python3 -m pip list
We'll get an output that looks something like this:
Package            Version
------------------ -------
attrs              19.3.0 
Click              7.0    
Flask              1.1.1  
importlib-metadata 1.5.0  
itsdangerous       1.1.0  
Jinja2             2.11.1 
MarkupSafe         1.1.1  
more-itertools     8.2.0  
packaging          20.3   
pip                18.1   
pkg-resources      0.0.0  
pluggy             0.13.1 
py                 1.8.1  
pyparsing          2.4.6  
pytest             5.3.5  
setuptools         40.8.0 
six                1.14.0 
wcwidth            0.1.8  
Werkzeug           1.0.0  
zipp               3.1.0  
Showing that we have Flask and PyTest (and their dependencies) installed. At this point we can run pip freeze and save the output into a requirements.txt file.
python3 -m pip freeze > requirements.txt
Now, let's see if our requirements.txt file works. We'll start by leaving our current virtual environment and leaving the myproject folder
deactivate
cd ..
At this point we can use venv to create otherproject and activate it's virtual environment:
python3 -m venv otherproject
cd otherproject/
source bin/activate
If we were to use pip list and look at what's currently installed:
python3 -m pip list
We'll then see something like this:
Package       Version
------------- -------
pip           18.1   
pkg-resources 0.0.0  
setuptools    40.8.0 
Which is pretty bare bones. Let's pull over the requirements.txt file from myproject and use it to set up the virtual environment.
cp ../myproject/requirements.txt requirements.txt
python3 -m pip install -r requirements.txt 
At this point if we run:
python3 -m pip list
Then we should get a list that looks like the list from myproject:
Package            Version
------------------ -------
attrs              19.3.0 
Click              7.0    
Flask              1.1.1  
importlib-metadata 1.5.0  
itsdangerous       1.1.0  
Jinja2             2.11.1 
MarkupSafe         1.1.1  
more-itertools     8.2.0  
packaging          20.3   
pip                18.1   
pkg-resources      0.0.0  
pluggy             0.13.1 
py                 1.8.1  
pyparsing          2.4.6  
pytest             5.3.5  
setuptools         40.8.0 
six                1.14.0 
wcwidth            0.1.8  
Werkzeug           1.0.0  
zipp               3.1.0 

Step 2: Modules

Let's start out by moving back over to myproject:
deactivate
cd ../myproject
source bin/activate
At this point we can create two folders, controllers and repositories:
mkdir controllers
mkdir repositories
Create a main.py file that we'll use to fire off our little program:
touch main.py
And inside of both the controllers folder and the repositories folder we'll create an __init__.py and a todo.py file.
cd controllers
touch __init__.py
touch todo.py
cd ../repositories
touch __init__.py
touch todo.py
At this point the modules are set up, and we can add code to the main.py, controllers/todo.py, and repositories/todo.py files like this:

main.py
from controllers import todo

print("In Main")
todo.makeTodo("Test")

controllers/todo.py
from repositories import todo as repo

def makeTodo(name: str):
    print("In controller")
    repo.makeTodo(name)

repositories/todo.py
def makeTodo(name: str):
    print("In repository")
    print(f"Made todo: {name}")

At which point if you run this from inside the myproject folder:
python3 main.py
Then you'll get this output:
In Main
In controller
In repository
Made todo: Test
Which gives a small taste of how modules can be used to avoid naming collisions.