dbca-utils 2.1.0__tar.gz → 2.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dbca-utils
3
- Version: 2.1.0
3
+ Version: 2.1.2
4
4
  Summary: Utilities for DBCA Django apps
5
- Author-email: Rocky Chen <rocky.chen@dbca.wa.gov.au>, Ashley Felton <ashley.felton@dbca.wa.gov.au>
6
- Project-URL: Homepage, https://github.com/dbca-wa/dbca-utils
7
- Project-URL: Repository, https://github.com/dbca-wa/dbca-utils.git
8
- Project-URL: Changelog, https://github.com/dbca-wa/dbca-utils/blob/master/CHANGELOG.md
9
- Project-URL: GitHub, https://github.com/dbca-wa/dbca-utils
5
+ Author-Email: Rocky Chen <rocky.chen@dbca.wa.gov.au>, Ashley Felton <ashley.felton@dbca.wa.gov.au>
6
+ License-Expression: Apache-2.0
10
7
  Classifier: Framework :: Django
11
8
  Classifier: Framework :: Django :: 4.0
12
9
  Classifier: Framework :: Django :: 4.2
@@ -15,7 +12,6 @@ Classifier: Framework :: Django :: 5.2
15
12
  Classifier: Environment :: Web Environment
16
13
  Classifier: Intended Audience :: Developers
17
14
  Classifier: Development Status :: 5 - Production/Stable
18
- Classifier: License :: OSI Approved :: Apache Software License
19
15
  Classifier: Programming Language :: Python
20
16
  Classifier: Programming Language :: Python :: 3
21
17
  Classifier: Programming Language :: Python :: 3.10
@@ -24,11 +20,14 @@ Classifier: Programming Language :: Python :: 3.12
24
20
  Classifier: Programming Language :: Python :: 3.13
25
21
  Classifier: Topic :: Software Development :: Libraries
26
22
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Project-URL: Homepage, https://github.com/dbca-wa/dbca-utils
24
+ Project-URL: Repository, https://github.com/dbca-wa/dbca-utils.git
25
+ Project-URL: Changelog, https://github.com/dbca-wa/dbca-utils/blob/master/CHANGELOG.md
26
+ Project-URL: GitHub, https://github.com/dbca-wa/dbca-utils
27
27
  Requires-Python: <4.0,>=3.10
28
- Description-Content-Type: text/markdown
29
- License-File: LICENSE
30
28
  Requires-Dist: django<6,>=4
31
- Dynamic: license-file
29
+ Requires-Dist: markupsafe==3.0.2
30
+ Description-Content-Type: text/markdown
32
31
 
33
32
  # Overview
34
33
 
@@ -0,0 +1,72 @@
1
+ [project]
2
+ name = "dbca-utils"
3
+ version = "2.1.2"
4
+ description = "Utilities for DBCA Django apps"
5
+ authors = [
6
+ { name = "Rocky Chen", email = "rocky.chen@dbca.wa.gov.au" },
7
+ { name = "Ashley Felton", email = "ashley.felton@dbca.wa.gov.au" },
8
+ ]
9
+ readme = "README.md"
10
+ license = "Apache-2.0"
11
+ classifiers = [
12
+ "Framework :: Django",
13
+ "Framework :: Django :: 4.0",
14
+ "Framework :: Django :: 4.2",
15
+ "Framework :: Django :: 5.0",
16
+ "Framework :: Django :: 5.2",
17
+ "Environment :: Web Environment",
18
+ "Intended Audience :: Developers",
19
+ "Development Status :: 5 - Production/Stable",
20
+ "Programming Language :: Python",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ "Topic :: Software Development :: Libraries",
27
+ "Topic :: Software Development :: Libraries :: Python Modules",
28
+ ]
29
+ requires-python = ">=3.10,<4.0"
30
+ dependencies = [
31
+ "django>=4,<6",
32
+ "markupsafe==3.0.2",
33
+ ]
34
+
35
+ [project.urls]
36
+ Homepage = "https://github.com/dbca-wa/dbca-utils"
37
+ Repository = "https://github.com/dbca-wa/dbca-utils.git"
38
+ Changelog = "https://github.com/dbca-wa/dbca-utils/blob/master/CHANGELOG.md"
39
+ GitHub = "https://github.com/dbca-wa/dbca-utils"
40
+
41
+ [dependency-groups]
42
+ dev = [
43
+ "pytest-django>=4.11.0",
44
+ "pytest-sugar>=1.0.0",
45
+ "tox>=4.25.0",
46
+ "tox-uv>=1.25.0",
47
+ ]
48
+
49
+ [build-system]
50
+ requires = [
51
+ "pdm-backend",
52
+ ]
53
+ build-backend = "pdm.backend"
54
+
55
+ [tool.uv]
56
+ package = true
57
+
58
+ [tool.pytest.ini_options]
59
+ DJANGO_SETTINGS_MODULE = "tests.settings"
60
+ pythonpath = ". src"
61
+ python_files = "tests.py test_*.py"
62
+
63
+ [tool.ruff]
64
+ line-length = 140
65
+ indent-width = 4
66
+
67
+ [tool.ruff.lint]
68
+ ignore = [
69
+ "E265",
70
+ "E501",
71
+ "E722",
72
+ ]
@@ -5,6 +5,7 @@ from django.contrib.auth.middleware import AuthenticationMiddleware, get_user
5
5
  from django.utils import timezone
6
6
  from django.utils.deprecation import MiddlewareMixin
7
7
  from django.utils.functional import SimpleLazyObject
8
+ from markupsafe import escape
8
9
 
9
10
  from dbca_utils.utils import env
10
11
 
@@ -13,18 +14,16 @@ LOCAL_USERGROUPS = env("LOCAL_USERGROUPS", default=[])
13
14
  User = get_user_model()
14
15
 
15
16
 
16
- def sync_usergroups(user, groups):
17
+ def sync_usergroups(user, groups=None):
17
18
  from django.contrib.auth.models import Group
18
19
 
19
- usergroups = (
20
- [Group.objects.get_or_create(name=name)[0] for name in groups.split(",")]
21
- if groups
22
- else []
23
- )
20
+ if groups:
21
+ usergroups = [Group.objects.get_or_create(name=name)[0] for name in groups.split(",")]
22
+ else:
23
+ usergroups = []
24
+
24
25
  usergroups.sort(key=lambda o: o.id)
25
- existing_usergroups = list(
26
- user.groups.exclude(name__in=LOCAL_USERGROUPS).order_by("id")
27
- )
26
+ existing_usergroups = list(user.groups.exclude(name__in=LOCAL_USERGROUPS).order_by("id"))
28
27
  index1 = 0
29
28
  index2 = 0
30
29
  len1 = len(usergroups)
@@ -76,9 +75,7 @@ if ENABLE_AUTH2_GROUPS:
76
75
  existing_groups = request.session.get("usergroups")
77
76
  if groups != existing_groups:
78
77
  # User group is changed.
79
- request.user = SimpleLazyUser(
80
- lambda: get_user(request), request, groups
81
- )
78
+ request.user = SimpleLazyUser(lambda: get_user(request), request, groups)
82
79
  return
83
80
  original_process_request(self, request)
84
81
 
@@ -102,11 +99,7 @@ class SSOLoginMiddleware(MiddlewareMixin):
102
99
  def process_request(self, request):
103
100
  # Logout headers included with request.
104
101
  if (
105
- (
106
- request.path.startswith("/logout")
107
- or request.path.startswith("/admin/logout")
108
- or request.path.startswith("/ledger/logout")
109
- )
102
+ (request.path.startswith("/logout") or request.path.startswith("/admin/logout") or request.path.startswith("/ledger/logout"))
110
103
  and "HTTP_X_LOGOUT_URL" in request.META
111
104
  and request.META["HTTP_X_LOGOUT_URL"]
112
105
  ):
@@ -114,18 +107,20 @@ class SSOLoginMiddleware(MiddlewareMixin):
114
107
  return http.HttpResponseRedirect(request.META["HTTP_X_LOGOUT_URL"])
115
108
 
116
109
  # Auth2 is not enabled, skip further processing.
117
- if (
118
- "HTTP_REMOTE_USER" not in request.META
119
- or not request.META["HTTP_REMOTE_USER"]
120
- ):
110
+ if "HTTP_REMOTE_USER" not in request.META or not request.META["HTTP_REMOTE_USER"]:
121
111
  # auth2 not enabled
122
112
  return
123
113
 
124
- user_authenticated = request.user.is_authenticated
125
-
126
114
  # Auth2 is enabled.
127
- # Request user is not authenticated.
128
- if not user_authenticated:
115
+ # Security check: if the logged-in request user's email does not match the email
116
+ # returned from Auth2, invalidate the current request session and force a new session
117
+ # using the returned SSO values.
118
+ if request.user.is_authenticated and request.user.email != request.META["HTTP_X_EMAIL"]:
119
+ logout(request)
120
+
121
+ # Request user is not authenticated locally: obtain user attributes from the request.META dict
122
+ # returned by SSO.
123
+ if not request.user.is_authenticated:
129
124
  attributemap = {
130
125
  "username": "HTTP_REMOTE_USER",
131
126
  "last_name": "HTTP_X_LAST_NAME",
@@ -137,31 +132,28 @@ class SSOLoginMiddleware(MiddlewareMixin):
137
132
  if value in request.META:
138
133
  attributemap[key] = request.META[value]
139
134
 
135
+ # Sanitise first_name and last_name values, because end-users have control over these
136
+ # values and could conceivably inject malicious values into them (e.g. a XSS attack).
137
+ if "first_name" in attributemap:
138
+ attributemap["first_name"] = str(escape(attributemap["first_name"]))
139
+ if "last_name" in attributemap:
140
+ attributemap["last_name"] = str(escape(attributemap["last_name"]))
141
+
140
142
  # Optional setting: projects may define accepted user email domains either as
141
143
  # a list of strings, or a single string.
142
- if (
143
- hasattr(settings, "ALLOWED_EMAIL_SUFFIXES")
144
- and settings.ALLOWED_EMAIL_SUFFIXES
145
- ):
146
- allowed = settings.ALLOWED_EMAIL_SUFFIXES
144
+ if hasattr(settings, "ALLOWED_EMAIL_SUFFIXES") and settings.ALLOWED_EMAIL_SUFFIXES:
147
145
  if isinstance(settings.ALLOWED_EMAIL_SUFFIXES, str):
148
- allowed = [settings.ALLOWED_EMAIL_SUFFIXES]
149
- if not any(
150
- [attributemap["email"].lower().endswith(x) for x in allowed]
151
- ):
146
+ allowed_email_suffixes = list(settings.ALLOWED_EMAIL_SUFFIXES)
147
+ else:
148
+ allowed_email_suffixes = settings.ALLOWED_EMAIL_SUFFIXES
149
+ # If the user email suffix is not in the allowed list, return a 404 response.
150
+ if not any([attributemap["email"].lower().endswith(suffix) for suffix in allowed_email_suffixes]):
152
151
  return http.HttpResponseForbidden()
153
152
 
154
- if (
155
- attributemap["email"]
156
- and User.objects.filter(email__iexact=attributemap["email"]).exists()
157
- ):
153
+ # Check for an existing User instance.
154
+ if attributemap["email"] and User.objects.filter(email__iexact=attributemap["email"]).exists():
158
155
  user = User.objects.filter(email__iexact=attributemap["email"])[0]
159
- elif (
160
- User.__name__ != "EmailUser"
161
- and User.objects.filter(
162
- username__iexact=attributemap["username"]
163
- ).exists()
164
- ):
156
+ elif User.__name__ != "EmailUser" and User.objects.filter(username__iexact=attributemap["username"]).exists():
165
157
  user = User.objects.filter(username__iexact=attributemap["username"])[0]
166
158
  else:
167
159
  user = User(last_login=timezone.localtime())
@@ -174,7 +166,7 @@ class SSOLoginMiddleware(MiddlewareMixin):
174
166
  # Log the user in.
175
167
  login(request, user)
176
168
 
177
- # Synchronize the user groups
169
+ # Synchronize the user groups.
178
170
  if ENABLE_AUTH2_GROUPS and "HTTP_X_GROUPS" in request.META:
179
171
  groups = request.META["HTTP_X_GROUPS"] or None
180
172
  sync_usergroups(user, groups)
File without changes
@@ -0,0 +1,6 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class TestsConfig(AppConfig):
5
+ default_auto_field = "django.db.models.AutoField"
6
+ name = "tests"
@@ -0,0 +1,63 @@
1
+ import django.db.models.deletion
2
+ import django.utils.timezone
3
+ from django.conf import settings
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+ initial = True
9
+
10
+ dependencies = [
11
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
12
+ ]
13
+
14
+ operations = [
15
+ migrations.CreateModel(
16
+ name="TestModel",
17
+ fields=[
18
+ (
19
+ "id",
20
+ models.AutoField(
21
+ auto_created=True,
22
+ primary_key=True,
23
+ serialize=False,
24
+ verbose_name="ID",
25
+ ),
26
+ ),
27
+ ("effective_to", models.DateTimeField(blank=True, null=True)),
28
+ (
29
+ "created",
30
+ models.DateTimeField(
31
+ default=django.utils.timezone.now, editable=False
32
+ ),
33
+ ),
34
+ ("modified", models.DateTimeField(auto_now=True)),
35
+ ("name", models.CharField(max_length=64)),
36
+ (
37
+ "creator",
38
+ models.ForeignKey(
39
+ blank=True,
40
+ editable=False,
41
+ null=True,
42
+ on_delete=django.db.models.deletion.PROTECT,
43
+ related_name="%(app_label)s_%(class)s_created",
44
+ to=settings.AUTH_USER_MODEL,
45
+ ),
46
+ ),
47
+ (
48
+ "modifier",
49
+ models.ForeignKey(
50
+ blank=True,
51
+ editable=False,
52
+ null=True,
53
+ on_delete=django.db.models.deletion.PROTECT,
54
+ related_name="%(app_label)s_%(class)s_modified",
55
+ to=settings.AUTH_USER_MODEL,
56
+ ),
57
+ ),
58
+ ],
59
+ options={
60
+ "abstract": False,
61
+ },
62
+ ),
63
+ ]
File without changes
@@ -0,0 +1,11 @@
1
+ from django.db import models
2
+
3
+ from dbca_utils.models import ActiveMixin, ActiveMixinManager, AuditMixin
4
+
5
+
6
+ class TestModel(ActiveMixin, AuditMixin):
7
+ name = models.CharField(max_length=64)
8
+ objects = ActiveMixinManager()
9
+
10
+ def __str__(self):
11
+ return self.name
@@ -0,0 +1,46 @@
1
+ SECRET_KEY = "secretkey"
2
+
3
+ INSTALLED_APPS = [
4
+ "django.contrib.auth",
5
+ "django.contrib.contenttypes",
6
+ "django.contrib.sessions",
7
+ "django.contrib.messages",
8
+ "django.contrib.staticfiles",
9
+ "tests",
10
+ ]
11
+
12
+ MIDDLEWARE = [
13
+ "django.middleware.security.SecurityMiddleware",
14
+ "django.contrib.sessions.middleware.SessionMiddleware",
15
+ "django.middleware.common.CommonMiddleware",
16
+ "django.middleware.csrf.CsrfViewMiddleware",
17
+ "django.contrib.auth.middleware.AuthenticationMiddleware",
18
+ "django.contrib.messages.middleware.MessageMiddleware",
19
+ "django.middleware.clickjacking.XFrameOptionsMiddleware",
20
+ "dbca_utils.middleware.SSOLoginMiddleware",
21
+ ]
22
+
23
+ ROOT_URLCONF = "tests.urls"
24
+
25
+ TEMPLATES = [
26
+ {
27
+ "BACKEND": "django.template.backends.django.DjangoTemplates",
28
+ "APP_DIRS": True,
29
+ "OPTIONS": {
30
+ "context_processors": [
31
+ "django.template.context_processors.debug",
32
+ "django.template.context_processors.request",
33
+ "django.contrib.auth.context_processors.auth",
34
+ "django.contrib.messages.context_processors.messages",
35
+ ]
36
+ },
37
+ }
38
+ ]
39
+
40
+ DATABASES = {"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}}
41
+
42
+ STATIC_URL = "/static/"
43
+
44
+ DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
45
+
46
+ USE_TZ = True
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>{{ TITLE }}</title>
6
+ </head>
7
+ <body>
8
+ <ul>
9
+ {% for object in object_list %}<li>{{ object.name }}, {{ object.created|date:"r" }}</li>{% endfor %}
10
+ </ul>
11
+ </body>
12
+ </html>
@@ -0,0 +1,7 @@
1
+ from django.urls import path
2
+
3
+ from .views import TestModelListView
4
+
5
+ urlpatterns = [
6
+ path("test-models/", TestModelListView.as_view(), name="test_model_list"),
7
+ ]
@@ -0,0 +1,16 @@
1
+ from django.contrib.auth.mixins import LoginRequiredMixin
2
+ from django.views.generic.list import ListView
3
+
4
+ from dbca_utils.utils import env
5
+
6
+ from .models import TestModel
7
+
8
+
9
+ class TestModelListView(LoginRequiredMixin, ListView):
10
+ model = TestModel
11
+ template_name = "tests/test_model_list.html"
12
+
13
+ def get_context_data(self, **kwargs):
14
+ context = super().get_context_data(**kwargs)
15
+ context["TITLE"] = env("TEST_ENVIRONMENT_VAR")
16
+ return context
dbca_utils-2.1.0/PKG-INFO DELETED
@@ -1,111 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: dbca-utils
3
- Version: 2.1.0
4
- Summary: Utilities for DBCA Django apps
5
- Author-email: Rocky Chen <rocky.chen@dbca.wa.gov.au>, Ashley Felton <ashley.felton@dbca.wa.gov.au>
6
- Project-URL: Homepage, https://github.com/dbca-wa/dbca-utils
7
- Project-URL: Repository, https://github.com/dbca-wa/dbca-utils.git
8
- Project-URL: Changelog, https://github.com/dbca-wa/dbca-utils/blob/master/CHANGELOG.md
9
- Project-URL: GitHub, https://github.com/dbca-wa/dbca-utils
10
- Classifier: Framework :: Django
11
- Classifier: Framework :: Django :: 4.0
12
- Classifier: Framework :: Django :: 4.2
13
- Classifier: Framework :: Django :: 5.0
14
- Classifier: Framework :: Django :: 5.2
15
- Classifier: Environment :: Web Environment
16
- Classifier: Intended Audience :: Developers
17
- Classifier: Development Status :: 5 - Production/Stable
18
- Classifier: License :: OSI Approved :: Apache Software License
19
- Classifier: Programming Language :: Python
20
- Classifier: Programming Language :: Python :: 3
21
- Classifier: Programming Language :: Python :: 3.10
22
- Classifier: Programming Language :: Python :: 3.11
23
- Classifier: Programming Language :: Python :: 3.12
24
- Classifier: Programming Language :: Python :: 3.13
25
- Classifier: Topic :: Software Development :: Libraries
26
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
- Requires-Python: <4.0,>=3.10
28
- Description-Content-Type: text/markdown
29
- License-File: LICENSE
30
- Requires-Dist: django<6,>=4
31
- Dynamic: license-file
32
-
33
- # Overview
34
-
35
- DBCA Django utility classes and functions.
36
-
37
- ## Development
38
-
39
- The recommended way to set up this project for development is using
40
- [uv](https://docs.astral.sh/uv/)
41
- to install and manage a Python virtual environment.
42
- With uv installed, install the required Python version (see `pyproject.toml`). Example:
43
-
44
- uv python install 3.12
45
-
46
- Change into the project directory and run:
47
-
48
- uv python pin 3.12
49
- uv sync
50
-
51
- Activate the virtualenv like so:
52
-
53
- source .venv/bin/activate
54
-
55
- Run unit tests using `pytest` (or `tox`, to test against multiple Python versions):
56
-
57
- pytest -sv
58
- tox -v
59
-
60
- ## Releases
61
-
62
- Tagged releases are built and pushed to PyPI automatically using a GitHub
63
- workflow in the project. Update the project version in `pyproject.toml` and
64
- tag the required commit with the same value to trigger a release. Packages
65
- can also be built and uploaded manually, if desired.
66
-
67
- Build the project locally using uv, [publish to the PyPI registry](https://docs.astral.sh/uv/guides/publish/#publishing-your-package)
68
- using the same tool if you require:
69
-
70
- uv build
71
- uv publish
72
-
73
- ## Installation
74
-
75
- 1. Install via pip/etc.: `pip install dbca-utils`
76
-
77
- ## SSO Login Middleware
78
-
79
- This will automatically login and create users using headers from an upstream proxy (REMOTE_USER and some others).
80
- The logout view will redirect to a separate logout page which clears the SSO session.
81
-
82
- ### Usage
83
-
84
- Add `dbca_utils.middleware.SSOLoginMiddleware` to `settings.MIDDLEWARE` (after both of
85
- `django.contrib.sessions.middleware.SessionMiddleware` and
86
- `django.contrib.auth.middleware.AuthenticationMiddleware`.
87
- Ensure that `AUTHENTICATION_BACKENDS` contains `django.contrib.auth.backends.ModelBackend`,
88
- as this middleware depends on it for retrieving the logged in user for a session.
89
- Note that the middleware will still work without it, but will reauthenticate the session
90
- on every request, and `request.user.is_authenticated` won't work properly/will be false.
91
-
92
- Example:
93
-
94
- ```python
95
- MIDDLEWARE = [
96
- ...,
97
- 'django.contrib.sessions.middleware.SessionMiddleware',
98
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
99
- 'dbca_utils.middleware.SSOLoginMiddleware'
100
- ...,
101
- ]
102
- ```
103
-
104
- ## Audit model mixin
105
-
106
- `AuditMixin` is an extension of `Django.db.model.Model` that adds a number of additional fields:
107
-
108
- - `creator` - FK to `AUTH_USER_MODEL`, used to record the object creator
109
- - `modifier` - FK to `AUTH_USER_MODEL`, used to record who the object was last modified by
110
- - `created` - a timestamp that is set on initial object save
111
- - `modified` - an auto-updating timestamp (on each object save)
@@ -1,52 +0,0 @@
1
- [project]
2
- name = "dbca-utils"
3
- version = "2.1.0"
4
- description = "Utilities for DBCA Django apps"
5
- authors = [
6
- { name = "Rocky Chen", email = "rocky.chen@dbca.wa.gov.au" },
7
- { name = "Ashley Felton", email = "ashley.felton@dbca.wa.gov.au" },
8
- ]
9
- readme = "README.md"
10
- classifiers = [
11
- "Framework :: Django",
12
- "Framework :: Django :: 4.0",
13
- "Framework :: Django :: 4.2",
14
- "Framework :: Django :: 5.0",
15
- "Framework :: Django :: 5.2",
16
- "Environment :: Web Environment",
17
- "Intended Audience :: Developers",
18
- "Development Status :: 5 - Production/Stable",
19
- "License :: OSI Approved :: Apache Software License",
20
- "Programming Language :: Python",
21
- "Programming Language :: Python :: 3",
22
- "Programming Language :: Python :: 3.10",
23
- "Programming Language :: Python :: 3.11",
24
- "Programming Language :: Python :: 3.12",
25
- "Programming Language :: Python :: 3.13",
26
- "Topic :: Software Development :: Libraries",
27
- "Topic :: Software Development :: Libraries :: Python Modules",
28
- ]
29
- requires-python = ">=3.10,<4.0"
30
- dependencies = ["django>=4,<6"]
31
-
32
- [project.urls]
33
- Homepage = "https://github.com/dbca-wa/dbca-utils"
34
- Repository = "https://github.com/dbca-wa/dbca-utils.git"
35
- Changelog = "https://github.com/dbca-wa/dbca-utils/blob/master/CHANGELOG.md"
36
- GitHub = "https://github.com/dbca-wa/dbca-utils"
37
-
38
- [dependency-groups]
39
- dev = [
40
- "pytest-django>=4.11.0",
41
- "pytest-sugar>=1.0.0",
42
- "tox>=4.25.0",
43
- "tox-uv>=1.25.0",
44
- ]
45
-
46
- [tool.pytest.ini_options]
47
- # https://pytest-django.readthedocs.io/en/latest/configuring_django.html#pyproject-toml-settings
48
- DJANGO_SETTINGS_MODULE = "tests.settings"
49
- # https://pytest-django.readthedocs.io/en/latest/managing_python_path.html#using-pytest-s-pythonpath-option
50
- pythonpath = ". src"
51
- # https://pytest-django.readthedocs.io/en/latest/faq.html#my-tests-are-not-being-found-why
52
- python_files = "tests.py test_*.py"
@@ -1,4 +0,0 @@
1
- [egg_info]
2
- tag_build =
3
- tag_date = 0
4
-
@@ -1,13 +0,0 @@
1
- LICENSE
2
- README.md
3
- pyproject.toml
4
- src/dbca_utils/__init__.py
5
- src/dbca_utils/middleware.py
6
- src/dbca_utils/models.py
7
- src/dbca_utils/utils.py
8
- src/dbca_utils.egg-info/PKG-INFO
9
- src/dbca_utils.egg-info/SOURCES.txt
10
- src/dbca_utils.egg-info/dependency_links.txt
11
- src/dbca_utils.egg-info/requires.txt
12
- src/dbca_utils.egg-info/top_level.txt
13
- tests/tests.py
@@ -1 +0,0 @@
1
- django<6,>=4
@@ -1 +0,0 @@
1
- dbca_utils
File without changes
File without changes
File without changes