Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to python 3.13 #1709

Draft
wants to merge 3 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/code_quality.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-python@v3
with:
python-version: "3.11"
python-version: "3.13"
- name: Install git-secrets in the repository
run: git secrets --install
- name: Install git-secrets aws register in the repository
Expand Down
12 changes: 6 additions & 6 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ alembic = "==1.14.0"
asyncpg = "==0.30.0"
azure-storage-blob = "==12.24.0"
bcrypt = "==4.2.1"
boto3 = "==1.35.*"
boto3 = "==1.36.*"
fastapi = "==0.115.6"
fastapi-mail = "==1.2.9"
firebase-admin = "==6.6.*"
httpx = "==0.28.*"
jinja2 = "==3.1.*"
more-itertools = "==10.5.0"
more-itertools = "==10.6.0"
nh3 = "==0.2.20"
opentelemetry-api = "==1.27.0"
opentelemetry-distro = "==0.48b0"
Expand Down Expand Up @@ -53,9 +53,9 @@ taskiq-fastapi = "==0.3.*"
taskiq-redis = "==1.0.2"
typer = "==0.15.*"
uvicorn = { extras = ["standard"], version = "==0.34.*" }
ddtrace = "==2.*"
ddtrace = "==2.19.*"
bytecode = "==0.16.0"
structlog = "==24.4.0"
structlog = "==25.1.*"
asgi-correlation-id = "==4.3.4"


Expand All @@ -78,7 +78,7 @@ pytest-env = "==1.1.5"
pytest-lazy-fixtures = "==1.*"
pytest-mock = "==3.14.0"
reproschema = "==0.6.2"
ruff = "==0.8.*"
ruff = "==0.9.*"
types-aiofiles = "==24.1.0.*"
types-cachetools = "==5.5.0.*"
types-python-dateutil = "==2.9.0.*"
Expand All @@ -87,7 +87,7 @@ types-requests = "==2.32.0.*"
typing-extensions = "==4.12.2"

[requires]
python_version = "3.11"
python_version = "3.13"

[scripts]
cli = "python src/cli.py"
732 changes: 373 additions & 359 deletions Pipfile.lock

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ See MindLogger's [Knowledge Base article](https://mindlogger.atlassian.net/servi

## Technologies

- ✅ [Python3.11+](https://www.python.org/downloads/release/python-31110/)
- ✅ [Python 3.13](https://www.python.org/downloads/release/python-3131/)
- ✅ [Pipenv](https://pipenv.pypa.io/en/latest/)
- ✅ [FastAPI](https://fastapi.tiangolo.com)
- ✅ [Postgresql](https://www.postgresql.org/docs/14/index.html)
Expand All @@ -61,7 +61,7 @@ And

### Prerequisites

- Python 3.11
- Python 3.13
- [Docker](https://docs.docker.com/get-docker/)

#### Recommended Extras
Expand All @@ -71,7 +71,7 @@ Installing [pyenv](https://github.com/pyenv/pyenv) is recommended to automatical
Alternatively, on macOS you can use a tool like [Homebrew](https://brew.sh/) to install multiple versions and specify when creating the virtual environment:

```bash
pipenv --python /opt/homebrew/bin/python3.11
pipenv --python /opt/homebrew/bin/python3.13
```

### Environment Variables
Expand Down Expand Up @@ -189,15 +189,15 @@ Create your virtual environment:
pipenv shell
```

If `pyenv` is installed Python 3.11 should automatically be installed in the virtual environment, you can check the
If `pyenv` is installed Python 3.13 should automatically be installed in the virtual environment, you can check the
correct version of Python is active by running:
```bash
python --version
```

If the active version is **not** 3.11, you can manually specify a version while creating your virtual environment:
If the active version is **not** 3.13, you can manually specify a version while creating your virtual environment:
```bash
pipenv --python /opt/homebrew/bin/python3.11
pipenv --python /opt/homebrew/bin/python3.13
```

Install all dependencies
Expand Down
2 changes: 1 addition & 1 deletion compose/fastapi/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.11-slim-bookworm AS base
FROM python:3.13-slim-bookworm AS base

ENV PYTHONUNBUFFERED=1
ENV PYTHONPATH="src/"
Expand Down
4 changes: 2 additions & 2 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ async def global_session(global_engine: AsyncEngine):


# TODO: Instead of custom faketime for tests add function wrapper `now`
# to use it instead of builtin datetime.datetime.utcnow
# to use it instead of builtin datetime.datetime.now
class FakeTime(datetime.datetime):
current_utc = datetime.datetime(2024, 1, 1, 0, 0, 0)

@classmethod
def utcnow(cls):
def now(cls, tzinfo=None):
return cls.current_utc


Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ omit = [
[tool.mypy]
plugins = ["pydantic.mypy"]
ignore_missing_imports = true
python_version = '3.11'
python_version = '3.13'
mypy_path = 'src'
files = ['*.py']
warn_redundant_casts = true
Expand Down
20 changes: 9 additions & 11 deletions src/apps/activities/domain/constants_ab_trails_mobile.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,12 @@
MOBILE_TUTORIALS_FIRST: ABTrailsTutorial = ABTrailsTutorial(
tutorials=[
Tutorial(text="There are numbers in circles on this screen."),
Tutorial(text="You will take a pen and draw a line from one number " "to the next, in order."),
Tutorial(text="You will take a pen and draw a line from one number to the next, in order."),
Tutorial(text="Start at 1.", node_label="1"),
Tutorial(text="Then go to 2.", node_label="2"),
Tutorial(text="Then 3, and so on.", node_label="3"),
Tutorial(
text="Please try not to lift the pen as you move from one "
"number to the next. Work as quickly as you can."
text="Please try not to lift the pen as you move from one number to the next. Work as quickly as you can."
),
Tutorial(text="Begin here.", node_label="1"),
Tutorial(text="And end here.", node_label="11"),
Expand All @@ -92,10 +91,10 @@
MOBILE_TUTORIALS_SECOND: ABTrailsTutorial = ABTrailsTutorial(
tutorials=[
Tutorial(text="On this screen are more numbers in circles."),
Tutorial(text="You will take a pen and draw a line from one circle " "to the next, in order."),
Tutorial(text="You will take a pen and draw a line from one circle to the next, in order."),
Tutorial(text="Start at 1.", node_label="1"),
Tutorial(text="And End here.", node_label="11"),
Tutorial(text="Please try not to lift the pen as you move from one " "circle to the next."),
Tutorial(text="Please try not to lift the pen as you move from one circle to the next."),
Tutorial(text="Work as quickly as you can."),
Tutorial(
text="Click next to start",
Expand All @@ -106,14 +105,13 @@
MOBILE_TUTORIALS_THIRD: ABTrailsTutorial = ABTrailsTutorial(
tutorials=[
Tutorial(text="There are numbers and letters in circles on this screen."),
Tutorial(text="You will take a pen and draw a line alternating in " "order between the numbers and letters."),
Tutorial(text="You will take a pen and draw a line alternating in order between the numbers and letters."),
Tutorial(text="Start at number 1.", node_label="1"),
Tutorial(text="Then go to the first letter A.", node_label="A"),
Tutorial(text="Then go to the next number 2.", node_label="2"),
Tutorial(text="Then go to the next letter B, and so on.", node_label="B"),
Tutorial(
text="Please try not to lift the pen as you move from one "
"number to the next. Work as quickly as you can."
text="Please try not to lift the pen as you move from one number to the next. Work as quickly as you can."
),
Tutorial(text="Begin here.", node_label="1"),
Tutorial(text="And end here.", node_label="6"),
Expand All @@ -125,12 +123,12 @@

MOBILE_TUTORIALS_FOURTH: ABTrailsTutorial = ABTrailsTutorial(
tutorials=[
Tutorial(text="On this screen there are more numbers and letters " "in circles."),
Tutorial(text="You will take a pen and draw a line from one circle " "to the next."),
Tutorial(text="On this screen there are more numbers and letters in circles."),
Tutorial(text="You will take a pen and draw a line from one circle to the next."),
Tutorial(text="Alternating in order between the numbers and letters."),
Tutorial(text="Start at 1.", node_label="1"),
Tutorial(text="And end here.", node_label="6"),
Tutorial(text="Please try not to lift the pen as you move from one " "circle to the next."),
Tutorial(text="Please try not to lift the pen as you move from one circle to the next."),
Tutorial(text="Work as quickly as you can."),
Tutorial(
text="Click next to start",
Expand Down
20 changes: 9 additions & 11 deletions src/apps/activities/domain/constants_ab_trails_tablet.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,12 @@
TABLET_TUTORIALS_FIRST: ABTrailsTutorial = ABTrailsTutorial(
tutorials=[
Tutorial(text="There are numbers in circles on this screen."),
Tutorial(text="You will take a pen and draw a line from one number " "to the next, in order."),
Tutorial(text="You will take a pen and draw a line from one number to the next, in order."),
Tutorial(text="Start at 1.", node_label="1"),
Tutorial(text="Then go to 2.", node_label="2"),
Tutorial(text="Then 3, and so on.", node_label="3"),
Tutorial(
text="Please try not to lift the pen as you move from one "
"number to the next. Work as quickly as you can."
text="Please try not to lift the pen as you move from one number to the next. Work as quickly as you can."
),
Tutorial(text="Begin here.", node_label="1"),
Tutorial(text="And end here.", node_label="8"),
Expand All @@ -126,10 +125,10 @@
TABLET_TUTORIALS_SECOND: ABTrailsTutorial = ABTrailsTutorial(
tutorials=[
Tutorial(text="On this screen are more numbers in circles."),
Tutorial(text="You will take a pen and draw a line from one circle to " "the next, in order."),
Tutorial(text="You will take a pen and draw a line from one circle to the next, in order."),
Tutorial(text="Start at 1.", node_label="1"),
Tutorial(text="And End here.", node_label="25"),
Tutorial(text="Please try not to lift the pen as you move from one " "circle to the next."),
Tutorial(text="Please try not to lift the pen as you move from one circle to the next."),
Tutorial(text="Work as quickly as you can."),
Tutorial(
text="Click next to start",
Expand All @@ -140,14 +139,13 @@
TABLET_TUTORIALS_THIRD: ABTrailsTutorial = ABTrailsTutorial(
tutorials=[
Tutorial(text="There are numbers and letters in circles on this screen."),
Tutorial(text="You will take a pen and draw a line alternating in " "order between the numbers and letters."),
Tutorial(text="You will take a pen and draw a line alternating in order between the numbers and letters."),
Tutorial(text="Start at number 1.", node_label="1"),
Tutorial(text="Then go to the first letter A.", node_label="A"),
Tutorial(text="Then go to the next number 2.", node_label="2"),
Tutorial(text="Then go to the next letter B, and so on.", node_label="B"),
Tutorial(
text="Please try not to lift the pen as you move from one "
"number to the next. Work as quickly as you can."
text="Please try not to lift the pen as you move from one number to the next. Work as quickly as you can."
),
Tutorial(text="Begin here.", node_label="1"),
Tutorial(text="And end here.", node_label="D"),
Expand All @@ -159,12 +157,12 @@

TABLET_TUTORIALS_FOURTH: ABTrailsTutorial = ABTrailsTutorial(
tutorials=[
Tutorial(text="On this screen there are more numbers and letters " "in circles."),
Tutorial(text="You will take a pen and draw a line from one circle " "to the next."),
Tutorial(text="On this screen there are more numbers and letters in circles."),
Tutorial(text="You will take a pen and draw a line from one circle to the next."),
Tutorial(text="Alternating in order between the numbers and letters."),
Tutorial(text="Start at 1.", node_label="1"),
Tutorial(text="And end here.", node_label="13"),
Tutorial(text="Please try not to lift the pen as you move from one " "circle to the next."),
Tutorial(text="Please try not to lift the pen as you move from one circle to the next."),
Tutorial(text="Work as quickly as you can."),
Tutorial(
text="Click next to start",
Expand Down
2 changes: 1 addition & 1 deletion src/apps/activities/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ class InvalidDataMatrixByOptionError(FieldError):


class InvalidScoreLengthError(FieldError):
message = _("Scores must have the same length as the " "range of min_value and max_value")
message = _("Scores must have the same length as the range of min_value and max_value")


class ActivityAccessDeniedError(AccessDeniedError):
Expand Down
2 changes: 1 addition & 1 deletion src/apps/activities/tests/test_activities.py
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ async def test_activities_applet_has_score(
en="Understand how was the morning",
fr="Understand how was the morning",
),
items=[dict(activity_key="577dbbda-3afc-" "4962-842b-8d8d11588bfe")],
items=[dict(activity_key="577dbbda-3afc-4962-842b-8d8d11588bfe")],
)
],
)
Expand Down
4 changes: 2 additions & 2 deletions src/apps/activities/tests/unit/test_activity_change.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def old_activity(activity_history_id: uuid.UUID, old_applet_id: str, old_id_vers
is_reviewable=False,
response_is_editable=False,
order=1,
created_at=datetime.datetime.utcnow(),
created_at=datetime.datetime.now(datetime.UTC),
is_hidden=False,
)

Expand All @@ -137,7 +137,7 @@ def new_activity(activity_history_id: uuid.UUID, new_applet_id: str, new_version
is_reviewable=False,
response_is_editable=False,
order=1,
created_at=datetime.datetime.utcnow(),
created_at=datetime.datetime.now(datetime.UTC),
is_hidden=False,
)

Expand Down
6 changes: 2 additions & 4 deletions src/apps/activities/tests/unit/test_activity_item_change.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ def test_conditional_logic_added(conditional_logic: ConditionalLogic):
condition_type = condition.type.lower().replace("_", " ")
item_name = condition.item_name
value = condition.payload.value # type: ignore
assert changes == [f"{parent_name}: If All: " f"{item_name} {condition_type} {value} was added"]
assert changes == [f"{parent_name}: If All: {item_name} {condition_type} {value} was added"]


def test_conditional_logic_changed(conditional_logic: ConditionalLogic):
Expand All @@ -356,9 +356,7 @@ def test_conditional_logic_changed(conditional_logic: ConditionalLogic):
condition_type = condition.type.lower().replace("_", " ")
item_name = condition.item_name
value = condition.payload.value # type: ignore
assert changes == [
f"{parent_name}: If {new.match.capitalize()}: " f"{item_name} {condition_type} {value} was updated"
]
assert changes == [f"{parent_name}: If {new.match.capitalize()}: {item_name} {condition_type} {value} was updated"]


def test_conditional_logic_removed(
Expand Down
2 changes: 1 addition & 1 deletion src/apps/activity_assignments/crud/assignments.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ async def upsert(self, values: dict) -> ActivityAssigmentSchema | None:
else ActivityAssigmentSchema.activity_flow_id,
],
set_={
"updated_at": datetime.datetime.utcnow(),
"updated_at": datetime.datetime.now(datetime.UTC).replace(tzinfo=None),
"is_deleted": False,
},
where=(ActivityAssigmentSchema.soft_exists(exists=False)),
Expand Down
4 changes: 2 additions & 2 deletions src/apps/answers/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@
)(answer_note_list)

router.put(
"/applet/{applet_id}/answers/{answer_id}/activities/" "{activity_id}/notes/{note_id}",
"/applet/{applet_id}/answers/{answer_id}/activities/{activity_id}/notes/{note_id}",
# noqa: E501
status_code=status.HTTP_200_OK,
responses={
Expand All @@ -340,7 +340,7 @@
)(answer_note_edit)

router.delete(
"/applet/{applet_id}/answers/{answer_id}/activities/" "{activity_id}/notes/{note_id}",
"/applet/{applet_id}/answers/{answer_id}/activities/{activity_id}/notes/{note_id}",
# noqa: E501
status_code=status.HTTP_204_NO_CONTENT,
responses={
Expand Down
16 changes: 8 additions & 8 deletions src/apps/answers/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ async def _get_answer_relation(
async def _create_answer(self, applet_answer: AppletAnswerCreate) -> AnswerSchema:
assert self.user_id
pk = self._generate_history_id(applet_answer.version)
created_at = applet_answer.created_at or datetime.datetime.utcnow()
created_at = applet_answer.created_at or datetime.datetime.now(datetime.UTC).replace(tzinfo=None)
subject_crud = SubjectsCrud(self.session)

respondent_subject = await subject_crud.get_user_subject(
Expand Down Expand Up @@ -1036,21 +1036,21 @@ async def create_assessment_answer(
AnswerItemSchema(
id=assessment.id,
created_at=assessment.created_at,
updated_at=datetime.datetime.utcnow(),
updated_at=datetime.datetime.now(datetime.UTC),
answer_id=answer_id,
respondent_id=self.user_id,
answer=schema.answer,
item_ids=list(map(str, schema.item_ids)),
user_public_key=schema.reviewer_public_key,
is_assessment=True,
start_datetime=datetime.datetime.utcnow(),
end_datetime=datetime.datetime.utcnow(),
start_datetime=datetime.datetime.now(datetime.UTC).replace(tzinfo=None),
end_datetime=datetime.datetime.now(datetime.UTC).replace(tzinfo=None),
assessment_activity_id=schema.assessment_version_id,
reviewed_flow_submit_id=submit_id,
)
)
else:
now = datetime.datetime.utcnow()
now = datetime.datetime.now(datetime.UTC).replace(tzinfo=None)
await AnswerItemsCRUD(self.answer_session).create(
AnswerItemSchema(
answer_id=answer_id,
Expand Down Expand Up @@ -2136,7 +2136,7 @@ async def create_report(

data = dict(
responses=responses,
now=datetime.datetime.utcnow().strftime("%x"),
now=datetime.datetime.now(datetime.UTC).strftime("%x"),
user=user_info,
applet=applet_full,
)
Expand Down Expand Up @@ -2268,12 +2268,12 @@ async def decrypt_data_for_loris(
) as resp:
duration = time.time() - start
if resp.status == 200:
logger.info(f"Successful request (for LORIS) in {duration:.1f}" " seconds.")
logger.info(f"Successful request (for LORIS) in {duration:.1f} seconds.")
response_data = await resp.json()
# return ReportServerResponse(**response_data)
return response_data, answer_versions
else:
logger.error(f"Failed request (for LORIS) in {duration:.1f}" " seconds.")
logger.error(f"Failed request (for LORIS) in {duration:.1f} seconds.")
error_message = await resp.text()
raise ReportServerError(message=error_message)

Expand Down
Loading
Loading