From db64fd4d59289b31950e6f3ea4e2ef3943202490 Mon Sep 17 00:00:00 2001 From: NM Date: Mon, 18 May 2026 12:25:26 +0200 Subject: [PATCH 01/41] Modification : initial commit, update setup.cfg and .gitignore, add flake8 report --- .gitignore | 2 + flake8-report/back.svg | 73 ++++ flake8-report/file.svg | 64 +++ flake8-report/index.html | 38 ++ .../oc_lettings_site.settings.report.html | 73 ++++ .../oc_lettings_site.settings.source.html | 374 ++++++++++++++++++ .../oc_lettings_site.views.report.html | 226 +++++++++++ .../oc_lettings_site.views.source.html | 305 ++++++++++++++ flake8-report/styles.css | 327 +++++++++++++++ setup.cfg | 4 +- 10 files changed, 1485 insertions(+), 1 deletion(-) create mode 100644 flake8-report/back.svg create mode 100644 flake8-report/file.svg create mode 100644 flake8-report/index.html create mode 100644 flake8-report/oc_lettings_site.settings.report.html create mode 100644 flake8-report/oc_lettings_site.settings.source.html create mode 100644 flake8-report/oc_lettings_site.views.report.html create mode 100644 flake8-report/oc_lettings_site.views.source.html create mode 100644 flake8-report/styles.css diff --git a/.gitignore b/.gitignore index b4405ebab4..cf3238f122 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ **/__pycache__ *.pyc venv +env +.idea \ No newline at end of file diff --git a/flake8-report/back.svg b/flake8-report/back.svg new file mode 100644 index 0000000000..ce80d2e6da --- /dev/null +++ b/flake8-report/back.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/flake8-report/file.svg b/flake8-report/file.svg new file mode 100644 index 0000000000..98706cfe53 --- /dev/null +++ b/flake8-report/file.svg @@ -0,0 +1,64 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/flake8-report/index.html b/flake8-report/index.html new file mode 100644 index 0000000000..2975318f72 --- /dev/null +++ b/flake8-report/index.html @@ -0,0 +1,38 @@ + + + + flake8 violations + + + + +
+
+

flake8 violations

+

Generated on 2026-05-18 12:22 + with mccabe: 0.6.1, pycodestyle: 2.5.0, pyflakes: 2.1.1 +

+ +
+ + \ No newline at end of file diff --git a/flake8-report/oc_lettings_site.settings.report.html b/flake8-report/oc_lettings_site.settings.report.html new file mode 100644 index 0000000000..2efd087813 --- /dev/null +++ b/flake8-report/oc_lettings_site.settings.report.html @@ -0,0 +1,73 @@ + + + + flake8 violations: oc_lettings_site\settings.py + + + + + +
+
+ +

+ + ⬅ + oc_lettings_site\settings.py + +

+ + +
+ + \ No newline at end of file diff --git a/flake8-report/oc_lettings_site.settings.source.html b/flake8-report/oc_lettings_site.settings.source.html new file mode 100644 index 0000000000..19a962680d --- /dev/null +++ b/flake8-report/oc_lettings_site.settings.source.html @@ -0,0 +1,374 @@ + + + + oc_lettings_site\settings.py - flake8 annotated source + + + + +
+
+

+ + ⬅ + oc_lettings_site\settings.py source + +

+ +
+
1 import os +
+
2   +
+
3 from pathlib import Path +
+
4   +
+
5 # Build paths inside the project like this: os.path.join(BASE_DIR, ...) +
+
6 BASE_DIR = Path(__file__).resolve().parent.parent +
+
7   +
+
8   +
+
9 # Quick-start development settings - unsuitable for production +
+
10 # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ +
+
11   +
+
12 # SECURITY WARNING: keep the secret key used in production secret! +
+
13 SECRET_KEY = 'fp$9^593hsriajg$_%=5trot9g!1qa@ew(o-1#@=&4%=hp46(s' +
+
14   +
+
15 # SECURITY WARNING: don't run with debug turned on in production! +
+
16 DEBUG = True +
+
17   +
+
18 ALLOWED_HOSTS = [] +
+
19   +
+
20   +
+
21 # Application definition +
+
22   +
+
23 INSTALLED_APPS = [ +
+
24 'oc_lettings_site.apps.OCLettingsSiteConfig', +
+
25 'django.contrib.admin', +
+
26 'django.contrib.auth', +
+
27 'django.contrib.contenttypes', +
+
28 'django.contrib.sessions', +
+
29 'django.contrib.messages', +
+
30 'django.contrib.staticfiles', +
+
31 ] +
+
32   +
+
33 MIDDLEWARE = [ +
+
34 'django.middleware.security.SecurityMiddleware', +
+
35 'django.contrib.sessions.middleware.SessionMiddleware', +
+
36 'django.middleware.common.CommonMiddleware', +
+
37 'django.middleware.csrf.CsrfViewMiddleware', +
+
38 'django.contrib.auth.middleware.AuthenticationMiddleware', +
+
39 'django.contrib.messages.middleware.MessageMiddleware', +
+
40 'django.middleware.clickjacking.XFrameOptionsMiddleware', +
+
41 ] +
+
42   +
+
43 ROOT_URLCONF = 'oc_lettings_site.urls' +
+
44   +
+
45 TEMPLATES = [ +
+
46 { +
+
47 'BACKEND': 'django.template.backends.django.DjangoTemplates', +
+
48 'DIRS': [os.path.join(BASE_DIR, 'templates')], +
+
49 'APP_DIRS': True, +
+
50 'OPTIONS': { +
+
51 'context_processors': [ +
+
52 'django.template.context_processors.debug', +
+
53 'django.template.context_processors.request', +
+
54 'django.contrib.auth.context_processors.auth', +
+
55 'django.contrib.messages.context_processors.messages', +
+
56 ], +
+
57 }, +
+
58 }, +
+
59 ] +
+
60   +
+
61 WSGI_APPLICATION = 'oc_lettings_site.wsgi.application' +
+
62   +
+
63   +
+
64 # Database +
+
65 # https://docs.djangoproject.com/en/3.0/ref/settings/#databases +
+
66   +
+
67 DATABASES = { +
+
68 'default': { +
+
69 'ENGINE': 'django.db.backends.sqlite3', +
+
70 'NAME': os.path.join(BASE_DIR, 'oc-lettings-site.sqlite3'), +
+
71 } +
+
72 } +
+
73   +
+
74   +
+
75 # Password validation +
+
76 # https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators +
+
77   +
+
78 AUTH_PASSWORD_VALIDATORS = [ +
+
79 { +
+
80 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', +
+
81 }, +
+
82 { +
+
83 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', +
+
84 }, +
+
85 { +
+
86 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', +
+
87 }, +
+
88 { +
+
89 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', +
+
90 }, +
+
91 ] +
+
92   +
+
93   +
+
94 # Internationalization +
+
95 # https://docs.djangoproject.com/en/3.0/topics/i18n/ +
+
96   +
+
97 LANGUAGE_CODE = 'en-us' +
+
98   +
+
99 TIME_ZONE = 'UTC' +
+
100   +
+
101 USE_I18N = True +
+
102   +
+
103 USE_L10N = True +
+
104   +
+
105 USE_TZ = True +
+
106   +
+
107   +
+
108 # Static files (CSS, JavaScript, Images) +
+
109 # https://docs.djangoproject.com/en/3.0/howto/static-files/ +
+
110   +
+
111 STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') +
+
112   +
+
113 STATIC_URL = '/static/' +
+
+
    + +
  • + + E231 + + Missing whitespace after ','
  • + +
114 STATICFILES_DIRS = [BASE_DIR / "static",] +
+ +
+
+ + \ No newline at end of file diff --git a/flake8-report/oc_lettings_site.views.report.html b/flake8-report/oc_lettings_site.views.report.html new file mode 100644 index 0000000000..6787b3915d --- /dev/null +++ b/flake8-report/oc_lettings_site.views.report.html @@ -0,0 +1,226 @@ + + + + flake8 violations: oc_lettings_site\views.py + + + + + +
+
+ +

+ + ⬅ + oc_lettings_site\views.py + +

+ + +
+ + \ No newline at end of file diff --git a/flake8-report/oc_lettings_site.views.source.html b/flake8-report/oc_lettings_site.views.source.html new file mode 100644 index 0000000000..ce67b841c5 --- /dev/null +++ b/flake8-report/oc_lettings_site.views.source.html @@ -0,0 +1,305 @@ + + + + oc_lettings_site\views.py - flake8 annotated source + + + + +
+
+

+ + ⬅ + oc_lettings_site\views.py source + +

+ +
+
1 from django.shortcuts import render +
+
2 from .models import Letting, Profile +
+
3   +
+
4   +
+
5   +
+
6   +
+
+
    + +
  • + + E303 + + Too many blank lines (4)
  • + +
  • + + E501 + + Line too long (198 > 99 characters)
  • + +
7 # Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque molestie quam lobortis leo consectetur ullamcorper non id est. Praesent dictum, nulla eget feugiat sagittis, sem mi convallis eros, +
+
+
    + +
  • + + E501 + + Line too long (153 > 99 characters)
  • + +
8 # vitae dapibus nisi lorem dapibus sem. Maecenas pharetra purus ipsum, eget consequat ipsum lobortis quis. Phasellus eleifend ex auctor venenatis tempus. +
+
+
    + +
  • + + E501 + + Line too long (174 > 99 characters)
  • + +
9 # Aliquam vitae erat ac orci placerat luctus. Nullam elementum urna nisi, pellentesque iaculis enim cursus in. Praesent volutpat porttitor magna, non finibus neque cursus id. +
+
+
    + +
  • + + E302 + + Expected 2 blank lines, found 4
  • + +
10 def index(request): +
+
11 return render(request, 'index.html') +
+
12   +
+
+
    + +
  • + + E501 + + Line too long (131 > 99 characters)
  • + +
13 # Aenean leo magna, vestibulum et tincidunt fermentum, consectetur quis velit. Sed non placerat massa. Integer est nunc, pulvinar a +
+
+
    + +
  • + + E501 + + Line too long (140 > 99 characters)
  • + +
14 # tempor et, bibendum id arcu. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Cras eget scelerisque +
+
+
    + +
  • + + E302 + + Expected 2 blank lines, found 1
  • + +
15 def lettings_index(request): +
+
16 lettings_list = Letting.objects.all() +
+
17 context = {'lettings_list': lettings_list} +
+
18 return render(request, 'lettings_index.html', context) +
+
19   +
+
20   +
+
+
    + +
  • + + E265 + + Block comment should start with '# '
  • + +
  • + + E501 + + Line too long (189 > 99 characters)
  • + +
21 #Cras ultricies dignissim purus, vitae hendrerit ex varius non. In accumsan porta nisl id eleifend. Praesent dignissim, odio eu consequat pretium, purus urna vulputate arcu, vitae efficitur +
+
+
    + +
  • + + E501 + + Line too long (216 > 99 characters)
  • + +
22 # lacus justo nec purus. Aenean finibus faucibus lectus at porta. Maecenas auctor, est ut luctus congue, dui enim mattis enim, ac condimentum velit libero in magna. Suspendisse potenti. In tempus a nisi sed laoreet. +
+
+
    + +
  • + + E501 + + Line too long (391 > 99 characters)
  • + +
23 # Suspendisse porta dui eget sem accumsan interdum. Ut quis urna pellentesque justo mattis ullamcorper ac non tellus. In tristique mauris eu velit fermentum, tempus pharetra est luctus. Vivamus consequat aliquam libero, eget bibendum lorem. Sed non dolor risus. Mauris condimentum auctor elementum. Donec quis nisi ligula. Integer vehicula tincidunt enim, ac lacinia augue pulvinar sit amet. +
+
24 def letting(request, letting_id): +
+
25 letting = Letting.objects.get(id=letting_id) +
+
26 context = { +
+
27 'title': letting.title, +
+
28 'address': letting.address, +
+
29 } +
+
30 return render(request, 'letting.html', context) +
+
31   +
+
+
    + +
  • + + E501 + + Line too long (112 > 99 characters)
  • + +
32 # Sed placerat quam in pulvinar commodo. Nullam laoreet consectetur ex, sed consequat libero pulvinar eget. Fusc +
+
33 # faucibus, urna quis auctor pharetra, massa dolor cursus neque, quis dictum lacus d +
+
+
    + +
  • + + E302 + + Expected 2 blank lines, found 1
  • + +
34 def profiles_index(request): +
+
35 profiles_list = Profile.objects.all() +
+
36 context = {'profiles_list': profiles_list} +
+
37 return render(request, 'profiles_index.html', context) +
+
38   +
+
39 # Aliquam sed metus eget nisi tincidunt ornare accumsan eget lac +
+
+
    + +
  • + + E501 + + Line too long (147 > 99 characters)
  • + +
40 # laoreet neque quis, pellentesque dui. Nullam facilisis pharetra vulputate. Sed tincidunt, dolor id facilisis fringilla, eros leo tristique lacus, +
+
+
    + +
  • + + E501 + + Line too long (100 > 99 characters)
  • + +
41 # it. Nam aliquam dignissim congue. Pellentesque habitant morbi tristique senectus et netus et males +
+
+
    + +
  • + + E302 + + Expected 2 blank lines, found 1
  • + +
42 def profile(request, username): +
+
43 profile = Profile.objects.get(user__username=username) +
+
44 context = {'profile': profile} +
+
45 return render(request, 'profile.html', context) +
+ +
+
+ + \ No newline at end of file diff --git a/flake8-report/styles.css b/flake8-report/styles.css new file mode 100644 index 0000000000..6e0e447a6e --- /dev/null +++ b/flake8-report/styles.css @@ -0,0 +1,327 @@ +html { + font-family: sans-serif; + font-size: 90%; +} + +#masthead { + position: fixed; + left: 0; + top: 0; + right: 0; + height: 40%; +} + +h1, h2 { + font-family: sans-serif; + font-weight: normal; +} + +h1 { + color: white; + font-size: 36px; + margin-top: 1em; +} + +h1 img { + margin-right: 0.3em; +} + +h2 { + margin-top: 0; +} + +h1 a { + color: white; +} + +#versions { + color: rgba(255, 255, 255, 0.7); +} + +#page { + position: relative; + max-width: 960px; + margin: 0 auto; +} + +#index { + background-color: white; + box-shadow: 0 0 4px rgba(0, 0, 0, 0.8); + padding: 0; + margin: 0; +} + +#index li { + list-style: none; + margin: 0; + padding: 1px 0; +} + +#index li + li { + border-top: solid silver 1px; +} + +.details p { + margin-left: 3em; + color: #888; +} + +#index a { + display: block; + padding: 0.8em 1em; + cursor: pointer; +} + +#index #all-good { + padding: 1.4em 1em 0.8em; +} + +#all-good .count .tick { + font-size: 2em; +} + +#all-good .count { + float: left; +} + +#all-good h2, +#all-good p { + margin-left: 50px; +} + +#index a:hover { + background-color: #eee; +} + +.count { + display: inline-block; + border-radius: 50%; + text-align: center; + width: 2.5em; + line-height: 2.5em; + height: 2.5em; + color: white; + margin-right: 1em; +} + +.sev-1 { + background-color: #a00; +} +.sev-2 { + background-color: #b80; +} +.sev-3 { + background-color: #28c; +} +.sev-4 { + background-color: #383; +} + +a { + text-decoration: none; +} + +#doc { + background-color: white; + margin: 1em 0; + padding: 1em; + padding-left: 1.2em; + position: relative; + box-shadow: 0 0 4px rgba(0, 0, 0, 0.8); +} + +#doc pre { + margin: 0; + padding: 0.07em; +} + +.violations { + position: absolute; + margin: 1.2em 0 0 3em; + padding: 0.5em 1em; + font-size: 14px; + background-color: white; + box-shadow: 0 0 4px rgba(0, 0, 0, 0.4); + display: none; +} + +.violations .count { + font-size: 70%; +} + +.violations li { + padding: 0.1em 0.3em; + list-style: none; +} + +.line-violations::before { + display: block; + content: ""; + position: absolute; + left: -1em; + width: 14px; + height: 14px; + border-radius: 50%; + background-color: red; +} + +.code:hover .violations { + display: block; +} + +tt { + white-space: pre-wrap; + font-family: Consolas, monospace; + font-size: 10pt; +} + +tt i { + color: silver; + display: inline-block; + text-align: right; + width: 3em; + box-sizing: border-box; + height: 100%; + border-right: solid #eee 1px; + padding-right: 0.2em; +} + +.le { + background-color: #ffe8e8; + cursor: pointer; +} + +.le:hover { + background-color: #fcc; +} + +.details { + clear: both; +} + +#index .details { + border-top-style: none; + margin: 1em; +} + +ul.details { + margin-left: 0; + padding-left: 0; +} + +#index .details li { + list-style: none; + border-top-style: none; + margin: 0.3em 0; + padding: 0; +} + +#srclink { + float: right; + font-size: 36px; + margin: 0; +} + +#srclink a { + color: white; +} + +#index .details a { + padding: 0; + color: inherit; +} + +.le { + background-color: #ffe8e8; + cursor: pointer; +} + +.le.sev-1 { + background-color: #f88; +} +.le.sev-2 { + background-color: #fda; +} +.le.sev-3 { + background-color: #adf; +} + +img { + height: 1.2em; + vertical-align: -0.35em; +} + +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.hll { background-color: #ffffcc } +.c { color: #3D7B7B; font-style: italic } /* Comment */ +.err { border: 1px solid #F00 } /* Error */ +.k { color: #008000; font-weight: bold } /* Keyword */ +.o { color: #666 } /* Operator */ +.ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ +.cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ +.cp { color: #9C6500 } /* Comment.Preproc */ +.cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ +.c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ +.cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ +.gd { color: #A00000 } /* Generic.Deleted */ +.ge { font-style: italic } /* Generic.Emph */ +.ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.gr { color: #E40000 } /* Generic.Error */ +.gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.gi { color: #008400 } /* Generic.Inserted */ +.go { color: #717171 } /* Generic.Output */ +.gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.gs { font-weight: bold } /* Generic.Strong */ +.gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.gt { color: #04D } /* Generic.Traceback */ +.kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +.kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +.kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +.kp { color: #008000 } /* Keyword.Pseudo */ +.kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +.kt { color: #B00040 } /* Keyword.Type */ +.m { color: #666 } /* Literal.Number */ +.s { color: #BA2121 } /* Literal.String */ +.na { color: #687822 } /* Name.Attribute */ +.nb { color: #008000 } /* Name.Builtin */ +.nc { color: #00F; font-weight: bold } /* Name.Class */ +.no { color: #800 } /* Name.Constant */ +.nd { color: #A2F } /* Name.Decorator */ +.ni { color: #717171; font-weight: bold } /* Name.Entity */ +.ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ +.nf { color: #00F } /* Name.Function */ +.nl { color: #767600 } /* Name.Label */ +.nn { color: #00F; font-weight: bold } /* Name.Namespace */ +.nt { color: #008000; font-weight: bold } /* Name.Tag */ +.nv { color: #19177C } /* Name.Variable */ +.ow { color: #A2F; font-weight: bold } /* Operator.Word */ +.w { color: #BBB } /* Text.Whitespace */ +.mb { color: #666 } /* Literal.Number.Bin */ +.mf { color: #666 } /* Literal.Number.Float */ +.mh { color: #666 } /* Literal.Number.Hex */ +.mi { color: #666 } /* Literal.Number.Integer */ +.mo { color: #666 } /* Literal.Number.Oct */ +.sa { color: #BA2121 } /* Literal.String.Affix */ +.sb { color: #BA2121 } /* Literal.String.Backtick */ +.sc { color: #BA2121 } /* Literal.String.Char */ +.dl { color: #BA2121 } /* Literal.String.Delimiter */ +.sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +.s2 { color: #BA2121 } /* Literal.String.Double */ +.se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ +.sh { color: #BA2121 } /* Literal.String.Heredoc */ +.si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ +.sx { color: #008000 } /* Literal.String.Other */ +.sr { color: #A45A77 } /* Literal.String.Regex */ +.s1 { color: #BA2121 } /* Literal.String.Single */ +.ss { color: #19177C } /* Literal.String.Symbol */ +.bp { color: #008000 } /* Name.Builtin.Pseudo */ +.fm { color: #00F } /* Name.Function.Magic */ +.vc { color: #19177C } /* Name.Variable.Class */ +.vg { color: #19177C } /* Name.Variable.Global */ +.vi { color: #19177C } /* Name.Variable.Instance */ +.vm { color: #19177C } /* Name.Variable.Magic */ +.il { color: #666 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index 9346841bbc..2c33038dd1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,8 @@ [flake8] +format = html +htmldir = flake8-report max-line-length = 99 -exclude = **/migrations/*,venv +exclude = **/migrations/*,env [tool:pytest] DJANGO_SETTINGS_MODULE = oc_lettings_site.settings From d401c94f00bf0b3c0935073fb37db647f9c43f66 Mon Sep 17 00:00:00 2001 From: NM Date: Mon, 18 May 2026 17:41:32 +0200 Subject: [PATCH 02/41] File change and modification : make migrations into two new apps ; update urls, views and templates accordingly to new apps ; update admin.py into new apps --- .gitignore | 5 +- lettings/__init__.py | 0 lettings/admin.py | 8 +++ lettings/apps.py | 5 ++ lettings/migrations/0001_initial.py | 36 +++++++++++++ .../migrations/0002_auto_20260518_1543.py | 48 ++++++++++++++++++ .../migrations/0003_auto_20260518_1551.py | 19 +++++++ lettings/migrations/__init__.py | 0 {oc_lettings_site => lettings}/models.py | 9 ---- .../templates/lettings/index.html | 4 +- .../templates/lettings}/letting.html | 4 +- lettings/tests.py | 3 ++ lettings/urls.py | 10 ++++ lettings/views.py | 23 +++++++++ oc-lettings-site.sqlite3 | Bin 151552 -> 180224 bytes oc_lettings_site/admin.py | 10 ---- .../migrations/0002_auto_20260518_1551.py | 30 +++++++++++ oc_lettings_site/settings.py | 2 + oc_lettings_site/urls.py | 8 ++- oc_lettings_site/views.py | 37 -------------- profiles/__init__.py | 0 profiles/admin.py | 6 +++ profiles/apps.py | 5 ++ profiles/migrations/0001_initial.py | 25 +++++++++ .../migrations/0002_auto_20260518_1548.py | 27 ++++++++++ .../migrations/0003_auto_20260518_1551.py | 21 ++++++++ profiles/migrations/__init__.py | 0 profiles/models.py | 10 ++++ .../templates/profiles/index.html | 4 +- .../templates/profiles}/profile.html | 4 +- profiles/tests.py | 3 ++ profiles/urls.py | 10 ++++ profiles/views.py | 20 ++++++++ templates/base.html | 4 +- templates/index.html | 4 +- 35 files changed, 330 insertions(+), 74 deletions(-) create mode 100644 lettings/__init__.py create mode 100644 lettings/admin.py create mode 100644 lettings/apps.py create mode 100644 lettings/migrations/0001_initial.py create mode 100644 lettings/migrations/0002_auto_20260518_1543.py create mode 100644 lettings/migrations/0003_auto_20260518_1551.py create mode 100644 lettings/migrations/__init__.py rename {oc_lettings_site => lettings}/models.py (75%) rename templates/lettings_index.html => lettings/templates/lettings/index.html (89%) rename {templates => lettings/templates/lettings}/letting.html (95%) create mode 100644 lettings/tests.py create mode 100644 lettings/urls.py create mode 100644 lettings/views.py create mode 100644 oc_lettings_site/migrations/0002_auto_20260518_1551.py create mode 100644 profiles/__init__.py create mode 100644 profiles/admin.py create mode 100644 profiles/apps.py create mode 100644 profiles/migrations/0001_initial.py create mode 100644 profiles/migrations/0002_auto_20260518_1548.py create mode 100644 profiles/migrations/0003_auto_20260518_1551.py create mode 100644 profiles/migrations/__init__.py create mode 100644 profiles/models.py rename templates/profiles_index.html => profiles/templates/profiles/index.html (88%) rename {templates => profiles/templates/profiles}/profile.html (96%) create mode 100644 profiles/tests.py create mode 100644 profiles/urls.py create mode 100644 profiles/views.py diff --git a/.gitignore b/.gitignore index cf3238f122..923c196816 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,7 @@ *.pyc venv env -.idea \ No newline at end of file +.idea +backup.sqlite3 +oc-lettings-site_old.sqlite3 +flake8-report \ No newline at end of file diff --git a/lettings/__init__.py b/lettings/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lettings/admin.py b/lettings/admin.py new file mode 100644 index 0000000000..4633a55339 --- /dev/null +++ b/lettings/admin.py @@ -0,0 +1,8 @@ +from django.contrib import admin + +from lettings.models import Address, Letting + + +admin.site.register(Letting) +admin.site.register(Address) + diff --git a/lettings/apps.py b/lettings/apps.py new file mode 100644 index 0000000000..b6abff1791 --- /dev/null +++ b/lettings/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class LettingsConfig(AppConfig): + name = 'lettings' diff --git a/lettings/migrations/0001_initial.py b/lettings/migrations/0001_initial.py new file mode 100644 index 0000000000..9a008d3d77 --- /dev/null +++ b/lettings/migrations/0001_initial.py @@ -0,0 +1,36 @@ +# Generated by Django 3.0 on 2026-05-18 12:53 + +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Address', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('number', models.PositiveIntegerField(validators=[django.core.validators.MaxValueValidator(9999)])), + ('street', models.CharField(max_length=64)), + ('city', models.CharField(max_length=64)), + ('state', models.CharField(max_length=2, validators=[django.core.validators.MinLengthValidator(2)])), + ('zip_code', models.PositiveIntegerField(validators=[django.core.validators.MaxValueValidator(99999)])), + ('country_iso_code', models.CharField(max_length=3, validators=[django.core.validators.MinLengthValidator(3)])), + ], + ), + migrations.CreateModel( + name='Letting', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=256)), + ('address', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='new_letting', to='lettings.Address')), + ], + ), + ] diff --git a/lettings/migrations/0002_auto_20260518_1543.py b/lettings/migrations/0002_auto_20260518_1543.py new file mode 100644 index 0000000000..47cb6b8db2 --- /dev/null +++ b/lettings/migrations/0002_auto_20260518_1543.py @@ -0,0 +1,48 @@ +# Generated by Django 3.0 on 2026-05-18 13:43 + +from django.db import migrations + + +def copy_address(apps, schema_editor): + OldAddress = apps.get_model('oc_lettings_site', 'Address') + NewAddress = apps.get_model('lettings', 'Address') + + for obj in OldAddress.objects.all(): + NewAddress.objects.create( + id=obj.id, + number=obj.number, + street=obj.street, + city=obj.city, + state=obj.state, + zip_code=obj.zip_code, + country_iso_code=obj.country_iso_code, + ) + + +def copy_lettings(apps, schema_editor): + OldLetting = apps.get_model('oc_lettings_site', 'Letting') + NewLetting = apps.get_model('lettings', 'Letting') + NewAddress = apps.get_model('lettings', 'Address') + + for obj in OldLetting.objects.all(): + + new_address = NewAddress.objects.get(id=obj.address.id) + + NewLetting.objects.create( + id=obj.id, + title=obj.title, + address=new_address, + ) + + +class Migration(migrations.Migration): + + dependencies = [ + ('lettings', '0001_initial'), + ('oc_lettings_site', '0001_initial'), + ] + + operations = [ + migrations.RunPython(copy_address), + migrations.RunPython(copy_lettings), + ] diff --git a/lettings/migrations/0003_auto_20260518_1551.py b/lettings/migrations/0003_auto_20260518_1551.py new file mode 100644 index 0000000000..11b098bd67 --- /dev/null +++ b/lettings/migrations/0003_auto_20260518_1551.py @@ -0,0 +1,19 @@ +# Generated by Django 3.0 on 2026-05-18 13:51 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('lettings', '0002_auto_20260518_1543'), + ] + + operations = [ + migrations.AlterField( + model_name='letting', + name='address', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='lettings.Address'), + ), + ] diff --git a/lettings/migrations/__init__.py b/lettings/migrations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/oc_lettings_site/models.py b/lettings/models.py similarity index 75% rename from oc_lettings_site/models.py rename to lettings/models.py index ed255e8c11..8e76ef00d2 100644 --- a/oc_lettings_site/models.py +++ b/lettings/models.py @@ -1,6 +1,5 @@ from django.db import models from django.core.validators import MaxValueValidator, MinLengthValidator -from django.contrib.auth.models import User class Address(models.Model): @@ -21,11 +20,3 @@ class Letting(models.Model): def __str__(self): return self.title - - -class Profile(models.Model): - user = models.OneToOneField(User, on_delete=models.CASCADE) - favorite_city = models.CharField(max_length=64, blank=True) - - def __str__(self): - return self.user.username diff --git a/templates/lettings_index.html b/lettings/templates/lettings/index.html similarity index 89% rename from templates/lettings_index.html rename to lettings/templates/lettings/index.html index 92857a78d9..a85f3a348e 100644 --- a/templates/lettings_index.html +++ b/lettings/templates/lettings/index.html @@ -20,7 +20,7 @@

Lettings

@@ -36,7 +36,7 @@

Lettings

Home - + Profiles diff --git a/templates/letting.html b/lettings/templates/lettings/letting.html similarity index 95% rename from templates/letting.html rename to lettings/templates/lettings/letting.html index 7e5f3a73fd..252d68035e 100644 --- a/templates/letting.html +++ b/lettings/templates/lettings/letting.html @@ -25,14 +25,14 @@

{{ title }}

diff --git a/lettings/tests.py b/lettings/tests.py new file mode 100644 index 0000000000..7ce503c2dd --- /dev/null +++ b/lettings/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/lettings/urls.py b/lettings/urls.py new file mode 100644 index 0000000000..8b261ec831 --- /dev/null +++ b/lettings/urls.py @@ -0,0 +1,10 @@ +from django.urls import path + +from . import views + +app_name = 'lettings' + +urlpatterns = [ + path('', views.index, name='index'), + path('/', views.letting, name='letting'), +] diff --git a/lettings/views.py b/lettings/views.py new file mode 100644 index 0000000000..fc357cad20 --- /dev/null +++ b/lettings/views.py @@ -0,0 +1,23 @@ +from django.shortcuts import render + +from .models import Letting + + +# Aenean leo magna, vestibulum et tincidunt fermentum, consectetur quis velit. Sed non placerat massa. Integer est nunc, pulvinar a +# tempor et, bibendum id arcu. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Cras eget scelerisque +def index(request): + lettings_list = Letting.objects.all() + context = {'lettings_list': lettings_list} + return render(request, 'lettings/index.html', context) + + +#Cras ultricies dignissim purus, vitae hendrerit ex varius non. In accumsan porta nisl id eleifend. Praesent dignissim, odio eu consequat pretium, purus urna vulputate arcu, vitae efficitur +# lacus justo nec purus. Aenean finibus faucibus lectus at porta. Maecenas auctor, est ut luctus congue, dui enim mattis enim, ac condimentum velit libero in magna. Suspendisse potenti. In tempus a nisi sed laoreet. +# Suspendisse porta dui eget sem accumsan interdum. Ut quis urna pellentesque justo mattis ullamcorper ac non tellus. In tristique mauris eu velit fermentum, tempus pharetra est luctus. Vivamus consequat aliquam libero, eget bibendum lorem. Sed non dolor risus. Mauris condimentum auctor elementum. Donec quis nisi ligula. Integer vehicula tincidunt enim, ac lacinia augue pulvinar sit amet. +def letting(request, letting_id): + letting = Letting.objects.get(id=letting_id) + context = { + 'title': letting.title, + 'address': letting.address, + } + return render(request, 'lettings/letting.html', context) diff --git a/oc-lettings-site.sqlite3 b/oc-lettings-site.sqlite3 index 3d885414f9f3ed046704e8b09bdcd5c791c82d42..92f150a14ef936c2ea5bdcf1208527af89ca775b 100644 GIT binary patch delta 3359 zcmcgvZ){W76~E`b=YP-7?9hMlEh9s~I+Of5pMva%4)FW|% zZJ?`$5~rYPtJF2k#GCk1zO)rXQ|nr(RjHzdPIT%AL?@<6B_(KGr?E0^l?wZ?RoQ(v z&ml3<%D&9;JHF@KbAIRCbMHCtX6CGEX2$$NeeEDZsDnIi^61I)y}1tAHi$Y$Ku0(R z-z5~aaHz<`(`he2LHT?WWI6=Zl3Srs=-TI@GW| zK9!w3lpaszBuSDJ$)ownL_i9JrI0_8@P|TvmGMa-pFiUC%RM1~PpG>y8i@uY;XVho zA5Z1;>CD*wWZxZ$c27&Y>^kJz9-kaZR4@{`bUsA_2|P$30jV=82cuG?Z&UR`?zay{ z)-NO&o$d)rok4#j><`N}0^nJj34bD;N$1na@hYoOPbkzGmi)3D>9bZZe*>@bM)sj- zfOrkbb<}HR?PS^i)oUmc2uR`5f%=y@rvsV9+X&ynXK)t3gI~wbVMe@-zmFfs4(t$1 z#loD(V+Yy>nbh$_Lis!cjzNwHHbG^(6WV~YT3H`df~f3--dej>nj9U?rgAwwzJ?wF zil*nt`0Jqjd;%Ozs(iDJ?FOrjSl#Eru483l^)S?dF#lZF;IO0~PgAv?4cIOi{b4dQ zHkp`6k7bkj^kgQtnJ3DEcn4tx=kc@n5FWxjZp44Wzryc}cW|&+_`Mjjat-yXjx}I` z3M(tqmSA2d)F%1)VC?D^LHq*YPw-`Y4xh%eIEPbs5X*QgHi=&p3)jS0oxq`n`byZ^ zZ=G2cR(Yx8*9x`Cd3o=LtR(c$8}svyej-cm=z|3CxrfD;bZgk zLmYTOIF=@Rr+JaA9JGQknj%=Kim+=%IPw%p*{ZO!mV<2|kmXj?d=$=1;j}DtP)oB0 zrwQ9vgd6NSr> zLzbQ_?L2UaSMP@v{*PH4(eC{L87#a(oRZ!Dm8ad+D>U3rL8LETPXEX+DxgZNlT30{14eEL-*q7x^nZYrJmM z8J^U=p_}I3)a_=Q#5o~rX*XYo@1lJ~d2lYi={x2#%py7Mi2Po&`+V?hET8&!Dr#<-q>AvItfA0o3EosM|u@M=?lth8K_m34}zOBpMe+4o+P*#y&Tfp2V7L4e0&4~ zdh$jC@3(wZ;$3y74HEupNee=pM_D=y^Bh9#^UASt*i$~2hCZ5lV1O^dO;&o9I}7A= z7#9`8RTy&cKj!!I9lX)>XVV4KX;ap;&(vZ<#>HYGZ#23k9RiO}P;TCU216HNTK$5; zErH9>sWBad8TJuoTl?DD+L_EaNt&EmnYueD(7IYvRn)_+>Zwh%xt&6qm0vD_)7adm zaqkeW&DlyltgW_+2hG~uLOt-xZZ%XdHRhGf4H9az#++6e4+Y|t3pb#?{L)8|w7vK) zSK_ArjbHf()ND~t8TqK!2QPWl%LU0RY9mi;sdnZPR&F#h%|^y@5{Z{ACyRxrEiJR# z8Qt(nT|9M6iso|iGoy#64o!uR9-c^zA03Oz8F}KFobe}PNFln@Za&B;?(na?uB9H)-pI;7CSN;FC*be!Dap#Ut=;D zFN?2<8N7fO^ykRm>&3!P^j6~qbj3a}0JAn)a`)cSx_d*bYki^Jn^6WQ;faA(;|0*u zHW8&Dl^0W`?^pA!>)|TX%8p5RS5Lwo(rVCOnW+FJ?vu2st5kCkdqi*7%%-ag_5RW| z&gys4PV<0`&9FY=Y6os-i#t8)cBV7=)L2T{Iso4PPn!#YvUnIyEA11|t7OOFEgmnx z!j=F4 delta 792 zcmY*W-Aj{U6o1b1zI*33-O=gX)aka+h-$hobz9Ak3e=$HML}KI{90!D5!?QNy|ZpI zLLK-(7bZcNq2e0x7F~p1WS7f=q7-EXkyi%Ygps{7iahY}oacAW`8|i-bSup^sFX78NoCxRWgya3^KGej8Q#iahzL({v=1`Bh2Lp-FX=J>ZRR zi3*Jbzv5jC;|pBGQ9OrrXiSQ~vKP$LQhK=py(DU*arIVjLqF!d7%8#S%=o z0/', views.letting, name='letting'), - path('profiles/', views.profiles_index, name='profiles_index'), - path('profiles//', views.profile, name='profile'), + path('lettings/', include('lettings.urls')), + path('profiles/', include('profiles.urls')), path('admin/', admin.site.urls), ] diff --git a/oc_lettings_site/views.py b/oc_lettings_site/views.py index a72db27074..22eaa0dcbe 100644 --- a/oc_lettings_site/views.py +++ b/oc_lettings_site/views.py @@ -1,7 +1,4 @@ from django.shortcuts import render -from .models import Letting, Profile - - # Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque molestie quam lobortis leo consectetur ullamcorper non id est. Praesent dictum, nulla eget feugiat sagittis, sem mi convallis eros, @@ -9,37 +6,3 @@ # Aliquam vitae erat ac orci placerat luctus. Nullam elementum urna nisi, pellentesque iaculis enim cursus in. Praesent volutpat porttitor magna, non finibus neque cursus id. def index(request): return render(request, 'index.html') - -# Aenean leo magna, vestibulum et tincidunt fermentum, consectetur quis velit. Sed non placerat massa. Integer est nunc, pulvinar a -# tempor et, bibendum id arcu. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Cras eget scelerisque -def lettings_index(request): - lettings_list = Letting.objects.all() - context = {'lettings_list': lettings_list} - return render(request, 'lettings_index.html', context) - - -#Cras ultricies dignissim purus, vitae hendrerit ex varius non. In accumsan porta nisl id eleifend. Praesent dignissim, odio eu consequat pretium, purus urna vulputate arcu, vitae efficitur -# lacus justo nec purus. Aenean finibus faucibus lectus at porta. Maecenas auctor, est ut luctus congue, dui enim mattis enim, ac condimentum velit libero in magna. Suspendisse potenti. In tempus a nisi sed laoreet. -# Suspendisse porta dui eget sem accumsan interdum. Ut quis urna pellentesque justo mattis ullamcorper ac non tellus. In tristique mauris eu velit fermentum, tempus pharetra est luctus. Vivamus consequat aliquam libero, eget bibendum lorem. Sed non dolor risus. Mauris condimentum auctor elementum. Donec quis nisi ligula. Integer vehicula tincidunt enim, ac lacinia augue pulvinar sit amet. -def letting(request, letting_id): - letting = Letting.objects.get(id=letting_id) - context = { - 'title': letting.title, - 'address': letting.address, - } - return render(request, 'letting.html', context) - -# Sed placerat quam in pulvinar commodo. Nullam laoreet consectetur ex, sed consequat libero pulvinar eget. Fusc -# faucibus, urna quis auctor pharetra, massa dolor cursus neque, quis dictum lacus d -def profiles_index(request): - profiles_list = Profile.objects.all() - context = {'profiles_list': profiles_list} - return render(request, 'profiles_index.html', context) - -# Aliquam sed metus eget nisi tincidunt ornare accumsan eget lac -# laoreet neque quis, pellentesque dui. Nullam facilisis pharetra vulputate. Sed tincidunt, dolor id facilisis fringilla, eros leo tristique lacus, -# it. Nam aliquam dignissim congue. Pellentesque habitant morbi tristique senectus et netus et males -def profile(request, username): - profile = Profile.objects.get(user__username=username) - context = {'profile': profile} - return render(request, 'profile.html', context) diff --git a/profiles/__init__.py b/profiles/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/profiles/admin.py b/profiles/admin.py new file mode 100644 index 0000000000..9f66e5c835 --- /dev/null +++ b/profiles/admin.py @@ -0,0 +1,6 @@ +from django.contrib import admin + +from profiles.models import Profile + + +admin.site.register(Profile) diff --git a/profiles/apps.py b/profiles/apps.py new file mode 100644 index 0000000000..5501fdad35 --- /dev/null +++ b/profiles/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class ProfilesConfig(AppConfig): + name = 'profiles' diff --git a/profiles/migrations/0001_initial.py b/profiles/migrations/0001_initial.py new file mode 100644 index 0000000000..069a3babcc --- /dev/null +++ b/profiles/migrations/0001_initial.py @@ -0,0 +1,25 @@ +# Generated by Django 3.0 on 2026-05-18 12:53 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Profile', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('favorite_city', models.CharField(blank=True, max_length=64)), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='new_profile', to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/profiles/migrations/0002_auto_20260518_1548.py b/profiles/migrations/0002_auto_20260518_1548.py new file mode 100644 index 0000000000..7be66c52bf --- /dev/null +++ b/profiles/migrations/0002_auto_20260518_1548.py @@ -0,0 +1,27 @@ +# Generated by Django 3.0 on 2026-05-18 13:48 + +from django.db import migrations + + +def copy_profile(apps, schema_editor): + OldProfile = apps.get_model('oc_lettings_site', 'Profile') + NewProfile = apps.get_model('profiles', 'Profile') + + for obj in OldProfile.objects.all(): + NewProfile.objects.create( + id=obj.id, + user=obj.user, + favorite_city=obj.favorite_city, + ) + + +class Migration(migrations.Migration): + + dependencies = [ + ('profiles', '0001_initial'), + ('oc_lettings_site', '0001_initial'), + ] + + operations = [ + migrations.RunPython(copy_profile), + ] diff --git a/profiles/migrations/0003_auto_20260518_1551.py b/profiles/migrations/0003_auto_20260518_1551.py new file mode 100644 index 0000000000..61fbe40024 --- /dev/null +++ b/profiles/migrations/0003_auto_20260518_1551.py @@ -0,0 +1,21 @@ +# Generated by Django 3.0 on 2026-05-18 13:51 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('profiles', '0002_auto_20260518_1548'), + ] + + operations = [ + migrations.AlterField( + model_name='profile', + name='user', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/profiles/migrations/__init__.py b/profiles/migrations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/profiles/models.py b/profiles/models.py new file mode 100644 index 0000000000..84c85c1001 --- /dev/null +++ b/profiles/models.py @@ -0,0 +1,10 @@ +from django.db import models +from django.contrib.auth.models import User + + +class Profile(models.Model): + user = models.OneToOneField(User, on_delete=models.CASCADE) + favorite_city = models.CharField(max_length=64, blank=True) + + def __str__(self): + return self.user.username diff --git a/templates/profiles_index.html b/profiles/templates/profiles/index.html similarity index 88% rename from templates/profiles_index.html rename to profiles/templates/profiles/index.html index 4ad1daf92f..563b7a0166 100644 --- a/templates/profiles_index.html +++ b/profiles/templates/profiles/index.html @@ -18,7 +18,7 @@

Profiles

@@ -34,7 +34,7 @@

Profiles

Home - + Lettings
diff --git a/templates/profile.html b/profiles/templates/profiles/profile.html similarity index 96% rename from templates/profile.html rename to profiles/templates/profiles/profile.html index d150d30e63..4b1af37496 100644 --- a/templates/profile.html +++ b/profiles/templates/profiles/profile.html @@ -24,14 +24,14 @@

{{ profile.user.username }}

diff --git a/profiles/tests.py b/profiles/tests.py new file mode 100644 index 0000000000..7ce503c2dd --- /dev/null +++ b/profiles/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/profiles/urls.py b/profiles/urls.py new file mode 100644 index 0000000000..b33a49ae2d --- /dev/null +++ b/profiles/urls.py @@ -0,0 +1,10 @@ +from django.urls import path + +from . import views + +app_name = 'profiles' + +urlpatterns = [ + path('', views.index, name='index'), + path('/', views.profile, name='profile'), +] diff --git a/profiles/views.py b/profiles/views.py new file mode 100644 index 0000000000..7d2af649c5 --- /dev/null +++ b/profiles/views.py @@ -0,0 +1,20 @@ +from django.shortcuts import render + +from profiles.models import Profile + + +# Sed placerat quam in pulvinar commodo. Nullam laoreet consectetur ex, sed consequat libero pulvinar eget. Fusc +# faucibus, urna quis auctor pharetra, massa dolor cursus neque, quis dictum lacus d +def index(request): + profiles_list = Profile.objects.all() + context = {'profiles_list': profiles_list} + return render(request, 'profiles/index.html', context) + +# Aliquam sed metus eget nisi tincidunt ornare accumsan eget lac +# laoreet neque quis, pellentesque dui. Nullam facilisis pharetra vulputate. Sed tincidunt, dolor id facilisis fringilla, eros leo tristique lacus, +# it. Nam aliquam dignissim congue. Pellentesque habitant morbi tristique senectus et netus et males +def profile(request, username): + profile = Profile.objects.get(user__username=username) + context = {'profile': profile} + return render(request, 'profiles/profile.html', context) + diff --git a/templates/base.html b/templates/base.html index ab7addba01..403b342755 100644 --- a/templates/base.html +++ b/templates/base.html @@ -24,10 +24,10 @@
Logo Orange County Lettings diff --git a/templates/index.html b/templates/index.html index 71a8e61a46..fc9a76c7ab 100644 --- a/templates/index.html +++ b/templates/index.html @@ -14,10 +14,10 @@

Welcome to Holiday Homes

From ac51dad279227da7b2d838ad6eb254db6b6f106b Mon Sep 17 00:00:00 2001 From: NM Date: Tue, 19 May 2026 09:29:22 +0200 Subject: [PATCH 03/41] Modification : update code after flake8 linting report in order to comfy Pep 8 convention --- flake8-report/back.svg | 73 ---- flake8-report/file.svg | 64 --- flake8-report/index.html | 38 -- .../oc_lettings_site.settings.report.html | 73 ---- .../oc_lettings_site.settings.source.html | 374 ------------------ .../oc_lettings_site.views.report.html | 226 ----------- .../oc_lettings_site.views.source.html | 305 -------------- flake8-report/styles.css | 327 --------------- lettings/admin.py | 1 - lettings/views.py | 17 +- oc_lettings_site/settings.py | 2 +- oc_lettings_site/views.py | 9 +- profiles/views.py | 12 +- 13 files changed, 26 insertions(+), 1495 deletions(-) delete mode 100644 flake8-report/back.svg delete mode 100644 flake8-report/file.svg delete mode 100644 flake8-report/index.html delete mode 100644 flake8-report/oc_lettings_site.settings.report.html delete mode 100644 flake8-report/oc_lettings_site.settings.source.html delete mode 100644 flake8-report/oc_lettings_site.views.report.html delete mode 100644 flake8-report/oc_lettings_site.views.source.html delete mode 100644 flake8-report/styles.css diff --git a/flake8-report/back.svg b/flake8-report/back.svg deleted file mode 100644 index ce80d2e6da..0000000000 --- a/flake8-report/back.svg +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - diff --git a/flake8-report/file.svg b/flake8-report/file.svg deleted file mode 100644 index 98706cfe53..0000000000 --- a/flake8-report/file.svg +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/flake8-report/index.html b/flake8-report/index.html deleted file mode 100644 index 2975318f72..0000000000 --- a/flake8-report/index.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - flake8 violations - - - - -
-
-

flake8 violations

-

Generated on 2026-05-18 12:22 - with mccabe: 0.6.1, pycodestyle: 2.5.0, pyflakes: 2.1.1 -

- -
- - \ No newline at end of file diff --git a/flake8-report/oc_lettings_site.settings.report.html b/flake8-report/oc_lettings_site.settings.report.html deleted file mode 100644 index 2efd087813..0000000000 --- a/flake8-report/oc_lettings_site.settings.report.html +++ /dev/null @@ -1,73 +0,0 @@ - - - - flake8 violations: oc_lettings_site\settings.py - - - - - -
- - - \ No newline at end of file diff --git a/flake8-report/oc_lettings_site.settings.source.html b/flake8-report/oc_lettings_site.settings.source.html deleted file mode 100644 index 19a962680d..0000000000 --- a/flake8-report/oc_lettings_site.settings.source.html +++ /dev/null @@ -1,374 +0,0 @@ - - - - oc_lettings_site\settings.py - flake8 annotated source - - - - -
-
-

- - ⬅ - oc_lettings_site\settings.py source - -

- -
-
1 import os -
-
2   -
-
3 from pathlib import Path -
-
4   -
-
5 # Build paths inside the project like this: os.path.join(BASE_DIR, ...) -
-
6 BASE_DIR = Path(__file__).resolve().parent.parent -
-
7   -
-
8   -
-
9 # Quick-start development settings - unsuitable for production -
-
10 # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ -
-
11   -
-
12 # SECURITY WARNING: keep the secret key used in production secret! -
-
13 SECRET_KEY = 'fp$9^593hsriajg$_%=5trot9g!1qa@ew(o-1#@=&4%=hp46(s' -
-
14   -
-
15 # SECURITY WARNING: don't run with debug turned on in production! -
-
16 DEBUG = True -
-
17   -
-
18 ALLOWED_HOSTS = [] -
-
19   -
-
20   -
-
21 # Application definition -
-
22   -
-
23 INSTALLED_APPS = [ -
-
24 'oc_lettings_site.apps.OCLettingsSiteConfig', -
-
25 'django.contrib.admin', -
-
26 'django.contrib.auth', -
-
27 'django.contrib.contenttypes', -
-
28 'django.contrib.sessions', -
-
29 'django.contrib.messages', -
-
30 'django.contrib.staticfiles', -
-
31 ] -
-
32   -
-
33 MIDDLEWARE = [ -
-
34 'django.middleware.security.SecurityMiddleware', -
-
35 'django.contrib.sessions.middleware.SessionMiddleware', -
-
36 'django.middleware.common.CommonMiddleware', -
-
37 'django.middleware.csrf.CsrfViewMiddleware', -
-
38 'django.contrib.auth.middleware.AuthenticationMiddleware', -
-
39 'django.contrib.messages.middleware.MessageMiddleware', -
-
40 'django.middleware.clickjacking.XFrameOptionsMiddleware', -
-
41 ] -
-
42   -
-
43 ROOT_URLCONF = 'oc_lettings_site.urls' -
-
44   -
-
45 TEMPLATES = [ -
-
46 { -
-
47 'BACKEND': 'django.template.backends.django.DjangoTemplates', -
-
48 'DIRS': [os.path.join(BASE_DIR, 'templates')], -
-
49 'APP_DIRS': True, -
-
50 'OPTIONS': { -
-
51 'context_processors': [ -
-
52 'django.template.context_processors.debug', -
-
53 'django.template.context_processors.request', -
-
54 'django.contrib.auth.context_processors.auth', -
-
55 'django.contrib.messages.context_processors.messages', -
-
56 ], -
-
57 }, -
-
58 }, -
-
59 ] -
-
60   -
-
61 WSGI_APPLICATION = 'oc_lettings_site.wsgi.application' -
-
62   -
-
63   -
-
64 # Database -
-
65 # https://docs.djangoproject.com/en/3.0/ref/settings/#databases -
-
66   -
-
67 DATABASES = { -
-
68 'default': { -
-
69 'ENGINE': 'django.db.backends.sqlite3', -
-
70 'NAME': os.path.join(BASE_DIR, 'oc-lettings-site.sqlite3'), -
-
71 } -
-
72 } -
-
73   -
-
74   -
-
75 # Password validation -
-
76 # https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators -
-
77   -
-
78 AUTH_PASSWORD_VALIDATORS = [ -
-
79 { -
-
80 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', -
-
81 }, -
-
82 { -
-
83 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', -
-
84 }, -
-
85 { -
-
86 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', -
-
87 }, -
-
88 { -
-
89 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', -
-
90 }, -
-
91 ] -
-
92   -
-
93   -
-
94 # Internationalization -
-
95 # https://docs.djangoproject.com/en/3.0/topics/i18n/ -
-
96   -
-
97 LANGUAGE_CODE = 'en-us' -
-
98   -
-
99 TIME_ZONE = 'UTC' -
-
100   -
-
101 USE_I18N = True -
-
102   -
-
103 USE_L10N = True -
-
104   -
-
105 USE_TZ = True -
-
106   -
-
107   -
-
108 # Static files (CSS, JavaScript, Images) -
-
109 # https://docs.djangoproject.com/en/3.0/howto/static-files/ -
-
110   -
-
111 STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') -
-
112   -
-
113 STATIC_URL = '/static/' -
-
-
    - -
  • - - E231 - - Missing whitespace after ','
  • - -
114 STATICFILES_DIRS = [BASE_DIR / "static",] -
- -
-
- - \ No newline at end of file diff --git a/flake8-report/oc_lettings_site.views.report.html b/flake8-report/oc_lettings_site.views.report.html deleted file mode 100644 index 6787b3915d..0000000000 --- a/flake8-report/oc_lettings_site.views.report.html +++ /dev/null @@ -1,226 +0,0 @@ - - - - flake8 violations: oc_lettings_site\views.py - - - - - -
-
- -

- - ⬅ - oc_lettings_site\views.py - -

- - -
- - \ No newline at end of file diff --git a/flake8-report/oc_lettings_site.views.source.html b/flake8-report/oc_lettings_site.views.source.html deleted file mode 100644 index ce67b841c5..0000000000 --- a/flake8-report/oc_lettings_site.views.source.html +++ /dev/null @@ -1,305 +0,0 @@ - - - - oc_lettings_site\views.py - flake8 annotated source - - - - -
-
-

- - ⬅ - oc_lettings_site\views.py source - -

- -
-
1 from django.shortcuts import render -
-
2 from .models import Letting, Profile -
-
3   -
-
4   -
-
5   -
-
6   -
-
-
    - -
  • - - E303 - - Too many blank lines (4)
  • - -
  • - - E501 - - Line too long (198 > 99 characters)
  • - -
7 # Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque molestie quam lobortis leo consectetur ullamcorper non id est. Praesent dictum, nulla eget feugiat sagittis, sem mi convallis eros, -
-
-
    - -
  • - - E501 - - Line too long (153 > 99 characters)
  • - -
8 # vitae dapibus nisi lorem dapibus sem. Maecenas pharetra purus ipsum, eget consequat ipsum lobortis quis. Phasellus eleifend ex auctor venenatis tempus. -
-
-
    - -
  • - - E501 - - Line too long (174 > 99 characters)
  • - -
9 # Aliquam vitae erat ac orci placerat luctus. Nullam elementum urna nisi, pellentesque iaculis enim cursus in. Praesent volutpat porttitor magna, non finibus neque cursus id. -
-
-
    - -
  • - - E302 - - Expected 2 blank lines, found 4
  • - -
10 def index(request): -
-
11 return render(request, 'index.html') -
-
12   -
-
-
    - -
  • - - E501 - - Line too long (131 > 99 characters)
  • - -
13 # Aenean leo magna, vestibulum et tincidunt fermentum, consectetur quis velit. Sed non placerat massa. Integer est nunc, pulvinar a -
-
-
    - -
  • - - E501 - - Line too long (140 > 99 characters)
  • - -
14 # tempor et, bibendum id arcu. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Cras eget scelerisque -
-
-
    - -
  • - - E302 - - Expected 2 blank lines, found 1
  • - -
15 def lettings_index(request): -
-
16 lettings_list = Letting.objects.all() -
-
17 context = {'lettings_list': lettings_list} -
-
18 return render(request, 'lettings_index.html', context) -
-
19   -
-
20   -
-
-
    - -
  • - - E265 - - Block comment should start with '# '
  • - -
  • - - E501 - - Line too long (189 > 99 characters)
  • - -
21 #Cras ultricies dignissim purus, vitae hendrerit ex varius non. In accumsan porta nisl id eleifend. Praesent dignissim, odio eu consequat pretium, purus urna vulputate arcu, vitae efficitur -
-
-
    - -
  • - - E501 - - Line too long (216 > 99 characters)
  • - -
22 # lacus justo nec purus. Aenean finibus faucibus lectus at porta. Maecenas auctor, est ut luctus congue, dui enim mattis enim, ac condimentum velit libero in magna. Suspendisse potenti. In tempus a nisi sed laoreet. -
-
-
    - -
  • - - E501 - - Line too long (391 > 99 characters)
  • - -
23 # Suspendisse porta dui eget sem accumsan interdum. Ut quis urna pellentesque justo mattis ullamcorper ac non tellus. In tristique mauris eu velit fermentum, tempus pharetra est luctus. Vivamus consequat aliquam libero, eget bibendum lorem. Sed non dolor risus. Mauris condimentum auctor elementum. Donec quis nisi ligula. Integer vehicula tincidunt enim, ac lacinia augue pulvinar sit amet. -
-
24 def letting(request, letting_id): -
-
25 letting = Letting.objects.get(id=letting_id) -
-
26 context = { -
-
27 'title': letting.title, -
-
28 'address': letting.address, -
-
29 } -
-
30 return render(request, 'letting.html', context) -
-
31   -
-
-
    - -
  • - - E501 - - Line too long (112 > 99 characters)
  • - -
32 # Sed placerat quam in pulvinar commodo. Nullam laoreet consectetur ex, sed consequat libero pulvinar eget. Fusc -
-
33 # faucibus, urna quis auctor pharetra, massa dolor cursus neque, quis dictum lacus d -
-
-
    - -
  • - - E302 - - Expected 2 blank lines, found 1
  • - -
34 def profiles_index(request): -
-
35 profiles_list = Profile.objects.all() -
-
36 context = {'profiles_list': profiles_list} -
-
37 return render(request, 'profiles_index.html', context) -
-
38   -
-
39 # Aliquam sed metus eget nisi tincidunt ornare accumsan eget lac -
-
-
    - -
  • - - E501 - - Line too long (147 > 99 characters)
  • - -
40 # laoreet neque quis, pellentesque dui. Nullam facilisis pharetra vulputate. Sed tincidunt, dolor id facilisis fringilla, eros leo tristique lacus, -
-
-
    - -
  • - - E501 - - Line too long (100 > 99 characters)
  • - -
41 # it. Nam aliquam dignissim congue. Pellentesque habitant morbi tristique senectus et netus et males -
-
-
    - -
  • - - E302 - - Expected 2 blank lines, found 1
  • - -
42 def profile(request, username): -
-
43 profile = Profile.objects.get(user__username=username) -
-
44 context = {'profile': profile} -
-
45 return render(request, 'profile.html', context) -
- -
-
- - \ No newline at end of file diff --git a/flake8-report/styles.css b/flake8-report/styles.css deleted file mode 100644 index 6e0e447a6e..0000000000 --- a/flake8-report/styles.css +++ /dev/null @@ -1,327 +0,0 @@ -html { - font-family: sans-serif; - font-size: 90%; -} - -#masthead { - position: fixed; - left: 0; - top: 0; - right: 0; - height: 40%; -} - -h1, h2 { - font-family: sans-serif; - font-weight: normal; -} - -h1 { - color: white; - font-size: 36px; - margin-top: 1em; -} - -h1 img { - margin-right: 0.3em; -} - -h2 { - margin-top: 0; -} - -h1 a { - color: white; -} - -#versions { - color: rgba(255, 255, 255, 0.7); -} - -#page { - position: relative; - max-width: 960px; - margin: 0 auto; -} - -#index { - background-color: white; - box-shadow: 0 0 4px rgba(0, 0, 0, 0.8); - padding: 0; - margin: 0; -} - -#index li { - list-style: none; - margin: 0; - padding: 1px 0; -} - -#index li + li { - border-top: solid silver 1px; -} - -.details p { - margin-left: 3em; - color: #888; -} - -#index a { - display: block; - padding: 0.8em 1em; - cursor: pointer; -} - -#index #all-good { - padding: 1.4em 1em 0.8em; -} - -#all-good .count .tick { - font-size: 2em; -} - -#all-good .count { - float: left; -} - -#all-good h2, -#all-good p { - margin-left: 50px; -} - -#index a:hover { - background-color: #eee; -} - -.count { - display: inline-block; - border-radius: 50%; - text-align: center; - width: 2.5em; - line-height: 2.5em; - height: 2.5em; - color: white; - margin-right: 1em; -} - -.sev-1 { - background-color: #a00; -} -.sev-2 { - background-color: #b80; -} -.sev-3 { - background-color: #28c; -} -.sev-4 { - background-color: #383; -} - -a { - text-decoration: none; -} - -#doc { - background-color: white; - margin: 1em 0; - padding: 1em; - padding-left: 1.2em; - position: relative; - box-shadow: 0 0 4px rgba(0, 0, 0, 0.8); -} - -#doc pre { - margin: 0; - padding: 0.07em; -} - -.violations { - position: absolute; - margin: 1.2em 0 0 3em; - padding: 0.5em 1em; - font-size: 14px; - background-color: white; - box-shadow: 0 0 4px rgba(0, 0, 0, 0.4); - display: none; -} - -.violations .count { - font-size: 70%; -} - -.violations li { - padding: 0.1em 0.3em; - list-style: none; -} - -.line-violations::before { - display: block; - content: ""; - position: absolute; - left: -1em; - width: 14px; - height: 14px; - border-radius: 50%; - background-color: red; -} - -.code:hover .violations { - display: block; -} - -tt { - white-space: pre-wrap; - font-family: Consolas, monospace; - font-size: 10pt; -} - -tt i { - color: silver; - display: inline-block; - text-align: right; - width: 3em; - box-sizing: border-box; - height: 100%; - border-right: solid #eee 1px; - padding-right: 0.2em; -} - -.le { - background-color: #ffe8e8; - cursor: pointer; -} - -.le:hover { - background-color: #fcc; -} - -.details { - clear: both; -} - -#index .details { - border-top-style: none; - margin: 1em; -} - -ul.details { - margin-left: 0; - padding-left: 0; -} - -#index .details li { - list-style: none; - border-top-style: none; - margin: 0.3em 0; - padding: 0; -} - -#srclink { - float: right; - font-size: 36px; - margin: 0; -} - -#srclink a { - color: white; -} - -#index .details a { - padding: 0; - color: inherit; -} - -.le { - background-color: #ffe8e8; - cursor: pointer; -} - -.le.sev-1 { - background-color: #f88; -} -.le.sev-2 { - background-color: #fda; -} -.le.sev-3 { - background-color: #adf; -} - -img { - height: 1.2em; - vertical-align: -0.35em; -} - -pre { line-height: 125%; } -td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } -span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } -td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } -span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } -.hll { background-color: #ffffcc } -.c { color: #3D7B7B; font-style: italic } /* Comment */ -.err { border: 1px solid #F00 } /* Error */ -.k { color: #008000; font-weight: bold } /* Keyword */ -.o { color: #666 } /* Operator */ -.ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ -.cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ -.cp { color: #9C6500 } /* Comment.Preproc */ -.cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ -.c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ -.cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ -.gd { color: #A00000 } /* Generic.Deleted */ -.ge { font-style: italic } /* Generic.Emph */ -.ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ -.gr { color: #E40000 } /* Generic.Error */ -.gh { color: #000080; font-weight: bold } /* Generic.Heading */ -.gi { color: #008400 } /* Generic.Inserted */ -.go { color: #717171 } /* Generic.Output */ -.gp { color: #000080; font-weight: bold } /* Generic.Prompt */ -.gs { font-weight: bold } /* Generic.Strong */ -.gu { color: #800080; font-weight: bold } /* Generic.Subheading */ -.gt { color: #04D } /* Generic.Traceback */ -.kc { color: #008000; font-weight: bold } /* Keyword.Constant */ -.kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ -.kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ -.kp { color: #008000 } /* Keyword.Pseudo */ -.kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ -.kt { color: #B00040 } /* Keyword.Type */ -.m { color: #666 } /* Literal.Number */ -.s { color: #BA2121 } /* Literal.String */ -.na { color: #687822 } /* Name.Attribute */ -.nb { color: #008000 } /* Name.Builtin */ -.nc { color: #00F; font-weight: bold } /* Name.Class */ -.no { color: #800 } /* Name.Constant */ -.nd { color: #A2F } /* Name.Decorator */ -.ni { color: #717171; font-weight: bold } /* Name.Entity */ -.ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ -.nf { color: #00F } /* Name.Function */ -.nl { color: #767600 } /* Name.Label */ -.nn { color: #00F; font-weight: bold } /* Name.Namespace */ -.nt { color: #008000; font-weight: bold } /* Name.Tag */ -.nv { color: #19177C } /* Name.Variable */ -.ow { color: #A2F; font-weight: bold } /* Operator.Word */ -.w { color: #BBB } /* Text.Whitespace */ -.mb { color: #666 } /* Literal.Number.Bin */ -.mf { color: #666 } /* Literal.Number.Float */ -.mh { color: #666 } /* Literal.Number.Hex */ -.mi { color: #666 } /* Literal.Number.Integer */ -.mo { color: #666 } /* Literal.Number.Oct */ -.sa { color: #BA2121 } /* Literal.String.Affix */ -.sb { color: #BA2121 } /* Literal.String.Backtick */ -.sc { color: #BA2121 } /* Literal.String.Char */ -.dl { color: #BA2121 } /* Literal.String.Delimiter */ -.sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ -.s2 { color: #BA2121 } /* Literal.String.Double */ -.se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ -.sh { color: #BA2121 } /* Literal.String.Heredoc */ -.si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ -.sx { color: #008000 } /* Literal.String.Other */ -.sr { color: #A45A77 } /* Literal.String.Regex */ -.s1 { color: #BA2121 } /* Literal.String.Single */ -.ss { color: #19177C } /* Literal.String.Symbol */ -.bp { color: #008000 } /* Name.Builtin.Pseudo */ -.fm { color: #00F } /* Name.Function.Magic */ -.vc { color: #19177C } /* Name.Variable.Class */ -.vg { color: #19177C } /* Name.Variable.Global */ -.vi { color: #19177C } /* Name.Variable.Instance */ -.vm { color: #19177C } /* Name.Variable.Magic */ -.il { color: #666 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/lettings/admin.py b/lettings/admin.py index 4633a55339..b31639f1b1 100644 --- a/lettings/admin.py +++ b/lettings/admin.py @@ -5,4 +5,3 @@ admin.site.register(Letting) admin.site.register(Address) - diff --git a/lettings/views.py b/lettings/views.py index fc357cad20..758a37bf64 100644 --- a/lettings/views.py +++ b/lettings/views.py @@ -3,17 +3,24 @@ from .models import Letting -# Aenean leo magna, vestibulum et tincidunt fermentum, consectetur quis velit. Sed non placerat massa. Integer est nunc, pulvinar a -# tempor et, bibendum id arcu. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Cras eget scelerisque +# Aenean leo magna, vestibulum et tincidunt fermentum, consectetur quis velit. Sed non placerat +# massa. Integer est nunc, pulvinar a tempor et, bibendum id arcu. Vestibulum ante ipsum primis in +# faucibus orci luctus et ultrices posuere cubilia curae; Cras eget scelerisque def index(request): lettings_list = Letting.objects.all() context = {'lettings_list': lettings_list} return render(request, 'lettings/index.html', context) -#Cras ultricies dignissim purus, vitae hendrerit ex varius non. In accumsan porta nisl id eleifend. Praesent dignissim, odio eu consequat pretium, purus urna vulputate arcu, vitae efficitur -# lacus justo nec purus. Aenean finibus faucibus lectus at porta. Maecenas auctor, est ut luctus congue, dui enim mattis enim, ac condimentum velit libero in magna. Suspendisse potenti. In tempus a nisi sed laoreet. -# Suspendisse porta dui eget sem accumsan interdum. Ut quis urna pellentesque justo mattis ullamcorper ac non tellus. In tristique mauris eu velit fermentum, tempus pharetra est luctus. Vivamus consequat aliquam libero, eget bibendum lorem. Sed non dolor risus. Mauris condimentum auctor elementum. Donec quis nisi ligula. Integer vehicula tincidunt enim, ac lacinia augue pulvinar sit amet. +# Cras ultricies dignissim purus, vitae hendrerit ex varius non. In accumsan porta nisl id +# eleifend. Praesent dignissim, odio eu consequat pretium, purus urna vulputate arcu, vitae +# efficitur lacus justo nec purus. Aenean finibus faucibus lectus at porta. Maecenas auctor, est ut +# luctus congue, dui enim mattis enim, ac condimentum velit libero in magna. Suspendisse potenti. +# In tempus a nisi sed laoreet. Suspendisse porta dui eget sem accumsan interdum. Ut quis urna +# pellentesque justo mattis ullamcorper ac non tellus. In tristique mauris eu velit fermentum, +# tempus pharetra est luctus. Vivamus consequat aliquam libero, eget bibendum lorem. Sed non dolor +# risus. Mauris condimentum auctor elementum. Donec quis nisi ligula. Integer vehicula tincidunt +# enim, ac lacinia augue pulvinar sit amet. def letting(request, letting_id): letting = Letting.objects.get(id=letting_id) context = { diff --git a/oc_lettings_site/settings.py b/oc_lettings_site/settings.py index e4d4401198..e527926df9 100644 --- a/oc_lettings_site/settings.py +++ b/oc_lettings_site/settings.py @@ -113,4 +113,4 @@ STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') STATIC_URL = '/static/' -STATICFILES_DIRS = [BASE_DIR / "static",] +STATICFILES_DIRS = [BASE_DIR / "static", ] diff --git a/oc_lettings_site/views.py b/oc_lettings_site/views.py index 22eaa0dcbe..967f48ff61 100644 --- a/oc_lettings_site/views.py +++ b/oc_lettings_site/views.py @@ -1,8 +1,11 @@ from django.shortcuts import render -# Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque molestie quam lobortis leo consectetur ullamcorper non id est. Praesent dictum, nulla eget feugiat sagittis, sem mi convallis eros, -# vitae dapibus nisi lorem dapibus sem. Maecenas pharetra purus ipsum, eget consequat ipsum lobortis quis. Phasellus eleifend ex auctor venenatis tempus. -# Aliquam vitae erat ac orci placerat luctus. Nullam elementum urna nisi, pellentesque iaculis enim cursus in. Praesent volutpat porttitor magna, non finibus neque cursus id. +# Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque molestie quam lobortis leo +# consectetur ullamcorper non id est. Praesent dictum, nulla eget feugiat sagittis, sem mi +# convallis eros, vitae dapibus nisi lorem dapibus sem. Maecenas pharetra purus ipsum, eget +# consequat ipsum lobortis quis. Phasellus eleifend ex auctor venenatis tempus. Aliquam vitae erat +# ac orci placerat luctus. Nullam elementum urna nisi, pellentesque iaculis enim cursus in. +# Praesent volutpat porttitor magna, non finibus neque cursus id. def index(request): return render(request, 'index.html') diff --git a/profiles/views.py b/profiles/views.py index 7d2af649c5..6853615d15 100644 --- a/profiles/views.py +++ b/profiles/views.py @@ -3,18 +3,20 @@ from profiles.models import Profile -# Sed placerat quam in pulvinar commodo. Nullam laoreet consectetur ex, sed consequat libero pulvinar eget. Fusc -# faucibus, urna quis auctor pharetra, massa dolor cursus neque, quis dictum lacus d +# Sed placerat quam in pulvinar commodo. Nullam laoreet consectetur ex, sed consequat libero +# pulvinar eget. Fusc faucibus, urna quis auctor pharetra, massa dolor cursus neque, quis dictum +# lacus d def index(request): profiles_list = Profile.objects.all() context = {'profiles_list': profiles_list} return render(request, 'profiles/index.html', context) + # Aliquam sed metus eget nisi tincidunt ornare accumsan eget lac -# laoreet neque quis, pellentesque dui. Nullam facilisis pharetra vulputate. Sed tincidunt, dolor id facilisis fringilla, eros leo tristique lacus, -# it. Nam aliquam dignissim congue. Pellentesque habitant morbi tristique senectus et netus et males +# laoreet neque quis, pellentesque dui. Nullam facilisis pharetra vulputate. Sed tincidunt, dolor +# id facilisis fringilla, eros leo tristique lacus, it. Nam aliquam dignissim congue. Pellentesque +# habitant morbi tristique senectus et netus et males def profile(request, username): profile = Profile.objects.get(user__username=username) context = {'profile': profile} return render(request, 'profiles/profile.html', context) - From 0c5b95577847cf2237ee8c741658f93de0e95e9f Mon Sep 17 00:00:00 2001 From: NM Date: Tue, 19 May 2026 10:10:32 +0200 Subject: [PATCH 04/41] Modification : fix admin plural issue, manage/customize 404 and 500 errors with new specific templates --- lettings/models.py | 4 ++++ lettings/views.py | 24 +++++++++++++++++------- profiles/views.py | 16 +++++++++++++--- templates/error_404.html | 30 ++++++++++++++++++++++++++++++ templates/error_500.html | 26 ++++++++++++++++++++++++++ 5 files changed, 90 insertions(+), 10 deletions(-) create mode 100644 templates/error_404.html create mode 100644 templates/error_500.html diff --git a/lettings/models.py b/lettings/models.py index 8e76ef00d2..df27eead49 100644 --- a/lettings/models.py +++ b/lettings/models.py @@ -10,6 +10,10 @@ class Address(models.Model): zip_code = models.PositiveIntegerField(validators=[MaxValueValidator(99999)]) country_iso_code = models.CharField(max_length=3, validators=[MinLengthValidator(3)]) + class Meta: + verbose_name = "Address" + verbose_name_plural = "Addresses" + def __str__(self): return f'{self.number} {self.street}' diff --git a/lettings/views.py b/lettings/views.py index 758a37bf64..303a59e040 100644 --- a/lettings/views.py +++ b/lettings/views.py @@ -1,4 +1,4 @@ -from django.shortcuts import render +from django.shortcuts import render, get_object_or_404 from .models import Letting @@ -22,9 +22,19 @@ def index(request): # risus. Mauris condimentum auctor elementum. Donec quis nisi ligula. Integer vehicula tincidunt # enim, ac lacinia augue pulvinar sit amet. def letting(request, letting_id): - letting = Letting.objects.get(id=letting_id) - context = { - 'title': letting.title, - 'address': letting.address, - } - return render(request, 'lettings/letting.html', context) + try: + letting = Letting.objects.get(id=letting_id) + + context = { + 'title': letting.title, + 'address': letting.address, + } + return render(request, 'lettings/letting.html', context=context) + + except Letting.DoesNotExist: + context = {"type": "letting", "id": letting_id} + return render(request, 'error_404.html', context=context) + + except Exception as e: + context = {"error": e} + return render(request, 'error_500.html', context=context) diff --git a/profiles/views.py b/profiles/views.py index 6853615d15..13fb49857f 100644 --- a/profiles/views.py +++ b/profiles/views.py @@ -17,6 +17,16 @@ def index(request): # id facilisis fringilla, eros leo tristique lacus, it. Nam aliquam dignissim congue. Pellentesque # habitant morbi tristique senectus et netus et males def profile(request, username): - profile = Profile.objects.get(user__username=username) - context = {'profile': profile} - return render(request, 'profiles/profile.html', context) + try: + profile = Profile.objects.get(user__username=username) + context = {'profile': profile} + + return render(request, 'profiles/profile.html', context) + + except Profile.DoesNotExist: + context = {"type": "profile", "name": username} + return render(request, 'error_404.html', context=context) + + except Exception as e: + context = {"error": e} + return render(request, 'error_500.html', context=context) diff --git a/templates/error_404.html b/templates/error_404.html new file mode 100644 index 0000000000..bc8477aadb --- /dev/null +++ b/templates/error_404.html @@ -0,0 +1,30 @@ +{% extends "base.html" %} +{% block title %}Holiday Homes{% endblock title %} + +{% block content %} + + +
+
+
+ {% if type == "letting" %} +

404 Error : {{ type }} n° {{ id }} not found !

+ {% elif type == "profile" %} +

404 Error : {{ type }} '{{ name }}' not found !

+ {% endif %} +
+
+
+ + + +{% endblock %} \ No newline at end of file diff --git a/templates/error_500.html b/templates/error_500.html new file mode 100644 index 0000000000..f7d65b087f --- /dev/null +++ b/templates/error_500.html @@ -0,0 +1,26 @@ +{% extends "base.html" %} +{% block title %}Holiday Homes{% endblock title %} + +{% block content %} + + +
+
+
+

500 Error : something wrong with the server - {{ error }}

+
+
+
+ + + +{% endblock %} \ No newline at end of file From e607c71d0f54f22b5489001a40346081afb9f202 Mon Sep 17 00:00:00 2001 From: NM Date: Tue, 19 May 2026 11:13:38 +0200 Subject: [PATCH 05/41] Modification : add docstrings and code typing --- lettings/admin.py | 3 +++ lettings/apps.py | 8 +++++++ lettings/models.py | 36 +++++++++++++++++++++++++++++-- lettings/tests.py | 3 +++ lettings/urls.py | 3 +++ lettings/views.py | 41 ++++++++++++++++++++++++++++++------ oc_lettings_site/apps.py | 8 +++++++ oc_lettings_site/settings.py | 3 +++ oc_lettings_site/tests.py | 8 +++++++ oc_lettings_site/urls.py | 4 ++++ oc_lettings_site/views.py | 21 ++++++++++++++++-- profiles/admin.py | 3 +++ profiles/apps.py | 8 +++++++ profiles/models.py | 16 +++++++++++++- profiles/tests.py | 3 +++ profiles/urls.py | 3 +++ profiles/views.py | 39 ++++++++++++++++++++++++++++------ pytest.ini | 4 ++++ 18 files changed, 196 insertions(+), 18 deletions(-) create mode 100644 pytest.ini diff --git a/lettings/admin.py b/lettings/admin.py index b31639f1b1..2b5abe26f8 100644 --- a/lettings/admin.py +++ b/lettings/admin.py @@ -1,3 +1,6 @@ +""" +Admin registration module for lettings app +""" from django.contrib import admin from lettings.models import Address, Letting diff --git a/lettings/apps.py b/lettings/apps.py index b6abff1791..9a30d0d289 100644 --- a/lettings/apps.py +++ b/lettings/apps.py @@ -1,5 +1,13 @@ +""" +Namespace module for lettings app +""" from django.apps import AppConfig class LettingsConfig(AppConfig): + """ + Namespace class for Lettings + Attributes: + name: namespace of the lettings app + """ name = 'lettings' diff --git a/lettings/models.py b/lettings/models.py index df27eead49..081de2a663 100644 --- a/lettings/models.py +++ b/lettings/models.py @@ -1,8 +1,21 @@ +""" +Models module for lettings app +""" from django.db import models from django.core.validators import MaxValueValidator, MinLengthValidator class Address(models.Model): + """ + Address model for Lettings + Attributes: + number (int): Letting number + street (str): Street address + city (str): City address + state (str): State address + zip_code (int): Zip code + country_iso_code (int): Country code + """ number = models.PositiveIntegerField(validators=[MaxValueValidator(9999)]) street = models.CharField(max_length=64) city = models.CharField(max_length=64) @@ -11,16 +24,35 @@ class Address(models.Model): country_iso_code = models.CharField(max_length=3, validators=[MinLengthValidator(3)]) class Meta: + """ + Meta class for Lettings to specify verbose names + """ verbose_name = "Address" verbose_name_plural = "Addresses" - def __str__(self): + def __str__(self) -> str: + """ + string method for Lettings + Returns: + A f-string with number and street address + """ return f'{self.number} {self.street}' class Letting(models.Model): + """ + Letting model for Lettings + Attributes: + title (str): Letting title + address (Address): Letting address + """ title = models.CharField(max_length=256) address = models.OneToOneField(Address, on_delete=models.CASCADE) - def __str__(self): + def __str__(self) -> str: + """ + String method for Lettings + Returns: + A f-string with letting title + """ return self.title diff --git a/lettings/tests.py b/lettings/tests.py index 7ce503c2dd..a6968aa8cb 100644 --- a/lettings/tests.py +++ b/lettings/tests.py @@ -1,3 +1,6 @@ +""" +Tests module for lettings app +""" from django.test import TestCase # Create your tests here. diff --git a/lettings/urls.py b/lettings/urls.py index 8b261ec831..61a7ca5c89 100644 --- a/lettings/urls.py +++ b/lettings/urls.py @@ -1,3 +1,6 @@ +""" +URLs module for lettings app +""" from django.urls import path from . import views diff --git a/lettings/views.py b/lettings/views.py index 303a59e040..9d66d4b454 100644 --- a/lettings/views.py +++ b/lettings/views.py @@ -1,4 +1,8 @@ -from django.shortcuts import render, get_object_or_404 +""" +Views module for lettings app +""" +from django.http import HttpRequest, HttpResponse +from django.shortcuts import render from .models import Letting @@ -6,10 +10,23 @@ # Aenean leo magna, vestibulum et tincidunt fermentum, consectetur quis velit. Sed non placerat # massa. Integer est nunc, pulvinar a tempor et, bibendum id arcu. Vestibulum ante ipsum primis in # faucibus orci luctus et ultrices posuere cubilia curae; Cras eget scelerisque -def index(request): - lettings_list = Letting.objects.all() - context = {'lettings_list': lettings_list} - return render(request, 'lettings/index.html', context) +def index(request: HttpRequest) -> HttpResponse: + """ + View function for lettings index page + Args: + request (HttpRequest): Http Request object + + Returns: + An HTTP response with the list of lettings or an HTTP response with 500 error. + """ + try: + lettings_list = Letting.objects.all() + context = {'lettings_list': lettings_list} + return render(request, 'lettings/index.html', context) + + except Exception as e: + context = {"error": str(e)} + return render(request, 'error_500.html', context=context) # Cras ultricies dignissim purus, vitae hendrerit ex varius non. In accumsan porta nisl id @@ -21,7 +38,17 @@ def index(request): # tempus pharetra est luctus. Vivamus consequat aliquam libero, eget bibendum lorem. Sed non dolor # risus. Mauris condimentum auctor elementum. Donec quis nisi ligula. Integer vehicula tincidunt # enim, ac lacinia augue pulvinar sit amet. -def letting(request, letting_id): +def letting(request: HttpRequest, letting_id: int) -> HttpResponse: + """ + View function for letting detail page + Args: + request (HttpRequest): Http Request object + letting_id (int): letting id + + Returns: + An HTTP response with the letting detail or an HTTP response with 404 error if not found + or an HTTP response with 500 error + """ try: letting = Letting.objects.get(id=letting_id) @@ -36,5 +63,5 @@ def letting(request, letting_id): return render(request, 'error_404.html', context=context) except Exception as e: - context = {"error": e} + context = {"error": str(e)} return render(request, 'error_500.html', context=context) diff --git a/oc_lettings_site/apps.py b/oc_lettings_site/apps.py index 6489692f04..805a860bb6 100644 --- a/oc_lettings_site/apps.py +++ b/oc_lettings_site/apps.py @@ -1,5 +1,13 @@ +""" +App config module for oc_lettings_site app +""" from django.apps import AppConfig class OCLettingsSiteConfig(AppConfig): + """ + Namespace class for oc_lettings_site app + Attributes: + name (str): Name of the app + """ name = 'oc_lettings_site' diff --git a/oc_lettings_site/settings.py b/oc_lettings_site/settings.py index e527926df9..d2e781dc2c 100644 --- a/oc_lettings_site/settings.py +++ b/oc_lettings_site/settings.py @@ -1,3 +1,6 @@ +""" +Settings module for oc_lettings_site app +""" import os from pathlib import Path diff --git a/oc_lettings_site/tests.py b/oc_lettings_site/tests.py index 3fd62bb718..851e35573d 100644 --- a/oc_lettings_site/tests.py +++ b/oc_lettings_site/tests.py @@ -1,2 +1,10 @@ +""" +Tests module for oc_lettings_site app +""" + + def test_dummy(): + """ + Test dummy function + """ assert 1 diff --git a/oc_lettings_site/urls.py b/oc_lettings_site/urls.py index 83498f45f2..87eebf52d6 100644 --- a/oc_lettings_site/urls.py +++ b/oc_lettings_site/urls.py @@ -1,3 +1,7 @@ +""" +URLs module for oc_lettings_site app. +Include the lettings and profiles apps urls +""" from django.contrib import admin from django.urls import path, include diff --git a/oc_lettings_site/views.py b/oc_lettings_site/views.py index 967f48ff61..12850d6962 100644 --- a/oc_lettings_site/views.py +++ b/oc_lettings_site/views.py @@ -1,3 +1,7 @@ +""" +Views module for oc_lettings_site app +""" +from django.http import HttpRequest, HttpResponse from django.shortcuts import render @@ -7,5 +11,18 @@ # consequat ipsum lobortis quis. Phasellus eleifend ex auctor venenatis tempus. Aliquam vitae erat # ac orci placerat luctus. Nullam elementum urna nisi, pellentesque iaculis enim cursus in. # Praesent volutpat porttitor magna, non finibus neque cursus id. -def index(request): - return render(request, 'index.html') +def index(request: HttpRequest) -> HttpResponse: + """ + View function for home page + Args: + request (HttpRequest): Http Request object + + Returns: + An HTTP response with index page or HTTP response with 500 error. + """ + try: + return render(request, 'index.html') + + except Exception as e: + context = {'error': str(e)} + return render(request, 'error_500.html', context) diff --git a/profiles/admin.py b/profiles/admin.py index 9f66e5c835..2b417bb0da 100644 --- a/profiles/admin.py +++ b/profiles/admin.py @@ -1,3 +1,6 @@ +""" +Admin registration module for profiles app +""" from django.contrib import admin from profiles.models import Profile diff --git a/profiles/apps.py b/profiles/apps.py index 5501fdad35..b0c6010f11 100644 --- a/profiles/apps.py +++ b/profiles/apps.py @@ -1,5 +1,13 @@ +""" +Namespace module for profiles app +""" from django.apps import AppConfig class ProfilesConfig(AppConfig): + """ + Namespace class for profiles app + Attributes: + name: namespace of the profiles app + """ name = 'profiles' diff --git a/profiles/models.py b/profiles/models.py index 84c85c1001..5893b3c972 100644 --- a/profiles/models.py +++ b/profiles/models.py @@ -1,10 +1,24 @@ +""" +Models module for profiles app +""" from django.db import models from django.contrib.auth.models import User class Profile(models.Model): + """ + Models class for profiles app + Attributes: + user (User): user + favorite_city (str): The favorite city of the user + """ user = models.OneToOneField(User, on_delete=models.CASCADE) favorite_city = models.CharField(max_length=64, blank=True) - def __str__(self): + def __str__(self) -> str: + """ + String method for profile model + Returns: + The user name of the profile + """ return self.user.username diff --git a/profiles/tests.py b/profiles/tests.py index 7ce503c2dd..8aa3d58736 100644 --- a/profiles/tests.py +++ b/profiles/tests.py @@ -1,3 +1,6 @@ +""" +Tests module for profiles app +""" from django.test import TestCase # Create your tests here. diff --git a/profiles/urls.py b/profiles/urls.py index b33a49ae2d..1efb5f1a21 100644 --- a/profiles/urls.py +++ b/profiles/urls.py @@ -1,3 +1,6 @@ +""" +URLs module for profiles app +""" from django.urls import path from . import views diff --git a/profiles/views.py b/profiles/views.py index 13fb49857f..0fd413dc80 100644 --- a/profiles/views.py +++ b/profiles/views.py @@ -1,3 +1,7 @@ +""" +Views module for profiles app +""" +from django.http import HttpRequest, HttpResponse from django.shortcuts import render from profiles.models import Profile @@ -6,17 +10,40 @@ # Sed placerat quam in pulvinar commodo. Nullam laoreet consectetur ex, sed consequat libero # pulvinar eget. Fusc faucibus, urna quis auctor pharetra, massa dolor cursus neque, quis dictum # lacus d -def index(request): - profiles_list = Profile.objects.all() - context = {'profiles_list': profiles_list} - return render(request, 'profiles/index.html', context) +def index(request: HttpRequest) -> HttpResponse: + """ + View function for profiles index page + Args: + request (HttpRequest): request object + + Returns: + An HTTP response with the list of profiles or HTTP response with 500 error. + """ + try: + profiles_list = Profile.objects.all() + context = {'profiles_list': profiles_list} + return render(request, 'profiles/index.html', context) + + except Exception as e: + context = {"error": str(e)} + return render(request, 'error_500.html', context=context) # Aliquam sed metus eget nisi tincidunt ornare accumsan eget lac # laoreet neque quis, pellentesque dui. Nullam facilisis pharetra vulputate. Sed tincidunt, dolor # id facilisis fringilla, eros leo tristique lacus, it. Nam aliquam dignissim congue. Pellentesque # habitant morbi tristique senectus et netus et males -def profile(request, username): +def profile(request: HttpRequest, username: str): + """ + View function for profile details page + Args: + request (HttpRequest): request object + username (str): username + + Returns: + An HTTP response with the profile or HTTP response with 404 error if not found + or an HTTP response with 500 error + """ try: profile = Profile.objects.get(user__username=username) context = {'profile': profile} @@ -28,5 +55,5 @@ def profile(request, username): return render(request, 'error_404.html', context=context) except Exception as e: - context = {"error": e} + context = {"error": str(e)} return render(request, 'error_500.html', context=context) diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000000..81e230b474 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,4 @@ +[pytest] +DJANGO_SETTINGS_MODULE = oc_lettings_site.settings + +python_files = test_* \ No newline at end of file From 03322c719b4078d8f0c062b5ee377999f962d75b Mon Sep 17 00:00:00 2001 From: NM Date: Wed, 20 May 2026 11:41:55 +0200 Subject: [PATCH 06/41] File change and modification : add tests packages and modules, update readme.md, relaunch reports --- .coverage | Bin 0 -> 53248 bytes .coveragerc | 13 + .gitignore | 12 +- README.md | 219 ++++-- docs/cov_report_1.png | Bin 0 -> 28563 bytes docs/cov_report_2.png | Bin 0 -> 51896 bytes docs/flake8_report.png | Bin 0 -> 16384 bytes docs/screenshots/home_page_screenshot.png | Bin 0 -> 26046 bytes .../letting_details_screenshot.png | Bin 0 -> 44626 bytes docs/screenshots/lettings_list_screenshot.png | Bin 0 -> 42869 bytes .../profile_details_screenshot.png | Bin 0 -> 43697 bytes docs/screenshots/profiles_list_screenshot.png | Bin 0 -> 27106 bytes lettings/tests.py | 6 - lettings/tests/__init__.py | 0 lettings/tests/conftest.py | 33 + lettings/tests/tests.py | 130 ++++ lettings/views.py | 10 +- .../migrations/0002_auto_20260518_1551.py | 2 + oc_lettings_site/tests.py | 55 +- oc_lettings_site/views.py | 4 +- poetry.lock | 624 ++++++++++++++++++ profiles/tests.py | 6 - profiles/tests/__init__.py | 0 profiles/tests/conftest.py | 22 + profiles/tests/tests.py | 135 ++++ profiles/views.py | 10 +- pyproject.toml | 23 + pytest.ini | 4 - requirements.txt | Bin 46 -> 876 bytes setup.cfg | 3 +- 30 files changed, 1222 insertions(+), 89 deletions(-) create mode 100644 .coverage create mode 100644 .coveragerc create mode 100644 docs/cov_report_1.png create mode 100644 docs/cov_report_2.png create mode 100644 docs/flake8_report.png create mode 100644 docs/screenshots/home_page_screenshot.png create mode 100644 docs/screenshots/letting_details_screenshot.png create mode 100644 docs/screenshots/lettings_list_screenshot.png create mode 100644 docs/screenshots/profile_details_screenshot.png create mode 100644 docs/screenshots/profiles_list_screenshot.png delete mode 100644 lettings/tests.py create mode 100644 lettings/tests/__init__.py create mode 100644 lettings/tests/conftest.py create mode 100644 lettings/tests/tests.py create mode 100644 poetry.lock delete mode 100644 profiles/tests.py create mode 100644 profiles/tests/__init__.py create mode 100644 profiles/tests/conftest.py create mode 100644 profiles/tests/tests.py create mode 100644 pyproject.toml delete mode 100644 pytest.ini diff --git a/.coverage b/.coverage new file mode 100644 index 0000000000000000000000000000000000000000..bd43345db0dc8d97108ca92cbca36692265a5511 GIT binary patch literal 53248 zcmeI)&2QUe90zbaPU56Z>P}@ur7L|dsH@g?ONRt(2UfNsrcK&b#>=51bCRcxM-r#D z)0e~6C7U$<2u}P3z>yOdE=WjlgA*La7(yU{KthZIzvr=?m$pGWOzDfhRuen6pU1!F z^Sn4t8ozn%vgL8MY&#XxW2cp2MOBq^j46teq(_<_;iS_-G<-pGwPU&0Vp5qcsA=PE zB^7^HG2Tl*XUwElQoj#=n0h(+)}W~n7_WjuFt=Ad4c)s*zo~I)65K;XO6wjYTRMVR+%%aTC@tLXH{32SK{H` zb(a^#Ig8fOSxf9VE7OamoK>V$9$%p>YK~PgolW*W-<*~^1V{7uhUc%KOt`gD6??Gb zLGmf)@MZ4sYJt0c6vwUN)WFo;tpPnVGNRt+vP`B^pufSc($I=_Q7$f1Mg`j`is zSuK>fJI%~i2@5vGx#9Vxb?nMX&t_$-DvMclEzh#6jBoHl-Q&ew3pg#%!in%YOGA0x z5Cyv7rwoqOq0>&hOUhvPAn`H1;zge%;MCDKl|G=KzD`l^= zo*fkSiR)&Ux@?!Xt2#q+QKNpUdevI3^H$|gvv$g9S&XVZ%|s!n1-vjA&%83CD%2|Z zhPzs(w@x{;?%DEnjw(NwrKi-rBMCh-F`?dHl?_Gk=_Eld*W_?9pCn&p($eelUSITU z?4>I;y2nY`bX~``EAGOcJyXx3CdBMwNPcNOC%PsPnO?M`-olTi~_x);) zEq-$CF0EO7-KC#$-_|Jrbq@llJ7sbFt$2R{=!Q4qmNgv!vHk+I0tf);{tFbqNdIcU zF66=(a@1aUt0^?%8bxws4t7(PUQw}&TsF&wqV_k0uu7I%A&Bq)6N3*F z<951~dN|~y9}PXG>;DG_bD%@i5P$##AOHafKmY;|fIvfuHnqLD`VKGu6I;=yx)%Wi zmwI}?1zOixp+LOP0<8c7fmkCEZI1M@3VL4uN9m)8=8?UOBp}fmYP1>aV<0=P|0AMZ z#*+Q}2%^<2TG#)${~yi|5P$##AOHafKmY;|fB*y_0D(g-psAXY7T^D?#=i>vVS)ez zAOHafKmY;|fB*y_009U<;1CLES~@9z|8IPx7=IW)8{ZjU8($co8K2M!Ob~zo1Rwwb z2tWV=5P$##AOHaf^id$4h^onBiBH+*XNT|nGNkMDa#&v+PsVBCnaJGTn3{}<#pv9* zJL7bp2imOVZw+a*@O)e(Qz9Qzx`@~iTO3cR(PZ-2oc8xu&D66|`TKw4OT~C>d}};3 zzBm3fel@ + +

-- `cd /path/to/Python-OC-Lettings-FR` -- `python -m venv venv` -- `apt-get install python3-venv` (Si l'étape précédente comporte des erreurs avec un paquet non trouvé sur Ubuntu) -- Activer l'environnement `source venv/bin/activate` -- Confirmer que la commande `python` exécute l'interpréteur Python dans l'environnement virtuel -`which python` -- Confirmer que la version de l'interpréteur Python est la version 3.6 ou supérieure `python --version` -- Confirmer que la commande `pip` exécute l'exécutable pip dans l'environnement virtuel, `which pip` -- Pour désactiver l'environnement, `deactivate` +--- -#### Exécuter le site +## INSTALLATION -- `cd /path/to/Python-OC-Lettings-FR` -- `source venv/bin/activate` -- `pip install --requirement requirements.txt` -- `python manage.py runserver` -- Aller sur `http://localhost:8000` dans un navigateur. -- Confirmer que le site fonctionne et qu'il est possible de naviguer (vous devriez voir plusieurs profils et locations). +- ### Clone the repository : -#### Linting +``` +git clone https://github.com/Tit-Co/OpenClassrooms_Project_13.git +``` -- `cd /path/to/Python-OC-Lettings-FR` -- `source venv/bin/activate` -- `flake8` +- ### Navigate into the project directory : + `cd OpenClassrooms_Project_13` -#### Tests unitaires +- ### Create a virtual environment and dependencies : -- `cd /path/to/Python-OC-Lettings-FR` -- `source venv/bin/activate` -- `pytest` +1. #### With [uv](https://docs.astral.sh/uv/) -#### Base de données + `uv` is an environment and dependencies manager. + + - #### Install environment and dependencies + + `uv sync` -- `cd /path/to/Python-OC-Lettings-FR` -- Ouvrir une session shell `sqlite3` -- Se connecter à la base de données `.open oc-lettings-site.sqlite3` -- Afficher les tables dans la base de données `.tables` -- Afficher les colonnes dans le tableau des profils, `pragma table_info(Python-OC-Lettings-FR_profile);` -- Lancer une requête sur la table des profils, `select user_id, favorite_city from - Python-OC-Lettings-FR_profile where favorite_city like 'B%';` -- `.quit` pour quitter +2. #### With pip -#### Panel d'administration + - #### Install the virtual env : -- Aller sur `http://localhost:8000/admin` -- Connectez-vous avec l'utilisateur `admin`, mot de passe `Abc1234!` + `python -m venv env` -### Windows + - #### Activate the virtual env : + `source env/bin/activate` in Git Bash on Windows or on macOS / Linux + Or + `env\Scripts\activate` on Windows -Utilisation de PowerShell, comme ci-dessus sauf : +3. #### With [Poetry](https://python-poetry.org/docs/) -- Pour activer l'environnement virtuel, `.\venv\Scripts\Activate.ps1` -- Remplacer `which ` par `(Get-Command ).Path` + `Poetry` is a tool for dependency management and packaging in Python. + + - #### Install the virtual env : + `py -3.10 -m venv env` + + - #### Activate the virtual env : + `poetry env activate` + +- ### Install dependencies + 1. #### With [uv](https://docs.astral.sh/uv/) + `uv sync` or `uv pip install -r requirements.txt` or `uv add -r requirements.txt` + + 2. #### With pip + `pip install -r requirements.txt` + + 3. #### With [Poetry](https://python-poetry.org/docs/) + `poetry install` + + (NB : Poetry and uv will read the `pyproject.toml` file to know which dependencies to install) + +--- + +## USAGE + +### Launching server +- Open a terminal +- Go to project folder - example : `cd oc_lettings_site` +- Activate the virtual environment as described previously +- Create environment variables (to avoid to add raw Sentry key into the code) + - With Power Shell : + ``` + $env:SENTRY_KEY = "my_key" + ``` + - With Git Bash : + ``` + export SENTRY_KEY = "my_key" + ``` +- Launch the local server by typing the command : + - `python manage.py runserver` + +### Launching the APP + +- Finally, in a web browser, open the urls : + - [http://127.0.0.1:8000/](http://127.0.0.1:8000/) + - [http://127.0.0.1:8000/admin](http://127.0.0.1:8000/admin) + - for the admin panel (username: ```admin```, password: ```Abc1234!```) + +--- + +## APP EXAMPLES + +Here are some examples of the application execution. + +- Home page +

+ +

+ +- Lettings index +

+ +

+ +- Letting details +

+ +

+ +- Profiles index +

+ +

+ +- Profile details +

+ +

+ +--- + +## PEP 8 CONVENTIONS + +- Flake 8 report +

+ +

+ +**Type the line below in the terminal to generate another report with [flake8-html](https://pypi.org/project/flake8-html/) tool :** + +` flake8` +- The app code has a setup.cfg file that specify Flake 8 options as below : + ``` + format = html + htmldir = flake8-report + max-line-length = 99 + exclude = **/migrations/*,env,cov_html + ``` + +--- + +## TESTS COVERAGE WITH PYTEST + +- Coverage report +

+ + +

+ +- **Type the line below in the terminal to generate another coverage report with pytest** + + `pytest --cov=lettings --cov=profiles --cov=oc_lettings_site --cov-report=html:cov_html` + +--- + +![Python](https://img.shields.io/badge/python-3.10-blue.svg) +![License](https://img.shields.io/badge/license-MIT-green.svg) +![Coverage](https://img.shields.io/badge/coverage-100%25-red) + +--- + +## AUTHOR +**Name**: Nicolas MARIE +**Track**: Python Developer – OpenClassrooms +**Project 13 – Scale a Django application using a modular architecture – May 2026** diff --git a/docs/cov_report_1.png b/docs/cov_report_1.png new file mode 100644 index 0000000000000000000000000000000000000000..8da9ced1d245243967b0ea0867f06af434c2994d GIT binary patch literal 28563 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 I!r1SB0jZC;PXGV_ literal 0 HcmV?d00001 diff --git a/docs/cov_report_2.png b/docs/cov_report_2.png new file mode 100644 index 0000000000000000000000000000000000000000..58c9a2c22e07fc4f427b2b6a5305f09272caad33 GIT binary patch literal 51896 zcmc$_cT`hP*FPFSK&c`iN{a&?d5CIhdr3wg0F5R9K>gt?9pxJ>(0z8w2bH&>`a?izKkpjl=8V0vjxqr7J&uuJO-s2y=b`c3 z8vtNwJN>8XbT4=b0QBf+swzK$SZ)$wiHjo^f+5I_-J6}g=k4u7=N^~6eQGz7;aATf zK3m+TaNjNgl2Cx2o4M(eR;2S7Kp&M6MxVnlX&n?eKJzK`RC;& zGGn;(-u96C-_E8|w2daNBKqxsyDeTSZ=_Bz1Qn`yktB_4?D2m zEvyh-ji!QJWbJF@1M#km3x%8qom9Xd+6~wPTMyEOHz(OkwsnRetIu68H-xIs964>) z&fm)XZO=xz21RZPvaITY| zB}df!=}K?XL6wmy$a&;k3yQyG)qkz`w?{o|H8_O6pU{(1CRg3EGY@M7j!u#}^`Jas z{zEa4<3eO>ZFMj;3bvK8wq%K;o`L?6Q3~oqEPPkb^PJYs>5h}V#VZ$Uf0J|;w%y1l zO1sm_H52o#0~GBXLcFga2IX7K7M;7FAF9#`Z}|x%DmGLjIUtKrT$ma80&-_*=+lpE zjKZE0p}7PW3ny*}dib1aW{k5wnd`%~jn2kZApN~7MNUO&!Zpw+;ozrm4^S?8JEXVs zJdWvuLwc~}&j_OXPXu}QdGO(Uy+?);Xs;E9hX!Ne*f}g1|3}~fb!ZBy3o*ZQb*>f< ziUK8Rqme|C{jOe+TPK3(#CwIRS$p?7((h8#4(}HEv-t&ZeJEn#j)`aJ82}j#p0mZV zH0|>pZ?lt^SP1>nGckH(DH;LFgtDiL>6Hf=aSIbso?GQAGA9H6X#ByrYjDsK>rMse zM0EF^PmPNwJC9r0_OdMvj?(Z36yr%rYhk;dr!0Rz|=H@8d zRmGrLc@K>9Y!tpJkk&1T+*oro6J&rtLa1zMvig&Dlplkz)S-=#QHmyJasgY=*_N-G zUbnZa@1T=73Fyfj!?lW|dF+NOp`*~ey#ENfOKu?(n0ZE#c*az~Tzk|^)Ff#KJRe8e zl2srR?ku}~sCwZZjEA*=i51o8t=UGdqZvGKcR3}ay;~j}=T*c(rs!SMIRtbTid#Q= zZ*y|0_uDfu=_12Bd6PH?>HlheIC;w{_^?TSw@o@9UsZ{{ z#veHAife-%s^jWcGCTLbd6&=j296RlkR1m+As0ku-m&u5a~+L@oReOnhWIz}gOb+E z_Nn>hPvqV=5T$oOWH^}yxuYELIKLAd0mBW=hC+!LQ!@XhAzWOuydkQ0jg^9cZb%Z#6zmUTp*KI@dY%z- zL}BD^6p6jbt4Gj?Dq0#dE0enhcc9*xcsDISJx_fuwOb)yO;9lWlD%5RYc&2tWr0WSj2Ac*HZa038I+bB5k$+^+#W8}_{1hTZ!@yJWB z5oqZ}4YR#JttD_^u7}Wq--T;DP3))+Mh67DJ=p@9=B_nO zigxlHA!*?dk~c&!l&e34VVhJ4Zr@v%-f7iFG;6F?@2JCrxv-=bo}Kj^<2f6>5SDH8 z&S>ht+`p_?pc!w86(vO|6@Jx@2DTAVm=+B3egew}z#M+&?Kr%V4zd@wv-T7K5t=cp zy-)z7gFh=$ZPkO(`I^V=1!cElzCH@xB(3Z;Cd6L2qKp+iF07t+8s0^c9%iu2`MS57 z9bjg6dU1S`loNOx@7X}&1~}V$-b_3A3C#E@YaZ7I98A9y0-QMx^PgWIu2kRosFy** z!q z)T_sbo5nM4(LM1%>4;<%1|)WWg5LO9YA!o@-u%J=A` zU&rlEsPFb~2VG>B--mDmc{A`Ug=vWAcfNH3oKc=Ff(AR}*iMmYy10lbc58RaORji-V7OcN)nI z2xIxZPRqRu=E-SS(tYO#z#T$|l@^|YB#!1 zSBPX4&&Ip8w%iAhHda9R z9Y=j0Ik#M%(jah%+zj8pUb9yxy^s<@_6&xi{y_Fc34*_%tDt$o!KW&N{+Jeis3}hn ztRYR)XiwIK!OSP+YQkby-3T#0g*#m3Hp3OEVqfkc8_}ktAQ75=*kwKLy@hqMCC!cs zr0-H_<1AzCYCe`Yikh`m;CvU^Q?j(_ zL=rOTPUd!Nzm8i#*^mCkQ1bZ{BmWdvdo=aFHxthr0>$1}u@>JbqOkHytUB<%DDh{4 zJ>dPkmEn(SkI^6&D!o8lxL~OI)D49amN5VzXo-hxFN$RGpYn{_6%WbbH*~bbx#LjC zs#hruyVp&EmJz%8(a|zk;8ruA|5UaloQ5>6O<4^nQZ&`+9BCK0+c*50vOhtg+M?!f z;rDVkV&y4KK_NQpJkyiSbtr{#UQWH;E->M#cqm|}h&am_OcdQ+N&N_5+i|8GKeXn%Nun z)_sG~0jsNvUhd6oTM2<)j9c>@tT?h>wpsCb?#aupwe}=rg;$qkzzhTvz%0G>-ljfFPPyI4$>d0$T3x1VcP+Hhil3V{Kqm%-j);t9OEwcx_9SREKHw~35?^8 z?F+d8HqM`qsUhAC3RRC=2v6mkDP}IlPXW>Xz`=gXpf9iqU_HL0bRqVd3wmfAVk)0G zi-mI33M=87qanwWGhxzB`xCOFQAv}}#1O%J@Xw9XNn2d}_$#p>26M7^R8B($S3-jH zLOB9h|86hfs*9j4v!N&yKOG0+^ z5mzWmlASRWK7hGK!FS-meGG1=hp}d}zO;SA4N5~gMBYXx!N8qx1vWGROuk_WJ-95a zO7oF|V=y(OSp04Y)CRI5IuoISIMZ}I4C{PLJ`u#NgJ6tGA1~kDq$PMBC*ca|$(Joj zddBlRDS9@h8$#@HHGbG~2n4Yfa%@on=``op%mi2A?ssLY}em7>dmb(Bih_EX)O;Cuyg7md!`MW z>3Z`>cn#NzS_lVfmYiSn*aD{DG+T|e-poM0sb^`t0N6P?OfVsBi?$)j>9hqlm9|s< z@*>CurjRA=0sW<-(ow!Rf**js3G2IwPd!?&h)AJ=k*_Sn_63?w&{Tw;>-qOnm;k%~ z@>qN>rZk?+&dtsqve#g3n`c3R)W{$(4LNaCP0%H!12Vb7I+p>w946o_&(&Kcur*r(3FPtaVtRv>TwnHw)!5iPWBQNQMta0L+j4h+(LC3Ip z8icb5aWf@$zAIxN_o8yscD4!_v3nht!OGv_d^kT0XxQnrZP?3C-XZjnIblc5DBF|k zS5Lww+Cb7#2`#j>#1zZ0?Or4cd5Z=akqYC9GabF7F&G)pp}k9#o(W@xVrSRa0L+zd zw>AN5Slk;o{C8TeBl_N7Ng0#^tocnFeDRtV^w=emL;agpK=XR=6DiAv&H6Irz1UQ} z%;tKQ)vw1~9$2I-WEN)93?}tS?@(Vk+Fwx$olQHg*0?)!J0|XrRUFx#a13e)?QPmP z{KU%tQ`E9bQTf6Sb$`hEG_DYA(XlRV39t;LRnr2#KKg!Sbx?os2!%G>ZIMGiB=1pVFRuA&SK5fh7g)IwN-&aS>n~?XOyJ z2Z+22ZV^NdH+RlV9G*RM+Fo^7g}3IPkcvi2+Nsk?xoE@xgTM>8CPZ_IzVP+s)Kff6 zREn0Gn{Y<7cXge`VkYxZf4fZ>Dze5m9hSJyquZl#9nwu%sEMS~8Z^V^WHsw7aeB4{ z<+OJCQw0bwu5dKv4cTqyIvlU0O0n>}jNKd$2jag2H{|r!s~djsNyWoXVN#@pUU;rM zbi)icG1?TV7=-n)_&x2&C2IN88>JX!+_?VKf=dDjJuvtz@6Un=UJ}|Jscw1-*WuZT z5Dlhi{ShqAxwMupiiK~`-u}SGa*~Co8+p3!w$glPyohDP8_F~1Y(;}om7GTd$9pYL z$C#r`@}xL9GjRQO0}dU{^x?;Ev)Pkpr?iDMc(e0=pI-0+&seoP&~h(6WwpYuB&A{T z2IYQMUwV99o%m_=2hG0dX}ss;P~u;qstL>`fz#b(W4ryI#EGaz;NC5_scO~)_*)YB zmjD)%u1XMfO#=K0W~q(OM_tnWWq-N^6&o%(O?b;<6Lc&e7GK~{cIJpb8uEzc1)n)toJ)8zSp6Pwm8!XR+0x{X?yy2M($m3)qW%Q`QyQ8(2Axol=Ka9=*n*54jo8P*F)C{#991| za)$!8pT5dKJ)U{LK(F-q7i@7S45Dl3owSI8Jma|1$kn%PLD-?fm0p-iyuV^{Hs#`C;Hx`!!Hl}l%YC@~_qN^=FFBsr&zZ5TulqCX%M`i^+R4hK z`V`%<3K^jzJbIqaAyLM_m}9fsO8ZL`m6LB#CP8mmF?0T04QVwyzBAPS{VYT9AyX3* z0CEAW#Mp3BH~KOKw%02YZJZ;!5y)$yaA$uZL47x!b?P1Kx66Bcz~*^l7$+PYSWXQ5 z>kRd7PF&Fh)@0Q`P`h{y8Aw=u5?Zz0$SR=Sus{>FyG}n-U!Qh+jYhh-1msYbW}yDe zhBiwwtnje($$-f@Yn{iogHJ!Dg>sgD$zB<4i-FKq=6t)foJ?DSy1T^k zcbR)B$NJ8Z{zQWY@(2Qr>l?TGg4??s%*i^}=rl9!FCGh%Joef+yg*^|K=OE%@}S)+ zRWd;s&F2ssE0})&yI!a6Em8Hp&1XV=O$PGlz=mbO&L8n|Qhrc5Xs{2CEb*=A^A}d@ zo9|as))OxX=zKB!Yil#e_DU|DHsV>@t2^+QfVWZ`H%|4ZH53KlCS$F03vXcyLP6wmX-$ zeM6oE_$2U|A^z%wlymc|+?wC`86RMtVB8C_JG3yna`;R`%6&%~(&LIaLw!E=yTcbZ z1RT+Mv0^J(iNka6t%s?f@dTb7e)0((!8fA+#2NbPPKWc=&2e7|R;Hp`Ycz_Rx&FfF zk8RDn>CD6#CGodBIs-$eLwjEAdlm?9d0A9DoggEZ%Ku#?Yq9-3B_KQb4f$??tP8}5 z^jEl!XrG>KW_EM01R8AExIn?qfpbymC@Y1v=~C=*&1E(zea@vvD;O1%ZZ z{RzJ@4brLTa{DRrO|t<0j}3iY^Q?P-tGtT<`BdSU>oe&!+t3utYhq#1ZltI9l`@MO z?1b}uF|k44&{LUEtu$bY|I3m$9EzBPzh9|VPX5mlK|B8OCtZc?QQtk(;0&AfOK!Y; zNK-h|oPsWYBRwm4D#~n2iDBWIOayxr*UsZ!Ux&#?H-^sbI!&`|a7OFfHt^4+yK#NX zxu}$R-p_JjZGAM+g$w>yWy=c#^1ONBlP{^Jpgz2={tE<6-o_Q{E=2B-H)+veDxvss zo!h$1MCSVN$>V_Q86BHSFWWnXD=<=y?swCxD@OIJH=OdPL!4GLK`2*b{Q!|-ZnOJd zd>BUQW;D->S~?2zc1Fx>xYg346sQRAtyA4z6&MM!*id=S8();m;#$*Lt3vVVv&y!dIT^H@PQQzjwF2s~vb z2nfz`s(|hS-=Lda&*X}yVWx*Sw^VLhNTysEdySB6Y3lyeRz1&zJ4JjZ7+l;&5vOyD zu=nUiePVoU90zRQUFbAuWv{`#BX-#K!wE9{A??03EQsciA?kcxtNCBPpR~04rRO^~ zLhVI9k6xU*&9!sT4z2M*DmBWl=v6C8Wqd~NF#X=DH;xmex&Sb5By;xsGLrf3K{u)+ zNfVa77#5*WZfv7)8hl(QI)vaU`)pw!`g&jHcsDA{Eac`nmQp1M4b~!D1_Ff6`*-?mf2_l!Wvf9<0UBA+PY~($f(OopB4RqY)A*#Je0v&!UJ8g_kKgppd02RphM>Y&u1Rf2g5e(XOuy|#2j*R z4V$Wk%-8Lz9+ZA4l-NOeDkX3?d-ulID-HZT-(`5WRle=pn2t1Lz9bd0%LGHH>^<06 zXLB-9Tcf_Hw!5)90vXb*>c>V~ZHlbmGyTFZ_q2qZ^nFQ-ToeY}z2zHZg#tH=ds>r+ zz3Qx{V~lzsIJ7UsyLa2=9z?@{X2i%O1b3}8s6sZ>U64K4PYZvXAX5Yne-?lz&??yc z+Tf`o5nU|f_?jjik(86q!R$~#L(UgnCS1u2ilwmHW?gRopx!-zj?thcfSiQ)FbKc| zpN_s7)^t=8kYk3>YPVbd|? zuLDVo0|ny=pZy72W@YZP%rcjfbWGiaHr~dmPsSwUaozg^JXrfL&ze5VU3I2D$kQ?2 zhD8{r|E_!RIe=z*FrZ5;|Hl+%0d;`Ke0=Ja4}N^{BS~b|)UZnbq<^R@fzb1(2!NUn z0&R20`JrhB{Gc2Hc}|yf5*RxhV}^a?ShprJ1?^QDXI;kaKK5?*E$MxLO7FDIYtgCU zUQo~X;KR-**T*g3cKdazUk-H|t4eyUc%HnC9`kQ&8NQD?L*LCbF1W;LP%>25N!dl_ zX0P4{_cn$X?6WI{L=0X2%@k8yG1o$Q~lQ8!{=@lQF-t<0f$cAxc9X( z2f0>S?=kfE9$L8k!pS@SNwWt@K#8AAOfRFkRlIs`OQ!V=!@lvB`auU2=vG@l&UA~V zG)*T#cYarVoyR>l#W>xnYBG6!ctM6{E)xEB)LSyG#J4AqCU*vnBGX*_VDp7%15}xyp=1*R=JG|(n{<5B^P|$bfo?D=u z3@ES}LONjARK8b{xu3uL+HfH&A1c0~b$@Z(C=TxErd=}bC{*Mdh^Cv$IQagtQ=hf} z07{h&AWLNV0r^KX))@EEtxX+4s0p z^Dew=>&U3onaXG&I!t#K^Wq;tcZGfMp{!<@k!IJY@qB61?P=Hz^a#E@R45&qk@EFt zZnGCIGk)pNi}%L3KeiTwCby0 zm~-~iiP6;R!zPu>((@uWzD!haC+9xmVx3`3DY zM$~FTD5MVi>>yG2wwn8!qXkYbct=Eml%Sib-~1XyJG3j-raWyqiiamdYJKvS7l!xR zG?fJsA`AS4L>^a9CTqcLN)RjSM8pRj`kZC&5`4C*&c5z#N&6zdDt)>WQifdC!Mtqn zr6|_ktSFSQ&(J}^q>@&-W`^ds{p;x^kKno78nEl4)$mQdya$aW-!+|?7peOJPM2AQ zj&Ici(_Svt^|#QRr~Ro3yz#Z$N*erZA9pGci+`jdjzv!Df3`d-!rnMHmX=fQ%K`|C zCAz_~X#asDcF6HVl>%2% zt52_M2F18{TQLRRZNL4wMxE!0H92YQ=+}bG?jxgp*(8^=qn%f^Kh`K5i{yR}x%YZl zwOM}*xh8TWREGbs;_b|b-sJaMm^K}0bX~OGoX>%K9q`G9Yey&H?J}3=HSWr*K_PCf zF{2hg+wycRjki06esA_ttV8GS&ZDpA4D%jLJ6hQ9KqQ1LjlY>j`oLslFYv{4s}F?~ zWZT7SCA3PU>K@{{?#sMv`kl^{XAu)Fz1fy3Dn-vK>-(a`WMPa0DmZiO0E?d}Fv>SP z#uK`8Ok{GT2OcL}?<~|Y8TxCzzm^_H^6W!$_c?TV zLllVkJ6`k4abA|v5x0fsqK!M+1Ur#mFO;k#8_!WPNl2*8)J0wNs-oUPU#IPC(J-qM zH|(|e*4RwI*m5#5BAXnk<*gPy%P^P@w53>P4qzuLH^iYLz@^eApJcK|F}DO#rCMcc9F-SnB*G!S-LEP^M~L?2sm+_=0uvs&k~9$4Bo%u)7*aMQ3{WQeuK2}GT) zLHu2`hFcway5@X6Nl+X#=ajv???ZYF4xb2+(n5SI?28*Jy&f~}Jt&89*f)Ec*N`E1 z*Wzno#WQ@WY$@Ae=L<8au~WtDDZa)8UJy8pe*EEgj1+CvYiwH<5krt7ToI&jiEUu( zJEjkF@@VRpL!&DR1%~9=&R%rvzx>8;jgFS!R)SMn3rn)qZVvml6F?vQ7*|X z@*kXDKezW%C-9N&o}>{5nUNdP}5cRe;lXCr@CibuKYvaYF+mGXDo() zPvid=;@#)-4_DboHwM3Ip9oyz77IGs`tz5)hc`z4-$R1`=>Y!cH-Q%gN}!dmq#M_C z3iXz9oB{klefFfY$@#lqu+VGV01_Lo0^~eB>rAAL{bB0ll5p&_-+B5t+zHdQ?D-|& z_)a5k^ZTU7&Kw(4zr~-V9exb71fubt~<7nS0!(;ozwt#00*lHx@74|Q5??7t}> z7ayfrZtpdgn+-h@>pFfD5rG1>sPXIB$4y7pd$KAaDJ3xDHZ>TxxlCralpn@%PVxLd z+rV`f5HOXMGJDKaz}&jC6xS8vwAeCvu2L!KjbA(&z&}lcFX95Jubd8K7bwYS3owsy zX8MSlP#1y>`BZpX;H32ys;V1qD}o%eM=it~hG2VKH3vyiWd#2d-fI)*NFT#xWcF`) zw6qVmgv+3NrQNH)PFyPJV|mG5dp+d9!iHTDsLs-{&w~D8V;?hlUozaGbpMN#sIJPe z>h@d8<3HzP9qwgK?Yc?!20wlSThTeDuhZ>OaJ` z%2FJ^{o@pCm~_7n>OEGx!hLP&5Bbn1Kh8UNs`BQGUBze9K+LDFamcz-9SuGZ#{ApS z;ggEiO>Y`N(*?`sEVG4^Mwg-b#iSzP=P{ZvbYOFM}#?^G``NBa( zr$@RYIbpkM0(lFJ8whwCXB_P;S+zABY&&_k-xG0gQ-gs_r?;S8aHB<+){`rD$33$n z3FPpIv4=Y!H(M3=Y-a`pQ&b|%g+q2)=;s@-+Bly<|H25QS%(UkDpVU64YGEFVr{7WdFgJNk{{3F(rg3iNWE&fBpDvK%53rmajeqkd?GYYy9qjC z;|-pB_E`za&6q@l9E4q`h&0s{Hv&HpClDb=eiKMGc|a?Io*Xo8WgLs6_b{t09jb`( zXdx=%I)V}cVA8rX;wb2%l@BWMsFXgIS95z(9sR1*TuB6uSI?WX9BL2^A$3s&z%yi{ zdLDl6C`h$hx8$3(QR$k@JN{JINj})TI`_LI-PsF*z2uf2c-H;RkW|pE@oF0Nt)E$p ztn;Lb0Wb09%{A1**OmCi7q?xFZ$QnD&7yC4- zVPKi}NK5ZkZk6|n=aOE?C04bT{&3d14;Bd{9$O8AOnN1rrubX2Ay_9F&DmV~-JO)s zZ#sVr-kqw7Mxe%bskaU(zxf|d(3t8ncwViQ?McVTZt(L)XXb)lV)Xb8N!zs#Y_Fz9 z(WrZDc2O+^8o8e(&V~ogpSMd8rN)*-g?j6C^K2VGG;hvnF7XUo0+cq=@i?g|tC}ez z^Kz&sA69_%>bm295GY5+WFuXLCY%+>s=y5%vfmw+ooki!M^}33{q6g}gR)+B`ZFZ9 zU!T8OUA4q+5+S$7pH-H6U)*w>sVoECcG%SwB3^c|q#5(WdI8Eg zmxYg;?;2Kts3aPjDoMXrhEJT?63&$4q8G>P!(lJ!RuWx5HNgp&aPOobkHrUgVggF<(7YP-470D6?>)ss zDUli3`3(oTvbc@#x57as5^anW1w~>nHryu3KgAz766T_SKg}y{SUxk1=CGmYUg;Ob z*J9)i)_%n6nlj|8pm^hNPJIa{&4Vxb32Sqkn?@^Q?)U!CXMYBL;}AQTi+%GWD#nJ9 z^K<$@TJ!p7WtMx+NiwJ+_yBEl)3JP?&4khO%2k?_9(EBvX)B^tPG)o_~eZy$OQq+5vTG(!2;xmSHFiUmL|MPu4QCbeZV7aRNfdlQH=_Zw>jXL2`fG)9K zb96b{Nr}(%cV6kILHIIN>6LtS`uL()=h}p4YI+t{KVBNW94;PYV?5j1lb-*UG&dUl z{a2ePLlfF@&2Mddn|(k^&f^R`F0E{ukCL--mfKGTBmF-mgN9uU6P-qqZ~wGq99+k~ z1XO(~);`B1ru-r6K>?ChdUIRtm{lRI$=+@-fkn6csFg-$?|8_h0I)T!_1g~Ewl-8D zbFlh&7^uqX)%0qo^=htr`ow*sYW6=?1-*#L@q7=Ks5G4#^m5oapn4vEt7Oz~m+a}~ z+KPzm7#Ml^7l;EWa)9PBqtsC4X-J9_O&)!V~I~{v zTvD%+^;B}NfJL?l{pu{z;eWEP)=81WNuWR#Pvup~_-XD%%g3z zi|Fz`_%N3swxmxa(nJkVY>A?04F*x6V?RE~dUmfHjNmfZPjDp6;_zc(wbOv3NWoFp{c z&rT9{pWB{qV6wSuxGAJP_hwF2{t@hKJD>A{oe=BXNYD&Gz+JIIdeTQ{n2Pt9AYA(P z8zGDsC<5h4lREm%|%lmwa7J$Fq>=mL6?*G zN}7(V_-G|j>B)I;n?H^Jvk!^0I=w)dS3!3^=yX)Fm5WJsrlwq*h-SxMvSTgOIZD$R z5>x&?j^F)YXcMn%yg{7)RfSovbIZP~nT zHxzXy&9p*{XzBhmjjFSQubC~tFnujq{?#Ol?tGT?PpF;CRN$(?FW%ir1?j=ghgkaw zxWs-P&(U1Jb7JrdBx@4UlmFf#(x!amF69-GL__d)MnM61>gJmL3FBXavECjX zrB-6%!r#1vgML{p->Iv__VJbSX-?z6C0=OLxj{C+cOIO2LlUYXi|Qe&@Wj?~>VcEp zx^>HZn<`7Q3;%Kjm>Hz1Pt*6;uKf?+a`~@!V-AEh_OxUdwKA0goFO+By#k)lKX{f6yh-{T#DwHV?d)Lco z?CJL`eLm#T}Xep}F;uEu<^*y9{ygU?7yFql$M z!p&iMJIY)n#cg~sseFm-`Xf3#mt>Gx$tH65;NU0Qp}6}%l%(f{3coiK650gHCM+_> zS#q8DsZ}Bd1VKMVlfs>pWLd%otCZ;^^73{JqCY}l;_gSLi_u@+U7n2;Iy04fp;e`@ zoMB~AA@Dh{JV)73uHu%vdgBGJT83ai$c;=vR=@8TsjZnG9WG}d<-8@c7ImeM0Ed=W zzVR0YV5qTLg%WmpVxfBin`M!)wv93t>vB0z4L-&p9V5Lc$IExyE)NyC_xhL{Rz7xX zI6q9fRwBya4Q8t)+?$n%ii>(Q+xqhf)sifIGSVSfKX>1e|4(GonYx~R&!*_v$CCSL zSPNp>;1+A)@yVgX*p{8dY<9O^x3e$!wHI?Y-q>4?4Wngwu6F908lN^?Je2y$K4-C< z@7b$Y)>-t0SXLB!gtAO{!i3JKasZwjtmuM2qJFm<(C2;LOnO%kQ?u8=$n^tkkcs5m zi;#TxeYoz9iLWlUsr}O`+h}Ac<|cWRPrKPmwNX~tB-B9!%^-gWYxsm!y!zV1m1->e z_^BB{=8@x>*GsCiMe?n$ZlGZi9uXyiw+#J@he?;)*R+xo@D6FoxmPvo z(_&>xdPtRo8M(N6KjDg%KHaY>saJ&`Xxmr9c8?DC1s->PqO*`=9f`2{y6;;4{wgee z&p2NJ2p(PQ6%T@Wx*ld`p%9FnvCFo56!6um_OjGqbjt&r*r|_HKR@8M$RJR=+*9VPhmq06;DD>7)E=bGLe8J*OfW_y-z%e>Khk?s&G0i=i4?bf`+RzxpkYURvlyFFt4 z@gnlDu-Avvd=SvRT<9|6`f;Ty-3=QQAL5!H4($H4J$%UHwsWq{w;}1^AU`!$heM!> zz`}-6E7`IRS4EEA6fLIBC|-U9GCFR*(Lzcc^mzR=c%e*-R*oDSNhAjwy~XfU0+>SzB|8rP4muG1=i-kfb#+ zVUUN@bMv-PCqLw=(8>s~cDkk*s?w_fA9Rz=~teaO1rwY^q2=zUh`5NR;{g(2n(DJ<1B3+dlfj>ZgJsGsL;`nW$qCTgPWckGRfkmOmlHW9Pg#cC~2E(n)wH``u?hHx_3T|Gy9qF3)^Q(?#aD-5k!p*=@a7J;w%&Mmg4j0UtC`L685x;I>)H# zY|$k|Oml{_1fG6F^ltSyWf2kg-#4opW|gU=NpgRudlqlpT_lzq@nHJ<1ikW-tjy{Q zK-8f_K(T`G$y&5fx>NwwP1DkE6|ID{O-ObBHa(;E*^+aQ+q>U8O5^BeFX zV8rjRS=G`^gL%%X%RVN_PDd}-Cez*8rLwK+^Bd}Gqa%Y+Tic90Pc4&`(>PzeUC3oO z0N!~Y)0I-;+-J~Defcuecm<3pCplPlG+1!DSv zS+>2YXL>ve$meG!eE~&Pk5blSV00fDUz&8b=*Ch^;V=C_$(PnHXU2RaOI+0Gkn!Bs z?Lyrja}v*O@P<8d*ZslS^T}Hnmvk`s67eL=UDDaQ$D5_NEYj09>x*2hY0;DMK2KxX zf@IT}hHL7Qnn-0<1ED(`EEF!Gi#lQ z@%1oGQ1(S5rEtNn*AWw&WPXd=S~o;EzlpTqcFEx?^nE<-(DmqczN0A@?(%Gw=sf5b zsy_i9RM5}}AEl}Y=XKtRN13B!J%?ExW^836S9X8-e;InOG}oN8ffO zd-@LEyl+aKPS^Xxt7WLO%-0?-Xh^^KlHmg$iMtu26{v!X#}7r-g-{EdazBi9&t5%f zc7)ItEJvH971+44H~wreWD(CvH&dTISJcIoa?ijWyXMfRa(lgUtVoFC6o3rqj%O|V z)juf<{i;vuTCz(NbbVd5CZ%H+X`XIptQ!81tUR{7Vj2vyOCz}a0h~W!Rg(tI#yN`* zWuxpS&Qeee^QZX|%{{Fy>E*-;{^#}clWrRyX9}uHo#TJx{fPY=_N`}f*BKnUb)I=v z2t+BCOb@QNP<8!j`%lqE{m9P0Bb%2g?f!*}sQ#nGv_1Jiv(9HNUgXiT@QKfWoEulJ+ zQg@i5F8SO3cU@flX$@klT$6Go{>;-wZ`oqO4N4}4t(_8MWiI~mP9dBjyR=x|;S?!N zQ2m8NVh!h5iUJn*p61?(>FGWHf_b0T_eC7X@_lFgCu_-z13$zq$$1l~R)vw*&0fzl z#(?kf8Wi{^K-s`ra}lD;k(MG%Y72d(5O%sl+Kh^do~Kv~u^2t~pBN}LB?ziT0YM_7 zR7J96ySlR`l_dp7%)5I?MXC=g#MZ{Z(6NS1g_8+OOH5icj_@Xg8A#9e-uM1T1NeSu+nsKELf*H|(p1 z{~&iUFFh}lWk}34QatbJZ1P%7u0!e+AMhTba}uJQ4>#`uzfEbX0>=vT7i`Ef75g zrqP#tg`xcb2K_$cvi0GsuR{yuAC!z`P2K;}aN)EN^Wg(kss~>Y+e>=^wKD6?i3yE{ zY*lQ=nf{b2FQFdsYL%ukwfo7Y#-}lJe zI-eBBHPj^d`h4kKfSCl+i4jn^v>uyed9$MNR!nHw=T$Rbb(1nx0^)pW+2NT-l%FO* zIWiXAUS2?*p?C=aN8=&3{HNpa{dINlEBxzBPsPwT9kx`n}H?-~QJ3ltj*i#c{mcepuUD0@K;Lx>U zgg$1TG=-JDSGKtS7~1qQ(+Jv8l~b9HZM%0jX;ywQx<-LztkoC8SFh`LOT#Oo1gO6t zmVPe&;4pvGzDc9%aWSGgqwadKZZG#p%DEXayn_cWQFOtedt3Mx_=dF=_Xgz1w_~YL$8R?d4!RqtjRWc(U_#Y#vALW~!+Ye?dxE zFA*=p8z9^}#Qwova9_%z*)e3CEzdrUf9$8|Nw&T3(Q&p2uk%VKRDNhm#KDU5s?(#Y z%f>96V6ca{+P#r-Q;`QYoMnRY2kRoJmhUgcGhHfp`~Ht`PP$IP#pKrhm9WUrhMTsQ zMtk-fziO!>35Bcc+!G8D0ly{&d}~Uj1TkBV6dYqR{G{gJIOa>1s5l2&_4 z)Pr~F$;JTVnzDpFt6UWd4p=CN`GsvtwRma&N&pbLnaKIaP7+k_BvVAaJo?hC=VQUn zh=|F092M_Kz*KMV`G;S&iu3TnF8bC^)XB(8hdj^!4Pt@-=vt&J>2R0wC>}I?-;AN4)Nm)i`y>AG}#N?raj@2DqyC(}j zR=WdM+tY*AX=vZad@AjpS%)yY7OviS?@Y5BO+%^rHoV01QPh4kEhnBXh zaznE9opJp2_1o+tveeNtpIwAbtCn|!)(n;!3~8JG6i3`f$(FTpcO*r;T9`GuLxw=^toOCfh5-x1H-*fyC-^*Yg08_rB{ubz=E!D zpAM+NwRLsMvA1KO>9)zA=iD~-%QBg@Z31FA!%!r?^CzV%JojG2IU!Y71rZgxf__}z zo>f%v)%5Y&wOKhP?y(>K$t9~9i9ezX_r1Lj7@)7KUxvN3^nNCRPMT=Z-mWPjiwfG& zKhPf$t+wW_QPu?KsiZ2`Q}HsbiTO^s$d*ihk7s;z9nu}QG&~BMVy3y98)r~%6(~?v zvyhptqmnGO&c__{c!p+>=ECZz`Ld~)Il1sqt#^Y@^N_ssbF*2150SNb7P67&n)3}R zF(v<|0B8&Uc0zR7k)XdFYRSSQR#Da9&z#dSWFW8 z!?TJW+?EuRaxMAhy2+%f=zT-qDhM zGWTPv`ZSwMV;_|^i7`C&HJpcZntKwYS|@z;CUvl!?rcq-Kb5kl)v!cyN#+4qV(oEv zj!%WsU6PC2T*7OTO=ZtYQF>|5g*>Yr=XXZNca7i-AEsc zgi6UOUsW@af@>hf$g0JYlz=Kadf%_!w<$fCn4W)IXYbGV5$!Gr6Is8>0<`f6LdBgEvz5i!~B4hk1Ac)V`o8hKJ0?hgUJb){2 zC~ck6=QeP316#{UA9|N4e`T54*53lY@_HTLfux_p5aR!WO?(-PjxnrV;dk~pfj@+< zoFWeJ7yk~myU@X#6!hpXwL=LiaX3LPwEcv5p12+f+{duoaGY<5#vpE9 zt@U_l?2Y-vmR#306;=}n66u^{08e_yK&I|ex<&d(c6R@YcfLzZ^@?6;4pa`@-9Lq# zX(&Hxh50iYC>ZA9@z_Mf^T*I!p32)gNlDx9H3niUJ87A}u8Y^~^!lYw;Zqh;Q}A3V zc)9C+-(fi&7hKZ3Kptn0W}(M`7p34@ccgSPPWn<|urtO8-V+DE^XgHp(8Xhu%L*~_ z6}oUs%RVK@o9bnvN-Sx=v7-6OZQqE{nhF~b>-LQ9A}QZ}pyqM>B6B}HCkI;LHO{z_ zlpOSwi;U;knP?Rg8;30@RC_v{sv#4`I+6p=x@)%QImr_7SYk=p0={dlt6=IF;;mn* ztk>^yziZwiS$QLG<(*pFX>~cYUhTX#zv*7on=1Xbnd6p~eF1MQ`DtZgyHtn{$8<9r z?X;8?@>WMoLiz4EN018B2U+nnNeMwYgX+*6EY5Hn^aCy2x2N_$p4)zDA9!PM^QRD6 zyPP7+)UffnB3C!K*)@l{u-bfHNHpMZk*y$nW98ZaQW17FKF7~1ou)F>${~^~EAe}r zw=l|;Eu}|_P?!3{(3Kf}0Ox2O$rwJnA%y7*lUD9P9*KuaaF<^n{Qr{0{uO^i1i+D%JC+cm+(_in}?MIx#_ap;iK)Y8cNa_C0nU z?9NpUrt=BLW0?h2!m*@{U3M)`kHoT*nUGij8KpxW;Il7_-o@#xIPigz?a^kdE%hA%ku>_OKv?#+2(tV!AfE0A3Ht0-EB zi6T$+MoaOgWcWKZR$Xzxm6++Js|}MO)w1n{@@PEN!c~Ko>`Z$tnDu=9e{_DZ_ZvxN z^ph}w%L6S&yx+T4O3&pMDr}@w?%^9OYOp%A=N9^v>jb&wYSetyU3CD$3GS&o7 z+4dVOXB~GB2?)gln0Zi7Gw>y>@TSvqON66FL?*rW&+2YRG~HE))8wrU8+eY$V5eaK zulKP-vEM%$>y)}MB8QiA{@mOpI_+i*9Nb&AggI7CRQRe`lS6Yn_BOhC)dteCrm)94vIW$Y?2q;1eE~>kq;yVrBLn`akg?8DI*f98DXUzs-+WJjBZwrhj&Vj@;(|q_ZwuJrT@ddRjhm4?%UY{(>5*l{3unJ4lAvaI^_&l* zCQ4Yc&u?q&-KPi-J6=rfxk6X&yLx81b>FXS3MPl$>OvLY1X;6qdChbTVa!#&KP;Rs zej9#Ro0X^ARG(WB%Q`W(YalKmNO#aYRdJ<(NQPOuPKiuZd@(G$7H-!c*QC|sSsqVS zz4jisK|XcK=_Nuj|8K<_N_2CphI#!}^Nq;|ubHaL&gYI=mdNBlwZynad6jjy@ne%|KG zLS$9h%q+D(TA)^~U(D6>nJWN%)7tCWL^mJo>tDrm_GoC3L5Qh=Fj9j@y z)-Bjdghj}g#U{=Fo(!!!6IFR=BZ^{y?CzW}Or`-l2W#FLeLG0AA7o~JnjA24a=Mz* z(g+ziNwi;#W#*-U|x6B_?4TO;OaBYj0ac_rk(;&TzT)PA7x+cx(ysS=O{aD1MB z7U-L*{_q9;QQ<=7+!!T8ns%HHO+|oSIRb^R;j4{4fBn)xQ7v(mmZ}$dHZ{pi??dfH z&(2K#MwrRrs~^nn-FUn@If!2%v}9M3`jl_$HJ5$gM1p2rfqmO)*UJW9OV@At*1nFM zMW?n?SS5UeHt9BQZS1f1JsvGd#H@vT(bU$frOHHlYN@Z#NR%a68;Ixc$TwYWZf&!Y znGn@JEaiq+O4OVq7e-98Kbb!ZgU8KGsW6%>5=VtsarM=yy14LAcB93!rg;`WtmK z&ter4vlJv1Hvl#SHe$s@w)h;h5QTfd~1bboneV3YrJFV^H;w4o7S*M8_Z`S0NU-=cu%95A$WRYx*^M1EvGc$W7%pU|5TYwKDdO!&6T-DS zC~K}0t}As^J!EDK)9DZR=b5C`Ijz3fZC*;p@x3Tpv|<6PoQr*+L-s zYp+z@6#F_^Ov`cAxb8Q2S#x_ot&KP=ya??d=xfQXy4{hIB+GO2D}h(uY(}sucap@x zTV|8ts<@rXP$z5^AGBhk=>bthM)1_frVe|+!`1F=o7? zc%E?}qkQ9p`ulgwCY>2jYQ|Y@yt(;?_f5L=Xggz#7i8Q@UMg;BHBhq0DYu|j7KEjo z1~=m$-?-;m45`Qcf#$%KQ;1F__1&hFl6wL1hGB?KRY?5o_j?Q|KWH_z#H-%t z;OrMeEZIJ&`*S+Ccl?fP{%1HxudwVQTW6W^Tagv5v!lRrId)%vgRTXwm(OGMw>b5Q z_igKSVl~noee;l!zE*DT1af7wWd4f|)6Iz`+fwB9P^)hnJG{%O@IwdrK?=YN)>6I* zkd+?MZZj=qFW>QGOcXC4|Iya7)|O5WlVP7^4^~AbQN)j_T`+P8jQE}Nl8@lpR!K+$ zke9Luyjz@?qED?PqF;#A zKGZcv!`13|=#1k%kPiyf0}!8kWR$(ujHL<%k`>HT56c)*y0vn0T64cD_p>0lH1cmt zj^`}ZhrJK)enCN>e=hweab7j7}zjB+>@#G6FkNuSmm7E=UtRnSDv zgmZEP)(HvqHlpBt2hF`+4;{}oV7YhReT?$u;2@oKBqe=B)=lW(4Q|;%;H3?hkfz67 z5D2)ha5n?=;t{g~q^j=KaR-1_lE;S1OiI8K1mm-&?HzCxdVBCjz>07zA$oec|I2Y3 z2WGJwo~C(I|H(y>YY&VQB7!PAHt92JwX5cv9G=DBgE}2#wqhF@Gt7Sow%F-iM{&oU zDqWfe84RY$!*wSd8YlWI*USvdw#Cf6#D`2^RL^JIGf-w;i-|-*~0N zB(DHBe~FNF(Cd03hee^Qt#EZr3>1=W*>7nzPBSpO$RoFNFD-T6jed>stMU7y`cq?e zSYDP*1wO*B0Pg+Q-)Ir%Ut1V6F~Ty5toq}yX2KZuY?Et+Fhigja`w?@=gAhu9;=qR zyT6u9Nbvr5l{q%Gfu?lmjep>^KlN3%cWu8AmZgD=_EWy|+xFF~mIF-lSb%6^MHNp8NvU~|zM4b8C;RA3z#_WmutVw~ zhF-UVN#526+ZQ<5eV9uN&J4_6s){l*ysc@ zv`8@Mw7x2T|E0EMeS+SQco%)O&FD- zMV&Hf1kihYxquBkwqzGz=F#G5xxp~ zYACp|7;04x#}7EZn-G7g^1kEtLl4z*AE9#uwMieKr9|J2M_nb{GY*#1l1{l|>8Ph; zpWIKvP1YiMyaRCtk0U#XZ%*&j;aGg5-jo%WXy)uw{;AU?acG(hM`h$iQaSwa0`@|9 z_WF5O-c863R_QZj70V~RKNU!-PC0KQee6-mJ7P~TxPeYuA`P|sJ5ET>Hj(Lr9qB0} zNx0lQqE~1}P=v4u#QS*p?8c{Bhj8tk+4jcS`dcFo%F~gN*jk|uav*8bz$<(a+KO=& zvqIb6p<0OKw=b zHot|zLgtaup`1}IvBD#MVys{J+kqv>-@b;|c;_rHgQ&aDO<1riNJ*?3y9;Mk1dEYA$aaFSNW5E| z^M$r02+z7F)b)4ef`T83=%4>mDa!RqHC-6fVxwA*FJo)p%5+Qpb*}+W1y>JCd8AWb!uS*h!Dh$GUTR-d<`m6~JR2eYA%8NYrucUIwg(5CvbLUI*)Ok0elFr*az z@HPc03pNl72y$A5toe0HHD>*e&klDe3!muOx{^$O+Med}W0dXhjp%x(Ew^x3vxY1t zQPX0|6662U-cl2=KS$oA$id<#8jlmEJ3uHmOtzWwL7tdb)VVvDhl6&Y1qK7Ea!tNt zwh;9an!|O!mj{g@uAxjPaMqiUQVYFiet4vwTl32X!3-WU)Q8$_3qi)u5O{#+X@=4b zPdL8ny)!^0DXenBb7m?~kSfq7HK96CH&19w_N_rSgF>i9)g2<3?b1jbmle7LV9G_O z@Ex}Y>GqA}@)IE;?(Yv5$SsD%(Ad?_)8a9dGZQ<{l&uV7B8}r_Eewv`=BW)g*EToZ zIVwy%)&j5}-g*1)**lK0AeeD5jEFP5iA5rDetD=w2F%!TV_!Gd}Hao{QxQke0F zq?j>g4`lrb@}$?LE)Y9B3&}mZ{zDdUKb@Je#RqY(c><0JFnF{KrX(jxl$W@zvchK- zD1PdIMUxl)xm7BZM@@|Q-(6f427ARBfTVq!Lf#Mn`(PGul}f*K!jl&;@EP_49n5fdJV7dA0!6?YT&78kkJp1bt{}=xUT=-$R z7p+o8GY{-q`k?rwa83qN;d=cyA{^-b6TDdHt`UiK|;tYA=RXwQmBdfgnbYC&;2tml(Db-vb|;o50k8N zUtEAmK1>7v46!E4iCnd)*8ON30?!8#fu)^!f$8b@VM$zzsn`evpVEr_O{nnM{K`uj zm}F=YQYb$cS03UU@mNPT@|k-fZ2$iO*=f+@%7!fS_FMrIL}4e=^5Ebx+j-C&Q{H%z zP#;`B$j?afF{^L8lh6#Ma7@fU=Si93%rf@cf019{Mr)R~_(iUHD5ij=!bY%=+P;wz z!;;#H%_~-Y`8Mno#i#I%lw~c@n|RbaFUrwqhbRtJJ-CAKn7%-dZ@smqa-_3rPn})f zdp`H65K%4zxt$5NfCdO1P@-&$aXY>h0S4-jOBD5Y?HA##x@_ERh+h0ON_;~Qd|!V| zhKTUSjtH)zTjQA&IX|x4e)GjElw*vh920(C;j%(7!FMgh-O;ZSZcGnkJ=<3=IG`R6 zQ9sThR6aT=se_BsDc{xFGUJ>N9Y;kSc-8vYH2_)e!xh>`G+ia-++D4rivdn(q(B+# z9l6=Mk4b$OuP1UUl)Nd*B0dTn(+XoHAH;i#q-q$;vZ=gIw?BMvXN~IUY^uVR3S);u z!P-lxaCu;XFxxD}EiJ^tOHZ)T$27fZ-Ll(ZD3g7mGq}1mQzU25Ei1!@F~hZ&P=+6` z?wP(vPkAI+vCKZZzIfwYDSM8bj;knDZn%w}N<@|3-td~vZeLkQ=) zmRUZ?HkhGarw{nwr4OUvGV(szx>}L?k#gG03PXRuX9DhC_sEK+_L6h`j$B_opc$xa zT#1M7##QO@wc*oHZ%ev0C{S#HoWUAF?VD!>UTu`Nn7FPJHd6TG_H_B(DxjfX-!iHl z>*1j%9RqZ!akkqh6~-xS>JPFR>EDM|4-`+co0+ZW1Cqo|@=u1oJONh_WXw`(iLydo z+JQdA8Z(HmD4}S21{U(!{+&B=yhmGF_)FJ9jy{Pej<8rlll zyX{b@7=!`#z5Ho~Oue7solmB`2}dbt)+eoUT2r#P*&{^qB@}DtkdSDMfmz(c|w#$mf(ii}Pwh+%2`Mx1WxCiSj*&B>t0Epu-Rqt!p>m{&#kwQ88;M%{Dw*N@E z>xC`Su3iqmw`inbHB>%Iov1Tp{Lr?*H1(LL@`-1-e)n7K!h)1-qPUHf%tbgX7!K~x zlxAhnEh)$+czw5CH4glb9{UewU*C=ciNM`LyXRoY3FDXN>i6FuGP6+nHhN|6=2|^; z4f`kz(V88fW2VmjFhkF*^=w;~%dq9yeNi+Mn*F@*ItR2?lr;WS9z_B{DsrtvHdDyG zbT6PJ4-U()PMaNDQI*Lmj6diHeaTRZMDekhE;HK!pEBObNYQ3ab$lF7-Y>^vXd32t zWRL*I1C_}@CZe!FUTXuDSr!`tFav_Rwh&dIo#^3;!waN@zsYWMgw|;mwQJ6~M1)ID zKvM0Ryj~THs~yyixvW-=A!LE*r!pXL`-#=L#9|ar7Ef4#6}M0vBU%#8&G8ZTrD zOkA3|iR{F|-os`GSr?yb^G5G+c-;+#J|P*(<#&JN!d+|e(lp%?uRbBibn|N9RdRF< zUwA}7+~pov63XBU;J8p_?Ue8w3RtpxE37d{Jd$X7Z0WLac34-Ku0_^y{X5}9tm zAhb=UA{g|5e67V?cwjvbLeCep*LSqFGj$c&mO%E1F?IwqXCE8KSx%U6^8B^8y`0GW z(K%%0l@w+?MN1){ysBGHD(4z&-Kpo&wdNQ+XmxdXh?;dnv6D%Z$MD0rgwWPWHO_Bq z;~seXhglmG1i;$pOj9+Jg-rhZK*WER=x(hr74D&N9FKbTQ6+aiAC#ahhjh{pSy> z2X?05AmqIiSX&EM+U_6Xu@6XVJ7 zBGokr!nRIgE5!B41y`f_p27T*s_P|JLG9Nx+xUObJjtK^18D;i{2QPP(m@yo`*T8B z>}@Djypd&13iv?pcV-wv0X~k2RdH9>C)Xg?J@yiM@pfNGocErAd#(ypi43iKXK3l+DClF)5Awhgf` zxJz6|Mk;(Upv#rq{0Lx|N#AVWJ#1HCqJH9YrAhlhW{R;lJ<{$OcoSqgZdLfn`K4s5XeV3`)S!1m6P{|}$o6Fq$ zeBqaAQgj-lsX8?~)cRqb*==sWzYbth`RE-{bku2l`iO60WrpkzNR;i9W`9iXdmGh1vPx#Ulh$E`)!t3l$Mv>$wc7GIV4%EYSF6);XnT#TQ^@r` zQMyR-Q+1!`Pw)~7yl2#1tU;I-#oSG z$aw%CO z`Q&u<*de#siAvjXQ$xLTG?rOPs}PXpK@8I4hLi)p444d&ef}tK?WqC`c$NGxq86gC z49mrhP~bUTG%O1KG+=lvBgTKIdwRVeB6_biVATKz6G&f_+w^~jI(4D&cR(eE*@we2 zVx8rz@(sUZ&k@iuy|#RjDmb;34ZSmklV8v$wZtrxo@j4T;KOEI@2#ByZR49oAqBHv zi0XI7&L4u5r|jloHYv&x6D$g19YoQ1*zPh3e`nQUs<71Ngush(xMv5uH?;Xw$R5Xg zy*2ZM0+t9dpPdQkx3Nta=UhMw90eejTTq-aJHn~gEU9x?x&KP-oNobYr@i*&q$Hu) zTW@?mrt9vO34YNc@bX|hElqWcy*c6RFDX=H>kv3&o741&X80x{%@}5xzVFy`xL|OF zWu^!v&+bqU9$rlFZ}j#IXxE9;h2a|6q9C|38%;!FgC|IMNQZuf`Inq6wd*)6JGM~|76}b`) zvNK9tvWe*QDMo&f%;K$2$31l?8@4j5M5O&E1IOas4XoCmvgx@<4ZKeu{**Fvxse7c zYE_uSXnXNlGc*p=B)UO%yFoH^*(B7e2+}XcFk__Wm6eV^L zA*pGJuh=a;48QF#st{!}Yp1s~i*EFfe?X4;Qqm>BgmG&r$I2LB7wM-pr?)npD5$da z6%)`=9vj<8wBl)cUs6UzzmIBBC+jSvz466j3K`?8TzQp>R^);6y-3Pmgj?6-r~{;8^d{pdKVAz9=*kc`$e7c&ki4aw_q2VRqH)=Z`a{+#0Kej{ z6hw`#)Dek*7S$??T?BpJP@+g}NDdEfvU`Fi;|1+e(xdqj^%bTepKi$~i#{;iTXjilwR7J6;I1&K*GmhYsb zlMqNE2;c=5Yn*7dRQ7bcS0rhyeJ2wcuJhG-1@iQ?2`aZxZ*zX?Z5lEB&pfr0J-!S| z9YK+@s_kFdg?i8DReyXTvKMA6=JG#}VNwgi{72L@?Mc`F3bT~)>iADgkJ)d-r;98l z9?QU8%Id<0pJQHI=Wi{aO|st92?)2TfCq`>R%k(9f^9w9oWLi?cwrHD_q@YGR|)95 zerelpSF?&G*Rd1dgb-!_#?X&aLq}5i$d5X*`Xznbw2N~`Nv-8g@=}B#b(*t1+;As6 zscxOVlM5H*G0!f8LO+^8=0#u2*8Stn@J{l+b%|$|$h`c>BzYe&#>wwvR)G6w968*h z+~pBT5H^`h^3_MAflQ>Z9a`+8r93o%*JbLU1EZD(R+zMZG~B8<#B{VG%n|7R4yx{Q!y z#PCnALF+1fkbzuR1C*UWlpktlvk`xN!MHPMyCKOrI1TEP zFzPxG0vV$J3w9kp(V{w{YXUq#34NGI2h?>6gJnAakC;lHDcYH}8%=55d>LJ3yR4{# z$dncMs)*dC_Q6d-y$%F6~yaW1`61OdC_QkY14iyTM=w`uY-;A-^!aGq*; zJWBl!+L~=!=vt&5@k*W~ zts0wST)_W)2B$219^aNs7Pgx`>i%?;7a8n;!PTQXKJln!O<@{tqJ`f+I|aN`qvZ8=&+E z>OIy(RkmK;zQ5?}-!-($OQFJFH8kEU7h8(>R@TtorxU;rQ!{a>PzR;Q_znGcAQ{t0 zu#5d88B?{}Bp#!2?z!zt`^Mcd#abM$?pdl@04D0p5JN|8;8}$VXr@~&ItXn|iUL#F z5l45vj@?@+1n3Y{ChdkF6h&*RCn*C&b(*dLfrpokF7Adq5orR#lKEZ=Q^txVDXcgd z=;CuaWE&ti8<7cGh-eLIC39;%S{t{7v`y^(=-H8@5a-Eob`&lu05Mk0j-tVhy2{wC zF`oQ4?*>~sYPn8g!v<@g2%nre&p5m5tWL<2N38D*xH{k3ii&u_@0Af^;VQR_d)8t+ zO4P4&_HT8a=MCL=f-k}k>7_aGHL54V14HdB?saMvPAesSMB3VlJ`A&EEzBJ+w`WS2 z%Wqv`C7vLgm@c|v%k~<~FM}!!C|4@zN=3!-w{3CPDFo-I9+~Yw?D5Ki#<7e_O{=A* z=JAiD?$^-)g|{^QTj7mN=bwjpw>bUQcwG?A4lDvV4>2E<0m9_`rze>c86qlqz8|$m zUFFRTgbbzFP(DA^xo)b-`PiK(+NaC|=c=RIH2=VfIF`3^E^5*qloO^tK=S8Fc{Mt6 zUn%S}Okr=M+xhVnYam%&V?Z@~F_eP(1NqNp>5N(8H&(RXCL5KkTiJqVqEmR8lJUBN zt#GCv{*J)mEf^^K<8_v{3VQMpK07Z$fXaDJ2LuTSM*i08D9%Cm270Cj0=LG?XpW;W zP=`RME5TZ!Obo5yuphg@`)t^++v>~%7=&SzwWsn|Sws0fo!J$8CTHiIWclY=#eZnN zd_I11G!@)USZBlehQ>R;k2bV-T&oM=%6&`XUfxh$C~f{}i{-k2p5)Jl+wM&5cq*mk z4Xx*bJ&>oiJy8fh73x$%oPDLczDteWyxu3 z!>xh6JwSp;uAtl%76a~^g6mP+Ov-q0pae_VZ0M2Cvnu|?5fN7Z#JMfzi%q|RgBD`g zzNYTw-1tsA{mXi@Mx{mFe#4giQenZ&s1fDbC6`e| zTOS)fM|t_Q;Un&yE!7F;10~1vZ)fAn90f|OCh1ZwpBQOsyRM!dv@m4kjyyls8D_^U zk7~RJIB-2SAROH>Q_Aa2!IV`Pe}-#XMBOwE&Jl8p|GB7a;?5yVGRFI#|7d>Ne|YAo z$V9lkwx00M{CBqPr}*q)YuhE?J%?*APhiSL%)<%>Gt}RYxN=EmLPIWhZ;krsGyrNfPc;$3YV;LD* zu^WGL?zmW#i!^9`z4M#3EmJsBejTIT(f#}oe-KY7CLmkabSYot}?$P5}NPF}~7Rp`*E zn%yZU6?Fb=cN7J?nQWatEreWRmH z7})-xFRN7I>6o!>fv@{>P$}G7Ba2=@RUJgRmBP*Q6STMmt2q`9w+(|*wdKmtm2*>J%b0=Tq;d{;cHSoc&Oa0F!kHDA4 z_!a&;zH^hit^9u|>gX=$7We-UbrgF~&5^gCPef7)WMqKzFub%M#6dm-_9T~fN0FtX zwBYeo-C#q`(Zs%(L#gfpJ$|yaj3L}NaBv2tjt|{cQvD-|nnmUUEGmh8;svzh>-_QC z&!(LII+5wmrrhS6rn<=2Szl&ERvn#y-Ih0k@T)LK4lB%+F)z~nQJ4ej(Sw)@-ggrq zNH^PWE4J_t)l$Lfz5_xH1?kH=-p9Fz7t@8n#;>(&NI$fqG~x$cx-wf`qPBYy`u7O} z;!E`|BOwm^9z$jr^Cf~E58ZwA1zReddlbniXeL_ecGwFZD^fecNNz8FW!~7sVSA@W-!g6LTBn8R0N#|P_>yKgq*c( z3WSd&^JZ*-Nj=%cD$bFlmw6&1!N-@@^tz_$x))u)=K>xde~Ds?c}oHol3W@wM#Y8D zV%`QmnK+dH*rGev$4;<)glm3Z%-#L2kco9*#f#z;7cbqax|iaKVOtSfJCG~FF=6wG zspEW*wN5&ucDz^^-;pcGIXIOmP+iLK8u2()9Y4H7?&Qu-U5wZJ0P#F(i@z)}N3V(au#^c_kt6Ph z6BlG)Ui`m0cSQb50(ez-Rs*?{rY|1T(93g-$ES>QQEXmEUMe zyZSsC1GpiINa?7x5H?i>?p&X_AE^~1IJydKEoIMnG6cgk+2(y;abm{^WS^?pX3Meq zl|eJb`=gVm#GQp8am`9*`_gA7KliN$4qcAw%YE^(lccaPOSe+rDjZ5Z%U+-BhN?vB zjpj$+$wuzkh6TDLs=7|A`gU7YYg_J*aXPzcYn*I=oWhlOeL+T|=0f$P#Mr`vfaf_I zt3sxMt5G0RNcuZ*x?OV>cs+Pc2E<#r|Bi~12I7S*v;HJLqn1o?RC3J>75Gvbsa`pU zW}MkL9RZ;@;)Xf9y;#qaKTqVVI2FL(fthbV9wlG0`n^8hC;+|{(_DJ+BSVxK84^Ea z=0K~_7W^KG#~KKn?Yf7cLsnN!S(X9aK9vzgMFPf_Sn9GhH8Ukb=&jEirA&!3rb^A zAa>;A>YcIBV_$kxrZbXX$b%D|S(TEG9nB|CSoe2AjJQ1uz*2JM)4GTAQ>ZSE-r%d; z5BIA_T~3cfUIa^R&yd5r(K=q}^rJ+|#NCQbVSocD+^8S-92Hpwtv2pVX&-m2eXbtr zbdcfJdLRwp8htP0!&d{sg@`rb-7ubMb*{tW@j;VUW!9PIjuw6 z!MdWiJKH}b#5D6hF}(+rQjTTOdW3Dnt2Oth;Htj49fRc)$Y@6xyF~O*JRa>v3t}>eO_UpyzK)9 zYvjq~h%&n~4FHrEJ#_`i=srRVXxJKB<&)e;#!M<9sfz~nIYC;o>Q9kX^*YsDsdIfL zENTT+rbwmVW1-*UNrZCvIZh+w(}lmky!7Gb;o6koZWnL%8o+VxY{%UG#!ilv7Sn3l z(kCxI7xy_+(SFzCaLfF&KGsT2J(8DQ7+%87PrA((-<59bus4xKlb)Lxik;e)pkWZYC0;pmbZ#+d|*knuQ z^r90fIB@?-V3`dOtj!qoUR!Qsyx(M1Hfk@S+`I7(NyKF)WeN&ocIz<9&368Z5f+DX zWvP&=lX}-s_>1WZSeW204B`VDmO%(9!K&-Fj_?Q82v6?GY3ff*FrurRhHF&e zUym)#Zl2(}H(G3hj#eU_GU33?upSO9arwVsptX)M!|i%^cWq!VxG^E7Do%QR$ zhCAd)&QQ=d$Sx=Nc4^M(9{P`7Tyx=x^0rC?)uY20Yjn7w$hDBh)-W&>sG0yD0Noz2 z0A`KR&3m<+nlmhQYjayih;`47YG~)v=COwi|N79c;x7YC!XM?bR3lP2mxeeeoJkUi(J_jHmWoTO3Qes~xkRd4@SU zjg4}_&Af;D)Y-zujeHn*&{K-Vlc4?dym%VDc|Dge6e_2q92*}G4>VY<8RZ6i;yqPd z1MtZb-!*3@lDg+T1;-yM=ibU@RxU&yDP+$y5Gr3hebT>R`WE?I-kh7jy?S}zjWlhg zC2K*3XXkMYLbS_EdeRa>7rI!pq+=fKVE!`qZYzS;n47ltI?g@)cq^*%J)ArWN>a!7 z3nCI*g*&U{SSF5vlnk7KJl8zPPuGwU(X0`J4H6hc_e>GgB^W|Jr!{E4b6NL}iS8p@ zOq&Nw1dB?aW|McAzz)Ikq)@K-uTaxFtK};x_u0Y1vk@|^pbe#U;z>h2LD?ot5sV4d zk#5j=XDFd6HX6++5*p8;WYDGORp29FZOlr;Fv&6yF%H7bEsz@Ls%yxMk!@-%)0%J3 zlIwQrIdtB>3Qgc!t>a@6f6vR}@%Qp7P#4In0Xz%cJ6t+#HZO%6)8`hLhc>3;>Uom) zl819z)5G%%7@8u_j-px&0=#c+(UJ9Ydx7r$J9ylL9VfW5=&S2Z_s5;zm**nZvQU#qY8+mg9CD`$gC782VRsSrz)Ki!Bs)Cda zpW&8{fj2F+>oYiy^>3RN>{M##88$(Hb21=hmIHMMQUE7gL%#l1`S&xw*8t+aUhpCO z+yVrE?lYakggsC1Zg#6ct=9rN+!_yOVh56HK3l@_!kOnmI(r;_hbjz4Hb|(NB>RRf z88FY}^J(tzFNaK&_g@^cFMZCpzG8E0Oe`M|d^ABS8hUzm%a&J&oWRSAVq!UQi+%Cd zMs8`bbjoN3dOzYdK8*M}3livmB&7QbY>7Ai>ylls=)nE&oyXe>Fvbkk^DaK-t3%!Cs{qHe?RHI(7JU`p~oHr8%5DM}Ht-3_te3pGINW+6tA zhb5>sBwBOq{T4YB!_rEdL~5$b@0!w=3@DR3T0*H9JX78ODZSe)7?rGr&k z!EP{*>Y?loIk_4^r8SXKOY%2mRZVUfQ+6E6`7OUhc;J_n_TU6&rOmCdiPqM<{I)dh z{Gi6%RCN5qSVgXNnV(f3yJwE9dknE=6sT^n%VT^=_|i-*)C1LM2;}Y z303?3`8&9uZzY_?Lv#fz)cXjYp#RKVWuqi@han$$$tWd|L*|^e>%lOdvi0kHj;T#J zEnA7{H?S3j%84O1z8LbOISv%Ql>1kFhWB6mX+#0C1*9<41#qFV2j9egx@xObLM#6q zwEhQDK3RM0z5a>PPWzLh5S>F!LKYuqrF0FG;OgfM6X z1-&GNd^Ub?M}XF=&pkFdsD`0OENyAwWOHJuyXj6lRa5!#R!qj1)96#$79swjQL)M{ zjn(@Hl|6gwB8O+@QGS;(3==ye{45na|B0(M2f>4y1BVT5q3)vM zi5L%?ATHzN`x;{SVz*iHrqIqd2EfaH>bKF{Xb?I2lf71YSh1fkTsEf-eF&B6vKsdZ zZ#vyFHwuP61~Ur^87K*N#3B`v>tbx|D!0~4$sTR6PE6T7dy)5~jsXE^KU?CdyS8Aw z;|F*5R0@wI_!v(xpKUkU1hi01I4g|9LC&DEKt+8*Gp|2-=T85qv&2PU=t63Wa&o0I z2rMI5kb=YD=?rA9pj4sol(n$<WlAiN zl=uA;S98o0#`fzI2wPOK_}y?tX&WRP`wYo;;lZ&i-f{+SE4p-019^G21bV^Z139fQ|pFv zXPEu-wE4{z*t9turBPE~%}={dD4CKO7NI`qd#CqSSeJX6KmpW?rwb|!^&^>VL<?-LMIiCs$gQ z;+!^h@UlLalt669cX4V-Ex&jf+iJI|FcmLyM!W> zoCe_xH!vdX&H|m2HjR~&lr1ap4E7F4u@8y|N z`IK?_>GD%=843RnPS9H<7v!nU&18Sfd!Er0?j@xsyBpzZ-j*2YxGpD7frGuKi=GZa z;c{<0hJ(X{C7Mi_W+{OxwGk{J)Z?Y&x+n*F?&afI$*1Cg>KcE*c8X_>`WYD{P0X`S z1tyM(Ll`TWkD2nF8m_K`R`v6`6kz$GsxTERBxIYvmP8&L0f=!I>-@0Q29~>8F+x5a z^Y_qiDG1EWftA&QQvUKS>#upj-XU1)kTu4)-ps5*GZAJO2sP>)!WURVtm|;!r70e~ zhzTiFdZZBXYZT!l8YE`}!V3}1Ro$2+X00A6le}X5xm(V7?&gHgT&n>)ecpBa z7C|M_4M!GU1w=-k#zo#p;n~3B6W_AR)^k*xG0|^Ky+dKVKIwV?v`EhDecVUrOEdIQ z>xSIFEFNrD{{#4^At`8wRCswnpGB=2kMXrpDS~A~1PYlo@rT~7T*=lpkZsOF1`}Wm0K-jH|y)gRIN&AZDjKq!S=?A=3#UxVxXNz=}CNLxudI?_<@Y??U><5L+&qD1cWzk%)k;vy2patrmg;;;RC{A{4xJ)=u^fXe&^Nmi~0Q;z4qm84AEqBZJnZ{Xe zQ_GyCu~GK59&WEpWak9$GLrJ@L7w~yrK{zdC7TT$6Zgi+Z^GGnPsf^vdtQZ{sU0_1 zwX$K{HoLnlMpS5ot7_IDEV7a8V7Y#pJiIfzVG-(?m6#L%)X9Zxp6PnvpoR=wLh;{~ zows6O!zMm0geHi=$9lXPDwkB~I+553TM)mGH2V^UZ=K28r_N)(0+skm-o*)*Sg$VK zFWJeoW4qZ`sE!8*7w>qvY(oW;yJ?V!g_nJ7UBHgGT@*gJ_!)Pn+?^xQpT7HZu$<^^ z3NOqR+a@iQ$xe^9{}c)it@w3rmFtOc)#{zM8LhR<`$`b+{bLnA>TY>3sd%XC38z(=vZ(4d0*%SgN+Ek> zEtHk$r`tuGzs-<61h{e#FR&(5r6oSCtPB`+V6RUj?TdOZXV7#H;Ieh!*A(Cns(F79 zPbq>YTanfYEMimriHfO5)u{c^Ud(QV(QBn0{0;H&{@VYmy7P`|YF*cT6a*XMLaGQ@ z5a}pIFf#Dy%~(b0K#N8=J)%a=lR}up&gCwfVq zq04(BS5Gv4icQayMt7`J?(QyPx$DK)`y({1GlSP@>yP7f_B9sFd&x(t(d9jb+!@*rxz}2owUSE57DW zXzo$NorET&Mao1=3S|v_C-_jMTr~9oLy~G^W5k`75%SqibNS|hTduGv%~B)9e86Ws zYQfT%9@sd%=0srq1dnuhKf?8dqs;6m$d7g_fj493y|KOK7dVm|uVaxG*FL@JJWBI( z)q8m`*r3Yoo15iy$r-Dp35|c``7zZ)_~;PZXG8*da`y4FgQpof|8f{f&PNX85xbBU z?HGX^VE1ZnqQmy_hVziwD}M4e1$LrxR9=TeP8v=GM;pYsOZx}r=D)EEO!%Em^lPB( z!!-gXchJ7B(Ck)*?AG33!DqK~_K$&Vzs|>&o}NKC4xS(_F)e`)3Xtd2(9-kb(ZD|0 zF@;#RL35Rp^N*w*=kJ@p2KQ%fbYaYteQZ7~_hl}qc~F7)*LFqCtBkl8 zY@zNJ>px3!F88fXEt`1Cf?hNq0}5V)o)nk9`U}Sx3;xNjU!jiU85qr?J@Z0lBaLt*QkbD*k8v zC&T?q7Rl-<~I%u`mBM?!WBv zrs|A|yWi(wI}z}e6JN@@YT~a|U-jU6o_E0Bs^s+ov+9YY8~D?O)aeok5WZdbbNy=M zo`dk?Q%&4HkzUbfRdsFrty|yIiRQOnw#W}~>o-27H+^P4d{B%R=v>jZ{F;`b#MXi} zcgRuwrNZa?|11ji;I=tF*(?LYdX7H)XeDIT?v^l6cH)KK%nVS>o3&h=ldR17J<0qD zLpw0p4GTVx;iqRPDejxl1d5GXHQqk%jT%^OnV9Q!mc7K=Rf}?QVmfWj9ukwgdF6?( zb%TO+j$x9L#?PV*aN}k#~F8ZQ4zm- zwWK??*t;!Be>OZ8%3a4!JHnxSKC9b;XY4IeE?zLukpkR^+2zl*El1hE+XMX<;{Bdr zm%p>lBC%}0t-*k{F-xvP^u~Y`MHlvGoz7nc(|4_!Ie7kiAqvRy-xnM6%l!vDsdRp# z`LhvAp{7OA@u0YtAYkQbFw5x8jAE`$?eJ>`W!s0Y>oAX4@_|BhkTDP}6&LSlRTzJ} zp&1$CQbj}G5kfQefKz!>y5%j7p5aR5Dl6)GnqNP?rdGsEo_+{f=*ocd@`c5!#fh!f z8+MP~8{z_9Qlnd*F^$M23Zq9$h_Z#~2n(=F4V{fne@Z>_jlk&|#4&zbDTkU8d`eU) z!tO1~ZVeV3XJ)x9r~BKrbgT`N1{8Nc_1Ha~{LQfd>wL_Hus1sU4%iINTbg7OsL6bG zA$EF|ZeNUIos`)-)1d?PzRjq|bYd>qLlNbg(Lm05^JQq%0~A>K8b&pjAUHUBDC#v= zpILvKI@xVh>;O%E1Xq;pgzbzp&G~w^yyDg*U%@VEN?V}D5C$*5Fv}a0kzBjkOSZN3 zH&|b*jrCFeX3yz@;~iT!Y&*iEKZZj?TUKhjm7t|#Gq+7cQ*fmEL#)G&g2_6Trl;G; z>8{Dk7(TZp_U|~U*-xWYT%GIO5p1I4i@9K}iP4c;1J9dQZFTH!qgEz6)&lH3ZJXMX zUzH}07avZ98hS5|5uNTUKQwVlWSst^6vBDn9t5_HaGs}vT`1LgCYn2wF)=79P~fe_ zsTJ0pxXR?*_a-qiic#oE1w^-HiGdhm-BVM+6-!?`e}+6Yim+VkYGt>cY+XJd`}lp) zw>4`^O;x6|+ivy!6s;&p$|;lF*&hbd5sq@$hfF8%@7pClpDVNpf1whzsvNX#B02nw z^z0Kh^`Q4U2((x@P4u#}@*qez&}TVh-nuBGq~aag);F*BC8ZAG5q3eFs>*YW2?Tnn z^ag%1uGWf=QJO0?uxR$e;^NsTA}lvl@$OgoE!>7+eoQ(_S>)9l5J-moIqx=K#EXk( z!*9&kjj;U2nPb<)vw!T~El#{c$9a4old;6{W1!%5?8G}>5b%LA0;ui7nLsoM5Y zTW7(4=_K#RyP0$eRP=*BUqyJk{dUPi#gVpKx3!KbUOy!n*fj8|arsTVgrAQAG0Yb{|G+eS#%9U< z!h^o`>HY7vxr+}imuX7%K*2*gp(HFSpIfYwuRd^M2#(sHZ;8}?s3VOin;$f zUt*?aDahwx^LJ6ih%r{*2|3lzITZIb>Fv|`PQ>`t?a29LH=P^oTH>4c^sXaBjmr9@ zQ>zmkM)x8}^@LjN1x`!xorhM_OH#GCEKd$^&hlxnmP$p!Lf}Fubv$5- zjc@y@9AzFoLDP)6DrsR?Pl~cEVDlO54JzH_rj$C}Q$wb$CSl1_JQOesg@kzen{TPp zyVumwO-FOTaHqFTu9Ve>)oFg}pupNa@T>)=rpD?z3Yi`jP0=E7Bh0N@CdsI|B~_UY{)1QBc;vR?z7t^D<4#-wp?0nrd)G48C(c>ZHdeE5@jJ zmo4ML(}7T3MOdUsid@)cF;NJU-~nAKo+93NHKUUOo&@uGTds~i8_a={ufAQNTwepP zx7WR}_5OH&3*M;!I(%=h;#<*i#l{qMJ#WxOUcn(3d4{4Kl3!HzmAggKXQk0gvZ@< z!-xk97LEyOfzDbp{b$W%ea7qF5iw0Cg_4C_5=6)yq!B7a{|{vzTB|N|hefHL8b8I= zs)ZfUzAY?iu2S18gu7+RzWgLUApyUo7d4dps9a~i-FLOj2qBdDsQfkFskCF3_?gWF zUOLu37n6_>7@BMO8M&u?+rj`YH@M|DkhE!ad-U-`?ZIicNvr@Hi zY&z?t>P5tUZ}7)+=IG<0j>$2hp?E=8e^DXB;ibjN(`g4jL663CoybZtm1XG^9r>yv zZu`~A7~An0+_CQ%-jIBP_90cjbp1xI9s{?iv|?X{xxjiIT}HEc<%Th`bLEDB=Kd8U zg`sDSgE_av7c}CWi>d=!a0y}+s@Tdi?OK?gAGi$qN~+r%eK`b4(Ki>29#pZbMWb%i zWO^bTyj^!c-*@e>A6Pm!^kg$vTb9qwE%jXzQUfzmuvTv=vbLq*b2<;pX7fl=3)ju@ zoni9Kd`<9226OP!0p*A1pEz0aj7#8Ha8s*mhlGP+Q|Nxp3At$D!B7J}@)VrtZkF1@-BzRJc* z{X~BqO=qSS2w6hFJU&j*ANwJZy3NTeWn05 zZzZo>Y#BOxK3qJZkH{$jjkc>FV(A$e%eGd`RsF?G(R*T)I2EM;mzA@yOX=8<4fT2{ z1rKr{GjOY!o@-sN=5W$!wrXLQ_FtNY?*rq)?jxyEArZXHR*X>KjY71yxhs)vplw-U z{vvL<10&UdvR%jgi3l?gY9N z!jo2yRBV?jMNidZYdi-FX}EXEQ^iRQrA^KM_f6$#Xw>D?_Et>U)~J6WezeU_8!N+~FSEP^+*n+*olh^AAeflT8AF z(sBYDCemMbl}@j6!{kt0{SDd`T#XQT`?j8rt+&me3?#ZU% zm-*TJL))$<+xoIj%l^HvAt`jj+j9q?C*&{Qoyd0zUTE0C4hIPI!-5uKC#G|g-To$2 z+V0A+b5FKQ$N)?6+Xl$>uxF64rzY%2ufl?rt{X!ub7I-bq(RThpJtu!|^?w9Rn648L$j$!8zz4ek z<|+d{%?Ze^?GZ5vcBe5?nIPK4S_+*T6L2;|=nx_M&w2YFpI_n}1$MjN<8M((e-zlG z;5c_(r9qDbH8!Kv832EP{@k}6M9HN94{hto`zvn^&zE-2oLj=F_N_lycz*(*wo8?0 zqj$KIZ)uyzHQ=Jl%LVGN0DPHPQ=mI=qCUsBfx=I}C#}?PV$1G_AWGU?pB4I-RM^`G ztQQQNDLQG7eo+w*T}95hAgZThfd>&IFa)u;Bd*=gevCH!VcEiPstGt!?Tq)lAH-jI z>LPC`LlD2YU;SLl7XP1+M(_w}Oa|u-0~Lk>I?bv@toZ?6ajjH%n5ZGSmR1%`VhJlt zPNX&Lm{>G^TIT0RN0ck$qR=`svwiVW7?14}?(z6=J*GY(1{{<`aGfV#Ep;*jx!ts3 zWV3Fvvh1gCWSS$FX!soT_d(}I4xvEJ*t>IMVc+)rw4@M(w1;_hF}-5SK18$F z*q_L(}pD`7%+&Vf^1#Br zIJXzSLfW;htP$@q4JudgrtbJ!&8c-9sIHn#teZ|*e62Xyv`}L#MT~^N2Fxr(X>8lvIi68?WWX-CrPg?)XhWK)M z`j7JI@H2aZu5X6HpNWr#9)|q!aJlsPVj!gVFg+xyNxd_vZse-uRJ4s5WwE4XBXDsq zWl?Ac=efw)a!o{(b?VRSnT6G%UxK*e)^bq`^KVh2 zx&GBvgL2Su7iVCA+(o-YkusJ>lSVN?u7&2PO|+i{^9B8~@8EIO<^t2nW#S@OT?I~Q%%-G^ zu#}Hb3Wa`1KX88(N(8-^1~R_7Kj3smITa0uKS&QERQSt^)zZ=((|Yy8BT$K!MV$w} z2GT!@m{X0LM;$K_qy68iU{j!SJJUU=Vb?d?XM7BTK6enB_V0C%)v1?6R2<*Y2`=|M z{&FB4)~LUAKbEOSPfMC- zQf4m;49F!Iyj{PE9t&*4o)F7yl)SC^i&FvR2;`got2wCEhXBG6od9=!7lJ1S}!{VStA-iTmF zgH$5mC;GD@II-eR)o!x{;SrPl3SHHo@X=TvFf#$%x@i362)GMb zR>aIbK{M4yCW6^mLN*!+6EVOJm7X{bI)}7Z*)!!@;8%y?G0jtnA7?vRS}y1hV>ibT z&?Ncg#6JwVZtHEo>29bOT4|EqR3T|sZd8Vk>F&%8Sk#5apUb-_*_2$KEiVgQoGIHY z1q%O@R@j$EQ`kR3Gbusow(D`EK>7X>|7yB;#8R4DR*?+-nvE&Nwa3_~$uxARfvzRV zA<9M(%<9cG((1J+!Bx=cxuEoZLLp8Z{slCjNFyd0f$CzLl(T4>HsD4Ng5EO{<;n9d zd;(t$lVsSU(5rt+EJ5)i(u=^7Phj zBJhCoRSjtG;74&@VLCBX{poPeMRiF;wYc*bZ%BetTAXPV$D{D_`=uub!O1=L6*2=u z`nq6T+GAC54L{d(PYP-%QN>beJ zG5*UaZ?geVFfQD0abG-svH7}G18piWw9C)7Uim8$_-A0h^7cRT%KFNlEDm~yM)c-v zCipjBvwW6Ru@}mJ>S+8YO<((Cn|H^Cmt)sGz2>C+H6K3n;Zq%Pk&XTOkaWxlVXMd1 z#U`ctz$$>aw?_J-BPo*l_G@j;bai9X2bM>+F^d#~#*?%8bil;K7#^_E>w$O{eb>aA$AM5I$#YQiMI7g8uTE+2`V34(W- z@(#GWkqF}f?fgc;H`O4f*EF4=p_;EfsUoqx<*0sl*Okv_I_K4P{U0_LTGQ?FMN@f% zc&K!c(ond#h8_M72D+Mp+S3`7>vs;l>2B|cb6I{fjOc$Ro9MDO{V<`nmn79^wA!%P zD;@aI)Lgjnuw3$ad6XfYtAA$shO7dObG%ZN*#erIwGMl_R@hZzz3#UF{ob1S2}6?; z!F`U~zy9I?Cmo$Z*fH-Ov zUxr*YG}w4X7-KhOVPO3Rm$4^+9GO zhZ3DvA?W^up^`g-&B7uEh+F<6YB;JZYPewlI<1i<1CD~Q@Is8x+i4Z67D9H-F9YFXI3A86x!xIu_wjnK9*NRp8q zkx4IN=4`ht0l=VPbNBCg0GV>iDR+^aErwUQ(=nR^vROt>5gVs4lj6Ws$cRp`OD-Wuw)}aLx>%XdTSH-Lk@c8MwwWT45g3l4mozf3{PQ=SK3Z_B`orHoTiUwnq_?o5k8U9# z^Rq7#JM_R>UbT(p(9vW4h9tf1`&(6xE<(?fMm&lPrf|n=vE^{pa4{ro7f{0n2@&FB z6Z8rKegjU;b0HsVHnjt5Mr5kXO0jGpnP8-v&nC0z)a@qK$?n-x98f4TV|GcVbXWN2 znJ?VMtnz$~ZcnJfJ-W!U$(F!Mu3dlc=FiN~KKO6{)EAt6tw}(exUS@n*H7g?`p*F1 zyZ614N66I57LXVU0f|9X>XgDAng|wJms`Gp@tM6WtByVbH1Ed{o(pljAMBO||AGL` zOM!4<8&CVK0K3ry-u__*`-k4>0i;E?k2R(B;bzB|2kk)4N+{jsNSVeuJ1-t?Rvs9o ze2aiJEDxs(h}-u~odj8qplj{IxpjS{y(b7Xoz5OYmPPp_6~zJS7b4z6GYokzRMc+FK}syW0wGz&;GFZkF3nKp)hQ%~$V`yB3<70=Q(QQX!{nMy~g& zTytI3E7)&u&gcV7ms)O@k)a8KOi9SCj=GScD}XDY*KRk^r+A9ax6XXn`en2xQ+()Z ziS3{WF#Y?<10k^F>{;V7>4)Y=!<@-dZ38a(-Q-@k9l2>Ib)Tbs{``#zjice-?)By6 z^L(!D>fErsA_!3m6Cgh*2z)>I!oB~m(ZCy`ZGK_Z=_BKNe;SaR+%cu)HlOMmq}6C3+p zPHFT<@F=9T`}`2Waq%Dst^k`G83YRDo`SevwB{N2rF+lAr|sU6%{qy@gsgn3v>KT{Q&S z_p+#ab4x{fCX)!1@d9pVeZtB!wturu+;`If=cLGNQBJVE$sv%V7%Aby6e-p43M0pj z(JC+uZam@;v}1`=akYW#Qq(eJ6{9M?IR|$6&G*5kdR^g#$Qv9!Sw*qnBqVk*wP(Cr z(uvx>H%Xcxyp9s%pj<0=b!l<(@q2=~x}7osb8y9Ic#@~7(|>Psw(&*E%F zwq9Ec)Xb$#Z#HavQfVsv=1Q^dJvfe1v2X14AaJ&5ifvVxv99(>b$?Ab#!30Mb5M^|+; zx&H|!UhA3iD}Z6Zl^f^K9saCxweDl<&bHx4&lcXr!`{{oi~KpY$>N;NMaQ+w%7YF{ zI>9NU>;b;ed}>`aA|i~em?*;1|1U84I?l2uST`M5zS`TsC4I?=;0g5^hW51(`yNo( zaTU|eUL3XlYn42PDGl<#F5Wo-fypDEE#VA!zcPa>B95P1Nvyy|Tu|KyYm zziFZtAX@MuA{p3^D1|dX71A~@5TDdbAld`tHk$&1 z(cBUhkNmo0d)SdOB5U*|(I6(w6ctaY^{wo9Xd_nEO`Wi!X5L|i42Gf7Yym&HW3^+h}5f3^{|MWz(g%=apoW7&x#%QNS3%J9+Q-8(TN?fdlPYAJdCMLzJq&bbkEkksz&*#3JOl z?Fl=fdDy6!2lyY9_nl+dUaH%TrfJ4ZaR^Sqm*SgUYhT!&uu)4>G=FkTB9OwbcgC?)cpA>v`>^-QAB#q+fVd{ z;w4@dEvPih?ztQxXyIvLXQ-C5V!{7N@wjI|D~7}aE^+Bomi2XnFxTXbB>+`@19bTO zD6Oo-6CP%*GjyU{6-!yyUVW%8V_Zun0u!jJa%vDRbKE0u5?UiM;|>_bB~G(blyU<2 z_)L<}%83F;z+CAva;EMp8Q!O}+tDUHO0w8^94Ge%7Vny!#P2}Q*Dmlgb^>|-*a4M z_L0lPN!y|?^?4KsrQ}qqJRI~jSy;aR@v-P`53KdDLeYeI7@Pm!1XrR}0h`j6yeD(( zPX~tmHBoE#S#2?q3!6$&*>*!S)|(=}st<%BTE^dsg~Pm3{jA>B4Ug~DvJo%mDHqXQ zaci1U#0XOAYo${~gm`KB>ch@& zsGN)Mi2nI=@!q|1C*cvlLMpq(&~wG&Lpl#?ms8BMbVdU%)bhFf=%g<5t3_3q7Pz$3 zNMcACl=9AMx>nb@DJ;1zgR7~B_r$~s(_*$x60SgVH==q4U%Ef}g;2UjsPUhjnm`kg z@*M2ek(@GI_n6K~8VGx$73s9q{#`*~%otAkD>6M9;Gy&ZSSV(Pz1s_cgXSMmKvI4-T8_N&c5To|{XE=+eOvGo5D7v@gpWq}CEOJ^n7 z&oc88Q;*0|d+Ca5H#0-T%u|X}A-|_0{n0n6ge$6hu-C_r3jtru%=0RZykaU`*-ubu z>o^Pme&OQsF7ETYZ`CK8#BoOE`5arQ#kX7KF0u8x(hR^a7`gfN*RjYhQlI1w1umG$ zPl{UF$t`3RE@kS96>C_)f=Yp@)i3EpJ}e^ap4f67 z{uQJI;9?XH$3(pRRxXw|RCzZ3$dXe(&Gw)}nAx}9cJA7_cp%OKh)9zG%6{`(efS7o z{=@)+#JyPFp-Pn{4#&S4V;Z^4aH z()$#9*+!=EhvkRXyLj&^UYobv-E>#Q%!i>{RxPR+JMtr5jj3+?O5=*ij)?r)fh|93 zJyvV@XhU>9CeFchpfBhOU<^ zT}oBQAV_vP4>`-YG3Cnz9Lz8StS1t3iW^@43a>Wk>*E0xQS4njoRGELHUh@^S2kQqq~Dbkxeg zcNLN`^=TyB;C^IEw2`mmgM8GQY3bR;89@5Z^}jvZhR?q9WUSpFonEuOb9eu62g3$= z@311!2px^O+?GM_Mh(C00Qb(Z>TNJDGn}q_YEez+k}?lY=y|6StS{LWApac@OMm1J zR8EzS`MFjvn@S2gzTEtDxbnyY=`?ssKoH{yPx5FmO%E#$8#qInUWo8U&!k5~e@(dM zbAh+Qr7{J`*2!PXUQTc0jc6ek#W^cZi$`iL6pj%BVBk~h!p7kE`c=d~ z4tNY1d-6@8eAVv^nUKJwN3RVI2M2l=cH~oha-fU~d^ics3B)QOADA`2qT1G%uaE;4 z(|^uafeQq9*~saEqpg5Ifv5f_`MAHAhyRbFb^nm75B=UVm8xr989e&y5Eae)sC$o} F|1Zu$OyB?j literal 0 HcmV?d00001 diff --git a/docs/flake8_report.png b/docs/flake8_report.png new file mode 100644 index 0000000000000000000000000000000000000000..3736cee381216f2b39c70c66eba2c9f6769957ef GIT binary patch literal 16384 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 IJ1(#O4?96*9{>OV literal 0 HcmV?d00001 diff --git a/docs/screenshots/home_page_screenshot.png b/docs/screenshots/home_page_screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..798f0950ee1e951ceb2fbbfb78d5bdb9e417f5cf GIT binary patch literal 26046 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 literal 0 HcmV?d00001 diff --git a/docs/screenshots/letting_details_screenshot.png b/docs/screenshots/letting_details_screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..ab0dbd83bb8465690ea930a329c9a86a84acfaf4 GIT binary patch literal 44626 zcmeFZcTkhx*9V9NQ4siAP(cBeCLo~n7C=xS^xh#-1PQ%_-b4YV6Pkd4^cs37p?wwU z0zycr0g;|iq=a7fLE-nlyE8kp`^UR8JM%uHlc%10@44rm@;T@7K}|)DlAMm5goK0= zEdN}CgoG4JLUJB|`4VtPIQCL3@N>>ZLr$8cr1#z;aB3lr;*B17F*b8_B(E{5sQbBob!g)o z^Q6m)va_m3+Fl*oJYBAJ@_C^7KZmth<*l=GsrAd)bEg--&wmj;yKiz|kL>jPUy6%_ zv)djI`p5_>d1!+(V)ykuMfIX0BI0{2nT*c9$ktDzz=9s^RY(pMs)y_&&3e4P!cIv@ zCDQ_Z!J64yCg*-q$xEKx2oSWNWM`~bUJdur?j!m>SIN^9G)xm4I&1T{becj;s!HC~ zmLI=z{9jLRHPbAt7S#?5gCxy9wKa&n5KK{~3TZ*no_(;ku2p7#Cz#n9KMw&18=HqT zWLrB#Bv?SdWp{d6?d4UBEx$V(QGms4QqD^ybe!p((fZW@`&vZS`GZ5^YI<{lR_Cvi zx4o=4J!pA1(YMiq<-UdqL1)}zX76KePYa7Zs_@A%yO+CSKO~!@a7$N7Dcr=Sz|V|y&oa?^6`{!Ju3`ek}| ztL=e1|1}ZJaJE30s<7YE3_HD~r@^d3yhf|@D`xkf0DJCHg+R4S3)vX_q^LB3fm$Ur zo^>#~J&>qr)!WH`Rr`^y!O_vthdmF=Jjv~0Ci2Z~OlA(J>&}8x!n^-);-rn2J4ED+kPD z1`Iu??XG8akh-3d!(T@v!e-UESL!@b-I#j2C^{@Rj%Kc2D8MHf{1JNyVP@8j5P zHg;}nHK@N&X)Do0USgsvM4g^#CN%z-iGq*6jo;iN?`f~f`Zx98-({)Euf{F9a_~Pk za^^XPYc=n|pxv&bRo)Kr@Wa29qg|3z^4$EyRhqY;2nz4&&TF@ej3hVsFMNdGb1Fxb zS*7?bV+_P38QA#3bo^c_@yWW;O)s&kGPkAu+o1Kqtb%sn3sbx6?)od68qUMe`n^;M zZlM{$kL>{gHfd6# z)qboiE2r}5hd&t=xU;x2jpx3Ugj;=PW){uu`Mvhbe|jA-ZrU=_w+^DMwHVoV`rO43YweK4Fs(pkN8wsv=;85Lf9;#ntb$~oTzs9_q*HM878Uz zlKR90@bmEv_&KHR@*eVV>$#4ur@i*hMrA9G!tjRH*4EA`$Bso;*5n|2n18$2t7H}5 zt>x{|h=_>voRW)Q_6jQJXX3OP&Wtw+>#^J64~ zWC0+YBB{9thd$a3ude}YRY4YNt0SP=T90a99=K73$N;V6T6bAiE*3G~Dx7zDt6iaY z%}!5Tm8LsBg1XO6FvSZbBwsntgPrM@AugFW&NvEN)KoHG{nHC6`zJ*VBC4`@B;Ur6 zsFf0*u1>g79V?*`4n23#RPZId!jG-dckTjPZ=}{~74D)+s@^sRh~H-37x1?Zz_1yv1`VOsAme;uwiLV$z^A zhJ51(`$S?K7~h|x8ESf}Dx4Xlhr{D(GC0kX>nhB`D^ng*V?ke#=*7VfFylf`CweA2 zg9YMOEH*Zg{AhSf+@#JeYZSEe{+^2FY7|}WJfr{fL>@>&X{kfzKjVw8_{7~V(MQ->MGn0^S>*kGk3wr^Kr z8v2z{9_&WB*+M3sU_h6z5gIT2?GDM$m{(s=*2xtkwxT{uwWE?d`F_So9hT5r*aq5I z0rLT2V5MMDA7-eAfF>`A_sf+^Y`g=Qb9jjwonOP&ZCTlAU&Cf#&<3aler1pk#0p`& zgIK9AYW(_@36pgkw)eYo1fGr8=CE#U;33+srr{^nRA7sa-Us_yio%Ewx8eqzKmuf6_|>B$?nIZwPU5|R#_o*=XNt5)6zfLiMc z1=L!Fg+jG;a%f~z@rtT=DbTE|IRbC6w|u+MxH0+HuU{55W15sTpzg2Xben-q9{z!$ z7jF+{&T?XkHH9eeJXH~MJ7xj{_G^7@?L+g+0@FLm!e;MTqi9P={2@etSe)O%tUGOR zMs01a7UcFR!=r0n?S;eols4EdQKG{gnskE(Sdi->rCJ3(A|m&wMwTa1jn|hPR+}!+ zi5}7WHt*;Hi&9xdz+qgCE16%b(Lg{eQ%`+&Z-)a|zU`{11Hkg-2kc}}u(8IQ^Sj8! zc}A^9g`DTN75|P}Y9+R$GKI`et8^mbajRbIJ^d`-RU&o{5~VlVaKrU@9<`ivT%h(W z#caEGaI{q$a}ZQL5InV)J81~rOqGG*ZTnZel##6{r(2z&fKnC7)t;2hom>=4n(<1%X8x%xRSY3W*L7Ydicn3)pq)3N zy7=Kism+00I$m0@_G*jTLXIPmb|>^6RntFz+4|dL2i3VZ&pE_pF*50#V4pQ=-i%Qu z7K0i!r;kFk@_(MAzq4NK=Cct&<#22)S5u7bM-mXmG1E%}A28jnZn#p>wR9xqh;eSO zo{+L;hH0W!GY%x`^DCQ`im~{as-#~}hL?0&)RcbL?2mqPgZf<_yU}VH?``@YNiOp= zcW<-#OG4r~)TOmKb=0!%5(=Gz*1djyn1{{GSo;dE2oP5fpH!ZD+0NygpKwb_<$fzJ z^?qrtIrj$r<5!j^rPV3KphrK(T(^4@wKmgNtLB{*F|`@t+*3AvZTID4i-2n5`R{x0D$E33ydoDd zeBGr915PT?acr80Ue8!ON<(Zv3tL?W3A!FR**IA=R?EFUQuFLu>)k@NXON`CD8iEa z1>*cW&(P@Xwzq>`JDeQ4h%(zy?eWeYQP0A{E{uCy^W?ZFU=VV1+5rzg*!1;4m8$E` z3_EV1tm(vK2K+t(6=s%dkg_Ejy%>jH)B;>pOqL>B^+|KOw#6M!nGVKk|i**ZxWAwY(3b1-I7>zQ+G;s zHcGMiUjbG5Sz$H-d$v5u!e;EJ1XqLh$$GhNh_B3w3%%|d!pN{K*U11h153TkRq(4( zVxR}ayl8^FvmeZ%RnF3R*GUFUIv+g|YL!HlxK3zxGen z(FA$nMuP#d-uRqoDMgC0ek}9iI^D8QSq|3ssa)P$6P@MiS2@1vuV-ZrtGw6lEqhG4 z*%^A9NWk{;?Wx&a34Ng-Vr_c1v?U3{SpVw{q1v99RV?^Tb*!l1nh9cm#cJ8NvaY&R zf+zhhqZ-1HMf=eM$&?xK+^`c}DjL1tzu{8Omd zMr9;o>{s%ew0FZ1(^X4BPesc-!V`S!WvOV?r`nEVS5~ulXO~b7M=->l^%AP$J-rkL ze97?^%STWzz@|;r>e!!G3MBXEyp3ybmWUbF{6Gi^eV`sMjkiwbjlJ?OAY?!Qg|lzQ z3)l)8`lMJbel+C~=aL!NnYCBCv4C1 zd< zp1i_GJCAMxSK2BNq)HItm zcNPhF%6n4vpRUq@k+)XA(x0{^v1tyN*W*e)e!SC@yq#r{?A5fIr4b10Fa2PRO7Jfq zfm05lzw*@|RwvZtuTjEWX9j5x8+>xU6`w}o+3H`z5|8*?qID$HbS0?{nMd?H7fXu| zHWWDqRfu^<*<<20A$Pl3*~<=?;J03z59Jy>bqb|gjnMc>3DWXkmxXy`e1KWW>lj43 zTyo;!iQ5tADpFhgbtR3jEs3S&Ef8}y+II^cdjE`u>J;RU83@LXXKW##q^fj2xe1%g z?zPkBYO#zhVanbvK0cD)F5$hJGIz8Y7WY#+|1aOA6u6JYq*5kaCnvmhL)`N!a)}jO zPx6l(3x9Wzf%Q)Megu_L?FIfwzqB~+Q!Xk3YBX#$j=A{ePvrSdM)Z!HiQoe4y8 ztKjR+Y%?yDp?k1J&aALiv_1t)RI6*qt#}j={bz+aU0JsaWK-V_m0E=Jbt75EOn!e? zfK-^pU#&MbUO^c*H8l;1-yL@qwivc0m#lzr?pL818|^V^Ne(h+WzV;l$8&DchduiB`n3;roA8E(N11(1eecI&gJ$*ImW-_$!5TL( zA9^aiuGQk}HIL+0*;ITZ53e-yEt&@w>?8uw{+Hu{pph#XZ2)6vYSPH}G1Cw6%8YLuo@*|4|F#y{nfw2Za?y>B3v+gOyP z9-);%5Ek&OJyexW>UI%ek zQ;g%g5@Sv8m~df!UBN^>PAbCmxy3IJkkUZ=pCNL&5+E6w&TValdoqWx4a3Ttgy}rZ zu%75~kK;hgitv?jN4R}qYx(LUx`+M8SUP?1@= z-HVsNx$G&WrAi?(G-9A^!--uTr=w@6o%x4{yRK};O&%t}JqfvvxEsZ{IW_cnQ$@Xx z0+FX-8i_?YlW5I~6}=&`QiZXs`az||>#~(AMLa=r9j*$b6f>$?svj0zyDV!6>8fnj z-5qQ*gmBG~lBj}N@5#=&`FZkX-2T%gww`%{AKixf`cqK@!lwB=Z(Vtt(}hYpqX%=4Sz5$x7>X?-r!Xua~=bG<=?-u+(cT19W9_u5~+^n$%p7Wc?wrY(tFClyswf= z?w--Vl9T2NAya)qfAh{GT8-xx7MUn*pO^M`MtS%2gM7qQg0rEA!G--cn#}IQc9a;9 z_>@4A0Gi7eHJD>Ku!EyN# z^ssYv9ib=Fi=xyE6|hqT*o_vjSkREZ%?r6^VE#6`!B-)392rZoWGr~O$2hD_T{ zIbS%WJKkDpKzvR{Z(RLk#L*ZYnJ&&kD;UqNExrCry6BW=0Syn9t%(A^zweZ&Raf~e z3m(=SfBwq!@H+8nstSO2azljkB-5AjWBnh)ZQU>nVtN8zARa5DPgme zMna(=-}0rPFit@Z4FZ|lP{s=ggr>yXvUv4~=Xr3CS_DV@4a^yus%A+_c%=}pg;bz{ z?Hzb7xr*GxlMR+s%e;;np0V<()>>Nx{Jn ztZc&tulnhETd96XA1S$5xgcb>ZHw#3+x(ceK0Cz39M3NT)8ry{qrZYOhyZC%SpIkr9Ur3d>9)7q{{NGSPUU9wc$K?Yn zSi_t5Zsto0+4fKPl3CmdKA@n{jv1w#fz-#0`c!NAy$I#p(#ZdmI{^D=D<}hh&=PGX z&6AHc=P8)rT?!=qQmGQNjWuLKv`Phj*b+mS zdvVVu@hUZT)mlER8g|{;)&7Z&5 z3U60%E(&QLLQ5QRWh2aan$L2&yQlnc+g3gqzw^6KdaPY!)K9aX=l+%YPip~>-8X)- z^V+)E&<=H$jlh5ltaC1agv;qf0)Qv`7Zi|^uuewhtSO_iU=*o!|Ktiy9LodXs*{sb znhLgu_q|xH&{Yw7su5qGD)-5AJ)ih=-C71e=k1}qa#}`L{*I}`FBIokiQo3;l6X%9 zeAZQFar@w&lD$KSX8B$F>dmfu;nr;(D(0VX7COoF4uhX>&)C#h?=3kX*GfBfp zcX&F~qv_@axkyb9ttzkaF|hJoY$AHmg7z<78er5_Hlnrq!4&0!RiG)sNx3mjKJLtQ z7L|eH+I53$gnpz}>J(1gXffh^VR7yZm%qw)BhS+NJYhaKVjzxZF5eG9XHfa`F6pJY zSU}0lO=tCF?GX+dqO@Q$O4`d<-Q1Q3Eq=a|(~i$y;PdLCkM_pdVMli9=exDkjBJa2 ze0+&tzVmE;?GVx`b}T#EvwPE(z|8`FeBlfnlh?>iGx`1a%0^oePk|doVf3iagm_n6 zDcJNIPotT|k2+?)BgtSOjppOyQ{_VxZCr0-1`mjpQft@o=I9&JpDMBFOeIPzhtOdhztxvMI&rVSB?$?5ws4-zA}C}c&VuhM;GGlR1F1YTq<$-3?)Xh8>RwTv z_n~Sd3Kr8c_43Lo)=VN5$_siScy%azEyX@Rt8apyC*^^1@=-w=ql5wc=1<1^d|$p3 zH#>$Y!76#|A?Sji2VX`T?D9m3_&oGH558BYhxlc92#8T%HTSYuo%WKX4w6eoaOSx( z?I=8mKpQ8ESbwq&-kiD(DVkI)WncRBf^_t1tLU$R<;+|sst{XVZDxo>PqGlieQP0W z+NyW4+A#U`N;vh*^mNNQ&neLW{!aKy;}b;#iFrj^3Q#m_>hgm@DjSfQ@>H zs0CeEuRHINrwQaWQJ#eWH-T4~J11ANgeOUqoAso8WgBufOil6FDL1Y?=U{-3eW+8o znz~156dq=#QeQSDU}K{TEh2$6f71LVh?GRXre!ax&!P zTp-2dok^o{s2QW7rOkwOk ztBOHheE`^MUqjIFs5MFXotEn(VMvuXGjFcB?Jb%=f4E)vB370oTCxLWUE#J$*&n6o zH&pB?iBI<>W1)rW)#S29dc3GXHoSme{*T2m>Av*^HD1{d;zJ7^A&sZ=e2RCQ4_HT* z;MRpci*RUvc1$vV?K2ouOY?)-i+IUL^1<1F?HBc5%cQy|QAqE7gc(&fL|TtcI(I}X zXlO-B1s_kcjFD0VT< zLSfAT7kzbGIha}Vjh`PB{mYWLFaS1QftDUTD;Zfi!*xgk2rB40qtz}^M`Qj{Ry;;(7K5)uQmJ-#_X^Y;&uKq0l!X=QYNAu@wE$ZOz^!#V zzFr9_XO`)wmqqtWT#L(_f$Z~Z9UYHeKq6z<^L%`LfWiJQOj<~zNMS{S&g69Hp&=RJ z3V_!FdOM}ZO*>#^>dF91r)4GJl%2jKh3bC#U&-{5X9JqeXKhKr|0}io|0Lu7=H=Nk zCgJ&~_)IhWBn>>143Y+^(}0tNB;a;^-?8CFZ$|qmDMJxB8=Tda#H~;3WfEWJn za{T`<7(}*kvr$#ITSi zXuod=3|1!N!rmQ1R*uhaPtgmQ#%6063oM7VYxj&kp!5au3H@O*^RHE1)sg;0`o@9G zvK+F8Yj>|@Dk~oS=t8C-cjZ5tG0D)-+9dkFIUp~i(b`232g|e-aej&y;;G8)DS>fI zeLpEek#eiqD-s!X>3q(nx)?L`TKma{O z1(&1#sgOoP@I_=~-v`?&ov@&j_33%*&(g0z@`5JNx(?I>|Ee?M>vdB)hepqJ*4N5T zdu?NCbMlPec)dx+OE~BH8T`)4jqotSiH>KEvM3fl?}Qh+Y8t|ph{dcvJ2|)djum1d zuZy}!m*Drv$M_&J-jaEphTM9P6P3~t`$ra{dv^0Z8msZc#qa}!viwAA4&CTHB|?}G zZJ}E($U`U+SzYLy%h8mKJQt+3zw#{k>HLjGCsop+&hTLuQ4i)%uS@}AB!863{oA3q zqD3Cx&k-^3o7r@YY}VK!g!cH@;!#s8W^<%-&-rIhA@lrskBZ(nUHA?AI1w zAT$rDy69TZ#<+xDjnFD~_#8-)I6#R&73R%0da=B1TV4NPXCUlQl3*wPneSSRZlr^n zy0(p1*ovKh4IPF%Ze4@>N@OBJLDlz2ojSgJtMg@|%yEB0kRtM>Z{Rdj=PflU($GX* z0(N^bZKWpPIRK^@b}@Z6nV&X4$9&AN2>f2tql3ej*urz=2sb;kM~}zqHv8E=e=m4g_IwgyRK#>U3s#`xf0&TF4X{68DVUZ3%t8`A zu=@L*;uRdjP&c1ne?l~x92OE88lm-i;o7p%X1uKUMl{2{Cz^Nr+VtI{vxndR!i&| zH-_J<1u={uUTsWZHE|3-Vl@TvO1F5v`Fd{Kf`$zHM3~vKZR6;?1a9MBMY^YB&OXc{Sv>5U9rj$GKstvg zVt+o1T!l~1)-aPIe_`JR)M`=<*RlOQln=XBo($G{Wxr*x$dEB&Z})TJM9zRbPkodIcj zm_ic^As>V287y`($8a&x;~Mo-61WGVQdH|N7}s~<_+&NH5Tys$RD)N;JH|g&Tha&L zDVH4X-73t)rmpA|wNYv#-rw}}sc{2v<;g^zA^Sc*78+ZS5rnew#qRYL{N_Cn#->`D znG}#|hqh|fLzkSy;bpIyAvLb1pI&&w{7`#a&oBc4>wMOD3PpG?y&gilnG0P?pkn{d zzO5k;%gS?%vx6>4Y|T^IVsa(@v8tTg1nJ@;)p9`@{$%J z8bu2YbK(>(=I#6`P_WQEF%m)N+pfO*RRNdsQ1Y-t}4!Ub*P_W}-Psle75^9aX4Jt~m8A z4VTX@(*|8r56OOr-@#hZ=^cAb+I(Gwa=dBG4r`A3kriA0NV??4eOw6Dka?#MN-Cpr1%Z9^=`WK;4`~v(~2oqYF0ke`nBcl&q zFGXvv_Iao%UtoD*-@kt&;n8foA$}oA)#|lHO`J3gyskTIKh0lm!w!bK3~eVPyGQ3k zhnE?lwQO2EL)w}Wj4`%=E^2B`#@A7^5t8n{y;;6^p=a1^Ip)jP$i;m8Vp0?

9T6 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 literal 0 HcmV?d00001 diff --git a/docs/screenshots/lettings_list_screenshot.png b/docs/screenshots/lettings_list_screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..21f41d766f075bdf47130dfcc8b71853eace897d GIT binary patch literal 42869 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 literal 0 HcmV?d00001 diff --git a/docs/screenshots/profile_details_screenshot.png b/docs/screenshots/profile_details_screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..57ca31328dad0b5ff4fe94ee078546bc0f836c53 GIT binary patch literal 43697 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 mtUkx#a~u>~{get_letting.title}' + + assert expected_h1 in content + assert expected_content in content + assert response.status_code == 200 + assertTemplateUsed(response, template_name="lettings/index.html") + + @pytest.mark.django_db + def test_lettings_index_view_returns_500(self, monkeypatch: MonkeyPatch, get_letting: Letting): + def raise_error(): + raise Exception("forced error") + + monkeypatch.setattr("lettings.views.Letting.objects.all", raise_error) + + client = Client() + path = reverse(viewname="lettings:index") + + response = client.get(path=path) + content = response.content.decode() + expected_h1 = (f'

500 Error : ' + f'something wrong with the server - forced error

') + + assert expected_h1 in content + assert response.status_code == 500 + assertTemplateUsed(response, template_name="error_500.html") + + @pytest.mark.django_db + def test_lettings_letting_view_ok(self, get_address: Address, get_letting: Letting): + client = Client() + path = reverse(viewname="lettings:letting", kwargs={"letting_id": get_letting.id}) + + response = client.get(path=path) + content = response.content.decode() + expected_h1 = f'

{get_letting.title}

' + expected_content = (f'

{get_address.number} {get_address.street}

\n\t\t\t' + f'

{get_address.city}, {get_address.state} ' + f'{get_address.zip_code}

\n\t\t\t' + f'

{get_address.country_iso_code}

') + + assert expected_h1 in content + assert expected_content in content + assert response.status_code == 200 + assertTemplateUsed(response, template_name="lettings/letting.html") + + @pytest.mark.django_db + def test_lettings_letting_view_returns_404(self, get_address: Address, get_letting: Letting): + client = Client() + path = reverse(viewname="lettings:letting", kwargs={"letting_id": 2}) + + response = client.get(path=path) + content = response.content.decode() + + expected_h1 = (f'

404 Error : ' + f'letting n\xb0 2 not found !

') + + assert expected_h1 in content + assert response.status_code == 404 + assertTemplateUsed(response, template_name="error_404.html") + + @pytest.mark.django_db + def test_lettings_letting_view_returns_500(self, + monkeypatch: MonkeyPatch, + get_letting: Letting): + def raise_error(*args, **kwargs): + raise Exception("forced error") + + monkeypatch.setattr("lettings.views.Letting.objects.get", raise_error) + + client = Client() + path = reverse(viewname="lettings:letting", kwargs={"letting_id": get_letting.id}) + + response = client.get(path=path) + content = response.content.decode() + expected_h1 = (f'

500 Error : ' + f'something wrong with the server - forced error

') + + assert expected_h1 in content + assert response.status_code == 500 + assertTemplateUsed(response, template_name="error_500.html") + + +class TestLettingsModel: + @pytest.mark.django_db + def test_lettings_address_model_ok(self, get_address: Address): + expected = f"{get_address.number} {get_address.street}" + + assert str(get_address) == expected + + @pytest.mark.django_db + def test_lettings_letting_model_ok(self, get_letting: Letting): + expected = f"{get_letting.title}" + + assert str(get_letting) == expected diff --git a/lettings/views.py b/lettings/views.py index 9d66d4b454..f7b0015b33 100644 --- a/lettings/views.py +++ b/lettings/views.py @@ -22,11 +22,11 @@ def index(request: HttpRequest) -> HttpResponse: try: lettings_list = Letting.objects.all() context = {'lettings_list': lettings_list} - return render(request, 'lettings/index.html', context) + return render(request, template_name='lettings/index.html', context=context, status=200) except Exception as e: context = {"error": str(e)} - return render(request, 'error_500.html', context=context) + return render(request, template_name='error_500.html', context=context, status=500) # Cras ultricies dignissim purus, vitae hendrerit ex varius non. In accumsan porta nisl id @@ -56,12 +56,12 @@ def letting(request: HttpRequest, letting_id: int) -> HttpResponse: 'title': letting.title, 'address': letting.address, } - return render(request, 'lettings/letting.html', context=context) + return render(request, template_name='lettings/letting.html', context=context, status=200) except Letting.DoesNotExist: context = {"type": "letting", "id": letting_id} - return render(request, 'error_404.html', context=context) + return render(request, template_name='error_404.html', context=context, status=404) except Exception as e: context = {"error": str(e)} - return render(request, 'error_500.html', context=context) + return render(request, template_name='error_500.html', context=context, status=500) diff --git a/oc_lettings_site/migrations/0002_auto_20260518_1551.py b/oc_lettings_site/migrations/0002_auto_20260518_1551.py index e865453170..586b4a1db8 100644 --- a/oc_lettings_site/migrations/0002_auto_20260518_1551.py +++ b/oc_lettings_site/migrations/0002_auto_20260518_1551.py @@ -7,6 +7,8 @@ class Migration(migrations.Migration): dependencies = [ ('oc_lettings_site', '0001_initial'), + ('lettings', '0003_auto_20260518_1551'), + ('profiles', '0003_auto_20260518_1551'), ] operations = [ diff --git a/oc_lettings_site/tests.py b/oc_lettings_site/tests.py index 851e35573d..1dcc30af82 100644 --- a/oc_lettings_site/tests.py +++ b/oc_lettings_site/tests.py @@ -1,10 +1,55 @@ """ Tests module for oc_lettings_site app """ +import pytest +from django.template.response import TemplateResponse +from django.test import Client +from django.urls import reverse, resolve +from pytest_django.asserts import assertTemplateUsed +from _pytest.monkeypatch import MonkeyPatch -def test_dummy(): - """ - Test dummy function - """ - assert 1 + +class TestOcLettingsSiteUrl: + def test_index_url(self): + path = reverse("index") + + assert path == "/" + assert resolve(path).view_name == 'index' + + +class TestOcLettingsSiteView: + @pytest.mark.django_db + def test_oc_lettings_site_index_view_ok(self): + client = Client() + path = reverse(viewname="index") + + response = client.get(path=path) + content = response.content.decode() + expected_h1 = (f'

Welcome to Holiday ' + f'Homes

') + + assert expected_h1 in content + assert response.status_code == 200 + assertTemplateUsed(response, template_name="index.html") + + @pytest.mark.django_db + def test_oc_lettings_site_index_view_returns_500(self, monkeypatch: MonkeyPatch): + def side_effect(request, template_name, context=None, status=500): + if template_name == "index.html": + raise Exception("forced error") + return TemplateResponse(request, template_name, context or {}, status=status) + + monkeypatch.setattr("oc_lettings_site.views.render", side_effect) + + client = Client() + path = reverse(viewname="index") + + response = client.get(path=path) + content = response.content.decode() + expected_h1 = (f'

500 Error : ' + f'something wrong with the server - forced error

') + + assert expected_h1 in content + assert response.status_code == 500 + assertTemplateUsed(response, template_name="error_500.html") diff --git a/oc_lettings_site/views.py b/oc_lettings_site/views.py index 12850d6962..ec37ad70d0 100644 --- a/oc_lettings_site/views.py +++ b/oc_lettings_site/views.py @@ -21,8 +21,8 @@ def index(request: HttpRequest) -> HttpResponse: An HTTP response with index page or HTTP response with 500 error. """ try: - return render(request, 'index.html') + return render(request, template_name='index.html') except Exception as e: context = {'error': str(e)} - return render(request, 'error_500.html', context) + return render(request, template_name='error_500.html', context=context) diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000000..59b81c4412 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,624 @@ +# This file is automatically @generated by Poetry 2.3.1 and should not be changed by hand. + +[[package]] +name = "asgiref" +version = "3.11.1" +description = "ASGI specs, helper code, and adapters" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "asgiref-3.11.1-py3-none-any.whl", hash = "sha256:e8667a091e69529631969fd45dc268fa79b99c92c5fcdda727757e52146ec133"}, + {file = "asgiref-3.11.1.tar.gz", hash = "sha256:5f184dc43b7e763efe848065441eac62229c9f7b0475f41f80e207a114eda4ce"}, +] + +[package.dependencies] +typing_extensions = {version = ">=4", markers = "python_version < \"3.11\""} + +[package.extras] +tests = ["mypy (>=1.14.0)", "pytest", "pytest-asyncio"] + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main"] +markers = "sys_platform == \"win32\"" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "coverage" +version = "7.14.0" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "coverage-7.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:84c32d90bf4537f0e7b4dec9aaa9a938fb8205136b9d2ecf4d7629d5262dc075"}, + {file = "coverage-7.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7c843572c605ab51cfdb5c6b5f2586e2a8467c0d28eca4bdef4ec70c5fecbd82"}, + {file = "coverage-7.14.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0c451757d3fa2603354fdc789b5e58a0e327a117c370a40e3476ba4eabab228c"}, + {file = "coverage-7.14.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3fd43f0616e765ab78d069cf8358def7363957a45cee446d65c502dcfeea7893"}, + {file = "coverage-7.14.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:731e535b1498b27d13594a0527a79b0510867b0ad891532be41cb883f2128e20"}, + {file = "coverage-7.14.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c7492f2d493b976941c7ca050f273cbda2f43c381124f7586a3e3c16d1804fec"}, + {file = "coverage-7.14.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dc38367eaa2abb1b766ac333142bce7655335a73537f5c8b75aaa89c2b987757"}, + {file = "coverage-7.14.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0a951308cde22cf77f953955a754d04dccb57fe3bb8e345d685778ed9fc1632a"}, + {file = "coverage-7.14.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fab3877e4ebb06bd9d4d4d00ee53309ee5478e66873c66a382272e3ee33eb7ea"}, + {file = "coverage-7.14.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:b812eb847b19876ebf33fb6c4f11819af05ab6050b0bfa1bc53412ae81779adb"}, + {file = "coverage-7.14.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d9c8ef6ed820c433de075657d72dda1f89a2984955e58b8a75feb3f184250218"}, + {file = "coverage-7.14.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d128b1bba9361fbaaf6a19e179e6cfd6a9103ce0c0555876f72780acc93efd85"}, + {file = "coverage-7.14.0-cp310-cp310-win32.whl", hash = "sha256:65f267ca1370726ec2c1aa38bbe4df9a71a740f22878d2d4bf59d71a4cd8d323"}, + {file = "coverage-7.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:b34ece8065914f938ed7f2c5872bb865336977a52919149846eac3744327267a"}, + {file = "coverage-7.14.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a78e2a9d9c5e3b8d4ab9b9d28c985ea66fced0a7d7c2aec1f216e03a2011480"}, + {file = "coverage-7.14.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a1816c505187592dcd1c5a5f226601a549f70365fbd00930ac88b0c225b76bb4"}, + {file = "coverage-7.14.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d8e1762f0e9cbc26ec315471e7b47855218e833cd5a032d706fbf43845d878c7"}, + {file = "coverage-7.14.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9336e23e8bb3a3925398261385e2a1533957d3e760e91070dcb0e98bfa514eed"}, + {file = "coverage-7.14.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cd1169b2230f9cbe9c638ba38022ed7a2b1e641cc07f7cea0365e4be2a74980"}, + {file = "coverage-7.14.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d1bb3543b58fea74d2cd1abc4054cc927e4724687cb4560cd2ed88d2c7d820c0"}, + {file = "coverage-7.14.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a93bac2cb577ef60074999ed56d8a1535894398e2ed920d4185c3ec0c8864742"}, + {file = "coverage-7.14.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5904abf7e18cddc463219b17552229650c6b79e061d31a1059283051169cf7d5"}, + {file = "coverage-7.14.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:741f57cddc9004a8c81b084660215f33a6b597dbe62c31386b983ee26310e327"}, + {file = "coverage-7.14.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:664123feb0929d7affc135717dbd70d61d98688a08ab1e5ba464739620c6252d"}, + {file = "coverage-7.14.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:c83d2399a51bbec8429266905d33616f04bc5726b1138c35844d5fcd896b2e20"}, + {file = "coverage-7.14.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb2e855b87321259a037429288ae85216d191c74de3e79bf57cd2bc0761992c"}, + {file = "coverage-7.14.0-cp311-cp311-win32.whl", hash = "sha256:731dc15b385ac52289743d476245b61e1a2927e803bef655b52bc3b2a75a21f3"}, + {file = "coverage-7.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:bfb0ed8ec5d25e93face268115d7964db9df8b9aae8edcde9ec6b16c726a7cc1"}, + {file = "coverage-7.14.0-cp311-cp311-win_arm64.whl", hash = "sha256:7ebb1c6df9f78046a1b1e0a89674cd4bf73b7c648914eebcf976a57fd99a5627"}, + {file = "coverage-7.14.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7ffd19fc8aed057fd686a17a4935eef5f9859d69208f96310e893e64b9b6ccf5"}, + {file = "coverage-7.14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:829994cfe1aeb773ca27bf246d4badc1e764893e3bfb98fff820fcecd1ca4662"}, + {file = "coverage-7.14.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b4f07cf7edcb7ec39431a5074d7ea83b29a9f71fcfc494f0f40af4e65180420f"}, + {file = "coverage-7.14.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ca3d9cf2c32b521bd9518385608787fa86f38daf993695307531822c3430ed67"}, + {file = "coverage-7.14.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92af52828e7f29d827346b0294e5a0853fa206db77db0395b282918d41e28db9"}, + {file = "coverage-7.14.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7b2bb6c9d7e769360d0f20a0f219603fd64f0c8f97de17ab25853261602be0fb"}, + {file = "coverage-7.14.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1c9ed6ef99f88fb8c14aa8e2bf8eb0fe55fa2edfea68f8675d78741df1a5ac0e"}, + {file = "coverage-7.14.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8231ade007f37959fbf58acc677f26b922c02eda6f0428ea307da0fd39681bf3"}, + {file = "coverage-7.14.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d8b013632cc1ce1d09dbe4f32667b4d320ec2f54fc326ebeffcd0b0bcc2bb6c4"}, + {file = "coverage-7.14.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1733198802d71ec4c524f322e2867ee05c62e9e75df86bdca545407a221827d1"}, + {file = "coverage-7.14.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:72a305291fa8ee01332f1aaf38b348ca34097f6aa0b0ef627eef2837e57bbba5"}, + {file = "coverage-7.14.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fcaba850dd317c65423a9d63d88f9573c53b00354d6dd95724576cc98a131595"}, + {file = "coverage-7.14.0-cp312-cp312-win32.whl", hash = "sha256:5ac83957a80d0701310e96d8bec68cdcf4f90a7674b7d13f15a344315b41ab27"}, + {file = "coverage-7.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:70390b0da32cb90b501953716302906e8bcce087cb283e70d8c97729f22e92b2"}, + {file = "coverage-7.14.0-cp312-cp312-win_arm64.whl", hash = "sha256:91b993743d959b8be85b4abf9d5478216a69329c321efe5be0433c1a841d691d"}, + {file = "coverage-7.14.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f2bbb8254370eb4c628ff3d6fa8a7f74ddc40565394d4f7ab791d1fe568e37ef"}, + {file = "coverage-7.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:23b81107f46d3f21d0cbce30664fcec0f5d9f585638a67081750f99738f6bf66"}, + {file = "coverage-7.14.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:22a7e06a5f11a757cdfe79018e9095f9f69ae283c5cd8123774c788deec8717b"}, + {file = "coverage-7.14.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9d1aa57a1dc8e05bdc42e81c5d671d849577aeedf279f4c449d6d286f9ed88ca"}, + {file = "coverage-7.14.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90c1a51bcfddf645b3bb7ec333d9e94393a8e94f55642380fa8a9a5a9e636cb7"}, + {file = "coverage-7.14.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a841fae2fadcae4f438d43b6ccc4aac2ad609f47cdb6cfdce60cbb3fe5ca7bc2"}, + {file = "coverage-7.14.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c79d2319cabef1fe8e86df73371126931550804738f78ad7d31e3aad85a67367"}, + {file = "coverage-7.14.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1b23b0c6f0b1db6ad769b7050c8b641c0bf215ded26c1816955b17b7f26edfa9"}, + {file = "coverage-7.14.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:55d3089079ce181a4566b1065ab28d2575eb76d8ac8f81f4fcda2bf037fee087"}, + {file = "coverage-7.14.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:49c005cba1e2f9677fb2845dcdf9a2e72a52a17d63e8231aaaae35d9f50215ef"}, + {file = "coverage-7.14.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:9117377b823daa28aa8635fbb08cda1cd6be3d7143257345459559aeef852d52"}, + {file = "coverage-7.14.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7b79d646cf46d5cf9a9f40281d4441df5849e445726e369006d2b117710b33fe"}, + {file = "coverage-7.14.0-cp313-cp313-win32.whl", hash = "sha256:fb609b3658479e33f9516d46f1a89dbb9b6c261366e3a11844a96ec487533dae"}, + {file = "coverage-7.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:0773d8329cf32b6fd222e4b52622c61fe8d503eb966cfc8d3c3c10c96266d50e"}, + {file = "coverage-7.14.0-cp313-cp313-win_arm64.whl", hash = "sha256:b4e26a0f1b696faf283bffe5b8569e44e336c582439df5d53281ab89ee0cba96"}, + {file = "coverage-7.14.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:953f521ca9445300397e65fda3dca58b2dbd68fee983777420b57ac3c77e9f90"}, + {file = "coverage-7.14.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:98af83fd65ae24b1fdd03aaead967a9f523bcd2f1aab2d4f3ffda65bb568a6f1"}, + {file = "coverage-7.14.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:668b92e6958c4db7cf92e81caac328dfbbdbb215db2850ad28f0cbe1eea0bfbd"}, + {file = "coverage-7.14.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9fbd898551762dea00d3fef2b1c4f99afd2c6a3ff952ea07d60a9bd5ed4f34bc"}, + {file = "coverage-7.14.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:68af363c07ecd8d4b7d4043d85cb376d7d227eceb54e5323ee45da73dbd3e426"}, + {file = "coverage-7.14.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6e57054a583da8ac55edf24117ea4c9133032cfc4cf72aa2d48c1e5d4b52f899"}, + {file = "coverage-7.14.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cc3499459bbcdd51a65b64c35ab7ed2764eaf3cba826e0df3f1d7fe2e102b70b"}, + {file = "coverage-7.14.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:45899ec2138a4346ed34d601dedf5076fb74edf2d1dd9dc76a78e82397edee90"}, + {file = "coverage-7.14.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8767486808c436f05b23ab98eb963fb29185e32a9357a166971685cb3459900f"}, + {file = "coverage-7.14.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:a3b5ddfd6aa7ddad53ee3edb231e88a2151507a43229b7d71b953916deca127d"}, + {file = "coverage-7.14.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:63df0fe568e698e1045792399f8ab6da3a6c2dce3182813fb92afa2641087b47"}, + {file = "coverage-7.14.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:827d6397dbd95144939b18f89edf31f63e1f99633e8d5f32f22ba8bdda567477"}, + {file = "coverage-7.14.0-cp313-cp313t-win32.whl", hash = "sha256:7bf43e000d24012599b879791cff41589af90674722421ef11b11a5431920bab"}, + {file = "coverage-7.14.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3f5549365af25d770e06b1f8f5682d9a5637d06eb494db91c6fa75d3950cc917"}, + {file = "coverage-7.14.0-cp313-cp313t-win_arm64.whl", hash = "sha256:6d160217ec6fe890f16ad3a9531761589443749e448f91986c972714fad361c8"}, + {file = "coverage-7.14.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:9aed9fa983514ca032790f3fe0d1c0e42ca7e16b42432af1706b50a9a46bef5d"}, + {file = "coverage-7.14.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ba3b8390db29296dbbf49e91b6fe08f990743a90c8f447ba4c2ffc29670dfa63"}, + {file = "coverage-7.14.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3a5d8e876dfa2f102e970b183863d6dedd023d3c0eeca1fe7a9787bc5f28b212"}, + {file = "coverage-7.14.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5ebb8f4614a3787d567e610bbfdf96a4798dd69a1afb1bd8ad228d4111fe6ff3"}, + {file = "coverage-7.14.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b9bf47223dd8db3d4c4b2e443b02bace480d428f0822c3f991600448a176c97"}, + {file = "coverage-7.14.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3485a836550b303d006d57cc06e3d5afaabc642c77050b7c985a97b13e3776b8"}, + {file = "coverage-7.14.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3e7e88110bae996d199d1693ca8ec3fd52441d426401ae963437598667b4c5eb"}, + {file = "coverage-7.14.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:15228a6800ce7bdf1b74800595e56db7138cecb338fdbf044806e10dcf182dfe"}, + {file = "coverage-7.14.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:9d26ac7f5398bafc5b57421ad994e8a4749e8a7a0e62d05ec7d53014d5963bfa"}, + {file = "coverage-7.14.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2fb73254ff43c911c967a899e1359bc5049b4b115d6e8fbdde4937d0a2246cd5"}, + {file = "coverage-7.14.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:454a380af72c6adada298ed270d38c7a391288198dbfb8467f786f588751a90c"}, + {file = "coverage-7.14.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:65c86fb646d2bd2972e96bd1a8b45817ed907cee68655d6295fe7ec031d04cca"}, + {file = "coverage-7.14.0-cp314-cp314-win32.whl", hash = "sha256:6a6516b02a6101398e19a3f44820f69bab2590697f7def4331f668b14adaf828"}, + {file = "coverage-7.14.0-cp314-cp314-win_amd64.whl", hash = "sha256:45e0f79d8351fa76e256716df91eab12890d32678b9590df7ae1042e4bd4cf5d"}, + {file = "coverage-7.14.0-cp314-cp314-win_arm64.whl", hash = "sha256:4b899594a8b2d81e5cc064a0d7f9cac2081fed91049456cae7676787e41549c9"}, + {file = "coverage-7.14.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:f580f8c80acd94ac72e863efe2cab791d8c38d153e0b463b92dfa000d5c84cd1"}, + {file = "coverage-7.14.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a2bd259c442cd43c49b30fbafc51776eb19ea396faf159d26a83e6a0a5f13b0c"}, + {file = "coverage-7.14.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a706b908dfa85538863504c624b237a3cc34232bf403c057414ebfdb3b4d9f84"}, + {file = "coverage-7.14.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7333cd944ee4393b9b3d3c1b598c936d4fc8d70573a4c7dacfec5590dd50e436"}, + {file = "coverage-7.14.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f162bc9a15b82d947b02651b0c7e1609d6f7a8735ca330cfadec8481dd97d5a"}, + {file = "coverage-7.14.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:362cb78e01a5dc82009d88004cf60f2e6b6d6fcbfdec05b05af73b0abf40118f"}, + {file = "coverage-7.14.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:acebd068fca5512c3a6fde9c045f901613478781a73f0e82b307b214daef23fb"}, + {file = "coverage-7.14.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:29fe3da551dface75deb2ccbf87b6b66e2e7ef38f6d89050b428be94afff3490"}, + {file = "coverage-7.14.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b4cc4fce8672fffcb09b0eafc167b396b3ba53c4a7230f54b7aaffbf6c835fa9"}, + {file = "coverage-7.14.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:5d4a51aad8ba8bdcd2b8bd8f03d4aca19693fa2327a3470e4718a25b03481020"}, + {file = "coverage-7.14.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:9f323af3e1e4f68b60b7b247e37b8515563a61375518fa59de1af48ba28a3db6"}, + {file = "coverage-7.14.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:1a0abc7342ea9711c469dd8b821c6c311e6bc6aac1442e5fbd6b27fae0a8f3db"}, + {file = "coverage-7.14.0-cp314-cp314t-win32.whl", hash = "sha256:a9f864ef57b7172e2db87a096642dd51e179e085ab6b2c371c29e885f65c8fb2"}, + {file = "coverage-7.14.0-cp314-cp314t-win_amd64.whl", hash = "sha256:29943e552fdc08e082eb51400fb2f58e118a83b5542bd06531214e084399b644"}, + {file = "coverage-7.14.0-cp314-cp314t-win_arm64.whl", hash = "sha256:742a73ea621953b012f2c4c2219b512180dd84489acf5b1596b0aafc55b9100b"}, + {file = "coverage-7.14.0-py3-none-any.whl", hash = "sha256:8de5b61163aee3d05c8a2beab6f47913df7981dad1baf82c414d99158c286ab1"}, + {file = "coverage-7.14.0.tar.gz", hash = "sha256:057a6af2f160a85384cde4ab36f0d2777bae1057bae255f95413cdd382aa5c74"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli ; python_full_version <= \"3.11.0a6\""] + +[[package]] +name = "django" +version = "3.0" +description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design." +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "Django-3.0-py3-none-any.whl", hash = "sha256:6f857bd4e574442ba35a7172f1397b303167dae964cf18e53db5e85fe248d000"}, + {file = "Django-3.0.tar.gz", hash = "sha256:d98c9b6e5eed147bc51f47c014ff6826bd1ab50b166956776ee13db5a58804ae"}, +] + +[package.dependencies] +asgiref = ">=3.2,<4.0" +pytz = "*" +sqlparse = ">=0.2.2" + +[package.extras] +argon2 = ["argon2-cffi (>=16.1.0)"] +bcrypt = ["bcrypt"] + +[[package]] +name = "entrypoints" +version = "0.3" +description = "Discover and load entry points from installed packages." +optional = false +python-versions = ">=2.7" +groups = ["main"] +files = [ + {file = "entrypoints-0.3-py2.py3-none-any.whl", hash = "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19"}, + {file = "entrypoints-0.3.tar.gz", hash = "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.3.1" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +groups = ["main"] +markers = "python_version == \"3.10\"" +files = [ + {file = "exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598"}, + {file = "exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "flake8" +version = "3.7.0" +description = "the modular source code checker: pep8, pyflakes and co" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main"] +files = [ + {file = "flake8-3.7.0-py2.py3-none-any.whl", hash = "sha256:7eda8e5c29ac9e0d3c0fd44649298c29768efc79a9b872b41c8f05ca5f502c83"}, + {file = "flake8-3.7.0.tar.gz", hash = "sha256:2baac1c277d917f3e01ce17a60dcfad4a4ce13a2c5d50a15d0811302a3bdf7aa"}, +] + +[package.dependencies] +entrypoints = ">=0.3.0,<0.4.0" +mccabe = ">=0.6.0,<0.7.0" +pycodestyle = ">=2.5.0,<2.6.0" +pyflakes = ">=2.1.0,<2.2.0" + +[[package]] +name = "flake8-html" +version = "0.4.3" +description = "Generate HTML reports of flake8 violations" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "flake8-html-0.4.3.tar.gz", hash = "sha256:8b870299620cc4a06f73644a1b4d457799abeca1cc914c62ae71ec5bf65c79a5"}, + {file = "flake8_html-0.4.3-py2.py3-none-any.whl", hash = "sha256:8f126748b1b0edd6cd39e87c6192df56e2f8655b0aa2bb00ffeac8cf27be4325"}, +] + +[package.dependencies] +flake8 = ">=3.3.0" +jinja2 = ">=3.1.0" +pygments = ">=2.2.0" + +[[package]] +name = "iniconfig" +version = "2.3.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"}, + {file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"}, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, + {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "markupsafe" +version = "3.0.3" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559"}, + {file = "markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1"}, + {file = "markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa"}, + {file = "markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8"}, + {file = "markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1"}, + {file = "markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad"}, + {file = "markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a"}, + {file = "markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19"}, + {file = "markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01"}, + {file = "markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c"}, + {file = "markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e"}, + {file = "markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b"}, + {file = "markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d"}, + {file = "markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c"}, + {file = "markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f"}, + {file = "markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795"}, + {file = "markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12"}, + {file = "markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed"}, + {file = "markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5"}, + {file = "markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485"}, + {file = "markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73"}, + {file = "markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287"}, + {file = "markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe"}, + {file = "markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe"}, + {file = "markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9"}, + {file = "markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581"}, + {file = "markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4"}, + {file = "markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab"}, + {file = "markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa"}, + {file = "markupsafe-3.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26"}, + {file = "markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d"}, + {file = "markupsafe-3.0.3-cp39-cp39-win32.whl", hash = "sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7"}, + {file = "markupsafe-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e"}, + {file = "markupsafe-3.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8"}, + {file = "markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698"}, +] + +[[package]] +name = "mccabe" +version = "0.6.1" +description = "McCabe checker, plugin for flake8" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, + {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, +] + +[[package]] +name = "packaging" +version = "26.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e"}, + {file = "packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661"}, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, + {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["coverage", "pytest", "pytest-benchmark"] + +[[package]] +name = "pycodestyle" +version = "2.5.0" +description = "Python style guide checker" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main"] +files = [ + {file = "pycodestyle-2.5.0-py2.py3-none-any.whl", hash = "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56"}, + {file = "pycodestyle-2.5.0.tar.gz", hash = "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"}, +] + +[[package]] +name = "pyflakes" +version = "2.1.1" +description = "passive checker of Python programs" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main"] +files = [ + {file = "pyflakes-2.1.1-py2.py3-none-any.whl", hash = "sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0"}, + {file = "pyflakes-2.1.1.tar.gz", hash = "sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"}, +] + +[[package]] +name = "pygments" +version = "2.20.0" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176"}, + {file = "pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pytest" +version = "9.0.3" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9"}, + {file = "pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c"}, +] + +[package.dependencies] +colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1", markers = "python_version < \"3.11\""} +iniconfig = ">=1.0.1" +packaging = ">=22" +pluggy = ">=1.5,<2" +pygments = ">=2.7.2" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-cov" +version = "7.1.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678"}, + {file = "pytest_cov-7.1.0.tar.gz", hash = "sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2"}, +] + +[package.dependencies] +coverage = {version = ">=7.10.6", extras = ["toml"]} +pluggy = ">=1.2" +pytest = ">=7" + +[package.extras] +testing = ["process-tests", "pytest-xdist", "virtualenv"] + +[[package]] +name = "pytest-django" +version = "4.12.0" +description = "A Django plugin for pytest." +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "pytest_django-4.12.0-py3-none-any.whl", hash = "sha256:3ff300c49f8350ba2953b90297d23bf5f589db69545f56f1ec5f8cff5da83e85"}, + {file = "pytest_django-4.12.0.tar.gz", hash = "sha256:df94ec819a83c8979c8f6de13d9cdfbe76e8c21d39473cfe2b40c9fc9be3c758"}, +] + +[package.dependencies] +pytest = ">=7.0.0" + +[[package]] +name = "pytz" +version = "2026.2" +description = "World timezone definitions, modern and historical" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "pytz-2026.2-py2.py3-none-any.whl", hash = "sha256:04156e608bee23d3792fd45c94ae47fae1036688e75032eea2e3bf0323d1f126"}, + {file = "pytz-2026.2.tar.gz", hash = "sha256:0e60b47b29f21574376f218fe21abc009894a2321ea16c6754f3cad6eb7cdd6a"}, +] + +[[package]] +name = "six" +version = "1.17.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main"] +files = [ + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, +] + +[[package]] +name = "sqlparse" +version = "0.5.5" +description = "A non-validating SQL parser." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba"}, + {file = "sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e"}, +] + +[package.extras] +dev = ["build"] +doc = ["sphinx"] + +[[package]] +name = "tomli" +version = "2.4.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_full_version <= \"3.11.0a6\"" +files = [ + {file = "tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30"}, + {file = "tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a"}, + {file = "tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076"}, + {file = "tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9"}, + {file = "tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c"}, + {file = "tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc"}, + {file = "tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049"}, + {file = "tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e"}, + {file = "tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece"}, + {file = "tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a"}, + {file = "tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085"}, + {file = "tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9"}, + {file = "tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5"}, + {file = "tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585"}, + {file = "tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1"}, + {file = "tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917"}, + {file = "tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9"}, + {file = "tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257"}, + {file = "tomli-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54"}, + {file = "tomli-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a"}, + {file = "tomli-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897"}, + {file = "tomli-2.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f"}, + {file = "tomli-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d"}, + {file = "tomli-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5"}, + {file = "tomli-2.4.1-cp313-cp313-win32.whl", hash = "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd"}, + {file = "tomli-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36"}, + {file = "tomli-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd"}, + {file = "tomli-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf"}, + {file = "tomli-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac"}, + {file = "tomli-2.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662"}, + {file = "tomli-2.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853"}, + {file = "tomli-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15"}, + {file = "tomli-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba"}, + {file = "tomli-2.4.1-cp314-cp314-win32.whl", hash = "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6"}, + {file = "tomli-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7"}, + {file = "tomli-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232"}, + {file = "tomli-2.4.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4"}, + {file = "tomli-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c"}, + {file = "tomli-2.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d"}, + {file = "tomli-2.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41"}, + {file = "tomli-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c"}, + {file = "tomli-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f"}, + {file = "tomli-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8"}, + {file = "tomli-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26"}, + {file = "tomli-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396"}, + {file = "tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe"}, + {file = "tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f"}, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +description = "Backported and Experimental Type Hints for Python 3.9+" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version == \"3.10\"" +files = [ + {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, + {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, +] + +[metadata] +lock-version = "2.1" +python-versions = ">=3.10" +content-hash = "aba3a85d7357ee7fc4f75d00fc36b305c285708e47cafb8470ae67bbf1a54ddd" diff --git a/profiles/tests.py b/profiles/tests.py deleted file mode 100644 index 8aa3d58736..0000000000 --- a/profiles/tests.py +++ /dev/null @@ -1,6 +0,0 @@ -""" -Tests module for profiles app -""" -from django.test import TestCase - -# Create your tests here. diff --git a/profiles/tests/__init__.py b/profiles/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/profiles/tests/conftest.py b/profiles/tests/conftest.py new file mode 100644 index 0000000000..003e1f0807 --- /dev/null +++ b/profiles/tests/conftest.py @@ -0,0 +1,22 @@ +import pytest + +from django.contrib.auth.models import User + +from profiles.models import Profile + + +@pytest.fixture +def get_profile(): + """ + Fixture that returns fictive profile + Returns: + The profile object + """ + return Profile.objects.create( + user=User.objects.create_user(username='Username', + first_name='First', + last_name='Last', + email='test@test.com', + password='test_pwd'), + favorite_city="City Test" + ) diff --git a/profiles/tests/tests.py b/profiles/tests/tests.py new file mode 100644 index 0000000000..dc7cb0d955 --- /dev/null +++ b/profiles/tests/tests.py @@ -0,0 +1,135 @@ +""" +Tests module for profiles app +""" +import pytest + +from django.contrib.auth.models import User +from django.urls import reverse, resolve +from django.test import Client +from pytest_django.asserts import assertTemplateUsed +from _pytest.monkeypatch import MonkeyPatch + +from profiles.models import Profile + + +class TestProfilesUrl: + def test_profiles_index_url(self): + path = reverse("profiles:index") + + assert path == "/profiles/" + assert resolve(path).view_name == 'profiles:index' + + @pytest.mark.django_db + def test_profiles_profile_url(self): + Profile.objects.create(user=User.objects.create_user(username="Username", + first_name='First Name', + last_name='Last Name', + email='test@test.com'), + favorite_city="Paris") + + path = reverse(viewname="profiles:profile", kwargs={'username': "Username"}) + + assert path == "/profiles/Username/" + assert resolve(path).view_name == "profiles:profile" + + +class TestProfilesView: + @pytest.mark.django_db + def test_profiles_index_view_ok(self, get_profile: Profile): + client = Client() + path = reverse(viewname="profiles:index") + + response = client.get(path=path) + content = response.content.decode() + expected_h1 = '

Profiles

' + expected_content = (f'' + f'{get_profile.user.username}') + + assert expected_h1 in content + assert expected_content in content + assert response.status_code == 200 + assertTemplateUsed(response, template_name="profiles/index.html") + + @pytest.mark.django_db + def test_profiles_index_view_returns_500(self, monkeypatch: MonkeyPatch, get_profile: Profile): + def raise_error(): + raise Exception("forced error") + + monkeypatch.setattr("profiles.views.Profile.objects.all", raise_error) + + client = Client() + path = reverse(viewname="profiles:index") + + response = client.get(path=path) + content = response.content.decode() + expected_h1 = (f'

500 Error : ' + f'something wrong with the server - forced error

') + + assert expected_h1 in content + assert response.status_code == 500 + assertTemplateUsed(response, template_name="error_500.html") + + @pytest.mark.django_db + def test_profiles_profile_view_ok(self, get_profile: Profile): + client = Client() + path = reverse(viewname="profiles:profile", kwargs={"username": get_profile.user.username}) + + response = client.get(path=path) + content = response.content.decode() + expected_h1 = (f'

' + f'{get_profile.user.username}

') + expected_content = (f'

First name : {get_profile.user.first_name}' + f'

\n\t\t\t' + f'

Last name : {get_profile.user.last_name}' + f'

\n\t\t\t' + f'

Email : {get_profile.user.email}

\n\t\t\t' + f'

Favorite city : {get_profile.favorite_city}

') + + assert expected_h1 in content + assert expected_content in content + assert response.status_code == 200 + assertTemplateUsed(response, template_name="profiles/profile.html") + + @pytest.mark.django_db + def test_profiles_profile_view_returns_404(self, get_profile: Profile): + client = Client() + path = reverse(viewname="profiles:profile", kwargs={"username": "test"}) + + response = client.get(path=path) + content = response.content.decode() + + expected_h1 = (f'

404 Error : ' + f'profile \'test\' not found !

') + + assert expected_h1 in content + assert response.status_code == 404 + assertTemplateUsed(response, template_name="error_404.html") + + @pytest.mark.django_db + def test_profiles_profile_view_returns_500(self, + monkeypatch: MonkeyPatch, + get_profile: Profile): + def raise_error(*args, **kwargs): + raise Exception("forced error") + + monkeypatch.setattr("profiles.views.Profile.objects.get", raise_error) + + client = Client() + path = reverse(viewname="profiles:profile", kwargs={"username": get_profile.user.username}) + + response = client.get(path=path) + content = response.content.decode() + expected_h1 = (f'

500 Error : ' + f'something wrong with the server - forced error

') + + assert expected_h1 in content + assert response.status_code == 500 + assertTemplateUsed(response, template_name="error_500.html") + + +class TestProfilesModel: + @pytest.mark.django_db + def test_profiles_profile_model_ok(self, get_profile: Profile): + expected = f"{get_profile.user.username}" + + assert str(get_profile) == expected diff --git a/profiles/views.py b/profiles/views.py index 0fd413dc80..7e6b705c5a 100644 --- a/profiles/views.py +++ b/profiles/views.py @@ -22,11 +22,11 @@ def index(request: HttpRequest) -> HttpResponse: try: profiles_list = Profile.objects.all() context = {'profiles_list': profiles_list} - return render(request, 'profiles/index.html', context) + return render(request, template_name='profiles/index.html', context=context, status=200) except Exception as e: context = {"error": str(e)} - return render(request, 'error_500.html', context=context) + return render(request, template_name='error_500.html', context=context, status=500) # Aliquam sed metus eget nisi tincidunt ornare accumsan eget lac @@ -48,12 +48,12 @@ def profile(request: HttpRequest, username: str): profile = Profile.objects.get(user__username=username) context = {'profile': profile} - return render(request, 'profiles/profile.html', context) + return render(request, template_name='profiles/profile.html', context=context, status=200) except Profile.DoesNotExist: context = {"type": "profile", "name": username} - return render(request, 'error_404.html', context=context) + return render(request, template_name='error_404.html', context=context, status=404) except Exception as e: context = {"error": str(e)} - return render(request, 'error_500.html', context=context) + return render(request, template_name='error_500.html', context=context, status=500) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000000..c09ccec3ab --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,23 @@ +[project] +name = "openclassrooms-project-13" +version = "0.1.0" +description = "" +authors = [ + {name = "NM",email = "nicolas.marie.nm@gmail.com"} +] +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + "django (==3.0)", + "flake8 (==3.7.0)", + "flake8-html (==0.4.3)", + "pytest (==9.0.3)", + "pytest-django (==4.12.0)", + "pytest-cov (==7.1.0)", + "six (==1.17.0)", +] + + +[build-system] +requires = ["poetry-core>=2.0.0,<3.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index 81e230b474..0000000000 --- a/pytest.ini +++ /dev/null @@ -1,4 +0,0 @@ -[pytest] -DJANGO_SETTINGS_MODULE = oc_lettings_site.settings - -python_files = test_* \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index c48c84ea409eb5d30f815c308247cfdcb2b44b99..77abd848f0d5c7971014b4b34fd4865597b6d3b4 100644 GIT binary patch literal 876 zcmZva-A=+#5QO*I#7DtE5!4IsyfQH{@c|6hQmX>BEd+dc^_$)PKw_Fh%bD5T+1dU5 zSy*kk6;@ehOS|Qn+J#Mc^m}e+mfFTXIh8GJ#Sv!=ddZphj2-b}j8F5NS(}1 zc!M+HzZkBPEG@7tYi;w(mWe_)bPtZD05xZ!260Kh%Z%n7OMBo@p Date: Wed, 20 May 2026 13:46:53 +0200 Subject: [PATCH 07/41] Modification : add monitoring with Sentry, update tests fixtures, update tests architecture, update environment variables loading with dotenv library --- .coverage | Bin 53248 -> 53248 bytes .gitignore | 5 +- config.py | 11 +++ lettings/tests/conftest.py | 13 +++ lettings/views.py | 23 +++++- manage.py | 3 + monitoring.py | 35 ++++++++ oc_lettings_site/tests/__init__.py | 0 oc_lettings_site/tests/conftest.py | 14 ++++ oc_lettings_site/{ => tests}/tests.py | 0 oc_lettings_site/views.py | 9 +++ poetry.lock | 111 +++++++++++++++++++++++++- profiles/tests/conftest.py | 12 +++ profiles/views.py | 22 ++++- pyproject.toml | 2 + requirements.txt | Bin 876 -> 1032 bytes 16 files changed, 254 insertions(+), 6 deletions(-) create mode 100644 config.py create mode 100644 monitoring.py create mode 100644 oc_lettings_site/tests/__init__.py create mode 100644 oc_lettings_site/tests/conftest.py rename oc_lettings_site/{ => tests}/tests.py (100%) diff --git a/.coverage b/.coverage index bd43345db0dc8d97108ca92cbca36692265a5511..8692df254ad1cdbe065296cdb43d50e0cb64c3b2 100644 GIT binary patch delta 100 zcmZozz}&Eac>`O6&|C)oPy8?Wuk)YdKg7SCe;xna&4L20{DS-(ER38A97T=|t5pRW zRxeeZys=+Ior@JHD#o&jfpMKGI}4C4z?@Vozzk$4v26k=WnkJ6?CrhzWxu!s0Qq(t AH2?qr delta 110 zcmZozz}&Eac>`O6&>{x@Py8?WZ}MN@Kgz$0e!W{RuGfL$e}@&odqP#oK(xl3}nc$fwVC&ZFtSM`DMSj F0{~f=8fyRm diff --git a/.gitignore b/.gitignore index e88dc89017..afbe75074a 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,7 @@ oc-lettings-site_old.sqlite3 # Reports flake8-report -cov_html \ No newline at end of file +cov_html + +# .env file +.env \ No newline at end of file diff --git a/config.py b/config.py new file mode 100644 index 0000000000..097854e7fc --- /dev/null +++ b/config.py @@ -0,0 +1,11 @@ +""" +Config module for environment variables +""" +import os + +from dotenv import load_dotenv + + +load_dotenv() + +SENTRY_KEY = os.getenv("SENTRY_KEY") diff --git a/lettings/tests/conftest.py b/lettings/tests/conftest.py index dac565b32f..66ffe3eac4 100644 --- a/lettings/tests/conftest.py +++ b/lettings/tests/conftest.py @@ -1,8 +1,21 @@ +""" +Fixture module for lettings tests +""" import pytest +from _pytest.monkeypatch import MonkeyPatch + from lettings.models import Address, Letting +@pytest.fixture(autouse=True) +def disable_sentry(monkeypatch: MonkeyPatch): + monkeypatch.setattr( + "monitoring.sentry_sdk.init", + lambda *args, **kwargs: None + ) + + @pytest.fixture def get_address(): """ diff --git a/lettings/views.py b/lettings/views.py index f7b0015b33..2536865100 100644 --- a/lettings/views.py +++ b/lettings/views.py @@ -5,6 +5,7 @@ from django.shortcuts import render from .models import Letting +from monitoring import logger # Aenean leo magna, vestibulum et tincidunt fermentum, consectetur quis velit. Sed non placerat @@ -22,10 +23,17 @@ def index(request: HttpRequest) -> HttpResponse: try: lettings_list = Letting.objects.all() context = {'lettings_list': lettings_list} + + logger.info(f"Going to lettings index page : {context=}, status = 200.") + return render(request, template_name='lettings/index.html', context=context, status=200) except Exception as e: context = {"error": str(e)} + + logger.error(f"Error 500 returned while reaching lettings index page : {context=}," + f" status = 500.") + return render(request, template_name='error_500.html', context=context, status=500) @@ -56,12 +64,23 @@ def letting(request: HttpRequest, letting_id: int) -> HttpResponse: 'title': letting.title, 'address': letting.address, } + + logger.info(f"Going to lettings details page : {context=}, status = 200.") + return render(request, template_name='lettings/letting.html', context=context, status=200) - except Letting.DoesNotExist: - context = {"type": "letting", "id": letting_id} + except Letting.DoesNotExist as e: + context = {"type": "letting", "id": letting_id, "error": str(e)} + + logger.warning(f"Error 404 returned while reaching letting n°{letting_id} : {context=}," + f" status = 404.") + return render(request, template_name='error_404.html', context=context, status=404) except Exception as e: context = {"error": str(e)} + + logger.error(f"Error 500 returned while reaching letting details page : {context=}," + f" status = 500.") + return render(request, template_name='error_500.html', context=context, status=500) diff --git a/manage.py b/manage.py index c0e27e034a..961c945a68 100755 --- a/manage.py +++ b/manage.py @@ -1,3 +1,6 @@ +""" +Main module +""" import os import sys diff --git a/monitoring.py b/monitoring.py new file mode 100644 index 0000000000..309dd0ca46 --- /dev/null +++ b/monitoring.py @@ -0,0 +1,35 @@ +""" +Module for monitoring with Sentry +""" +import logging +import sentry_sdk + +from sentry_sdk.integrations.logging import LoggingIntegration + +from config import SENTRY_KEY + +logger = logging.getLogger(__name__) + + +def init_sentry(): + """ + Method to initialize sentry integration + """ + logging.basicConfig(level=logging.INFO) + + sentry_logging = LoggingIntegration( + level=logging.INFO, + event_level=logging.ERROR, + ) + + sentry_sdk.init( + dsn=SENTRY_KEY, + # Add request headers and IP for users, + # see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info + send_default_pii=True, + + # Enable logs to be sent to Sentry + enable_logs=True, + + integrations=[sentry_logging] + ) diff --git a/oc_lettings_site/tests/__init__.py b/oc_lettings_site/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/oc_lettings_site/tests/conftest.py b/oc_lettings_site/tests/conftest.py new file mode 100644 index 0000000000..943f1fbb0b --- /dev/null +++ b/oc_lettings_site/tests/conftest.py @@ -0,0 +1,14 @@ +""" +Fixture module for oc_lettings_site tests +""" +import pytest + +from _pytest.monkeypatch import MonkeyPatch + + +@pytest.fixture(autouse=True) +def disable_sentry(monkeypatch: MonkeyPatch): + monkeypatch.setattr( + "monitoring.sentry_sdk.init", + lambda *args, **kwargs: None + ) diff --git a/oc_lettings_site/tests.py b/oc_lettings_site/tests/tests.py similarity index 100% rename from oc_lettings_site/tests.py rename to oc_lettings_site/tests/tests.py diff --git a/oc_lettings_site/views.py b/oc_lettings_site/views.py index ec37ad70d0..12b562c384 100644 --- a/oc_lettings_site/views.py +++ b/oc_lettings_site/views.py @@ -4,6 +4,8 @@ from django.http import HttpRequest, HttpResponse from django.shortcuts import render +from monitoring import init_sentry, logger + # Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque molestie quam lobortis leo # consectetur ullamcorper non id est. Praesent dictum, nulla eget feugiat sagittis, sem mi @@ -20,9 +22,16 @@ def index(request: HttpRequest) -> HttpResponse: Returns: An HTTP response with index page or HTTP response with 500 error. """ + init_sentry() try: + logger.info(f"Going to home page : status = 200.") + return render(request, template_name='index.html') except Exception as e: context = {'error': str(e)} + + logger.error(f"Error 500 returned while reaching home page : {context=}" + f", status = 500.") + return render(request, template_name='error_500.html', context=context) diff --git a/poetry.lock b/poetry.lock index 59b81c4412..222502339e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -18,6 +18,18 @@ typing_extensions = {version = ">=4", markers = "python_version < \"3.11\""} [package.extras] tests = ["mypy (>=1.14.0)", "pytest", "pytest-asyncio"] +[[package]] +name = "certifi" +version = "2026.4.22" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "certifi-2026.4.22-py3-none-any.whl", hash = "sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a"}, + {file = "certifi-2026.4.22.tar.gz", hash = "sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580"}, +] + [[package]] name = "colorama" version = "0.4.6" @@ -507,6 +519,21 @@ files = [ [package.dependencies] pytest = ">=7.0.0" +[[package]] +name = "python-dotenv" +version = "1.2.2" +description = "Read key-value pairs from a .env file and set them as environment variables" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a"}, + {file = "python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3"}, +] + +[package.extras] +cli = ["click (>=5.0)"] + [[package]] name = "pytz" version = "2026.2" @@ -519,6 +546,70 @@ files = [ {file = "pytz-2026.2.tar.gz", hash = "sha256:0e60b47b29f21574376f218fe21abc009894a2321ea16c6754f3cad6eb7cdd6a"}, ] +[[package]] +name = "sentry-sdk" +version = "2.60.0" +description = "Python client for Sentry (https://sentry.io)" +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "sentry_sdk-2.60.0-py3-none-any.whl", hash = "sha256:28a536c03291c8bcb363cf35c611b32738ec118ff64d8d6383b096448ac4c803"}, + {file = "sentry_sdk-2.60.0.tar.gz", hash = "sha256:0bd25e54e78ca02d0be512529fa644bbbf9e8470d7b26371294012d4ca93c978"}, +] + +[package.dependencies] +certifi = "*" +urllib3 = ">=1.26.11" + +[package.extras] +aiohttp = ["aiohttp (>=3.5)"] +anthropic = ["anthropic (>=0.16)"] +arq = ["arq (>=0.23)"] +asyncio = ["httpcore[asyncio] (==1.*)"] +asyncpg = ["asyncpg (>=0.23)"] +beam = ["apache-beam (>=2.12)"] +bottle = ["bottle (>=0.12.13)"] +celery = ["celery (>=3)"] +celery-redbeat = ["celery-redbeat (>=2)"] +chalice = ["chalice (>=1.16.0)"] +clickhouse-driver = ["clickhouse-driver (>=0.2.0)"] +django = ["django (>=1.8)"] +falcon = ["falcon (>=1.4)"] +fastapi = ["fastapi (>=0.79.0)"] +flask = ["blinker (>=1.1)", "flask (>=0.11)", "markupsafe"] +google-genai = ["google-genai (>=1.29.0)"] +grpcio = ["grpcio (>=1.21.1)", "protobuf (>=3.8.0)"] +http2 = ["httpcore[http2] (==1.*)"] +httpx = ["httpx (>=0.16.0)"] +huey = ["huey (>=2)"] +huggingface-hub = ["huggingface_hub (>=0.22)"] +langchain = ["langchain (>=0.0.210)"] +langgraph = ["langgraph (>=0.6.6)"] +launchdarkly = ["launchdarkly-server-sdk (>=9.8.0)"] +litellm = ["litellm (>=1.77.5,!=1.82.7,!=1.82.8)"] +litestar = ["litestar (>=2.0.0)"] +loguru = ["loguru (>=0.5)"] +mcp = ["mcp (>=1.15.0)"] +openai = ["openai (>=1.0.0)", "tiktoken (>=0.3.0)"] +openfeature = ["openfeature-sdk (>=0.7.1)"] +opentelemetry = ["opentelemetry-distro (>=0.35b0)"] +opentelemetry-experimental = ["opentelemetry-distro"] +opentelemetry-otlp = ["opentelemetry-distro[otlp] (>=0.35b0)"] +pure-eval = ["asttokens", "executing", "pure_eval"] +pydantic-ai = ["pydantic-ai (>=1.0.0)"] +pymongo = ["pymongo (>=3.1)"] +pyspark = ["pyspark (>=2.4.4)"] +quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] +rq = ["rq (>=0.6)"] +sanic = ["sanic (>=0.8)"] +sqlalchemy = ["sqlalchemy (>=1.2)"] +starlette = ["starlette (>=0.19.1)"] +starlite = ["starlite (>=1.48)"] +statsig = ["statsig (>=0.55.3)"] +tornado = ["tornado (>=6)"] +unleash = ["UnleashClient (>=6.0.1)"] + [[package]] name = "six" version = "1.17.0" @@ -618,7 +709,25 @@ files = [ {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, ] +[[package]] +name = "urllib3" +version = "2.7.0" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897"}, + {file = "urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c"}, +] + +[package.extras] +brotli = ["brotli (>=1.2.0) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=1.2.0.0) ; platform_python_implementation != \"CPython\""] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["backports-zstd (>=1.0.0) ; python_version < \"3.14\""] + [metadata] lock-version = "2.1" python-versions = ">=3.10" -content-hash = "aba3a85d7357ee7fc4f75d00fc36b305c285708e47cafb8470ae67bbf1a54ddd" +content-hash = "6e2f2adfbc0ae06398494a726625a155716005abb006e86c1ed008ddd97cbbab" diff --git a/profiles/tests/conftest.py b/profiles/tests/conftest.py index 003e1f0807..f6addc0755 100644 --- a/profiles/tests/conftest.py +++ b/profiles/tests/conftest.py @@ -1,10 +1,22 @@ +""" +Fixture module for profiles tests +""" import pytest +from _pytest.monkeypatch import MonkeyPatch from django.contrib.auth.models import User from profiles.models import Profile +@pytest.fixture(autouse=True) +def disable_sentry(monkeypatch: MonkeyPatch): + monkeypatch.setattr( + "monitoring.sentry_sdk.init", + lambda *args, **kwargs: None + ) + + @pytest.fixture def get_profile(): """ diff --git a/profiles/views.py b/profiles/views.py index 7e6b705c5a..e6b3d808f0 100644 --- a/profiles/views.py +++ b/profiles/views.py @@ -3,6 +3,7 @@ """ from django.http import HttpRequest, HttpResponse from django.shortcuts import render +from monitoring import logger from profiles.models import Profile @@ -22,10 +23,17 @@ def index(request: HttpRequest) -> HttpResponse: try: profiles_list = Profile.objects.all() context = {'profiles_list': profiles_list} + + logger.info(f"Going to profiles index page : {context=}, status = 200.") + return render(request, template_name='profiles/index.html', context=context, status=200) except Exception as e: context = {"error": str(e)} + + logger.error(f"Error 500 returned while reaching profiles index page : {context=}" + f", status = 500.") + return render(request, template_name='error_500.html', context=context, status=500) @@ -48,12 +56,22 @@ def profile(request: HttpRequest, username: str): profile = Profile.objects.get(user__username=username) context = {'profile': profile} + logger.info(f"Going to profile details page : {context=}, status = 200.") + return render(request, template_name='profiles/profile.html', context=context, status=200) - except Profile.DoesNotExist: - context = {"type": "profile", "name": username} + except Profile.DoesNotExist as e: + context = {"type": "profile", "name": username, "error": str(e)} + + logger.warning(f"Error 404 returned while reaching profile {username} : {context=}," + f" status = 404.") + return render(request, template_name='error_404.html', context=context, status=404) except Exception as e: context = {"error": str(e)} + + logger.error(f"Error 500 returned while reaching profile details page : {context=}," + f" status = 500.") + return render(request, template_name='error_500.html', context=context, status=500) diff --git a/pyproject.toml b/pyproject.toml index c09ccec3ab..fe5853fc61 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,8 @@ dependencies = [ "pytest-django (==4.12.0)", "pytest-cov (==7.1.0)", "six (==1.17.0)", + "sentry-sdk (>=2.60.0,<3.0.0)", + "python-dotenv (>=1.2.2,<2.0.0)", ] diff --git a/requirements.txt b/requirements.txt index 77abd848f0d5c7971014b4b34fd4865597b6d3b4..66496eaeec9838bcb982b0552e721aff862c2d86 100644 GIT binary patch delta 153 zcmaFE*1<7BO)-_Bh@pfblOYX=ZGq5;!2pQO81xuSfY^w^Xruf}CdCYfe1<#*U4|4O zUBZwGWS4}o&iv$!Q`7vlNCyVDsq4@ TlOc)07_Pz`B+tOhz{LOn)Vv#4 delta 18 ZcmeC+c*8b9ZKK~JrpYqQ5|d+?djLN61|$Fg From bbd4f9630276d4e3ab2be5d9e0d7dd002d87f2fb Mon Sep 17 00:00:00 2001 From: NM Date: Wed, 20 May 2026 17:54:00 +0200 Subject: [PATCH 08/41] Modification : update tests before CI/CD pipeline --- docs/structure.png | Bin 0 -> 71943 bytes lettings/tests/tests.py | 11 ++++++----- oc_lettings_site/tests/tests.py | 5 ++--- profiles/tests/tests.py | 13 ++++++------- 4 files changed, 14 insertions(+), 15 deletions(-) create mode 100644 docs/structure.png diff --git a/docs/structure.png b/docs/structure.png new file mode 100644 index 0000000000000000000000000000000000000000..af2dd62183261d942ab30634358bdba8477d59bd GIT binary patch literal 71943 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.title}' - expected_content = (f'

{get_address.number} {get_address.street}

\n\t\t\t' - f'

{get_address.city}, {get_address.state} ' - f'{get_address.zip_code}

\n\t\t\t' - f'

{get_address.country_iso_code}

') + expected_content = [f'{get_address.number} {get_address.street}', + f'{get_address.city}, {get_address.state}', + f'{get_address.zip_code}', + f'{get_address.country_iso_code}'] assert expected_h1 in content - assert expected_content in content + for expected_child in expected_content: + assert expected_child in content assert response.status_code == 200 assertTemplateUsed(response, template_name="lettings/letting.html") diff --git a/oc_lettings_site/tests/tests.py b/oc_lettings_site/tests/tests.py index 1dcc30af82..3c297ea058 100644 --- a/oc_lettings_site/tests/tests.py +++ b/oc_lettings_site/tests/tests.py @@ -26,10 +26,9 @@ def test_oc_lettings_site_index_view_ok(self): response = client.get(path=path) content = response.content.decode() - expected_h1 = (f'

Welcome to Holiday ' - f'Homes

') + expected = "Welcome to Holiday Homes" - assert expected_h1 in content + assert expected in content assert response.status_code == 200 assertTemplateUsed(response, template_name="index.html") diff --git a/profiles/tests/tests.py b/profiles/tests/tests.py index dc7cb0d955..ddb06cbbd8 100644 --- a/profiles/tests/tests.py +++ b/profiles/tests/tests.py @@ -78,15 +78,14 @@ def test_profiles_profile_view_ok(self, get_profile: Profile): content = response.content.decode() expected_h1 = (f'

' f'{get_profile.user.username}

') - expected_content = (f'

First name : {get_profile.user.first_name}' - f'

\n\t\t\t' - f'

Last name : {get_profile.user.last_name}' - f'

\n\t\t\t' - f'

Email : {get_profile.user.email}

\n\t\t\t' - f'

Favorite city : {get_profile.favorite_city}

') + expected_content = [f'First name : {get_profile.user.first_name}', + f'Last name : {get_profile.user.last_name}', + f'Email : {get_profile.user.email}', + f'Favorite city : {get_profile.favorite_city}'] assert expected_h1 in content - assert expected_content in content + for expected_child in expected_content: + assert expected_child in content assert response.status_code == 200 assertTemplateUsed(response, template_name="profiles/profile.html") From 58fecf51a9d68af25f8a072735a7cb3e894a410e Mon Sep 17 00:00:00 2001 From: NM Date: Fri, 22 May 2026 10:59:08 +0200 Subject: [PATCH 09/41] Modification : update setup and gitignore files --- .gitignore | 4 ---- setup.cfg | 3 +-- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index afbe75074a..b96a98b209 100644 --- a/.gitignore +++ b/.gitignore @@ -13,9 +13,5 @@ env backup.sqlite3 oc-lettings-site_old.sqlite3 -# Reports -flake8-report -cov_html - # .env file .env \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index 8b4e36634a..5fb8f09adb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -7,5 +7,4 @@ exclude = **/migrations/*,env,cov_html [tool:pytest] DJANGO_SETTINGS_MODULE = oc_lettings_site.settings python_files = tests.py -addopts = -v - +addopts = -v --cov=lettings --cov=profiles --cov=oc_lettings_site --cov-report=html:cov_html From 518f4d5f9ad3255889a3abffe6a2915aee1168d3 Mon Sep 17 00:00:00 2001 From: Nicolas MARIE <63230028+Tit-Co@users.noreply.github.com> Date: Fri, 22 May 2026 20:53:06 +0200 Subject: [PATCH 10/41] File change : Create django.yml --- .github/workflows/django.yml | 49 ++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 .github/workflows/django.yml diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml new file mode 100644 index 0000000000..fd7028b5fd --- /dev/null +++ b/.github/workflows/django.yml @@ -0,0 +1,49 @@ +name: OC Lettings site CI + +on: + push: + branches: + - '**' + pull_request: + branches: + - '**' + +jobs: + ci: + + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.10] + + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + - name: Run Lint + run: | + flake8 + - name: Upload flake8 report + if: ${{ always() }} + uses: actions/upload-artifact@v4 + with: + name: flake8-report + path: flake8-report/ + retention-days: 5 + - name: Run Tests + run: | + pytest + - name: Upload coverage report + if: ${{ always() }} + uses: actions/upload-artifact@v4 + with: + name: cov_html + path: cov_html/ + retention-days: 5 + From b139986dccfaa501a94747f121db3368f4d782c3 Mon Sep 17 00:00:00 2001 From: NM Date: Fri, 22 May 2026 21:01:24 +0200 Subject: [PATCH 11/41] Modification : update yaml for CI --- .github/workflows/django.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml index fd7028b5fd..e9311d8afd 100644 --- a/.github/workflows/django.yml +++ b/.github/workflows/django.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.10] + python-version: ["3.10"] steps: - uses: actions/checkout@v4 @@ -34,7 +34,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: flake8-report - path: flake8-report/ + path: flake8-report/index.html retention-days: 5 - name: Run Tests run: | @@ -44,6 +44,6 @@ jobs: uses: actions/upload-artifact@v4 with: name: cov_html - path: cov_html/ + path: cov_html/index.html retention-days: 5 From 7ab2b81999aefdfd4505fca18a6796a3a3e5b3af Mon Sep 17 00:00:00 2001 From: NM Date: Fri, 22 May 2026 21:25:24 +0200 Subject: [PATCH 12/41] Modification : update yaml for CI --- .github/workflows/django.yml | 7 +- cov_html/.gitignore | 1 + cov_html/class_index.html | 231 +++++++ cov_html/coverage_html_cb_188fc9a4.js | 735 +++++++++++++++++++++ cov_html/favicon_32_cb_c827f16f.png | Bin 0 -> 1732 bytes cov_html/function_index.html | 271 ++++++++ cov_html/index.html | 180 +++++ cov_html/keybd_closed_cb_900cfef5.png | Bin 0 -> 9004 bytes cov_html/status.json | 1 + cov_html/style_cb_5c747636.css | 389 +++++++++++ cov_html/z_a9b1b018a4ee155b_models_py.html | 155 +++++ cov_html/z_a9b1b018a4ee155b_urls_py.html | 110 +++ cov_html/z_a9b1b018a4ee155b_views_py.html | 183 +++++ cov_html/z_b4872cbce420d762_models_py.html | 121 ++++ cov_html/z_b4872cbce420d762_urls_py.html | 110 +++ cov_html/z_b4872cbce420d762_views_py.html | 174 +++++ cov_html/z_d8907effad88fb1e_urls_py.html | 112 ++++ cov_html/z_d8907effad88fb1e_views_py.html | 134 ++++ flake8-report/back.svg | 73 ++ flake8-report/file.svg | 64 ++ flake8-report/index.html | 30 + flake8-report/styles.css | 327 +++++++++ 22 files changed, 3405 insertions(+), 3 deletions(-) create mode 100644 cov_html/.gitignore create mode 100644 cov_html/class_index.html create mode 100644 cov_html/coverage_html_cb_188fc9a4.js create mode 100644 cov_html/favicon_32_cb_c827f16f.png create mode 100644 cov_html/function_index.html create mode 100644 cov_html/index.html create mode 100644 cov_html/keybd_closed_cb_900cfef5.png create mode 100644 cov_html/status.json create mode 100644 cov_html/style_cb_5c747636.css create mode 100644 cov_html/z_a9b1b018a4ee155b_models_py.html create mode 100644 cov_html/z_a9b1b018a4ee155b_urls_py.html create mode 100644 cov_html/z_a9b1b018a4ee155b_views_py.html create mode 100644 cov_html/z_b4872cbce420d762_models_py.html create mode 100644 cov_html/z_b4872cbce420d762_urls_py.html create mode 100644 cov_html/z_b4872cbce420d762_views_py.html create mode 100644 cov_html/z_d8907effad88fb1e_urls_py.html create mode 100644 cov_html/z_d8907effad88fb1e_views_py.html create mode 100644 flake8-report/back.svg create mode 100644 flake8-report/file.svg create mode 100644 flake8-report/index.html create mode 100644 flake8-report/styles.css diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml index e9311d8afd..e228964896 100644 --- a/.github/workflows/django.yml +++ b/.github/workflows/django.yml @@ -34,7 +34,8 @@ jobs: uses: actions/upload-artifact@v4 with: name: flake8-report - path: flake8-report/index.html + path: flake8-report/ + if-no-files-found: warn retention-days: 5 - name: Run Tests run: | @@ -44,6 +45,6 @@ jobs: uses: actions/upload-artifact@v4 with: name: cov_html - path: cov_html/index.html + path: cov_html/ + if-no-files-found: warn retention-days: 5 - diff --git a/cov_html/.gitignore b/cov_html/.gitignore new file mode 100644 index 0000000000..23006f1f32 --- /dev/null +++ b/cov_html/.gitignore @@ -0,0 +1 @@ +# Created by coverage.py diff --git a/cov_html/class_index.html b/cov_html/class_index.html new file mode 100644 index 0000000000..52ccc8a9f7 --- /dev/null +++ b/cov_html/class_index.html @@ -0,0 +1,231 @@ + + + + + Coverage report + + + + + +
+
+

Coverage report: + 100% +

+ +
+ +
+ + +
+
+

+ Files + Functions + Classes +

+

+ coverage.py v7.14.0, + created at 2026-05-22 10:56 +0200 +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Fileclass statementsmissingexcluded coverage
lettings \ models.pyAddress 100 100%
lettings \ models.pyAddress.Meta 000 100%
lettings \ models.pyLetting 100 100%
lettings \ models.py(no class) 1700 100%
lettings \ urls.py(no class) 400 100%
lettings \ views.py(no class) 2800 100%
oc_lettings_site \ urls.py(no class) 400 100%
oc_lettings_site \ views.py(no class) 1200 100%
profiles \ models.pyProfile 100 100%
profiles \ models.py(no class) 600 100%
profiles \ urls.py(no class) 400 100%
profiles \ views.py(no class) 2800 100%
Total  10600 100%
+

+ No items found using the specified filter. +

+
+ + + diff --git a/cov_html/coverage_html_cb_188fc9a4.js b/cov_html/coverage_html_cb_188fc9a4.js new file mode 100644 index 0000000000..6f871742cd --- /dev/null +++ b/cov_html/coverage_html_cb_188fc9a4.js @@ -0,0 +1,735 @@ +// Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +// For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt + +// Coverage.py HTML report browser code. +/*jslint browser: true, sloppy: true, vars: true, plusplus: true, maxerr: 50, indent: 4 */ +/*global coverage: true, document, window, $ */ + +coverage = {}; + +// General helpers +function debounce(callback, wait) { + let timeoutId = null; + return function(...args) { + clearTimeout(timeoutId); + timeoutId = setTimeout(() => { + callback.apply(this, args); + }, wait); + }; +}; + +function checkVisible(element) { + const rect = element.getBoundingClientRect(); + const viewBottom = Math.max(document.documentElement.clientHeight, window.innerHeight); + const viewTop = 30; + return !(rect.bottom < viewTop || rect.top >= viewBottom); +} + +function on_click(sel, fn) { + const elt = document.querySelector(sel); + if (elt) { + elt.addEventListener("click", fn); + } +} + +// Helpers for table sorting +function getCellValue(row, column = 0) { + const cell = row.cells[column] // nosemgrep: eslint.detect-object-injection + if (cell.childElementCount == 1) { + var child = cell.firstElementChild; + if (child.tagName === "A") { + child = child.firstElementChild; + } + if (child instanceof HTMLDataElement && child.value) { + return child.value; + } + } + return cell.innerText || cell.textContent; +} + +function rowComparator(rowA, rowB, column = 0) { + let valueA = getCellValue(rowA, column); + let valueB = getCellValue(rowB, column); + if (!isNaN(valueA) && !isNaN(valueB)) { + return valueA - valueB; + } + return valueA.localeCompare(valueB, undefined, {numeric: true}); +} + +function sortColumn(th) { + // Get the current sorting direction of the selected header, + // clear state on other headers and then set the new sorting direction. + const currentSortOrder = th.getAttribute("aria-sort"); + [...th.parentElement.cells].forEach(header => header.setAttribute("aria-sort", "none")); + var direction; + if (currentSortOrder === "none") { + direction = th.dataset.defaultSortOrder || "ascending"; + } + else if (currentSortOrder === "ascending") { + direction = "descending"; + } + else { + direction = "ascending"; + } + th.setAttribute("aria-sort", direction); + + const column = [...th.parentElement.cells].indexOf(th) + + // Sort all rows and afterwards append them in order to move them in the DOM. + Array.from(th.closest("table").querySelectorAll("tbody tr")) + .sort((rowA, rowB) => rowComparator(rowA, rowB, column) * (direction === "ascending" ? 1 : -1)) + .forEach(tr => tr.parentElement.appendChild(tr)); + + // Save the sort order for next time. + if (th.id !== "region") { + let th_id = "file"; // Sort by file if we don't have a column id + let current_direction = direction; + const stored_list = localStorage.getItem(coverage.INDEX_SORT_STORAGE); + if (stored_list) { + ({th_id, direction} = JSON.parse(stored_list)) + } + localStorage.setItem(coverage.INDEX_SORT_STORAGE, JSON.stringify({ + "th_id": th.id, + "direction": current_direction + })); + if (th.id !== th_id || document.getElementById("region")) { + // Sort column has changed, unset sorting by function or class. + localStorage.setItem(coverage.SORTED_BY_REGION, JSON.stringify({ + "by_region": false, + "region_direction": current_direction + })); + } + } + else { + // Sort column has changed to by function or class, remember that. + localStorage.setItem(coverage.SORTED_BY_REGION, JSON.stringify({ + "by_region": true, + "region_direction": direction + })); + } +} + +// Find all the elements with data-shortcut attribute, and use them to assign a shortcut key. +coverage.assign_shortkeys = function () { + document.querySelectorAll("[data-shortcut]").forEach(element => { + document.addEventListener("keypress", event => { + if (event.target.tagName.toLowerCase() === "input") { + return; // ignore keypress from search filter + } + if (event.key === element.dataset.shortcut) { + element.click(); + } + }); + }); +}; + +// Create the events for the filter box. +coverage.wire_up_filter = function () { + // Populate the filter and hide100 inputs if there are saved values for them. + const saved_filter_value = localStorage.getItem(coverage.FILTER_STORAGE); + if (saved_filter_value) { + document.getElementById("filter").value = saved_filter_value; + } + const saved_hide100_value = localStorage.getItem(coverage.HIDE100_STORAGE); + if (saved_hide100_value) { + document.getElementById("hide100").checked = JSON.parse(saved_hide100_value); + } + + // Cache elements. + const table = document.querySelector("table.index"); + const table_body_rows = table.querySelectorAll("tbody tr"); + const no_rows = document.getElementById("no_rows"); + + const footer = table.tFoot.rows[0]; + const ratio_columns = Array.from(footer.cells).map(cell => Boolean(cell.dataset.ratio)); + + // Observe filter keyevents. + const filter_handler = (event => { + // Keep running total of each metric, first index contains number of shown rows + const totals = ratio_columns.map( + is_ratio => is_ratio ? {"numer": 0, "denom": 0} : 0 + ); + + var text = document.getElementById("filter").value; + // Store filter value + localStorage.setItem(coverage.FILTER_STORAGE, text); + const casefold = (text === text.toLowerCase()); + const hide100 = document.getElementById("hide100").checked; + // Store hide value. + localStorage.setItem(coverage.HIDE100_STORAGE, JSON.stringify(hide100)); + + // Hide / show elements. + table_body_rows.forEach(row => { + var show = false; + // Check the text filter. + for (let column = 0; column < totals.length; column++) { + cell = row.cells[column]; + if (cell.classList.contains("name")) { + var celltext = cell.textContent; + if (casefold) { + celltext = celltext.toLowerCase(); + } + if (celltext.includes(text)) { + show = true; + } + } + } + + // Check the "hide covered" filter. + if (show && hide100) { + const [numer, denom] = row.cells[row.cells.length - 1].dataset.ratio.split(" "); + show = (numer !== denom); + } + + if (!show) { + // hide + row.classList.add("hidden"); + return; + } + + // show + row.classList.remove("hidden"); + totals[0]++; + + for (let column = 0; column < totals.length; column++) { + // Accumulate dynamic totals + cell = row.cells[column] // nosemgrep: eslint.detect-object-injection + if (cell.matches(".name, .spacer")) { + continue; + } + if (ratio_columns[column] && cell.dataset.ratio) { + // Column stores a ratio + const [numer, denom] = cell.dataset.ratio.split(" "); + totals[column]["numer"] += parseInt(numer, 10); // nosemgrep: eslint.detect-object-injection + totals[column]["denom"] += parseInt(denom, 10); // nosemgrep: eslint.detect-object-injection + } + else { + totals[column] += parseInt(cell.textContent, 10); // nosemgrep: eslint.detect-object-injection + } + } + }); + + // Show placeholder if no rows will be displayed. + if (!totals[0]) { + // Show placeholder, hide table. + no_rows.style.display = "block"; + table.style.display = "none"; + return; + } + + // Hide placeholder, show table. + no_rows.style.display = null; + table.style.display = null; + + // Calculate new dynamic sum values based on visible rows. + for (let column = 0; column < totals.length; column++) { + // Get footer cell element. + const cell = footer.cells[column]; // nosemgrep: eslint.detect-object-injection + if (cell.matches(".name, .spacer")) { + continue; + } + + // Set value into dynamic footer cell element. + if (ratio_columns[column]) { + // Percentage column uses the numerator and denominator, + // and adapts to the number of decimal places. + const match = /\.([0-9]+)/.exec(cell.textContent); + const places = match ? match[1].length : 0; + const { numer, denom } = totals[column]; // nosemgrep: eslint.detect-object-injection + cell.dataset.ratio = `${numer} ${denom}`; + // Check denom to prevent NaN if filtered files contain no statements + cell.textContent = denom + ? `${(numer * 100 / denom).toFixed(places)}%` + : `${(100).toFixed(places)}%`; + } + else { + cell.textContent = totals[column]; // nosemgrep: eslint.detect-object-injection + } + } + }); + + document.getElementById("filter").addEventListener("input", debounce(filter_handler)); + document.getElementById("hide100").addEventListener("input", debounce(filter_handler)); + + // Trigger change event on setup, to force filter on page refresh + // (filter value may still be present). + document.getElementById("filter").dispatchEvent(new Event("input")); + document.getElementById("hide100").dispatchEvent(new Event("input")); +}; +coverage.FILTER_STORAGE = "COVERAGE_FILTER_VALUE"; +coverage.HIDE100_STORAGE = "COVERAGE_HIDE100_VALUE"; + +// Set up the click-to-sort columns. +coverage.wire_up_sorting = function () { + document.querySelectorAll("[data-sortable] th[aria-sort]").forEach( + th => th.addEventListener("click", e => sortColumn(e.target)) + ); + + // Look for a localStorage item containing previous sort settings: + let th_id = "file", direction = "ascending"; + const stored_list = localStorage.getItem(coverage.INDEX_SORT_STORAGE); + if (stored_list) { + ({th_id, direction} = JSON.parse(stored_list)); + } + let by_region = false, region_direction = "ascending"; + const sorted_by_region = localStorage.getItem(coverage.SORTED_BY_REGION); + if (sorted_by_region) { + ({ + by_region, + region_direction + } = JSON.parse(sorted_by_region)); + } + + const region_id = "region"; + if (by_region && document.getElementById(region_id)) { + direction = region_direction; + } + // If we are in a page that has a column with id of "region", sort on + // it if the last sort was by function or class. + let th; + if (document.getElementById(region_id)) { + th = document.getElementById(by_region ? region_id : th_id); + } + else { + th = document.getElementById(th_id); + } + th.setAttribute("aria-sort", direction === "ascending" ? "descending" : "ascending"); + th.click() +}; + +coverage.INDEX_SORT_STORAGE = "COVERAGE_INDEX_SORT_2"; +coverage.SORTED_BY_REGION = "COVERAGE_SORT_REGION"; + +// Loaded on index.html +coverage.index_ready = function () { + coverage.assign_shortkeys(); + coverage.wire_up_filter(); + coverage.wire_up_sorting(); + + on_click(".button_prev_file", coverage.to_prev_file); + on_click(".button_next_file", coverage.to_next_file); + + on_click(".button_show_hide_help", coverage.show_hide_help); +}; + +// -- pyfile stuff -- + +coverage.LINE_FILTERS_STORAGE = "COVERAGE_LINE_FILTERS"; + +coverage.pyfile_ready = function () { + // If we're directed to a particular line number, highlight the line. + var frag = location.hash; + if (frag.length > 2 && frag[1] === "t") { + document.querySelector(frag).closest(".n").classList.add("highlight"); + coverage.set_sel(parseInt(frag.substr(2), 10)); + } + else { + coverage.set_sel(0); + } + + on_click(".button_toggle_run", coverage.toggle_lines); + on_click(".button_toggle_mis", coverage.toggle_lines); + on_click(".button_toggle_exc", coverage.toggle_lines); + on_click(".button_toggle_par", coverage.toggle_lines); + + on_click(".button_next_chunk", coverage.to_next_chunk_nicely); + on_click(".button_prev_chunk", coverage.to_prev_chunk_nicely); + on_click(".button_top_of_page", coverage.to_top); + on_click(".button_first_chunk", coverage.to_first_chunk); + + on_click(".button_prev_file", coverage.to_prev_file); + on_click(".button_next_file", coverage.to_next_file); + on_click(".button_to_index", coverage.to_index); + + on_click(".button_show_hide_help", coverage.show_hide_help); + + coverage.filters = undefined; + try { + coverage.filters = localStorage.getItem(coverage.LINE_FILTERS_STORAGE); + } catch(err) {} + + if (coverage.filters) { + coverage.filters = JSON.parse(coverage.filters); + } + else { + coverage.filters = {run: false, exc: true, mis: true, par: true}; + } + + for (cls in coverage.filters) { + coverage.set_line_visibilty(cls, coverage.filters[cls]); // nosemgrep: eslint.detect-object-injection + } + + coverage.assign_shortkeys(); + coverage.init_scroll_markers(); + coverage.wire_up_sticky_header(); + + document.querySelectorAll("[id^=ctxs]").forEach( + cbox => cbox.addEventListener("click", coverage.expand_contexts) + ); + + // Rebuild scroll markers when the window height changes. + window.addEventListener("resize", coverage.build_scroll_markers); +}; + +coverage.toggle_lines = function (event) { + const btn = event.target.closest("button"); + const category = btn.value + const show = !btn.classList.contains("show_" + category); + coverage.set_line_visibilty(category, show); + coverage.build_scroll_markers(); + coverage.filters[category] = show; + try { + localStorage.setItem(coverage.LINE_FILTERS_STORAGE, JSON.stringify(coverage.filters)); + } catch(err) {} +}; + +coverage.set_line_visibilty = function (category, should_show) { + const cls = "show_" + category; + const btn = document.querySelector(".button_toggle_" + category); + if (btn) { + if (should_show) { + document.querySelectorAll("#source ." + category).forEach(e => e.classList.add(cls)); + btn.classList.add(cls); + } + else { + document.querySelectorAll("#source ." + category).forEach(e => e.classList.remove(cls)); + btn.classList.remove(cls); + } + } +}; + +// Return the nth line div. +coverage.line_elt = function (n) { + return document.getElementById("t" + n)?.closest("p"); +}; + +// Set the selection. b and e are line numbers. +coverage.set_sel = function (b, e) { + // The first line selected. + coverage.sel_begin = b; + // The next line not selected. + coverage.sel_end = (e === undefined) ? b+1 : e; +}; + +coverage.to_top = function () { + coverage.set_sel(0, 1); + coverage.scroll_window(0); +}; + +coverage.to_first_chunk = function () { + coverage.set_sel(0, 1); + coverage.to_next_chunk(); +}; + +coverage.to_prev_file = function () { + window.location = document.getElementById("prevFileLink").href; +} + +coverage.to_next_file = function () { + window.location = document.getElementById("nextFileLink").href; +} + +coverage.to_index = function () { + location.href = document.getElementById("indexLink").href; +} + +coverage.show_hide_help = function () { + const helpCheck = document.getElementById("help_panel_state") + helpCheck.checked = !helpCheck.checked; +} + +// Return a string indicating what kind of chunk this line belongs to, +// or null if not a chunk. +coverage.chunk_indicator = function (line_elt) { + const classes = line_elt?.className; + if (!classes) { + return null; + } + const match = classes.match(/\bshow_\w+\b/); + if (!match) { + return null; + } + return match[0]; +}; + +coverage.to_next_chunk = function () { + const c = coverage; + + // Find the start of the next colored chunk. + var probe = c.sel_end; + var chunk_indicator, probe_line; + while (true) { + probe_line = c.line_elt(probe); + if (!probe_line) { + return; + } + chunk_indicator = c.chunk_indicator(probe_line); + if (chunk_indicator) { + break; + } + probe++; + } + + // There's a next chunk, `probe` points to it. + var begin = probe; + + // Find the end of this chunk. + var next_indicator = chunk_indicator; + while (next_indicator === chunk_indicator) { + probe++; + probe_line = c.line_elt(probe); + next_indicator = c.chunk_indicator(probe_line); + } + c.set_sel(begin, probe); + c.show_selection(); +}; + +coverage.to_prev_chunk = function () { + const c = coverage; + + // Find the end of the prev colored chunk. + var probe = c.sel_begin-1; + var probe_line = c.line_elt(probe); + if (!probe_line) { + return; + } + var chunk_indicator = c.chunk_indicator(probe_line); + while (probe > 1 && !chunk_indicator) { + probe--; + probe_line = c.line_elt(probe); + if (!probe_line) { + return; + } + chunk_indicator = c.chunk_indicator(probe_line); + } + + // There's a prev chunk, `probe` points to its last line. + var end = probe+1; + + // Find the beginning of this chunk. + var prev_indicator = chunk_indicator; + while (prev_indicator === chunk_indicator) { + probe--; + if (probe <= 0) { + return; + } + probe_line = c.line_elt(probe); + prev_indicator = c.chunk_indicator(probe_line); + } + c.set_sel(probe+1, end); + c.show_selection(); +}; + +// Returns 0, 1, or 2: how many of the two ends of the selection are on +// the screen right now? +coverage.selection_ends_on_screen = function () { + if (coverage.sel_begin === 0) { + return 0; + } + + const begin = coverage.line_elt(coverage.sel_begin); + const end = coverage.line_elt(coverage.sel_end-1); + + return ( + (checkVisible(begin) ? 1 : 0) + + (checkVisible(end) ? 1 : 0) + ); +}; + +coverage.to_next_chunk_nicely = function () { + if (coverage.selection_ends_on_screen() === 0) { + // The selection is entirely off the screen: + // Set the top line on the screen as selection. + + // This will select the top-left of the viewport + // As this is most likely the span with the line number we take the parent + const line = document.elementFromPoint(0, 0).parentElement; + if (line.parentElement !== document.getElementById("source")) { + // The element is not a source line but the header or similar + coverage.select_line_or_chunk(1); + } + else { + // We extract the line number from the id + coverage.select_line_or_chunk(parseInt(line.id.substring(1), 10)); + } + } + coverage.to_next_chunk(); +}; + +coverage.to_prev_chunk_nicely = function () { + if (coverage.selection_ends_on_screen() === 0) { + // The selection is entirely off the screen: + // Set the lowest line on the screen as selection. + + // This will select the bottom-left of the viewport + // As this is most likely the span with the line number we take the parent + const line = document.elementFromPoint(document.documentElement.clientHeight-1, 0).parentElement; + if (line.parentElement !== document.getElementById("source")) { + // The element is not a source line but the header or similar + coverage.select_line_or_chunk(coverage.lines_len); + } + else { + // We extract the line number from the id + coverage.select_line_or_chunk(parseInt(line.id.substring(1), 10)); + } + } + coverage.to_prev_chunk(); +}; + +// Select line number lineno, or if it is in a colored chunk, select the +// entire chunk +coverage.select_line_or_chunk = function (lineno) { + var c = coverage; + var probe_line = c.line_elt(lineno); + if (!probe_line) { + return; + } + var the_indicator = c.chunk_indicator(probe_line); + if (the_indicator) { + // The line is in a highlighted chunk. + // Search backward for the first line. + var probe = lineno; + var indicator = the_indicator; + while (probe > 0 && indicator === the_indicator) { + probe--; + probe_line = c.line_elt(probe); + if (!probe_line) { + break; + } + indicator = c.chunk_indicator(probe_line); + } + var begin = probe + 1; + + // Search forward for the last line. + probe = lineno; + indicator = the_indicator; + while (indicator === the_indicator) { + probe++; + probe_line = c.line_elt(probe); + indicator = c.chunk_indicator(probe_line); + } + + coverage.set_sel(begin, probe); + } + else { + coverage.set_sel(lineno); + } +}; + +coverage.show_selection = function () { + // Highlight the lines in the chunk + document.querySelectorAll("#source .highlight").forEach(e => e.classList.remove("highlight")); + for (let probe = coverage.sel_begin; probe < coverage.sel_end; probe++) { + coverage.line_elt(probe).querySelector(".n").classList.add("highlight"); + } + + coverage.scroll_to_selection(); +}; + +coverage.scroll_to_selection = function () { + // Scroll the page if the chunk isn't fully visible. + if (coverage.selection_ends_on_screen() < 2) { + const element = coverage.line_elt(coverage.sel_begin); + coverage.scroll_window(element.offsetTop - 60); + } +}; + +coverage.scroll_window = function (to_pos) { + window.scroll({top: to_pos, behavior: "smooth"}); +}; + +coverage.init_scroll_markers = function () { + // Init some variables + coverage.lines_len = document.querySelectorAll("#source > p").length; + + // Build html + coverage.build_scroll_markers(); +}; + +coverage.build_scroll_markers = function () { + const temp_scroll_marker = document.getElementById("scroll_marker") + if (temp_scroll_marker) temp_scroll_marker.remove(); + // Don't build markers if the window has no scroll bar. + if (document.body.scrollHeight <= window.innerHeight) { + return; + } + + const marker_scale = window.innerHeight / document.body.scrollHeight; + const line_height = Math.min(Math.max(3, window.innerHeight / coverage.lines_len), 10); + + let previous_line = -99, last_mark, last_top; + + const scroll_marker = document.createElement("div"); + scroll_marker.id = "scroll_marker"; + document.getElementById("source").querySelectorAll( + "p.show_run, p.show_mis, p.show_exc, p.show_exc, p.show_par" + ).forEach(element => { + const line_top = Math.floor(element.offsetTop * marker_scale); + const line_number = parseInt(element.querySelector(".n a").id.substr(1)); + + if (line_number === previous_line + 1) { + // If this solid missed block just make previous mark higher. + last_mark.style.height = `${line_top + line_height - last_top}px`; + } + else { + // Add colored line in scroll_marker block. + last_mark = document.createElement("div"); + last_mark.id = `m${line_number}`; + last_mark.classList.add("marker"); + last_mark.style.height = `${line_height}px`; + last_mark.style.top = `${line_top}px`; + scroll_marker.append(last_mark); + last_top = line_top; + } + + previous_line = line_number; + }); + + // Append last to prevent layout calculation + document.body.append(scroll_marker); +}; + +coverage.wire_up_sticky_header = function () { + const header = document.querySelector("header"); + const header_bottom = ( + header.querySelector(".content h2").getBoundingClientRect().top - + header.getBoundingClientRect().top + ); + + function updateHeader() { + if (window.scrollY > header_bottom) { + header.classList.add("sticky"); + } + else { + header.classList.remove("sticky"); + } + } + + window.addEventListener("scroll", updateHeader); + updateHeader(); +}; + +coverage.expand_contexts = function (e) { + var ctxs = e.target.parentNode.querySelector(".ctxs"); + + if (!ctxs.classList.contains("expanded")) { + var ctxs_text = ctxs.textContent; + var width = Number(ctxs_text[0]); + ctxs.textContent = ""; + for (var i = 1; i < ctxs_text.length; i += width) { + key = ctxs_text.substring(i, i + width).trim(); + ctxs.appendChild(document.createTextNode(contexts[key])); + ctxs.appendChild(document.createElement("br")); + } + ctxs.classList.add("expanded"); + } +}; + +document.addEventListener("DOMContentLoaded", () => { + if (document.body.classList.contains("indexfile")) { + coverage.index_ready(); + } + else { + coverage.pyfile_ready(); + } +}); diff --git a/cov_html/favicon_32_cb_c827f16f.png b/cov_html/favicon_32_cb_c827f16f.png new file mode 100644 index 0000000000000000000000000000000000000000..8649f0475d8d20793b2ec431fe25a186a414cf10 GIT binary patch literal 1732 zcmV;#20QtQP)K2KOkBOVxIZChq#W-v7@TU%U6P(wycKT1hUJUToW3ke1U1ONa4 z000000000000000bb)GRa9mqwR9|UWHy;^RUrt?IT__Y0JUcxmBP0(51q1>E00030 z|NrOz)aw7%8sJzM<5^g%z7^qE`}_Ot|JUUG(NUkWzR|7K?Zo%@_v-8G-1N%N=D$;; zw;keH4dGY$`1t4M=HK_s*zm^0#KgqfwWhe3qO_HtvXYvtjgX>;-~C$L`&k>^R)9)7 zdPh2TL^pCnHC#0+_4D)M`p?qp!pq{jO_{8;$fbaflbx`Tn52n|n}8VFRTA1&ugOP< zPd{uvFjz7t*Vot1&d$l-xWCk}s;sQL&#O(Bskh6gqNJv>#iB=ypG1e3K!K4yc7!~M zfj4S*g^zZ7eP$+_Sl07Z646l;%urinP#D8a6TwRtnLIRcI!r4f@bK~9-`~;E(N?Lv zSEst7s;rcxsi~}{Nsytfz@MtUoR*iFc8!#vvx}Umhm4blk(_~MdVD-@dW&>!Nn~ro z_E~-ESVQAj6Wmn;(olz(O&_{U2*pZBc1aYjMh>Dq3z|6`jW`RDHV=t3I6yRKJ~LOX zz_z!!vbVXPqob#=pj3^VMT?x6t(irRmSKsMo1~LLkB&=#j!=M%NP35mfqim$drWb9 zYIb>no_LUwc!r^NkDzs4YHu@=ZHRzrafWDZd1EhEVq=tGX?tK$pIa)DTh#bkvh!J- z?^%@YS!U*0E8$q$_*aOTQ&)Ra64g>ep;BdcQgvlg8qQHrP*E$;P{-m=A*@axn@$bO zO-Y4JzS&EAi%YG}N?cn?YFS7ivPY=EMV6~YH;+Xxu|tefLS|Aza)Cg6us#)=JW!uH zQa?H>d^j+YHCtyjL^LulF*05|F$RG!AX_OHVI&MtA~_@=5_lU|0000rbW%=J06GH4 z^5LD8b8apw8vNh1ua1mF{{Hy)_U`NA;Nacc+sCpuHXa-V{r&yz?c(9#+}oX+NmiRW z+W-IqK1oDDR5;6GfCDCOP5}iL5fK(cB~ET81`MFgF2kGa9AjhSIk~-E-4&*tPPKdiilQJ11k_J082ZS z>@TvivP!5ZFG?t@{t+GpR3XR&@*hA_VE1|Lo8@L@)l*h(Z@=?c-NS$Fk&&61IzUU9 z*nPqBM=OBZ-6ka1SJgGAS-Us5EN)r#dUX%>wQZLa2ytPCtMKp)Ob z*xcu38Z&d5<-NBS)@jRD+*!W*cf-m_wmxDEqBf?czI%3U0J$Xik;lA`jg}VH?(S(V zE!M3;X2B8w0TnnW&6(8;_Uc)WD;Ms6PKP+s(sFgO!}B!^ES~GDt4qLPxwYB)^7)XA zZwo9zDy-B0B+jT6V=!=bo(zs_8{eBA78gT9GH$(DVhz;4VAYwz+bOIdZ-PNb|I&rl z^XG=vFLF)1{&nT2*0vMz#}7^9hXzzf&ZdKlEj{LihP;|;Ywqn35ajP?H?7t|i-Un% z&&kxee@9B{nwgv1+S-~0)E1{ob1^Wn`F2isurqThKK=3%&;`@{0{!D- z&CSj80t;uPu&FaJFtSXKH#ajgGj}=sEad7US6jP0|Db@0j)?(5@sf<7`~a9>s;wCa zm^)spe{uxGFmrJYI9cOh7s$>8Npkt-5EWB1UKc`{W{y5Ce$1+nM9Cr;);=Ju#N^62OSlJMn7omiUgP&ErsYzT~iGxcW aE(`!K@+CXylaC4j0000 + + + + Coverage report + + + + + +
+
+

Coverage report: + 100% +

+ +
+ +
+ + +
+
+

+ Files + Functions + Classes +

+

+ coverage.py v7.14.0, + created at 2026-05-22 10:56 +0200 +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Filefunction statementsmissingexcluded coverage
lettings \ models.pyAddress.__str__ 100 100%
lettings \ models.pyLetting.__str__ 100 100%
lettings \ models.py(no function) 1700 100%
lettings \ urls.py(no function) 400 100%
lettings \ views.pyindex 900 100%
lettings \ views.pyletting 1300 100%
lettings \ views.py(no function) 600 100%
oc_lettings_site \ urls.py(no function) 400 100%
oc_lettings_site \ views.pyindex 800 100%
oc_lettings_site \ views.py(no function) 400 100%
profiles \ models.pyProfile.__str__ 100 100%
profiles \ models.py(no function) 600 100%
profiles \ urls.py(no function) 400 100%
profiles \ views.pyindex 900 100%
profiles \ views.pyprofile 1300 100%
profiles \ views.py(no function) 600 100%
Total  10600 100%
+

+ No items found using the specified filter. +

+
+ + + diff --git a/cov_html/index.html b/cov_html/index.html new file mode 100644 index 0000000000..51d248ae38 --- /dev/null +++ b/cov_html/index.html @@ -0,0 +1,180 @@ + + + + + Coverage report + + + + + +
+
+

Coverage report: + 100% +

+ +
+ +
+ + +
+
+

+ Files + Functions + Classes +

+

+ coverage.py v7.14.0, + created at 2026-05-22 10:56 +0200 +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
File statementsmissingexcluded coverage
lettings \ models.py 1900 100%
lettings \ urls.py 400 100%
lettings \ views.py 2800 100%
oc_lettings_site \ urls.py 400 100%
oc_lettings_site \ views.py 1200 100%
profiles \ models.py 700 100%
profiles \ urls.py 400 100%
profiles \ views.py 2800 100%
Total 10600 100%
+

+ No items found using the specified filter. +

+
+ + + diff --git a/cov_html/keybd_closed_cb_900cfef5.png b/cov_html/keybd_closed_cb_900cfef5.png new file mode 100644 index 0000000000000000000000000000000000000000..ba119c47df81ed2bbd27a06988abf700139c4f99 GIT binary patch literal 9004 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 literal 0 HcmV?d00001 diff --git a/cov_html/status.json b/cov_html/status.json new file mode 100644 index 0000000000..d17d83f315 --- /dev/null +++ b/cov_html/status.json @@ -0,0 +1 @@ +{"note":"This file is an internal implementation detail to speed up HTML report generation. Its format can change at any time. You might be looking for the JSON report: https://coverage.rtfd.io/cmd.html#cmd-json","format":5,"version":"7.14.0","globals":"5d68ca9844fe654e0fbee8d2e59249f4","files":{"z_a9b1b018a4ee155b_models_py":{"hash":"a5537957613848ba266b88176a8e0ab7","index":{"url":"z_a9b1b018a4ee155b_models_py.html","file":"lettings\\models.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":19,"n_excluded":0,"n_missing":0,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_a9b1b018a4ee155b_urls_py":{"hash":"926e542cc4f7b882a38e94b89c64788b","index":{"url":"z_a9b1b018a4ee155b_urls_py.html","file":"lettings\\urls.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":4,"n_excluded":0,"n_missing":0,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_a9b1b018a4ee155b_views_py":{"hash":"1c2d2f4ca195eef879fa15b7da0bfdf8","index":{"url":"z_a9b1b018a4ee155b_views_py.html","file":"lettings\\views.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":28,"n_excluded":0,"n_missing":0,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_d8907effad88fb1e_urls_py":{"hash":"f5c03788ee38dd1b9a052320b7c8e410","index":{"url":"z_d8907effad88fb1e_urls_py.html","file":"oc_lettings_site\\urls.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":4,"n_excluded":0,"n_missing":0,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_d8907effad88fb1e_views_py":{"hash":"f96e72908b5332539d929b2009283f82","index":{"url":"z_d8907effad88fb1e_views_py.html","file":"oc_lettings_site\\views.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":12,"n_excluded":0,"n_missing":0,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_b4872cbce420d762_models_py":{"hash":"2de4f9efdcb0811adaf7246ef9369bbe","index":{"url":"z_b4872cbce420d762_models_py.html","file":"profiles\\models.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":7,"n_excluded":0,"n_missing":0,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_b4872cbce420d762_urls_py":{"hash":"b9923831fb1c54710d4be641bd654bc2","index":{"url":"z_b4872cbce420d762_urls_py.html","file":"profiles\\urls.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":4,"n_excluded":0,"n_missing":0,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_b4872cbce420d762_views_py":{"hash":"fccf0e7fd30f69d9db73ddbf8be1274f","index":{"url":"z_b4872cbce420d762_views_py.html","file":"profiles\\views.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":28,"n_excluded":0,"n_missing":0,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}}}} \ No newline at end of file diff --git a/cov_html/style_cb_5c747636.css b/cov_html/style_cb_5c747636.css new file mode 100644 index 0000000000..5e304ce5f6 --- /dev/null +++ b/cov_html/style_cb_5c747636.css @@ -0,0 +1,389 @@ +@charset "UTF-8"; +/* Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 */ +/* For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt */ +/* Don't edit this .css file. Edit the .scss file instead! */ +html, body, h1, h2, h3, p, table, td, th { margin: 0; padding: 0; border: 0; font-weight: inherit; font-style: inherit; font-size: 100%; font-family: inherit; vertical-align: baseline; } + +body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 1em; background: #fff; color: #000; } + +@media (prefers-color-scheme: dark) { body { background: #1e1e1e; } } + +@media (prefers-color-scheme: dark) { body { color: #eee; } } + +html > body { font-size: 16px; } + +a:active, a:focus { outline: 2px dashed #007acc; } + +p { font-size: .875em; line-height: 1.4em; } + +table { border-collapse: collapse; } + +td { vertical-align: top; } + +table tr.hidden { display: none !important; } + +p#no_rows { display: none; font-size: 1.15em; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; } + +a.nav { text-decoration: none; color: inherit; } + +a.nav:hover { text-decoration: underline; color: inherit; } + +.hidden { display: none; } + +header { background: #f8f8f8; width: 100%; z-index: 2; border-bottom: 1px solid #ccc; } + +@media (prefers-color-scheme: dark) { header { background: black; } } + +@media (prefers-color-scheme: dark) { header { border-color: #333; } } + +header .content { padding: 1rem 3.5rem; } + +header h2 { margin-top: .5em; font-size: 1em; } + +header h2 a.button { font-family: inherit; font-size: inherit; border: 1px solid; border-radius: .2em; background: #eee; color: inherit; text-decoration: none; padding: .1em .5em; margin: 1px calc(.1em + 1px); cursor: pointer; border-color: #ccc; } + +@media (prefers-color-scheme: dark) { header h2 a.button { background: #333; } } + +@media (prefers-color-scheme: dark) { header h2 a.button { border-color: #444; } } + +header h2 a.button.current { border: 2px solid; background: #fff; border-color: #999; cursor: default; } + +@media (prefers-color-scheme: dark) { header h2 a.button.current { background: #1e1e1e; } } + +@media (prefers-color-scheme: dark) { header h2 a.button.current { border-color: #777; } } + +header p.text { margin: .5em 0 -.5em; color: #666; font-style: italic; } + +@media (prefers-color-scheme: dark) { header p.text { color: #aaa; } } + +header.sticky { position: fixed; left: 0; right: 0; height: 2.5em; } + +header.sticky .text { display: none; } + +header.sticky h1, header.sticky h2 { font-size: 1em; margin-top: 0; display: inline-block; } + +header.sticky .content { padding: 0.5rem 3.5rem; } + +header.sticky .content p { font-size: 1em; } + +header.sticky ~ #source { padding-top: 6.5em; } + +main { position: relative; z-index: 1; } + +footer { margin: 1rem 3.5rem; } + +footer .content { padding: 0; color: #666; font-style: italic; } + +@media (prefers-color-scheme: dark) { footer .content { color: #aaa; } } + +#index { margin: 1rem 0 0 3.5rem; } + +h1 { font-size: 1.25em; display: inline-block; } + +#filter_container { float: right; margin: 0 2em 0 0; line-height: 1.66em; } + +#filter_container #filter { width: 10em; padding: 0.2em 0.5em; border: 2px solid #ccc; background: #fff; color: #000; } + +@media (prefers-color-scheme: dark) { #filter_container #filter { border-color: #444; } } + +@media (prefers-color-scheme: dark) { #filter_container #filter { background: #1e1e1e; } } + +@media (prefers-color-scheme: dark) { #filter_container #filter { color: #eee; } } + +#filter_container #filter:focus { border-color: #007acc; } + +#filter_container :disabled ~ label { color: #ccc; } + +@media (prefers-color-scheme: dark) { #filter_container :disabled ~ label { color: #444; } } + +#filter_container label { font-size: .875em; color: #666; } + +@media (prefers-color-scheme: dark) { #filter_container label { color: #aaa; } } + +header button { font-family: inherit; font-size: inherit; border: 1px solid; border-radius: .2em; background: #eee; color: inherit; text-decoration: none; padding: .1em .5em; margin: 1px calc(.1em + 1px); cursor: pointer; border-color: #ccc; } + +@media (prefers-color-scheme: dark) { header button { background: #333; } } + +@media (prefers-color-scheme: dark) { header button { border-color: #444; } } + +header button:active, header button:focus { outline: 2px dashed #007acc; } + +header button.run { background: #eeffee; } + +@media (prefers-color-scheme: dark) { header button.run { background: #373d29; } } + +header button.run.show_run { background: #dfd; border: 2px solid #00dd00; margin: 0 .1em; } + +@media (prefers-color-scheme: dark) { header button.run.show_run { background: #373d29; } } + +header button.mis { background: #ffeeee; } + +@media (prefers-color-scheme: dark) { header button.mis { background: #4b1818; } } + +header button.mis.show_mis { background: #fdd; border: 2px solid #ff0000; margin: 0 .1em; } + +@media (prefers-color-scheme: dark) { header button.mis.show_mis { background: #4b1818; } } + +header button.exc { background: #f7f7f7; } + +@media (prefers-color-scheme: dark) { header button.exc { background: #333; } } + +header button.exc.show_exc { background: #eee; border: 2px solid #808080; margin: 0 .1em; } + +@media (prefers-color-scheme: dark) { header button.exc.show_exc { background: #333; } } + +header button.par { background: #ffffd5; } + +@media (prefers-color-scheme: dark) { header button.par { background: #650; } } + +header button.par.show_par { background: #ffa; border: 2px solid #bbbb00; margin: 0 .1em; } + +@media (prefers-color-scheme: dark) { header button.par.show_par { background: #650; } } + +#help_panel, #source p .annotate.long { display: none; position: absolute; z-index: 999; background: #ffffcc; border: 1px solid #888; border-radius: .2em; color: #333; padding: .25em .5em; } + +#source p .annotate.long { white-space: normal; float: right; top: 1.75em; right: 1em; height: auto; } + +#help_panel_wrapper { float: right; position: relative; } + +#keyboard_icon { margin: 5px; } + +#help_panel_state { display: none; } + +#help_panel { top: 25px; right: 0; padding: .75em; border: 1px solid #883; color: #333; } + +#help_panel .keyhelp p { margin-top: .75em; } + +#help_panel .legend { font-style: italic; margin-bottom: 1em; } + +.indexfile #help_panel { width: 25em; } + +.pyfile #help_panel { width: 18em; } + +#help_panel_state:checked ~ #help_panel { display: block; } + +kbd { border: 1px solid black; border-color: #888 #333 #333 #888; padding: .1em .35em; font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-weight: bold; background: #eee; border-radius: 3px; } + +#source { padding: 1em 0 1em 3.5rem; font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; } + +#source p { position: relative; white-space: pre; } + +#source p * { box-sizing: border-box; } + +#source p .n { float: left; text-align: right; width: 3.5rem; box-sizing: border-box; margin-left: -3.5rem; padding-right: 1em; color: #999; user-select: none; } + +@media (prefers-color-scheme: dark) { #source p .n { color: #777; } } + +#source p .n.highlight { background: #ffdd00; } + +#source p .n a { scroll-margin-top: 6em; text-decoration: none; color: #999; } + +@media (prefers-color-scheme: dark) { #source p .n a { color: #777; } } + +#source p .n a:hover { text-decoration: underline; color: #999; } + +@media (prefers-color-scheme: dark) { #source p .n a:hover { color: #777; } } + +#source p .t { display: inline-block; width: 100%; box-sizing: border-box; margin-left: -.5em; padding-left: 0.3em; border-left: 0.2em solid #fff; } + +@media (prefers-color-scheme: dark) { #source p .t { border-color: #1e1e1e; } } + +#source p .t:hover { background: #f2f2f2; } + +@media (prefers-color-scheme: dark) { #source p .t:hover { background: #282828; } } + +#source p .t:hover ~ .r .annotate.long { display: block; } + +#source p .t .com { color: #008000; font-style: italic; line-height: 1px; } + +@media (prefers-color-scheme: dark) { #source p .t .com { color: #6a9955; } } + +#source p .t .key { font-weight: bold; line-height: 1px; } + +#source p .t .str, #source p .t .fst { color: #0451a5; } + +@media (prefers-color-scheme: dark) { #source p .t .str, #source p .t .fst { color: #9cdcfe; } } + +#source p.mis .t { border-left: 0.2em solid #ff0000; } + +#source p.mis.show_mis .t { background: #fdd; } + +@media (prefers-color-scheme: dark) { #source p.mis.show_mis .t { background: #4b1818; } } + +#source p.mis.show_mis .t:hover { background: #f2d2d2; } + +@media (prefers-color-scheme: dark) { #source p.mis.show_mis .t:hover { background: #532323; } } + +#source p.mis.mis2 .t { border-left: 0.2em dotted #ff0000; } + +#source p.mis.mis2.show_mis .t { background: #ffeeee; } + +@media (prefers-color-scheme: dark) { #source p.mis.mis2.show_mis .t { background: #351b1b; } } + +#source p.mis.mis2.show_mis .t:hover { background: #f2d2d2; } + +@media (prefers-color-scheme: dark) { #source p.mis.mis2.show_mis .t:hover { background: #532323; } } + +#source p.run .t { border-left: 0.2em solid #00dd00; } + +#source p.run.show_run .t { background: #dfd; } + +@media (prefers-color-scheme: dark) { #source p.run.show_run .t { background: #373d29; } } + +#source p.run.show_run .t:hover { background: #d2f2d2; } + +@media (prefers-color-scheme: dark) { #source p.run.show_run .t:hover { background: #404633; } } + +#source p.run.run2 .t { border-left: 0.2em dotted #00dd00; } + +#source p.run.run2.show_run .t { background: #eeffee; } + +@media (prefers-color-scheme: dark) { #source p.run.run2.show_run .t { background: #2b2e24; } } + +#source p.run.run2.show_run .t:hover { background: #d2f2d2; } + +@media (prefers-color-scheme: dark) { #source p.run.run2.show_run .t:hover { background: #404633; } } + +#source p.exc .t { border-left: 0.2em solid #808080; } + +#source p.exc.show_exc .t { background: #eee; } + +@media (prefers-color-scheme: dark) { #source p.exc.show_exc .t { background: #333; } } + +#source p.exc.show_exc .t:hover { background: #e2e2e2; } + +@media (prefers-color-scheme: dark) { #source p.exc.show_exc .t:hover { background: #3c3c3c; } } + +#source p.exc.exc2 .t { border-left: 0.2em dotted #808080; } + +#source p.exc.exc2.show_exc .t { background: #f7f7f7; } + +@media (prefers-color-scheme: dark) { #source p.exc.exc2.show_exc .t { background: #292929; } } + +#source p.exc.exc2.show_exc .t:hover { background: #e2e2e2; } + +@media (prefers-color-scheme: dark) { #source p.exc.exc2.show_exc .t:hover { background: #3c3c3c; } } + +#source p.par .t { border-left: 0.2em solid #bbbb00; } + +#source p.par.show_par .t { background: #ffa; } + +@media (prefers-color-scheme: dark) { #source p.par.show_par .t { background: #650; } } + +#source p.par.show_par .t:hover { background: #f2f2a2; } + +@media (prefers-color-scheme: dark) { #source p.par.show_par .t:hover { background: #6d5d0c; } } + +#source p.par.par2 .t { border-left: 0.2em dotted #bbbb00; } + +#source p.par.par2.show_par .t { background: #ffffd5; } + +@media (prefers-color-scheme: dark) { #source p.par.par2.show_par .t { background: #423a0f; } } + +#source p.par.par2.show_par .t:hover { background: #f2f2a2; } + +@media (prefers-color-scheme: dark) { #source p.par.par2.show_par .t:hover { background: #6d5d0c; } } + +#source p .r { position: absolute; top: 0; right: 2.5em; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; } + +#source p .annotate { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; color: #666; padding-right: .5em; } + +@media (prefers-color-scheme: dark) { #source p .annotate { color: #ddd; } } + +#source p .annotate.short:hover ~ .long { display: block; } + +#source p .annotate.long { width: 30em; right: 2.5em; } + +#source p input { display: none; } + +#source p input ~ .r label.ctx { cursor: pointer; border-radius: .25em; } + +#source p input ~ .r label.ctx::before { content: "▶ "; } + +#source p input ~ .r label.ctx:hover { background: #e8f4ff; color: #666; } + +@media (prefers-color-scheme: dark) { #source p input ~ .r label.ctx:hover { background: #0f3a42; } } + +@media (prefers-color-scheme: dark) { #source p input ~ .r label.ctx:hover { color: #aaa; } } + +#source p input:checked ~ .r label.ctx { background: #d0e8ff; color: #666; border-radius: .75em .75em 0 0; padding: 0 .5em; margin: -.25em 0; } + +@media (prefers-color-scheme: dark) { #source p input:checked ~ .r label.ctx { background: #056; } } + +@media (prefers-color-scheme: dark) { #source p input:checked ~ .r label.ctx { color: #aaa; } } + +#source p input:checked ~ .r label.ctx::before { content: "▼ "; } + +#source p input:checked ~ .ctxs { padding: .25em .5em; overflow-y: scroll; max-height: 10.5em; } + +#source p label.ctx { color: #999; display: inline-block; padding: 0 .5em; font-size: .8333em; } + +@media (prefers-color-scheme: dark) { #source p label.ctx { color: #777; } } + +#source p .ctxs { display: block; max-height: 0; overflow-y: hidden; transition: all .2s; padding: 0 .5em; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; white-space: nowrap; background: #d0e8ff; border-radius: .25em; margin-right: 1.75em; text-align: right; } + +@media (prefers-color-scheme: dark) { #source p .ctxs { background: #056; } } + +#index { font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 0.875em; } + +#index table.index { margin-left: -.5em; } + +#index td, #index th { text-align: right; vertical-align: baseline; padding: .25em .5em; border-bottom: 1px solid #eee; } + +@media (prefers-color-scheme: dark) { #index td, #index th { border-color: #333; } } + +#index td.name, #index th.name { text-align: left; width: auto; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; min-width: 15em; } + +#index td.left, #index th.left { text-align: left; } + +#index td.spacer, #index th.spacer { border: none; padding: 0; } + +#index td.spacer:hover, #index th.spacer:hover { background: inherit; } + +#index th { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-style: italic; color: #333; border-color: #ccc; cursor: pointer; } + +@media (prefers-color-scheme: dark) { #index th { color: #ddd; } } + +@media (prefers-color-scheme: dark) { #index th { border-color: #444; } } + +#index th:hover { background: #eee; } + +@media (prefers-color-scheme: dark) { #index th:hover { background: #333; } } + +#index th .arrows { color: #666; font-size: 85%; font-family: sans-serif; font-style: normal; pointer-events: none; } + +#index th[aria-sort="ascending"], #index th[aria-sort="descending"] { white-space: nowrap; background: #eee; padding-left: .5em; } + +@media (prefers-color-scheme: dark) { #index th[aria-sort="ascending"], #index th[aria-sort="descending"] { background: #333; } } + +#index th[aria-sort="ascending"] .arrows::after { content: " ▲"; } + +#index th[aria-sort="descending"] .arrows::after { content: " ▼"; } + +#index tr.grouphead th { cursor: default; font-style: normal; border-color: #999; } + +@media (prefers-color-scheme: dark) { #index tr.grouphead th { border-color: #777; } } + +#index td.name { font-size: 1.15em; } + +#index td.name a { text-decoration: none; color: inherit; } + +#index td.name .no-noun { font-style: italic; } + +#index tr.total td, #index tr.total_dynamic td { font-weight: bold; border-bottom: none; } + +#index tr.region:hover { background: #eee; } + +@media (prefers-color-scheme: dark) { #index tr.region:hover { background: #333; } } + +#index tr.region:hover td.name { text-decoration: underline; color: inherit; } + +#scroll_marker { position: fixed; z-index: 3; right: 0; top: 0; width: 16px; height: 100%; background: #fff; border-left: 1px solid #eee; will-change: transform; } + +@media (prefers-color-scheme: dark) { #scroll_marker { background: #1e1e1e; } } + +@media (prefers-color-scheme: dark) { #scroll_marker { border-color: #333; } } + +#scroll_marker .marker { background: #ccc; position: absolute; min-height: 3px; width: 100%; } + +@media (prefers-color-scheme: dark) { #scroll_marker .marker { background: #444; } } diff --git a/cov_html/z_a9b1b018a4ee155b_models_py.html b/cov_html/z_a9b1b018a4ee155b_models_py.html new file mode 100644 index 0000000000..62e1438043 --- /dev/null +++ b/cov_html/z_a9b1b018a4ee155b_models_py.html @@ -0,0 +1,155 @@ + + + + + Coverage for lettings\models.py: 100% + + + + + +
+
+

+ Coverage for lettings \ models.py: + 100% +

+ +

+ 19 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.14.0, + created at 2026-05-22 10:56 +0200 +

+ +
+
+
+

1""" 

+

2Models module for lettings app 

+

3""" 

+

4from django.db import models 

+

5from django.core.validators import MaxValueValidator, MinLengthValidator 

+

6 

+

7 

+

8class Address(models.Model): 

+

9 """ 

+

10 Address model for Lettings 

+

11 Attributes: 

+

12 number (int): Letting number 

+

13 street (str): Street address 

+

14 city (str): City address 

+

15 state (str): State address 

+

16 zip_code (int): Zip code 

+

17 country_iso_code (int): Country code 

+

18 """ 

+

19 number = models.PositiveIntegerField(validators=[MaxValueValidator(9999)]) 

+

20 street = models.CharField(max_length=64) 

+

21 city = models.CharField(max_length=64) 

+

22 state = models.CharField(max_length=2, validators=[MinLengthValidator(2)]) 

+

23 zip_code = models.PositiveIntegerField(validators=[MaxValueValidator(99999)]) 

+

24 country_iso_code = models.CharField(max_length=3, validators=[MinLengthValidator(3)]) 

+

25 

+

26 class Meta: 

+

27 """ 

+

28 Meta class for Lettings to specify verbose names 

+

29 """ 

+

30 verbose_name = "Address" 

+

31 verbose_name_plural = "Addresses" 

+

32 

+

33 def __str__(self) -> str: 

+

34 """ 

+

35 string method for Lettings 

+

36 Returns: 

+

37 A f-string with number and street address 

+

38 """ 

+

39 return f'{self.number} {self.street}' 

+

40 

+

41 

+

42class Letting(models.Model): 

+

43 """ 

+

44 Letting model for Lettings 

+

45 Attributes: 

+

46 title (str): Letting title 

+

47 address (Address): Letting address 

+

48 """ 

+

49 title = models.CharField(max_length=256) 

+

50 address = models.OneToOneField(Address, on_delete=models.CASCADE) 

+

51 

+

52 def __str__(self) -> str: 

+

53 """ 

+

54 String method for Lettings 

+

55 Returns: 

+

56 A f-string with letting title 

+

57 """ 

+

58 return self.title 

+
+ + + diff --git a/cov_html/z_a9b1b018a4ee155b_urls_py.html b/cov_html/z_a9b1b018a4ee155b_urls_py.html new file mode 100644 index 0000000000..6d2c380b64 --- /dev/null +++ b/cov_html/z_a9b1b018a4ee155b_urls_py.html @@ -0,0 +1,110 @@ + + + + + Coverage for lettings\urls.py: 100% + + + + + +
+
+

+ Coverage for lettings \ urls.py: + 100% +

+ +

+ 4 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.14.0, + created at 2026-05-22 10:56 +0200 +

+ +
+
+
+

1""" 

+

2URLs module for lettings app 

+

3""" 

+

4from django.urls import path 

+

5 

+

6from . import views 

+

7 

+

8app_name = 'lettings' 

+

9 

+

10urlpatterns = [ 

+

11 path('', views.index, name='index'), 

+

12 path('<int:letting_id>/', views.letting, name='letting'), 

+

13] 

+
+ + + diff --git a/cov_html/z_a9b1b018a4ee155b_views_py.html b/cov_html/z_a9b1b018a4ee155b_views_py.html new file mode 100644 index 0000000000..9c0132966f --- /dev/null +++ b/cov_html/z_a9b1b018a4ee155b_views_py.html @@ -0,0 +1,183 @@ + + + + + Coverage for lettings\views.py: 100% + + + + + +
+
+

+ Coverage for lettings \ views.py: + 100% +

+ +

+ 28 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.14.0, + created at 2026-05-22 10:56 +0200 +

+ +
+
+
+

1""" 

+

2Views module for lettings app 

+

3""" 

+

4from django.http import HttpRequest, HttpResponse 

+

5from django.shortcuts import render 

+

6 

+

7from .models import Letting 

+

8from monitoring import logger 

+

9 

+

10 

+

11# Aenean leo magna, vestibulum et tincidunt fermentum, consectetur quis velit. Sed non placerat 

+

12# massa. Integer est nunc, pulvinar a tempor et, bibendum id arcu. Vestibulum ante ipsum primis in 

+

13# faucibus orci luctus et ultrices posuere cubilia curae; Cras eget scelerisque 

+

14def index(request: HttpRequest) -> HttpResponse: 

+

15 """ 

+

16 View function for lettings index page 

+

17 Args: 

+

18 request (HttpRequest): Http Request object 

+

19 

+

20 Returns: 

+

21 An HTTP response with the list of lettings or an HTTP response with 500 error. 

+

22 """ 

+

23 try: 

+

24 lettings_list = Letting.objects.all() 

+

25 context = {'lettings_list': lettings_list} 

+

26 

+

27 logger.info(f"Going to lettings index page : {context=}, status = 200.") 

+

28 

+

29 return render(request, template_name='lettings/index.html', context=context, status=200) 

+

30 

+

31 except Exception as e: 

+

32 context = {"error": str(e)} 

+

33 

+

34 logger.error(f"Error 500 returned while reaching lettings index page : {context=}," 

+

35 f" status = 500.") 

+

36 

+

37 return render(request, template_name='error_500.html', context=context, status=500) 

+

38 

+

39 

+

40# Cras ultricies dignissim purus, vitae hendrerit ex varius non. In accumsan porta nisl id 

+

41# eleifend. Praesent dignissim, odio eu consequat pretium, purus urna vulputate arcu, vitae 

+

42# efficitur lacus justo nec purus. Aenean finibus faucibus lectus at porta. Maecenas auctor, est ut 

+

43# luctus congue, dui enim mattis enim, ac condimentum velit libero in magna. Suspendisse potenti. 

+

44# In tempus a nisi sed laoreet. Suspendisse porta dui eget sem accumsan interdum. Ut quis urna 

+

45# pellentesque justo mattis ullamcorper ac non tellus. In tristique mauris eu velit fermentum, 

+

46# tempus pharetra est luctus. Vivamus consequat aliquam libero, eget bibendum lorem. Sed non dolor 

+

47# risus. Mauris condimentum auctor elementum. Donec quis nisi ligula. Integer vehicula tincidunt 

+

48# enim, ac lacinia augue pulvinar sit amet. 

+

49def letting(request: HttpRequest, letting_id: int) -> HttpResponse: 

+

50 """ 

+

51 View function for letting detail page 

+

52 Args: 

+

53 request (HttpRequest): Http Request object 

+

54 letting_id (int): letting id 

+

55 

+

56 Returns: 

+

57 An HTTP response with the letting detail or an HTTP response with 404 error if not found 

+

58 or an HTTP response with 500 error 

+

59 """ 

+

60 try: 

+

61 letting = Letting.objects.get(id=letting_id) 

+

62 

+

63 context = { 

+

64 'title': letting.title, 

+

65 'address': letting.address, 

+

66 } 

+

67 

+

68 logger.info(f"Going to lettings details page : {context=}, status = 200.") 

+

69 

+

70 return render(request, template_name='lettings/letting.html', context=context, status=200) 

+

71 

+

72 except Letting.DoesNotExist as e: 

+

73 context = {"type": "letting", "id": letting_id, "error": str(e)} 

+

74 

+

75 logger.warning(f"Error 404 returned while reaching letting n°{letting_id} : {context=}," 

+

76 f" status = 404.") 

+

77 

+

78 return render(request, template_name='error_404.html', context=context, status=404) 

+

79 

+

80 except Exception as e: 

+

81 context = {"error": str(e)} 

+

82 

+

83 logger.error(f"Error 500 returned while reaching letting details page : {context=}," 

+

84 f" status = 500.") 

+

85 

+

86 return render(request, template_name='error_500.html', context=context, status=500) 

+
+ + + diff --git a/cov_html/z_b4872cbce420d762_models_py.html b/cov_html/z_b4872cbce420d762_models_py.html new file mode 100644 index 0000000000..53b5f5d8cc --- /dev/null +++ b/cov_html/z_b4872cbce420d762_models_py.html @@ -0,0 +1,121 @@ + + + + + Coverage for profiles\models.py: 100% + + + + + +
+
+

+ Coverage for profiles \ models.py: + 100% +

+ +

+ 7 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.14.0, + created at 2026-05-22 10:56 +0200 +

+ +
+
+
+

1""" 

+

2Models module for profiles app 

+

3""" 

+

4from django.db import models 

+

5from django.contrib.auth.models import User 

+

6 

+

7 

+

8class Profile(models.Model): 

+

9 """ 

+

10 Models class for profiles app 

+

11 Attributes: 

+

12 user (User): user 

+

13 favorite_city (str): The favorite city of the user 

+

14 """ 

+

15 user = models.OneToOneField(User, on_delete=models.CASCADE) 

+

16 favorite_city = models.CharField(max_length=64, blank=True) 

+

17 

+

18 def __str__(self) -> str: 

+

19 """ 

+

20 String method for profile model 

+

21 Returns: 

+

22 The user name of the profile 

+

23 """ 

+

24 return self.user.username 

+
+ + + diff --git a/cov_html/z_b4872cbce420d762_urls_py.html b/cov_html/z_b4872cbce420d762_urls_py.html new file mode 100644 index 0000000000..c27feb0078 --- /dev/null +++ b/cov_html/z_b4872cbce420d762_urls_py.html @@ -0,0 +1,110 @@ + + + + + Coverage for profiles\urls.py: 100% + + + + + +
+
+

+ Coverage for profiles \ urls.py: + 100% +

+ +

+ 4 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.14.0, + created at 2026-05-22 10:56 +0200 +

+ +
+
+
+

1""" 

+

2URLs module for profiles app 

+

3""" 

+

4from django.urls import path 

+

5 

+

6from . import views 

+

7 

+

8app_name = 'profiles' 

+

9 

+

10urlpatterns = [ 

+

11 path('', views.index, name='index'), 

+

12 path('<str:username>/', views.profile, name='profile'), 

+

13] 

+
+ + + diff --git a/cov_html/z_b4872cbce420d762_views_py.html b/cov_html/z_b4872cbce420d762_views_py.html new file mode 100644 index 0000000000..ebd90785ea --- /dev/null +++ b/cov_html/z_b4872cbce420d762_views_py.html @@ -0,0 +1,174 @@ + + + + + Coverage for profiles\views.py: 100% + + + + + +
+
+

+ Coverage for profiles \ views.py: + 100% +

+ +

+ 28 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.14.0, + created at 2026-05-22 10:56 +0200 +

+ +
+
+
+

1""" 

+

2Views module for profiles app 

+

3""" 

+

4from django.http import HttpRequest, HttpResponse 

+

5from django.shortcuts import render 

+

6from monitoring import logger 

+

7 

+

8from profiles.models import Profile 

+

9 

+

10 

+

11# Sed placerat quam in pulvinar commodo. Nullam laoreet consectetur ex, sed consequat libero 

+

12# pulvinar eget. Fusc faucibus, urna quis auctor pharetra, massa dolor cursus neque, quis dictum 

+

13# lacus d 

+

14def index(request: HttpRequest) -> HttpResponse: 

+

15 """ 

+

16 View function for profiles index page 

+

17 Args: 

+

18 request (HttpRequest): request object 

+

19 

+

20 Returns: 

+

21 An HTTP response with the list of profiles or HTTP response with 500 error. 

+

22 """ 

+

23 try: 

+

24 profiles_list = Profile.objects.all() 

+

25 context = {'profiles_list': profiles_list} 

+

26 

+

27 logger.info(f"Going to profiles index page : {context=}, status = 200.") 

+

28 

+

29 return render(request, template_name='profiles/index.html', context=context, status=200) 

+

30 

+

31 except Exception as e: 

+

32 context = {"error": str(e)} 

+

33 

+

34 logger.error(f"Error 500 returned while reaching profiles index page : {context=}" 

+

35 f", status = 500.") 

+

36 

+

37 return render(request, template_name='error_500.html', context=context, status=500) 

+

38 

+

39 

+

40# Aliquam sed metus eget nisi tincidunt ornare accumsan eget lac 

+

41# laoreet neque quis, pellentesque dui. Nullam facilisis pharetra vulputate. Sed tincidunt, dolor 

+

42# id facilisis fringilla, eros leo tristique lacus, it. Nam aliquam dignissim congue. Pellentesque 

+

43# habitant morbi tristique senectus et netus et males 

+

44def profile(request: HttpRequest, username: str): 

+

45 """ 

+

46 View function for profile details page 

+

47 Args: 

+

48 request (HttpRequest): request object 

+

49 username (str): username 

+

50 

+

51 Returns: 

+

52 An HTTP response with the profile or HTTP response with 404 error if not found 

+

53 or an HTTP response with 500 error 

+

54 """ 

+

55 try: 

+

56 profile = Profile.objects.get(user__username=username) 

+

57 context = {'profile': profile} 

+

58 

+

59 logger.info(f"Going to profile details page : {context=}, status = 200.") 

+

60 

+

61 return render(request, template_name='profiles/profile.html', context=context, status=200) 

+

62 

+

63 except Profile.DoesNotExist as e: 

+

64 context = {"type": "profile", "name": username, "error": str(e)} 

+

65 

+

66 logger.warning(f"Error 404 returned while reaching profile {username} : {context=}," 

+

67 f" status = 404.") 

+

68 

+

69 return render(request, template_name='error_404.html', context=context, status=404) 

+

70 

+

71 except Exception as e: 

+

72 context = {"error": str(e)} 

+

73 

+

74 logger.error(f"Error 500 returned while reaching profile details page : {context=}," 

+

75 f" status = 500.") 

+

76 

+

77 return render(request, template_name='error_500.html', context=context, status=500) 

+
+ + + diff --git a/cov_html/z_d8907effad88fb1e_urls_py.html b/cov_html/z_d8907effad88fb1e_urls_py.html new file mode 100644 index 0000000000..9c80146b72 --- /dev/null +++ b/cov_html/z_d8907effad88fb1e_urls_py.html @@ -0,0 +1,112 @@ + + + + + Coverage for oc_lettings_site\urls.py: 100% + + + + + +
+
+

+ Coverage for oc_lettings_site \ urls.py: + 100% +

+ +

+ 4 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.14.0, + created at 2026-05-22 10:56 +0200 +

+ +
+
+
+

1""" 

+

2URLs module for oc_lettings_site app. 

+

3Include the lettings and profiles apps urls 

+

4""" 

+

5from django.contrib import admin 

+

6from django.urls import path, include 

+

7 

+

8from . import views 

+

9 

+

10urlpatterns = [ 

+

11 path('', views.index, name='index'), 

+

12 path('lettings/', include('lettings.urls')), 

+

13 path('profiles/', include('profiles.urls')), 

+

14 path('admin/', admin.site.urls), 

+

15] 

+
+ + + diff --git a/cov_html/z_d8907effad88fb1e_views_py.html b/cov_html/z_d8907effad88fb1e_views_py.html new file mode 100644 index 0000000000..5d496eb607 --- /dev/null +++ b/cov_html/z_d8907effad88fb1e_views_py.html @@ -0,0 +1,134 @@ + + + + + Coverage for oc_lettings_site\views.py: 100% + + + + + +
+
+

+ Coverage for oc_lettings_site \ views.py: + 100% +

+ +

+ 12 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.14.0, + created at 2026-05-22 10:56 +0200 +

+ +
+
+
+

1""" 

+

2Views module for oc_lettings_site app 

+

3""" 

+

4from django.http import HttpRequest, HttpResponse 

+

5from django.shortcuts import render 

+

6 

+

7from monitoring import init_sentry, logger 

+

8 

+

9 

+

10# Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque molestie quam lobortis leo 

+

11# consectetur ullamcorper non id est. Praesent dictum, nulla eget feugiat sagittis, sem mi 

+

12# convallis eros, vitae dapibus nisi lorem dapibus sem. Maecenas pharetra purus ipsum, eget 

+

13# consequat ipsum lobortis quis. Phasellus eleifend ex auctor venenatis tempus. Aliquam vitae erat 

+

14# ac orci placerat luctus. Nullam elementum urna nisi, pellentesque iaculis enim cursus in. 

+

15# Praesent volutpat porttitor magna, non finibus neque cursus id. 

+

16def index(request: HttpRequest) -> HttpResponse: 

+

17 """ 

+

18 View function for home page 

+

19 Args: 

+

20 request (HttpRequest): Http Request object 

+

21 

+

22 Returns: 

+

23 An HTTP response with index page or HTTP response with 500 error. 

+

24 """ 

+

25 init_sentry() 

+

26 try: 

+

27 logger.info(f"Going to home page : status = 200.") 

+

28 

+

29 return render(request, template_name='index.html') 

+

30 

+

31 except Exception as e: 

+

32 context = {'error': str(e)} 

+

33 

+

34 logger.error(f"Error 500 returned while reaching home page : {context=}" 

+

35 f", status = 500.") 

+

36 

+

37 return render(request, template_name='error_500.html', context=context) 

+
+ + + diff --git a/flake8-report/back.svg b/flake8-report/back.svg new file mode 100644 index 0000000000..ce80d2e6da --- /dev/null +++ b/flake8-report/back.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/flake8-report/file.svg b/flake8-report/file.svg new file mode 100644 index 0000000000..98706cfe53 --- /dev/null +++ b/flake8-report/file.svg @@ -0,0 +1,64 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/flake8-report/index.html b/flake8-report/index.html new file mode 100644 index 0000000000..195631a111 --- /dev/null +++ b/flake8-report/index.html @@ -0,0 +1,30 @@ + + + + flake8 violations + + + + +
+
+

flake8 violations

+

Generated on 2026-05-22 21:12 + with mccabe: 0.6.1, pycodestyle: 2.5.0, pyflakes: 2.1.1 +

+
    + +
  • +
    + + + +

    All good!

    +

    No flake8 errors found in 32 files scanned.

    +
    +
  • + +
+
+ + \ No newline at end of file diff --git a/flake8-report/styles.css b/flake8-report/styles.css new file mode 100644 index 0000000000..6e0e447a6e --- /dev/null +++ b/flake8-report/styles.css @@ -0,0 +1,327 @@ +html { + font-family: sans-serif; + font-size: 90%; +} + +#masthead { + position: fixed; + left: 0; + top: 0; + right: 0; + height: 40%; +} + +h1, h2 { + font-family: sans-serif; + font-weight: normal; +} + +h1 { + color: white; + font-size: 36px; + margin-top: 1em; +} + +h1 img { + margin-right: 0.3em; +} + +h2 { + margin-top: 0; +} + +h1 a { + color: white; +} + +#versions { + color: rgba(255, 255, 255, 0.7); +} + +#page { + position: relative; + max-width: 960px; + margin: 0 auto; +} + +#index { + background-color: white; + box-shadow: 0 0 4px rgba(0, 0, 0, 0.8); + padding: 0; + margin: 0; +} + +#index li { + list-style: none; + margin: 0; + padding: 1px 0; +} + +#index li + li { + border-top: solid silver 1px; +} + +.details p { + margin-left: 3em; + color: #888; +} + +#index a { + display: block; + padding: 0.8em 1em; + cursor: pointer; +} + +#index #all-good { + padding: 1.4em 1em 0.8em; +} + +#all-good .count .tick { + font-size: 2em; +} + +#all-good .count { + float: left; +} + +#all-good h2, +#all-good p { + margin-left: 50px; +} + +#index a:hover { + background-color: #eee; +} + +.count { + display: inline-block; + border-radius: 50%; + text-align: center; + width: 2.5em; + line-height: 2.5em; + height: 2.5em; + color: white; + margin-right: 1em; +} + +.sev-1 { + background-color: #a00; +} +.sev-2 { + background-color: #b80; +} +.sev-3 { + background-color: #28c; +} +.sev-4 { + background-color: #383; +} + +a { + text-decoration: none; +} + +#doc { + background-color: white; + margin: 1em 0; + padding: 1em; + padding-left: 1.2em; + position: relative; + box-shadow: 0 0 4px rgba(0, 0, 0, 0.8); +} + +#doc pre { + margin: 0; + padding: 0.07em; +} + +.violations { + position: absolute; + margin: 1.2em 0 0 3em; + padding: 0.5em 1em; + font-size: 14px; + background-color: white; + box-shadow: 0 0 4px rgba(0, 0, 0, 0.4); + display: none; +} + +.violations .count { + font-size: 70%; +} + +.violations li { + padding: 0.1em 0.3em; + list-style: none; +} + +.line-violations::before { + display: block; + content: ""; + position: absolute; + left: -1em; + width: 14px; + height: 14px; + border-radius: 50%; + background-color: red; +} + +.code:hover .violations { + display: block; +} + +tt { + white-space: pre-wrap; + font-family: Consolas, monospace; + font-size: 10pt; +} + +tt i { + color: silver; + display: inline-block; + text-align: right; + width: 3em; + box-sizing: border-box; + height: 100%; + border-right: solid #eee 1px; + padding-right: 0.2em; +} + +.le { + background-color: #ffe8e8; + cursor: pointer; +} + +.le:hover { + background-color: #fcc; +} + +.details { + clear: both; +} + +#index .details { + border-top-style: none; + margin: 1em; +} + +ul.details { + margin-left: 0; + padding-left: 0; +} + +#index .details li { + list-style: none; + border-top-style: none; + margin: 0.3em 0; + padding: 0; +} + +#srclink { + float: right; + font-size: 36px; + margin: 0; +} + +#srclink a { + color: white; +} + +#index .details a { + padding: 0; + color: inherit; +} + +.le { + background-color: #ffe8e8; + cursor: pointer; +} + +.le.sev-1 { + background-color: #f88; +} +.le.sev-2 { + background-color: #fda; +} +.le.sev-3 { + background-color: #adf; +} + +img { + height: 1.2em; + vertical-align: -0.35em; +} + +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.hll { background-color: #ffffcc } +.c { color: #3D7B7B; font-style: italic } /* Comment */ +.err { border: 1px solid #F00 } /* Error */ +.k { color: #008000; font-weight: bold } /* Keyword */ +.o { color: #666 } /* Operator */ +.ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ +.cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ +.cp { color: #9C6500 } /* Comment.Preproc */ +.cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ +.c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ +.cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ +.gd { color: #A00000 } /* Generic.Deleted */ +.ge { font-style: italic } /* Generic.Emph */ +.ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.gr { color: #E40000 } /* Generic.Error */ +.gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.gi { color: #008400 } /* Generic.Inserted */ +.go { color: #717171 } /* Generic.Output */ +.gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.gs { font-weight: bold } /* Generic.Strong */ +.gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.gt { color: #04D } /* Generic.Traceback */ +.kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +.kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +.kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +.kp { color: #008000 } /* Keyword.Pseudo */ +.kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +.kt { color: #B00040 } /* Keyword.Type */ +.m { color: #666 } /* Literal.Number */ +.s { color: #BA2121 } /* Literal.String */ +.na { color: #687822 } /* Name.Attribute */ +.nb { color: #008000 } /* Name.Builtin */ +.nc { color: #00F; font-weight: bold } /* Name.Class */ +.no { color: #800 } /* Name.Constant */ +.nd { color: #A2F } /* Name.Decorator */ +.ni { color: #717171; font-weight: bold } /* Name.Entity */ +.ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ +.nf { color: #00F } /* Name.Function */ +.nl { color: #767600 } /* Name.Label */ +.nn { color: #00F; font-weight: bold } /* Name.Namespace */ +.nt { color: #008000; font-weight: bold } /* Name.Tag */ +.nv { color: #19177C } /* Name.Variable */ +.ow { color: #A2F; font-weight: bold } /* Operator.Word */ +.w { color: #BBB } /* Text.Whitespace */ +.mb { color: #666 } /* Literal.Number.Bin */ +.mf { color: #666 } /* Literal.Number.Float */ +.mh { color: #666 } /* Literal.Number.Hex */ +.mi { color: #666 } /* Literal.Number.Integer */ +.mo { color: #666 } /* Literal.Number.Oct */ +.sa { color: #BA2121 } /* Literal.String.Affix */ +.sb { color: #BA2121 } /* Literal.String.Backtick */ +.sc { color: #BA2121 } /* Literal.String.Char */ +.dl { color: #BA2121 } /* Literal.String.Delimiter */ +.sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +.s2 { color: #BA2121 } /* Literal.String.Double */ +.se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ +.sh { color: #BA2121 } /* Literal.String.Heredoc */ +.si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ +.sx { color: #008000 } /* Literal.String.Other */ +.sr { color: #A45A77 } /* Literal.String.Regex */ +.s1 { color: #BA2121 } /* Literal.String.Single */ +.ss { color: #19177C } /* Literal.String.Symbol */ +.bp { color: #008000 } /* Name.Builtin.Pseudo */ +.fm { color: #00F } /* Name.Function.Magic */ +.vc { color: #19177C } /* Name.Variable.Class */ +.vg { color: #19177C } /* Name.Variable.Global */ +.vi { color: #19177C } /* Name.Variable.Instance */ +.vm { color: #19177C } /* Name.Variable.Magic */ +.il { color: #666 } /* Literal.Number.Integer.Long */ \ No newline at end of file From c36df220292b815e21cd2c95bf364502a48a7d33 Mon Sep 17 00:00:00 2001 From: NM Date: Fri, 22 May 2026 21:39:34 +0200 Subject: [PATCH 13/41] Modification : update yaml for CI --- .github/workflows/django.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml index e228964896..e3062dfc63 100644 --- a/.github/workflows/django.yml +++ b/.github/workflows/django.yml @@ -15,6 +15,8 @@ jobs: strategy: matrix: python-version: ["3.10"] + env: + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true steps: - uses: actions/checkout@v4 From b2f8253b1e1c373bd4e0e18168573f5446bb9ac3 Mon Sep 17 00:00:00 2001 From: NM Date: Sat, 23 May 2026 08:18:08 +0200 Subject: [PATCH 14/41] Modification : update tests with refactoring in several modules --- lettings/tests/tests_url.py | 23 +++++++++++++ lettings/tests/{tests.py => tests_view.py} | 33 ++---------------- oc_lettings_site/tests/tests_model.py | 20 +++++++++++ oc_lettings_site/tests/tests_url.py | 12 +++++++ .../tests/{tests.py => tests_view.py} | 12 ++----- profiles/tests/tests_model.py | 14 ++++++++ profiles/tests/tests_url.py | 30 ++++++++++++++++ profiles/tests/{tests.py => tests_view.py} | 34 ++----------------- 8 files changed, 105 insertions(+), 73 deletions(-) create mode 100644 lettings/tests/tests_url.py rename lettings/tests/{tests.py => tests_view.py} (80%) create mode 100644 oc_lettings_site/tests/tests_model.py create mode 100644 oc_lettings_site/tests/tests_url.py rename oc_lettings_site/tests/{tests.py => tests_view.py} (86%) create mode 100644 profiles/tests/tests_model.py create mode 100644 profiles/tests/tests_url.py rename profiles/tests/{tests.py => tests_view.py} (78%) diff --git a/lettings/tests/tests_url.py b/lettings/tests/tests_url.py new file mode 100644 index 0000000000..0a7309ee62 --- /dev/null +++ b/lettings/tests/tests_url.py @@ -0,0 +1,23 @@ +""" +Tests module for lettings app urls +""" +import pytest + +from django.urls import reverse, resolve + +from lettings.models import Letting, Address + + +class TestLettingsUrl: + def test_lettings_index_url(self): + path = reverse(viewname="lettings:index") + + assert path == "/lettings/" + assert resolve(path).view_name == "lettings:index" + + @pytest.mark.django_db + def test_lettings_letting_url(self, get_address: Address, get_letting: Letting): + path = reverse(viewname="lettings:letting", kwargs={"letting_id": get_letting.id}) + + assert path == "/lettings/1/" + assert resolve(path).view_name == "lettings:letting" diff --git a/lettings/tests/tests.py b/lettings/tests/tests_view.py similarity index 80% rename from lettings/tests/tests.py rename to lettings/tests/tests_view.py index 9d4e923b93..0731a4e8df 100644 --- a/lettings/tests/tests.py +++ b/lettings/tests/tests_view.py @@ -1,9 +1,9 @@ """ -Tests module for lettings app +Tests module for lettings app views """ import pytest -from django.urls import reverse, resolve +from django.urls import reverse from django.test import Client from pytest_django.asserts import assertTemplateUsed from _pytest.monkeypatch import MonkeyPatch @@ -11,21 +11,6 @@ from lettings.models import Letting, Address -class TestLettingsUrl: - def test_lettings_index_url(self): - path = reverse(viewname="lettings:index") - - assert path == "/lettings/" - assert resolve(path).view_name == "lettings:index" - - @pytest.mark.django_db - def test_lettings_letting_url(self, get_address: Address, get_letting: Letting): - path = reverse(viewname="lettings:letting", kwargs={"letting_id": get_letting.id}) - - assert path == "/lettings/1/" - assert resolve(path).view_name == "lettings:letting" - - class TestLettingsView: @pytest.mark.django_db def test_lettings_index_view_ok(self, get_letting: Letting): @@ -115,17 +100,3 @@ def raise_error(*args, **kwargs): assert expected_h1 in content assert response.status_code == 500 assertTemplateUsed(response, template_name="error_500.html") - - -class TestLettingsModel: - @pytest.mark.django_db - def test_lettings_address_model_ok(self, get_address: Address): - expected = f"{get_address.number} {get_address.street}" - - assert str(get_address) == expected - - @pytest.mark.django_db - def test_lettings_letting_model_ok(self, get_letting: Letting): - expected = f"{get_letting.title}" - - assert str(get_letting) == expected diff --git a/oc_lettings_site/tests/tests_model.py b/oc_lettings_site/tests/tests_model.py new file mode 100644 index 0000000000..74f035e3bc --- /dev/null +++ b/oc_lettings_site/tests/tests_model.py @@ -0,0 +1,20 @@ +""" +Tests module for lettings app models +""" +import pytest + +from lettings.models import Letting, Address + + +class TestLettingsModel: + @pytest.mark.django_db + def test_lettings_address_model_ok(self, get_address: Address): + expected = f"{get_address.number} {get_address.street}" + + assert str(get_address) == expected + + @pytest.mark.django_db + def test_lettings_letting_model_ok(self, get_letting: Letting): + expected = f"{get_letting.title}" + + assert str(get_letting) == expected diff --git a/oc_lettings_site/tests/tests_url.py b/oc_lettings_site/tests/tests_url.py new file mode 100644 index 0000000000..1140fabfdd --- /dev/null +++ b/oc_lettings_site/tests/tests_url.py @@ -0,0 +1,12 @@ +""" +Tests module for oc_lettings_site app urls +""" +from django.urls import reverse, resolve + + +class TestOcLettingsSiteUrl: + def test_index_url(self): + path = reverse("index") + + assert path == "/" + assert resolve(path).view_name == 'index' diff --git a/oc_lettings_site/tests/tests.py b/oc_lettings_site/tests/tests_view.py similarity index 86% rename from oc_lettings_site/tests/tests.py rename to oc_lettings_site/tests/tests_view.py index 3c297ea058..c6c2330a3b 100644 --- a/oc_lettings_site/tests/tests.py +++ b/oc_lettings_site/tests/tests_view.py @@ -1,23 +1,15 @@ """ -Tests module for oc_lettings_site app +Tests module for oc_lettings_site app views """ import pytest from django.template.response import TemplateResponse from django.test import Client -from django.urls import reverse, resolve +from django.urls import reverse from pytest_django.asserts import assertTemplateUsed from _pytest.monkeypatch import MonkeyPatch -class TestOcLettingsSiteUrl: - def test_index_url(self): - path = reverse("index") - - assert path == "/" - assert resolve(path).view_name == 'index' - - class TestOcLettingsSiteView: @pytest.mark.django_db def test_oc_lettings_site_index_view_ok(self): diff --git a/profiles/tests/tests_model.py b/profiles/tests/tests_model.py new file mode 100644 index 0000000000..44970b1485 --- /dev/null +++ b/profiles/tests/tests_model.py @@ -0,0 +1,14 @@ +""" +Tests module for profiles app models +""" +import pytest + +from profiles.models import Profile + + +class TestProfilesModel: + @pytest.mark.django_db + def test_profiles_profile_model_ok(self, get_profile: Profile): + expected = f"{get_profile.user.username}" + + assert str(get_profile) == expected diff --git a/profiles/tests/tests_url.py b/profiles/tests/tests_url.py new file mode 100644 index 0000000000..1d52508917 --- /dev/null +++ b/profiles/tests/tests_url.py @@ -0,0 +1,30 @@ +""" +Tests module for profiles app urls +""" +import pytest + +from django.contrib.auth.models import User +from django.urls import reverse, resolve + +from profiles.models import Profile + + +class TestProfilesUrl: + def test_profiles_index_url(self): + path = reverse("profiles:index") + + assert path == "/profiles/" + assert resolve(path).view_name == 'profiles:index' + + @pytest.mark.django_db + def test_profiles_profile_url(self): + Profile.objects.create(user=User.objects.create_user(username="Username", + first_name='First Name', + last_name='Last Name', + email='test@test.com'), + favorite_city="Paris") + + path = reverse(viewname="profiles:profile", kwargs={'username': "Username"}) + + assert path == "/profiles/Username/" + assert resolve(path).view_name == "profiles:profile" diff --git a/profiles/tests/tests.py b/profiles/tests/tests_view.py similarity index 78% rename from profiles/tests/tests.py rename to profiles/tests/tests_view.py index ddb06cbbd8..1951f139fb 100644 --- a/profiles/tests/tests.py +++ b/profiles/tests/tests_view.py @@ -1,10 +1,9 @@ """ -Tests module for profiles app +Tests module for profiles app views """ import pytest -from django.contrib.auth.models import User -from django.urls import reverse, resolve +from django.urls import reverse from django.test import Client from pytest_django.asserts import assertTemplateUsed from _pytest.monkeypatch import MonkeyPatch @@ -12,27 +11,6 @@ from profiles.models import Profile -class TestProfilesUrl: - def test_profiles_index_url(self): - path = reverse("profiles:index") - - assert path == "/profiles/" - assert resolve(path).view_name == 'profiles:index' - - @pytest.mark.django_db - def test_profiles_profile_url(self): - Profile.objects.create(user=User.objects.create_user(username="Username", - first_name='First Name', - last_name='Last Name', - email='test@test.com'), - favorite_city="Paris") - - path = reverse(viewname="profiles:profile", kwargs={'username': "Username"}) - - assert path == "/profiles/Username/" - assert resolve(path).view_name == "profiles:profile" - - class TestProfilesView: @pytest.mark.django_db def test_profiles_index_view_ok(self, get_profile: Profile): @@ -124,11 +102,3 @@ def raise_error(*args, **kwargs): assert expected_h1 in content assert response.status_code == 500 assertTemplateUsed(response, template_name="error_500.html") - - -class TestProfilesModel: - @pytest.mark.django_db - def test_profiles_profile_model_ok(self, get_profile: Profile): - expected = f"{get_profile.user.username}" - - assert str(get_profile) == expected From 1e94a7d2799ae0675e2d4cde9e5123efae17ce0d Mon Sep 17 00:00:00 2001 From: NM Date: Sat, 23 May 2026 08:20:17 +0200 Subject: [PATCH 15/41] Modification : update cfg files to run tests*.py --- setup.cfg | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 5fb8f09adb..9584347f87 100644 --- a/setup.cfg +++ b/setup.cfg @@ -6,5 +6,4 @@ exclude = **/migrations/*,env,cov_html [tool:pytest] DJANGO_SETTINGS_MODULE = oc_lettings_site.settings -python_files = tests.py addopts = -v --cov=lettings --cov=profiles --cov=oc_lettings_site --cov-report=html:cov_html From 06ceb755bacbbfeabe76f5c084b45b8ca825feef Mon Sep 17 00:00:00 2001 From: NM Date: Sat, 23 May 2026 08:27:11 +0200 Subject: [PATCH 16/41] Modification : update tests with refactoring in several modules --- cov_html/class_index.html | 4 ++-- cov_html/function_index.html | 4 ++-- cov_html/index.html | 4 ++-- cov_html/z_a9b1b018a4ee155b_models_py.html | 4 ++-- cov_html/z_a9b1b018a4ee155b_urls_py.html | 4 ++-- cov_html/z_a9b1b018a4ee155b_views_py.html | 4 ++-- cov_html/z_b4872cbce420d762_models_py.html | 4 ++-- cov_html/z_b4872cbce420d762_urls_py.html | 4 ++-- cov_html/z_b4872cbce420d762_views_py.html | 4 ++-- cov_html/z_d8907effad88fb1e_urls_py.html | 4 ++-- cov_html/z_d8907effad88fb1e_views_py.html | 4 ++-- {oc_lettings_site => lettings}/tests/tests_model.py | 0 setup.cfg | 1 + 13 files changed, 23 insertions(+), 22 deletions(-) rename {oc_lettings_site => lettings}/tests/tests_model.py (100%) diff --git a/cov_html/class_index.html b/cov_html/class_index.html index 52ccc8a9f7..afefc90b74 100644 --- a/cov_html/class_index.html +++ b/cov_html/class_index.html @@ -55,7 +55,7 @@

coverage.py v7.14.0, - created at 2026-05-22 10:56 +0200 + created at 2026-05-23 08:26 +0200

@@ -216,7 +216,7 @@

coverage.py v7.14.0, - created at 2026-05-22 10:56 +0200 + created at 2026-05-23 08:26 +0200

@@ -256,7 +256,7 @@

coverage.py v7.14.0, - created at 2026-05-22 10:56 +0200 + created at 2026-05-23 08:26 +0200

@@ -165,7 +165,7 @@

coverage.py v7.14.0, - created at 2026-05-22 10:56 +0200 + created at 2026-05-23 08:26 +0200