├── ONBOARDING.md ├── README.md ├── app ├── class-1 │ ├── CONTRIBUTING.md │ ├── README.md │ ├── my_mod.py │ └── my_script.py ├── class-2 │ ├── assignment_func.py │ ├── assignment_oop.py │ ├── assignment_oop_inherit.py │ ├── polos.py │ ├── teams_func.py │ ├── teams_oop.py │ └── teams_oop_inherit.py └── class-4 │ └── rectangles_test.py ├── img └── polos.png ├── notes ├── class-1.md ├── class-2.md ├── class-3.md └── class-4.md └── test ├── another_team_test.py ├── example_test.py └── team_test.py /ONBOARDING.md: -------------------------------------------------------------------------------- 1 | 2 | # Unit 3 Onboarding 3 | 4 | This document contains an introduction to the local development environment and provides instructions for how to install and configure all the necessary local development tools. 5 | 6 | ## Notebooks vs Local Development 7 | 8 | Co-lab Notebook Advantages: 9 | + Minimal learning curve 10 | + High degree of visibility and shareability 11 | + Effective presentation when code mixed with markdown and data visualizations 12 | + GPU / TPU processing power 13 | 14 | Co-lab Notebook Disadvantages: 15 | + Can only write and execute Python code, not other languages 16 | + Minimal processing power and parallel processing capabilities (excluding GPU / TPU) 17 | + Relatively low ability to manage files and credentials 18 | + Relatively low degree of customization 19 | + Unable to run certain kinds of apps, like web apps written in the Flask framework 20 | 21 | Local Development Advantages: 22 | + Can write and execute code written in many different languages and frameworks 23 | + Greater ability to manage files and credentials 24 | + Greater degree of customization / control 25 | + Greater privacy (not managed by Google) 26 | + More processing power and parallel processing capabilities (excluding GPU / TPU) 27 | 28 | Local Development Disadvantages: 29 | + Steeper learning curve, likely many tools to learn 30 | + Not as immediately shareable, unless pushing code to GitHub or a remote server 31 | 32 | ## Local Development Tools 33 | 34 | Category | Recommended Tool(s) | Purpose 35 | --- | --- | --- 36 | Text Editor or IDE | VS Code | For creating, reading, editing, and deleting files of text and code. 37 | Command-line Application | Mac Terminal, Windows Git Bash, the built-in terminal in VS Code, or whatever you can get to work! | For interfacing with the computer in programmatic ways (i.e. installing and running software). 38 | Programming Language | Python (`python`) | For executing software written in a given programming language. 39 | Programming Language Virtual Environment Manager | Anaconda (`conda`) or Pipenv (`pipenv`) | For installing different versions of a programming language, to suit project-specific purposes, because sometimes you might need to use a different version. 40 | Programming Language Package Manager | Pip (`pip`) in general and in Anaconda environments, but replaced by `pipenv` for Pipenv environments. | For installing third-party packages written in a given programming language. 41 | Version Control Utility | Git (`git`) | For incrementally saving different versions of software files, and interfacing with GitHub, which is an online place to share code repositories. 42 | Server Management Utility | Heroku (`heroku`) | For provisioning and managing remote servers on which to run software. 43 | 44 | ### Text Editor 45 | 46 | To edit Python files locally, we'll need a development-class text editor. Students who don't already have a preferred editor or IDE are encouraged to [download and install VS Code](https://code.visualstudio.com/). After doing so, it is important to install the [Python language extension](https://github.com/prof-rossetti/intro-to-python/blob/master/notes/devtools/vs-code.md#python-syntax-auto-completion) which provides code syntax-highlighting and auto-completion capabilities. 47 | 48 | > OPTIONAL: you may also want to further [customize your text editor's appearance and functionality](https://github.com/prof-rossetti/intro-to-python/blob/master/notes/devtools/vs-code.md#basic-configuration), as desired. 49 | 50 | ### Command-Line Application 51 | 52 | To run Python files locally, we'll need a command-line application. 53 | 54 | Mac users who don't already have a preferred command-line application are encouraged to use the built-in Terminal application (no need to download anything). 55 | 56 | > OPTIONAL (for Mac users): you may want to [customize your Terminal appearance and functionality](https://github.com/prof-rossetti/intro-to-python/blob/master/exercises/command-line-computing/mac-terminal-config.md), as desired. 57 | > NOTE: newer Macs may use the "zsh" shell instead of the "bash" shell, in which case you can do the "\~/.bash_profile" customizations using a file like "\~/.zshrc" instead. 58 | 59 | Windows users who don't already have a preferred command-line application are encouraged to [download and install Git Bash](https://git-scm.com/downloads), which will integrate well with the other development tools and allow Windows users to write the same commands as Mac users. Ultimately, Windows users may opt to use an alternative tool such as the Command Prompt or Anaconda Prompt, but if you do you are responsible for translating unix-style commands you'll see everywhere to windows-style commands. The command-line computing exercise referenced at the bottom of this document can help! 60 | 61 | Mac or Windows students who'd rather configure and use the built-in terminal inside the VS Code text editor may do so, just make sure it works for you! 62 | 63 | ### Programming Language 64 | 65 | To get started with Python locally, if you haven't already done so as instructed during Unit 2, you'll want to [download and install Anaconda 3.7](https://www.anaconda.com/distribution/), which will provide the ability to install and manage local installations of Python and third-party Python packages. 66 | 67 | > IMPORTANT NOTE: remember to check the "add to PATH" option during installation, especially on Windows, so Anaconda will integrate with the other local development tools, such as Git Bash on Windows. 68 | 69 | > FYI: this installation process can take a half-hour or more, so prefer to do it over a strong Internet connection. 70 | 71 | After installing Anaconda, you'll have access to the Python language and its side-kick, the Pip package manager. For more information on Python, see this bonus [`python` reference document](https://github.com/prof-rossetti/intro-to-python/blob/master/notes/clis/python.md). For more information on Pip, see this bonus [`pip` reference document](https://github.com/prof-rossetti/intro-to-python/blob/master/notes/clis/pip.md). 72 | 73 | ### Virtual Environment Manager 74 | 75 | For reasons we'll discuss, it is a best practice to work on project-specific environments which have project-specific versions of the Python programming language and third-party Python packages. There are two main tools to help us do this. 76 | 77 | The first alternative, which you may be using almost exclusively in other units, is the aforementioned Anaconda, which provides the `conda` utility. It is good to be familiar with using `conda` virtual environments. For more information on Anaconda, see this bonus [`conda` reference document](https://github.com/prof-rossetti/intro-to-python/blob/master/notes/clis/conda.md). 78 | 79 | > NOTE: when using `conda` to activate a virtual environment for the first time, when prompted to do so, Git Bash users on Windows may need to run `conda init bash` and Zsh users on Mac may need to run `conda init zsh`. 80 | > NOTE: if experiencing issues recognizing `conda` commands on Mac OS Catalina, reference these [Catalina setup steps](https://github.com/prof-rossetti/intro-to-python/issues/13). 81 | 82 | The second alternative, which we'll be using almost exclusively in this unit, is [Pipenv](https://pipenv.readthedocs.io/en/latest/). For more information on Pipenv, see this bonus [`pipenv` reference document](https://github.com/prof-rossetti/intro-to-python/blob/master/notes/python/packages/pipenv.md). Installation guidance: 83 | 84 | + Mac users are encouraged to download Pipenv via [homebrew](https://github.com/prof-rossetti/intro-to-python/blob/master/notes/clis/brew.md) (`brew install pipenv`). NOTE: Homebrew is a popular and amazing programmatic installation tool that no Mac developer should go without! 85 | + Windows users can consult [this link](https://pipenv.readthedocs.io/en/latest/install/#pragmatic-installation-of-pipenv) for download instructions via Pip. 86 | 87 | 88 | ### Version Control Utility 89 | 90 | Finally, we need a version control utility to manage different versions of our software files, and interface with GitHub, where we can share our code and collaborate with others. 91 | 92 | Unless you already have one, please take a moment to [create a GitHub account](https://github.com/) and consider optionally signing up for the [GitHub Student Developer Pack](https://education.github.com/pack), which provides some free resources. You are encouraged to also optionally [generate SSH keys and associate them with your GitHub account](https://help.github.com/en/github/authenticating-to-github/connecting-to-github-with-ssh), which will allow you to connect to GitHub over the SSH protocol so you don't have to repeatedly type your username and/or password like you would with the HTTPS protocol. 93 | 94 | We'll ideally want to get comfortable using Git from the command line. For more information on Git, see this bonus [`git` reference document](https://github.com/prof-rossetti/intro-to-python/blob/master/notes/clis/git.md). Installation guidance: 95 | 96 | + Windows users can leverage the aforementioned Git Bash application for this purpose (nothing else to install). 97 | + Mac users can download Git via homebrew (`brew install git`), or in many cases Git may already be installed on your computer. 98 | 99 | Although you should really invest the time to become a Git command-line pro, students on either Mac or Windows who are less comfortable with the command-line may optionally start by using the [GitHub Desktop](https://desktop.github.com/) application as a temporary bridge solution which provides a graphical user interface (GUI) for performing Git version control operations. If doing so, students should [customize GitHub Desktop](https://github.com/prof-rossetti/intro-to-python/blob/master/notes/devtools/github-desktop.md#configuration) to recognize their preferred dev tools (e.g. VS Code as the preferred text editor, and Terminal or Git Bash as the preferred command-line utility.) 100 | 101 | ## Success Criteria 102 | 103 | After installing and configuring these local development tools, you should be able run each of the following commands without error: 104 | 105 | + `conda --version` 106 | + `pipenv --version` 107 | + `git --version` 108 | + `code ~/Desktop` (Mac Terminal, Windows Git Bash) OR `code C:\Users\USERNAME\Desktop` (Windows other) 109 | 110 | ## Preparation Exercise 111 | 112 | Finally, in order to become more comfortable with these tools and command-line computing in general, consider completing this optional [Command-line Computing Exercise](https://github.com/prof-rossetti/intro-to-python/tree/master/exercises/command-line-computing). 113 | 114 | Good luck, drop questions in Slack if you need help, and see you in class! 115 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DS Unit 3 - Sprint 1 2 | 3 | Lecture notes and references: 4 | 5 | + [Onboarding Guide](/ONBOARDING.md) 6 | + [Class 1](/notes/class-1.md) 7 | + [Class 2](/notes/class-2.md) 8 | + [Class 3](/notes/class-3.md) 9 | + [Class 4](/notes/class-4.md) 10 | 11 | Example "Lambdata" package solutions: 12 | 13 | + https://github.com/s2t2/lambdata-pt5 14 | + https://github.com/s2t2/lambdata-14 15 | + https://github.com/s2t2/my-lambdata-13 16 | + https://github.com/s2t2/my-lambdata-pt4 17 | + https://github.com/s2t2/my-lambdata-12 18 | + https://github.com/s2t2/my-lambdata-11 19 | -------------------------------------------------------------------------------- /app/class-1/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Contributing Instructions 4 | 5 | If you want to contribute to this package... 6 | 7 | ## Installation 8 | 9 | First install the repo from Github, then navigate there from the command-line: 10 | 11 | ```sh 12 | cd path/to/lambdata-12 13 | ``` 14 | 15 | Install package dependencies: 16 | 17 | ```sh 18 | pipenv install 19 | ``` 20 | 21 | ## Usage 22 | 23 | An example script, not what people will use when they install our package, just an example: 24 | 25 | ```sh 26 | python my_lambdata/my_script.py 27 | ``` 28 | 29 | ## Test 30 | 31 | todo 32 | -------------------------------------------------------------------------------- /app/class-1/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # lambdata-12 4 | 5 | ## Installation 6 | 7 | Install from test PyPi: 8 | 9 | ```sh 10 | pip install -i https://test.pypi.org/simple/ s2t2-lambdata-12 11 | 12 | # haven't pushed to the real PyPI though... 13 | # pip install s2t2-lambdata-12 14 | ``` 15 | 16 | ## Usage 17 | 18 | Using the package from PIPY instructions: 19 | 20 | ```py 21 | from my_lambdata.my_mod import enlarge 22 | 23 | enlarge(5) #> 500 24 | ``` 25 | -------------------------------------------------------------------------------- /app/class-1/my_mod.py: -------------------------------------------------------------------------------- 1 | # my_lambdata/my_mod.py 2 | 3 | def enlarge(n): 4 | """ 5 | Param n is a number 6 | Function will enlarge the number 7 | """ 8 | return n * 100 9 | 10 | # this code breaks our ability to import enlarge from other files, if left in the global scope: 11 | # 12 | # print("HELLO") 13 | # y = int(input("Please choose a number")) 14 | # print(y, enlarge(y)) 15 | 16 | if __name__ == "__main__": 17 | # only run the code below IF this script is invoked from the command-line 18 | # not if it is imported from another script 19 | print("HELLO") 20 | y = int(input("Please choose a number")) 21 | print(y, enlarge(y)) 22 | -------------------------------------------------------------------------------- /app/class-1/my_script.py: -------------------------------------------------------------------------------- 1 | 2 | # my_lambdata/my_script.py 3 | 4 | import pandas 5 | 6 | from my_lambdata.my_mod import enlarge 7 | 8 | print("HELLO WORLD") 9 | 10 | df = pandas.DataFrame({"state": ["CT", "CO", "CA", "TX"]}) 11 | print(df.head()) 12 | 13 | print("-----------------") 14 | x = 5 15 | print("NUMBER", x) 16 | print("ENLARGED NUMBER", enlarge(x)) # invoking our function!! 17 | -------------------------------------------------------------------------------- /app/class-2/assignment_func.py: -------------------------------------------------------------------------------- 1 | 2 | # my_lambdata/assignment.py 3 | 4 | import pandas 5 | 6 | # State abbreviation -> Full Name and visa versa. 7 | # FL -> Florida, etc. 8 | # (Handle Washington DC and territories like Puerto Rico etc.) 9 | 10 | def add_state_names(my_df): 11 | """ Param my_df pandas dataframe with column name "abbrevs" """ 12 | new_df = my_df.copy() # don't mutate existing df (just a pref, you could mutate and not return anything if you want) 13 | names_map = { 14 | "CA": "Cali", 15 | "CO": "Colo", 16 | "CT": "Conn", 17 | "DC": "Wash DC", 18 | "TX": "Texas" 19 | } 20 | #breakpoint() 21 | my_col = new_df["abbrevs"] 22 | other_col = my_col.map(names_map) 23 | new_df["state_name"] = other_col 24 | return new_df 25 | 26 | if __name__ == "__main__": 27 | #print("hahahah") 28 | #input(".............") 29 | 30 | df = pandas.DataFrame({"abbrevs": ["CA", "CO", "CT", "DC", "TX"]}) 31 | print(type(df)) 32 | print(df.head()) 33 | 34 | df2 = add_state_names(df) 35 | print(df2.head()) 36 | -------------------------------------------------------------------------------- /app/class-2/assignment_oop.py: -------------------------------------------------------------------------------- 1 | 2 | # my_lambdata/assignment.py 3 | 4 | import pandas 5 | 6 | class DataFrameTransformer(object): 7 | def __init__(self, df): 8 | """Param df pandas dataframe with column name "abbrevs" """ 9 | self.df = df 10 | 11 | def inspect_data(self): 12 | print(self.df.head()) 13 | 14 | def add_state_names(self): 15 | """ 16 | State abbreviation -> Full Name and visa versa. 17 | FL -> Florida, etc. 18 | """ 19 | names_map = { 20 | "CA": "Cali", 21 | "CO": "Colo", 22 | "CT": "Conn", 23 | "DC": "Wash DC", 24 | "TX": "Texas" 25 | } 26 | #breakpoint() 27 | my_col = self.df["abbrevs"] 28 | other_col = my_col.map(names_map) 29 | self.df["state_name"] = other_col 30 | 31 | if __name__ == "__main__": 32 | 33 | df = pandas.DataFrame({"abbrevs": ["CA", "CO", "CT", "DC", "TX"]}) 34 | 35 | transformer = DataFrameTransformer(df) 36 | transformer.inspect_data() 37 | 38 | transformer.add_state_names() 39 | transformer.inspect_data() 40 | -------------------------------------------------------------------------------- /app/class-2/assignment_oop_inherit.py: -------------------------------------------------------------------------------- 1 | # my_lambdata/assignment_w_inherit.py 2 | 3 | import pandas 4 | 5 | class MyFrame(pandas.DataFrame): 6 | 7 | def inspect_data(self): 8 | print(self.head()) 9 | 10 | def add_state_names(self): 11 | """ 12 | State abbreviation -> Full Name and visa versa. 13 | FL -> Florida, etc. 14 | """ 15 | names_map = { 16 | "CA": "Cali", 17 | "CO": "Colo", 18 | "CT": "Conn", 19 | "DC": "Wash DC", 20 | "TX": "Texas" 21 | } 22 | #breakpoint() 23 | my_col = self["abbrevs"] 24 | other_col = my_col.map(names_map) 25 | self["state_name"] = other_col 26 | 27 | if __name__ == "__main__": 28 | 29 | #df = pandas.DataFrame({"abbrevs": ["CA", "CO", "CT", "DC", "TX"]}) 30 | 31 | my_frame = MyFrame({"abbrevs": ["CA", "CO", "CT", "DC", "TX"]}) 32 | print(my_frame.head()) 33 | my_frame.inspect_data() 34 | my_frame.add_state_names() 35 | my_frame.inspect_data() 36 | -------------------------------------------------------------------------------- /app/class-2/polos.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | class Polo(): 5 | def __init__(size, color): 6 | self.size = size 7 | self.color = color 8 | 9 | def pop_collar(self): 10 | print("Popping the collar") 11 | 12 | 13 | if __name__ == "__main__": 14 | 15 | polo = Polo(color="Blue", size="L") 16 | polo.pop_collar() 17 | -------------------------------------------------------------------------------- /app/class-2/teams_func.py: -------------------------------------------------------------------------------- 1 | 2 | # example teams.py (functional approach) 3 | 4 | def advertise(my_team): 5 | print(f"HEY COME TO {my_team['city'].upper()} TO SEE OUR GAMES!!!") 6 | 7 | def full_name(my_team): 8 | return f"{my_team['city']} {my_team['name']}" 9 | 10 | if __name__ == "__main__": 11 | teams = [ 12 | {"city": "New York", "name": "Yankees"}, 13 | {"city": "New York", "name": "Mets"}, 14 | {"city": "Boston", "name": "Red Sox"}, 15 | {"city": "New Haven", "name": "Ravens"}, 16 | {"city": "Washington", "name": "Nationals"} 17 | ] 18 | 19 | for team in teams: 20 | print("-------") 21 | print(full_name(team)) 22 | advertise(team) 23 | -------------------------------------------------------------------------------- /app/class-2/teams_oop.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | class Team(): 4 | 5 | def __init__(self, name, city): 6 | self.name = name 7 | self.city = city 8 | 9 | def __str__(self): 10 | return f"" 11 | 12 | def __repr__(self): 13 | return f"" 14 | 15 | @property 16 | def full_name(self): 17 | return f"{self.city} {self.name}" 18 | 19 | def advertise(self): 20 | print(f"HELLO PLEASE COME TO {self.city.upper()} TO SEE OUR GAMES!") 21 | 22 | @staticmethod 23 | def advertise_generically(): 24 | print("HELLO PLEASE COME TO OUR GAMES!") 25 | 26 | if __name__ == "__main__": 27 | team = Team("Terriers", "Hometown") 28 | print(team.full_name) 29 | 30 | team2 = Team("Yankees", "New York") 31 | print(team2.full_name) 32 | -------------------------------------------------------------------------------- /app/class-2/teams_oop_inherit.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | def enlarge_again(): 5 | print("DOING SOME STUFF") 6 | 7 | class Team(): 8 | def __init__(self, city, name, players): 9 | self.city = city 10 | self.name = name 11 | self.players = players 12 | 13 | @property 14 | def full_name(self): 15 | """ 16 | Prints the full team name, including the city. 17 | """ 18 | return f"{self.city} {self.name}" 19 | 20 | def count_players(self): 21 | """ 22 | Count the number of players on a team. 23 | """ 24 | return len(self.players) 25 | 26 | def advertise(self): 27 | print(f"HEY COME TO {self.city} TO SEE OUR GAMES!!!!!") 28 | 29 | class BaseballTeam(Team): 30 | def __init__(self, city, name, players, starting_pitcher): 31 | super().__init__(city, name, players) 32 | self.starting_pitcher = starting_pitcher 33 | 34 | def advertise(self): 35 | print(f"HEY COME TO {self.city} TO SEE OUR BASEBALL GAMES!!!!! TO SEE OUR STARTING PITCHER {self.starting_pitcher}") 36 | 37 | if __name__ == "__main__": 38 | 39 | #team = {"city": "New York", "name": "Yankees", "players": ["A"]} 40 | #team2 = {"city": "New York", "name": "Mets", "players": ["B", "C"]} 41 | #team3 = {"city": "Boston", "name": "Red Socks", "players": ["D", "E", "F"]} 42 | 43 | team = Team("New York", "Giants", []) 44 | print(team.name) 45 | #print(team.full_name()) 46 | print(team.full_name) 47 | print(team.count_players()) 48 | team.advertise() 49 | 50 | baseball_team = BaseballTeam("New York", "Yankees", [], "John Snow") 51 | print(baseball_team.full_name) 52 | print(baseball_team.starting_pitcher) 53 | baseball_team.advertise() 54 | -------------------------------------------------------------------------------- /app/class-4/rectangles_test.py: -------------------------------------------------------------------------------- 1 | # test/rectangles_test.py 2 | import unittest 3 | 4 | # assume this function exists in my_labmdata/rectangles.py 5 | def calc_area(l, w): 6 | """ 7 | Params: l and w are both real positive numbers representing the length and width of a rect 8 | """ 9 | if l <= 0 or w <= 0: 10 | raise ValueError 11 | return l * w 12 | 13 | class TestRectangles(unittest.TestCase): 14 | def test_area_calculation(self): 15 | self.assertEqual(calc_area(5, 3), 15) 16 | # https://docs.python.org/3/library/exceptions.html#ValueError 17 | with self.assertRaises(ValueError): 18 | calc_area(-5, 3) 19 | with self.assertRaises(ValueError): 20 | calc_area(5, -3) 21 | 22 | if __name__ == "__main__": 23 | unittest.main() 24 | -------------------------------------------------------------------------------- /img/polos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s2t2/lambda-ds-3-1/031bbbb0271a2a09091e335753a4c944e9e75aab/img/polos.png -------------------------------------------------------------------------------- /notes/class-1.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Class 1 4 | 5 | Announcement: 6 | 7 | ``` 8 | Hey @channel, my name is Mike Rossetti and I'll be your instructor for Unit 3. :wave: To prepare for the first class, please review the official Lambda material and register for a test PyPI account: 9 | 10 |   + https://github.com/LambdaSchool/DS-Unit-3-Sprint-1-Software-Engineering 11 |   + https://learn.lambdaschool.com/ds/sprint/recA7O3QeO8AQxsxE 12 |   + https://test.pypi.org/account/register/ 13 | 14 | Also ensure you are able to run each of the following commands without error: 15 | 16 |   + conda --version 17 |   + pipenv --version 18 |   + git --version 19 |   + code ~/Desktop (Mac / Windows Git Bash) or code C:\Users\USERNAME\Desktop (Windows other) 20 | 21 | If you need help setting up your local development environment, I encourage you to consult this detailed "Onboarding Guide", which will walk you through the process and address common questions raised by students in previous cohorts: 22 | 23 |   + https://github.com/s2t2/lambda-ds-3-1/blob/master/ONBOARDING.md 24 | 25 | If you have any questions or run into any issues, post a message here and we can work through them together. Looking forward to working with you, and see you on Monday morning! 26 | ``` 27 | 28 | Lambda Materials: 29 | + https://learn.lambdaschool.com/ds/module/recwEPR24pu5LCnA5 30 | + https://github.com/LambdaSchool/DS-Unit-3-Sprint-1-Software-Engineering/tree/master/module1-python-modules-packages-and-environments 31 | 32 | Topics: 33 | 1. Git Repositories 34 | 2. Pipenv Virtual Environments 35 | 3. Python Imports, Modules, and Packages 36 | 4. Releasing a Python Package to PyPI 37 | 38 | 39 | ## Part I - Git Repositories 40 | 41 | README files (BONUS): 42 | + https://guides.github.com/pdfs/markdown-cheatsheet-online.pdf 43 | 44 | Choosing a License (BONUS): 45 | + https://choosealicense.com/ 46 | + https://github.com/prof-rossetti/intro-to-python/blob/master/notes/software/licensing.md 47 | 48 | Managing Repositories: 49 | 50 | ```sh 51 | cd ~/Desktop # navigates to the place where you'd like to download the repo 52 | git clone REMOTE_ADDRESS # downloads repo from GitHub (where REMOTE_ADDRESS comes from GitHub - prefer SSH address if possible) 53 | cd REPO_NAME # navigates into the repo's root directory (where REPO_NAME is the name of the folder / repo that got downloaded - same as on GitHub) 54 | code . # use VS Code to open all files and folders in this directory 55 | ``` 56 | 57 | The Git commit process (will run any time we are ready to commit new changes): 58 | 59 | ```sh 60 | git status # what files have changed? 61 | git diff # how have the files changed? 62 | git add . # prepare to commit all the files and folders in this directory 63 | git status # (optional) 64 | git commit -m "Setup repo and virtual env" # creates a new version / commit with the specified message 65 | git log # (optional) shows the version history. press "q" to quit 66 | git remote -v # shows the remote addresses associated with this local repo, for example the "origin" address 67 | git push origin master # uploads the code to GitHub 68 | ``` 69 | 70 | ## Part II - Virtual Environments 71 | 72 | A virtual environment is a place where we install specific version of the python programming language and third-party Python packages. Different projects often require different dependencies, and project-specific virtual environments help us prevent conflicts between different versions. 73 | 74 | > NOTE: we'll use either Anaconda or Pipenv for managing virtual environments. The instructions below show you both ways (for instructional purposes), but normally you'd just choose one! In Unit 3, we'll be focusing on Pipenv exclusively. 75 | 76 | ### Anaconda Environments 77 | 78 | > NOTE: OK to skip (i.e. read but not attempt / follow- along with) this Anaconda information for now. We'll be using Pipenv exclusively in Unit 3. 79 | 80 | Advantages: 81 | + Can be created, modified, activated from anywhere on the filesystem 82 | + Integrates with pip for python package management 83 | 84 | Disadvantages: 85 | + Requires specification of development and production dependencies in different files ("requirements.txt" vs. "dev-requirements.txt", for example) 86 | + Requires specification of python version using a separate file called the "runtime.txt" 87 | 88 | Managing a virtual environment with Anaconda: 89 | 90 | ```sh 91 | # requirements.txt file 92 | pandas 93 | ``` 94 | 95 | ```sh 96 | conda create -n my-lambdata-env python=3.7 # creates a new virtual env 97 | conda activate my-lambdata-env # activates the virtual env 98 | pip install -r requirements.txt # installs inside the virtual env all packages listed in the requirements.txt file 99 | pip list # verifies packages are installed properly 100 | ``` 101 | 102 | ### Pipenv Environments 103 | 104 | Advantages: 105 | + Handles python package management 106 | + Can specify development and production dependencies, as well as the python version, in same file ("Pipfile") 107 | + Performs a "locking" process to provide more details about the package versions and ensure dependencies are not in conflict 108 | 109 | Disadvantages: 110 | + Must be created, modified, activated from the given project directory !!!!! 111 | + Replaces pip for python package management 112 | + Locking process takes a while 113 | 114 | > IMPORTANT: Make sure you run the following commands from the repo's root dir! 115 | > 116 | > IMPORTANT: Also make sure to deactivate all anaconda env(s) as necessary (`conda deactivate`) before proceeding... 117 | 118 | Managing a virtual environment with Pipenv: 119 | 120 | ```sh 121 | pipenv --python 3.7 # creates a new virtual env for the first time, also creates Pipfile 122 | pipenv install pandas # installs a given package inside the virtual env, creates a Pipfile.lock if installing something for the first time, and auto-adds pandas to the Pipfile and Pipfile.lock 123 | pipenv shell # activates the virtual env 124 | 125 | python --version # verifies the right version of Python has been installed 126 | pip list # verifies packages have been installed properly 127 | ``` 128 | 129 | 130 | 131 | 132 | 133 | 134 | ## Part III - Python Imports, Modules, and Packages 135 | 136 | Python Modules: 137 | + https://docs.python.org/3.7/tutorial/modules.html 138 | 139 | 140 | ```py 141 | # my_lambdata/__init__.py 142 | 143 | # nothing to see here! 144 | ``` 145 | 146 | ```py 147 | # my_lambdata/my_mod.py 148 | 149 | def enlarge(n): 150 | """ 151 | Param n is a number 152 | Function will enlarge the number 153 | """ 154 | return n * 100 155 | 156 | # this code breaks our ability to import enlarge from other files, if left in the global scope: 157 | # 158 | # print("HELLO") 159 | # y = int(input("Please choose a number")) 160 | # print(y, enlarge(y)) 161 | 162 | if __name__ == "__main__": 163 | # only run the code below IF this script is invoked from the command-line 164 | # not if it is imported from another script 165 | print("HELLO") 166 | y = int(input("Please choose a number")) 167 | print(y, enlarge(y)) 168 | ``` 169 | 170 | ```py 171 | # my_lambdata/my_script.py 172 | 173 | import pandas 174 | 175 | from my_lambdata.my_mod import enlarge 176 | 177 | print("HELLO WORLD") 178 | 179 | df = pandas.DataFrame({"state": ["CT", "CO", "CA", "TX"]}) 180 | print(df.head()) 181 | 182 | print("-----------------") 183 | x = 5 184 | print("NUMBER", x) 185 | print("ENLARGED NUMBER", enlarge(x)) # invoking our function!! 186 | ``` 187 | 188 | Running the scripts: 189 | 190 | ```sh 191 | python my_lambdata/my_script.py 192 | python my_lambdata/my_mod.py 193 | 194 | # note, the alternative "module" invocation syntax 195 | # ... required if our script imports from another local file: 196 | python -m my_lambdata.my_script 197 | python -m my_lambdata.my_mod 198 | ``` 199 | 200 | 201 | 202 | 203 | 204 | 205 | ## Part IV - Releasing a Package to PyPI 206 | 207 | Publishing Packages to the PyPI: 208 | + https://pypi.org/ 209 | + https://test.pypi.org (SIGN UP FOR AN ACCOUNT!) 210 | + https://pypi.org/help/#publishing 211 | + https://packaging.python.org/tutorials/packaging-projects/ 212 | + http://data-creative.info/reference-docs/2019/05/30/how-to-publish-python-package-pypi/ 213 | 214 | Example Package Published to PyPI (BONUS): 215 | + https://github.com/s2t2/game-utils-py 216 | + https://pypi.org/project/s2t2-game-utils/ 217 | + https://test.pypi.org/project/s2t2-game-utils/ 218 | 219 | Installing the "twine" package as a development dependency: 220 | 221 | ```sh 222 | pipenv install twine --dev 223 | ``` 224 | 225 | > FYI: passing --dev specifies the package should be installed as a development dependency. We do this with packages that our source code doesn't require to perform its desired functionality (e.g. packages for testing and distributing the code) 226 | 227 | Specifying metadata about our package in a new file called "setup.py": 228 | 229 | ```py 230 | # setup.py file 231 | 232 | from setuptools import find_packages, setup 233 | 234 | with open("README.md", "r") as fh: 235 | long_description = fh.read() 236 | 237 | setup( 238 | name="my-package-name", # the name that you will install via pip 239 | version="1.0", 240 | author="Your Full Name", 241 | author_email="your@email.com", 242 | description="A short description", 243 | long_description=long_description, 244 | long_description_content_type="text/markdown", # required if using a md file for long desc 245 | #license="MIT", 246 | url="https://github.com/YOUR_USERNAME/YOUR_REPO_NAME", 247 | #keywords="", 248 | packages=find_packages() # ["my_lambdata"] 249 | ) 250 | ``` 251 | 252 | After configuring the "setup.py" file, invoking it will save a compressed version of the code in the "dist" directory. 253 | 254 | ```sh 255 | python setup.py sdist bdist_wheel 256 | ``` 257 | 258 | After the package source code has been "built" locally, use twine to upload the distribution files to PyPI (or in this case the test PyPI server), where it can be downloaded by others via Pip commands: 259 | 260 | ```sh 261 | twine upload --repository-url https://test.pypi.org/legacy/ dist/* 262 | 263 | # OR, if you see 403 "file already exists" errors: 264 | twine upload --skip-existing --repository-url https://test.pypi.org/legacy/ dist/* 265 | ``` 266 | 267 | > NOTE: the process whenever you want to release a new version of your package to PyPI is something like: 268 | > 1. make change and save file 269 | > 2. revise version value in the setup.py file (for example from 1.0 to 1.1, or from 1.1 to 1.2) and save the file 270 | > 3. make a commit 271 | > 4. run the bdist_wheel command to package your code 272 | > 5. run the twine command to upload the packaged code 273 | 274 | -------------------------------------------------------------------------------- /notes/class-2.md: -------------------------------------------------------------------------------- 1 | 2 | # Class 2 3 | 4 | Lambda Materials: 5 | 6 | + https://learn.lambdaschool.com/ds/module/recqeF16aJfb1UTWF/ 7 | + https://github.com/LambdaSchool/DS-Unit-3-Sprint-1-Software-Engineering/tree/master/module2-oop-code-style-and-reviews 8 | 9 | Outline: 10 | 11 | 1) Review of Lambdata Package Functionality 12 | 2) Docs, Style, PEP8 and Docstrings 13 | 3) OOP Concepts 14 | 4) Classes and Inheritance in Python 15 | 16 | ## Part I 17 | 18 | Review of functionality for lambdata package - operating on dataframes, converting a column of state abbreviations to state names. Using a functional approach (for now). 19 | 20 | Introspection and debugging: 21 | 22 | ```sh 23 | # introspection: 24 | type("HELLO") # what datatype /class is this object? 25 | dir("HELLO") # method methods and properties are available to be invoked on the object? 26 | 27 | # debugging with breakpoint: 28 | for i in [1,2,3,4,5]: 29 | if i >= 3: 30 | breakpoint() 31 | ``` 32 | 33 | > NOTE: breakpoint() is available as of Python 3.7 or later. For earlier versions, try `from pdb import set_trace as breakpoint` and then you should be able to use `breakpoint()`. 34 | 35 | Branch operations to facilitate Pull Request Reviews: 36 | 37 | ```sh 38 | git checkout -b my-new-feature # checkout a new branch 39 | git add . 40 | git commit -m "Implement feature" 41 | git push origin my-new-feature 42 | ``` 43 | 44 | ## Part II 45 | 46 | Style, Formatting, PEP8, and Docstrings: 47 | 48 | + https://pep8.org/ 49 | + https://www.python.org/dev/peps/pep-0008/ 50 | + https://www.python.org/dev/peps/pep-0257/ 51 | + https://stackoverflow.com/questions/3898572/what-is-the-standard-python-docstring-format 52 | + https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html 53 | + https://marketplace.visualstudio.com/items?itemName=njpwerner.autodocstring 54 | 55 | > The docstring for a function or method should summarize its behavior and document its arguments, return value(s), side effects, exceptions raised, and restrictions on when it can be called (all if applicable). Optional arguments should be indicated. It should be documented whether keyword arguments are part of the interface. - PEP 257 56 | 57 | Doc generation example (Pandas): 58 | 59 | + https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html 60 | + https://github.com/pandas-dev/pandas/blob/master/pandas/core/frame.py#L319 61 | 62 | Doc generation, Read The Docs, Sphinx (BONUS): 63 | 64 | + https://readthedocs.org/ 65 | + https://docs.readthedocs.io/en/stable/intro/getting-started-with-sphinx.html 66 | + https://www.youtube.com/watch?v=b4iFyrLQQh4 67 | 68 | Style-checking: 69 | 70 | + https://pypi.org/project/autopep8/ 71 | + http://pep8online.com/ 72 | + https://codeclimate.com/ 73 | 74 | ```sh 75 | # use pip or pipenv to install. if pipenv save as dev dependency: 76 | pipenv install autopep8 --dev 77 | 78 | # make a commit before running the following command, as the in-place flag will modify your files: 79 | autopep8 --in-place --aggressive --recursive . 80 | ``` 81 | 82 | ## Part III 83 | 84 | Classes and OOP: 85 | 86 | + https://docs.python.org/3/tutorial/classes.html 87 | + https://realpython.com/python3-object-oriented-programming/ 88 | + https://www.youtube.com/watch?v=ZDa-Z5JzLYM&list=PL-osiE80TeTsqhIuOqKhwlXsIBIdSeYtc 89 | + https://www.youtube.com/playlist?list=PL-osiE80TeTsqhIuOqKhwlXsIBIdSeYtc 90 | + https://realpython.com/instance-class-and-static-methods-demystified/#static-methods 91 | 92 | Characteristics of an "object": 93 | 94 | + Identity 95 | + Attributes / Properties 96 | + Behaviors / Methods 97 | 98 | Example objects: 99 | 100 | ![different color polos on the shelf](/img/polos.png) 101 | 102 | Example class definition: 103 | 104 | ```py 105 | # polos.py 106 | 107 | class Polo(): 108 | def __init__(self, color, size, price=99.00, style=None): 109 | self.color = color 110 | self.size = size 111 | self.price = price 112 | self.style = style 113 | 114 | if __name__ == "__main__": 115 | 116 | #df = DataFrame(...) 117 | # df.head() 118 | polo1 = Polo(color="Blue", size="L", price=4.99) # a new "instance" of the class 119 | print(polo1.color) 120 | print(polo1.price) 121 | 122 | polo2 = Polo(color="Yello", size="Small") # a new "instance" of the class 123 | print(polo2.color) 124 | print(polo2.price) 125 | ``` 126 | 127 | > TERMINOLOGY NOTE: the `__init__` function inside a class is often called the "constructor" or "initializer" function 128 | 129 | > TERMINOLOGY NOTE: when we create a new instance of the class (e.g. `polo1` and `polo2`, we call this "initialization" or "instantiation" 130 | 131 | 132 | ### Refactoring from a Functional to an Object-Oriented Approach 133 | 134 | Example of a functional approach: 135 | 136 | ```py 137 | # teams.py 138 | 139 | def full_name(team_dict): 140 | return team["city"] + " " + team["name"] 141 | 142 | teams = [ 143 | {"name": "Yankees", "city": "New York"}, 144 | {"name": "Mets", "city": "New York"}, 145 | {"name": "Nationals", "city": "Washington"} 146 | ] 147 | 148 | for team in teams: 149 | print(full_name(team)) #> functional approach (pass the object to the function) 150 | ``` 151 | 152 | ... and converting to an object-oriented approach: 153 | 154 | ```py 155 | # teams.py 156 | 157 | class Team(): 158 | def __init__(self, name, city, sport=None, roster=[]): 159 | # these are attributes / nouns 160 | self.name = name 161 | self.city = city 162 | self.sport = sport 163 | self.roster = roster 164 | 165 | # this is a property / noun 166 | # the @property decorator allows us to invoke this without trailing parentheses 167 | @property 168 | def full_name(self): 169 | return f"{team.city} {team.name}" 170 | 171 | # this is a method / verb 172 | def advertise(self): 173 | print("PLEASE COME TO", self.city.upper(), "TO SEE US PLAY") 174 | 175 | # this method doesn't require any information about the specific instance itself 176 | # the @staticmethod decorator allows us to omit passing "self" as a param 177 | @staticmethod 178 | def advertise_generically(): 179 | print("PLEASE COME TO OUR GAMES") 180 | 181 | if __name__ == "__main__": 182 | 183 | teams = [ 184 | {"name": "Yankees", "city": "New York"}, 185 | {"name": "Mets", "city": "New York"}, 186 | {"name": "Nationals", "city": "Washington"} 187 | ] 188 | 189 | for d in teams: 190 | #print(team["city"] + " " + team["name"]) 191 | #print(full_name(team)) #> functional approach 192 | team = Team(d["name"], d["city"]) 193 | print(team.name) 194 | print(team.full_name) #> OOP (invoke the method on the object) 195 | team.advertise() 196 | ``` 197 | 198 | A real-world example of Refactoring from Functions to Classes (BONUS): 199 | + https://github.com/s2t2/playlist-service-py/blob/25cae16201adc935f71e863a79d51690c00e492b/app/spotify_service.py 200 | + https://github.com/s2t2/playlist-service-py/blob/master/app/spotify_service.py 201 | + https://github.com/s2t2/playlist-service-py/blob/master/app/sync_service.py 202 | 203 | ## Part IV 204 | 205 | Class Inheritance in Python: 206 | 207 | + https://www.w3schools.com/python/python_inheritance.asp 208 | 209 | Inheritance Example (SKLearn): 210 | 211 | + https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/tree/_classes.py#L77 212 | + https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/tree/_classes.py#L589 213 | 214 | Starting with a single class: 215 | 216 | ```py 217 | # autos.py 218 | 219 | class Auto(): 220 | def __init__(self, make, model, year, color, num_wheels): 221 | self.make = make 222 | self.model = model 223 | self.year = year 224 | self.color = color 225 | self.num_wheels = num_wheels 226 | 227 | def drive(self): 228 | print("WE ARE DRIVING", self.model) 229 | 230 | if __name__ == "__main__": 231 | car = Auto("Toyota", "Prius", 2020, "Blue", 4) 232 | car.drive() 233 | car2 = Auto("Tesla", "Model S", 2020, "Blue", 4) 234 | car2.drive() 235 | truck = Auto("Ford", "F150", 2020, "Blue", 4) 236 | truck.drive() 237 | truck2 = Auto("Tesla", "Cybertuck", 2020, "Blue", 4) 238 | truck2.drive() 239 | ``` 240 | 241 | ... then implementing inheritance between classes: 242 | 243 | ```py 244 | # autos.py 245 | 246 | class Auto(): 247 | def __init__(self, make, model, year, color, num_wheels): 248 | self.make = make 249 | self.model = model 250 | self.year = year 251 | self.color = color 252 | self.num_wheels = num_wheels 253 | 254 | def drive(self): 255 | print("WE ARE DRIVING", self.model) 256 | 257 | def advertise(self): 258 | print("BUY OUR", self.model) 259 | 260 | class Truck(Auto): # designates the Truck class should inherit from the Auto class 261 | def __init__(self, make, model, year, color, num_wheels, bed_size): 262 | super().__init__(make, model, year, color, num_wheels) # can invoke parent class methods via super() 263 | self.bed_size = bed_size 264 | 265 | # can overwrite parent class methods 266 | def advertise(self): 267 | print("VROOOOM", self.model) 268 | 269 | if __name__ == "__main__": 270 | 271 | car = Auto("Toyota", "Prius", 2020, "Blue", 4) 272 | car.drive() 273 | car.advertise() 274 | 275 | car2 = Auto("Tesla", "Model S", 2020, "Blue", 4) 276 | car2.drive() 277 | car2.advertise() 278 | 279 | truck = Truck("Ford", "F150", 2020, "Blue", 4, bed_size="5x5") 280 | truck.drive() 281 | truck.advertise() 282 | print(truck.bed_size) 283 | 284 | truck2 = Truck("Tesla", "Cybertuck", 2020, "Blue", 4, bed_size="10x10") 285 | truck2.drive() 286 | truck2.advertise() 287 | print(truck2.bed_size) 288 | ``` 289 | -------------------------------------------------------------------------------- /notes/class-3.md: -------------------------------------------------------------------------------- 1 | 2 | # Class 3 3 | 4 | 5 | Announcement: 6 | 7 | ``` 8 | Hey @channel, heads up we'll be working with Docker today. 9 | 10 | If you have Linux, MacOS Sierra or newer or Windows 10 Pro, install [Docker Desktop](https://www.docker.com/products/docker-desktop) 11 | 12 | Else If you have older MacOS, Windows 10 Home, or older Windows, install [Docker Toolbox](https://docs.docker.com/toolbox/overview/) 13 | 14 | If you're unable to locally install Docker, sign up for an account at [Docker Hub](https://hub.docker.com/) 15 | ``` 16 | 17 | Lambda Materials: 18 | 19 | + https://learn.lambdaschool.com/ds/module/recLjxZbBV3Jmrj2T/ 20 | + https://github.com/LambdaSchool/DS-Unit-3-Sprint-1-Software-Engineering/tree/master/module3-containers-and-reproducible-builds 21 | 22 | 23 | ## Part I and II 24 | 25 | Review of Virtual Environments and OOP 26 | 27 | + [Class 1](class-1.md) 28 | + [Class 2](class-2.md) 29 | 30 | Review of the Lambdata Package Functionality: 31 | 32 | + [Functional Approach](/app/class-2/assignment_func.py) 33 | + [OOP Approach](/app/class-2/assignment_oop.py) 34 | + [Inheritance Approach](/app/class-2/assignment_oop_inherit.py) 35 | 36 | ## Part III 37 | 38 | Using a Docker image: 39 | 40 | ```sh 41 | docker run hello-world 42 | ``` 43 | 44 | Using a Dockerfile: 45 | 46 | ```sh 47 | # Dockerfile 48 | 49 | FROM debian 50 | 51 | ### So logging/io works reliably w/Docker 52 | ENV PYTHONUNBUFFERED=1 53 | ### UTF Python issue for Click package (pipenv dependency) 54 | ENV LC_ALL=C.UTF-8 55 | ENV LANG=C.UTF-8 56 | ### Need to explicitly set this so `pipenv shell` works 57 | ENV SHELL=/bin/bash 58 | 59 | ### Basic Python dev dependencies 60 | RUN apt-get update && \ 61 | apt-get upgrade -y && \ 62 | apt-get install python3-pip curl -y && \ 63 | pip3 install pipenv 64 | 65 | ### Install via pip or pipenv: 66 | RUN pip3 install pandas 67 | #RUN pipenv install pandas 68 | ``` 69 | 70 | Alternatively, try this Dockerfile which directly uses the "python" image: 71 | 72 | ```sh 73 | # Dockerfile 74 | 75 | FROM python:3 76 | 77 | ENV PYTHONUNBUFFERED=1 78 | 79 | RUN apt-get update && \ 80 | apt-get upgrade -y && \ 81 | pip install --upgrade pip 82 | 83 | RUN pip install pandas 84 | 85 | # or install packages from the requirements.txt file (must be in same dir as Dockerfile) 86 | # COPY requirements.txt /tmp/requirements.txt 87 | # RUN pip install -r /tmp/requirements.txt 88 | ``` 89 | 90 | > Thanks to Robert from DS PT5 for [sharing](https://lambda-students.slack.com/archives/GQE2AB1GC/p1589255699396000)! 91 | 92 | Run from the directory where the dockerfile is: 93 | 94 | ```sh 95 | docker build . -t my_python_image # builds a new docker image 96 | 97 | docker run -it my_python_image /bin/bash # starts up a new container of a docker image 98 | 99 | # mess around with python3, pip3, pipenv inside the container 100 | # then exit 101 | 102 | docker container ls --all # find all container names and IDs 103 | 104 | docker start # starts a paused docker container 105 | 106 | docker attach # reconnects to a running docker container 107 | ``` 108 | 109 | > Thanks to Benjamin and Caleb from DS 11 for [sharing](https://app.slack.com/client/T4JUEB3ME/GPP0JA5RD/thread/GPP0JA5RD-1581534096.091100) 110 | 111 | 112 | 113 | FYI: Here's a more in-depth walkthrough of Docker, for those who are interested: 114 | 115 | + https://youtu.be/nrzxKL4bsLI 116 | + https://www.youtube.com/watch?v=kQbDnDsO8MQ&feature=youtu.be 117 | -------------------------------------------------------------------------------- /notes/class-4.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Class 4 4 | 5 | Lambda Materials: 6 | + https://learn.lambdaschool.com/ds/module/recq9eVVCzZpgeH58/ 7 | + https://github.com/LambdaSchool/DS-Unit-3-Sprint-1-Software-Engineering/tree/master/module4-software-testing-documentation-and-licensing 8 | 9 | Previous Lecture and Materials on Testing (BONUS / FYI) : 10 | + https://github.com/prof-rossetti/intro-to-python/blob/master/notes/software/testing.md 11 | + https://www.youtube.com/watch?v=pS8pzmtqxVA 12 | + https://github.com/prof-rossetti/lambda-lecture-pytest 13 | 14 | See also the [reference test code](/test/). 15 | 16 | Testing Philosophies at Google vs. Facebook (BONUS): 17 | + https://www.youtube.com/watch?v=GjE7clki4a0 18 | 19 | ## Part I 20 | 21 | Testing Frameworks (Unittest): 22 | + https://docs.python.org/3.5/library/unittest.html 23 | + https://docs.python.org/3.5/library/unittest.html#organizing-tests 24 | + https://docs.python.org/3.5/library/unittest.html#test-discovery 25 | 26 | Running tests: 27 | 28 | ```sh 29 | python -m unittest test.team_test 30 | ``` 31 | 32 | It may be possible to run all tests at once: 33 | 34 | ```sh 35 | python -m unittest discover 36 | ``` 37 | 38 | > NOTE: may need to add "`__init__.py`" files to both the "app" and "test" directories for this to work from the root directory 39 | 40 | 41 | ## Part II (FYI / BONUS) 42 | 43 | > FYI this is related bonus material, not required for your assignment or SC 44 | 45 | Testing Frameworks (Pytest): 46 | + https://docs.pytest.org/en/latest/ 47 | + https://github.com/prof-rossetti/intro-to-python/blob/master/notes/python/packages/pytest.md 48 | + https://github.com/prof-rossetti/intro-to-python/tree/master/exercises/testing-123 49 | 50 | Installing pytest as a development dependency: 51 | 52 | ```sh 53 | pipenv install pytest --dev 54 | ``` 55 | Running tests: 56 | 57 | ```sh 58 | pytest 59 | ``` 60 | 61 | ## Part III (BONUS / FYI) 62 | 63 | > FYI this is related bonus material, not required for your assignment or SC 64 | 65 | Test-Driven Development (TDD): 66 | 67 | ```py 68 | # from app.game import determine_winner 69 | 70 | # FYI normally we'd have this application code (determine_winner()) in another file, 71 | # ... but for this exercise we'll keep it here 72 | def determine_winner(user_choice, computer_choice): 73 | return "rock" # todo: write logic here to make the tests pass! 74 | 75 | def test_determine_winner(): 76 | assert determine_winner("rock", "rock") == None 77 | assert determine_winner("rock", "paper") == "paper" 78 | assert determine_winner("rock", "scissors") == "rock" 79 | 80 | assert determine_winner("paper", "rock") == "paper" 81 | assert determine_winner("paper", "paper") == None 82 | assert determine_winner("paper", "scissors") == "scissors" 83 | 84 | assert determine_winner("scissors", "rock") == "rock" 85 | assert determine_winner("scissors", "paper") == "scissors" 86 | assert determine_winner("scissors", "scissors") == None 87 | ``` 88 | 89 | Continuous Integration (CI): 90 | + https://travis-ci.com/ 91 | + https://travis-ci.com/s2t2/playlist-service-py/builds/142617662 92 | + https://github.com/s2t2/playlist-service-py/pull/7 93 | + https://github.com/prof-rossetti/intro-to-python/blob/master/notes/devtools/travis-ci.md 94 | + https://github.com/prof-rossetti/intro-to-python/tree/master/exercises/ci-123 95 | -------------------------------------------------------------------------------- /test/another_team_test.py: -------------------------------------------------------------------------------- 1 | 2 | # OBJECTIVES: 3 | # 4 | # 1) make sure that we can initialize / instantiate our Team class 5 | # 6 | # 2) make sure that the Team class' .full_name property behaves as desired 7 | # 8 | 9 | from app.team import Team 10 | 11 | def test_example(): 12 | team = Team("New York", "Giants", []) 13 | assert team.full_name == "New York Giants" 14 | -------------------------------------------------------------------------------- /test/example_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | class TestStrings(unittest.TestCase): 4 | 5 | def test_upper(self): 6 | self.assertEqual('foo'.upper(), 'FOO') 7 | self.assertTrue('foo'.upper() == 'FOO') 8 | #self.assertEqual('foo'.upper(), "Foo") 9 | 10 | def test_isupper(self): 11 | self.assertTrue('FOO'.isupper()) 12 | self.assertFalse('Foo'.isupper()) 13 | 14 | def test_split(self): 15 | s = 'hello world' 16 | self.assertEqual(s.split(), ['hello', 'world']) 17 | # check that s.split fails when the separator is not a string 18 | with self.assertRaises(TypeError): 19 | s.split(2) 20 | 21 | if __name__ == '__main__': # only run if this script is invoked from the command-line: 22 | unittest.main() 23 | -------------------------------------------------------------------------------- /test/team_test.py: -------------------------------------------------------------------------------- 1 | # OBJECTIVES: 2 | # 3 | # 1) make sure that we can initialize / instantiate our Team class 4 | # 5 | # 2) make sure that the Team class' .full_name property behaves as desired 6 | # 7 | 8 | import unittest 9 | 10 | from app.team import Team 11 | 12 | class TestTeams(unittest.TestCase): 13 | 14 | def test_full_name(self): 15 | team = Team("New York", "Giants", []) 16 | self.assertEqual(team.full_name, "New York Giants") 17 | 18 | if __name__ == "__main__": # only run if this script is invoked from the command-line: 19 | unittest.main() 20 | --------------------------------------------------------------------------------