Skip to content

Commit

Permalink
python: various updates
Browse files Browse the repository at this point in the history
  • Loading branch information
marko-knoebl committed Sep 15, 2021
1 parent 52c256c commit 88aa903
Show file tree
Hide file tree
Showing 23 changed files with 494 additions and 344 deletions.
16 changes: 16 additions & 0 deletions exercises/python-in-practice/fastapi_contacts/data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"contacts": [
{
"id": 1,
"first_name": "John",
"last_name": "Doe",
"phone_nr": "+123456789"
},
{
"id": 2,
"first_name": "Jane",
"last_name": "Doe",
"phone_nr": "+987654321"
}
]
}
104 changes: 104 additions & 0 deletions exercises/python-in-practice/fastapi_contacts/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
from typing import Optional
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import json


class Contact(BaseModel):
id: int
first_name: str
last_name: str
phone_nr: str


app = FastAPI()


def load_contacts():
with open("./data.json", encoding="utf-8") as data_file:
contents = json.load(data_file)
contacts = contents["contacts"]
return contacts


def save_contacts(contacts):
with open("./data.json", "w", encoding="utf-8") as data_file:
json.dump({"contacts": contacts}, data_file, indent=2)


@app.get("/")
def read_contacts(first_name: str = None):
result = []
contacts = load_contacts()
if first_name:
for contact in contacts:
if first_name.lower() in contact["first_name"].lower():
result.append(contact)
return result
else:
return contacts


@app.get("/{contact_id}")
def read_contact(contact_id: int):
contacts = load_contacts()
for contact in contacts:
if contact["id"] == contact_id:
return contact
raise HTTPException(status_code=404, detail="item not found")


@app.post("/")
def add_contact(first_name: str, last_name: str, phone_nr: str):
contacts = load_contacts()
max_id = 0
for c in contacts:
if c["id"] > max_id:
max_id = c["id"]
contact = {
"id": max_id + 1,
"first_name": first_name,
"last_name": last_name,
"phone_nr": phone_nr,
}
contacts.append(contact)
save_contacts(contacts)


@app.put("/{contact_id}")
def replace_contact(contact_id: int, first_name: str, last_name: str, phone_nr: str):
contacts = load_contacts()
for (i, contact) in enumerate(contacts):
if contact["id"] == contact_id:
contacts[i] = {
"id": contact_id,
"first_name": first_name,
"last_name": last_name,
"phone_nr": phone_nr,
}
break
save_contacts(contacts)


@app.patch("/{todo_id}")
def modify_contact(
contact_id: int, first_name: str = None, last_name: str = None, phone_nr: str = None
):
contacts = load_contacts()
for contact in contacts:
if contact["id"] == contact_id:
if first_name:
contact["first_name"] = first_name
if last_name:
contact["last_name"] = last_name
if phone_nr:
contact["phone_nr"] = phone_nr
break
save_contacts(contacts)


@app.delete("/{todo_id}")
def delete_contact(contact_id: int):
contacts = load_contacts()
new_contacts = [c for c in contacts if c["id"] != contact_id]
save_contacts(new_contacts)
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"todos": [
{
"id": 1,
"title": "abc",
"completed": false
},
{
"id": 3,
"title": "xyz",
"completed": false
}
]
}
{
"todos": [
{
"id": 1,
"title": "abc",
"completed": false
},
{
"id": 3,
"title": "xyz",
"completed": false
}
]
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# start with:
# uvicorn main:app --reload

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import json
Expand All @@ -22,20 +25,10 @@ def load_todos():

def save_todos(todos):
data_file = open("./data.json", "w", encoding="utf-8")
content = json.dump({"todos": todos}, data_file, indent=2)
json.dump({"todos": todos}, data_file, indent=2)
data_file.close()


@app.get("/")
def read_root():
return {"Hello": "World"}


@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q}


@app.get("/todos/")
def read_todos():
todos = load_todos()
Expand All @@ -45,10 +38,10 @@ def read_todos():
@app.get("/todos/{todo_id}")
def read_todo(todo_id: int):
todos = load_todos()
filtered_todos = [todo for todo in todos if todo["id"] == todo_id]
if len(filtered_todos) == 0:
raise HTTPException(status_code=404, detail="Item not found")
return filtered_todos[0]
for todo in todos:
if todo["id"] == todo_id:
return todo
raise HTTPException(status_code=404, detail="Item not found")


@app.post("/todos")
Expand All @@ -63,16 +56,16 @@ def add_todo(title: str):
save_todos(todos)


@app.put("/todos/{todo_id}")
def modify_todo(todo_id: int, todo: Todo):
@app.delete("/todos/{todo_id}")
def delete_todo(todo_id: int):
todos = load_todos()
filtered_todos = [todo for todo in todos if todo["id"] == todo_id]
if len(filtered_todos) == 0:
found_index = None
for index, todo in enumerate(todos):
if todo_id == todo["id"]:
found_index = index
if found_index is None:
raise HTTPException(status_code=404, detail="todo not found")
t = filtered_todos[0]
t["id"] = todo.id
t["title"] = todo.title
t["completed"] = todo.completed
todos.pop(found_index)
save_todos(todos)


Expand All @@ -90,14 +83,21 @@ def modify_todo(todo_id: int, title: str = None, completed: bool = None):
save_todos(todos)


@app.delete("/todos/{todo_id}")
def delete_todo(todo_id: int):
@app.put("/todos/{todo_id}")
def modify_todo(todo_id: int, todo: Todo):
todos = load_todos()
found_index = None
for index, todo in enumerate(todos):
if todo_id == todo["id"]:
found_index = index
if found_index is None:
filtered_todos = [todo for todo in todos if todo["id"] == todo_id]
if len(filtered_todos) == 0:
raise HTTPException(status_code=404, detail="todo not found")
todos.pop(found_index)
t = filtered_todos[0]
t["id"] = todo.id
t["title"] = todo.title
t["completed"] = todo.completed
save_todos(todos)


@app.post("delete_completed_todos")
def delete_completed_todos():
todos = load_todos()
filtered_todos = [t for t in todos if not t["completed"]]
save_todos(filtered_todos)
Original file line number Diff line number Diff line change
@@ -1,30 +1,61 @@
# Iterators
# Iterables und Iterators

## Iterables und Iterators

_Iterable_: ein Objekt, über das mittels `for element in my_iterable` iteriert werden kann

_Iterator_: ein leichtgewichtiges Iterable
- "statisches _Iterable_": Elementenabfolge ist vordefiniert (z.B. _list_)
- "dynamisches _Iterable_": Elemente werden während des Durchlaufs erzeugt (z.B. _range_)

## Iterables und Iterators

Beispiele für Iterables:
Hierarchie von Iterables:

- lists
- dicts
- range-Objekte
- iterators

## Iterators
- "statische Iterables" (z.B. _list_, _dict_)
- "dynamische Iterables" (z.B. _range_)
- Iterators (z.B. _enumerate_, _os.scandir_)
- Generators (selbst-definiert)

Ein _Iterator_ ist ein ressourcensparendes Iterable
## Iterables und Iterators

Mögliche Vorteile eines Iterators gegenüber Listen:
Vorteile von "dynamischen Iterables" / Iterators:

- Ressourcen werden nur bei Bedarf erstellt / abgefragt
- Speicherverbrauch bleibt niedrig (nur je ein Element ist jeweils im Speicher)

## Iterators
## Iterables und Iterators

Beispiele für "statische Iterables":

- list
- tuple
- dict
- string

## Iterables und Iterators

Beispiele für "dynamische Iterables":

- range-Objekte
- iterators

## Iterables und Iterators

Aufrufe, die Iterators zurückgeben:

- `enumerate()`
- `reversed()`
- `open()`
- `os.walk()`
- `os.scandir()`
- `map()`
- `filter()`
- Funktionen in _itertools_
- üblicherweise Datenbankcursor (PEP 249)
- Generators
- ...

## Iterables und Iterators

Beispiel: `open()` gibt einen Iterator von Zeilen einer Datei zurück

Expand All @@ -34,9 +65,9 @@ with open("./foo.txt", encoding="utf-8") as f:
print line
```

Die Datei könnte mehrere GB oder größer sein und dieser Code würde problemlos laufen
Die Datei könnte mehrere GB groß sein und dieser Code würde problemlos laufen

## Iterators
## Iterators und Iterators

Beispielfunktionen:

Expand All @@ -54,23 +85,6 @@ for text in read_textfiles_as_iterator("./foo/"):
print(text[:5])
```

## Iterators

Aufrufe, die Iterators zurückgeben:

- `enumerate()`
- `reversed()`
- `open()`
- `os.walk()`
- `os.scandir()`
- `map()`
- `filter()`
- Funktionen in _itertools_
- üblicherweise Datenbankcursor (PEP 249)
- ...

Bemerkung: `range` gibt keinen Iterator zurück (aber ein ähnliches Objekt)

## Itertools

[itertools](https://docs.python.org/3/library/itertools.html): Modul zum erstellen von Iterators
Expand Down
Loading

0 comments on commit 88aa903

Please sign in to comment.