Code Monkey home page Code Monkey logo

intro-to-python's Introduction

An Introduction to Python Programming (2024 Edition)

Instructional Modules

This repository contains instructional materials to support various introductory Python programming courses. Students using these materials should consult their respective syllabus to know which materials they are responsible for.

Intro to Software Development in Python

Instructional Units:

  • Unit 0 - Onboarding
  • Unit 1 - Python Development Environment
  • Unit 2 - Python Language Overview
  • Unit 3 - Python Datatypes
  • Unit 4 - User Interfaces and Experiences
  • Unit 5 - Processing CSV Data
  • Unit 6 - Data Visualization
  • Unit 7 - Fetching Data from the Internet
  • Review

Management of Software Development in Python

Instructional Units:

  • Unit 8 - Software Maintenance and Quality Control
  • Unit 9 - Software Products and Services
  • Unit 10 - Software Planning, Analysis, and Design
  • Unit 11 - Project Implementation Sprint
  • Unit 12 - Project Presentations

Alternative Resources

intro-to-python's People

Contributors

s2t2 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

intro-to-python's Issues

Memoization

Using functools module to perform memoization in Python (almost as easy as Ruby):

# h/t: http://codingnews.info/post/memoization.html
#  ... https://docs.python.org/3/library/functools.html#functools.lru_cache

from functools import lru_cache

@lru_cache(maxsize=None) # memoizes the results
def test_method():
    print("DOING WORK HERE...")
    time.sleep(10)
    return "COMPLETE"

print(test_method()) # takes 10 seconds
print(test_method()) # returns immediately
print(test_method()) # returns immediately
print(test_method()) # returns immediately

Deploying Google Credentials to Heroku

Should add pertinent commands from here into the gspread docs, or maybe a separate doc relating to google credentials which is referenced from the gspread docs:

https://github.com/s2t2/tweet-analyzer-py/blob/master/DEPLOYING.md

heroku buildpacks:set heroku/python
heroku buildpacks:add https://github.com/s2t2/heroku-google-application-credentials-buildpack
heroku config:set GOOGLE_CREDENTIALS="$(< path/to/local/credentials.json)" # references local creds
heroku config:set GOOGLE_APPLICATION_CREDENTIALS="google-credentials.json"

Plotly Maps

Add links to the notes, with example code:

import os

import plotly.graph_objects as go
from dotenv import load_dotenv

load_dotenv()

MAPBOX_ACCESS_TOKEN = os.getenv("MAPBOX_ACCESS_TOKEN")

fig = go.Figure(go.Scattermapbox(
        lat=['38.91427','38.91538','38.91458',
             '38.92239','38.93222','38.90842',
             '38.91931','38.93260','38.91368',
             '38.88516','38.921894','38.93206',
             '38.91275'],
        lon=['-77.02827','-77.02013','-77.03155',
             '-77.04227','-77.02854','-77.02419',
             '-77.02518','-77.03304','-77.04509',
             '-76.99656','-77.042438','-77.02821',
             '-77.01239'],
        mode='markers',
        marker=go.scattermapbox.Marker(
            size=9
        ),
        text=["The coffee bar","Bistro Bohem","Black Cat",
             "Snap","Columbia Heights Coffee","Azi's Cafe",
             "Blind Dog Cafe","Le Caprice","Filter",
             "Peregrine","Tryst","The Coupe",
             "Big Bear Cafe"],
    ))

fig.update_layout(
    autosize=True,
    hovermode='closest',
    mapbox=dict(
        accesstoken=MAPBOX_ACCESS_TOKEN,
        bearing=0,
        center=dict(
            lat=38.92,
            lon=-77.07
        ),
        pitch=0,
        zoom=10
    ),
)

fig.show()

Question about Python Script Invocation Commands

Student question about when to use python app/my_script.py vs python my_script.py.

Answer is depends on the path structure of the repo where that file is.

Reminder: clarify with students or add to notes.

Update Exec Dash Requirements

Before assigning this project again:

  • add requirement that packages should be installed via requirements.txt
  • update / clarify README requirements, explicitly mentioning it in the evaluation rubric
  • update desired data directory to just be "data" (no nested "monthly-sales" dir)
  • for chart, don't need decimals in USD formatting - use whole values
  • be more explicit about prompting the user with example valid values, providing instructions to help the user select a file
  • use os.path.join and os.path.dirname for reliable filepath construction! ("file should be able to be run from any location on the computer, and still find the file")
  • change file name from "dashboard_generator.py" to "top_sellers.py"

Shopping Cart DONE signal

Be more explicit in the project description about expectations for the program to instruct the user about the DONE signal.

Update Shopping Cart Requirements

Rubric should be more explicit about README requirements mentioned in the Repo setup step. See the robo advisor rubric for a good example.

Matplotlib Bar Charts - Removing Scientific Notation

... in the Chart Gallery exercise. Some students were seeing scientific notation to represent the large numbers. And said they were able to solve this with code like:

plt.gcf().axes[0].xaxis.get_major_formatter().set_scientific(False)

Email attachments

Add some example code to the sendgrid notes: h/t: https://github.com/Gplafferty0219/workout-app/blob/master/app/workout.py#L230-L235

import base64
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail, Attachment, FileContent, FileName, FileType, Disposition, ContentId

# ...

def send_email(subject="Workout", html="<p>Today's Workout</p>", pdf="workout.pdf"):
    client = SendGridAPIClient(SENDGRID_API_KEY) #> <class 'sendgrid.sendgrid.SendGridAPIClient>
    message = Mail(from_email=MY_EMAIL, to_emails=MY_EMAIL, subject=subject, html_content=html)
    #attaches the PDF we generated earlier
    file_path = 'workout.pdf'
    with open(file_path, 'rb') as f:
        data = f.read()
        f.close()
    encoded = base64.b64encode(data).decode()
    attachment = Attachment()
    attachment.file_content = FileContent(encoded)
    attachment.file_type = FileType('application/pdf')
    attachment.file_name = FileName('JuicyLiftWorkout.pdf')
    attachment.disposition = Disposition('attachment')
    attachment.content_id = ContentId('Example Content ID')
    message.attachment = attachment
    #send email
    try:
        response = client.send(message)
        return response
    except Exception as e:
        print("OOPS", e.message)
        return None

Conda: Command Not Found

After installing Anaconda for the first time on Mac OS Catalina, students might be running into "conda: command not found" related issues.

As a one-time step, locate where the "anaconda3" folder was installed, for example on the desktop, and replace references to conda with ~/Desktop/anaconda3/bin conda.

After initializing the shell for the first time with ~/Desktop/anaconda3/bin conda init zsh(default on Catalina) or ~/Desktop/anaconda3/bin conda init bash, future references to conda should work without need for the prefix.

https://docs.anaconda.com/anaconda/user-guide/troubleshooting/#conda-command-not-found-on-macos-or-linux

Common Errors

Some students were asking for a list of common errors, like what do I do when I see "TypeError: list indices must be integers or slices, not str"

Better Notes - Edition 2021

  1. Re-structure beginning material to focus on environments, including environment variables. then list all the environments (dev, prod, notebooks, etc), then transition into specific setup of the development environment

  2. Can probably lean more heavily on official python tutorial. These links are great resources that I don't believe are currently included in course materials:

  3. More smaller digestible exercises and practice sets

  4. Update and extend screen casts

Pickle Module Notes

import os
import pickle

class Team()
  # ...

FILEPATH = os.path.join(os.path.dirname(__file__), "..", "my", "my-team.pkl")

def save_it():
   team = Team()

    print("SAVING...")
    with open(FILEPATH, "wb") as f:
        pickle.dump(team, f)

def load_it():
    print("LOADING...")
    with open(FILEPATH, "rb") as f:
        team = pickle.load(f)
    return team

FYI: the Team class definition is required for pickle load step, so if defined in separate file, need to import class

Codebase Cleanup Assignment

Need to tell students to merge their PRs into master branch OR submit the /tree URL pointing to their unmerged branch.

Also prefer to fold in the refactoring and simplification from the beginning, so we can spend more time on projects and less time on stressing out about error-prone Travis integrations. Prefer code climate over Travis next time.

Installing Anaconda

Screen Shot 2020-08-13 at 6 27 42 PM

Screen Shot 2020-08-13 at 6 27 50 PM

Screen Shot 2020-08-13 at 6 27 57 PM

Screen Shot 2020-08-13 at 6 28 06 PM

Screen Shot 2020-08-13 at 6 28 50 PM

Screen Shot 2020-08-13 at 6 33 31 PM

There were no special selections or options. But I did have to do the zsh config. It was weird the conda init code got written into my bash profile, but the shell is zsh. After doing the conda init step things seem ok.

Update psycopg2 notes

Add notes to "/packages/psycopg.md":

import os
from dotenv import load_dotenv
import psycopg2

load_dotenv() #> loads contents of the .env file into the script's environment

DB_NAME = os.getenv("DB_NAME")
DB_USER = os.getenv("DB_USER")
DB_PASSWORD = os.getenv("DB_PASSWORD")
DB_HOST = os.getenv("DB_HOST")

connection = psycopg2.connect(dbname=DB_NAME, user=DB_USER, password=DB_PASSWORD, host=DB_HOST)
print("CONNECTION:", connection)

cursor = connection.cursor()
print("CURSOR:", cursor)

cursor.execute('SELECT * from my_table;')
result = cursor.fetchall()
print("RESULT:", type(result))
print(result)

Updating Default Branch Name for Local Git Repos

If you generated your local repo with git init . and it has a "master" branch by default (for example if you're using an old version of local Git), follow these steps to re-configure the local repo:

git branch -m master main
git fetch origin
git branch -u origin/main main
git remote set-head origin -a

Require requirements.txt for shopping cart project

If package installation is required, require usage of requirements.txt file. Students are doing a great job doing this on their robo advisor projects, so they can probably handle it earlier on, and it makes grading much easier 😸

Better Matplotlib Notes

Including how to save files, FTI about "backends", using in notebooks etc.

plt.scatter(_____)


plt.title("_____")
plt.xlabel("______")
plt.ylabel("______")


plt.savefig(img_filepath)

plt.show()

Google Cloud Storage

New Notes

References

Installation

pip install google-cloud-storage

Usage

import os
from pprint import pprint

from google.cloud import storage
from dotenv import load_dotenv

load_dotenv()

GOOGLE_APPLICATION_CREDENTIALS = os.getenv("GOOGLE_APPLICATION_CREDENTIALS", default="google-credentials.json")
GCS_BUCKET_NAME=os.getenv("GCS_BUCKET_NAME", default="my-bucket") # "gs://my-bucket"

if __name__ == "__main__":

    client = storage.Client() # implicit check for GOOGLE_APPLICATION_CREDENTIALS

    print("------------")
    print("BUCKETS:")
    for bucket in client.list_buckets():
        print(bucket)

    print("------------")
    print("BUCKET:")
    bucket = client.bucket(GCS_BUCKET_NAME)
    print(bucket)

    print("------------")
    print("UPLOADING LOCAL FILE:")
    filename = "my_data.csv"
    local_filepath = os.path.join(os.path.dirname(__file__), "..", "data", filename)
    remote_filepath = os.path.join("data", filename)

    blob = bucket.blob(remote_filepath)
    print(blob) #> <Blob: impeachment-analysis-2020, storage/data/mock_graph.gpickle, None>
    print(blob.exists())

    blob.upload_from_filename(local_filepath)
    print(blob) #> <Blob: impeachment-analysis-2020, storage/data/mock_graph.gpickle, 1590433751346995>
    
    print(blob.exists()) #> True

Sendgrid API Issues

Students are having various issues with getting a working Sendgrid API Key. Posting possible solutions here.

Default Flask Command Not Working

Some students have reported that the default Flask run command doesn't work (could not find app hello.py).

However once we re-organized the app into the "web_app" directory init file and used an app factory function, they reported it started working. In hindsight I think maybe flask was looking for an init file in the root directory, and that's why the hello.py version doesn't work.

Let's update Checkpoint 1 to reflect this student experience, and de-emphasise the need to put all the routes in before we move to the app factory pattern, to make it easier for students to follow along between Checkpoints 1 and 2.

https://github.com/prof-rossetti/intro-to-python/blob/master/exercises/web-app/checkpoints/1-routing.md

More Conda Info

conda info
ls -al /opt/anaconda3/envs

list envs:

conda info --envs

SQL Alchemy Notes

# models.py


import os
from dotenv import load_dotenv
from sqlalchemy import create_engine, Column, Integer, BigInteger, String, ARRAY, TIMESTAMP
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm.exc import NoResultFound

load_dotenv()

DATABASE_URL = os.getenv("DATABASE_URL", default="postgresql://username:password@localhost/dbname")
USER_FRIENDS_TABLE_NAME = os.getenv("USER_FRIENDS_TABLE_NAME", default="user_friends")

db = create_engine(DATABASE_URL)
Base = declarative_base()
Base.metadata.bind = db # fixes sqlalchemy.exc.UnboundExecutionError: Table object 'books' is not bound to an Engine or Connection.  Execution can not proceed without a database to execute against.
BoundSession = sessionmaker(bind=db)

class Book(Base):
    __tablename__ = "books"
    id = Column(Integer, primary_key=True)
    title = Column(String(128))
    author = Column(String(128))
    readers = Column(ARRAY(String(128)))

class UserFriend(Base):
    __tablename__ = USER_FRIENDS_TABLE_NAME
    id = Column(Integer, primary_key=True)
    user_id = Column(BigInteger) # , primary_key=True
    screen_name = Column(String(128))
    friend_count = Column(Integer)
    friend_names = Column(ARRAY(String(128)))
    #start_at = Column(TIMESTAMP)
    #end_at = Column(TIMESTAMP)

if __name__ == "__main__":

    #breakpoint()
    #Book.__table__.drop(db)
    #Book.__table__.create(db)
    #if not Book.__table__.exists(): Book.__table__.create(db)
    #if not UserFriend.__table__.exists(): UserFriend.__table__.create(db)
    Base.metadata.create_all(db)

    session = BoundSession()

    try:
        book = session.query(Book).filter(Book.title=="Harry Potter").one()
    except NoResultFound as err:
        book = Book(title="Harry Potter", author="JKR", readers=["John", "Jane", "Sally"])
        session.add(book)
        session.commit()

    print("-------")
    print("BOOKS:")
    books = session.query(Book)
    for book in books:
        print("...", book.id, "|", book.title, "|", book.author, "|", book.readers)


    print("-------")
    print("USER FRIENDS:")
    results = db.execute("SELECT count(DISTINCT screen_name) as row_count FROM user_friends;")
    #print(results.keys()) #> ["row_count"]
    #print(results.rowcount) #> 1
    print("...", results.fetchone()[0]) #TODO: row factory ... results.fetchone()["row_count"]

    session.close()
       self.session = BoundSession()
        batch.append({
            "user_id": row["user_id"],
            "screen_name": row["screen_name"],
            "friend_count": row["friend_count"],
            "friend_names": row["friend_names"]
        })
        session.bulk_insert_mappings(UserFriend, batch)
        session.commit()
        session.close()

Configuring Git

The Case for Env Vars

Add to notes about Env Vars the following excerpt from Twilio SendGrid:

Storing an API key in an environment variable

Twilio SendGrid recommends storing your API key in an environment variable or a config file that is not stored in version control.

When setting a variable in your program, that variable is readable by any person or system that can access the text file where it’s set. However, a variable that's confined to the environment where the code is executed, stored outside the program itself, is called an environment variable. Only people and programs with access to the environment can read the value assigned to an environment variable. This makes environment variables a more secure choice for storing credentials such as API keys.

Once you assign your API key to an environment variable, you can then tell your program to look for and use that variable. Another benefit of this approach is the ability to set API keys with different permissions in different environments such as development, staging, and production without changing the code you deploy to those environments.

Git Collaboration between Forked Repos

Step 1: Fork the "upstream" repo. This creates an "origin" repo under your own control.
Step 2: Clone the forked repo.
Step 3: Add "upstream" remote address
Step 4: Checkout a new feature branch, and make commits there, and push commits to origin branch. Optionally create a PR against your origin repo to do a preliminary code review, post comments, etc.
Step 5. When ready, create a PR against the upstream repo.
Step 6: A maintainer of the upstream repo will review your PR, and if everything looks good, merge your changes in to the upstream master branch.

After your pull request is merged:

git checkout master
git fetch upstream
git pull upstream master
git push origin master

If something goes wrong, you can reset your repo to reflect the current state of the upstream repo:

git checkout master # if not already there
git reset --hard upstream/master
git push origin master

Customizing VS Code Snippets

Use the command palette and starty typing "snippets" to find the "Preferences > Configure User Snippets" setting which should yield a snippets JSON file.

See below custom snippet for auto-generating a class constructor method. Todo: placeholder args perhaps.

{
	// Place your global snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
	// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
	// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
	// used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
	// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
	// Placeholders with the same ids are connected.
	// Example:
	// "Print to console": {
	// 	"scope": "javascript,typescript",
	// 	"prefix": "log",
	// 	"body": [
	// 		"console.log('$1');",
	// 		"$2"
	// 	],
	// 	"description": "Log output to console"
	// }

	"Python Function Definition": {
		"prefix": ["def"],
		"body": [
			"def my_func():",
			"    pass"
		],
		"description": "A function definition in Python."
	},

	"Python Class Constructor": {
		"prefix": ["init", "__init", "defi"],
		"body": [
			"def __init__(self):",
			"    pass"
		],
		"description": "A class initializer method for Python."
	},

	"Python Main Conditional": {
		"scope": "python",
		"prefix": ["main", "__main"],
		"body": [
			"if __name__ == '__main__':",
			"    pass"
		],
		"description": "The main conditional for Python."
	}
}

https://code.visualstudio.com/docs/editor/userdefinedsnippets

Flask Static Assets

How to customize CSS and JS? Create a /static directory and then insert home.css and home.js and then load them like:

{% extends "bootstrap_layout.html" %}
{% set active_page = "home" %}

{% block css %}
    <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='home.css') }}">
{% endblock %}

{% block content %}

    <h1>Impeachment Tweet Analysis</h1>

    <p>This is a description.</p>

    <ul>
        <li>First list item</li>
        <li>Second list item</li>
        <li>Third list item</li>
    </ul>

{% endblock %}

{% block js %}
    <script type="text/javascript" src="{{ url_for('static', filename='home.js') }}"></script>
{% endblock %}
console.log("HELLO WURLD... FROM THE HOME PAGE")

console.log(2+2)
h1 {color: royalblue;}

See https://flask.palletsprojects.com/en/1.1.x/tutorial/static/

VS Code - Disabling the Squiggly Lines

Some students have asked about grammar / spell-check style red squiggles in their vs code text editor. This is due to pylint not being configured properly. To fix we can just turn off pylint. from the command pallete, "python > enable linting" then "current: off"

aaah that seems to be a local file fix. for a more permanent fix, go to settings:

Screen Shot 2020-08-19 at 12 05 43 AM

Functions Notes

# function definition (once only)

def f(x):
    return (2 * x) + 1

# function invocations

y = f(5)
print(y) #> 11

z = f(10)
print(z) #> 21

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.