Virtual environments
We will start by learning about virtual environments.
There are few different virtual environment providers such as pipenv, virtualenv, we will cover anaconda in this class, but the basic principles for all of them are same. The syntax is different.
Conda Cheat Sheet
We'll work with one of the flask applications we built last week
There are few different virtual environment providers such as pipenv, virtualenv, we will cover anaconda in this class, but the basic principles for all of them are same. The syntax is different.
Conda Cheat Sheet
We'll work with one of the flask applications we built last week
from flask import Flask, jsonify, request, abort app=Flask(__name__) data=[{'fname':'Steve', 'lname':'Jobbs'},{'fname':'Bill', 'lname':'Gates'}] @app.route('/createperson', methods=['POST']) def create_person(): print(request.json) if not request.json or not 'person' in request.json: abort(400) data.append(request.json['person']) return jsonify({'data' : data}), 201 @app.route('/data', methods=['GET']) def get_data(): return jsonify({'data' : data}) @app.route('/data/', methods=['GET']) def get_data_byid(id): return jsonify({'data' : data[id]}) app.run(debug = True)
and this is what my console looks like:
Please note the (base) in the top left corner of the screen - that's the name of the virtual environment I am currently in, now I'm going to stop the flask server and get out of that environment
conda deactivate command deactivates the current environment, you can see how the (base) disappeared after running that command below
conda deactivate command deactivates the current environment, you can see how the (base) disappeared after running that command below
(base) Gulas-MacBook-Pro:app gulanurmatova$ conda deactivate Gulas-MacBook-Pro:app gulanurmatova$
conda env list command lists the environments that you currently have on your machine, right now I only have base:
Gulas-MacBook-Pro:app gulanurmatova$ conda env list # conda environments: # base * /Users/gulanurmatova/opt/anaconda3 Gulas-MacBook-Pro:app gulanurmatova$
to activate base environment back use conda activate command
$ conda activate (base) Gulas-MacBook-Pro:app gulanurmatova$
or you can specify the name as well:
$ conda activate base (base) Gulas-MacBook-Pro:app gulanurmatova$
To create a new environment use conda create command (I replaced some of the traceback with ... for readability):
$ conda create --name my_env python=3.8 Collecting package metadata (current_repodata.json): done Solving environment: done ... Proceed ([y]/n)? y ... # # To activate this environment, use # # $ conda activate my_env # # To deactivate an active environment, use # # $ conda deactivate
I can now activate my new environment:
$ conda activate my_env (my_env) Gulas-MacBook-Pro:app gulanurmatova$
and conda env list command has the newly created env in the list:
$ conda env list # conda environments: # base /Users/gulanurmatova/opt/anaconda3 my_env * /Users/gulanurmatova/opt/anaconda3/envs/my_env
if I try to run the application I ran above in the new env, I get an error:
$ python flask_app.py Traceback (most recent call last): File "flask_app.py", line 1, in <module> from flask import Flask, jsonify, request, abort ModuleNotFoundError: No module named 'flask'
That happens because the new environment we created does not have Flask installed.
Don't rush to install it just yet. We will now look how we can specify dependencies for our applications.
So our application above depends on Flask library, we will now look into specifying dependencies for your application using 2 methods.
Method 1 - requirements.txt
create a file with each requirement you want to install on a new line:
and then run following command to install all dependencies:
$ pip install -r requirements.txt Collecting flask Downloading Flask-1.1.2-py2.py3-none-any.whl (94 kB) |████████████████████████████████| 94 kB 391 kB/s Collecting markupsafe Downloading MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl (16 kB) Collecting click>=5.1 Downloading click-7.1.2-py2.py3-none-any.whl (82 kB) |████████████████████████████████| 82 kB 524 kB/s Collecting Werkzeug>=0.15 Downloading Werkzeug-1.0.1-py2.py3-none-any.whl (298 kB) |████████████████████████████████| 298 kB 1.1 MB/s Collecting Jinja2>=2.10.1 Downloading Jinja2-2.11.2-py2.py3-none-any.whl (125 kB) |████████████████████████████████| 125 kB 1.7 MB/s Collecting itsdangerous>=0.24 Downloading itsdangerous-1.1.0-py2.py3-none-any.whl (16 kB) Installing collected packages: click, Werkzeug, markupsafe, Jinja2, itsdangerous, flask Successfully installed Jinja2-2.11.2 Werkzeug-1.0.1 click-7.1.2 flask-1.1.2 itsdangerous-1.1.0 markupsafe-1.1.1
You can also specify the versions of the packages that you are installing
flask == 1.1.2 markupsafe >=1.0,<2.0
Method 2 - setup.py
I am going to deactivate and create new environment for this exercise.
(I purposely captured the history and grep commands, it won't hurt for you to learn them if you don't know them already)
$ conda deactivate Gulas-MacBook-Pro:app gulanurmatova$ history | grep create 891 conda create --name my_env python=3.8 903 history | grep create Gulas-MacBook-Pro:app gulanurmatova$ conda create --name my_env2 python=3.8
And I am now in my new environment
$ conda activate my_env2 (my_env2) Gulas-MacBook-Pro:app gulanurmatova$
This is what my directory structure looks like:
├──test.py test file to validate installation └──my_app/ application package ├── setup.py the setup file └── my_api/ └── flask_app.py the API module
setup.py
from setuptools import setup, find_packages setup( name='my_app', version='0.1.0', packages=find_packages(include=['my_api', 'my_api.*']), install_requires=['flask == 1.1.2','markupsafe >=1.0,<2.0'] )
flask_app.py
from flask import Flask, jsonify, request, abort app=Flask(__name__) data=[{'fname':'Steve', 'lname':'Jobbs'},{'fname':'Bill', 'lname':'Gates'}] @app.route('/createperson', methods=['POST']) def create_person(): print(request.json) if not request.json or not 'person' in request.json: abort(400) data.append(request.json['person']) return jsonify({'data' : data}), 201 @app.route('/data', methods=['GET']) def get_data(): return jsonify({'data' : data}) @app.route('/data/', methods=['GET']) def get_data_byid(id): return jsonify({'data' : data[id]})
and you run it by using the pip install -e . in the my_app filder:
$ pip install -e . Obtaining file:///Users/gulanurmatova/Desktop/python/lecture10/my_app Collecting flask==1.1.2 Using cached Flask-1.1.2-py2.py3-none-any.whl (94 kB) Collecting markupsafe<2.0,>=1.0 Using cached MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl (16 kB) Collecting Jinja2>=2.10.1 Using cached Jinja2-2.11.2-py2.py3-none-any.whl (125 kB) Collecting click>=5.1 Using cached click-7.1.2-py2.py3-none-any.whl (82 kB) Collecting Werkzeug>=0.15 Using cached Werkzeug-1.0.1-py2.py3-none-any.whl (298 kB) Collecting itsdangerous>=0.24 Using cached itsdangerous-1.1.0-py2.py3-none-any.whl (16 kB) Installing collected packages: markupsafe, Jinja2, click, Werkzeug, itsdangerous, flask, my-app Running setup.py develop for my-app Successfully installed Jinja2-2.11.2 Werkzeug-1.0.1 click-7.1.2 flask-1.1.2 itsdangerous-1.1.0 markupsafe-1.1.1 my-app
setup.py doesn't just install dependencies, but also installs your project as if you just installed it
test.py
from my_api import flask_app flask_app.app.run(debug = True)
$ python test.py * Serving Flask app "my_api.flask_app" (lazy loading) * Environment: development * Debug mode: on * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) * Restarting with stat * Debugger is active! * Debugger PIN: 963-757-298 127.0.0.1 - - [06/Nov/2020 19:56:20] "GET / HTTP/1.1" 404 - 127.0.0.1 - - [06/Nov/2020 19:56:23] "GET /data HTTP/1.1" 200 -
PyPi are where your packages found by default
Pronounced Pie-Pee-Eye is the default global python artifactory where all the packages you try to install are found. You company may have their own artifactories that can be reachable through letting pip know about their existence in pip config file.
To prepare your package for distribution you can run following command:
To prepare your package for distribution you can run following command:
$ python setup.py sdist bdist_wheel running sdist running egg_info writing my_app.egg-info/PKG-INFO writing dependency_links to my_app.egg-info/dependency_links.txt writing requirements to my_app.egg-info/requires.txt writing top-level names to my_app.egg-info/top_level.txt reading manifest file 'my_app.egg-info/SOURCES.txt' writing manifest file 'my_app.egg-info/SOURCES.txt' warning: sdist: standard file not found: should have one of README, README.rst, README.txt, README.md running check warning: check: missing required meta-data: url warning: check: missing meta-data: either (author and author_email) or (maintainer and maintainer_email) must be supplied creating my_app-0.1.0 creating my_app-0.1.0/my_app.egg-info copying files to my_app-0.1.0... copying setup.py -> my_app-0.1.0 copying my_app.egg-info/PKG-INFO -> my_app-0.1.0/my_app.egg-info copying my_app.egg-info/SOURCES.txt -> my_app-0.1.0/my_app.egg-info copying my_app.egg-info/dependency_links.txt -> my_app-0.1.0/my_app.egg-info copying my_app.egg-info/requires.txt -> my_app-0.1.0/my_app.egg-info copying my_app.egg-info/top_level.txt -> my_app-0.1.0/my_app.egg-info Writing my_app-0.1.0/setup.cfg creating dist Creating tar archive removing 'my_app-0.1.0' (and everything under it) running bdist_wheel running build installing to build/bdist.macosx-10.9-x86_64/wheel running install running install_egg_info Copying my_app.egg-info to build/bdist.macosx-10.9-x86_64/wheel/my_app-0.1.0-py3.8.egg-info running install_scripts creating build/bdist.macosx-10.9-x86_64/wheel/my_app-0.1.0.dist-info/WHEEL creating 'dist/my_app-0.1.0-py3-none-any.whl' and adding 'build/bdist.macosx-10.9-x86_64/wheel' to it adding 'my_app-0.1.0.dist-info/METADATA' adding 'my_app-0.1.0.dist-info/WHEEL' adding 'my_app-0.1.0.dist-info/top_level.txt' adding 'my_app-0.1.0.dist-info/RECORD' removing build/bdist.macosx-10.9-x86_64/wheel
We are going to stop here, but if you want to try uploading your artifact to PyPi, you can follow these instructions for test.pypi.org