forked from tecladocode/complete-python-course
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Moved contents, added new sections for course update.
- Loading branch information
Showing
199 changed files
with
800 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,8 @@ __pycache__/ | |
*.pyc | ||
*.screenflow | ||
*.mp4 | ||
*.mov | ||
*.cmproj | ||
exports/ | ||
videos/ | ||
*.numbers | ||
|
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
12 changes: 12 additions & 0 deletions
12
course_contents/12_browser_automation_selenium/code/Pipfile
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
[[source]] | ||
name = "pypi" | ||
url = "https://pypi.org/simple" | ||
verify_ssl = true | ||
|
||
[dev-packages] | ||
|
||
[packages] | ||
selenium = "*" | ||
|
||
[requires] | ||
python_version = "3.7" |
36 changes: 36 additions & 0 deletions
36
course_contents/12_browser_automation_selenium/code/Pipfile.lock
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
25 changes: 25 additions & 0 deletions
25
course_contents/12_browser_automation_selenium/code/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Browser automation with Selenium | ||
|
||
The code is very similar to last section, but now we're launching a browser instead of requesting the page with Python. We will be controlling the browser, instead of just getting HTML. | ||
|
||
The browser will work like a normal browser: it will run JavaScript, it will have cookies, etc... | ||
|
||
## Requirements | ||
|
||
- Selenium library | ||
- A webdriver | ||
|
||
### Selenium | ||
|
||
Install `selenium` using PyCharm's preferences panel or in your virtual environment. | ||
|
||
### Webdriver | ||
|
||
Each of the major browsers releases a webdriver for their browser. It essentially allows other applications to interact with the browser. In this course we use the Chrome webdriver. | ||
|
||
Download it from http://chromedriver.chromium.org/. Make sure to download the version for your browser (e.g. v74 if you're using Chrome v74). | ||
|
||
Place the de-compressed executable, `chromedriver`, into a folder. Remember the folder's path, as you'll need it after. | ||
|
||
## Recap | ||
|
33 changes: 33 additions & 0 deletions
33
course_contents/12_browser_automation_selenium/code/app.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
from pages.quotes_page import QuotesPage, InvalidTagForAuthorError | ||
from selenium import webdriver | ||
|
||
# chrome = webdriver.Chrome(executable_path='/usr/local/bin/chromedriver') | ||
# chrome.get('http://quotes.toscrape.com/search.aspx') | ||
# page = QuotesPage(chrome) | ||
|
||
# author = input("Enter the author you'd like quotes from: ") | ||
# page.select_author(author) | ||
|
||
# tags = page.get_available_tags() | ||
# print("Select one of these tags: [{}]".format(" | ".join(tags))) | ||
# selected_tag = input("Enter your tag: ") | ||
|
||
# page.select_tag(selected_tag) | ||
# page.search_button.click() | ||
# print(page.quotes) | ||
|
||
# -- | ||
|
||
try: | ||
author = input("Enter the author you'd like quotes from: ") | ||
tag = input("Enter your tag: ") | ||
|
||
chrome = webdriver.Chrome(executable_path='/usr/local/bin/chromedriver') | ||
chrome.get('http://quotes.toscrape.com/search.aspx') | ||
page = QuotesPage(chrome) | ||
|
||
print(page.search_for_quotes(author, tag)) | ||
except InvalidTagForAuthorError as e: | ||
print(e) | ||
except Exception: | ||
print("An unknown error occurred. Please try again.") |
File renamed without changes.
4 changes: 4 additions & 0 deletions
4
course_contents/12_browser_automation_selenium/code/locators/quote_locators.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
class QuoteLocators: | ||
CONTENT_LOCATOR = 'span.content' | ||
AUTHOR_LOCATOR = 'span.author' | ||
TAGS_LOCATOR = 'span.tag' |
5 changes: 5 additions & 0 deletions
5
course_contents/12_browser_automation_selenium/code/locators/quotes_page_locators.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
class QuotesPageLocators: | ||
QUOTE = 'div.quote' | ||
AUTHOR_DROPDOWN = 'select#author' | ||
TAG_DROPDOWN = 'select#tag' | ||
SEARCH_BUTTON = 'input[name="submit_button"]' |
File renamed without changes.
51 changes: 51 additions & 0 deletions
51
course_contents/12_browser_automation_selenium/code/pages/quotes_page.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
from typing import List | ||
from selenium.webdriver.support.ui import Select | ||
from selenium.common.exceptions import NoSuchElementException | ||
|
||
from locators.quotes_page_locators import QuotesPageLocators | ||
from parsers.quote import QuoteParser | ||
|
||
|
||
class QuotesPage: | ||
def __init__(self, browser): | ||
self.browser = browser | ||
|
||
@property | ||
def quotes(self) -> List[QuoteParser]: | ||
return [QuoteParser(e) for e in self.browser.find_elements_by_css_selector(QuotesPageLocators.QUOTE)] | ||
|
||
@property | ||
def author_dropdown(self) -> Select: | ||
element = self.browser.find_element_by_css_selector(QuotesPageLocators.AUTHOR_DROPDOWN) | ||
return Select(element) | ||
|
||
@property | ||
def tags_dropdown(self): | ||
element = self.browser.find_element_by_css_selector(QuotesPageLocators.TAG_DROPDOWN) | ||
return Select(element) | ||
|
||
@property | ||
def search_button(self): | ||
return self.browser.find_element_by_css_selector(QuotesPageLocators.SEARCH_BUTTON) | ||
|
||
def select_author(self, author_name: str): | ||
self.author_dropdown.select_by_visible_text(author_name) | ||
|
||
def get_available_tags(self) -> List[str]: | ||
return [option.text for option in self.tags_dropdown.options] | ||
|
||
def select_tag(self, tag_name: str): | ||
self.tags_dropdown.select_by_visible_text(tag_name) | ||
|
||
def search_for_quotes(self, author_name: str, tag_name: str) -> List[QuoteParser]: | ||
self.select_author(author_name) | ||
try: | ||
self.select_tag(tag_name) | ||
except NoSuchElementException: | ||
raise InvalidTagForAuthorError(f"Author '{author_name}' does not have any quotes tagged with '{tag_name}'.") | ||
self.search_button.click() | ||
return self.quotes | ||
|
||
|
||
class InvalidTagForAuthorError(ValueError): | ||
pass |
File renamed without changes.
24 changes: 24 additions & 0 deletions
24
course_contents/12_browser_automation_selenium/code/parsers/quote.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
from locators.quote_locators import QuoteLocators | ||
|
||
|
||
class QuoteParser: | ||
def __init__(self, parent): | ||
self.parent = parent | ||
|
||
def __repr__(self): | ||
return f'<Quote {self.content}, by {self.author}>' | ||
|
||
@property | ||
def content(self): | ||
locator = QuoteLocators.CONTENT_LOCATOR | ||
return self.parent.find_element_by_css_selector(locator).text | ||
|
||
@property | ||
def author(self): | ||
locator = QuoteLocators.AUTHOR_LOCATOR | ||
return self.parent.find_element_by_css_selector(locator).text | ||
|
||
@property | ||
def tags(self): | ||
locator = QuoteLocators.TAGS_LOCATOR | ||
return self.parent.find_element_by_css_selector(locator) |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Interacting with APIs | ||
|
||
## Requirements | ||
|
||
- requests | ||
- cachetools (for part 3) | ||
- An account with OpenExchangeRates (free) | ||
- Generate an **App ID** on their website, you need this to use their API. | ||
|
||
## Recap | ||
|
||
First two parts recapped here: https://blog.tecladocode.com/how-to-interact-with-apis-using-python/ | ||
|
||
### Caching | ||
|
||
Can use something like `functools.lru_cache` for caching function calls. That is, if you apply this decorator to a function and then you call the function with the same arguments 10 times, 9 of them will be really quick and the function won't evaluate. | ||
|
||
Can use `cachetools.TTLCache` to cache a function call for up to a certain amount of time. When interacting with APIs it can be useful as sometimes we won't be interested in repeating the same call over and over. |
12 changes: 12 additions & 0 deletions
12
course_contents/16_interacting_with_apis/code/1_simple_interaction/app.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import requests | ||
|
||
APP_ID = "72dba35060b54cf9ad3ffbdc68de9174" | ||
ENDPOINT = "https://openexchangerates.org/api/latest.json" | ||
|
||
response = requests.get(f"{ENDPOINT}?app_id={APP_ID}") | ||
exchange_rates = response.json() | ||
|
||
usd_amount = 1000 | ||
gbp_amount = usd_amount * exchange_rates['rates']['GBP'] | ||
|
||
print(f"USD{usd_amount} is GBP{gbp_amount}") |
10 changes: 10 additions & 0 deletions
10
course_contents/16_interacting_with_apis/code/2_creating_a_library/app.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from libs.openexchange import OpenExchangeClient | ||
|
||
APP_ID = "72dba35060b54cf9ad3ffbdc68de9174" | ||
|
||
client = OpenExchangeClient(APP_ID) | ||
|
||
usd_amount = 1000 | ||
gbp_amount = client.convert(usd_amount, 'USD', 'GBP') | ||
|
||
print(f"USD{usd_amount} is GBP{gbp_amount}") |
File renamed without changes.
24 changes: 24 additions & 0 deletions
24
course_contents/16_interacting_with_apis/code/2_creating_a_library/libs/openexchange.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import requests | ||
import functools | ||
|
||
|
||
class OpenExchangeClient: | ||
BASE_URL = "https://openexchangerates.org/api/" | ||
|
||
def __init__(self, app_id): | ||
self.app_id = app_id | ||
|
||
@property | ||
def latest(self): | ||
return requests.get(f"{self.BASE_URL}/latest.json?app_id={self.app_id}").json() | ||
|
||
def convert(self, from_amount, from_currency, to_currency): | ||
rates = self.latest['rates'] | ||
to_rate = rates[to_currency] | ||
|
||
if from_currency == 'USD': | ||
return from_amount * to_rate | ||
else: | ||
from_in_usd = from_amount / rates[from_currency] | ||
return from_in_usd * to_rate | ||
|
28 changes: 28 additions & 0 deletions
28
course_contents/16_interacting_with_apis/code/3_speed_up_with_cache/app.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
from libs.openexchange import OpenExchangeClient | ||
import time | ||
|
||
|
||
|
||
APP_ID = "72dba35060b54cf9ad3ffbdc68de9174" | ||
|
||
client = OpenExchangeClient(APP_ID) | ||
|
||
usd_amount = 1000 | ||
start = time.time() | ||
gbp_amount = client.convert(usd_amount, 'USD', 'GBP') | ||
print(f'First call took {time.time() - start} seconds.') | ||
|
||
start = time.time() | ||
gbp_amount = client.convert(usd_amount, 'USD', 'GBP') | ||
gbp_amount = client.convert(usd_amount, 'USD', 'GBP') | ||
gbp_amount = client.convert(usd_amount, 'USD', 'GBP') | ||
gbp_amount = client.convert(usd_amount, 'USD', 'GBP') | ||
gbp_amount = client.convert(usd_amount, 'USD', 'GBP') | ||
gbp_amount = client.convert(usd_amount, 'USD', 'GBP') | ||
gbp_amount = client.convert(usd_amount, 'USD', 'GBP') | ||
gbp_amount = client.convert(usd_amount, 'USD', 'GBP') | ||
gbp_amount = client.convert(usd_amount, 'USD', 'GBP') | ||
gbp_amount = client.convert(usd_amount, 'USD', 'GBP') | ||
print(f'After, 10 calls took {time.time() - start} seconds.') | ||
|
||
print(f"USD{usd_amount} is GBP{gbp_amount}") |
File renamed without changes.
25 changes: 25 additions & 0 deletions
25
course_contents/16_interacting_with_apis/code/3_speed_up_with_cache/libs/openexchange.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import requests | ||
from cachetools import cached, TTLCache | ||
|
||
|
||
class OpenExchangeClient: | ||
BASE_URL = "https://openexchangerates.org/api/" | ||
|
||
def __init__(self, app_id): | ||
self.app_id = app_id | ||
|
||
@property | ||
@cached(cache=TTLCache(maxsize=2, ttl=900)) | ||
def latest(self): | ||
return requests.get(f"{self.BASE_URL}/latest.json?app_id={self.app_id}").json() | ||
|
||
def convert(self, from_amount, from_currency, to_currency): | ||
rates = self.latest['rates'] | ||
to_rate = rates[to_currency] | ||
|
||
if from_currency == 'USD': | ||
return from_amount * to_rate | ||
else: | ||
from_in_usd = from_amount / rates[from_currency] | ||
return from_in_usd * to_rate | ||
|
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
from typing import Union, Tuple | ||
|
||
def divide(dividend: Union[int, float], divisor: Union[int, float]): | ||
if divisor == 0: | ||
raise ValueError('The divisor cannot be zero.') | ||
|
||
return dividend / divisor | ||
|
||
|
||
def multiply(*args: Tuple[Union[int, float]]): | ||
if len(args) == 0: | ||
raise ValueError('At least one value to multiply must be passed.') | ||
total = 1 | ||
for arg in args: | ||
total *= arg | ||
|
||
return total |
Oops, something went wrong.