Skip to content

Commit

Permalink
⬆️ Bump fastapi 0.87.0 -> 0.103.2
Browse files Browse the repository at this point in the history
  • Loading branch information
otytlandsvik committed Oct 15, 2023
1 parent f8c2578 commit 7488d86
Show file tree
Hide file tree
Showing 15 changed files with 1,137 additions and 886 deletions.
2 changes: 1 addition & 1 deletion .docker/dockerfile.api.development
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.9
FROM python:3.11

WORKDIR /app

Expand Down
2 changes: 1 addition & 1 deletion .docker/dockerfile.api.production
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.9 as Build
FROM python:3.11 as Build

# creates production user
RUN useradd --create-home prod_user
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/python-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ jobs:
uses: supercharge/[email protected]

- uses: actions/checkout@v1
- name: Set up Python 3.9
- name: Set up Python 3.11
uses: actions/setup-python@v1
with:
python-version: 3.9
python-version: 3.11

- name: Install pipenv
run: pip install pipenv
Expand Down
8 changes: 4 additions & 4 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ pylint = "*"
[packages]
pyjwt = "==2.6.0"
Werkzeug = "==2.2.3"
"fastapi[all]" = "==0.87.0"
"fastapi[all]" = "==0.103.2"
pymongo = "==4.3.3"
uvicorn = "==0.20.0"
email-validator = "1.3.0"
email-validator = "2.0.0"
python-multipart = "0.0.5"
aiofiles = "22.1.0"
pytest = "7.2.0"
pytest = "7.4.2"
google-api-python-client = "2.66.0"
google-auth-httplib2 = "0.1.0"
google-auth-oauthlib = "0.7.1"
Expand All @@ -30,4 +30,4 @@ numpy = "1.23.5"
openpyxl = "3.0.9"
xlsxwriter = "3.0.3"
[requires]
python_version = "3.9"
python_version = "3.11"
1,809 changes: 1,030 additions & 779 deletions Pipfile.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions app/api/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def create_admin_user(request: Request, newAdmin: MemberInput, token: AccessToke
'status': f'{Status.inactive}',
}

admin = newAdmin.dict()
admin = newAdmin.model_dump()
admin.update(additionalFields)
# Create user object
db.members.insert_one(admin)
Expand All @@ -65,7 +65,7 @@ def create_admin_user(request: Request, newAdmin: MemberInput, token: AccessToke
def update_member(request: Request, id: str, memberData: AdminMemberUpdate, token: AccessTokenPayload = Depends(authorize_admin)):
db = get_database(request)

values = memberData.dict()
values = memberData.model_dump()
updateInfo = {}
for key in values:
if values[key] or values[key] == 0:
Expand Down
10 changes: 5 additions & 5 deletions app/api/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def login(request: Request, credentials: Credentials, response: Response):
if not member:
raise HTTPException(401, 'Invalid e-mail')
#raise credential_exception
member = MemberDB.parse_obj(member)
member = MemberDB.model_validate(member)

if not check_password_hash(member.password, credentials.password):
raise credential_exception
Expand All @@ -43,7 +43,7 @@ def login(request: Request, credentials: Credentials, response: Response):
def logout(request: Request, response: Response):
try:
refresh_token = request.cookies.get("refresh_token") or ""
token = RefreshTokenPayload.parse_obj(decode_token(
token = RefreshTokenPayload.model_validate(decode_token(
refresh_token, request.app.config))
except:
raise HTTPException(401, "Refresh token is invalid")
Expand All @@ -60,7 +60,7 @@ def renew(request: Request, response: Response):
if not refresh_token:
raise HTTPException(401, 'Refresh token is not present')

tokenPayload = RefreshTokenPayload.parse_obj(
tokenPayload = RefreshTokenPayload.model_validate(
decode_token(refresh_token, request.app.config))

if is_blacklisted(tokenPayload, request.app.db):
Expand All @@ -70,7 +70,7 @@ def renew(request: Request, response: Response):
# Edge case
raise HTTPException(
400, 'The member associated with refresh token no longer exists')
user = MemberDB.parse_obj(user)
user = MemberDB.model_validate(user)
token = create_token(user, request.app.config)
refresh_token = create_refresh_token(user, request.app.config)
set_auth_cookies(response, token, refresh_token)
Expand All @@ -83,7 +83,7 @@ def renew(request: Request, response: Response):
@router.post('/password')
def change_password(passwords: ChangePasswordPayload, request: Request, token: AccessTokenPayload = Depends(authorize)):
db = get_database(request)
user = MemberDB.parse_obj(db.members.find_one({'id': UUID(token.user_id)}))
user = MemberDB.model_validate(db.members.find_one({'id': UUID(token.user_id)}))
if not user:
raise HTTPException(401, 'User not found')

Expand Down
30 changes: 15 additions & 15 deletions app/api/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def create_event(request: Request, newEvent: EventInput, token: AccessTokenPaylo
if newEvent.bindingRegistration:
additionalFields['confirmed'] = False

event = newEvent.dict()
event = newEvent.model_dump()
event.update(additionalFields)
event = db.events.insert_one(event)

Expand Down Expand Up @@ -90,7 +90,7 @@ def get_upcoming_events(request: Request, token: AccessTokenPayload = Depends(op

upcoming_events = db.events.find(search_filter)

return [Event.parse_obj(event) for event in upcoming_events]
return [Event.model_validate(event) for event in upcoming_events]

@router.get('/past-events')
def get_past_events(request: Request, token: AccessTokenPayload = Depends(optional_authentication)):
Expand Down Expand Up @@ -125,7 +125,7 @@ def get_past_events(request: Request, token: AccessTokenPayload = Depends(option
if not res:
raise HTTPException(500)

return [Event.parse_obj(event) for event in res]
return [Event.model_validate(event) for event in res]


@router.get('/joined-events')
Expand Down Expand Up @@ -155,7 +155,7 @@ def get_joined_events(request: Request, token: AccessTokenPayload = Depends(auth
]
res = db.events.aggregate(pipeline)

return [EventUserView.parse_obj(e) for e in res]
return [EventUserView.model_validate(e) for e in res]


# custom uuid validation as eid: UUID will not allow users to copy eids into swagger as they are not formatted correctly
Expand Down Expand Up @@ -196,7 +196,7 @@ def update_event(request: Request, id: str, eventUpdate: EventUpdate, AccessToke
event = get_event_or_404(db, id)

# exclude_unset allows null to be included allowing for optional fields to be updated to be null i.e not present
values = eventUpdate.dict(exclude_unset=True)
values = eventUpdate.model_dump(exclude_unset=True)
if len(values) == 0:
raise HTTPException(400, "Update values cannot be empty")

Expand All @@ -212,7 +212,7 @@ def update_event(request: Request, id: str, eventUpdate: EventUpdate, AccessToke

# check if update does not remove required fields i.e a valid update
try:
EventDB.parse_obj({**event, **values})
EventDB.model_validate({**event, **values})
except ValidationError:
raise HTTPException(
400, "Cannot remove field as this is required filed for all events")
Expand Down Expand Up @@ -254,9 +254,9 @@ def get_event_by_id(request: Request, id: str, token: AccessTokenPayload = Depen
403, "Insufficient privileges to access this resource")

if role == Role.admin:
return EventDB.parse_obj(event)
return EventDB.model_validate(event)

return EventUserView.parse_obj(event)
return EventUserView.model_validate(event)


@router.get('/{id}/participants', dependencies=[Depends(validate_uuid)])
Expand All @@ -265,7 +265,7 @@ def get_event_participants(request: Request, id: str, token: AccessTokenPayload
event = get_event_or_404(db, id)

if token.role == Role.admin:
return [Participant.parse_obj(p) for p in event['participants']]
return [Participant.model_validate(p) for p in event['participants']]

if event["maxParticipants"] != None:
# only return the list when events are open i.e no cap
Expand Down Expand Up @@ -318,7 +318,7 @@ def update_event_options(request: Request, id: str, payload: JoinEventPayload, t
raise HTTPException(400, "Cannot update options for confirmed event")

# Create a dictionary with the payload
values = payload.dict(exclude_unset=True)
values = payload.model_dump(exclude_unset=True)
update_dict = {f"participants.$.{key}": value for key, value in values.items()}

# Update db field
Expand Down Expand Up @@ -369,7 +369,7 @@ def join_event(request: Request, id: str, payload: JoinEventPayload, token: Acce
}

new_fields = {**member, **participantData}
participant = Participant.parse_obj(new_fields)
participant = Participant.model_validate(new_fields)

# find pos in query to have the newest list when inserting
pos = len(event["participants"])
Expand All @@ -381,7 +381,7 @@ def join_event(request: Request, id: str, payload: JoinEventPayload, token: Acce
{'eid': event['eid']},
{"$push": {
"participants": {
"$each": [participant.dict()],
"$each": [participant.model_dump()],
"$position": pos}
}
})
Expand Down Expand Up @@ -514,7 +514,7 @@ async def reorder_participants(request: Request, id:str, position_update: Partic
raise HTTPException(400, "Not valid: got invalid or outdated participant list")

for participant in position_update.updateList:
participant = participant.dict()
participant = participant.model_dump()
for i, p in enumerate(participants):
if p["id"] == participant["id"]:
new_pos = participant["pos"]
Expand All @@ -532,7 +532,7 @@ async def reorder_participants(request: Request, id:str, position_update: Partic
if event["maxParticipants"]:
for i, p in enumerate(participants):
# ensure fields exist
p = Participant.parse_obj(p).dict()
p = Participant.model_validate(p).model_dump()
if p["confirmed"] and i >= event["maxParticipants"]:
raise HTTPException(400, "Confirmed user cannot be moved to a non confirmed spot")

Expand Down Expand Up @@ -853,7 +853,7 @@ async def exportEvent(background_tasks: BackgroundTasks, request: Request, id: s
event = get_event_or_404(db, id)

participants = [Participant(
**p).copy(exclude={'id'}).dict() for p in event['participants']]
**p).model_copy().model_dump(exclude={'id'}) for p in event['participants']]

event_details = [{'Title': event['title'], 'date':event['date'], 'address':event['address'], 'price':event['price'],
'maxParticipants':event['maxParticipants'], 'duration':event['duration'], 'transportation':str(event['transportation']), 'food':str(event['food'])}]
Expand Down
14 changes: 7 additions & 7 deletions app/api/jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
def get_jobs(request: Request):
db = get_database(request)
jobs = db.jobs.find()
return [JobItem.parse_obj(job) for job in jobs]
return [JobItem.model_validate(job) for job in jobs]


@router.get('/{id}')
Expand All @@ -29,18 +29,18 @@ def get_job_by_id(request: Request, id: str):
job = db.jobs.find_one({'id': UUID(id)})
if job == None:
raise HTTPException(404, "No such job with this id")
return JobItem.parse_obj(job)
return JobItem.model_validate(job)


@router.post('/')
def create_job(request: Request, job: JobItemPayload, token: AccessTokenPayload = Depends(authorize_admin)):
db = get_database(request)
item = job.dict()
item = job.model_dump()
jid = uuid4()
item['id'] = jid
item['published_date'] = datetime.now()
_job = JobItem.parse_obj(item)
retval = db.jobs.insert_one(_job.dict())
_job = JobItem.model_validate(item)
retval = db.jobs.insert_one(_job.model_dump())
if not retval:
raise HTTPException(500, "Job could not be created")

Expand All @@ -64,12 +64,12 @@ def update_job(request: Request, id: str, job: UpdateJob, token: AccessTokenPayl
if not orig_job:
raise HTTPException(404, "Job could not be found")

_job = job.dict(exclude_unset=True)
_job = job.model_dump(exclude_unset=True)
if len(_job) == 0:
raise HTTPException(400, "Update values cannot be empty")

try:
JobItem.parse_obj({**orig_job, **_job})
JobItem.model_validate({**orig_job, **_job})
except ValidationError:
raise HTTPException(
400, "Cannot remove field as this is required filed for all jobs")
Expand Down
12 changes: 6 additions & 6 deletions app/api/members.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def create_new_member(request: Request, newMember: MemberInput):
'penalty': 0
}

member = newMember.dict()
member = newMember.model_dump()
member.update(additionalFields)
# Create user object
db.members.insert_one(member)
Expand All @@ -62,7 +62,7 @@ def get_member_associated_with_token(request: Request, token: AccessTokenPayload
currentMember = db.members.find_one({'id': UUID(token.user_id)})
if not currentMember:
raise HTTPException(404, "User could not be found")
return Member.parse_obj(currentMember)
return Member.model_validate(currentMember)


@router.get('/{id}', response_model=Member, responses={404: {"model": None}}, dependencies=[Depends(validate_uuid)])
Expand All @@ -72,7 +72,7 @@ def get_member_by_id(request: Request, id: str, token: dict = Depends(authorize)
member = db.members.find_one({'id': UUID(id)})
if not member:
raise HTTPException(404, 'Member not found')
return Member.parse_obj(member)
return Member.model_validate(member)

@router.get('/email/{email}')
def get_member_by_email(request: Request, email: EmailStr, token: AccessTokenPayload = Depends(authorize_admin)):
Expand All @@ -86,7 +86,7 @@ def get_member_by_email(request: Request, email: EmailStr, token: AccessTokenPay
def get_all_members(request: Request, token: AccessTokenPayload = Depends(authorize_admin)):
'''List all members objects'''
db = get_database(request)
return [Member.parse_obj(m) for m in db.members.find()]
return [Member.model_validate(m) for m in db.members.find()]

@router.post('/activate')
def change_status(request: Request, token: AccessTokenPayload = Depends(authorize)):
Expand All @@ -96,7 +96,7 @@ def change_status(request: Request, token: AccessTokenPayload = Depends(authoriz
if not member:
raise HTTPException(404, 'Member not found')

member = MemberDB.parse_obj(member)
member = MemberDB.model_validate(member)
if member.status == Status.active:
raise HTTPException(400, "member already activated")

Expand Down Expand Up @@ -258,7 +258,7 @@ def update_member(request: Request, memberData: MemberUpdate, token: AccessToken
if not member:
raise HTTPException(404, "User not found")

values = memberData.dict()
values = memberData.model_dump()
updateInfo = {}
for key in values:
if values[key]:
Expand Down
2 changes: 1 addition & 1 deletion app/api/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def get_event_or_404(db, eid: str):
if not event:
raise HTTPException(404, "Event could not be found")

return EventDB.parse_obj(event).dict()
return EventDB.model_validate(event).model_dump()


async def penalize(db, uid: UUID):
Expand Down
6 changes: 3 additions & 3 deletions app/auth_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def authorize(request: Request):
raise HTTPException(
401, 'Access token is not present')

payload = AccessTokenPayload.parse_obj(decode_token(
payload = AccessTokenPayload.model_validate(decode_token(
access_token, request.app.config))

if not payload.access_token:
Expand All @@ -64,7 +64,7 @@ def optional_authentication(request: Request):
try:
# Don't use decode_token function as it raises an exception which we
# do not want on optional authentication
payload = AccessTokenPayload.parse_obj(decode(access_token, request.app.config.SECRET_KEY, algorithms=['HS256']))
payload = AccessTokenPayload.model_validate(decode(access_token, request.app.config.SECRET_KEY, algorithms=['HS256']))
return payload.access_token and payload or None
except:
return None
Expand Down Expand Up @@ -129,7 +129,7 @@ def blacklist_token(refreshToken: RefreshTokenPayload, db: Database):
Blacklists the provided (decoded) refresh token.
'''
# Insert token into database
db.tokens.insert_one(refreshToken.dict())
db.tokens.insert_one(refreshToken.model_dump())


def is_blacklisted(refreshToken: RefreshTokenPayload, db: Database):
Expand Down
Loading

0 comments on commit 7488d86

Please sign in to comment.