From cf71deacc6aac929c06931d3efc3b5e0e78c34dd Mon Sep 17 00:00:00 2001 From: "priya.basker" Date: Fri, 19 Jan 2024 10:15:58 +0000 Subject: [PATCH 001/221] Added basic styles --- templates/base/navigation.html | 13 +- templates/home copy.html | 157 ------------------------ templates/hometest.html | 173 --------------------------- templates/partial/filter.html | 6 +- templates/partial/search_result.html | 53 ++++++++ templates/search.html | 56 +-------- 6 files changed, 61 insertions(+), 397 deletions(-) delete mode 100644 templates/home copy.html delete mode 100644 templates/hometest.html create mode 100644 templates/partial/search_result.html diff --git a/templates/base/navigation.html b/templates/base/navigation.html index 3d91de5a..5b25376a 100644 --- a/templates/base/navigation.html +++ b/templates/base/navigation.html @@ -24,18 +24,13 @@ diff --git a/templates/home copy.html b/templates/home copy.html deleted file mode 100644 index 5d2967d0..00000000 --- a/templates/home copy.html +++ /dev/null @@ -1,157 +0,0 @@ -{% extends "base/base.html" %} -{% load static %} - - - -
- -
- Skip to main content - -
-
-

- - - This is a new service – your feedback will help us to improve it. - -

-
- Back -
-

Customised page template

-
-
- - - - - - diff --git a/templates/hometest.html b/templates/hometest.html deleted file mode 100644 index 7ee3b89e..00000000 --- a/templates/hometest.html +++ /dev/null @@ -1,173 +0,0 @@ -{% load static %} - - - - - - - GOV.UK - Customised page template - - - - - - - - - - - - - -
- -
- Skip to main content - -
-
-

- - - This is a new service – your feedback will help us to improve it. - -

-
- Back -
-

Customised page template

-
-
- - - - - - diff --git a/templates/partial/filter.html b/templates/partial/filter.html index 8c9d2283..37cca882 100644 --- a/templates/partial/filter.html +++ b/templates/partial/filter.html @@ -19,12 +19,12 @@

Selected filters

Type

Status

diff --git a/templates/partial/search_result.html b/templates/partial/search_result.html new file mode 100644 index 00000000..c65f0edb --- /dev/null +++ b/templates/partial/search_result.html @@ -0,0 +1,53 @@ +
+
+

+ {{result.title}} +

+ +

{{result.summary}}

+ +
+ +
+
Registered by
+
+ {{result.registered_by}} +
+
+ +
+
Database Name
+
+ {{result.database_name}} +
+
+ + +
+
First created
+
+ {{result.first_created}} +
+
+ +
+
Refresh period
+
+ {{result.refresh_period}} +
+
+ +
+
Retention period
+
+ {{result.retention_period}} +
+
+
+
Tags
+
+ {{ result.tags |join:", " }} +
+
+
+
diff --git a/templates/search.html b/templates/search.html index 9dde25e1..3f67fc9f 100644 --- a/templates/search.html +++ b/templates/search.html @@ -38,61 +38,7 @@

236 Results

{% for result in results %} -
-
-

- {{result.title}} -

- -

{{result.summary}}

- -
- -
-
Registered by
-
- {{result.registered_by}} -
-
- -
-
Database Name
-
- {{result.database_name}} -
-
- - -
-
First created
-
- {{result.first_created}} -
-
- -
-
Refresh period
-
- {{result.refresh_period}} -
-
- -
-
Retention period
-
- {{result.retention_period}} -
-
-
-
Tags
-
- {{ result.tags |join:", " }} -
-
-
-
-
- + {% include "partial/search_result.html" %} {%endfor%} From 42deb44c4ff623f4d4cfd189e562957ce583e84e Mon Sep 17 00:00:00 2001 From: "priya.basker" Date: Fri, 19 Jan 2024 14:08:20 +0000 Subject: [PATCH 002/221] Add pagination template --- home/views.py | 2 -- sample_data/sample_search_page.yaml | 2 +- templates/base/navigation.html | 2 +- templates/partial/filter.html | 28 ++++++++++++++++++------- templates/partial/pagination.html | 31 ++++++++++++++++++++++++++++ templates/partial/search_result.html | 4 +++- templates/search.html | 5 ++++- 7 files changed, 60 insertions(+), 14 deletions(-) create mode 100644 templates/partial/pagination.html diff --git a/home/views.py b/home/views.py index 8a2687c4..43bbe379 100644 --- a/home/views.py +++ b/home/views.py @@ -5,12 +5,10 @@ # Create your views here. def home_view(request): context = {} - context["service_name"] = "Daap Data Catalogue" return render(request, "home.html", context) def search_view(request): context = {} - context["service_name"] = "Daap Data Catalogue" context.update(settings.SAMPLE_SEARCH_RESULTS) return render(request, "search.html", context) diff --git a/sample_data/sample_search_page.yaml b/sample_data/sample_search_page.yaml index d447e314..69bf8382 100644 --- a/sample_data/sample_search_page.yaml +++ b/sample_data/sample_search_page.yaml @@ -1,7 +1,7 @@ # Example search results for prototyping results: - title: Data supporting HMCTS ‘Commonality’ study - summary: Dataset supporting the study on the extent of commonalities between individuals who become involved in violent extremist groups and violent criminal gangs, and the processes by ... + summary: Dataset supporting the study on the extent of commonalities between individuals who become involved in violent extremist groups and violent criminal gangs. registered_by: HMCTS Behavioural Science Team database_name: Output_CommStud first_created: 23/10/2021 diff --git a/templates/base/navigation.html b/templates/base/navigation.html index 5b25376a..2c506ea8 100644 --- a/templates/base/navigation.html +++ b/templates/base/navigation.html @@ -18,7 +18,7 @@
- {{ service_name}} + Data Catalogue
+ + {% endblock content %} From 9506b20f63be42560fe20297264d9e1b85a05be6 Mon Sep 17 00:00:00 2001 From: "priya.basker" Date: Fri, 19 Jan 2024 16:36:39 +0000 Subject: [PATCH 003/221] Added filter functionality --- home/urls.py | 1 + home/views.py | 12 ++++++++++++ sample_data/sample_search_page.yaml | 5 +++++ templates/partial/filter.html | 11 +++++++---- templates/partial/search_result.html | 7 +++++++ templates/search.html | 9 ++++----- 6 files changed, 36 insertions(+), 9 deletions(-) diff --git a/home/urls.py b/home/urls.py index 3c0cea7a..d09647d2 100644 --- a/home/urls.py +++ b/home/urls.py @@ -6,4 +6,5 @@ urlpatterns = [ path("", views.home_view, name="home"), path("search", views.search_view, name="search"), + path("search/filter", views.filter_view, name="filter"), ] diff --git a/home/views.py b/home/views.py index 43bbe379..1410d489 100644 --- a/home/views.py +++ b/home/views.py @@ -2,11 +2,23 @@ from django.shortcuts import render +def filter_json_dict(json_dict, target_value): + filtered_dict = {key: value for key, value in json_dict.items() if value == target_value} + return filtered_dict + # Create your views here. def home_view(request): context = {} return render(request, "home.html", context) +def filter_view(request): + data = {} + data.update(settings.SAMPLE_SEARCH_RESULTS) + + filtered_results =[item for item in data['results'] if item['domain_name'] == 'HMPPS'] + context={'results': filtered_results, 'total': len(filtered_results)} + + return render(request, "search.html", context) def search_view(request): context = {} diff --git a/sample_data/sample_search_page.yaml b/sample_data/sample_search_page.yaml index 69bf8382..0239d04c 100644 --- a/sample_data/sample_search_page.yaml +++ b/sample_data/sample_search_page.yaml @@ -3,6 +3,7 @@ results: - title: Data supporting HMCTS ‘Commonality’ study summary: Dataset supporting the study on the extent of commonalities between individuals who become involved in violent extremist groups and violent criminal gangs. registered_by: HMCTS Behavioural Science Team + domain_name: HMCTS database_name: Output_CommStud first_created: 23/10/2021 refresh_period: None @@ -14,6 +15,7 @@ results: - title: Gang violence in UK prisons summary: Source data for the official Q2 2023 statistics on gang violence in prisons registered_by: D&A Statistics Team + domain_name: HMPPS database_name: GangStatQ32023v1 first_created: 31/06/2023 refresh_period: None @@ -25,6 +27,7 @@ results: - title: NOMIS gang violence extracts summary: Daily extracts of NOMIS tables related to gang violence, including non-association data, violent incidents data, movement data. Data extracts are anonymised at source registered_by: NART Team + domain_name: HMPPS database_name: DailyGangExports first_created: 01/01/2001 refresh_period: Daily @@ -36,6 +39,7 @@ results: - title: Modelling output summary: Output of experimental model run on most working days aiming to predict upticks and downticks in violent activity in prisons, based on prisoner moves of known gang members registered_by: D&A Data Modelling Team + domain_name: HMPPS database_name: ViolentMoves_model first_created: 01/11/2023 (1 week ago) refresh_period: Daily @@ -47,6 +51,7 @@ results: - title: Non-association data summary: Data held in NOMIS for each prisoner, detailing any other person (prisoner, visitor, payee, violent gang member, victim...) that they are not allowed to associate with registered_by: NOMIS Team + domain_name: HMPPS database_name: non-association-list first_created: 01/01/2001 refresh_period: Daily diff --git a/templates/partial/filter.html b/templates/partial/filter.html index bb89a972..0a3a3552 100644 --- a/templates/partial/filter.html +++ b/templates/partial/filter.html @@ -7,6 +7,7 @@

Filter

+
@@ -17,17 +18,18 @@

Selected filters

Clear filters

-

Type

+

Domain

-

Status

+

DPIA Status

+
+ {% csrf_token %} @@ -97,6 +99,7 @@

Status

+ diff --git a/templates/partial/search_result.html b/templates/partial/search_result.html index ba33d34b..e3fc0eb4 100644 --- a/templates/partial/search_result.html +++ b/templates/partial/search_result.html @@ -16,6 +16,13 @@

+
+
Domain name
+
+ {{result.domain_name}} +
+
+
Database name
diff --git a/templates/search.html b/templates/search.html index 60a90813..071d4200 100644 --- a/templates/search.html +++ b/templates/search.html @@ -7,7 +7,7 @@
-
- -
-
Owner email
-
- {{result.metadata.owner_email}} -
-
- -
Domain name
{{result.metadata.domain.properties.name}}
- -
Last updated date
{{result.last_updated}}
- -
-
Refresh period
-
- -
-
- -
-
Retention period
-
- -
-
-
-
DPIA Status
-
- -
-
Tags
From 4414e8c4305648cc6f823e4ec072679cbd70af59 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 29 Jan 2024 14:14:59 +0000 Subject: [PATCH 026/221] Commit changes made by code formatters --- core/settings.py | 3 +- home/views.py | 87 +++++++++++++++-------------- sample_data/sample_search_page.yaml | 2 +- 3 files changed, 48 insertions(+), 44 deletions(-) diff --git a/core/settings.py b/core/settings.py index 438c1080..05c4f92b 100644 --- a/core/settings.py +++ b/core/settings.py @@ -123,7 +123,8 @@ "django.contrib.staticfiles.finders.AppDirectoriesFinder", ) -SAMPLE_SEARCH_RESULTS_FILENAME = BASE_DIR / "sample_data/sample_search_page.yaml" +SAMPLE_SEARCH_RESULTS_FILENAME = BASE_DIR / \ + "sample_data/sample_search_page.yaml" with open(SAMPLE_SEARCH_RESULTS_FILENAME) as f: SAMPLE_SEARCH_RESULTS = yaml.safe_load(f) diff --git a/home/views.py b/home/views.py index 4addd12d..daaafe36 100644 --- a/home/views.py +++ b/home/views.py @@ -3,32 +3,35 @@ from .services import get_catalogue_client from data_platform_catalogue.search_types import MultiSelectFilter + def filter_seleted_domains(domain_list, domains): - selected_domain={} + selected_domain = {} for domain in domain_list: if domain.value in domains: - selected_domain[domain.value]=domain.label + selected_domain[domain.value] = domain.label return selected_domain - + # Create your views here. def home_view(request): context = {} return render(request, "home.html", context) + def details_view(request): - id=request.GET.get('id') + id = request.GET.get('id') context = {} client = get_catalogue_client() - filter_value = [MultiSelectFilter("urn",id )] + filter_value = [MultiSelectFilter("urn", id)] search_results = client.search(query="", page=None, filters=filter_value) context["result"] = search_results.page_results[0] - + return render(request, "details.html", context) + def search_view(request): - + query = request.GET.get("query", "") page = request.GET.get("page", None) @@ -37,57 +40,57 @@ def search_view(request): # Fetch domainlist without query search_results = client.search(query="", page=None) context = {} - domain_list=search_results.facets['domains'] - context["domainlist"]=domain_list - + domain_list = search_results.facets['domains'] + context["domainlist"] = domain_list + if request.GET.getlist("domain"): - domains=request.GET.getlist("domain") - selected_domain=filter_seleted_domains(domain_list, domains) + domains = request.GET.getlist("domain") + selected_domain = filter_seleted_domains(domain_list, domains) context['selected_domain'] = selected_domain request.session['selected_domain'] = selected_domain request.session['domains'] = domains - filter_value = [MultiSelectFilter("domains",domains )] - - elif request.GET.get('clear_filter') == "True": - filter_value =[] - context['selected_domain'] ={} - elif request.GET.get('clear_label')=='True': - #Value to clear - label_value=request.GET.getlist("value") - - #Remove the selected value from list - domains= request.session.get('domains', None) - domains=list(set(domains) - set(label_value)) - - #Populated selected domain - selected_domain=filter_seleted_domains(domain_list, domains) + filter_value = [MultiSelectFilter("domains", domains)] + + elif request.GET.get('clear_filter') == "True": + filter_value = [] + context['selected_domain'] = {} + elif request.GET.get('clear_label') == 'True': + # Value to clear + label_value = request.GET.getlist("value") + + # Remove the selected value from list + domains = request.session.get('domains', None) + domains = list(set(domains) - set(label_value)) + + # Populated selected domain + selected_domain = filter_seleted_domains(domain_list, domains) context['domains'] = domains context['selected_domain'] = selected_domain - - #Reassign to session + + # Reassign to session request.session['selected_domain'] = selected_domain request.session['domains'] = domains if not domains: filter_value = [] else: - filter_value = [MultiSelectFilter("domains",domains )] + filter_value = [MultiSelectFilter("domains", domains)] - elif request.GET.get('query'): - domains= request.session.get('domains', None) - #Preserve filter - selected_domain=filter_seleted_domains(domain_list, domains) + elif request.GET.get('query'): + domains = request.session.get('domains', None) + # Preserve filter + selected_domain = filter_seleted_domains(domain_list, domains) context['selected_domain'] = selected_domain context['domains'] = domains - filter_value = [MultiSelectFilter("domains",domains )] - else: - filter_value =[] - context['selected_domain'] ={} - + filter_value = [MultiSelectFilter("domains", domains)] + else: + filter_value = [] + context['selected_domain'] = {} + # Search with filter - search_results = client.search(query=query, page=page, filters=filter_value) + search_results = client.search( + query=query, page=page, filters=filter_value) context["query"] = query context["results"] = search_results.page_results context["total_results"] = search_results.total_results - + return render(request, "search.html", context) - \ No newline at end of file diff --git a/sample_data/sample_search_page.yaml b/sample_data/sample_search_page.yaml index 1f209dcc..d447e314 100644 --- a/sample_data/sample_search_page.yaml +++ b/sample_data/sample_search_page.yaml @@ -55,4 +55,4 @@ results: - NOMIS - Non-association -total_results: 93 \ No newline at end of file +total_results: 93 From de4de802ae2e2999bd892007cf3dbff0ee4c4767 Mon Sep 17 00:00:00 2001 From: "priya.basker" Date: Mon, 29 Jan 2024 14:31:23 +0000 Subject: [PATCH 027/221] Updated query functionality --- home/views.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/home/views.py b/home/views.py index daaafe36..4d2dce11 100644 --- a/home/views.py +++ b/home/views.py @@ -79,9 +79,12 @@ def search_view(request): domains = request.session.get('domains', None) # Preserve filter selected_domain = filter_seleted_domains(domain_list, domains) - context['selected_domain'] = selected_domain - context['domains'] = domains - filter_value = [MultiSelectFilter("domains", domains)] + if not domains: + filter_value = [] + else: + context['selected_domain'] = selected_domain + context['domains'] = domains + filter_value = [MultiSelectFilter("domains", domains)] else: filter_value = [] context['selected_domain'] = {} From 52dcc5aac0344c925d16e23d9d988676deb69699 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 29 Jan 2024 14:32:00 +0000 Subject: [PATCH 028/221] Commit changes made by code formatters --- home/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/home/views.py b/home/views.py index 4d2dce11..2beb2cda 100644 --- a/home/views.py +++ b/home/views.py @@ -81,7 +81,7 @@ def search_view(request): selected_domain = filter_seleted_domains(domain_list, domains) if not domains: filter_value = [] - else: + else: context['selected_domain'] = selected_domain context['domains'] = domains filter_value = [MultiSelectFilter("domains", domains)] From db3574a85fc163df4e8f469dd1bdc9b43e653669 Mon Sep 17 00:00:00 2001 From: PriyaBasker23 <90777804+PriyaBasker23@users.noreply.github.com> Date: Mon, 29 Jan 2024 16:54:09 +0000 Subject: [PATCH 029/221] Update home/views.py Co-authored-by: Mitch Dawson <86007219+mitchdawson1982@users.noreply.github.com> --- home/views.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/home/views.py b/home/views.py index 2beb2cda..63799851 100644 --- a/home/views.py +++ b/home/views.py @@ -43,7 +43,13 @@ def search_view(request): domain_list = search_results.facets['domains'] context["domainlist"] = domain_list - if request.GET.getlist("domain"): + domains = request.GET.getlist("domain", []) + if domains: + selected_domain = filter_seleted_domains(domain_list, domains) + context['selected_domain'] = selected_domain + request.session['selected_domain'] = selected_domain + request.session['domains'] = domains + filter_value = [MultiSelectFilter("domains", domains)] domains = request.GET.getlist("domain") selected_domain = filter_seleted_domains(domain_list, domains) context['selected_domain'] = selected_domain From c647f0fd6c173a794de8cf219cbab4ea6d4a1056 Mon Sep 17 00:00:00 2001 From: "priya.basker" Date: Mon, 29 Jan 2024 17:20:31 +0000 Subject: [PATCH 030/221] Updated requested information --- README.md | 2 +- home/helper.py | 15 ++++++--------- home/urls.py | 2 +- home/views.py | 14 +++----------- pyproject.toml | 1 - static/assets/js/htmx.min.js | 1 - templates/base/head.html | 1 - templates/partial/search_result.html | 2 +- 8 files changed, 12 insertions(+), 26 deletions(-) delete mode 100644 static/assets/js/htmx.min.js diff --git a/README.md b/README.md index ae9e59e0..35744aff 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ You will need npm (for javascript dependencies) and poetry (for python dependenc 2. Copy `.env.example` to `.env`. 3. You wil need to obtain an access token from Datahub catalogue and populate the `CATALOGUE_TOKEN` var in .env to be able to retrieve search data. https://datahub.apps-tools.development.data-platform.service.justice.gov.uk/settings/tokens -4. Run `poetry run python manage.py runserver` +5. Run `poetry run python manage.py runserver` Run `npm install` and then `npm run sass` to compile the stylesheets. diff --git a/home/helper.py b/home/helper.py index a68b0dc2..7952f7d9 100644 --- a/home/helper.py +++ b/home/helper.py @@ -1,9 +1,6 @@ -def filter_json_dict(json_dict, target_value): - filtered_dict = { - key: value for key, value in json_dict.items() if value == target_value - } - return filtered_dict - - -def sort_output(json_dict, sortvalue): - return None +def filter_seleted_domains(domain_list, domains): + selected_domain = {} + for domain in domain_list: + if domain.value in domains: + selected_domain[domain.value] = domain.label + return selected_domain \ No newline at end of file diff --git a/home/urls.py b/home/urls.py index 6da74019..4338d7bf 100644 --- a/home/urls.py +++ b/home/urls.py @@ -7,5 +7,5 @@ urlpatterns = [ path("", views.home_view, name="home"), path("search", views.search_view, name="search"), - path("details", views.details_view, name="details"), + path("details//", views.details_view, name="details"), ] diff --git a/home/views.py b/home/views.py index 63799851..11acf7ee 100644 --- a/home/views.py +++ b/home/views.py @@ -1,27 +1,19 @@ from django.conf import settings from django.shortcuts import render from .services import get_catalogue_client +from .helper import filter_seleted_domains from data_platform_catalogue.search_types import MultiSelectFilter -def filter_seleted_domains(domain_list, domains): - selected_domain = {} - for domain in domain_list: - if domain.value in domains: - selected_domain[domain.value] = domain.label - return selected_domain - - # Create your views here. def home_view(request): context = {} return render(request, "home.html", context) -def details_view(request): - id = request.GET.get('id') +def details_view(request, id): + context = {} - client = get_catalogue_client() filter_value = [MultiSelectFilter("urn", id)] search_results = client.search(query="", page=None, filters=filter_value) diff --git a/pyproject.toml b/pyproject.toml index 90e154d1..d2f6c06c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,6 @@ readme = "README.md" python = "^3.11" django = "^5.0.1" pyyaml = "^6.0.1" -htmx = "^0.0.0" gunicorn = "^21.2.0" whitenoise = "^6.6.0" ministryofjustice-data-platform-catalogue = "^0.7.0" diff --git a/static/assets/js/htmx.min.js b/static/assets/js/htmx.min.js deleted file mode 100644 index 47eb70fe..00000000 --- a/static/assets/js/htmx.min.js +++ /dev/null @@ -1 +0,0 @@ -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{e.htmx=e.htmx||t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var Q={onLoad:F,process:zt,on:de,off:ge,trigger:ce,ajax:Nr,find:C,findAll:f,closest:v,values:function(e,t){var r=dr(e,t||"post");return r.values},remove:_,addClass:z,removeClass:n,toggleClass:$,takeClass:W,defineExtension:Ur,removeExtension:Br,logAll:V,logNone:j,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get"],selfRequestsOnly:false,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null},parseInterval:d,_:t,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){var t=new WebSocket(e,[]);t.binaryType=Q.config.wsBinaryType;return t},version:"1.9.10"};var r={addTriggerHandler:Lt,bodyContains:se,canAccessLocalStorage:U,findThisElement:xe,filterValues:yr,hasAttribute:o,getAttributeValue:te,getClosestAttributeValue:ne,getClosestMatch:c,getExpressionVars:Hr,getHeaders:xr,getInputValues:dr,getInternalData:ae,getSwapSpecification:wr,getTriggerSpecs:it,getTarget:ye,makeFragment:l,mergeObjects:le,makeSettleInfo:T,oobSwap:Ee,querySelectorExt:ue,selectAndSwap:je,settleImmediately:nr,shouldCancel:ut,triggerEvent:ce,triggerErrorEvent:fe,withExtensions:R};var w=["get","post","put","delete","patch"];var i=w.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");var S=e("head"),q=e("title"),H=e("svg",true);function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e.getAttribute&&e.getAttribute(t)}function o(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){return e.parentElement}function re(){return document}function c(e,t){while(e&&!t(e)){e=u(e)}return e?e:null}function L(e,t,r){var n=te(t,r);var i=te(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function ne(t,r){var n=null;c(t,function(e){return n=L(t,e,r)});if(n!=="unset"){return n}}function h(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function A(e){var t=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i;var r=t.exec(e);if(r){return r[1].toLowerCase()}else{return""}}function a(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=re().createDocumentFragment()}return i}function N(e){return/",0);return i.querySelector("template").content}switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return a(""+n+"
",1);case"col":return a(""+n+"
",2);case"tr":return a(""+n+"
",2);case"td":case"th":return a(""+n+"
",3);case"script":case"style":return a("
"+n+"
",1);default:return a(n,0)}}function ie(e){if(e){e()}}function I(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function k(e){return I(e,"Function")}function P(e){return I(e,"Object")}function ae(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function M(e){var t=[];if(e){for(var r=0;r=0}function se(e){if(e.getRootNode&&e.getRootNode()instanceof window.ShadowRoot){return re().body.contains(e.getRootNode().host)}else{return re().body.contains(e)}}function D(e){return e.trim().split(/\s+/)}function le(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function E(e){try{return JSON.parse(e)}catch(e){b(e);return null}}function U(){var e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function B(t){try{var e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function t(e){return Tr(re().body,function(){return eval(e)})}function F(t){var e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function V(){Q.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function j(){Q.logger=null}function C(e,t){if(t){return e.querySelector(t)}else{return C(re(),e)}}function f(e,t){if(t){return e.querySelectorAll(t)}else{return f(re(),e)}}function _(e,t){e=g(e);if(t){setTimeout(function(){_(e);e=null},t)}else{e.parentElement.removeChild(e)}}function z(e,t,r){e=g(e);if(r){setTimeout(function(){z(e,t);e=null},r)}else{e.classList&&e.classList.add(t)}}function n(e,t,r){e=g(e);if(r){setTimeout(function(){n(e,t);e=null},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function $(e,t){e=g(e);e.classList.toggle(t)}function W(e,t){e=g(e);oe(e.parentElement.children,function(e){n(e,t)});z(e,t)}function v(e,t){e=g(e);if(e.closest){return e.closest(t)}else{do{if(e==null||h(e,t)){return e}}while(e=e&&u(e));return null}}function s(e,t){return e.substring(0,t.length)===t}function G(e,t){return e.substring(e.length-t.length)===t}function J(e){var t=e.trim();if(s(t,"<")&&G(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function Z(e,t){if(t.indexOf("closest ")===0){return[v(e,J(t.substr(8)))]}else if(t.indexOf("find ")===0){return[C(e,J(t.substr(5)))]}else if(t==="next"){return[e.nextElementSibling]}else if(t.indexOf("next ")===0){return[K(e,J(t.substr(5)))]}else if(t==="previous"){return[e.previousElementSibling]}else if(t.indexOf("previous ")===0){return[Y(e,J(t.substr(9)))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else{return re().querySelectorAll(J(t))}}var K=function(e,t){var r=re().querySelectorAll(t);for(var n=0;n=0;n--){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING){return i}}};function ue(e,t){if(t){return Z(e,t)[0]}else{return Z(re().body,e)[0]}}function g(e){if(I(e,"String")){return C(e)}else{return e}}function ve(e,t,r){if(k(t)){return{target:re().body,event:e,listener:t}}else{return{target:g(e),event:t,listener:r}}}function de(t,r,n){jr(function(){var e=ve(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=k(r);return e?r:n}function ge(t,r,n){jr(function(){var e=ve(t,r,n);e.target.removeEventListener(e.event,e.listener)});return k(r)?r:n}var me=re().createElement("output");function pe(e,t){var r=ne(e,t);if(r){if(r==="this"){return[xe(e,t)]}else{var n=Z(e,r);if(n.length===0){b('The selector "'+r+'" on '+t+" returned no matches!");return[me]}else{return n}}}}function xe(e,t){return c(e,function(e){return te(e,t)!=null})}function ye(e){var t=ne(e,"hx-target");if(t){if(t==="this"){return xe(e,"hx-target")}else{return ue(e,t)}}else{var r=ae(e);if(r.boosted){return re().body}else{return e}}}function be(e){var t=Q.config.attributesToSettle;for(var r=0;r0){o=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{o=e}var r=re().querySelectorAll(t);if(r){oe(r,function(e){var t;var r=i.cloneNode(true);t=re().createDocumentFragment();t.appendChild(r);if(!Se(o,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!ce(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){Fe(o,e,e,t,a)}oe(a.elts,function(e){ce(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);fe(re().body,"htmx:oobErrorNoTarget",{content:i})}return e}function Ce(e,t,r){var n=ne(e,"hx-select-oob");if(n){var i=n.split(",");for(var a=0;a0){var r=t.replace("'","\\'");var n=e.tagName.replace(":","\\:");var i=o.querySelector(n+"[id='"+r+"']");if(i&&i!==o){var a=e.cloneNode();we(e,i);s.tasks.push(function(){we(e,a)})}}})}function Oe(e){return function(){n(e,Q.config.addedClass);zt(e);Nt(e);qe(e);ce(e,"htmx:load")}}function qe(e){var t="[autofocus]";var r=h(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function m(e,t,r,n){Te(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;z(i,Q.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Oe(i))}}}function He(e,t){var r=0;while(r-1){var t=e.replace(H,"");var r=t.match(q);if(r){return r[2]}}}function je(e,t,r,n,i,a){i.title=Ve(n);var o=l(n);if(o){Ce(r,o,i);o=Be(r,o,a);Re(o);return Fe(e,r,t,o,i)}}function _e(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=E(n);for(var a in i){if(i.hasOwnProperty(a)){var o=i[a];if(!P(o)){o={value:o}}ce(r,a,o)}}}else{var s=n.split(",");for(var l=0;l0){var o=t[0];if(o==="]"){n--;if(n===0){if(a===null){i=i+"true"}t.shift();i+=")})";try{var s=Tr(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){fe(re().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(o==="["){n++}if(Qe(o,a,r)){i+="(("+r+"."+o+") ? ("+r+"."+o+") : (window."+o+"))"}else{i=i+o}a=t.shift()}}}function y(e,t){var r="";while(e.length>0&&!t.test(e[0])){r+=e.shift()}return r}function tt(e){var t;if(e.length>0&&Ze.test(e[0])){e.shift();t=y(e,Ke).trim();e.shift()}else{t=y(e,x)}return t}var rt="input, textarea, select";function nt(e,t,r){var n=[];var i=Ye(t);do{y(i,Je);var a=i.length;var o=y(i,/[,\[\s]/);if(o!==""){if(o==="every"){var s={trigger:"every"};y(i,Je);s.pollInterval=d(y(i,/[,\[\s]/));y(i,Je);var l=et(e,i,"event");if(l){s.eventFilter=l}n.push(s)}else if(o.indexOf("sse:")===0){n.push({trigger:"sse",sseEvent:o.substr(4)})}else{var u={trigger:o};var l=et(e,i,"event");if(l){u.eventFilter=l}while(i.length>0&&i[0]!==","){y(i,Je);var f=i.shift();if(f==="changed"){u.changed=true}else if(f==="once"){u.once=true}else if(f==="consume"){u.consume=true}else if(f==="delay"&&i[0]===":"){i.shift();u.delay=d(y(i,x))}else if(f==="from"&&i[0]===":"){i.shift();if(Ze.test(i[0])){var c=tt(i)}else{var c=y(i,x);if(c==="closest"||c==="find"||c==="next"||c==="previous"){i.shift();var h=tt(i);if(h.length>0){c+=" "+h}}}u.from=c}else if(f==="target"&&i[0]===":"){i.shift();u.target=tt(i)}else if(f==="throttle"&&i[0]===":"){i.shift();u.throttle=d(y(i,x))}else if(f==="queue"&&i[0]===":"){i.shift();u.queue=y(i,x)}else if(f==="root"&&i[0]===":"){i.shift();u[f]=tt(i)}else if(f==="threshold"&&i[0]===":"){i.shift();u[f]=y(i,x)}else{fe(e,"htmx:syntax:error",{token:i.shift()})}}n.push(u)}}if(i.length===a){fe(e,"htmx:syntax:error",{token:i.shift()})}y(i,Je)}while(i[0]===","&&i.shift());if(r){r[t]=n}return n}function it(e){var t=te(e,"hx-trigger");var r=[];if(t){var n=Q.config.triggerSpecsCache;r=n&&n[t]||nt(e,t,n)}if(r.length>0){return r}else if(h(e,"form")){return[{trigger:"submit"}]}else if(h(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(h(e,rt)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function at(e){ae(e).cancelled=true}function ot(e,t,r){var n=ae(e);n.timeout=setTimeout(function(){if(se(e)&&n.cancelled!==true){if(!ct(r,e,Wt("hx:poll:trigger",{triggerSpec:r,target:e}))){t(e)}ot(e,t,r)}},r.pollInterval)}function st(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function lt(t,r,e){if(t.tagName==="A"&&st(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=ee(t,"href")}else{var a=ee(t,"method");n=a?a.toLowerCase():"get";if(n==="get"){}i=ee(t,"action")}e.forEach(function(e){ht(t,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(n,i,e,t)},r,e,true)})}}function ut(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(h(t,'input[type="submit"], button')&&v(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function ft(e,t){return ae(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function ct(e,t,r){var n=e.eventFilter;if(n){try{return n.call(t,r)!==true}catch(e){fe(re().body,"htmx:eventFilter:error",{error:e,source:n.source});return true}}return false}function ht(a,o,e,s,l){var u=ae(a);var t;if(s.from){t=Z(a,s.from)}else{t=[a]}if(s.changed){t.forEach(function(e){var t=ae(e);t.lastValue=e.value})}oe(t,function(n){var i=function(e){if(!se(a)){n.removeEventListener(s.trigger,i);return}if(ft(a,e)){return}if(l||ut(e,a)){e.preventDefault()}if(ct(s,a,e)){return}var t=ae(e);t.triggerSpec=s;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(a)<0){t.handledFor.push(a);if(s.consume){e.stopPropagation()}if(s.target&&e.target){if(!h(e.target,s.target)){return}}if(s.once){if(u.triggeredOnce){return}else{u.triggeredOnce=true}}if(s.changed){var r=ae(n);if(r.lastValue===n.value){return}r.lastValue=n.value}if(u.delayed){clearTimeout(u.delayed)}if(u.throttle){return}if(s.throttle>0){if(!u.throttle){o(a,e);u.throttle=setTimeout(function(){u.throttle=null},s.throttle)}}else if(s.delay>0){u.delayed=setTimeout(function(){o(a,e)},s.delay)}else{ce(a,"htmx:trigger");o(a,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:s.trigger,listener:i,on:n});n.addEventListener(s.trigger,i)})}var vt=false;var dt=null;function gt(){if(!dt){dt=function(){vt=true};window.addEventListener("scroll",dt);setInterval(function(){if(vt){vt=false;oe(re().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){mt(e)})}},200)}}function mt(t){if(!o(t,"data-hx-revealed")&&X(t)){t.setAttribute("data-hx-revealed","true");var e=ae(t);if(e.initHash){ce(t,"revealed")}else{t.addEventListener("htmx:afterProcessNode",function(e){ce(t,"revealed")},{once:true})}}}function pt(e,t,r){var n=D(r);for(var i=0;i=0){var t=wt(n);setTimeout(function(){xt(s,r,n+1)},t)}};t.onopen=function(e){n=0};ae(s).webSocket=t;t.addEventListener("message",function(e){if(yt(s)){return}var t=e.data;R(s,function(e){t=e.transformResponse(t,null,s)});var r=T(s);var n=l(t);var i=M(n.children);for(var a=0;a0){ce(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(ut(e,u)){e.preventDefault()}})}else{fe(u,"htmx:noWebSocketSourceError")}}function wt(e){var t=Q.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}b('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function St(e,t,r){var n=D(r);for(var i=0;i0){setTimeout(i,n)}else{i()}}function Ht(t,i,e){var a=false;oe(w,function(r){if(o(t,"hx-"+r)){var n=te(t,"hx-"+r);a=true;i.path=n;i.verb=r;e.forEach(function(e){Lt(t,e,i,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(r,n,e,t)})})}});return a}function Lt(n,e,t,r){if(e.sseEvent){Rt(n,r,e.sseEvent)}else if(e.trigger==="revealed"){gt();ht(n,r,t,e);mt(n)}else if(e.trigger==="intersect"){var i={};if(e.root){i.root=ue(n,e.root)}if(e.threshold){i.threshold=parseFloat(e.threshold)}var a=new IntersectionObserver(function(e){for(var t=0;t0){t.polling=true;ot(n,r,e)}else{ht(n,r,t,e)}}function At(e){if(Q.config.allowScriptTags&&(e.type==="text/javascript"||e.type==="module"||e.type==="")){var t=re().createElement("script");oe(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){b(e)}finally{if(e.parentElement){e.parentElement.removeChild(e)}}}}function Nt(e){if(h(e,"script")){At(e)}oe(f(e,"script"),function(e){At(e)})}function It(e){var t=e.attributes;for(var r=0;r0){var o=n.shift();var s=o.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/);if(a===0&&s){o.split(":");i=s[1].slice(0,-1);r[i]=s[2]}else{r[i]+=o}a+=Bt(o)}for(var l in r){Ft(e,l,r[l])}}}function jt(e){Ae(e);for(var t=0;tQ.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){fe(re().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Yt(e){if(!U()){return null}e=B(e);var t=E(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r=200&&this.status<400){ce(re().body,"htmx:historyCacheMissLoad",o);var e=l(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=Zt();var r=T(t);var n=Ve(this.response);if(n){var i=C("title");if(i){i.innerHTML=n}else{window.document.title=n}}Ue(t,e,r);nr(r.tasks);Jt=a;ce(re().body,"htmx:historyRestore",{path:a,cacheMiss:true,serverResponse:this.response})}else{fe(re().body,"htmx:historyCacheMissLoadError",o)}};e.send()}function ar(e){er();e=e||location.pathname+location.search;var t=Yt(e);if(t){var r=l(t.content);var n=Zt();var i=T(n);Ue(n,r,i);nr(i.tasks);document.title=t.title;setTimeout(function(){window.scrollTo(0,t.scroll)},0);Jt=e;ce(re().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{ir(e)}}}function or(e){var t=pe(e,"hx-indicator");if(t==null){t=[e]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.classList["add"].call(e.classList,Q.config.requestClass)});return t}function sr(e){var t=pe(e,"hx-disabled-elt");if(t==null){t=[]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function lr(e,t){oe(e,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList["remove"].call(e.classList,Q.config.requestClass)}});oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function ur(e,t){for(var r=0;r=0}function wr(e,t){var r=t?t:ne(e,"hx-swap");var n={swapStyle:ae(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ae(e).boosted&&!br(e)){n["show"]="top"}if(r){var i=D(r);if(i.length>0){for(var a=0;a0?l.join(":"):null;n["scroll"]=u;n["scrollTarget"]=f}else if(o.indexOf("show:")===0){var c=o.substr(5);var l=c.split(":");var h=l.pop();var f=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=f}else if(o.indexOf("focus-scroll:")===0){var v=o.substr("focus-scroll:".length);n["focusScroll"]=v=="true"}else if(a==0){n["swapStyle"]=o}else{b("Unknown modifier in hx-swap: "+o)}}}}return n}function Sr(e){return ne(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function Er(t,r,n){var i=null;R(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(Sr(r)){return pr(n)}else{return mr(n)}}}function T(e){return{tasks:[],elts:[e]}}function Cr(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ue(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var a=t.showTarget;if(t.showTarget==="window"){a="body"}i=ue(r,a)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function Rr(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=te(e,t);if(i){var a=i.trim();var o=r;if(a==="unset"){return null}if(a.indexOf("javascript:")===0){a=a.substr(11);o=true}else if(a.indexOf("js:")===0){a=a.substr(3);o=true}if(a.indexOf("{")!==0){a="{"+a+"}"}var s;if(o){s=Tr(e,function(){return Function("return ("+a+")")()},{})}else{s=E(a)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Rr(u(e),t,r,n)}function Tr(e,t,r){if(Q.config.allowEval){return t()}else{fe(e,"htmx:evalDisallowedError");return r}}function Or(e,t){return Rr(e,"hx-vars",true,t)}function qr(e,t){return Rr(e,"hx-vals",false,t)}function Hr(e){return le(Or(e),qr(e))}function Lr(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Ar(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){fe(re().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function O(e,t){return t.test(e.getAllResponseHeaders())}function Nr(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||I(r,"String")){return he(e,t,null,null,{targetOverride:g(r),returnPromise:true})}else{return he(e,t,g(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:g(r.target),swapOverride:r.swap,select:r.select,returnPromise:true})}}else{return he(e,t,null,null,{returnPromise:true})}}function Ir(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function kr(e,t,r){var n;var i;if(typeof URL==="function"){i=new URL(t,document.location.href);var a=document.location.origin;n=a===i.origin}else{i=t;n=s(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!n){return false}}return ce(e,"htmx:validateUrl",le({url:i,sameHost:n},r))}function he(t,r,n,i,a,e){var o=null;var s=null;a=a!=null?a:{};if(a.returnPromise&&typeof Promise!=="undefined"){var l=new Promise(function(e,t){o=e;s=t})}if(n==null){n=re().body}var M=a.handler||Mr;var X=a.select||null;if(!se(n)){ie(o);return l}var u=a.targetOverride||ye(n);if(u==null||u==me){fe(n,"htmx:targetError",{target:te(n,"hx-target")});ie(s);return l}var f=ae(n);var c=f.lastButtonClicked;if(c){var h=ee(c,"formaction");if(h!=null){r=h}var v=ee(c,"formmethod");if(v!=null){if(v.toLowerCase()!=="dialog"){t=v}}}var d=ne(n,"hx-confirm");if(e===undefined){var D=function(e){return he(t,r,n,i,a,!!e)};var U={target:u,elt:n,path:r,verb:t,triggeringEvent:i,etc:a,issueRequest:D,question:d};if(ce(n,"htmx:confirm",U)===false){ie(o);return l}}var g=n;var m=ne(n,"hx-sync");var p=null;var x=false;if(m){var B=m.split(":");var F=B[0].trim();if(F==="this"){g=xe(n,"hx-sync")}else{g=ue(n,F)}m=(B[1]||"drop").trim();f=ae(g);if(m==="drop"&&f.xhr&&f.abortable!==true){ie(o);return l}else if(m==="abort"){if(f.xhr){ie(o);return l}else{x=true}}else if(m==="replace"){ce(g,"htmx:abort")}else if(m.indexOf("queue")===0){var V=m.split(" ");p=(V[1]||"last").trim()}}if(f.xhr){if(f.abortable){ce(g,"htmx:abort")}else{if(p==null){if(i){var y=ae(i);if(y&&y.triggerSpec&&y.triggerSpec.queue){p=y.triggerSpec.queue}}if(p==null){p="last"}}if(f.queuedRequests==null){f.queuedRequests=[]}if(p==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="all"){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){he(t,r,n,i,a)})}ie(o);return l}}var b=new XMLHttpRequest;f.xhr=b;f.abortable=x;var w=function(){f.xhr=null;f.abortable=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var j=ne(n,"hx-prompt");if(j){var S=prompt(j);if(S===null||!ce(n,"htmx:prompt",{prompt:S,target:u})){ie(o);w();return l}}if(d&&!e){if(!confirm(d)){ie(o);w();return l}}var E=xr(n,u,S);if(t!=="get"&&!Sr(n)){E["Content-Type"]="application/x-www-form-urlencoded"}if(a.headers){E=le(E,a.headers)}var _=dr(n,t);var C=_.errors;var R=_.values;if(a.values){R=le(R,a.values)}var z=Hr(n);var $=le(R,z);var T=yr($,n);if(Q.config.getCacheBusterParam&&t==="get"){T["org.htmx.cache-buster"]=ee(u,"id")||"true"}if(r==null||r===""){r=re().location.href}var O=Rr(n,"hx-request");var W=ae(n).boosted;var q=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;var H={boosted:W,useUrlParams:q,parameters:T,unfilteredParameters:$,headers:E,target:u,verb:t,errors:C,withCredentials:a.credentials||O.credentials||Q.config.withCredentials,timeout:a.timeout||O.timeout||Q.config.timeout,path:r,triggeringEvent:i};if(!ce(n,"htmx:configRequest",H)){ie(o);w();return l}r=H.path;t=H.verb;E=H.headers;T=H.parameters;C=H.errors;q=H.useUrlParams;if(C&&C.length>0){ce(n,"htmx:validation:halted",H);ie(o);w();return l}var G=r.split("#");var J=G[0];var L=G[1];var A=r;if(q){A=J;var Z=Object.keys(T).length!==0;if(Z){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=mr(T);if(L){A+="#"+L}}}if(!kr(n,A,H)){fe(n,"htmx:invalidPath",H);ie(s);return l}b.open(t.toUpperCase(),A,true);b.overrideMimeType("text/html");b.withCredentials=H.withCredentials;b.timeout=H.timeout;if(O.noHeaders){}else{for(var N in E){if(E.hasOwnProperty(N)){var K=E[N];Lr(b,N,K)}}}var I={xhr:b,target:u,requestConfig:H,etc:a,boosted:W,select:X,pathInfo:{requestPath:r,finalRequestPath:A,anchor:L}};b.onload=function(){try{var e=Ir(n);I.pathInfo.responsePath=Ar(b);M(n,I);lr(k,P);ce(n,"htmx:afterRequest",I);ce(n,"htmx:afterOnLoad",I);if(!se(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(se(r)){t=r}}if(t){ce(t,"htmx:afterRequest",I);ce(t,"htmx:afterOnLoad",I)}}ie(o);w()}catch(e){fe(n,"htmx:onLoadError",le({error:e},I));throw e}};b.onerror=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendError",I);ie(s);w()};b.onabort=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendAbort",I);ie(s);w()};b.ontimeout=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:timeout",I);ie(s);w()};if(!ce(n,"htmx:beforeRequest",I)){ie(o);w();return l}var k=or(n);var P=sr(n);oe(["loadstart","loadend","progress","abort"],function(t){oe([b,b.upload],function(e){e.addEventListener(t,function(e){ce(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});ce(n,"htmx:beforeSend",I);var Y=q?null:Er(b,n,T);b.send(Y);return l}function Pr(e,t){var r=t.xhr;var n=null;var i=null;if(O(r,/HX-Push:/i)){n=r.getResponseHeader("HX-Push");i="push"}else if(O(r,/HX-Push-Url:/i)){n=r.getResponseHeader("HX-Push-Url");i="push"}else if(O(r,/HX-Replace-Url:/i)){n=r.getResponseHeader("HX-Replace-Url");i="replace"}if(n){if(n==="false"){return{}}else{return{type:i,path:n}}}var a=t.pathInfo.finalRequestPath;var o=t.pathInfo.responsePath;var s=ne(e,"hx-push-url");var l=ne(e,"hx-replace-url");var u=ae(e).boosted;var f=null;var c=null;if(s){f="push";c=s}else if(l){f="replace";c=l}else if(u){f="push";c=o||a}if(c){if(c==="false"){return{}}if(c==="true"){c=o||a}if(t.pathInfo.anchor&&c.indexOf("#")===-1){c=c+"#"+t.pathInfo.anchor}return{type:f,path:c}}else{return{}}}function Mr(l,u){var f=u.xhr;var c=u.target;var e=u.etc;var t=u.requestConfig;var h=u.select;if(!ce(l,"htmx:beforeOnLoad",u))return;if(O(f,/HX-Trigger:/i)){_e(f,"HX-Trigger",l)}if(O(f,/HX-Location:/i)){er();var r=f.getResponseHeader("HX-Location");var v;if(r.indexOf("{")===0){v=E(r);r=v["path"];delete v["path"]}Nr("GET",r,v).then(function(){tr(r)});return}var n=O(f,/HX-Refresh:/i)&&"true"===f.getResponseHeader("HX-Refresh");if(O(f,/HX-Redirect:/i)){location.href=f.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(O(f,/HX-Retarget:/i)){if(f.getResponseHeader("HX-Retarget")==="this"){u.target=l}else{u.target=ue(l,f.getResponseHeader("HX-Retarget"))}}var d=Pr(l,u);var i=f.status>=200&&f.status<400&&f.status!==204;var g=f.response;var a=f.status>=400;var m=Q.config.ignoreTitle;var o=le({shouldSwap:i,serverResponse:g,isError:a,ignoreTitle:m},u);if(!ce(c,"htmx:beforeSwap",o))return;c=o.target;g=o.serverResponse;a=o.isError;m=o.ignoreTitle;u.target=c;u.failed=a;u.successful=!a;if(o.shouldSwap){if(f.status===286){at(l)}R(l,function(e){g=e.transformResponse(g,f,l)});if(d.type){er()}var s=e.swapOverride;if(O(f,/HX-Reswap:/i)){s=f.getResponseHeader("HX-Reswap")}var v=wr(l,s);if(v.hasOwnProperty("ignoreTitle")){m=v.ignoreTitle}c.classList.add(Q.config.swappingClass);var p=null;var x=null;var y=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r;if(h){r=h}if(O(f,/HX-Reselect:/i)){r=f.getResponseHeader("HX-Reselect")}if(d.type){ce(re().body,"htmx:beforeHistoryUpdate",le({history:d},u));if(d.type==="push"){tr(d.path);ce(re().body,"htmx:pushedIntoHistory",{path:d.path})}else{rr(d.path);ce(re().body,"htmx:replacedInHistory",{path:d.path})}}var n=T(c);je(v.swapStyle,c,l,g,n,r);if(t.elt&&!se(t.elt)&&ee(t.elt,"id")){var i=document.getElementById(ee(t.elt,"id"));var a={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!Q.config.defaultFocusScroll};if(i){if(t.start&&i.setSelectionRange){try{i.setSelectionRange(t.start,t.end)}catch(e){}}i.focus(a)}}c.classList.remove(Q.config.swappingClass);oe(n.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}ce(e,"htmx:afterSwap",u)});if(O(f,/HX-Trigger-After-Swap:/i)){var o=l;if(!se(l)){o=re().body}_e(f,"HX-Trigger-After-Swap",o)}var s=function(){oe(n.tasks,function(e){e.call()});oe(n.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}ce(e,"htmx:afterSettle",u)});if(u.pathInfo.anchor){var e=re().getElementById(u.pathInfo.anchor);if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}if(n.title&&!m){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}Cr(n.elts,v);if(O(f,/HX-Trigger-After-Settle:/i)){var r=l;if(!se(l)){r=re().body}_e(f,"HX-Trigger-After-Settle",r)}ie(p)};if(v.settleDelay>0){setTimeout(s,v.settleDelay)}else{s()}}catch(e){fe(l,"htmx:swapError",u);ie(x);throw e}};var b=Q.config.globalViewTransitions;if(v.hasOwnProperty("transition")){b=v.transition}if(b&&ce(l,"htmx:beforeTransition",u)&&typeof Promise!=="undefined"&&document.startViewTransition){var w=new Promise(function(e,t){p=e;x=t});var S=y;y=function(){document.startViewTransition(function(){S();return w})}}if(v.swapDelay>0){setTimeout(y,v.swapDelay)}else{y()}}if(a){fe(l,"htmx:responseError",le({error:"Response Status Error Code "+f.status+" from "+u.pathInfo.requestPath},u))}}var Xr={};function Dr(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Ur(e,t){if(t.init){t.init(r)}Xr[e]=le(Dr(),t)}function Br(e){delete Xr[e]}function Fr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=te(e,"hx-ext");if(t){oe(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Xr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return Fr(u(e),r,n)}var Vr=false;re().addEventListener("DOMContentLoaded",function(){Vr=true});function jr(e){if(Vr||re().readyState==="complete"){e()}else{re().addEventListener("DOMContentLoaded",e)}}function _r(){if(Q.config.includeIndicatorStyles!==false){re().head.insertAdjacentHTML("beforeend","")}}function zr(){var e=re().querySelector('meta[name="htmx-config"]');if(e){return E(e.content)}else{return null}}function $r(){var e=zr();if(e){Q.config=le(Q.config,e)}}jr(function(){$r();_r();var e=re().body;zt(e);var t=re().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=ae(t);if(r&&r.xhr){r.xhr.abort()}});const r=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){ar();oe(t,function(e){ce(e,"htmx:restored",{document:re(),triggerEvent:ce})})}else{if(r){r(e)}}};setTimeout(function(){ce(e,"htmx:load",{});e=null},0)});return Q}()}); \ No newline at end of file diff --git a/templates/base/head.html b/templates/base/head.html index 7949af9b..94d85c4f 100644 --- a/templates/base/head.html +++ b/templates/base/head.html @@ -11,6 +11,5 @@ - \ No newline at end of file diff --git a/templates/partial/search_result.html b/templates/partial/search_result.html index 37c3eccf..1ea36fd9 100644 --- a/templates/partial/search_result.html +++ b/templates/partial/search_result.html @@ -4,7 +4,7 @@

- {{result.name}} + {{result.name}} {% if result.result_type.name == "DATA_PRODUCT" %} Data product From fb3d0275d6e21c84e59e7d76f50e6d772a8d031f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 29 Jan 2024 17:21:52 +0000 Subject: [PATCH 031/221] Commit changes made by code formatters --- README.md | 2 +- home/helper.py | 2 +- home/views.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 35744aff..ae9e59e0 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ You will need npm (for javascript dependencies) and poetry (for python dependenc 2. Copy `.env.example` to `.env`. 3. You wil need to obtain an access token from Datahub catalogue and populate the `CATALOGUE_TOKEN` var in .env to be able to retrieve search data. https://datahub.apps-tools.development.data-platform.service.justice.gov.uk/settings/tokens -5. Run `poetry run python manage.py runserver` +4. Run `poetry run python manage.py runserver` Run `npm install` and then `npm run sass` to compile the stylesheets. diff --git a/home/helper.py b/home/helper.py index 7952f7d9..181d2eb6 100644 --- a/home/helper.py +++ b/home/helper.py @@ -3,4 +3,4 @@ def filter_seleted_domains(domain_list, domains): for domain in domain_list: if domain.value in domains: selected_domain[domain.value] = domain.label - return selected_domain \ No newline at end of file + return selected_domain diff --git a/home/views.py b/home/views.py index 11acf7ee..6879a0c3 100644 --- a/home/views.py +++ b/home/views.py @@ -12,7 +12,7 @@ def home_view(request): def details_view(request, id): - + context = {} client = get_catalogue_client() filter_value = [MultiSelectFilter("urn", id)] From 9dc88115baf347403a80423a6baabba3028dc858 Mon Sep 17 00:00:00 2001 From: "priya.basker" Date: Mon, 29 Jan 2024 17:29:35 +0000 Subject: [PATCH 032/221] Added result type --- home/views.py | 12 +++--------- templates/details.html | 3 ++- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/home/views.py b/home/views.py index 6879a0c3..9751ab06 100644 --- a/home/views.py +++ b/home/views.py @@ -30,25 +30,19 @@ def search_view(request): client = get_catalogue_client() # Fetch domainlist without query + # This will be replaced ater matt creates a new function search_results = client.search(query="", page=None) context = {} domain_list = search_results.facets['domains'] context["domainlist"] = domain_list - domains = request.GET.getlist("domain", []) - if domains: + domains = request.GET.getlist("domain", []) + if domains: selected_domain = filter_seleted_domains(domain_list, domains) context['selected_domain'] = selected_domain request.session['selected_domain'] = selected_domain request.session['domains'] = domains filter_value = [MultiSelectFilter("domains", domains)] - domains = request.GET.getlist("domain") - selected_domain = filter_seleted_domains(domain_list, domains) - context['selected_domain'] = selected_domain - request.session['selected_domain'] = selected_domain - request.session['domains'] = domains - filter_value = [MultiSelectFilter("domains", domains)] - elif request.GET.get('clear_filter') == "True": filter_value = [] context['selected_domain'] = {} diff --git a/templates/details.html b/templates/details.html index 5650b0dd..e99172f5 100644 --- a/templates/details.html +++ b/templates/details.html @@ -7,7 +7,8 @@ Back
-
+
+ {{result.result_type.name}}

{{result.name}}

From e535a913404745e5a8006221be95a39066f312ae Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 29 Jan 2024 17:30:29 +0000 Subject: [PATCH 033/221] Commit changes made by code formatters --- home/views.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/home/views.py b/home/views.py index 9751ab06..d7d9a732 100644 --- a/home/views.py +++ b/home/views.py @@ -38,11 +38,11 @@ def search_view(request): domains = request.GET.getlist("domain", []) if domains: - selected_domain = filter_seleted_domains(domain_list, domains) - context['selected_domain'] = selected_domain - request.session['selected_domain'] = selected_domain - request.session['domains'] = domains - filter_value = [MultiSelectFilter("domains", domains)] + selected_domain = filter_seleted_domains(domain_list, domains) + context['selected_domain'] = selected_domain + request.session['selected_domain'] = selected_domain + request.session['domains'] = domains + filter_value = [MultiSelectFilter("domains", domains)] elif request.GET.get('clear_filter') == "True": filter_value = [] context['selected_domain'] = {} From 4d7e5ec4e8c9d76144b8b4929cf8e32403dc92be Mon Sep 17 00:00:00 2001 From: "priya.basker" Date: Mon, 29 Jan 2024 17:49:07 +0000 Subject: [PATCH 034/221] Added details page styles --- templates/details.html | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/templates/details.html b/templates/details.html index e99172f5..2d87d006 100644 --- a/templates/details.html +++ b/templates/details.html @@ -108,24 +108,25 @@

{{result.name}}

- - - -
-

IAO or Data Owner

-

- {{result.metadata.owner}}
+

+

IAO or Data Owner

+ + {{result.metadata.owner}} + +
+
+

Contact for Access requirement

+ {{result.metadata.owner_email}} -

+
- -
-

Contact for Access requirement

-

- {{result.domain_name}} -

+
+

Access requirement

+ + Processing the data might require + permission from IAO or Data ownwer +
-
From c7cccebf95bfb1e236957fa124e1da4c08eefe2d Mon Sep 17 00:00:00 2001 From: "priya.basker" Date: Mon, 29 Jan 2024 17:50:29 +0000 Subject: [PATCH 035/221] updated spelling error --- templates/details.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/details.html b/templates/details.html index 2d87d006..af89355f 100644 --- a/templates/details.html +++ b/templates/details.html @@ -124,7 +124,7 @@

{{result.name}}

Access requirement

Processing the data might require - permission from IAO or Data ownwer + permission from IAO or Data owner

From 282eb6559e639a6cf8b99feb4da3e7cdfb13211a Mon Sep 17 00:00:00 2001 From: "priya.basker" Date: Tue, 30 Jan 2024 11:11:21 +0000 Subject: [PATCH 036/221] Added signed cookie --- core/settings.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/core/settings.py b/core/settings.py index 05c4f92b..3c219313 100644 --- a/core/settings.py +++ b/core/settings.py @@ -64,13 +64,6 @@ # Database # https://docs.djangoproject.com/en/5.0/ref/settings/#databases -DATABASES = { - "default": { - "ENGINE": "django.db.backends.sqlite3", - "NAME": BASE_DIR / "db.sqlite3", - } -} - # Password validation # https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators @@ -134,4 +127,4 @@ CATALOGUE_TOKEN = os.environ.get("CATALOGUE_TOKEN") # session -SESSION_ENGINE = 'django.contrib.sessions.backends.db' +SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' From ab5da3f83ce4143f43df3685067d99d1e914a5b7 Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Tue, 30 Jan 2024 14:31:54 +0000 Subject: [PATCH 037/221] Update catalogue library --- home/views.py | 47 ++-- poetry.lock | 701 +------------------------------------------------ pyproject.toml | 2 +- 3 files changed, 28 insertions(+), 722 deletions(-) diff --git a/home/views.py b/home/views.py index d7d9a732..45f1ff8e 100644 --- a/home/views.py +++ b/home/views.py @@ -1,8 +1,9 @@ +from data_platform_catalogue.search_types import MultiSelectFilter from django.conf import settings from django.shortcuts import render -from .services import get_catalogue_client + from .helper import filter_seleted_domains -from data_platform_catalogue.search_types import MultiSelectFilter +from .services import get_catalogue_client # Create your views here. @@ -23,67 +24,63 @@ def details_view(request, id): def search_view(request): - query = request.GET.get("query", "") page = request.GET.get("page", None) client = get_catalogue_client() - # Fetch domainlist without query - # This will be replaced ater matt creates a new function - search_results = client.search(query="", page=None) + facets = client.search_facets() context = {} - domain_list = search_results.facets['domains'] + domain_list = facets.options("domains") context["domainlist"] = domain_list domains = request.GET.getlist("domain", []) if domains: selected_domain = filter_seleted_domains(domain_list, domains) - context['selected_domain'] = selected_domain - request.session['selected_domain'] = selected_domain - request.session['domains'] = domains + context["selected_domain"] = selected_domain + request.session["selected_domain"] = selected_domain + request.session["domains"] = domains filter_value = [MultiSelectFilter("domains", domains)] - elif request.GET.get('clear_filter') == "True": + elif request.GET.get("clear_filter") == "True": filter_value = [] - context['selected_domain'] = {} - elif request.GET.get('clear_label') == 'True': + context["selected_domain"] = {} + elif request.GET.get("clear_label") == "True": # Value to clear label_value = request.GET.getlist("value") # Remove the selected value from list - domains = request.session.get('domains', None) + domains = request.session.get("domains", None) domains = list(set(domains) - set(label_value)) # Populated selected domain selected_domain = filter_seleted_domains(domain_list, domains) - context['domains'] = domains - context['selected_domain'] = selected_domain + context["domains"] = domains + context["selected_domain"] = selected_domain # Reassign to session - request.session['selected_domain'] = selected_domain - request.session['domains'] = domains + request.session["selected_domain"] = selected_domain + request.session["domains"] = domains if not domains: filter_value = [] else: filter_value = [MultiSelectFilter("domains", domains)] - elif request.GET.get('query'): - domains = request.session.get('domains', None) + elif request.GET.get("query"): + domains = request.session.get("domains", None) # Preserve filter selected_domain = filter_seleted_domains(domain_list, domains) if not domains: filter_value = [] else: - context['selected_domain'] = selected_domain - context['domains'] = domains + context["selected_domain"] = selected_domain + context["domains"] = domains filter_value = [MultiSelectFilter("domains", domains)] else: filter_value = [] - context['selected_domain'] = {} + context["selected_domain"] = {} # Search with filter - search_results = client.search( - query=query, page=page, filters=filter_value) + search_results = client.search(query=query, page=page, filters=filter_value) context["query"] = query context["results"] = search_results.page_results context["total_results"] = search_results.total_results diff --git a/poetry.lock b/poetry.lock index ecf1087a..81518792 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] name = "acryl-datahub" @@ -121,17 +121,6 @@ trino = ["Deprecated", "PyYAML", "acryl-sqlglot (==20.4.1.dev14)", "aiohttp (<4) unity-catalog = ["Deprecated", "PyYAML", "acryl-sqlglot (==20.4.1.dev14)", "aiohttp (<4)", "avro (>=1.11.3,<1.12)", "avro-gen3 (==0.7.11)", "cached-property", "click (>=7.1.2)", "click-default-group", "click-spinner", "databricks-sdk (>=0.9.0)", "databricks-sql-connector (>=2.8.0,<3.0.0)", "docker", "expandvars (>=0.6.5)", "great-expectations (>=0.15.12,<=0.15.50)", "greenlet", "humanfriendly", "ijson", "importlib-metadata (>=4.0.0)", "jsonref", "jsonschema", "jsonschema (<=4.17.3)", "packaging", "progressbar2", "psutil (>=5.8.0)", "pydantic (<2)", "pyspark (>=3.3.0,<3.4.0)", "python-dateutil (>=2.8.0)", "requests", "requests-file", "ruamel.yaml", "scipy (>=1.7.2)", "sqlalchemy (>=1.4.39,<2)", "sqllineage (==1.3.8)", "sqlparse", "sqlparse (==0.4.4)", "tabulate", "termcolor (>=1.0.0)", "toml (>=0.10.0)", "traitlets (<5.2.2)"] vertica = ["Deprecated", "PyYAML", "acryl-sqlglot (==20.4.1.dev14)", "aiohttp (<4)", "avro (>=1.11.3,<1.12)", "avro-gen3 (==0.7.11)", "cached-property", "click (>=7.1.2)", "click-default-group", "click-spinner", "docker", "expandvars (>=0.6.5)", "great-expectations (>=0.15.12,<=0.15.50)", "greenlet", "humanfriendly", "ijson", "importlib-metadata (>=4.0.0)", "jsonref", "jsonschema", "jsonschema (<=4.17.3)", "packaging", "progressbar2", "psutil (>=5.8.0)", "pydantic (<2)", "python-dateutil (>=2.8.0)", "requests-file", "ruamel.yaml", "scipy (>=1.7.2)", "sqlalchemy (>=1.4.39,<2)", "sqlparse", "tabulate", "termcolor (>=1.0.0)", "toml (>=0.10.0)", "traitlets (<5.2.2)", "vertica-sqlalchemy-dialect[vertica-python] (==0.0.8.1)"] -[[package]] -name = "aiofiles" -version = "23.2.1" -description = "File support for asyncio." -optional = false -python-versions = ">=3.7" -files = [ - {file = "aiofiles-23.2.1-py3-none-any.whl", hash = "sha256:19297512c647d4b27a2cf7c34caa7e405c0d60b5560618a29a9fe027b18b0107"}, - {file = "aiofiles-23.2.1.tar.gz", hash = "sha256:84ec2218d8419404abcb9f0c02df3f34c6e0a68ed41072acfb1cef5cbc29051a"}, -] - [[package]] name = "aiohttp" version = "3.9.1" @@ -251,26 +240,6 @@ files = [ {file = "antlr4-python3-runtime-4.9.2.tar.gz", hash = "sha256:31f5abdc7faf16a1a6e9bf2eb31565d004359b821b09944436a34361929ae85a"}, ] -[[package]] -name = "anyio" -version = "4.2.0" -description = "High level compatibility layer for multiple asynchronous event loop implementations" -optional = false -python-versions = ">=3.8" -files = [ - {file = "anyio-4.2.0-py3-none-any.whl", hash = "sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee"}, - {file = "anyio-4.2.0.tar.gz", hash = "sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f"}, -] - -[package.dependencies] -idna = ">=2.8" -sniffio = ">=1.1" - -[package.extras] -doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] -trio = ["trio (>=0.23)"] - [[package]] name = "appdirs" version = "1.4.4" @@ -365,22 +334,6 @@ charset-normalizer = ["charset-normalizer"] html5lib = ["html5lib"] lxml = ["lxml"] -[[package]] -name = "bidict" -version = "0.22.1" -description = "The bidirectional mapping library for Python." -optional = false -python-versions = ">=3.7" -files = [ - {file = "bidict-0.22.1-py3-none-any.whl", hash = "sha256:6ef212238eb884b664f28da76f33f1d28b260f665fc737b413b287d5487d1e7b"}, - {file = "bidict-0.22.1.tar.gz", hash = "sha256:1e0f7f74e4860e6d0943a05d4134c63a2fad86f3d4732fb265bd79e4e856d81d"}, -] - -[package.extras] -docs = ["furo", "sphinx", "sphinx-copybutton"] -lint = ["pre-commit"] -test = ["hypothesis", "pytest", "pytest-benchmark[histogram]", "pytest-cov", "pytest-xdist", "sortedcollections", "sortedcontainers", "sphinx"] - [[package]] name = "black" version = "23.12.1" @@ -999,25 +952,6 @@ files = [ [package.extras] tests = ["black", "pytest", "pytest-cov", "tox"] -[[package]] -name = "fastapi" -version = "0.109.0" -description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" -optional = false -python-versions = ">=3.8" -files = [ - {file = "fastapi-0.109.0-py3-none-any.whl", hash = "sha256:8c77515984cd8e8cfeb58364f8cc7a28f0692088475e2614f7bf03275eba9093"}, - {file = "fastapi-0.109.0.tar.gz", hash = "sha256:b978095b9ee01a5cf49b19f4bc1ac9b8ca83aa076e770ef8fd9af09a2b88d191"}, -] - -[package.dependencies] -pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" -starlette = ">=0.35.0,<0.36.0" -typing-extensions = ">=4.8.0" - -[package.extras] -all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] - [[package]] name = "filelock" version = "3.13.1" @@ -1396,125 +1330,6 @@ gevent = ["gevent (>=1.4.0)"] setproctitle = ["setproctitle"] tornado = ["tornado (>=0.2)"] -[[package]] -name = "h11" -version = "0.14.0" -description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -optional = false -python-versions = ">=3.7" -files = [ - {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, - {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, -] - -[[package]] -name = "htmx" -version = "0.0.0" -description = "Build web apps with Python, HTMX and Tailwind CSS" -optional = false -python-versions = ">=3.7,<4.0" -files = [ - {file = "htmx-0.0.0-py3-none-any.whl", hash = "sha256:7f2adf003ad74a5efaa8c37abf2771fc1903fbc07aba72c0c9208e3cf578b487"}, - {file = "htmx-0.0.0.tar.gz", hash = "sha256:6a410e86f58e7431fca222d7fe61888deeae05702f564bf0e6ca40f6669333fd"}, -] - -[package.dependencies] -nicegui = ">=1.2.9" -pydantic = ">=1.10.7,<2.0.0" - -[[package]] -name = "httpcore" -version = "1.0.2" -description = "A minimal low-level HTTP client." -optional = false -python-versions = ">=3.8" -files = [ - {file = "httpcore-1.0.2-py3-none-any.whl", hash = "sha256:096cc05bca73b8e459a1fc3dcf585148f63e534eae4339559c9b8a8d6399acc7"}, - {file = "httpcore-1.0.2.tar.gz", hash = "sha256:9fc092e4799b26174648e54b74ed5f683132a464e95643b226e00c2ed2fa6535"}, -] - -[package.dependencies] -certifi = "*" -h11 = ">=0.13,<0.15" - -[package.extras] -asyncio = ["anyio (>=4.0,<5.0)"] -http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<0.23.0)"] - -[[package]] -name = "httptools" -version = "0.6.1" -description = "A collection of framework independent HTTP protocol utils." -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "httptools-0.6.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d2f6c3c4cb1948d912538217838f6e9960bc4a521d7f9b323b3da579cd14532f"}, - {file = "httptools-0.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:00d5d4b68a717765b1fabfd9ca755bd12bf44105eeb806c03d1962acd9b8e563"}, - {file = "httptools-0.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:639dc4f381a870c9ec860ce5c45921db50205a37cc3334e756269736ff0aac58"}, - {file = "httptools-0.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e57997ac7fb7ee43140cc03664de5f268813a481dff6245e0075925adc6aa185"}, - {file = "httptools-0.6.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0ac5a0ae3d9f4fe004318d64b8a854edd85ab76cffbf7ef5e32920faef62f142"}, - {file = "httptools-0.6.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3f30d3ce413088a98b9db71c60a6ada2001a08945cb42dd65a9a9fe228627658"}, - {file = "httptools-0.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:1ed99a373e327f0107cb513b61820102ee4f3675656a37a50083eda05dc9541b"}, - {file = "httptools-0.6.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7a7ea483c1a4485c71cb5f38be9db078f8b0e8b4c4dc0210f531cdd2ddac1ef1"}, - {file = "httptools-0.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:85ed077c995e942b6f1b07583e4eb0a8d324d418954fc6af913d36db7c05a5a0"}, - {file = "httptools-0.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b0bb634338334385351a1600a73e558ce619af390c2b38386206ac6a27fecfc"}, - {file = "httptools-0.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d9ceb2c957320def533671fc9c715a80c47025139c8d1f3797477decbc6edd2"}, - {file = "httptools-0.6.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4f0f8271c0a4db459f9dc807acd0eadd4839934a4b9b892f6f160e94da309837"}, - {file = "httptools-0.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6a4f5ccead6d18ec072ac0b84420e95d27c1cdf5c9f1bc8fbd8daf86bd94f43d"}, - {file = "httptools-0.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:5cceac09f164bcba55c0500a18fe3c47df29b62353198e4f37bbcc5d591172c3"}, - {file = "httptools-0.6.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:75c8022dca7935cba14741a42744eee13ba05db00b27a4b940f0d646bd4d56d0"}, - {file = "httptools-0.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:48ed8129cd9a0d62cf4d1575fcf90fb37e3ff7d5654d3a5814eb3d55f36478c2"}, - {file = "httptools-0.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f58e335a1402fb5a650e271e8c2d03cfa7cea46ae124649346d17bd30d59c90"}, - {file = "httptools-0.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93ad80d7176aa5788902f207a4e79885f0576134695dfb0fefc15b7a4648d503"}, - {file = "httptools-0.6.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9bb68d3a085c2174c2477eb3ffe84ae9fb4fde8792edb7bcd09a1d8467e30a84"}, - {file = "httptools-0.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b512aa728bc02354e5ac086ce76c3ce635b62f5fbc32ab7082b5e582d27867bb"}, - {file = "httptools-0.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:97662ce7fb196c785344d00d638fc9ad69e18ee4bfb4000b35a52efe5adcc949"}, - {file = "httptools-0.6.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8e216a038d2d52ea13fdd9b9c9c7459fb80d78302b257828285eca1c773b99b3"}, - {file = "httptools-0.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3e802e0b2378ade99cd666b5bffb8b2a7cc8f3d28988685dc300469ea8dd86cb"}, - {file = "httptools-0.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4bd3e488b447046e386a30f07af05f9b38d3d368d1f7b4d8f7e10af85393db97"}, - {file = "httptools-0.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe467eb086d80217b7584e61313ebadc8d187a4d95bb62031b7bab4b205c3ba3"}, - {file = "httptools-0.6.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3c3b214ce057c54675b00108ac42bacf2ab8f85c58e3f324a4e963bbc46424f4"}, - {file = "httptools-0.6.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8ae5b97f690badd2ca27cbf668494ee1b6d34cf1c464271ef7bfa9ca6b83ffaf"}, - {file = "httptools-0.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:405784577ba6540fa7d6ff49e37daf104e04f4b4ff2d1ac0469eaa6a20fde084"}, - {file = "httptools-0.6.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:95fb92dd3649f9cb139e9c56604cc2d7c7bf0fc2e7c8d7fbd58f96e35eddd2a3"}, - {file = "httptools-0.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dcbab042cc3ef272adc11220517278519adf8f53fd3056d0e68f0a6f891ba94e"}, - {file = "httptools-0.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cf2372e98406efb42e93bfe10f2948e467edfd792b015f1b4ecd897903d3e8d"}, - {file = "httptools-0.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:678fcbae74477a17d103b7cae78b74800d795d702083867ce160fc202104d0da"}, - {file = "httptools-0.6.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e0b281cf5a125c35f7f6722b65d8542d2e57331be573e9e88bc8b0115c4a7a81"}, - {file = "httptools-0.6.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:95658c342529bba4e1d3d2b1a874db16c7cca435e8827422154c9da76ac4e13a"}, - {file = "httptools-0.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:7ebaec1bf683e4bf5e9fbb49b8cc36da482033596a415b3e4ebab5a4c0d7ec5e"}, - {file = "httptools-0.6.1.tar.gz", hash = "sha256:c6e26c30455600b95d94b1b836085138e82f177351454ee841c148f93a9bad5a"}, -] - -[package.extras] -test = ["Cython (>=0.29.24,<0.30.0)"] - -[[package]] -name = "httpx" -version = "0.26.0" -description = "The next generation HTTP client." -optional = false -python-versions = ">=3.8" -files = [ - {file = "httpx-0.26.0-py3-none-any.whl", hash = "sha256:8915f5a3627c4d47b73e8202457cb28f1266982d1159bd5779d86a80c0eab1cd"}, - {file = "httpx-0.26.0.tar.gz", hash = "sha256:451b55c30d5185ea6b23c2c793abf9bb237d2a7dfb901ced6ff69ad37ec1dfaf"}, -] - -[package.dependencies] -anyio = "*" -certifi = "*" -httpcore = "==1.*" -idna = "*" -sniffio = "*" - -[package.extras] -brotli = ["brotli", "brotlicffi"] -cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] -http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] - [[package]] name = "humanfriendly" version = "10.0" @@ -1554,17 +1369,6 @@ files = [ {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, ] -[[package]] -name = "ifaddr" -version = "0.2.0" -description = "Cross-platform network interface and IP address enumeration library" -optional = false -python-versions = "*" -files = [ - {file = "ifaddr-0.2.0-py3-none-any.whl", hash = "sha256:085e0305cfe6f16ab12d72e2024030f5d52674afad6911bb1eee207177b8a748"}, - {file = "ifaddr-0.2.0.tar.gz", hash = "sha256:cc0cbfcaabf765d44595825fb96a99bb12c79716b73b44330ea38ee2b0c4aed4"}, -] - [[package]] name = "ijson" version = "3.2.3" @@ -1693,17 +1497,6 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] -[[package]] -name = "itsdangerous" -version = "2.1.2" -description = "Safely pass data to untrusted environments and back." -optional = false -python-versions = ">=3.7" -files = [ - {file = "itsdangerous-2.1.2-py3-none-any.whl", hash = "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44"}, - {file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"}, -] - [[package]] name = "jinja2" version = "3.1.3" @@ -1818,22 +1611,6 @@ files = [ docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.5)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"] testing = ["coverage", "pyyaml"] -[[package]] -name = "markdown2" -version = "2.4.10" -description = "A fast and complete Python implementation of Markdown" -optional = false -python-versions = ">=3.5, <4" -files = [ - {file = "markdown2-2.4.10-py2.py3-none-any.whl", hash = "sha256:e6105800483783831f5dc54f827aa5b44eb137ecef5a70293d8ecfbb4109ecc6"}, - {file = "markdown2-2.4.10.tar.gz", hash = "sha256:cdba126d90dc3aef6f4070ac342f974d63f415678959329cc7909f96cc235d72"}, -] - -[package.extras] -all = ["pygments (>=2.7.3)", "wavedrom"] -code-syntax-highlighting = ["pygments (>=2.7.3)"] -wavedrom = ["wavedrom"] - [[package]] name = "markupsafe" version = "2.1.4" @@ -1919,13 +1696,13 @@ psutil = "*" [[package]] name = "ministryofjustice-data-platform-catalogue" -version = "0.7.0" +version = "0.8.1" description = "Library to integrate the MoJ data platform with the catalogue component." optional = false python-versions = ">=3.10,<4.0" files = [ - {file = "ministryofjustice_data_platform_catalogue-0.7.0-py3-none-any.whl", hash = "sha256:2c8c0a7324ead0f45a4f339dfe31905dddf28b0de897d8250172b96296cfdcf4"}, - {file = "ministryofjustice_data_platform_catalogue-0.7.0.tar.gz", hash = "sha256:7858d43e71e2edb409cd6fb78fb8ee2db3e87649eeaef6167c3ad575e0d44916"}, + {file = "ministryofjustice_data_platform_catalogue-0.8.1-py3-none-any.whl", hash = "sha256:8dc0530f9458c66f7b8b62a83599039efb7ee4d2499f12abffa4634841378471"}, + {file = "ministryofjustice_data_platform_catalogue-0.8.1.tar.gz", hash = "sha256:4dcdd8f793033e0fc1356a1d2f8d6eb64e886fc690d32bde92d4f436f9ccdd07"}, ] [package.dependencies] @@ -2062,40 +1839,6 @@ doc = ["nb2plots (>=0.7)", "nbconvert (<7.9)", "numpydoc (>=1.6)", "pillow (>=9. extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.11)", "sympy (>=1.10)"] test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] -[[package]] -name = "nicegui" -version = "1.4.12" -description = "Create web-based user interfaces with Python. The nice way." -optional = false -python-versions = ">=3.8,<4.0" -files = [ - {file = "nicegui-1.4.12-py3-none-any.whl", hash = "sha256:50325f94ff3b28880f299fdf98638d1daa482208bcf951d27feb461f0937e41a"}, - {file = "nicegui-1.4.12.tar.gz", hash = "sha256:ec8df7d74f531968b553f7a909a50e3fb8fbbdac0ecbc0c4a017ba7bf6714ccc"}, -] - -[package.dependencies] -aiofiles = ">=23.1.0,<24.0.0" -fastapi = ">=0.109.0,<0.110.0" -httpx = ">=0.24.0,<1.0.0" -ifaddr = ">=0.2.0,<0.3.0" -itsdangerous = ">=2.1.2,<3.0.0" -jinja2 = ">=3.1.3,<4.0.0" -markdown2 = ">=2.4.7,<2.4.11" -orjson = {version = ">=3.8.6,<4.0.0", markers = "platform_machine != \"i386\" and platform_machine != \"i686\""} -Pygments = ">=2.15.1,<3.0.0" -python-multipart = ">=0.0.6,<0.0.7" -python-socketio = ">=5.10.0" -typing-extensions = ">=4.0.0" -uvicorn = {version = ">=0.22.0", extras = ["standard"]} -vbuild = ">=0.8.2" -watchfiles = ">=0.18.1,<1.0.0" - -[package.extras] -highcharts = ["nicegui-highcharts (>=1.0.1,<2.0.0)"] -matplotlib = ["matplotlib (>=3.5.0,<4.0.0)"] -native = ["pywebview (>=4.4.0,<5.0.0)"] -plotly = ["plotly (>=5.13.0,<6.0.0)"] - [[package]] name = "nodeenv" version = "1.8.0" @@ -2235,65 +1978,6 @@ files = [ [package.extras] dev = ["black", "mypy", "pytest"] -[[package]] -name = "orjson" -version = "3.9.12" -description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" -optional = false -python-versions = ">=3.8" -files = [ - {file = "orjson-3.9.12-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:6b4e2bed7d00753c438e83b613923afdd067564ff7ed696bfe3a7b073a236e07"}, - {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd1b8ec63f0bf54a50b498eedeccdca23bd7b658f81c524d18e410c203189365"}, - {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ab8add018a53665042a5ae68200f1ad14c7953fa12110d12d41166f111724656"}, - {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12756a108875526b76e505afe6d6ba34960ac6b8c5ec2f35faf73ef161e97e07"}, - {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:890e7519c0c70296253660455f77e3a194554a3c45e42aa193cdebc76a02d82b"}, - {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d664880d7f016efbae97c725b243b33c2cbb4851ddc77f683fd1eec4a7894146"}, - {file = "orjson-3.9.12-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cfdaede0fa5b500314ec7b1249c7e30e871504a57004acd116be6acdda3b8ab3"}, - {file = "orjson-3.9.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6492ff5953011e1ba9ed1bf086835fd574bd0a3cbe252db8e15ed72a30479081"}, - {file = "orjson-3.9.12-cp310-none-win32.whl", hash = "sha256:29bf08e2eadb2c480fdc2e2daae58f2f013dff5d3b506edd1e02963b9ce9f8a9"}, - {file = "orjson-3.9.12-cp310-none-win_amd64.whl", hash = "sha256:0fc156fba60d6b50743337ba09f052d8afc8b64595112996d22f5fce01ab57da"}, - {file = "orjson-3.9.12-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:2849f88a0a12b8d94579b67486cbd8f3a49e36a4cb3d3f0ab352c596078c730c"}, - {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3186b18754befa660b31c649a108a915493ea69b4fc33f624ed854ad3563ac65"}, - {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cbbf313c9fb9d4f6cf9c22ced4b6682230457741daeb3d7060c5d06c2e73884a"}, - {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99e8cd005b3926c3db9b63d264bd05e1bf4451787cc79a048f27f5190a9a0311"}, - {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:59feb148392d9155f3bfed0a2a3209268e000c2c3c834fb8fe1a6af9392efcbf"}, - {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4ae815a172a1f073b05b9e04273e3b23e608a0858c4e76f606d2d75fcabde0c"}, - {file = "orjson-3.9.12-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ed398f9a9d5a1bf55b6e362ffc80ac846af2122d14a8243a1e6510a4eabcb71e"}, - {file = "orjson-3.9.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d3cfb76600c5a1e6be91326b8f3b83035a370e727854a96d801c1ea08b708073"}, - {file = "orjson-3.9.12-cp311-none-win32.whl", hash = "sha256:a2b6f5252c92bcab3b742ddb3ac195c0fa74bed4319acd74f5d54d79ef4715dc"}, - {file = "orjson-3.9.12-cp311-none-win_amd64.whl", hash = "sha256:c95488e4aa1d078ff5776b58f66bd29d628fa59adcb2047f4efd3ecb2bd41a71"}, - {file = "orjson-3.9.12-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d6ce2062c4af43b92b0221ed4f445632c6bf4213f8a7da5396a122931377acd9"}, - {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:950951799967558c214cd6cceb7ceceed6f81d2c3c4135ee4a2c9c69f58aa225"}, - {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2dfaf71499d6fd4153f5c86eebb68e3ec1bf95851b030a4b55c7637a37bbdee4"}, - {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:659a8d7279e46c97661839035a1a218b61957316bf0202674e944ac5cfe7ed83"}, - {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af17fa87bccad0b7f6fd8ac8f9cbc9ee656b4552783b10b97a071337616db3e4"}, - {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd52dec9eddf4c8c74392f3fd52fa137b5f2e2bed1d9ae958d879de5f7d7cded"}, - {file = "orjson-3.9.12-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:640e2b5d8e36b970202cfd0799d11a9a4ab46cf9212332cd642101ec952df7c8"}, - {file = "orjson-3.9.12-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:daa438bd8024e03bcea2c5a92cd719a663a58e223fba967296b6ab9992259dbf"}, - {file = "orjson-3.9.12-cp312-none-win_amd64.whl", hash = "sha256:1bb8f657c39ecdb924d02e809f992c9aafeb1ad70127d53fb573a6a6ab59d549"}, - {file = "orjson-3.9.12-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:f4098c7674901402c86ba6045a551a2ee345f9f7ed54eeffc7d86d155c8427e5"}, - {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5586a533998267458fad3a457d6f3cdbddbcce696c916599fa8e2a10a89b24d3"}, - {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:54071b7398cd3f90e4bb61df46705ee96cb5e33e53fc0b2f47dbd9b000e238e1"}, - {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:67426651faa671b40443ea6f03065f9c8e22272b62fa23238b3efdacd301df31"}, - {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4a0cd56e8ee56b203abae7d482ac0d233dbfb436bb2e2d5cbcb539fe1200a312"}, - {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a84a0c3d4841a42e2571b1c1ead20a83e2792644c5827a606c50fc8af7ca4bee"}, - {file = "orjson-3.9.12-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:09d60450cda3fa6c8ed17770c3a88473a16460cd0ff2ba74ef0df663b6fd3bb8"}, - {file = "orjson-3.9.12-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bc82a4db9934a78ade211cf2e07161e4f068a461c1796465d10069cb50b32a80"}, - {file = "orjson-3.9.12-cp38-none-win32.whl", hash = "sha256:61563d5d3b0019804d782137a4f32c72dc44c84e7d078b89d2d2a1adbaa47b52"}, - {file = "orjson-3.9.12-cp38-none-win_amd64.whl", hash = "sha256:410f24309fbbaa2fab776e3212a81b96a1ec6037259359a32ea79fbccfcf76aa"}, - {file = "orjson-3.9.12-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e773f251258dd82795fd5daeac081d00b97bacf1548e44e71245543374874bcf"}, - {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b159baecfda51c840a619948c25817d37733a4d9877fea96590ef8606468b362"}, - {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:975e72e81a249174840d5a8df977d067b0183ef1560a32998be340f7e195c730"}, - {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:06e42e899dde61eb1851a9fad7f1a21b8e4be063438399b63c07839b57668f6c"}, - {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c157e999e5694475a5515942aebeed6e43f7a1ed52267c1c93dcfde7d78d421"}, - {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dde1bc7c035f2d03aa49dc8642d9c6c9b1a81f2470e02055e76ed8853cfae0c3"}, - {file = "orjson-3.9.12-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b0e9d73cdbdad76a53a48f563447e0e1ce34bcecef4614eb4b146383e6e7d8c9"}, - {file = "orjson-3.9.12-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:96e44b21fe407b8ed48afbb3721f3c8c8ce17e345fbe232bd4651ace7317782d"}, - {file = "orjson-3.9.12-cp39-none-win32.whl", hash = "sha256:cbd0f3555205bf2a60f8812133f2452d498dbefa14423ba90fe89f32276f7abf"}, - {file = "orjson-3.9.12-cp39-none-win_amd64.whl", hash = "sha256:03ea7ee7e992532c2f4a06edd7ee1553f0644790553a118e003e3c405add41fa"}, - {file = "orjson-3.9.12.tar.gz", hash = "sha256:da908d23a3b3243632b523344403b128722a5f45e278a8343c2bb67538dff0e4"}, -] - [[package]] name = "packaging" version = "23.2" @@ -2402,17 +2086,6 @@ files = [ {file = "protobuf-4.25.2.tar.gz", hash = "sha256:fe599e175cb347efc8ee524bcd4b902d11f7262c0e569ececcb89995c15f0a5e"}, ] -[[package]] -name = "pscript" -version = "0.7.7" -description = "Python to JavaScript compiler." -optional = false -python-versions = "*" -files = [ - {file = "pscript-0.7.7-py3-none-any.whl", hash = "sha256:b0fdac0df0393a4d7497153fea6a82e6429f32327c4c0a4817f1cd68adc08083"}, - {file = "pscript-0.7.7.tar.gz", hash = "sha256:8632f7a4483f235514aadee110edee82eb6d67336bf68744a7b18d76e50442f8"}, -] - [[package]] name = "psutil" version = "5.9.8" @@ -2618,25 +2291,6 @@ files = [ [package.extras] cli = ["click (>=5.0)"] -[[package]] -name = "python-engineio" -version = "4.8.2" -description = "Engine.IO server and client for Python" -optional = false -python-versions = ">=3.6" -files = [ - {file = "python-engineio-4.8.2.tar.gz", hash = "sha256:f8609e3afdda318fdc336b4ba2de8dd397bb8f9b8a1b43e56c27330e32c2e34c"}, - {file = "python_engineio-4.8.2-py3-none-any.whl", hash = "sha256:a357f0aba275c311b66f22181472ed5b174bbc541742eea1d16feae2fa1afabd"}, -] - -[package.dependencies] -simple-websocket = ">=0.10.0" - -[package.extras] -asyncio-client = ["aiohttp (>=3.4)"] -client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"] -docs = ["sphinx"] - [[package]] name = "python-jose" version = "3.3.0" @@ -2658,40 +2312,6 @@ cryptography = ["cryptography (>=3.4.0)"] pycrypto = ["pyasn1", "pycrypto (>=2.6.0,<2.7.0)"] pycryptodome = ["pyasn1", "pycryptodome (>=3.3.1,<4.0.0)"] -[[package]] -name = "python-multipart" -version = "0.0.6" -description = "A streaming multipart parser for Python" -optional = false -python-versions = ">=3.7" -files = [ - {file = "python_multipart-0.0.6-py3-none-any.whl", hash = "sha256:ee698bab5ef148b0a760751c261902cd096e57e10558e11aca17646b74ee1c18"}, - {file = "python_multipart-0.0.6.tar.gz", hash = "sha256:e9925a80bb668529f1b67c7fdb0a5dacdd7cbfc6fb0bff3ea443fe22bdd62132"}, -] - -[package.extras] -dev = ["atomicwrites (==1.2.1)", "attrs (==19.2.0)", "coverage (==6.5.0)", "hatch", "invoke (==1.7.3)", "more-itertools (==4.3.0)", "pbr (==4.3.0)", "pluggy (==1.0.0)", "py (==1.11.0)", "pytest (==7.2.0)", "pytest-cov (==4.0.0)", "pytest-timeout (==2.1.0)", "pyyaml (==5.1)"] - -[[package]] -name = "python-socketio" -version = "5.11.0" -description = "Socket.IO server and client for Python" -optional = false -python-versions = ">=3.6" -files = [ - {file = "python-socketio-5.11.0.tar.gz", hash = "sha256:b03186e04b942088781f6286c13604a853e5e35ed59158c51ff7af22fa032e6f"}, - {file = "python_socketio-5.11.0-py3-none-any.whl", hash = "sha256:cfcb0163d77c8d23b98285754e79016786740dd901268654a52823da0bc73382"}, -] - -[package.dependencies] -bidict = ">=0.21.0" -python-engineio = ">=4.8.0" - -[package.extras] -asyncio-client = ["aiohttp (>=3.4)"] -client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"] -docs = ["sphinx"] - [[package]] name = "python-utils" version = "3.8.2" @@ -2759,7 +2379,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -3242,23 +2861,6 @@ docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-g testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] -[[package]] -name = "simple-websocket" -version = "1.0.0" -description = "Simple WebSocket server and client for Python" -optional = false -python-versions = ">=3.6" -files = [ - {file = "simple-websocket-1.0.0.tar.gz", hash = "sha256:17d2c72f4a2bd85174a97e3e4c88b01c40c3f81b7b648b0cc3ce1305968928c8"}, - {file = "simple_websocket-1.0.0-py3-none-any.whl", hash = "sha256:1d5bf585e415eaa2083e2bcf02a3ecf91f9712e7b3e6b9fa0b461ad04e0837bc"}, -] - -[package.dependencies] -wsproto = "*" - -[package.extras] -docs = ["sphinx"] - [[package]] name = "six" version = "1.16.0" @@ -3270,17 +2872,6 @@ files = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] -[[package]] -name = "sniffio" -version = "1.3.0" -description = "Sniff out which async library your code is running under" -optional = false -python-versions = ">=3.7" -files = [ - {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, - {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, -] - [[package]] name = "soupsieve" version = "2.5" @@ -3413,23 +3004,6 @@ dev = ["build", "flake8"] doc = ["sphinx"] test = ["pytest", "pytest-cov"] -[[package]] -name = "starlette" -version = "0.35.1" -description = "The little ASGI library that shines." -optional = false -python-versions = ">=3.8" -files = [ - {file = "starlette-0.35.1-py3-none-any.whl", hash = "sha256:50bbbda9baa098e361f398fda0928062abbaf1f54f4fadcbe17c092a01eb9a25"}, - {file = "starlette-0.35.1.tar.gz", hash = "sha256:3e2639dac3520e4f58734ed22553f950d3f3cb1001cd2eaac4d57e8cdc5f66bc"}, -] - -[package.dependencies] -anyio = ">=3.4.0,<5" - -[package.extras] -full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyaml"] - [[package]] name = "tabulate" version = "0.9.0" @@ -3565,89 +3139,6 @@ secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17. socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] -[[package]] -name = "uvicorn" -version = "0.27.0" -description = "The lightning-fast ASGI server." -optional = false -python-versions = ">=3.8" -files = [ - {file = "uvicorn-0.27.0-py3-none-any.whl", hash = "sha256:890b00f6c537d58695d3bb1f28e23db9d9e7a17cbcc76d7457c499935f933e24"}, - {file = "uvicorn-0.27.0.tar.gz", hash = "sha256:c855578045d45625fd027367f7653d249f7c49f9361ba15cf9624186b26b8eb6"}, -] - -[package.dependencies] -click = ">=7.0" -colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""} -h11 = ">=0.8" -httptools = {version = ">=0.5.0", optional = true, markers = "extra == \"standard\""} -python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} -pyyaml = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} -uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "(sys_platform != \"win32\" and sys_platform != \"cygwin\") and platform_python_implementation != \"PyPy\" and extra == \"standard\""} -watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} -websockets = {version = ">=10.4", optional = true, markers = "extra == \"standard\""} - -[package.extras] -standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] - -[[package]] -name = "uvloop" -version = "0.19.0" -description = "Fast implementation of asyncio event loop on top of libuv" -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de4313d7f575474c8f5a12e163f6d89c0a878bc49219641d49e6f1444369a90e"}, - {file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5588bd21cf1fcf06bded085f37e43ce0e00424197e7c10e77afd4bbefffef428"}, - {file = "uvloop-0.19.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b1fd71c3843327f3bbc3237bedcdb6504fd50368ab3e04d0410e52ec293f5b8"}, - {file = "uvloop-0.19.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a05128d315e2912791de6088c34136bfcdd0c7cbc1cf85fd6fd1bb321b7c849"}, - {file = "uvloop-0.19.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cd81bdc2b8219cb4b2556eea39d2e36bfa375a2dd021404f90a62e44efaaf957"}, - {file = "uvloop-0.19.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5f17766fb6da94135526273080f3455a112f82570b2ee5daa64d682387fe0dcd"}, - {file = "uvloop-0.19.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4ce6b0af8f2729a02a5d1575feacb2a94fc7b2e983868b009d51c9a9d2149bef"}, - {file = "uvloop-0.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:31e672bb38b45abc4f26e273be83b72a0d28d074d5b370fc4dcf4c4eb15417d2"}, - {file = "uvloop-0.19.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:570fc0ed613883d8d30ee40397b79207eedd2624891692471808a95069a007c1"}, - {file = "uvloop-0.19.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5138821e40b0c3e6c9478643b4660bd44372ae1e16a322b8fc07478f92684e24"}, - {file = "uvloop-0.19.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:91ab01c6cd00e39cde50173ba4ec68a1e578fee9279ba64f5221810a9e786533"}, - {file = "uvloop-0.19.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:47bf3e9312f63684efe283f7342afb414eea4d3011542155c7e625cd799c3b12"}, - {file = "uvloop-0.19.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:da8435a3bd498419ee8c13c34b89b5005130a476bda1d6ca8cfdde3de35cd650"}, - {file = "uvloop-0.19.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:02506dc23a5d90e04d4f65c7791e65cf44bd91b37f24cfc3ef6cf2aff05dc7ec"}, - {file = "uvloop-0.19.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2693049be9d36fef81741fddb3f441673ba12a34a704e7b4361efb75cf30befc"}, - {file = "uvloop-0.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7010271303961c6f0fe37731004335401eb9075a12680738731e9c92ddd96ad6"}, - {file = "uvloop-0.19.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:5daa304d2161d2918fa9a17d5635099a2f78ae5b5960e742b2fcfbb7aefaa593"}, - {file = "uvloop-0.19.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7207272c9520203fea9b93843bb775d03e1cf88a80a936ce760f60bb5add92f3"}, - {file = "uvloop-0.19.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:78ab247f0b5671cc887c31d33f9b3abfb88d2614b84e4303f1a63b46c046c8bd"}, - {file = "uvloop-0.19.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:472d61143059c84947aa8bb74eabbace30d577a03a1805b77933d6bd13ddebbd"}, - {file = "uvloop-0.19.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45bf4c24c19fb8a50902ae37c5de50da81de4922af65baf760f7c0c42e1088be"}, - {file = "uvloop-0.19.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271718e26b3e17906b28b67314c45d19106112067205119dddbd834c2b7ce797"}, - {file = "uvloop-0.19.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:34175c9fd2a4bc3adc1380e1261f60306344e3407c20a4d684fd5f3be010fa3d"}, - {file = "uvloop-0.19.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e27f100e1ff17f6feeb1f33968bc185bf8ce41ca557deee9d9bbbffeb72030b7"}, - {file = "uvloop-0.19.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:13dfdf492af0aa0a0edf66807d2b465607d11c4fa48f4a1fd41cbea5b18e8e8b"}, - {file = "uvloop-0.19.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6e3d4e85ac060e2342ff85e90d0c04157acb210b9ce508e784a944f852a40e67"}, - {file = "uvloop-0.19.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ca4956c9ab567d87d59d49fa3704cf29e37109ad348f2d5223c9bf761a332e7"}, - {file = "uvloop-0.19.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f467a5fd23b4fc43ed86342641f3936a68ded707f4627622fa3f82a120e18256"}, - {file = "uvloop-0.19.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:492e2c32c2af3f971473bc22f086513cedfc66a130756145a931a90c3958cb17"}, - {file = "uvloop-0.19.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2df95fca285a9f5bfe730e51945ffe2fa71ccbfdde3b0da5772b4ee4f2e770d5"}, - {file = "uvloop-0.19.0.tar.gz", hash = "sha256:0246f4fd1bf2bf702e06b0d45ee91677ee5c31242f39aab4ea6fe0c51aedd0fd"}, -] - -[package.extras] -docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] -test = ["Cython (>=0.29.36,<0.30.0)", "aiohttp (==3.9.0b0)", "aiohttp (>=3.8.1)", "flake8 (>=5.0,<6.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=23.0.0,<23.1.0)", "pycodestyle (>=2.9.0,<2.10.0)"] - -[[package]] -name = "vbuild" -version = "0.8.2" -description = "A simple module to extract html/script/style from a vuejs '.vue' file (can minimize/es2015 compliant js) ... just py2 or py3, NO nodejs !" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" -files = [ - {file = "vbuild-0.8.2-py2.py3-none-any.whl", hash = "sha256:d76bcc976a1c53b6a5776ac947606f9e7786c25df33a587ebe33ed09dd8a1076"}, - {file = "vbuild-0.8.2.tar.gz", hash = "sha256:270cd9078349d907dfae6c0e6364a5a5e74cb86183bb5093613f12a18b435fa9"}, -] - -[package.dependencies] -pscript = ">=0.7.0,<0.8.0" - [[package]] name = "virtualenv" version = "20.25.0" @@ -3668,174 +3159,6 @@ platformdirs = ">=3.9.1,<5" docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] -[[package]] -name = "watchfiles" -version = "0.21.0" -description = "Simple, modern and high performance file watching and code reload in python." -optional = false -python-versions = ">=3.8" -files = [ - {file = "watchfiles-0.21.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:27b4035013f1ea49c6c0b42d983133b136637a527e48c132d368eb19bf1ac6aa"}, - {file = "watchfiles-0.21.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c81818595eff6e92535ff32825f31c116f867f64ff8cdf6562cd1d6b2e1e8f3e"}, - {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6c107ea3cf2bd07199d66f156e3ea756d1b84dfd43b542b2d870b77868c98c03"}, - {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d9ac347653ebd95839a7c607608703b20bc07e577e870d824fa4801bc1cb124"}, - {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5eb86c6acb498208e7663ca22dbe68ca2cf42ab5bf1c776670a50919a56e64ab"}, - {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f564bf68404144ea6b87a78a3f910cc8de216c6b12a4cf0b27718bf4ec38d303"}, - {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d0f32ebfaa9c6011f8454994f86108c2eb9c79b8b7de00b36d558cadcedaa3d"}, - {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6d45d9b699ecbac6c7bd8e0a2609767491540403610962968d258fd6405c17c"}, - {file = "watchfiles-0.21.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:aff06b2cac3ef4616e26ba17a9c250c1fe9dd8a5d907d0193f84c499b1b6e6a9"}, - {file = "watchfiles-0.21.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d9792dff410f266051025ecfaa927078b94cc7478954b06796a9756ccc7e14a9"}, - {file = "watchfiles-0.21.0-cp310-none-win32.whl", hash = "sha256:214cee7f9e09150d4fb42e24919a1e74d8c9b8a9306ed1474ecaddcd5479c293"}, - {file = "watchfiles-0.21.0-cp310-none-win_amd64.whl", hash = "sha256:1ad7247d79f9f55bb25ab1778fd47f32d70cf36053941f07de0b7c4e96b5d235"}, - {file = "watchfiles-0.21.0-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:668c265d90de8ae914f860d3eeb164534ba2e836811f91fecc7050416ee70aa7"}, - {file = "watchfiles-0.21.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3a23092a992e61c3a6a70f350a56db7197242f3490da9c87b500f389b2d01eef"}, - {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e7941bbcfdded9c26b0bf720cb7e6fd803d95a55d2c14b4bd1f6a2772230c586"}, - {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:11cd0c3100e2233e9c53106265da31d574355c288e15259c0d40a4405cbae317"}, - {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d78f30cbe8b2ce770160d3c08cff01b2ae9306fe66ce899b73f0409dc1846c1b"}, - {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6674b00b9756b0af620aa2a3346b01f8e2a3dc729d25617e1b89cf6af4a54eb1"}, - {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fd7ac678b92b29ba630d8c842d8ad6c555abda1b9ef044d6cc092dacbfc9719d"}, - {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c873345680c1b87f1e09e0eaf8cf6c891b9851d8b4d3645e7efe2ec20a20cc7"}, - {file = "watchfiles-0.21.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:49f56e6ecc2503e7dbe233fa328b2be1a7797d31548e7a193237dcdf1ad0eee0"}, - {file = "watchfiles-0.21.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:02d91cbac553a3ad141db016e3350b03184deaafeba09b9d6439826ee594b365"}, - {file = "watchfiles-0.21.0-cp311-none-win32.whl", hash = "sha256:ebe684d7d26239e23d102a2bad2a358dedf18e462e8808778703427d1f584400"}, - {file = "watchfiles-0.21.0-cp311-none-win_amd64.whl", hash = "sha256:4566006aa44cb0d21b8ab53baf4b9c667a0ed23efe4aaad8c227bfba0bf15cbe"}, - {file = "watchfiles-0.21.0-cp311-none-win_arm64.whl", hash = "sha256:c550a56bf209a3d987d5a975cdf2063b3389a5d16caf29db4bdddeae49f22078"}, - {file = "watchfiles-0.21.0-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:51ddac60b96a42c15d24fbdc7a4bfcd02b5a29c047b7f8bf63d3f6f5a860949a"}, - {file = "watchfiles-0.21.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:511f0b034120cd1989932bf1e9081aa9fb00f1f949fbd2d9cab6264916ae89b1"}, - {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cfb92d49dbb95ec7a07511bc9efb0faff8fe24ef3805662b8d6808ba8409a71a"}, - {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f92944efc564867bbf841c823c8b71bb0be75e06b8ce45c084b46411475a915"}, - {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:642d66b75eda909fd1112d35c53816d59789a4b38c141a96d62f50a3ef9b3360"}, - {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d23bcd6c8eaa6324fe109d8cac01b41fe9a54b8c498af9ce464c1aeeb99903d6"}, - {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18d5b4da8cf3e41895b34e8c37d13c9ed294954907929aacd95153508d5d89d7"}, - {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b8d1eae0f65441963d805f766c7e9cd092f91e0c600c820c764a4ff71a0764c"}, - {file = "watchfiles-0.21.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1fd9a5205139f3c6bb60d11f6072e0552f0a20b712c85f43d42342d162be1235"}, - {file = "watchfiles-0.21.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a1e3014a625bcf107fbf38eece0e47fa0190e52e45dc6eee5a8265ddc6dc5ea7"}, - {file = "watchfiles-0.21.0-cp312-none-win32.whl", hash = "sha256:9d09869f2c5a6f2d9df50ce3064b3391d3ecb6dced708ad64467b9e4f2c9bef3"}, - {file = "watchfiles-0.21.0-cp312-none-win_amd64.whl", hash = "sha256:18722b50783b5e30a18a8a5db3006bab146d2b705c92eb9a94f78c72beb94094"}, - {file = "watchfiles-0.21.0-cp312-none-win_arm64.whl", hash = "sha256:a3b9bec9579a15fb3ca2d9878deae789df72f2b0fdaf90ad49ee389cad5edab6"}, - {file = "watchfiles-0.21.0-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:4ea10a29aa5de67de02256a28d1bf53d21322295cb00bd2d57fcd19b850ebd99"}, - {file = "watchfiles-0.21.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:40bca549fdc929b470dd1dbfcb47b3295cb46a6d2c90e50588b0a1b3bd98f429"}, - {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9b37a7ba223b2f26122c148bb8d09a9ff312afca998c48c725ff5a0a632145f7"}, - {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec8c8900dc5c83650a63dd48c4d1d245343f904c4b64b48798c67a3767d7e165"}, - {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8ad3fe0a3567c2f0f629d800409cd528cb6251da12e81a1f765e5c5345fd0137"}, - {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d353c4cfda586db2a176ce42c88f2fc31ec25e50212650c89fdd0f560ee507b"}, - {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:83a696da8922314ff2aec02987eefb03784f473281d740bf9170181829133765"}, - {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a03651352fc20975ee2a707cd2d74a386cd303cc688f407296064ad1e6d1562"}, - {file = "watchfiles-0.21.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3ad692bc7792be8c32918c699638b660c0de078a6cbe464c46e1340dadb94c19"}, - {file = "watchfiles-0.21.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06247538e8253975bdb328e7683f8515ff5ff041f43be6c40bff62d989b7d0b0"}, - {file = "watchfiles-0.21.0-cp38-none-win32.whl", hash = "sha256:9a0aa47f94ea9a0b39dd30850b0adf2e1cd32a8b4f9c7aa443d852aacf9ca214"}, - {file = "watchfiles-0.21.0-cp38-none-win_amd64.whl", hash = "sha256:8d5f400326840934e3507701f9f7269247f7c026d1b6cfd49477d2be0933cfca"}, - {file = "watchfiles-0.21.0-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:7f762a1a85a12cc3484f77eee7be87b10f8c50b0b787bb02f4e357403cad0c0e"}, - {file = "watchfiles-0.21.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6e9be3ef84e2bb9710f3f777accce25556f4a71e15d2b73223788d528fcc2052"}, - {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4c48a10d17571d1275701e14a601e36959ffada3add8cdbc9e5061a6e3579a5d"}, - {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c889025f59884423428c261f212e04d438de865beda0b1e1babab85ef4c0f01"}, - {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:66fac0c238ab9a2e72d026b5fb91cb902c146202bbd29a9a1a44e8db7b710b6f"}, - {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4a21f71885aa2744719459951819e7bf5a906a6448a6b2bbce8e9cc9f2c8128"}, - {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c9198c989f47898b2c22201756f73249de3748e0fc9de44adaf54a8b259cc0c"}, - {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8f57c4461cd24fda22493109c45b3980863c58a25b8bec885ca8bea6b8d4b28"}, - {file = "watchfiles-0.21.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:853853cbf7bf9408b404754b92512ebe3e3a83587503d766d23e6bf83d092ee6"}, - {file = "watchfiles-0.21.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d5b1dc0e708fad9f92c296ab2f948af403bf201db8fb2eb4c8179db143732e49"}, - {file = "watchfiles-0.21.0-cp39-none-win32.whl", hash = "sha256:59137c0c6826bd56c710d1d2bda81553b5e6b7c84d5a676747d80caf0409ad94"}, - {file = "watchfiles-0.21.0-cp39-none-win_amd64.whl", hash = "sha256:6cb8fdc044909e2078c248986f2fc76f911f72b51ea4a4fbbf472e01d14faa58"}, - {file = "watchfiles-0.21.0-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ab03a90b305d2588e8352168e8c5a1520b721d2d367f31e9332c4235b30b8994"}, - {file = "watchfiles-0.21.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:927c589500f9f41e370b0125c12ac9e7d3a2fd166b89e9ee2828b3dda20bfe6f"}, - {file = "watchfiles-0.21.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bd467213195e76f838caf2c28cd65e58302d0254e636e7c0fca81efa4a2e62c"}, - {file = "watchfiles-0.21.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02b73130687bc3f6bb79d8a170959042eb56eb3a42df3671c79b428cd73f17cc"}, - {file = "watchfiles-0.21.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:08dca260e85ffae975448e344834d765983237ad6dc308231aa16e7933db763e"}, - {file = "watchfiles-0.21.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:3ccceb50c611c433145502735e0370877cced72a6c70fd2410238bcbc7fe51d8"}, - {file = "watchfiles-0.21.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57d430f5fb63fea141ab71ca9c064e80de3a20b427ca2febcbfcef70ff0ce895"}, - {file = "watchfiles-0.21.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dd5fad9b9c0dd89904bbdea978ce89a2b692a7ee8a0ce19b940e538c88a809c"}, - {file = "watchfiles-0.21.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:be6dd5d52b73018b21adc1c5d28ac0c68184a64769052dfeb0c5d9998e7f56a2"}, - {file = "watchfiles-0.21.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b3cab0e06143768499384a8a5efb9c4dc53e19382952859e4802f294214f36ec"}, - {file = "watchfiles-0.21.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c6ed10c2497e5fedadf61e465b3ca12a19f96004c15dcffe4bd442ebadc2d85"}, - {file = "watchfiles-0.21.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43babacef21c519bc6631c5fce2a61eccdfc011b4bcb9047255e9620732c8097"}, - {file = "watchfiles-0.21.0.tar.gz", hash = "sha256:c76c635fabf542bb78524905718c39f736a98e5ab25b23ec6d4abede1a85a6a3"}, -] - -[package.dependencies] -anyio = ">=3.0.0" - -[[package]] -name = "websockets" -version = "12.0" -description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" -optional = false -python-versions = ">=3.8" -files = [ - {file = "websockets-12.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d554236b2a2006e0ce16315c16eaa0d628dab009c33b63ea03f41c6107958374"}, - {file = "websockets-12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2d225bb6886591b1746b17c0573e29804619c8f755b5598d875bb4235ea639be"}, - {file = "websockets-12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:eb809e816916a3b210bed3c82fb88eaf16e8afcf9c115ebb2bacede1797d2547"}, - {file = "websockets-12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c588f6abc13f78a67044c6b1273a99e1cf31038ad51815b3b016ce699f0d75c2"}, - {file = "websockets-12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5aa9348186d79a5f232115ed3fa9020eab66d6c3437d72f9d2c8ac0c6858c558"}, - {file = "websockets-12.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6350b14a40c95ddd53e775dbdbbbc59b124a5c8ecd6fbb09c2e52029f7a9f480"}, - {file = "websockets-12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:70ec754cc2a769bcd218ed8d7209055667b30860ffecb8633a834dde27d6307c"}, - {file = "websockets-12.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e96f5ed1b83a8ddb07909b45bd94833b0710f738115751cdaa9da1fb0cb66e8"}, - {file = "websockets-12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4d87be612cbef86f994178d5186add3d94e9f31cc3cb499a0482b866ec477603"}, - {file = "websockets-12.0-cp310-cp310-win32.whl", hash = "sha256:befe90632d66caaf72e8b2ed4d7f02b348913813c8b0a32fae1cc5fe3730902f"}, - {file = "websockets-12.0-cp310-cp310-win_amd64.whl", hash = "sha256:363f57ca8bc8576195d0540c648aa58ac18cf85b76ad5202b9f976918f4219cf"}, - {file = "websockets-12.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5d873c7de42dea355d73f170be0f23788cf3fa9f7bed718fd2830eefedce01b4"}, - {file = "websockets-12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3f61726cae9f65b872502ff3c1496abc93ffbe31b278455c418492016e2afc8f"}, - {file = "websockets-12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed2fcf7a07334c77fc8a230755c2209223a7cc44fc27597729b8ef5425aa61a3"}, - {file = "websockets-12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e332c210b14b57904869ca9f9bf4ca32f5427a03eeb625da9b616c85a3a506c"}, - {file = "websockets-12.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5693ef74233122f8ebab026817b1b37fe25c411ecfca084b29bc7d6efc548f45"}, - {file = "websockets-12.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e9e7db18b4539a29cc5ad8c8b252738a30e2b13f033c2d6e9d0549b45841c04"}, - {file = "websockets-12.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6e2df67b8014767d0f785baa98393725739287684b9f8d8a1001eb2839031447"}, - {file = "websockets-12.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bea88d71630c5900690fcb03161ab18f8f244805c59e2e0dc4ffadae0a7ee0ca"}, - {file = "websockets-12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dff6cdf35e31d1315790149fee351f9e52978130cef6c87c4b6c9b3baf78bc53"}, - {file = "websockets-12.0-cp311-cp311-win32.whl", hash = "sha256:3e3aa8c468af01d70332a382350ee95f6986db479ce7af14d5e81ec52aa2b402"}, - {file = "websockets-12.0-cp311-cp311-win_amd64.whl", hash = "sha256:25eb766c8ad27da0f79420b2af4b85d29914ba0edf69f547cc4f06ca6f1d403b"}, - {file = "websockets-12.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0e6e2711d5a8e6e482cacb927a49a3d432345dfe7dea8ace7b5790df5932e4df"}, - {file = "websockets-12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:dbcf72a37f0b3316e993e13ecf32f10c0e1259c28ffd0a85cee26e8549595fbc"}, - {file = "websockets-12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12743ab88ab2af1d17dd4acb4645677cb7063ef4db93abffbf164218a5d54c6b"}, - {file = "websockets-12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b645f491f3c48d3f8a00d1fce07445fab7347fec54a3e65f0725d730d5b99cb"}, - {file = "websockets-12.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9893d1aa45a7f8b3bc4510f6ccf8db8c3b62120917af15e3de247f0780294b92"}, - {file = "websockets-12.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f38a7b376117ef7aff996e737583172bdf535932c9ca021746573bce40165ed"}, - {file = "websockets-12.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f764ba54e33daf20e167915edc443b6f88956f37fb606449b4a5b10ba42235a5"}, - {file = "websockets-12.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1e4b3f8ea6a9cfa8be8484c9221ec0257508e3a1ec43c36acdefb2a9c3b00aa2"}, - {file = "websockets-12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9fdf06fd06c32205a07e47328ab49c40fc1407cdec801d698a7c41167ea45113"}, - {file = "websockets-12.0-cp312-cp312-win32.whl", hash = "sha256:baa386875b70cbd81798fa9f71be689c1bf484f65fd6fb08d051a0ee4e79924d"}, - {file = "websockets-12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae0a5da8f35a5be197f328d4727dbcfafa53d1824fac3d96cdd3a642fe09394f"}, - {file = "websockets-12.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5f6ffe2c6598f7f7207eef9a1228b6f5c818f9f4d53ee920aacd35cec8110438"}, - {file = "websockets-12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9edf3fc590cc2ec20dc9d7a45108b5bbaf21c0d89f9fd3fd1685e223771dc0b2"}, - {file = "websockets-12.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8572132c7be52632201a35f5e08348137f658e5ffd21f51f94572ca6c05ea81d"}, - {file = "websockets-12.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:604428d1b87edbf02b233e2c207d7d528460fa978f9e391bd8aaf9c8311de137"}, - {file = "websockets-12.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1a9d160fd080c6285e202327aba140fc9a0d910b09e423afff4ae5cbbf1c7205"}, - {file = "websockets-12.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87b4aafed34653e465eb77b7c93ef058516cb5acf3eb21e42f33928616172def"}, - {file = "websockets-12.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b2ee7288b85959797970114deae81ab41b731f19ebcd3bd499ae9ca0e3f1d2c8"}, - {file = "websockets-12.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7fa3d25e81bfe6a89718e9791128398a50dec6d57faf23770787ff441d851967"}, - {file = "websockets-12.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a571f035a47212288e3b3519944f6bf4ac7bc7553243e41eac50dd48552b6df7"}, - {file = "websockets-12.0-cp38-cp38-win32.whl", hash = "sha256:3c6cc1360c10c17463aadd29dd3af332d4a1adaa8796f6b0e9f9df1fdb0bad62"}, - {file = "websockets-12.0-cp38-cp38-win_amd64.whl", hash = "sha256:1bf386089178ea69d720f8db6199a0504a406209a0fc23e603b27b300fdd6892"}, - {file = "websockets-12.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ab3d732ad50a4fbd04a4490ef08acd0517b6ae6b77eb967251f4c263011a990d"}, - {file = "websockets-12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a1d9697f3337a89691e3bd8dc56dea45a6f6d975f92e7d5f773bc715c15dde28"}, - {file = "websockets-12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1df2fbd2c8a98d38a66f5238484405b8d1d16f929bb7a33ed73e4801222a6f53"}, - {file = "websockets-12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23509452b3bc38e3a057382c2e941d5ac2e01e251acce7adc74011d7d8de434c"}, - {file = "websockets-12.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e5fc14ec6ea568200ea4ef46545073da81900a2b67b3e666f04adf53ad452ec"}, - {file = "websockets-12.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46e71dbbd12850224243f5d2aeec90f0aaa0f2dde5aeeb8fc8df21e04d99eff9"}, - {file = "websockets-12.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b81f90dcc6c85a9b7f29873beb56c94c85d6f0dac2ea8b60d995bd18bf3e2aae"}, - {file = "websockets-12.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a02413bc474feda2849c59ed2dfb2cddb4cd3d2f03a2fedec51d6e959d9b608b"}, - {file = "websockets-12.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bbe6013f9f791944ed31ca08b077e26249309639313fff132bfbf3ba105673b9"}, - {file = "websockets-12.0-cp39-cp39-win32.whl", hash = "sha256:cbe83a6bbdf207ff0541de01e11904827540aa069293696dd528a6640bd6a5f6"}, - {file = "websockets-12.0-cp39-cp39-win_amd64.whl", hash = "sha256:fc4e7fa5414512b481a2483775a8e8be7803a35b30ca805afa4998a84f9fd9e8"}, - {file = "websockets-12.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:248d8e2446e13c1d4326e0a6a4e9629cb13a11195051a73acf414812700badbd"}, - {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f44069528d45a933997a6fef143030d8ca8042f0dfaad753e2906398290e2870"}, - {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c4e37d36f0d19f0a4413d3e18c0d03d0c268ada2061868c1e6f5ab1a6d575077"}, - {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d829f975fc2e527a3ef2f9c8f25e553eb7bc779c6665e8e1d52aa22800bb38b"}, - {file = "websockets-12.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2c71bd45a777433dd9113847af751aae36e448bc6b8c361a566cb043eda6ec30"}, - {file = "websockets-12.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0bee75f400895aef54157b36ed6d3b308fcab62e5260703add87f44cee9c82a6"}, - {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:423fc1ed29f7512fceb727e2d2aecb952c46aa34895e9ed96071821309951123"}, - {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27a5e9964ef509016759f2ef3f2c1e13f403725a5e6a1775555994966a66e931"}, - {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3181df4583c4d3994d31fb235dc681d2aaad744fbdbf94c4802485ececdecf2"}, - {file = "websockets-12.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b067cb952ce8bf40115f6c19f478dc71c5e719b7fbaa511359795dfd9d1a6468"}, - {file = "websockets-12.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:00700340c6c7ab788f176d118775202aadea7602c5cc6be6ae127761c16d6b0b"}, - {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e469d01137942849cff40517c97a30a93ae79917752b34029f0ec72df6b46399"}, - {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffefa1374cd508d633646d51a8e9277763a9b78ae71324183693959cf94635a7"}, - {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba0cab91b3956dfa9f512147860783a1829a8d905ee218a9837c18f683239611"}, - {file = "websockets-12.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2cb388a5bfb56df4d9a406783b7f9dbefb888c09b71629351cc6b036e9259370"}, - {file = "websockets-12.0-py3-none-any.whl", hash = "sha256:dc284bbc8d7c78a6c69e0c7325ab46ee5e40bb4d50e494d8131a07ef47500e9e"}, - {file = "websockets-12.0.tar.gz", hash = "sha256:81df9cbcbb6c260de1e007e58c011bfebe2dafc8435107b0537f393dd38c8b1b"}, -] - [[package]] name = "wheel" version = "0.38.4" @@ -3943,20 +3266,6 @@ files = [ {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, ] -[[package]] -name = "wsproto" -version = "1.2.0" -description = "WebSockets state-machine based protocol implementation" -optional = false -python-versions = ">=3.7.0" -files = [ - {file = "wsproto-1.2.0-py3-none-any.whl", hash = "sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736"}, - {file = "wsproto-1.2.0.tar.gz", hash = "sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065"}, -] - -[package.dependencies] -h11 = ">=0.9.0,<1" - [[package]] name = "yarl" version = "1.9.4" @@ -4078,4 +3387,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "d8a09e801ec8d36fbc604eea61ebd079532d2952959ec671b1c9857a66f85de2" +content-hash = "df94a5200f0f8d5f60aebdad98a6170f2f238838a9261d1b8d604a668593d804" diff --git a/pyproject.toml b/pyproject.toml index d2f6c06c..3b0fe90a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ django = "^5.0.1" pyyaml = "^6.0.1" gunicorn = "^21.2.0" whitenoise = "^6.6.0" -ministryofjustice-data-platform-catalogue = "^0.7.0" +ministryofjustice-data-platform-catalogue = "^0.8.1" markdown = "^3.5.2" python-dotenv = "^1.0.1" From 263a7a38b1d0f1226a9dd5e78df55cc725ad0c64 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 30 Jan 2024 14:35:40 +0000 Subject: [PATCH 038/221] Commit changes made by code formatters --- home/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/home/views.py b/home/views.py index 45f1ff8e..5bec41c2 100644 --- a/home/views.py +++ b/home/views.py @@ -80,7 +80,8 @@ def search_view(request): context["selected_domain"] = {} # Search with filter - search_results = client.search(query=query, page=page, filters=filter_value) + search_results = client.search( + query=query, page=page, filters=filter_value) context["query"] = query context["results"] = search_results.page_results context["total_results"] = search_results.total_results From 286e31899b6bc0853009e369384ebd06ce239642 Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Wed, 31 Jan 2024 10:01:19 +0000 Subject: [PATCH 039/221] Add page titles, defaulting to "Data catalogue" --- home/views.py | 13 +++++++++---- templates/base/head.html | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/home/views.py b/home/views.py index 5bec41c2..8d61d5cd 100644 --- a/home/views.py +++ b/home/views.py @@ -13,12 +13,13 @@ def home_view(request): def details_view(request, id): - context = {} client = get_catalogue_client() filter_value = [MultiSelectFilter("urn", id)] search_results = client.search(query="", page=None, filters=filter_value) - context["result"] = search_results.page_results[0] + result = search_results.page_results[0] + context["result"] = result + context["page_title"] = f"Data catalogue - {result.name}" return render(request, "details.html", context) @@ -80,10 +81,14 @@ def search_view(request): context["selected_domain"] = {} # Search with filter - search_results = client.search( - query=query, page=page, filters=filter_value) + search_results = client.search(query=query, page=page, filters=filter_value) context["query"] = query context["results"] = search_results.page_results context["total_results"] = search_results.total_results + if query: + context["page_title"] = f'Data catalogue - Search for "{query}"' + else: + context["page_title"] = f"Data catalogue - Search" + return render(request, "search.html", context) diff --git a/templates/base/head.html b/templates/base/head.html index 94d85c4f..452857ef 100644 --- a/templates/base/head.html +++ b/templates/base/head.html @@ -1,7 +1,7 @@ {% load static %} - GOV.UK - Customised page template + {{page_title|default:"Data catalogue"}} From 95584e3c1201b10ba06e5542d2739f62cd81ece5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 31 Jan 2024 10:02:30 +0000 Subject: [PATCH 040/221] Commit changes made by code formatters --- home/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/home/views.py b/home/views.py index 8d61d5cd..c7d9f1cd 100644 --- a/home/views.py +++ b/home/views.py @@ -81,7 +81,8 @@ def search_view(request): context["selected_domain"] = {} # Search with filter - search_results = client.search(query=query, page=page, filters=filter_value) + search_results = client.search( + query=query, page=page, filters=filter_value) context["query"] = query context["results"] = search_results.page_results context["total_results"] = search_results.total_results From 8260fbbd2d3b9cce54e88a1f8173e9cd23671a85 Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Wed, 31 Jan 2024 10:04:48 +0000 Subject: [PATCH 041/221] Reverse polarity --- home/views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/home/views.py b/home/views.py index c7d9f1cd..ae82dd38 100644 --- a/home/views.py +++ b/home/views.py @@ -19,7 +19,7 @@ def details_view(request, id): search_results = client.search(query="", page=None, filters=filter_value) result = search_results.page_results[0] context["result"] = result - context["page_title"] = f"Data catalogue - {result.name}" + context["page_title"] = f"{result.name} - Data catalogue" return render(request, "details.html", context) @@ -88,8 +88,8 @@ def search_view(request): context["total_results"] = search_results.total_results if query: - context["page_title"] = f'Data catalogue - Search for "{query}"' + context["page_title"] = f'Search for "{query}" - Data catalogue' else: - context["page_title"] = f"Data catalogue - Search" + context["page_title"] = f"Search - Data catalogue" return render(request, "search.html", context) From a6de0f6fd1f614df270da4144846646156d20be9 Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Wed, 31 Jan 2024 13:46:08 +0000 Subject: [PATCH 042/221] Remove CSRF token from search form The CSRF tag adds a random token[1] that ensures that forms cannot be submitted directly without the user visiting the app first. This is important when taking destructive actions or submitting data. In the case of search we want the opposite though: users should be able to bookmark searches and share working links. CSRF tokens should therefore not be added to the query parameters. [1]. https://docs.djangoproject.com/en/5.0/ref/csrf/ --- templates/search.html | 1 - 1 file changed, 1 deletion(-) diff --git a/templates/search.html b/templates/search.html index 371d3356..ed798ecf 100644 --- a/templates/search.html +++ b/templates/search.html @@ -9,7 +9,6 @@
- {% csrf_token %}

Find MOJ Data

From fb0d7336ca43c5ea3b35acb289a8d1e3c8d8f865 Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Wed, 31 Jan 2024 13:58:09 +0000 Subject: [PATCH 043/221] Make navigation respond to the current page --- templates/base/navigation.html | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/templates/base/navigation.html b/templates/base/navigation.html index f0953107..0cc64bcc 100644 --- a/templates/base/navigation.html +++ b/templates/base/navigation.html @@ -23,12 +23,14 @@
-
- +
@@ -53,7 +52,6 @@

Domain

-
From 090cd3b69425ea6d3115a953fd51872b64763771 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 1 Feb 2024 15:28:18 +0000 Subject: [PATCH 065/221] Commit changes made by code formatters --- home/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/home/views.py b/home/views.py index 0f0fc055..7936ba66 100644 --- a/home/views.py +++ b/home/views.py @@ -99,7 +99,8 @@ def search_view(request, page: str = "1"): else: domains = request.session.get("domains", []) filter_value = [] - context["selected_domain"] = filter_seleted_domains(domain_list, domains) + context["selected_domain"] = filter_seleted_domains( + domain_list, domains) context["domains"] = domains query = request.session.get("query", "") From 9925b04043149cc3374ec974697d61cc29a66fe1 Mon Sep 17 00:00:00 2001 From: Murdo Moyse Date: Thu, 1 Feb 2024 16:28:37 +0000 Subject: [PATCH 066/221] Added sort radio --- home/views.py | 15 +++++++++++++-- templates/search.html | 40 ++++++++++++++++++++++++++++------------ 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/home/views.py b/home/views.py index 7936ba66..63364042 100644 --- a/home/views.py +++ b/home/views.py @@ -1,4 +1,6 @@ -from data_platform_catalogue.search_types import MultiSelectFilter, ResultType +from data_platform_catalogue.search_types import( + MultiSelectFilter, ResultType, SortOption +) from django.conf import settings from django.shortcuts import render @@ -42,6 +44,14 @@ def search_view(request, page: str = "1"): context["domainlist"] = domain_list domains = request.GET.getlist("domain", []) + sortby = request.GET.get("sortby", None) + + if sortby=="ascending": + sort = SortOption(field="name", ascending=True) + elif sortby=="descending": + sort = SortOption(field="name", ascending=False) + else: + sort = None if domains: selected_domain = filter_seleted_domains(domain_list, domains) context["selected_domain"] = selected_domain @@ -106,7 +116,7 @@ def search_view(request, page: str = "1"): # Search with filter search_results = client.search( - query=query, page=page_for_search, filters=filter_value + query=query, page=page_for_search, filters=filter_value, sort=sort ) items_per_page = 20 @@ -121,6 +131,7 @@ def search_view(request, page: str = "1"): page, on_each_side=2, on_ends=1 ) context["paginator"] = paginator + context["sortby"] = sortby if query: context["page_title"] = f'Search for "{query}" - Data catalogue' diff --git a/templates/search.html b/templates/search.html index d7b20394..8173550e 100644 --- a/templates/search.html +++ b/templates/search.html @@ -22,19 +22,35 @@

Find MOJ Data

{% include "partial/filter.html" %} -
+

{{total_results|intcomma}} Results

-
- - -
+
+
+ + Sort results + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
{% include "partial/search_result.html" %} {% include "partial/pagination.html" %}
From 5ad45e0ca12f1c117a188b88cb736f28a5bc3583 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 1 Feb 2024 16:30:10 +0000 Subject: [PATCH 067/221] Commit changes made by code formatters --- home/views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/home/views.py b/home/views.py index 63364042..5c5a4900 100644 --- a/home/views.py +++ b/home/views.py @@ -1,4 +1,4 @@ -from data_platform_catalogue.search_types import( +from data_platform_catalogue.search_types import ( MultiSelectFilter, ResultType, SortOption ) from django.conf import settings @@ -46,9 +46,9 @@ def search_view(request, page: str = "1"): domains = request.GET.getlist("domain", []) sortby = request.GET.get("sortby", None) - if sortby=="ascending": + if sortby == "ascending": sort = SortOption(field="name", ascending=True) - elif sortby=="descending": + elif sortby == "descending": sort = SortOption(field="name", ascending=False) else: sort = None From f9e75ece0b021235834a37f3ad5931c3e42cf88f Mon Sep 17 00:00:00 2001 From: "priya.basker" Date: Fri, 2 Feb 2024 14:24:53 +0000 Subject: [PATCH 068/221] pagination and search fixed --- home/helper.py | 5 + home/urls.py | 2 +- home/views.py | 22 +- poetry.lock | 694 +++++++++++++++--------------- pyproject.toml | 2 +- templates/base/navigation.html | 2 +- templates/partial/pagination.html | 2 +- 7 files changed, 378 insertions(+), 351 deletions(-) diff --git a/home/helper.py b/home/helper.py index 181d2eb6..cb119111 100644 --- a/home/helper.py +++ b/home/helper.py @@ -4,3 +4,8 @@ def filter_seleted_domains(domain_list, domains): if domain.value in domains: selected_domain[domain.value] = domain.label return selected_domain + +def get_domain_list(client): + facets = client.search_facets() + domain_list = facets.options("domains") + return domain_list diff --git a/home/urls.py b/home/urls.py index 71eb1be1..d508c4f4 100644 --- a/home/urls.py +++ b/home/urls.py @@ -7,5 +7,5 @@ path("", views.home_view, name="home"), path("search", views.search_view, name="search"), path("details//", views.details_view, name="details"), - path("pagination//", views.search_view, name="pagination"), + path("pagination/", views.search_view, name="pagination"), ] diff --git a/home/views.py b/home/views.py index 5c5a4900..8da1e71e 100644 --- a/home/views.py +++ b/home/views.py @@ -4,7 +4,7 @@ from django.conf import settings from django.shortcuts import render -from .helper import filter_seleted_domains +from .helper import filter_seleted_domains, get_domain_list from django.core.paginator import Paginator from .services import get_catalogue_client @@ -31,20 +31,19 @@ def details_view(request, id): def search_view(request, page: str = "1"): - query = request.GET.get("query", "") + + new_search = request.GET.get("new", "") page_for_search = str(int(page) - 1) client = get_catalogue_client() + domain_list = get_domain_list(client) - facets = client.search_facets() context = {} - - domain_list = facets.options("domains") - context["domainlist"] = domain_list domains = request.GET.getlist("domain", []) sortby = request.GET.get("sortby", None) + context["sortby"]=sortby if sortby == "ascending": sort = SortOption(field="name", ascending=True) @@ -52,6 +51,7 @@ def search_view(request, page: str = "1"): sort = SortOption(field="name", ascending=False) else: sort = None + if domains: selected_domain = filter_seleted_domains(domain_list, domains) context["selected_domain"] = selected_domain @@ -88,8 +88,11 @@ def search_view(request, page: str = "1"): filter_value = [MultiSelectFilter("domains", domains)] elif request.GET.get("query"): + query=request.GET.get("query") + print("query", query) domains = request.session.get("domains", None) request.session["query"] = query + context["query"] = query domains = request.session.get("domains", []) # Preserve filter @@ -101,11 +104,13 @@ def search_view(request, page: str = "1"): context["domains"] = domains filter_value = [MultiSelectFilter("domains", domains)] else: - if page is None: + if page=="1" and new_search: filter_value = [] - context["selected_domain"] = {} + request.session.clear() request.session["domains"] = domains + context["selected_domain"] = {} + context["query"]="" else: domains = request.session.get("domains", []) filter_value = [] @@ -115,6 +120,7 @@ def search_view(request, page: str = "1"): query = request.session.get("query", "") # Search with filter + query = request.GET.get("query", "") search_results = client.search( query=query, page=page_for_search, filters=filter_value, sort=sort ) diff --git a/poetry.lock b/poetry.lock index 81518792..8caca685 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "acryl-datahub" @@ -123,87 +123,87 @@ vertica = ["Deprecated", "PyYAML", "acryl-sqlglot (==20.4.1.dev14)", "aiohttp (< [[package]] name = "aiohttp" -version = "3.9.1" +version = "3.9.3" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.8" files = [ - {file = "aiohttp-3.9.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e1f80197f8b0b846a8d5cf7b7ec6084493950d0882cc5537fb7b96a69e3c8590"}, - {file = "aiohttp-3.9.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c72444d17777865734aa1a4d167794c34b63e5883abb90356a0364a28904e6c0"}, - {file = "aiohttp-3.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9b05d5cbe9dafcdc733262c3a99ccf63d2f7ce02543620d2bd8db4d4f7a22f83"}, - {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c4fa235d534b3547184831c624c0b7c1e262cd1de847d95085ec94c16fddcd5"}, - {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:289ba9ae8e88d0ba16062ecf02dd730b34186ea3b1e7489046fc338bdc3361c4"}, - {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bff7e2811814fa2271be95ab6e84c9436d027a0e59665de60edf44e529a42c1f"}, - {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81b77f868814346662c96ab36b875d7814ebf82340d3284a31681085c051320f"}, - {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b9c7426923bb7bd66d409da46c41e3fb40f5caf679da624439b9eba92043fa6"}, - {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8d44e7bf06b0c0a70a20f9100af9fcfd7f6d9d3913e37754c12d424179b4e48f"}, - {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:22698f01ff5653fe66d16ffb7658f582a0ac084d7da1323e39fd9eab326a1f26"}, - {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ca7ca5abfbfe8d39e653870fbe8d7710be7a857f8a8386fc9de1aae2e02ce7e4"}, - {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:8d7f98fde213f74561be1d6d3fa353656197f75d4edfbb3d94c9eb9b0fc47f5d"}, - {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5216b6082c624b55cfe79af5d538e499cd5f5b976820eac31951fb4325974501"}, - {file = "aiohttp-3.9.1-cp310-cp310-win32.whl", hash = "sha256:0e7ba7ff228c0d9a2cd66194e90f2bca6e0abca810b786901a569c0de082f489"}, - {file = "aiohttp-3.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:c7e939f1ae428a86e4abbb9a7c4732bf4706048818dfd979e5e2839ce0159f23"}, - {file = "aiohttp-3.9.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:df9cf74b9bc03d586fc53ba470828d7b77ce51b0582d1d0b5b2fb673c0baa32d"}, - {file = "aiohttp-3.9.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ecca113f19d5e74048c001934045a2b9368d77b0b17691d905af18bd1c21275e"}, - {file = "aiohttp-3.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8cef8710fb849d97c533f259103f09bac167a008d7131d7b2b0e3a33269185c0"}, - {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bea94403a21eb94c93386d559bce297381609153e418a3ffc7d6bf772f59cc35"}, - {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91c742ca59045dce7ba76cab6e223e41d2c70d79e82c284a96411f8645e2afff"}, - {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6c93b7c2e52061f0925c3382d5cb8980e40f91c989563d3d32ca280069fd6a87"}, - {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee2527134f95e106cc1653e9ac78846f3a2ec1004cf20ef4e02038035a74544d"}, - {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11ff168d752cb41e8492817e10fb4f85828f6a0142b9726a30c27c35a1835f01"}, - {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b8c3a67eb87394386847d188996920f33b01b32155f0a94f36ca0e0c635bf3e3"}, - {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c7b5d5d64e2a14e35a9240b33b89389e0035e6de8dbb7ffa50d10d8b65c57449"}, - {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:69985d50a2b6f709412d944ffb2e97d0be154ea90600b7a921f95a87d6f108a2"}, - {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:c9110c06eaaac7e1f5562caf481f18ccf8f6fdf4c3323feab28a93d34cc646bd"}, - {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d737e69d193dac7296365a6dcb73bbbf53bb760ab25a3727716bbd42022e8d7a"}, - {file = "aiohttp-3.9.1-cp311-cp311-win32.whl", hash = "sha256:4ee8caa925aebc1e64e98432d78ea8de67b2272252b0a931d2ac3bd876ad5544"}, - {file = "aiohttp-3.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:a34086c5cc285be878622e0a6ab897a986a6e8bf5b67ecb377015f06ed316587"}, - {file = "aiohttp-3.9.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f800164276eec54e0af5c99feb9494c295118fc10a11b997bbb1348ba1a52065"}, - {file = "aiohttp-3.9.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:500f1c59906cd142d452074f3811614be04819a38ae2b3239a48b82649c08821"}, - {file = "aiohttp-3.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0b0a6a36ed7e164c6df1e18ee47afbd1990ce47cb428739d6c99aaabfaf1b3af"}, - {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69da0f3ed3496808e8cbc5123a866c41c12c15baaaead96d256477edf168eb57"}, - {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:176df045597e674fa950bf5ae536be85699e04cea68fa3a616cf75e413737eb5"}, - {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b796b44111f0cab6bbf66214186e44734b5baab949cb5fb56154142a92989aeb"}, - {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f27fdaadce22f2ef950fc10dcdf8048407c3b42b73779e48a4e76b3c35bca26c"}, - {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcb6532b9814ea7c5a6a3299747c49de30e84472fa72821b07f5a9818bce0f66"}, - {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:54631fb69a6e44b2ba522f7c22a6fb2667a02fd97d636048478db2fd8c4e98fe"}, - {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:4b4c452d0190c5a820d3f5c0f3cd8a28ace48c54053e24da9d6041bf81113183"}, - {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:cae4c0c2ca800c793cae07ef3d40794625471040a87e1ba392039639ad61ab5b"}, - {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:565760d6812b8d78d416c3c7cfdf5362fbe0d0d25b82fed75d0d29e18d7fc30f"}, - {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:54311eb54f3a0c45efb9ed0d0a8f43d1bc6060d773f6973efd90037a51cd0a3f"}, - {file = "aiohttp-3.9.1-cp312-cp312-win32.whl", hash = "sha256:85c3e3c9cb1d480e0b9a64c658cd66b3cfb8e721636ab8b0e746e2d79a7a9eed"}, - {file = "aiohttp-3.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:11cb254e397a82efb1805d12561e80124928e04e9c4483587ce7390b3866d213"}, - {file = "aiohttp-3.9.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8a22a34bc594d9d24621091d1b91511001a7eea91d6652ea495ce06e27381f70"}, - {file = "aiohttp-3.9.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:598db66eaf2e04aa0c8900a63b0101fdc5e6b8a7ddd805c56d86efb54eb66672"}, - {file = "aiohttp-3.9.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2c9376e2b09895c8ca8b95362283365eb5c03bdc8428ade80a864160605715f1"}, - {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41473de252e1797c2d2293804e389a6d6986ef37cbb4a25208de537ae32141dd"}, - {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c5857612c9813796960c00767645cb5da815af16dafb32d70c72a8390bbf690"}, - {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ffcd828e37dc219a72c9012ec44ad2e7e3066bec6ff3aaa19e7d435dbf4032ca"}, - {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:219a16763dc0294842188ac8a12262b5671817042b35d45e44fd0a697d8c8361"}, - {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f694dc8a6a3112059258a725a4ebe9acac5fe62f11c77ac4dcf896edfa78ca28"}, - {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bcc0ea8d5b74a41b621ad4a13d96c36079c81628ccc0b30cfb1603e3dfa3a014"}, - {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:90ec72d231169b4b8d6085be13023ece8fa9b1bb495e4398d847e25218e0f431"}, - {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:cf2a0ac0615842b849f40c4d7f304986a242f1e68286dbf3bd7a835e4f83acfd"}, - {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:0e49b08eafa4f5707ecfb321ab9592717a319e37938e301d462f79b4e860c32a"}, - {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2c59e0076ea31c08553e868cec02d22191c086f00b44610f8ab7363a11a5d9d8"}, - {file = "aiohttp-3.9.1-cp38-cp38-win32.whl", hash = "sha256:4831df72b053b1eed31eb00a2e1aff6896fb4485301d4ccb208cac264b648db4"}, - {file = "aiohttp-3.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:3135713c5562731ee18f58d3ad1bf41e1d8883eb68b363f2ffde5b2ea4b84cc7"}, - {file = "aiohttp-3.9.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cfeadf42840c1e870dc2042a232a8748e75a36b52d78968cda6736de55582766"}, - {file = "aiohttp-3.9.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:70907533db712f7aa791effb38efa96f044ce3d4e850e2d7691abd759f4f0ae0"}, - {file = "aiohttp-3.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cdefe289681507187e375a5064c7599f52c40343a8701761c802c1853a504558"}, - {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7481f581251bb5558ba9f635db70908819caa221fc79ee52a7f58392778c636"}, - {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:49f0c1b3c2842556e5de35f122fc0f0b721334ceb6e78c3719693364d4af8499"}, - {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0d406b01a9f5a7e232d1b0d161b40c05275ffbcbd772dc18c1d5a570961a1ca4"}, - {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d8e4450e7fe24d86e86b23cc209e0023177b6d59502e33807b732d2deb6975f"}, - {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c0266cd6f005e99f3f51e583012de2778e65af6b73860038b968a0a8888487a"}, - {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab221850108a4a063c5b8a70f00dd7a1975e5a1713f87f4ab26a46e5feac5a0e"}, - {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c88a15f272a0ad3d7773cf3a37cc7b7d077cbfc8e331675cf1346e849d97a4e5"}, - {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:237533179d9747080bcaad4d02083ce295c0d2eab3e9e8ce103411a4312991a0"}, - {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:02ab6006ec3c3463b528374c4cdce86434e7b89ad355e7bf29e2f16b46c7dd6f"}, - {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04fa38875e53eb7e354ece1607b1d2fdee2d175ea4e4d745f6ec9f751fe20c7c"}, - {file = "aiohttp-3.9.1-cp39-cp39-win32.whl", hash = "sha256:82eefaf1a996060602f3cc1112d93ba8b201dbf5d8fd9611227de2003dddb3b7"}, - {file = "aiohttp-3.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:9b05d33ff8e6b269e30a7957bd3244ffbce2a7a35a81b81c382629b80af1a8bf"}, - {file = "aiohttp-3.9.1.tar.gz", hash = "sha256:8fc49a87ac269d4529da45871e2ffb6874e87779c3d0e2ccd813c0899221239d"}, + {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:939677b61f9d72a4fa2a042a5eee2a99a24001a67c13da113b2e30396567db54"}, + {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1f5cd333fcf7590a18334c90f8c9147c837a6ec8a178e88d90a9b96ea03194cc"}, + {file = "aiohttp-3.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:82e6aa28dd46374f72093eda8bcd142f7771ee1eb9d1e223ff0fa7177a96b4a5"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f56455b0c2c7cc3b0c584815264461d07b177f903a04481dfc33e08a89f0c26b"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bca77a198bb6e69795ef2f09a5f4c12758487f83f33d63acde5f0d4919815768"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e083c285857b78ee21a96ba1eb1b5339733c3563f72980728ca2b08b53826ca5"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab40e6251c3873d86ea9b30a1ac6d7478c09277b32e14745d0d3c6e76e3c7e29"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df822ee7feaaeffb99c1a9e5e608800bd8eda6e5f18f5cfb0dc7eeb2eaa6bbec"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:acef0899fea7492145d2bbaaaec7b345c87753168589cc7faf0afec9afe9b747"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cd73265a9e5ea618014802ab01babf1940cecb90c9762d8b9e7d2cc1e1969ec6"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a78ed8a53a1221393d9637c01870248a6f4ea5b214a59a92a36f18151739452c"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:6b0e029353361f1746bac2e4cc19b32f972ec03f0f943b390c4ab3371840aabf"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7cf5c9458e1e90e3c390c2639f1017a0379a99a94fdfad3a1fd966a2874bba52"}, + {file = "aiohttp-3.9.3-cp310-cp310-win32.whl", hash = "sha256:3e59c23c52765951b69ec45ddbbc9403a8761ee6f57253250c6e1536cacc758b"}, + {file = "aiohttp-3.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:055ce4f74b82551678291473f66dc9fb9048a50d8324278751926ff0ae7715e5"}, + {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6b88f9386ff1ad91ace19d2a1c0225896e28815ee09fc6a8932fded8cda97c3d"}, + {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c46956ed82961e31557b6857a5ca153c67e5476972e5f7190015018760938da2"}, + {file = "aiohttp-3.9.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:07b837ef0d2f252f96009e9b8435ec1fef68ef8b1461933253d318748ec1acdc"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad46e6f620574b3b4801c68255492e0159d1712271cc99d8bdf35f2043ec266"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ed3e046ea7b14938112ccd53d91c1539af3e6679b222f9469981e3dac7ba1ce"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:039df344b45ae0b34ac885ab5b53940b174530d4dd8a14ed8b0e2155b9dddccb"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7943c414d3a8d9235f5f15c22ace69787c140c80b718dcd57caaade95f7cd93b"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84871a243359bb42c12728f04d181a389718710129b36b6aad0fc4655a7647d4"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5eafe2c065df5401ba06821b9a054d9cb2848867f3c59801b5d07a0be3a380ae"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9d3c9b50f19704552f23b4eaea1fc082fdd82c63429a6506446cbd8737823da3"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:f033d80bc6283092613882dfe40419c6a6a1527e04fc69350e87a9df02bbc283"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:2c895a656dd7e061b2fd6bb77d971cc38f2afc277229ce7dd3552de8313a483e"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1f5a71d25cd8106eab05f8704cd9167b6e5187bcdf8f090a66c6d88b634802b4"}, + {file = "aiohttp-3.9.3-cp311-cp311-win32.whl", hash = "sha256:50fca156d718f8ced687a373f9e140c1bb765ca16e3d6f4fe116e3df7c05b2c5"}, + {file = "aiohttp-3.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:5fe9ce6c09668063b8447f85d43b8d1c4e5d3d7e92c63173e6180b2ac5d46dd8"}, + {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:38a19bc3b686ad55804ae931012f78f7a534cce165d089a2059f658f6c91fa60"}, + {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:770d015888c2a598b377bd2f663adfd947d78c0124cfe7b959e1ef39f5b13869"}, + {file = "aiohttp-3.9.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee43080e75fc92bf36219926c8e6de497f9b247301bbf88c5c7593d931426679"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52df73f14ed99cee84865b95a3d9e044f226320a87af208f068ecc33e0c35b96"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc9b311743a78043b26ffaeeb9715dc360335e5517832f5a8e339f8a43581e4d"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b955ed993491f1a5da7f92e98d5dad3c1e14dc175f74517c4e610b1f2456fb11"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:504b6981675ace64c28bf4a05a508af5cde526e36492c98916127f5a02354d53"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a6fe5571784af92b6bc2fda8d1925cccdf24642d49546d3144948a6a1ed58ca5"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ba39e9c8627edc56544c8628cc180d88605df3892beeb2b94c9bc857774848ca"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e5e46b578c0e9db71d04c4b506a2121c0cb371dd89af17a0586ff6769d4c58c1"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:938a9653e1e0c592053f815f7028e41a3062e902095e5a7dc84617c87267ebd5"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:c3452ea726c76e92f3b9fae4b34a151981a9ec0a4847a627c43d71a15ac32aa6"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ff30218887e62209942f91ac1be902cc80cddb86bf00fbc6783b7a43b2bea26f"}, + {file = "aiohttp-3.9.3-cp312-cp312-win32.whl", hash = "sha256:38f307b41e0bea3294a9a2a87833191e4bcf89bb0365e83a8be3a58b31fb7f38"}, + {file = "aiohttp-3.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:b791a3143681a520c0a17e26ae7465f1b6f99461a28019d1a2f425236e6eedb5"}, + {file = "aiohttp-3.9.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0ed621426d961df79aa3b963ac7af0d40392956ffa9be022024cd16297b30c8c"}, + {file = "aiohttp-3.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7f46acd6a194287b7e41e87957bfe2ad1ad88318d447caf5b090012f2c5bb528"}, + {file = "aiohttp-3.9.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:feeb18a801aacb098220e2c3eea59a512362eb408d4afd0c242044c33ad6d542"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f734e38fd8666f53da904c52a23ce517f1b07722118d750405af7e4123933511"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b40670ec7e2156d8e57f70aec34a7216407848dfe6c693ef131ddf6e76feb672"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fdd215b7b7fd4a53994f238d0f46b7ba4ac4c0adb12452beee724ddd0743ae5d"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:017a21b0df49039c8f46ca0971b3a7fdc1f56741ab1240cb90ca408049766168"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e99abf0bba688259a496f966211c49a514e65afa9b3073a1fcee08856e04425b"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:648056db9a9fa565d3fa851880f99f45e3f9a771dd3ff3bb0c048ea83fb28194"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8aacb477dc26797ee089721536a292a664846489c49d3ef9725f992449eda5a8"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:522a11c934ea660ff8953eda090dcd2154d367dec1ae3c540aff9f8a5c109ab4"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:5bce0dc147ca85caa5d33debc4f4d65e8e8b5c97c7f9f660f215fa74fc49a321"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b4af9f25b49a7be47c0972139e59ec0e8285c371049df1a63b6ca81fdd216a2"}, + {file = "aiohttp-3.9.3-cp38-cp38-win32.whl", hash = "sha256:298abd678033b8571995650ccee753d9458dfa0377be4dba91e4491da3f2be63"}, + {file = "aiohttp-3.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:69361bfdca5468c0488d7017b9b1e5ce769d40b46a9f4a2eed26b78619e9396c"}, + {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0fa43c32d1643f518491d9d3a730f85f5bbaedcbd7fbcae27435bb8b7a061b29"}, + {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:835a55b7ca49468aaaac0b217092dfdff370e6c215c9224c52f30daaa735c1c1"}, + {file = "aiohttp-3.9.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06a9b2c8837d9a94fae16c6223acc14b4dfdff216ab9b7202e07a9a09541168f"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abf151955990d23f84205286938796c55ff11bbfb4ccfada8c9c83ae6b3c89a3"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59c26c95975f26e662ca78fdf543d4eeaef70e533a672b4113dd888bd2423caa"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f95511dd5d0e05fd9728bac4096319f80615aaef4acbecb35a990afebe953b0e"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:595f105710293e76b9dc09f52e0dd896bd064a79346234b521f6b968ffdd8e58"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7c8b816c2b5af5c8a436df44ca08258fc1a13b449393a91484225fcb7545533"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f1088fa100bf46e7b398ffd9904f4808a0612e1d966b4aa43baa535d1b6341eb"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f59dfe57bb1ec82ac0698ebfcdb7bcd0e99c255bd637ff613760d5f33e7c81b3"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:361a1026c9dd4aba0109e4040e2aecf9884f5cfe1b1b1bd3d09419c205e2e53d"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:363afe77cfcbe3a36353d8ea133e904b108feea505aa4792dad6585a8192c55a"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e2c45c208c62e955e8256949eb225bd8b66a4c9b6865729a786f2aa79b72e9d"}, + {file = "aiohttp-3.9.3-cp39-cp39-win32.whl", hash = "sha256:f7217af2e14da0856e082e96ff637f14ae45c10a5714b63c77f26d8884cf1051"}, + {file = "aiohttp-3.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:27468897f628c627230dba07ec65dc8d0db566923c48f29e084ce382119802bc"}, + {file = "aiohttp-3.9.3.tar.gz", hash = "sha256:90842933e5d1ff760fae6caca4b2b3edba53ba8f4b71e95dacf2818a2aca06f7"}, ] [package.dependencies] @@ -380,17 +380,17 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "boto3" -version = "1.34.28" +version = "1.34.33" description = "The AWS SDK for Python" optional = false python-versions = ">= 3.8" files = [ - {file = "boto3-1.34.28-py3-none-any.whl", hash = "sha256:fb56622ce195c06ae0d15ae9472d44529362a869ad52862a5a28b891530969f9"}, - {file = "boto3-1.34.28.tar.gz", hash = "sha256:9e0dcca7bb0567f7b4b84d1d26c19b217abfe149d19106af7f120f09142688cf"}, + {file = "boto3-1.34.33-py3-none-any.whl", hash = "sha256:5a5db6defe73238c25c0c4f9e5522401d2563d75fb10e1cf925bf4ea16514280"}, + {file = "boto3-1.34.33.tar.gz", hash = "sha256:5bbd73711f7664c6e8b80981ff247ba8dd2a8c5aa0bf619c5466cb9c24b9f279"}, ] [package.dependencies] -botocore = ">=1.34.28,<1.35.0" +botocore = ">=1.34.33,<1.35.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.10.0,<0.11.0" @@ -399,13 +399,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.34.28" +version = "1.34.33" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">= 3.8" files = [ - {file = "botocore-1.34.28-py3-none-any.whl", hash = "sha256:03be8209257ab65f3c8be7377cf8d38bff6a6afbe3d36c72924e48959bb694dc"}, - {file = "botocore-1.34.28.tar.gz", hash = "sha256:45c99ccc6389ab1a87e996a7cc8797c7e41d5ecd9a5757d567ba3a57cb7655e7"}, + {file = "botocore-1.34.33-py3-none-any.whl", hash = "sha256:5d154d0af41d5978d58f198837450953ae7168e292071f013ef7b739f40fb18f"}, + {file = "botocore-1.34.33.tar.gz", hash = "sha256:a50fb5e0c1ddf17d28dc8d0d2c33242b78009fb7f28e390cadcdc310908492b0"}, ] [package.dependencies] @@ -440,13 +440,13 @@ files = [ [[package]] name = "certifi" -version = "2023.11.17" +version = "2024.2.2" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, - {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, + {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, + {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, ] [[package]] @@ -726,43 +726,43 @@ python-dateutil = "*" [[package]] name = "cryptography" -version = "42.0.1" +version = "42.0.2" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-42.0.1-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:265bdc693570b895eb641410b8fc9e8ddbce723a669236162b9d9cfb70bd8d77"}, - {file = "cryptography-42.0.1-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:160fa08dfa6dca9cb8ad9bd84e080c0db6414ba5ad9a7470bc60fb154f60111e"}, - {file = "cryptography-42.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:727387886c9c8de927c360a396c5edcb9340d9e960cda145fca75bdafdabd24c"}, - {file = "cryptography-42.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d84673c012aa698555d4710dcfe5f8a0ad76ea9dde8ef803128cc669640a2e0"}, - {file = "cryptography-42.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e6edc3a568667daf7d349d7e820783426ee4f1c0feab86c29bd1d6fe2755e009"}, - {file = "cryptography-42.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:d50718dd574a49d3ef3f7ef7ece66ef281b527951eb2267ce570425459f6a404"}, - {file = "cryptography-42.0.1-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:9544492e8024f29919eac2117edd8c950165e74eb551a22c53f6fdf6ba5f4cb8"}, - {file = "cryptography-42.0.1-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ab6b302d51fbb1dd339abc6f139a480de14d49d50f65fdc7dff782aa8631d035"}, - {file = "cryptography-42.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2fe16624637d6e3e765530bc55caa786ff2cbca67371d306e5d0a72e7c3d0407"}, - {file = "cryptography-42.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ed1b2130f5456a09a134cc505a17fc2830a1a48ed53efd37dcc904a23d7b82fa"}, - {file = "cryptography-42.0.1-cp37-abi3-win32.whl", hash = "sha256:e5edf189431b4d51f5c6fb4a95084a75cef6b4646c934eb6e32304fc720e1453"}, - {file = "cryptography-42.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:6bfd823b336fdcd8e06285ae8883d3d2624d3bdef312a0e2ef905f332f8e9302"}, - {file = "cryptography-42.0.1-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:351db02c1938c8e6b1fee8a78d6b15c5ccceca7a36b5ce48390479143da3b411"}, - {file = "cryptography-42.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:430100abed6d3652208ae1dd410c8396213baee2e01a003a4449357db7dc9e14"}, - {file = "cryptography-42.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dff7a32880a51321f5de7869ac9dde6b1fca00fc1fef89d60e93f215468e824"}, - {file = "cryptography-42.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:b512f33c6ab195852595187af5440d01bb5f8dd57cb7a91e1e009a17f1b7ebca"}, - {file = "cryptography-42.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:95d900d19a370ae36087cc728e6e7be9c964ffd8cbcb517fd1efb9c9284a6abc"}, - {file = "cryptography-42.0.1-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:6ac8924085ed8287545cba89dc472fc224c10cc634cdf2c3e2866fe868108e77"}, - {file = "cryptography-42.0.1-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cb2861a9364fa27d24832c718150fdbf9ce6781d7dc246a516435f57cfa31fe7"}, - {file = "cryptography-42.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:25ec6e9e81de5d39f111a4114193dbd39167cc4bbd31c30471cebedc2a92c323"}, - {file = "cryptography-42.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9d61fcdf37647765086030d81872488e4cb3fafe1d2dda1d487875c3709c0a49"}, - {file = "cryptography-42.0.1-cp39-abi3-win32.whl", hash = "sha256:16b9260d04a0bfc8952b00335ff54f471309d3eb9d7e8dbfe9b0bd9e26e67881"}, - {file = "cryptography-42.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:7911586fc69d06cd0ab3f874a169433db1bc2f0e40988661408ac06c4527a986"}, - {file = "cryptography-42.0.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d3594947d2507d4ef7a180a7f49a6db41f75fb874c2fd0e94f36b89bfd678bf2"}, - {file = "cryptography-42.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:8d7efb6bf427d2add2f40b6e1e8e476c17508fa8907234775214b153e69c2e11"}, - {file = "cryptography-42.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:126e0ba3cc754b200a2fb88f67d66de0d9b9e94070c5bc548318c8dab6383cb6"}, - {file = "cryptography-42.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:802d6f83233cf9696b59b09eb067e6b4d5ae40942feeb8e13b213c8fad47f1aa"}, - {file = "cryptography-42.0.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0b7cacc142260ada944de070ce810c3e2a438963ee3deb45aa26fd2cee94c9a4"}, - {file = "cryptography-42.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:32ea63ceeae870f1a62e87f9727359174089f7b4b01e4999750827bf10e15d60"}, - {file = "cryptography-42.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d3902c779a92151f134f68e555dd0b17c658e13429f270d8a847399b99235a3f"}, - {file = "cryptography-42.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:50aecd93676bcca78379604ed664c45da82bc1241ffb6f97f6b7392ed5bc6f04"}, - {file = "cryptography-42.0.1.tar.gz", hash = "sha256:fd33f53809bb363cf126bebe7a99d97735988d9b0131a2be59fbf83e1259a5b7"}, + {file = "cryptography-42.0.2-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:701171f825dcab90969596ce2af253143b93b08f1a716d4b2a9d2db5084ef7be"}, + {file = "cryptography-42.0.2-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:61321672b3ac7aade25c40449ccedbc6db72c7f5f0fdf34def5e2f8b51ca530d"}, + {file = "cryptography-42.0.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea2c3ffb662fec8bbbfce5602e2c159ff097a4631d96235fcf0fb00e59e3ece4"}, + {file = "cryptography-42.0.2-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b15c678f27d66d247132cbf13df2f75255627bcc9b6a570f7d2fd08e8c081d2"}, + {file = "cryptography-42.0.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8e88bb9eafbf6a4014d55fb222e7360eef53e613215085e65a13290577394529"}, + {file = "cryptography-42.0.2-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a047682d324ba56e61b7ea7c7299d51e61fd3bca7dad2ccc39b72bd0118d60a1"}, + {file = "cryptography-42.0.2-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:36d4b7c4be6411f58f60d9ce555a73df8406d484ba12a63549c88bd64f7967f1"}, + {file = "cryptography-42.0.2-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:a00aee5d1b6c20620161984f8ab2ab69134466c51f58c052c11b076715e72929"}, + {file = "cryptography-42.0.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b97fe7d7991c25e6a31e5d5e795986b18fbbb3107b873d5f3ae6dc9a103278e9"}, + {file = "cryptography-42.0.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5fa82a26f92871eca593b53359c12ad7949772462f887c35edaf36f87953c0e2"}, + {file = "cryptography-42.0.2-cp37-abi3-win32.whl", hash = "sha256:4b063d3413f853e056161eb0c7724822a9740ad3caa24b8424d776cebf98e7ee"}, + {file = "cryptography-42.0.2-cp37-abi3-win_amd64.whl", hash = "sha256:841ec8af7a8491ac76ec5a9522226e287187a3107e12b7d686ad354bb78facee"}, + {file = "cryptography-42.0.2-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:55d1580e2d7e17f45d19d3b12098e352f3a37fe86d380bf45846ef257054b242"}, + {file = "cryptography-42.0.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28cb2c41f131a5758d6ba6a0504150d644054fd9f3203a1e8e8d7ac3aea7f73a"}, + {file = "cryptography-42.0.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9097a208875fc7bbeb1286d0125d90bdfed961f61f214d3f5be62cd4ed8a446"}, + {file = "cryptography-42.0.2-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:44c95c0e96b3cb628e8452ec060413a49002a247b2b9938989e23a2c8291fc90"}, + {file = "cryptography-42.0.2-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2f9f14185962e6a04ab32d1abe34eae8a9001569ee4edb64d2304bf0d65c53f3"}, + {file = "cryptography-42.0.2-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:09a77e5b2e8ca732a19a90c5bca2d124621a1edb5438c5daa2d2738bfeb02589"}, + {file = "cryptography-42.0.2-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad28cff53f60d99a928dfcf1e861e0b2ceb2bc1f08a074fdd601b314e1cc9e0a"}, + {file = "cryptography-42.0.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:130c0f77022b2b9c99d8cebcdd834d81705f61c68e91ddd614ce74c657f8b3ea"}, + {file = "cryptography-42.0.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:fa3dec4ba8fb6e662770b74f62f1a0c7d4e37e25b58b2bf2c1be4c95372b4a33"}, + {file = "cryptography-42.0.2-cp39-abi3-win32.whl", hash = "sha256:3dbd37e14ce795b4af61b89b037d4bc157f2cb23e676fa16932185a04dfbf635"}, + {file = "cryptography-42.0.2-cp39-abi3-win_amd64.whl", hash = "sha256:8a06641fb07d4e8f6c7dda4fc3f8871d327803ab6542e33831c7ccfdcb4d0ad6"}, + {file = "cryptography-42.0.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:087887e55e0b9c8724cf05361357875adb5c20dec27e5816b653492980d20380"}, + {file = "cryptography-42.0.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a7ef8dd0bf2e1d0a27042b231a3baac6883cdd5557036f5e8df7139255feaac6"}, + {file = "cryptography-42.0.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4383b47f45b14459cab66048d384614019965ba6c1a1a141f11b5a551cace1b2"}, + {file = "cryptography-42.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:fbeb725c9dc799a574518109336acccaf1303c30d45c075c665c0793c2f79a7f"}, + {file = "cryptography-42.0.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:320948ab49883557a256eab46149df79435a22d2fefd6a66fe6946f1b9d9d008"}, + {file = "cryptography-42.0.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5ef9bc3d046ce83c4bbf4c25e1e0547b9c441c01d30922d812e887dc5f125c12"}, + {file = "cryptography-42.0.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:52ed9ebf8ac602385126c9a2fe951db36f2cb0c2538d22971487f89d0de4065a"}, + {file = "cryptography-42.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:141e2aa5ba100d3788c0ad7919b288f89d1fe015878b9659b307c9ef867d3a65"}, + {file = "cryptography-42.0.2.tar.gz", hash = "sha256:e0ec52ba3c7f1b7d813cd52649a5b3ef1fc0d433219dc8c93827c57eab6cf888"}, ] [package.dependencies] @@ -1178,135 +1178,135 @@ test = ["objgraph", "psutil"] [[package]] name = "grpcio" -version = "1.60.0" +version = "1.60.1" description = "HTTP/2-based RPC framework" optional = false python-versions = ">=3.7" files = [ - {file = "grpcio-1.60.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:d020cfa595d1f8f5c6b343530cd3ca16ae5aefdd1e832b777f9f0eb105f5b139"}, - {file = "grpcio-1.60.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:b98f43fcdb16172dec5f4b49f2fece4b16a99fd284d81c6bbac1b3b69fcbe0ff"}, - {file = "grpcio-1.60.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:20e7a4f7ded59097c84059d28230907cd97130fa74f4a8bfd1d8e5ba18c81491"}, - {file = "grpcio-1.60.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:452ca5b4afed30e7274445dd9b441a35ece656ec1600b77fff8c216fdf07df43"}, - {file = "grpcio-1.60.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43e636dc2ce9ece583b3e2ca41df5c983f4302eabc6d5f9cd04f0562ee8ec1ae"}, - {file = "grpcio-1.60.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e306b97966369b889985a562ede9d99180def39ad42c8014628dd3cc343f508"}, - {file = "grpcio-1.60.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f897c3b127532e6befdcf961c415c97f320d45614daf84deba0a54e64ea2457b"}, - {file = "grpcio-1.60.0-cp310-cp310-win32.whl", hash = "sha256:b87efe4a380887425bb15f220079aa8336276398dc33fce38c64d278164f963d"}, - {file = "grpcio-1.60.0-cp310-cp310-win_amd64.whl", hash = "sha256:a9c7b71211f066908e518a2ef7a5e211670761651039f0d6a80d8d40054047df"}, - {file = "grpcio-1.60.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:fb464479934778d7cc5baf463d959d361954d6533ad34c3a4f1d267e86ee25fd"}, - {file = "grpcio-1.60.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:4b44d7e39964e808b071714666a812049765b26b3ea48c4434a3b317bac82f14"}, - {file = "grpcio-1.60.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:90bdd76b3f04bdb21de5398b8a7c629676c81dfac290f5f19883857e9371d28c"}, - {file = "grpcio-1.60.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91229d7203f1ef0ab420c9b53fe2ca5c1fbeb34f69b3bc1b5089466237a4a134"}, - {file = "grpcio-1.60.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b36a2c6d4920ba88fa98075fdd58ff94ebeb8acc1215ae07d01a418af4c0253"}, - {file = "grpcio-1.60.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:297eef542156d6b15174a1231c2493ea9ea54af8d016b8ca7d5d9cc65cfcc444"}, - {file = "grpcio-1.60.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:87c9224acba0ad8bacddf427a1c2772e17ce50b3042a789547af27099c5f751d"}, - {file = "grpcio-1.60.0-cp311-cp311-win32.whl", hash = "sha256:95ae3e8e2c1b9bf671817f86f155c5da7d49a2289c5cf27a319458c3e025c320"}, - {file = "grpcio-1.60.0-cp311-cp311-win_amd64.whl", hash = "sha256:467a7d31554892eed2aa6c2d47ded1079fc40ea0b9601d9f79204afa8902274b"}, - {file = "grpcio-1.60.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:a7152fa6e597c20cb97923407cf0934e14224af42c2b8d915f48bc3ad2d9ac18"}, - {file = "grpcio-1.60.0-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:7db16dd4ea1b05ada504f08d0dca1cd9b926bed3770f50e715d087c6f00ad748"}, - {file = "grpcio-1.60.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:b0571a5aef36ba9177e262dc88a9240c866d903a62799e44fd4aae3f9a2ec17e"}, - {file = "grpcio-1.60.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fd9584bf1bccdfff1512719316efa77be235469e1e3295dce64538c4773840b"}, - {file = "grpcio-1.60.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6a478581b1a1a8fdf3318ecb5f4d0cda41cacdffe2b527c23707c9c1b8fdb55"}, - {file = "grpcio-1.60.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:77c8a317f0fd5a0a2be8ed5cbe5341537d5c00bb79b3bb27ba7c5378ba77dbca"}, - {file = "grpcio-1.60.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1c30bb23a41df95109db130a6cc1b974844300ae2e5d68dd4947aacba5985aa5"}, - {file = "grpcio-1.60.0-cp312-cp312-win32.whl", hash = "sha256:2aef56e85901c2397bd557c5ba514f84de1f0ae5dd132f5d5fed042858115951"}, - {file = "grpcio-1.60.0-cp312-cp312-win_amd64.whl", hash = "sha256:e381fe0c2aa6c03b056ad8f52f8efca7be29fb4d9ae2f8873520843b6039612a"}, - {file = "grpcio-1.60.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:92f88ca1b956eb8427a11bb8b4a0c0b2b03377235fc5102cb05e533b8693a415"}, - {file = "grpcio-1.60.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:e278eafb406f7e1b1b637c2cf51d3ad45883bb5bd1ca56bc05e4fc135dfdaa65"}, - {file = "grpcio-1.60.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:a48edde788b99214613e440fce495bbe2b1e142a7f214cce9e0832146c41e324"}, - {file = "grpcio-1.60.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de2ad69c9a094bf37c1102b5744c9aec6cf74d2b635558b779085d0263166454"}, - {file = "grpcio-1.60.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:073f959c6f570797272f4ee9464a9997eaf1e98c27cb680225b82b53390d61e6"}, - {file = "grpcio-1.60.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c826f93050c73e7769806f92e601e0efdb83ec8d7c76ddf45d514fee54e8e619"}, - {file = "grpcio-1.60.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:9e30be89a75ee66aec7f9e60086fadb37ff8c0ba49a022887c28c134341f7179"}, - {file = "grpcio-1.60.0-cp37-cp37m-win_amd64.whl", hash = "sha256:b0fb2d4801546598ac5cd18e3ec79c1a9af8b8f2a86283c55a5337c5aeca4b1b"}, - {file = "grpcio-1.60.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:9073513ec380434eb8d21970e1ab3161041de121f4018bbed3146839451a6d8e"}, - {file = "grpcio-1.60.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:74d7d9fa97809c5b892449b28a65ec2bfa458a4735ddad46074f9f7d9550ad13"}, - {file = "grpcio-1.60.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:1434ca77d6fed4ea312901122dc8da6c4389738bf5788f43efb19a838ac03ead"}, - {file = "grpcio-1.60.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e61e76020e0c332a98290323ecfec721c9544f5b739fab925b6e8cbe1944cf19"}, - {file = "grpcio-1.60.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675997222f2e2f22928fbba640824aebd43791116034f62006e19730715166c0"}, - {file = "grpcio-1.60.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5208a57eae445ae84a219dfd8b56e04313445d146873117b5fa75f3245bc1390"}, - {file = "grpcio-1.60.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:428d699c8553c27e98f4d29fdc0f0edc50e9a8a7590bfd294d2edb0da7be3629"}, - {file = "grpcio-1.60.0-cp38-cp38-win32.whl", hash = "sha256:83f2292ae292ed5a47cdcb9821039ca8e88902923198f2193f13959360c01860"}, - {file = "grpcio-1.60.0-cp38-cp38-win_amd64.whl", hash = "sha256:705a68a973c4c76db5d369ed573fec3367d7d196673fa86614b33d8c8e9ebb08"}, - {file = "grpcio-1.60.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:c193109ca4070cdcaa6eff00fdb5a56233dc7610216d58fb81638f89f02e4968"}, - {file = "grpcio-1.60.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:676e4a44e740deaba0f4d95ba1d8c5c89a2fcc43d02c39f69450b1fa19d39590"}, - {file = "grpcio-1.60.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:5ff21e000ff2f658430bde5288cb1ac440ff15c0d7d18b5fb222f941b46cb0d2"}, - {file = "grpcio-1.60.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c86343cf9ff7b2514dd229bdd88ebba760bd8973dac192ae687ff75e39ebfab"}, - {file = "grpcio-1.60.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fd3b3968ffe7643144580f260f04d39d869fcc2cddb745deef078b09fd2b328"}, - {file = "grpcio-1.60.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:30943b9530fe3620e3b195c03130396cd0ee3a0d10a66c1bee715d1819001eaf"}, - {file = "grpcio-1.60.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b10241250cb77657ab315270b064a6c7f1add58af94befa20687e7c8d8603ae6"}, - {file = "grpcio-1.60.0-cp39-cp39-win32.whl", hash = "sha256:79a050889eb8d57a93ed21d9585bb63fca881666fc709f5d9f7f9372f5e7fd03"}, - {file = "grpcio-1.60.0-cp39-cp39-win_amd64.whl", hash = "sha256:8a97a681e82bc11a42d4372fe57898d270a2707f36c45c6676e49ce0d5c41353"}, - {file = "grpcio-1.60.0.tar.gz", hash = "sha256:2199165a1affb666aa24adf0c97436686d0a61bc5fc113c037701fb7c7fceb96"}, + {file = "grpcio-1.60.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:14e8f2c84c0832773fb3958240c69def72357bc11392571f87b2d7b91e0bb092"}, + {file = "grpcio-1.60.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:33aed0a431f5befeffd9d346b0fa44b2c01aa4aeae5ea5b2c03d3e25e0071216"}, + {file = "grpcio-1.60.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:fead980fbc68512dfd4e0c7b1f5754c2a8e5015a04dea454b9cada54a8423525"}, + {file = "grpcio-1.60.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:082081e6a36b6eb5cf0fd9a897fe777dbb3802176ffd08e3ec6567edd85bc104"}, + {file = "grpcio-1.60.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55ccb7db5a665079d68b5c7c86359ebd5ebf31a19bc1a91c982fd622f1e31ff2"}, + {file = "grpcio-1.60.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9b54577032d4f235452f77a83169b6527bf4b77d73aeada97d45b2aaf1bf5ce0"}, + {file = "grpcio-1.60.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7d142bcd604166417929b071cd396aa13c565749a4c840d6c702727a59d835eb"}, + {file = "grpcio-1.60.1-cp310-cp310-win32.whl", hash = "sha256:2a6087f234cb570008a6041c8ffd1b7d657b397fdd6d26e83d72283dae3527b1"}, + {file = "grpcio-1.60.1-cp310-cp310-win_amd64.whl", hash = "sha256:f2212796593ad1d0235068c79836861f2201fc7137a99aa2fea7beeb3b101177"}, + {file = "grpcio-1.60.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:79ae0dc785504cb1e1788758c588c711f4e4a0195d70dff53db203c95a0bd303"}, + {file = "grpcio-1.60.1-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:4eec8b8c1c2c9b7125508ff7c89d5701bf933c99d3910e446ed531cd16ad5d87"}, + {file = "grpcio-1.60.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:8c9554ca8e26241dabe7951aa1fa03a1ba0856688ecd7e7bdbdd286ebc272e4c"}, + {file = "grpcio-1.60.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91422ba785a8e7a18725b1dc40fbd88f08a5bb4c7f1b3e8739cab24b04fa8a03"}, + {file = "grpcio-1.60.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cba6209c96828711cb7c8fcb45ecef8c8859238baf15119daa1bef0f6c84bfe7"}, + {file = "grpcio-1.60.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c71be3f86d67d8d1311c6076a4ba3b75ba5703c0b856b4e691c9097f9b1e8bd2"}, + {file = "grpcio-1.60.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:af5ef6cfaf0d023c00002ba25d0751e5995fa0e4c9eec6cd263c30352662cbce"}, + {file = "grpcio-1.60.1-cp311-cp311-win32.whl", hash = "sha256:a09506eb48fa5493c58f946c46754ef22f3ec0df64f2b5149373ff31fb67f3dd"}, + {file = "grpcio-1.60.1-cp311-cp311-win_amd64.whl", hash = "sha256:49c9b6a510e3ed8df5f6f4f3c34d7fbf2d2cae048ee90a45cd7415abab72912c"}, + {file = "grpcio-1.60.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:b58b855d0071575ea9c7bc0d84a06d2edfbfccec52e9657864386381a7ce1ae9"}, + {file = "grpcio-1.60.1-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:a731ac5cffc34dac62053e0da90f0c0b8560396a19f69d9703e88240c8f05858"}, + {file = "grpcio-1.60.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:cf77f8cf2a651fbd869fbdcb4a1931464189cd210abc4cfad357f1cacc8642a6"}, + {file = "grpcio-1.60.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c557e94e91a983e5b1e9c60076a8fd79fea1e7e06848eb2e48d0ccfb30f6e073"}, + {file = "grpcio-1.60.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:069fe2aeee02dfd2135d562d0663fe70fbb69d5eed6eb3389042a7e963b54de8"}, + {file = "grpcio-1.60.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cb0af13433dbbd1c806e671d81ec75bd324af6ef75171fd7815ca3074fe32bfe"}, + {file = "grpcio-1.60.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2f44c32aef186bbba254129cea1df08a20be414144ac3bdf0e84b24e3f3b2e05"}, + {file = "grpcio-1.60.1-cp312-cp312-win32.whl", hash = "sha256:a212e5dea1a4182e40cd3e4067ee46be9d10418092ce3627475e995cca95de21"}, + {file = "grpcio-1.60.1-cp312-cp312-win_amd64.whl", hash = "sha256:6e490fa5f7f5326222cb9f0b78f207a2b218a14edf39602e083d5f617354306f"}, + {file = "grpcio-1.60.1-cp37-cp37m-linux_armv7l.whl", hash = "sha256:4216e67ad9a4769117433814956031cb300f85edc855252a645a9a724b3b6594"}, + {file = "grpcio-1.60.1-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:73e14acd3d4247169955fae8fb103a2b900cfad21d0c35f0dcd0fdd54cd60367"}, + {file = "grpcio-1.60.1-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:6ecf21d20d02d1733e9c820fb5c114c749d888704a7ec824b545c12e78734d1c"}, + {file = "grpcio-1.60.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33bdea30dcfd4f87b045d404388469eb48a48c33a6195a043d116ed1b9a0196c"}, + {file = "grpcio-1.60.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53b69e79d00f78c81eecfb38f4516080dc7f36a198b6b37b928f1c13b3c063e9"}, + {file = "grpcio-1.60.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:39aa848794b887120b1d35b1b994e445cc028ff602ef267f87c38122c1add50d"}, + {file = "grpcio-1.60.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:72153a0d2e425f45b884540a61c6639436ddafa1829a42056aa5764b84108b8e"}, + {file = "grpcio-1.60.1-cp37-cp37m-win_amd64.whl", hash = "sha256:50d56280b482875d1f9128ce596e59031a226a8b84bec88cb2bf76c289f5d0de"}, + {file = "grpcio-1.60.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:6d140bdeb26cad8b93c1455fa00573c05592793c32053d6e0016ce05ba267549"}, + {file = "grpcio-1.60.1-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:bc808924470643b82b14fe121923c30ec211d8c693e747eba8a7414bc4351a23"}, + {file = "grpcio-1.60.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:70c83bb530572917be20c21f3b6be92cd86b9aecb44b0c18b1d3b2cc3ae47df0"}, + {file = "grpcio-1.60.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9b106bc52e7f28170e624ba61cc7dc6829566e535a6ec68528f8e1afbed1c41f"}, + {file = "grpcio-1.60.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30e980cd6db1088c144b92fe376747328d5554bc7960ce583ec7b7d81cd47287"}, + {file = "grpcio-1.60.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0c5807e9152eff15f1d48f6b9ad3749196f79a4a050469d99eecb679be592acc"}, + {file = "grpcio-1.60.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f1c3dc536b3ee124e8b24feb7533e5c70b9f2ef833e3b2e5513b2897fd46763a"}, + {file = "grpcio-1.60.1-cp38-cp38-win32.whl", hash = "sha256:d7404cebcdb11bb5bd40bf94131faf7e9a7c10a6c60358580fe83913f360f929"}, + {file = "grpcio-1.60.1-cp38-cp38-win_amd64.whl", hash = "sha256:c8754c75f55781515a3005063d9a05878b2cfb3cb7e41d5401ad0cf19de14872"}, + {file = "grpcio-1.60.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:0250a7a70b14000fa311de04b169cc7480be6c1a769b190769d347939d3232a8"}, + {file = "grpcio-1.60.1-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:660fc6b9c2a9ea3bb2a7e64ba878c98339abaf1811edca904ac85e9e662f1d73"}, + {file = "grpcio-1.60.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:76eaaba891083fcbe167aa0f03363311a9f12da975b025d30e94b93ac7a765fc"}, + {file = "grpcio-1.60.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d97c65ea7e097056f3d1ead77040ebc236feaf7f71489383d20f3b4c28412a"}, + {file = "grpcio-1.60.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb2a2911b028f01c8c64d126f6b632fcd8a9ac975aa1b3855766c94e4107180"}, + {file = "grpcio-1.60.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:5a1ebbae7e2214f51b1f23b57bf98eeed2cf1ba84e4d523c48c36d5b2f8829ff"}, + {file = "grpcio-1.60.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9a66f4d2a005bc78e61d805ed95dedfcb35efa84b7bba0403c6d60d13a3de2d6"}, + {file = "grpcio-1.60.1-cp39-cp39-win32.whl", hash = "sha256:8d488fbdbf04283f0d20742b64968d44825617aa6717b07c006168ed16488804"}, + {file = "grpcio-1.60.1-cp39-cp39-win_amd64.whl", hash = "sha256:61b7199cd2a55e62e45bfb629a35b71fc2c0cb88f686a047f25b1112d3810904"}, + {file = "grpcio-1.60.1.tar.gz", hash = "sha256:dd1d3a8d1d2e50ad9b59e10aa7f07c7d1be2b367f3f2d33c5fade96ed5460962"}, ] [package.extras] -protobuf = ["grpcio-tools (>=1.60.0)"] +protobuf = ["grpcio-tools (>=1.60.1)"] [[package]] name = "grpcio-tools" -version = "1.60.0" +version = "1.60.1" description = "Protobuf code generator for gRPC" optional = false python-versions = ">=3.7" files = [ - {file = "grpcio-tools-1.60.0.tar.gz", hash = "sha256:ed30499340228d733ff69fcf4a66590ed7921f94eb5a2bf692258b1280b9dac7"}, - {file = "grpcio_tools-1.60.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:6807b7a3f3e6e594566100bd7fe04a2c42ce6d5792652677f1aaf5aa5adaef3d"}, - {file = "grpcio_tools-1.60.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:857c5351e9dc33a019700e171163f94fcc7e3ae0f6d2b026b10fda1e3c008ef1"}, - {file = "grpcio_tools-1.60.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:ec0e401e9a43d927d216d5169b03c61163fb52b665c5af2fed851357b15aef88"}, - {file = "grpcio_tools-1.60.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e68dc4474f30cad11a965f0eb5d37720a032b4720afa0ec19dbcea2de73b5aae"}, - {file = "grpcio_tools-1.60.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbf0ed772d2ae7e8e5d7281fcc00123923ab130b94f7a843eee9af405918f924"}, - {file = "grpcio_tools-1.60.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c771b19dce2bfe06899247168c077d7ab4e273f6655d8174834f9a6034415096"}, - {file = "grpcio_tools-1.60.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e5614cf0960456d21d8a0f4902e3e5e3bcacc4e400bf22f196e5dd8aabb978b7"}, - {file = "grpcio_tools-1.60.0-cp310-cp310-win32.whl", hash = "sha256:87cf439178f3eb45c1a889b2e4a17cbb4c450230d92c18d9c57e11271e239c55"}, - {file = "grpcio_tools-1.60.0-cp310-cp310-win_amd64.whl", hash = "sha256:687f576d7ff6ce483bc9a196d1ceac45144e8733b953620a026daed8e450bc38"}, - {file = "grpcio_tools-1.60.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:2a8a758701f3ac07ed85f5a4284c6a9ddefcab7913a8e552497f919349e72438"}, - {file = "grpcio_tools-1.60.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:7c1cde49631732356cb916ee1710507967f19913565ed5f9991e6c9cb37e3887"}, - {file = "grpcio_tools-1.60.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:d941749bd8dc3f8be58fe37183143412a27bec3df8482d5abd6b4ec3f1ac2924"}, - {file = "grpcio_tools-1.60.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9ee35234f1da8fba7ddbc544856ff588243f1128ea778d7a1da3039be829a134"}, - {file = "grpcio_tools-1.60.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8f7a5094adb49e85db13ea3df5d99a976c2bdfd83b0ba26af20ebb742ac6786"}, - {file = "grpcio_tools-1.60.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:24c4ead4a03037beaeb8ef2c90d13d70101e35c9fae057337ed1a9144ef10b53"}, - {file = "grpcio_tools-1.60.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:811abb9c4fb6679e0058dfa123fb065d97b158b71959c0e048e7972bbb82ba0f"}, - {file = "grpcio_tools-1.60.0-cp311-cp311-win32.whl", hash = "sha256:bd2a17b0193fbe4793c215d63ce1e01ae00a8183d81d7c04e77e1dfafc4b2b8a"}, - {file = "grpcio_tools-1.60.0-cp311-cp311-win_amd64.whl", hash = "sha256:b22b1299b666eebd5752ba7719da536075eae3053abcf2898b65f763c314d9da"}, - {file = "grpcio_tools-1.60.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:74025fdd6d1cb7ba4b5d087995339e9a09f0c16cf15dfe56368b23e41ffeaf7a"}, - {file = "grpcio_tools-1.60.0-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:5a907a4f1ffba86501b2cdb8682346249ea032b922fc69a92f082ba045cca548"}, - {file = "grpcio_tools-1.60.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:1fbb9554466d560472f07d906bfc8dcaf52f365c2a407015185993e30372a886"}, - {file = "grpcio_tools-1.60.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f10ef47460ce3c6fd400f05fe757b90df63486c9b84d1ecad42dcc5f80c8ac14"}, - {file = "grpcio_tools-1.60.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:321b18f42a70813545e416ddcb8bf20defa407a8114906711c9710a69596ceda"}, - {file = "grpcio_tools-1.60.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:081336d8258f1a56542aa8a7a5dec99a2b38d902e19fbdd744594783301b0210"}, - {file = "grpcio_tools-1.60.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:addc9b23d6ff729d9f83d4a2846292d4c84f5eb2ec38f08489a6a0d66ac2b91e"}, - {file = "grpcio_tools-1.60.0-cp312-cp312-win32.whl", hash = "sha256:e87cabac7969bdde309575edc2456357667a1b28262b2c1f12580ef48315b19d"}, - {file = "grpcio_tools-1.60.0-cp312-cp312-win_amd64.whl", hash = "sha256:e70d867c120d9849093b0ac24d861e378bc88af2552e743d83b9f642d2caa7c2"}, - {file = "grpcio_tools-1.60.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:559ce714fe212aaf4abbe1493c5bb8920def00cc77ce0d45266f4fd9d8b3166f"}, - {file = "grpcio_tools-1.60.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:7a5263a0f2ddb7b1cfb2349e392cfc4f318722e0f48f886393e06946875d40f3"}, - {file = "grpcio_tools-1.60.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:18976684a931ca4bcba65c78afa778683aefaae310f353e198b1823bf09775a0"}, - {file = "grpcio_tools-1.60.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5c519a0d4ba1ab44a004fa144089738c59278233e2010b2cf4527dc667ff297"}, - {file = "grpcio_tools-1.60.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6170873b1e5b6580ebb99e87fb6e4ea4c48785b910bd7af838cc6e44b2bccb04"}, - {file = "grpcio_tools-1.60.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:fb4df80868b3e397d5fbccc004c789d2668b622b51a9d2387b4c89c80d31e2c5"}, - {file = "grpcio_tools-1.60.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:dba6e32c87b4af29b5f475fb2f470f7ee3140bfc128644f17c6c59ddeb670680"}, - {file = "grpcio_tools-1.60.0-cp37-cp37m-win_amd64.whl", hash = "sha256:f610384dee4b1ca705e8da66c5b5fe89a2de3d165c5282c3d1ddf40cb18924e4"}, - {file = "grpcio_tools-1.60.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:4041538f55aad5b3ae7e25ab314d7995d689e968bfc8aa169d939a3160b1e4c6"}, - {file = "grpcio_tools-1.60.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:2fb4cf74bfe1e707cf10bc9dd38a1ebaa145179453d150febb121c7e9cd749bf"}, - {file = "grpcio_tools-1.60.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:2fd1671c52f96e79a2302c8b1c1f78b8a561664b8b3d6946f20d8f1cc6b4225a"}, - {file = "grpcio_tools-1.60.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd1e68c232fe01dd5312a8dbe52c50ecd2b5991d517d7f7446af4ba6334ba872"}, - {file = "grpcio_tools-1.60.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17a32b3da4fc0798cdcec0a9c974ac2a1e98298f151517bf9148294a3b1a5742"}, - {file = "grpcio_tools-1.60.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9970d384fb0c084b00945ef57d98d57a8d32be106d8f0bd31387f7cbfe411b5b"}, - {file = "grpcio_tools-1.60.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5ce6bbd4936977ec1114f2903eb4342781960d521b0d82f73afedb9335251f6f"}, - {file = "grpcio_tools-1.60.0-cp38-cp38-win32.whl", hash = "sha256:2e00de389729ca8d8d1a63c2038703078a887ff738dc31be640b7da9c26d0d4f"}, - {file = "grpcio_tools-1.60.0-cp38-cp38-win_amd64.whl", hash = "sha256:6192184b1f99372ff1d9594bd4b12264e3ff26440daba7eb043726785200ff77"}, - {file = "grpcio_tools-1.60.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:eae27f9b16238e2aaee84c77b5923c6924d6dccb0bdd18435bf42acc8473ae1a"}, - {file = "grpcio_tools-1.60.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:b96981f3a31b85074b73d97c8234a5ed9053d65a36b18f4a9c45a2120a5b7a0a"}, - {file = "grpcio_tools-1.60.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:1748893efd05cf4a59a175d7fa1e4fbb652f4d84ccaa2109f7869a2be48ed25e"}, - {file = "grpcio_tools-1.60.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a6fe752205caae534f29fba907e2f59ff79aa42c6205ce9a467e9406cbac68c"}, - {file = "grpcio_tools-1.60.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3456df087ea61a0972a5bc165aed132ed6ddcc63f5749e572f9fff84540bdbad"}, - {file = "grpcio_tools-1.60.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f3d916606dcf5610d4367918245b3d9d8cd0d2ec0b7043d1bbb8c50fe9815c3a"}, - {file = "grpcio_tools-1.60.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:fc01bc1079279ec342f0f1b6a107b3f5dc3169c33369cf96ada6e2e171f74e86"}, - {file = "grpcio_tools-1.60.0-cp39-cp39-win32.whl", hash = "sha256:2dd01257e4feff986d256fa0bac9f56de59dc735eceeeb83de1c126e2e91f653"}, - {file = "grpcio_tools-1.60.0-cp39-cp39-win_amd64.whl", hash = "sha256:1b93ae8ffd18e9af9a965ebca5fa521e89066267de7abdde20721edc04e42721"}, + {file = "grpcio-tools-1.60.1.tar.gz", hash = "sha256:da08224ab8675c6d464b988bd8ca02cccd2bf0275bceefe8f6219bfd4a4f5e85"}, + {file = "grpcio_tools-1.60.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:184b27333b627a7cc0972fb70d21a8bb7c02ac4a6febc16768d78ea8ff883ddd"}, + {file = "grpcio_tools-1.60.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:18d7737f29ef5bbe3352547d0eccd080807834f00df223867dfc860bf81e9180"}, + {file = "grpcio_tools-1.60.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:cc8ba358d2c658c6ecbc58e779bf0fc5a673fecac015a70db27fc5b4d37b76b6"}, + {file = "grpcio_tools-1.60.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2973f75e8ba5c551033a1d59cc97654f6f386deaf2559082011d245d7ed87bba"}, + {file = "grpcio_tools-1.60.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28ae665113affebdd109247386786e5ab4dccfcfad1b5f68e9cce2e326b57ee6"}, + {file = "grpcio_tools-1.60.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5c7ed086fef5ff59f46d53a052b1934b73e0f7d12365d656d6af3a88057d5a3e"}, + {file = "grpcio_tools-1.60.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8540f6480428a52614db71dd6394f52cbc0d2565b5ea1136a982f26390a42c7a"}, + {file = "grpcio_tools-1.60.1-cp310-cp310-win32.whl", hash = "sha256:5b4a939097005531edec331f22d0b82bff26e71ede009354d2f375b5d41e74f0"}, + {file = "grpcio_tools-1.60.1-cp310-cp310-win_amd64.whl", hash = "sha256:075bb67895970f96aabc1761ca674bf4db193f8fcad387f08e50402023b5f953"}, + {file = "grpcio_tools-1.60.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:284749d20fb22418f17d3d351b9eb838caf4a0393a9cb02c36e5c32fa4bbe9db"}, + {file = "grpcio_tools-1.60.1-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:b1041377cf32ee2338284ee26e6b9c10f9ea7728092376b19803dcb9b91d510d"}, + {file = "grpcio_tools-1.60.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:e529cd3d4109a6f4a3f7bdaca68946eb33734e2d7ffe861785a0586abe99ee67"}, + {file = "grpcio_tools-1.60.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:31294b534f25f02ead204e58dcbe0e5437a95a1a6f276bb9378905595b02ff6d"}, + {file = "grpcio_tools-1.60.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fb6f4d2df0388c35c2804ba170f511238a681b679ead013bfe5e39d0ea9cf48"}, + {file = "grpcio_tools-1.60.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:40cd8268a675269ce59c4fa50877597ec638bb1099c52237bb726c8ac9791868"}, + {file = "grpcio_tools-1.60.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:985ac476da365267a2367ab20060f9096fbfc2e190fb02dd394f9ec05edf03ca"}, + {file = "grpcio_tools-1.60.1-cp311-cp311-win32.whl", hash = "sha256:bd85f6c368b93ae45edf8568473053cb1cc075ef3489efb18f9832d4ecce062f"}, + {file = "grpcio_tools-1.60.1-cp311-cp311-win_amd64.whl", hash = "sha256:c20e752ff5057758845f4e5c7a298739bfba291f373ed18ea9c7c7acbe69e8ab"}, + {file = "grpcio_tools-1.60.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:aafc94616c5f89c891d859057b194a153c451f9921053454e9d7d4cbf79047eb"}, + {file = "grpcio_tools-1.60.1-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:9bba347000f57dae8aea79c0d76ef7d72895597524d30d0170c7d1974a3a03f3"}, + {file = "grpcio_tools-1.60.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:1e96a532d38411f0543fe1903ff522f7142a9901afb0ed94de58d79caf1905be"}, + {file = "grpcio_tools-1.60.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ea6e397d87f458bb2c387a4a6e1b65df74ce5b5194a1f16850c38309012e981"}, + {file = "grpcio_tools-1.60.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3aeecd5b8faa2aab67e6c8b8a57e888c00ce70d39f331ede0a21312e92def1a6"}, + {file = "grpcio_tools-1.60.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:d2c26ce5f774c98bd2d3d8d1703048394018b55d297ebdb41ed2ba35b9a34f68"}, + {file = "grpcio_tools-1.60.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:214281cdafb7acfdcde848eca2de7c888a6e2b5cd25ab579712b965ea09a9cd4"}, + {file = "grpcio_tools-1.60.1-cp312-cp312-win32.whl", hash = "sha256:8c4b917aa4fcdc77990773063f0f14540aab8d4a8bf6c862b964a45d891a31d2"}, + {file = "grpcio_tools-1.60.1-cp312-cp312-win_amd64.whl", hash = "sha256:0aa34c7c21cff2177a4096b2b0d51dfbc9f8a41f929847a434e89b352c5a215d"}, + {file = "grpcio_tools-1.60.1-cp37-cp37m-linux_armv7l.whl", hash = "sha256:acdba77584981fe799104aa545d9d97910bcf88c69b668b768c1f3e7d7e5afac"}, + {file = "grpcio_tools-1.60.1-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:2a7fa55bc62d4b8ebe6fb26f8cf89df3cf3b504eb6c5f3a2f0174689d35fddb0"}, + {file = "grpcio_tools-1.60.1-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:dffa326cf901fe08a0e218d9fdf593f12276088a8caa07fcbec7d051149cf9ef"}, + {file = "grpcio_tools-1.60.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf945bd22f396c0d0c691e0990db2bfc4e77816b1edc2aea8a69c35ae721aac9"}, + {file = "grpcio_tools-1.60.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6801cfc5a85f0fb6fd12cade45942aaa1c814422328d594d12d364815fe34123"}, + {file = "grpcio_tools-1.60.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f95bdc6c7c50b7fc442e53537bc5b4eb8cab2a671c1da80d40b5a4ab1fd5d416"}, + {file = "grpcio_tools-1.60.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:402efeec36d8b12b792bae8a900085416fc2f57a34b599445ace2e847b6b0d75"}, + {file = "grpcio_tools-1.60.1-cp37-cp37m-win_amd64.whl", hash = "sha256:af88a2062b9c35034a80b25f289034b9c3c00c42bb88efaa465503a06fbd6a87"}, + {file = "grpcio_tools-1.60.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:46b495bae31c5d3f6ac0240eb848f0642b5410f80dff2aacdea20cdea3938c1d"}, + {file = "grpcio_tools-1.60.1-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:b5ae375207af9aa82f516dcd513d2e0c83690b7788d45844daad846ed87550f8"}, + {file = "grpcio_tools-1.60.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:15f13e8f3d77b96adcb1e3615acec5b100bd836c6010c58a51465bcb9c06d128"}, + {file = "grpcio_tools-1.60.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c354505e6a3d170da374f20404ea6a78135502df4f5534e5c532bdf24c4cc2a5"}, + {file = "grpcio_tools-1.60.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8cfab27ba2bd36a3e3b522aed686133531e8b919703d0247a0885dae8815317"}, + {file = "grpcio_tools-1.60.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b6ef213cb0aecb2832ee82a2eac32f29f31f50b17ce020604d82205096a6bd0c"}, + {file = "grpcio_tools-1.60.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0b62cb2d43a7f0eacc6a6962dfff7c2564874012e1a72ae4167e762f449e2912"}, + {file = "grpcio_tools-1.60.1-cp38-cp38-win32.whl", hash = "sha256:3fcabf484720a9fa1690e2825fc940027a05a0c79a1075a730008ef634bd8ad2"}, + {file = "grpcio_tools-1.60.1-cp38-cp38-win_amd64.whl", hash = "sha256:22ce3e3d861321d208d8bfd6161ab976623520b179712c90b2c175151463a6b1"}, + {file = "grpcio_tools-1.60.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:4e66fe204da15e08e599adb3060109a42927c0868fe8933e2d341ea649eceb03"}, + {file = "grpcio_tools-1.60.1-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:c1047bd831de5d9da761e9dc246988d5f07d722186938dfd5f34807398101010"}, + {file = "grpcio_tools-1.60.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:eba5fafd70585fbd4cb6ae45e3c5e11d8598e2426c9f289b78f682c0606e81cb"}, + {file = "grpcio_tools-1.60.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bba7230c60238c7a4ffa29f1aff6d78edb41f2c79cbe4443406472b1c80ccb5d"}, + {file = "grpcio_tools-1.60.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2bb8efc2cd64bd8f2779b426dd7e94e60924078ba5150cbbb60a846e62d1ed2"}, + {file = "grpcio_tools-1.60.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:26f91161a91f1601777751230eaaafdf416fed08a15c3ba2ae391088e4a906c6"}, + {file = "grpcio_tools-1.60.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2c19be2bba5583e30f88bb5d71b430176c396f0d6d0db3785e5845bfa3d28cd2"}, + {file = "grpcio_tools-1.60.1-cp39-cp39-win32.whl", hash = "sha256:9aadc9c00baa2064baa4414cff7c269455449f14805a355226674d89c507342c"}, + {file = "grpcio_tools-1.60.1-cp39-cp39-win_amd64.whl", hash = "sha256:652b08c9fef39186ce4f97f05f5440c0ed41f117db0f7d6cb0e0d75dbc6afd3f"}, ] [package.dependencies] -grpcio = ">=1.60.0" +grpcio = ">=1.60.1" protobuf = ">=4.21.6,<5.0dev" setuptools = "*" @@ -1696,13 +1696,13 @@ psutil = "*" [[package]] name = "ministryofjustice-data-platform-catalogue" -version = "0.8.1" +version = "0.10.0" description = "Library to integrate the MoJ data platform with the catalogue component." optional = false python-versions = ">=3.10,<4.0" files = [ - {file = "ministryofjustice_data_platform_catalogue-0.8.1-py3-none-any.whl", hash = "sha256:8dc0530f9458c66f7b8b62a83599039efb7ee4d2499f12abffa4634841378471"}, - {file = "ministryofjustice_data_platform_catalogue-0.8.1.tar.gz", hash = "sha256:4dcdd8f793033e0fc1356a1d2f8d6eb64e886fc690d32bde92d4f436f9ccdd07"}, + {file = "ministryofjustice_data_platform_catalogue-0.10.0-py3-none-any.whl", hash = "sha256:6818d4be3d7e87f655ee125f89ca3cc797aa2d79bc77b04fe1ec7f656a2c2ac0"}, + {file = "ministryofjustice_data_platform_catalogue-0.10.0.tar.gz", hash = "sha256:1d052dcd97afed31daef37a185d48dbbd1aedfdb81fe03227c9aea07727ad772"}, ] [package.dependencies] @@ -1729,85 +1729,101 @@ urllib3 = "*" [[package]] name = "multidict" -version = "6.0.4" +version = "6.0.5" description = "multidict implementation" optional = false python-versions = ">=3.7" files = [ - {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8"}, - {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eeb6dcc05e911516ae3d1f207d4b0520d07f54484c49dfc294d6e7d63b734171"}, - {file = "multidict-6.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d6d635d5209b82a3492508cf5b365f3446afb65ae7ebd755e70e18f287b0adf7"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c048099e4c9e9d615545e2001d3d8a4380bd403e1a0578734e0d31703d1b0c0b"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea20853c6dbbb53ed34cb4d080382169b6f4554d394015f1bef35e881bf83547"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16d232d4e5396c2efbbf4f6d4df89bfa905eb0d4dc5b3549d872ab898451f569"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36c63aaa167f6c6b04ef2c85704e93af16c11d20de1d133e39de6a0e84582a93"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64bdf1086b6043bf519869678f5f2757f473dee970d7abf6da91ec00acb9cb98"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:43644e38f42e3af682690876cff722d301ac585c5b9e1eacc013b7a3f7b696a0"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7582a1d1030e15422262de9f58711774e02fa80df0d1578995c76214f6954988"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ddff9c4e225a63a5afab9dd15590432c22e8057e1a9a13d28ed128ecf047bbdc"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ee2a1ece51b9b9e7752e742cfb661d2a29e7bcdba2d27e66e28a99f1890e4fa0"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a2e4369eb3d47d2034032a26c7a80fcb21a2cb22e1173d761a162f11e562caa5"}, - {file = "multidict-6.0.4-cp310-cp310-win32.whl", hash = "sha256:574b7eae1ab267e5f8285f0fe881f17efe4b98c39a40858247720935b893bba8"}, - {file = "multidict-6.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:4dcbb0906e38440fa3e325df2359ac6cb043df8e58c965bb45f4e406ecb162cc"}, - {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0dfad7a5a1e39c53ed00d2dd0c2e36aed4650936dc18fd9a1826a5ae1cad6f03"}, - {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:64da238a09d6039e3bd39bb3aee9c21a5e34f28bfa5aa22518581f910ff94af3"}, - {file = "multidict-6.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c5cb09abb18c1ea940fb99360ea0396f34d46566f157122c92dfa069d3e0e982"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666daae833559deb2d609afa4490b85830ab0dfca811a98b70a205621a6109fe"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11bdf3f5e1518b24530b8241529d2050014c884cf18b6fc69c0c2b30ca248710"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d18748f2d30f94f498e852c67d61261c643b349b9d2a581131725595c45ec6c"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:458f37be2d9e4c95e2d8866a851663cbc76e865b78395090786f6cd9b3bbf4f4"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b1a2eeedcead3a41694130495593a559a668f382eee0727352b9a41e1c45759a"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7d6ae9d593ef8641544d6263c7fa6408cc90370c8cb2bbb65f8d43e5b0351d9c"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5979b5632c3e3534e42ca6ff856bb24b2e3071b37861c2c727ce220d80eee9ed"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dcfe792765fab89c365123c81046ad4103fcabbc4f56d1c1997e6715e8015461"}, - {file = "multidict-6.0.4-cp311-cp311-win32.whl", hash = "sha256:3601a3cece3819534b11d4efc1eb76047488fddd0c85a3948099d5da4d504636"}, - {file = "multidict-6.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:81a4f0b34bd92df3da93315c6a59034df95866014ac08535fc819f043bfd51f0"}, - {file = "multidict-6.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:67040058f37a2a51ed8ea8f6b0e6ee5bd78ca67f169ce6122f3e2ec80dfe9b78"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:853888594621e6604c978ce2a0444a1e6e70c8d253ab65ba11657659dcc9100f"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:39ff62e7d0f26c248b15e364517a72932a611a9b75f35b45be078d81bdb86603"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af048912e045a2dc732847d33821a9d84ba553f5c5f028adbd364dd4765092ac"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1e8b901e607795ec06c9e42530788c45ac21ef3aaa11dbd0c69de543bfb79a9"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62501642008a8b9871ddfccbf83e4222cf8ac0d5aeedf73da36153ef2ec222d2"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:99b76c052e9f1bc0721f7541e5e8c05db3941eb9ebe7b8553c625ef88d6eefde"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:509eac6cf09c794aa27bcacfd4d62c885cce62bef7b2c3e8b2e49d365b5003fe"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:21a12c4eb6ddc9952c415f24eef97e3e55ba3af61f67c7bc388dcdec1404a067"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:5cad9430ab3e2e4fa4a2ef4450f548768400a2ac635841bc2a56a2052cdbeb87"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ab55edc2e84460694295f401215f4a58597f8f7c9466faec545093045476327d"}, - {file = "multidict-6.0.4-cp37-cp37m-win32.whl", hash = "sha256:5a4dcf02b908c3b8b17a45fb0f15b695bf117a67b76b7ad18b73cf8e92608775"}, - {file = "multidict-6.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6ed5f161328b7df384d71b07317f4d8656434e34591f20552c7bcef27b0ab88e"}, - {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5fc1b16f586f049820c5c5b17bb4ee7583092fa0d1c4e28b5239181ff9532e0c"}, - {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1502e24330eb681bdaa3eb70d6358e818e8e8f908a22a1851dfd4e15bc2f8161"}, - {file = "multidict-6.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b692f419760c0e65d060959df05f2a531945af31fda0c8a3b3195d4efd06de11"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45e1ecb0379bfaab5eef059f50115b54571acfbe422a14f668fc8c27ba410e7e"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddd3915998d93fbcd2566ddf9cf62cdb35c9e093075f862935573d265cf8f65d"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:59d43b61c59d82f2effb39a93c48b845efe23a3852d201ed2d24ba830d0b4cf2"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc8e1d0c705233c5dd0c5e6460fbad7827d5d36f310a0fadfd45cc3029762258"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6aa0418fcc838522256761b3415822626f866758ee0bc6632c9486b179d0b52"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6748717bb10339c4760c1e63da040f5f29f5ed6e59d76daee30305894069a660"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4d1a3d7ef5e96b1c9e92f973e43aa5e5b96c659c9bc3124acbbd81b0b9c8a951"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4372381634485bec7e46718edc71528024fcdc6f835baefe517b34a33c731d60"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:fc35cb4676846ef752816d5be2193a1e8367b4c1397b74a565a9d0389c433a1d"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b9d9e4e2b37daddb5c23ea33a3417901fa7c7b3dee2d855f63ee67a0b21e5b1"}, - {file = "multidict-6.0.4-cp38-cp38-win32.whl", hash = "sha256:e41b7e2b59679edfa309e8db64fdf22399eec4b0b24694e1b2104fb789207779"}, - {file = "multidict-6.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:d6c254ba6e45d8e72739281ebc46ea5eb5f101234f3ce171f0e9f5cc86991480"}, - {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:16ab77bbeb596e14212e7bab8429f24c1579234a3a462105cda4a66904998664"}, - {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc779e9e6f7fda81b3f9aa58e3a6091d49ad528b11ed19f6621408806204ad35"}, - {file = "multidict-6.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ceef517eca3e03c1cceb22030a3e39cb399ac86bff4e426d4fc6ae49052cc60"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:281af09f488903fde97923c7744bb001a9b23b039a909460d0f14edc7bf59706"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52f2dffc8acaba9a2f27174c41c9e57f60b907bb9f096b36b1a1f3be71c6284d"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b41156839806aecb3641f3208c0dafd3ac7775b9c4c422d82ee2a45c34ba81ca"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5e3fc56f88cc98ef8139255cf8cd63eb2c586531e43310ff859d6bb3a6b51f1"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8316a77808c501004802f9beebde51c9f857054a0c871bd6da8280e718444449"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f70b98cd94886b49d91170ef23ec5c0e8ebb6f242d734ed7ed677b24d50c82cf"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bf6774e60d67a9efe02b3616fee22441d86fab4c6d335f9d2051d19d90a40063"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:e69924bfcdda39b722ef4d9aa762b2dd38e4632b3641b1d9a57ca9cd18f2f83a"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:6b181d8c23da913d4ff585afd1155a0e1194c0b50c54fcfe286f70cdaf2b7176"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52509b5be062d9eafc8170e53026fbc54cf3b32759a23d07fd935fb04fc22d95"}, - {file = "multidict-6.0.4-cp39-cp39-win32.whl", hash = "sha256:27c523fbfbdfd19c6867af7346332b62b586eed663887392cff78d614f9ec313"}, - {file = "multidict-6.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:33029f5734336aa0d4c0384525da0387ef89148dc7191aae00ca5fb23d7aafc2"}, - {file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"}, + {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9"}, + {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604"}, + {file = "multidict-6.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc"}, + {file = "multidict-6.0.5-cp310-cp310-win32.whl", hash = "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319"}, + {file = "multidict-6.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e"}, + {file = "multidict-6.0.5-cp311-cp311-win32.whl", hash = "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c"}, + {file = "multidict-6.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda"}, + {file = "multidict-6.0.5-cp312-cp312-win32.whl", hash = "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5"}, + {file = "multidict-6.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556"}, + {file = "multidict-6.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc"}, + {file = "multidict-6.0.5-cp37-cp37m-win32.whl", hash = "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee"}, + {file = "multidict-6.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423"}, + {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54"}, + {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d"}, + {file = "multidict-6.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44"}, + {file = "multidict-6.0.5-cp38-cp38-win32.whl", hash = "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241"}, + {file = "multidict-6.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c"}, + {file = "multidict-6.0.5-cp39-cp39-win32.whl", hash = "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b"}, + {file = "multidict-6.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755"}, + {file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"}, + {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, ] [[package]] @@ -1855,13 +1871,13 @@ setuptools = "*" [[package]] name = "openmetadata-ingestion" -version = "1.2.5.0" +version = "1.2.5.1" description = "Ingestion Framework for OpenMetadata" optional = false python-versions = ">=3.8" files = [ - {file = "openmetadata-ingestion-1.2.5.0.tar.gz", hash = "sha256:2573d1f25e7afa9e3a5836c1e1e156ae6ba945ebea2e712526d827bfcb682fcd"}, - {file = "openmetadata_ingestion-1.2.5.0-py3-none-any.whl", hash = "sha256:b5334bbc932b9c01f410c65957969c592685f28d0e11f894862db149474a6dcf"}, + {file = "openmetadata-ingestion-1.2.5.1.tar.gz", hash = "sha256:3df74dacd60d05b6ca9daa739ec9f65f6bb82dbea262d1e911133cc903885a21"}, + {file = "openmetadata_ingestion-1.2.5.1-py3-none-any.whl", hash = "sha256:a9b58c8f3f0122626217699bcce9db3fd5b5ca7262901f0efc714c9f48467757"}, ] [package.dependencies] @@ -1870,7 +1886,7 @@ avro = ">=1.11,<2.0" boto3 = ">=1.20,<2.0" cached-property = "1.5.2" chardet = "4.0.0" -collate-sqllineage = ">=1.0.4" +collate-sqllineage = ">=1.0.4,<1.3" croniter = ">=1.3.0,<1.4.0" cryptography = "*" email-validator = ">=1.0.3" @@ -1900,13 +1916,13 @@ wheel = ">=0.38.4,<0.39.0" [package.extras] airflow = ["apache-airflow (==2.6.3)", "attrs"] -all = ["GeoAlchemy2 (>=0.12,<1.0)", "Jinja2 (>=2.11.3)", "PyYAML (>=6.0,<7.0)", "adlfs (>=2022.2.0)", "alembic (>=1.10.2,<1.11.0)", "antlr4-python3-runtime (==4.9.2)", "avro (>=1.11,<2.0)", "azure-identity", "azure-identity (>=1.12,<2.0)", "azure-storage-blob", "azure-storage-blob (>=12.14,<13.0)", "boto3 (>=1.20,<2.0)", "cached-property (==1.5.2)", "cachetools", "chardet (==4.0.0)", "clickhouse-driver (>=0.2,<1.0)", "clickhouse-sqlalchemy (>=0.2,<1.0)", "collate-sqllineage (>=1.0.4)", "confluent-kafka (==2.1.1)", "couchbase (>=4.1,<5.0)", "croniter (>=1.3.0,<1.4.0)", "cryptography", "cx-Oracle (>=8.3.0,<9)", "dagster-graphql (>=1.1,<2.0)", "databricks-sdk (>=0.1,<1.0)", "dbt-artifacts-parser", "delta-spark (<=2.3.0)", "elasticsearch (==7.13.1)", "elasticsearch8 (>=8.9.0,<8.10.0)", "email-validator (>=1.0.3)", "fastavro (>=1.2.0)", "gcsfs (==2022.11.0)", "gitpython (>=3.1.34,<3.2.0)", "giturlparse", "google (>=3.0.0)", "google-auth (>=1.33.0)", "google-cloud", "google-cloud-datacatalog (>=3.6.2)", "google-cloud-logging", "google-cloud-storage (==1.43.0)", "grpcio-tools (>=1.47.2)", "hdbcli", "idna (>=2.5,<3)", "importlib-metadata (>=4.13.0)", "impyla (>=0.18.0,<0.19.0)", "impyla[kerberos] (>=0.18.0,<0.19.0)", "jsonpatch (==1.32)", "jsonschema", "ldap3 (==2.9.1)", "lkml (>=1.3,<2.0)", "looker-sdk (>=22.20.0)", "memory-profiler", "mlflow-skinny (>=2.3.0)", "msal (>=1.2,<2.0)", "mypy-extensions (>=0.4.3)", "neo4j (>=5.3.0,<5.4.0)", "okta (>=2.3,<3.0)", "oracledb (>=1.2,<2.0)", "packaging (==21.3)", "pandas (==1.3.5)", "pinotdb (>=0.3,<1.0)", "presidio-analyzer (==2.2.32)", "presto-types-parser (>=0.0.2)", "protobuf", "psycopg2-binary", "pyarrow (>=10.0,<11.0)", "pyathena (==3.0.8)", "pydantic (>=1.10,<2.0)", "pydomo (>=0.3,<1.0)", "pydruid (>=0.6.5)", "pyhive (>=0.7,<1.0)", "pymongo (>=4.3,<5.0)", "pymssql (>=2.2.0,<2.3.0)", "pymysql (>=1.0.2)", "pyodbc (>=4.0.35,<5)", "python-dateutil (>=2.8.1)", "python-jose (>=3.3,<4.0)", "python-on-whales (==0.55.0)", "python-snappy (>=0.6.1,<0.7.0)", "requests (>=2.23)", "requests-aws4auth (>=1.1,<2.0)", "s3fs (==0.4.2)", "sasl (>=0.3,<1.0)", "scikit-learn (>=1.0,<2.0)", "setuptools (>=66.0.0,<66.1.0)", "simple-salesforce (==1.11.4)", "snowflake-sqlalchemy (>=1.4,<2.0)", "spacy (==3.5.0)", "sqlalchemy (>=1.4.0,<2)", "sqlalchemy-bigquery (>=1.2.2)", "sqlalchemy-databricks (>=0.1,<1.0)", "sqlalchemy-hana", "sqlalchemy-pgspider", "sqlalchemy-pytds (>=0.3,<1.0)", "sqlalchemy-redshift (==0.8.12)", "sqlalchemy-vertica[vertica-python] (>=0.0.5)", "tableau-api-lib (>=0.1,<1.0)", "tabulate (==0.9.0)", "thrift (>=0.13,<1)", "thrift-sasl (>=0.4,<1.0)", "trino[sqlalchemy]", "typing-compat (>=0.1.0,<0.2.0)", "typing-inspect", "websocket-client (>=1.6.1,<1.7.0)", "wheel (>=0.38.4,<0.39.0)"] +all = ["GeoAlchemy2 (>=0.12,<1.0)", "Jinja2 (>=2.11.3)", "PyYAML (>=6.0,<7.0)", "adlfs (>=2022.2.0)", "alembic (>=1.10.2,<1.11.0)", "antlr4-python3-runtime (==4.9.2)", "avro (>=1.11,<2.0)", "azure-identity", "azure-identity (>=1.12,<2.0)", "azure-storage-blob", "azure-storage-blob (>=12.14,<13.0)", "boto3 (>=1.20,<2.0)", "cached-property (==1.5.2)", "cachetools", "chardet (==4.0.0)", "clickhouse-driver (>=0.2,<1.0)", "clickhouse-sqlalchemy (>=0.2,<1.0)", "collate-sqllineage (>=1.0.4,<1.3)", "confluent-kafka (==2.1.1)", "couchbase (>=4.1,<5.0)", "croniter (>=1.3.0,<1.4.0)", "cryptography", "cx-Oracle (>=8.3.0,<9)", "dagster-graphql (>=1.1,<2.0)", "databricks-sdk (>=0.1,<1.0)", "dbt-artifacts-parser", "delta-spark (<=2.3.0)", "elasticsearch (==7.13.1)", "elasticsearch8 (>=8.9.0,<8.10.0)", "email-validator (>=1.0.3)", "fastavro (>=1.2.0)", "gcsfs (==2022.11.0)", "gitpython (>=3.1.34,<3.2.0)", "giturlparse", "google (>=3.0.0)", "google-auth (>=1.33.0)", "google-cloud", "google-cloud-datacatalog (>=3.6.2)", "google-cloud-logging", "google-cloud-storage (==1.43.0)", "grpcio-tools (>=1.47.2)", "hdbcli", "idna (>=2.5,<3)", "importlib-metadata (>=4.13.0)", "impyla (>=0.18.0,<0.19.0)", "impyla[kerberos] (>=0.18.0,<0.19.0)", "jsonpatch (==1.32)", "jsonschema", "ldap3 (==2.9.1)", "lkml (>=1.3,<2.0)", "looker-sdk (>=22.20.0)", "memory-profiler", "mlflow-skinny (>=2.3.0)", "msal (>=1.2,<2.0)", "mypy-extensions (>=0.4.3)", "neo4j (>=5.3.0,<5.4.0)", "okta (>=2.3,<3.0)", "oracledb (>=1.2,<2.0)", "packaging (==21.3)", "pandas (==1.3.5)", "pinotdb (>=0.3,<1.0)", "presidio-analyzer (==2.2.32)", "presto-types-parser (>=0.0.2)", "protobuf", "psycopg2-binary", "pyarrow (>=10.0,<11.0)", "pyathena (==3.0.8)", "pydantic (>=1.10,<2.0)", "pydomo (>=0.3,<1.0)", "pydruid (>=0.6.5)", "pyhive (>=0.7,<1.0)", "pymongo (>=4.3,<5.0)", "pymssql (>=2.2.0,<2.3.0)", "pymysql (>=1.0.2)", "pyodbc (>=4.0.35,<5)", "python-dateutil (>=2.8.1)", "python-jose (>=3.3,<4.0)", "python-on-whales (==0.55.0)", "python-snappy (>=0.6.1,<0.7.0)", "requests (>=2.23)", "requests-aws4auth (>=1.1,<2.0)", "s3fs (==0.4.2)", "sasl (>=0.3,<1.0)", "scikit-learn (>=1.0,<2.0)", "setuptools (>=66.0.0,<66.1.0)", "simple-salesforce (==1.11.4)", "snowflake-sqlalchemy (>=1.4,<2.0)", "spacy (==3.5.0)", "sqlalchemy (>=1.4.0,<2)", "sqlalchemy-bigquery (>=1.2.2)", "sqlalchemy-databricks (>=0.1,<1.0)", "sqlalchemy-hana", "sqlalchemy-pgspider", "sqlalchemy-pytds (>=0.3,<1.0)", "sqlalchemy-redshift (==0.8.12)", "sqlalchemy-vertica[vertica-python] (>=0.0.5)", "tableau-api-lib (>=0.1,<1.0)", "tabulate (==0.9.0)", "thrift (>=0.13,<1)", "thrift-sasl (>=0.4,<1.0)", "trino[sqlalchemy]", "typing-compat (>=0.1.0,<0.2.0)", "typing-inspect", "websocket-client (>=1.6.1,<1.7.0)", "wheel (>=0.38.4,<0.39.0)"] amundsen = ["neo4j (>=5.3.0,<5.4.0)"] athena = ["pyathena (==3.0.8)"] azure-sso = ["msal (>=1.2,<2.0)"] azuresql = ["pyodbc (>=4.0.35,<5)"] backup = ["azure-identity", "azure-storage-blob", "boto3 (>=1.20,<2.0)"] -base = ["Jinja2 (>=2.11.3)", "PyYAML (>=6.0,<7.0)", "antlr4-python3-runtime (==4.9.2)", "avro (>=1.11,<2.0)", "boto3 (>=1.20,<2.0)", "cached-property (==1.5.2)", "chardet (==4.0.0)", "collate-sqllineage (>=1.0.4)", "croniter (>=1.3.0,<1.4.0)", "cryptography", "email-validator (>=1.0.3)", "google (>=3.0.0)", "google-auth (>=1.33.0)", "grpcio-tools (>=1.47.2)", "idna (>=2.5,<3)", "importlib-metadata (>=4.13.0)", "jsonpatch (==1.32)", "jsonschema", "memory-profiler", "mypy-extensions (>=0.4.3)", "pydantic (>=1.10,<2.0)", "pymysql (>=1.0.2)", "python-dateutil (>=2.8.1)", "python-jose (>=3.3,<4.0)", "requests (>=2.23)", "requests-aws4auth (>=1.1,<2.0)", "setuptools (>=66.0.0,<66.1.0)", "sqlalchemy (>=1.4.0,<2)", "tabulate (==0.9.0)", "typing-compat (>=0.1.0,<0.2.0)", "typing-inspect", "wheel (>=0.38.4,<0.39.0)"] +base = ["Jinja2 (>=2.11.3)", "PyYAML (>=6.0,<7.0)", "antlr4-python3-runtime (==4.9.2)", "avro (>=1.11,<2.0)", "boto3 (>=1.20,<2.0)", "cached-property (==1.5.2)", "chardet (==4.0.0)", "collate-sqllineage (>=1.0.4,<1.3)", "croniter (>=1.3.0,<1.4.0)", "cryptography", "email-validator (>=1.0.3)", "google (>=3.0.0)", "google-auth (>=1.33.0)", "grpcio-tools (>=1.47.2)", "idna (>=2.5,<3)", "importlib-metadata (>=4.13.0)", "jsonpatch (==1.32)", "jsonschema", "memory-profiler", "mypy-extensions (>=0.4.3)", "pydantic (>=1.10,<2.0)", "pymysql (>=1.0.2)", "python-dateutil (>=2.8.1)", "python-jose (>=3.3,<4.0)", "requests (>=2.23)", "requests-aws4auth (>=1.1,<2.0)", "setuptools (>=66.0.0,<66.1.0)", "sqlalchemy (>=1.4.0,<2)", "tabulate (==0.9.0)", "typing-compat (>=0.1.0,<0.2.0)", "typing-inspect", "wheel (>=0.38.4,<0.39.0)"] bigquery = ["cachetools", "google-cloud-datacatalog (>=3.6.2)", "google-cloud-logging", "pyarrow (>=10.0,<11.0)", "sqlalchemy-bigquery (>=1.2.2)"] clickhouse = ["clickhouse-driver (>=0.2,<1.0)", "clickhouse-sqlalchemy (>=0.2,<1.0)"] couchbase = ["couchbase (>=4.1,<5.0)"] @@ -2002,18 +2018,18 @@ files = [ [[package]] name = "platformdirs" -version = "4.1.0" +version = "4.2.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, - {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, + {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, + {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, ] [package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] [[package]] name = "pluggy" @@ -2245,20 +2261,20 @@ files = [ [[package]] name = "pytest" -version = "7.4.4" +version = "8.0.0" description = "pytest: simple powerful testing with Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, - {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, + {file = "pytest-8.0.0-py3-none-any.whl", hash = "sha256:50fb9cbe836c3f20f0dfa99c565201fb75dc54c8d76373cd1bde06b06657bdb6"}, + {file = "pytest-8.0.0.tar.gz", hash = "sha256:249b1b0864530ba251b7438274c4d251c58d868edaaec8762893ad4a0d71c36c"}, ] [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} iniconfig = "*" packaging = "*" -pluggy = ">=0.12,<2.0" +pluggy = ">=1.3.0,<2.0" [package.extras] testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] @@ -2379,6 +2395,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -2415,13 +2432,13 @@ files = [ [[package]] name = "referencing" -version = "0.32.1" +version = "0.33.0" description = "JSON Referencing + Python" optional = false python-versions = ">=3.8" files = [ - {file = "referencing-0.32.1-py3-none-any.whl", hash = "sha256:7e4dc12271d8e15612bfe35792f5ea1c40970dadf8624602e33db2758f7ee554"}, - {file = "referencing-0.32.1.tar.gz", hash = "sha256:3c57da0513e9563eb7e203ebe9bb3a1b509b042016433bd1e45a2853466c3dd3"}, + {file = "referencing-0.33.0-py3-none-any.whl", hash = "sha256:39240f2ecc770258f28b642dd47fd74bc8b02484de54e1882b74b35ebd779bd5"}, + {file = "referencing-0.33.0.tar.gz", hash = "sha256:c775fedf74bc0f9189c2a3be1c12fd03e8c23f4d371dce795df44e06c5b412f7"}, ] [package.dependencies] @@ -2571,18 +2588,17 @@ httpx = ["httpx"] [[package]] name = "requests-file" -version = "1.5.1" +version = "2.0.0" description = "File transport adapter for Requests" optional = false python-versions = "*" files = [ - {file = "requests-file-1.5.1.tar.gz", hash = "sha256:07d74208d3389d01c38ab89ef403af0cfec63957d53a0081d8eca738d0247d8e"}, - {file = "requests_file-1.5.1-py2.py3-none-any.whl", hash = "sha256:dfe5dae75c12481f68ba353183c53a65e6044c923e64c24b2209f6c7570ca953"}, + {file = "requests-file-2.0.0.tar.gz", hash = "sha256:20c5931629c558fda566cacc10cfe2cd502433e628f568c34c80d96a0cc95972"}, + {file = "requests_file-2.0.0-py2.py3-none-any.whl", hash = "sha256:3e493d390adb44aa102ebea827a48717336d5268968c370eaf19abaf5cae13bf"}, ] [package.dependencies] requests = ">=1.0.0" -six = "*" [[package]] name = "rpds-py" @@ -2802,13 +2818,13 @@ crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"] [[package]] name = "sentry-sdk" -version = "1.39.2" +version = "1.40.0" description = "Python client for Sentry (https://sentry.io)" optional = false python-versions = "*" files = [ - {file = "sentry-sdk-1.39.2.tar.gz", hash = "sha256:24c83b0b41c887d33328a9166f5950dc37ad58f01c9f2fbff6b87a6f1094170c"}, - {file = "sentry_sdk-1.39.2-py2.py3-none-any.whl", hash = "sha256:acaf597b30258fc7663063b291aa99e58f3096e91fe1e6634f4b79f9c1943e8e"}, + {file = "sentry-sdk-1.40.0.tar.gz", hash = "sha256:34ad8cfc9b877aaa2a8eb86bfe5296a467fffe0619b931a05b181c45f6da59bf"}, + {file = "sentry_sdk-1.40.0-py2.py3-none-any.whl", hash = "sha256:78575620331186d32f34b7ece6edea97ce751f58df822547d3ab85517881a27a"}, ] [package.dependencies] @@ -2834,7 +2850,7 @@ huey = ["huey (>=2)"] loguru = ["loguru (>=0.5)"] opentelemetry = ["opentelemetry-distro (>=0.35b0)"] opentelemetry-experimental = ["opentelemetry-distro (>=0.40b0,<1.0)", "opentelemetry-instrumentation-aiohttp-client (>=0.40b0,<1.0)", "opentelemetry-instrumentation-django (>=0.40b0,<1.0)", "opentelemetry-instrumentation-fastapi (>=0.40b0,<1.0)", "opentelemetry-instrumentation-flask (>=0.40b0,<1.0)", "opentelemetry-instrumentation-requests (>=0.40b0,<1.0)", "opentelemetry-instrumentation-sqlite3 (>=0.40b0,<1.0)", "opentelemetry-instrumentation-urllib (>=0.40b0,<1.0)"] -pure-eval = ["asttokens", "executing", "pure_eval"] +pure-eval = ["asttokens", "executing", "pure-eval"] pymongo = ["pymongo (>=3.1)"] pyspark = ["pyspark (>=2.4.4)"] quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] @@ -3387,4 +3403,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "df94a5200f0f8d5f60aebdad98a6170f2f238838a9261d1b8d604a668593d804" +content-hash = "429ad4f0963ec675ccf5649e25e685103ac516030f18c6fe5e4dc11e63124afc" diff --git a/pyproject.toml b/pyproject.toml index 3b0fe90a..360ad6b2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ django = "^5.0.1" pyyaml = "^6.0.1" gunicorn = "^21.2.0" whitenoise = "^6.6.0" -ministryofjustice-data-platform-catalogue = "^0.8.1" +ministryofjustice-data-platform-catalogue = "^0.10.0" markdown = "^3.5.2" python-dotenv = "^1.0.1" diff --git a/templates/base/navigation.html b/templates/base/navigation.html index 0cc64bcc..b1d29e00 100644 --- a/templates/base/navigation.html +++ b/templates/base/navigation.html @@ -31,7 +31,7 @@
  • - + Search
  • diff --git a/templates/partial/pagination.html b/templates/partial/pagination.html index 56ae6962..bcebe556 100644 --- a/templates/partial/pagination.html +++ b/templates/partial/pagination.html @@ -15,7 +15,7 @@ {% else %}
  • {% endif %} - + {{ p }}
  • From 596937b93209c14911e0001f28e5c0117bdae122 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 2 Feb 2024 14:25:32 +0000 Subject: [PATCH 069/221] Commit changes made by code formatters --- home/helper.py | 1 + home/views.py | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/home/helper.py b/home/helper.py index cb119111..fecc2622 100644 --- a/home/helper.py +++ b/home/helper.py @@ -5,6 +5,7 @@ def filter_seleted_domains(domain_list, domains): selected_domain[domain.value] = domain.label return selected_domain + def get_domain_list(client): facets = client.search_facets() domain_list = facets.options("domains") diff --git a/home/views.py b/home/views.py index 8da1e71e..2bcfc8b5 100644 --- a/home/views.py +++ b/home/views.py @@ -31,7 +31,7 @@ def details_view(request, id): def search_view(request, page: str = "1"): - + new_search = request.GET.get("new", "") page_for_search = str(int(page) - 1) @@ -43,7 +43,7 @@ def search_view(request, page: str = "1"): domains = request.GET.getlist("domain", []) sortby = request.GET.get("sortby", None) - context["sortby"]=sortby + context["sortby"] = sortby if sortby == "ascending": sort = SortOption(field="name", ascending=True) @@ -88,7 +88,7 @@ def search_view(request, page: str = "1"): filter_value = [MultiSelectFilter("domains", domains)] elif request.GET.get("query"): - query=request.GET.get("query") + query = request.GET.get("query") print("query", query) domains = request.session.get("domains", None) request.session["query"] = query @@ -104,13 +104,13 @@ def search_view(request, page: str = "1"): context["domains"] = domains filter_value = [MultiSelectFilter("domains", domains)] else: - if page=="1" and new_search: + if page == "1" and new_search: filter_value = [] - + request.session.clear() request.session["domains"] = domains context["selected_domain"] = {} - context["query"]="" + context["query"] = "" else: domains = request.session.get("domains", []) filter_value = [] From 74a203176d24f0b2283a9fbfaa6f6e6c40e84a4f Mon Sep 17 00:00:00 2001 From: "priya.basker" Date: Fri, 2 Feb 2024 15:04:40 +0000 Subject: [PATCH 070/221] fixed pagination --- home/views.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/home/views.py b/home/views.py index 2bcfc8b5..65c8f4a1 100644 --- a/home/views.py +++ b/home/views.py @@ -31,9 +31,8 @@ def details_view(request, id): def search_view(request, page: str = "1"): - new_search = request.GET.get("new", "") - + query=request.GET.get("query", "") page_for_search = str(int(page) - 1) client = get_catalogue_client() domain_list = get_domain_list(client) @@ -88,8 +87,7 @@ def search_view(request, page: str = "1"): filter_value = [MultiSelectFilter("domains", domains)] elif request.GET.get("query"): - query = request.GET.get("query") - print("query", query) + query=request.GET.get("query") domains = request.session.get("domains", None) request.session["query"] = query context["query"] = query @@ -106,7 +104,6 @@ def search_view(request, page: str = "1"): else: if page == "1" and new_search: filter_value = [] - request.session.clear() request.session["domains"] = domains context["selected_domain"] = {} @@ -120,7 +117,7 @@ def search_view(request, page: str = "1"): query = request.session.get("query", "") # Search with filter - query = request.GET.get("query", "") + search_results = client.search( query=query, page=page_for_search, filters=filter_value, sort=sort ) From f1f9106118be5da9603fc1e6add708e1b92cc556 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 2 Feb 2024 15:06:02 +0000 Subject: [PATCH 071/221] Commit changes made by code formatters --- home/views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/home/views.py b/home/views.py index 65c8f4a1..e36c3e70 100644 --- a/home/views.py +++ b/home/views.py @@ -32,7 +32,7 @@ def details_view(request, id): def search_view(request, page: str = "1"): new_search = request.GET.get("new", "") - query=request.GET.get("query", "") + query = request.GET.get("query", "") page_for_search = str(int(page) - 1) client = get_catalogue_client() domain_list = get_domain_list(client) @@ -87,7 +87,7 @@ def search_view(request, page: str = "1"): filter_value = [MultiSelectFilter("domains", domains)] elif request.GET.get("query"): - query=request.GET.get("query") + query = request.GET.get("query") domains = request.session.get("domains", None) request.session["query"] = query context["query"] = query @@ -117,7 +117,7 @@ def search_view(request, page: str = "1"): query = request.session.get("query", "") # Search with filter - + search_results = client.search( query=query, page=page_for_search, filters=filter_value, sort=sort ) From ec142a95be63dbbff24505d0de0eeca9500f06f8 Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Fri, 2 Feb 2024 15:35:41 +0000 Subject: [PATCH 072/221] Add some starter tests --- home/test_views.py | 60 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 home/test_views.py diff --git a/home/test_views.py b/home/test_views.py new file mode 100644 index 00000000..69322733 --- /dev/null +++ b/home/test_views.py @@ -0,0 +1,60 @@ +from unittest import skip + +from django.test import SimpleTestCase +from django.urls import reverse + + +class SearchViewTests(SimpleTestCase): + """ + Test the view renders the correct context depending on query parameters and session + + TODO: this should stub out the search client and use dummy results + """ + + def test_renders_200(self): + response = self.client.get(reverse("home:search"), data={}) + self.assertEqual(response.status_code, 200) + + def test_exposes_results(self): + response = self.client.get(reverse("home:search"), data={}) + self.assertEqual(response.status_code, 200) + self.assertEqual(len(response.context["results"]), 20) + + @skip("possibly broken") + def test_exposes_domains(self): + response = self.client.get(reverse("home:search"), data={}) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context["selected_domain"], {}) + self.assertGreater(len(response.context["domains"]), 0) + + def test_exposes_empty_query(self): + response = self.client.get(reverse("home:search"), data={}) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context["query"], "") + + def test_exposes_query(self): + response = self.client.get(reverse("home:search"), data={"query": "foo"}) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context["query"], "foo") + + @skip("possibly broken") + def test_exposes_filter(self): + response = self.client.get( + reverse("home:search"), data={"domain": ["urn:li:domain:HMCTS"]} + ) + self.assertEqual(response.status_code, 200) + self.assertEqual( + response.context["selected_domain"], {"urn:li:domain:HMCTS": "HMCTS"} + ) + self.assertEqual(len(response.context["domains"]), 0) + + @skip("possibly broken") + def test_exposes_filter_and_query(self): + response = self.client.get( + reverse("home:search"), + data={"domain": ["urn:li:domain:HMCTS"], "query": "courts"}, + ) + self.assertEqual( + response.context["selected_domain"], {"urn:li:domain:HMCTS": "HMCTS"} + ) + self.assertEqual(response.context["query"], "courts") From 936d7cce01324782be7358b29a855a87b64474a4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 2 Feb 2024 15:36:36 +0000 Subject: [PATCH 073/221] Commit changes made by code formatters --- home/test_views.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/home/test_views.py b/home/test_views.py index 69322733..3b027df5 100644 --- a/home/test_views.py +++ b/home/test_views.py @@ -33,7 +33,8 @@ def test_exposes_empty_query(self): self.assertEqual(response.context["query"], "") def test_exposes_query(self): - response = self.client.get(reverse("home:search"), data={"query": "foo"}) + response = self.client.get( + reverse("home:search"), data={"query": "foo"}) self.assertEqual(response.status_code, 200) self.assertEqual(response.context["query"], "foo") @@ -44,7 +45,8 @@ def test_exposes_filter(self): ) self.assertEqual(response.status_code, 200) self.assertEqual( - response.context["selected_domain"], {"urn:li:domain:HMCTS": "HMCTS"} + response.context["selected_domain"], { + "urn:li:domain:HMCTS": "HMCTS"} ) self.assertEqual(len(response.context["domains"]), 0) @@ -55,6 +57,7 @@ def test_exposes_filter_and_query(self): data={"domain": ["urn:li:domain:HMCTS"], "query": "courts"}, ) self.assertEqual( - response.context["selected_domain"], {"urn:li:domain:HMCTS": "HMCTS"} + response.context["selected_domain"], { + "urn:li:domain:HMCTS": "HMCTS"} ) self.assertEqual(response.context["query"], "courts") From e8e5ff1a933f62cb1e83d7b487e59d8bfeb481a1 Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Fri, 2 Feb 2024 17:07:32 +0000 Subject: [PATCH 074/221] Speed up tests by mocking out the catalogue client --- home/test_views.py | 68 +++++++++++++++++++++- poetry.lock | 141 +++++++++++++++++++++++++-------------------- pyproject.toml | 1 + 3 files changed, 144 insertions(+), 66 deletions(-) diff --git a/home/test_views.py b/home/test_views.py index 3b027df5..23d3af0e 100644 --- a/home/test_views.py +++ b/home/test_views.py @@ -1,16 +1,80 @@ +from random import choice from unittest import skip +from unittest.mock import MagicMock, patch +from data_platform_catalogue.client import BaseCatalogueClient +from data_platform_catalogue.search_types import ( + FacetOption, + ResultType, + SearchFacets, + SearchResponse, + SearchResult, +) from django.test import SimpleTestCase from django.urls import reverse +from faker import Faker + +fake = Faker() + + +def generate_page(page_size=20): + """ + Generate a fake search page + """ + results = [] + for _ in range(page_size): + results.append( + SearchResult( + id=fake.unique.name(), + result_type=choice((ResultType.DATA_PRODUCT, ResultType.TABLE)), + name=fake.name(), + description=fake.paragraphs(), + ) + ) + return results + + +def generate_options(num_options=5): + """ + Generate a list of options for the search facets + """ + results = [] + for _ in range(num_options): + results.append( + FacetOption( + value=fake.name(), + label=fake.name(), + count=fake.random_int(min=0, max=100), + ) + ) + return results class SearchViewTests(SimpleTestCase): """ Test the view renders the correct context depending on query parameters and session - - TODO: this should stub out the search client and use dummy results """ + def setUp(self): + self.patcher = patch("home.views.get_catalogue_client") + mock_fn = self.patcher.start() + self.mock_client = MagicMock(spec=BaseCatalogueClient) + mock_fn.return_value = self.mock_client + self.mock_search_response(page_results=generate_page(), total_results=100) + self.mock_search_facets_response(domains=generate_options()) + + def tearDown(self): + self.patcher.stop() + + def mock_search_response(self, total_results=0, page_results=()): + search_response = SearchResponse( + total_results=total_results, page_results=page_results + ) + self.mock_client.search.return_value = search_response + + def mock_search_facets_response(self, domains): + self.mock_client.search_facets.return_value = SearchFacets({"domains": domains}) + def test_renders_200(self): response = self.client.get(reverse("home:search"), data={}) self.assertEqual(response.status_code, 200) diff --git a/poetry.lock b/poetry.lock index 8caca685..e48a14a1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] name = "acryl-datahub" @@ -952,6 +952,20 @@ files = [ [package.extras] tests = ["black", "pytest", "pytest-cov", "tox"] +[[package]] +name = "faker" +version = "22.6.0" +description = "Faker is a Python package that generates fake data for you." +optional = false +python-versions = ">=3.8" +files = [ + {file = "Faker-22.6.0-py3-none-any.whl", hash = "sha256:2b57f0256da6b45b7851dca87836ef5e2ae2fbb64d63d8697f1e47830d7b505d"}, + {file = "Faker-22.6.0.tar.gz", hash = "sha256:fa6d969728ef3da6229da91267a1bd4e6b902044c4822012d4fc46c71bb92b26"}, +] + +[package.dependencies] +python-dateutil = ">=2.4" + [[package]] name = "filelock" version = "3.13.1" @@ -1613,71 +1627,71 @@ testing = ["coverage", "pyyaml"] [[package]] name = "markupsafe" -version = "2.1.4" +version = "2.1.5" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.7" files = [ - {file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de8153a7aae3835484ac168a9a9bdaa0c5eee4e0bc595503c95d53b942879c84"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e888ff76ceb39601c59e219f281466c6d7e66bd375b4ec1ce83bcdc68306796b"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0b838c37ba596fcbfca71651a104a611543077156cb0a26fe0c475e1f152ee8"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac1ebf6983148b45b5fa48593950f90ed6d1d26300604f321c74a9ca1609f8e"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fbad3d346df8f9d72622ac71b69565e621ada2ce6572f37c2eae8dacd60385d"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5291d98cd3ad9a562883468c690a2a238c4a6388ab3bd155b0c75dd55ece858"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a7cc49ef48a3c7a0005a949f3c04f8baa5409d3f663a1b36f0eba9bfe2a0396e"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b83041cda633871572f0d3c41dddd5582ad7d22f65a72eacd8d3d6d00291df26"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-win32.whl", hash = "sha256:0c26f67b3fe27302d3a412b85ef696792c4a2386293c53ba683a89562f9399b0"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-win_amd64.whl", hash = "sha256:a76055d5cb1c23485d7ddae533229039b850db711c554a12ea64a0fd8a0129e2"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9e9e3c4020aa2dc62d5dd6743a69e399ce3de58320522948af6140ac959ab863"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0042d6a9880b38e1dd9ff83146cc3c9c18a059b9360ceae207805567aacccc69"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55d03fea4c4e9fd0ad75dc2e7e2b6757b80c152c032ea1d1de487461d8140efc"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ab3a886a237f6e9c9f4f7d272067e712cdb4efa774bef494dccad08f39d8ae6"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abf5ebbec056817057bfafc0445916bb688a255a5146f900445d081db08cbabb"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e1a0d1924a5013d4f294087e00024ad25668234569289650929ab871231668e7"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e7902211afd0af05fbadcc9a312e4cf10f27b779cf1323e78d52377ae4b72bea"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c669391319973e49a7c6230c218a1e3044710bc1ce4c8e6eb71f7e6d43a2c131"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-win32.whl", hash = "sha256:31f57d64c336b8ccb1966d156932f3daa4fee74176b0fdc48ef580be774aae74"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-win_amd64.whl", hash = "sha256:54a7e1380dfece8847c71bf7e33da5d084e9b889c75eca19100ef98027bd9f56"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a76cd37d229fc385738bd1ce4cba2a121cf26b53864c1772694ad0ad348e509e"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:987d13fe1d23e12a66ca2073b8d2e2a75cec2ecb8eab43ff5624ba0ad42764bc"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5244324676254697fe5c181fc762284e2c5fceeb1c4e3e7f6aca2b6f107e60dc"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78bc995e004681246e85e28e068111a4c3f35f34e6c62da1471e844ee1446250"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4d176cfdfde84f732c4a53109b293d05883e952bbba68b857ae446fa3119b4f"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f9917691f410a2e0897d1ef99619fd3f7dd503647c8ff2475bf90c3cf222ad74"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:f06e5a9e99b7df44640767842f414ed5d7bedaaa78cd817ce04bbd6fd86e2dd6"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:396549cea79e8ca4ba65525470d534e8a41070e6b3500ce2414921099cb73e8d"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-win32.whl", hash = "sha256:f6be2d708a9d0e9b0054856f07ac7070fbe1754be40ca8525d5adccdbda8f475"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-win_amd64.whl", hash = "sha256:5045e892cfdaecc5b4c01822f353cf2c8feb88a6ec1c0adef2a2e705eef0f656"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7a07f40ef8f0fbc5ef1000d0c78771f4d5ca03b4953fc162749772916b298fc4"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d18b66fe626ac412d96c2ab536306c736c66cf2a31c243a45025156cc190dc8a"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:698e84142f3f884114ea8cf83e7a67ca8f4ace8454e78fe960646c6c91c63bfa"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a3b78a5af63ec10d8604180380c13dcd870aba7928c1fe04e881d5c792dc4e"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:15866d7f2dc60cfdde12ebb4e75e41be862348b4728300c36cdf405e258415ec"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6aa5e2e7fc9bc042ae82d8b79d795b9a62bd8f15ba1e7594e3db243f158b5565"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:54635102ba3cf5da26eb6f96c4b8c53af8a9c0d97b64bdcb592596a6255d8518"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-win32.whl", hash = "sha256:3583a3a3ab7958e354dc1d25be74aee6228938312ee875a22330c4dc2e41beb0"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-win_amd64.whl", hash = "sha256:d6e427c7378c7f1b2bef6a344c925b8b63623d3321c09a237b7cc0e77dd98ceb"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:bf1196dcc239e608605b716e7b166eb5faf4bc192f8a44b81e85251e62584bd2"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4df98d4a9cd6a88d6a585852f56f2155c9cdb6aec78361a19f938810aa020954"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b835aba863195269ea358cecc21b400276747cc977492319fd7682b8cd2c253d"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23984d1bdae01bee794267424af55eef4dfc038dc5d1272860669b2aa025c9e3"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c98c33ffe20e9a489145d97070a435ea0679fddaabcafe19982fe9c971987d5"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9896fca4a8eb246defc8b2a7ac77ef7553b638e04fbf170bff78a40fa8a91474"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b0fe73bac2fed83839dbdbe6da84ae2a31c11cfc1c777a40dbd8ac8a6ed1560f"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c7556bafeaa0a50e2fe7dc86e0382dea349ebcad8f010d5a7dc6ba568eaaa789"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-win32.whl", hash = "sha256:fc1a75aa8f11b87910ffd98de62b29d6520b6d6e8a3de69a70ca34dea85d2a8a"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-win_amd64.whl", hash = "sha256:3a66c36a3864df95e4f62f9167c734b3b1192cb0851b43d7cc08040c074c6279"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:765f036a3d00395a326df2835d8f86b637dbaf9832f90f5d196c3b8a7a5080cb"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:21e7af8091007bf4bebf4521184f4880a6acab8df0df52ef9e513d8e5db23411"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5c31fe855c77cad679b302aabc42d724ed87c043b1432d457f4976add1c2c3e"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7653fa39578957bc42e5ebc15cf4361d9e0ee4b702d7d5ec96cdac860953c5b4"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47bb5f0142b8b64ed1399b6b60f700a580335c8e1c57f2f15587bd072012decc"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fe8512ed897d5daf089e5bd010c3dc03bb1bdae00b35588c49b98268d4a01e00"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:36d7626a8cca4d34216875aee5a1d3d654bb3dac201c1c003d182283e3205949"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b6f14a9cd50c3cb100eb94b3273131c80d102e19bb20253ac7bd7336118a673a"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-win32.whl", hash = "sha256:c8f253a84dbd2c63c19590fa86a032ef3d8cc18923b8049d91bcdeeb2581fbf6"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-win_amd64.whl", hash = "sha256:8b570a1537367b52396e53325769608f2a687ec9a4363647af1cded8928af959"}, - {file = "MarkupSafe-2.1.4.tar.gz", hash = "sha256:3aae9af4cac263007fd6309c64c6ab4506dd2b79382d9d19a1994f9240b8db4f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] [[package]] @@ -2395,7 +2409,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -3403,4 +3416,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "429ad4f0963ec675ccf5649e25e685103ac516030f18c6fe5e4dc11e63124afc" +content-hash = "0ae06695e2ac3dedebe33805f20a25c4cf72a2395ce547f5cbb66f4f1f8cc6e7" diff --git a/pyproject.toml b/pyproject.toml index 360ad6b2..68694726 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,7 @@ whitenoise = "^6.6.0" ministryofjustice-data-platform-catalogue = "^0.10.0" markdown = "^3.5.2" python-dotenv = "^1.0.1" +faker = "^22.6.0" [tool.poetry.group.dev] # dev group definition From 9102c5f5e6fbb1290bc620f8553b36ed53ac7799 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 2 Feb 2024 17:15:36 +0000 Subject: [PATCH 075/221] Commit changes made by code formatters --- home/test_views.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/home/test_views.py b/home/test_views.py index 23d3af0e..908cb49b 100644 --- a/home/test_views.py +++ b/home/test_views.py @@ -26,7 +26,8 @@ def generate_page(page_size=20): results.append( SearchResult( id=fake.unique.name(), - result_type=choice((ResultType.DATA_PRODUCT, ResultType.TABLE)), + result_type=choice( + (ResultType.DATA_PRODUCT, ResultType.TABLE)), name=fake.name(), description=fake.paragraphs(), ) @@ -60,7 +61,8 @@ def setUp(self): mock_fn = self.patcher.start() self.mock_client = MagicMock(spec=BaseCatalogueClient) mock_fn.return_value = self.mock_client - self.mock_search_response(page_results=generate_page(), total_results=100) + self.mock_search_response( + page_results=generate_page(), total_results=100) self.mock_search_facets_response(domains=generate_options()) def tearDown(self): @@ -73,7 +75,8 @@ def mock_search_response(self, total_results=0, page_results=()): self.mock_client.search.return_value = search_response def mock_search_facets_response(self, domains): - self.mock_client.search_facets.return_value = SearchFacets({"domains": domains}) + self.mock_client.search_facets.return_value = SearchFacets( + {"domains": domains}) def test_renders_200(self): response = self.client.get(reverse("home:search"), data={}) From 8968d94fbb40fc747ea208100df642dfdc94dbf3 Mon Sep 17 00:00:00 2001 From: Mitch Dawson Date: Tue, 6 Feb 2024 10:20:18 +0000 Subject: [PATCH 076/221] initial form --- home/forms/search.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 home/forms/search.py diff --git a/home/forms/search.py b/home/forms/search.py new file mode 100644 index 00000000..e1f0eda9 --- /dev/null +++ b/home/forms/search.py @@ -0,0 +1,27 @@ +from django.forms import forms + + +def get_domain_choices(): + """Make API call to obtain domain choices""" + return [ + ("HMCTS", "HMCTS"), + ("HMPPS", "HMPPS"), + ("OPG", "OPG"), + ("HQ", "HQ"), + ] + + +class SearchForm(forms.Form): + """Django form to represent data product search page inputs""" + + new = forms.BooleanField(default=False) + query = forms.CharField(max_length=100, strip=False, required=False) + domains = forms.MultipleChoiceField( + choices=get_domain_choices, required=False) + sort = forms.CharField(max_length=15, default="ascending") + clear_filter = forms.BooleanField(default=False) + clear_lable = forms.BooleanField(default=False) + + def clean_query(self): + """Example clean method to apply custom validation to input fields""" + return str(self.cleaned_data["query"]).capitalize() From ec92651a56d9de6d8945fd4540299f67df5b4786 Mon Sep 17 00:00:00 2001 From: Mitch Dawson Date: Tue, 6 Feb 2024 10:21:20 +0000 Subject: [PATCH 077/221] update form --- home/forms/search.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/home/forms/search.py b/home/forms/search.py index e1f0eda9..7328341a 100644 --- a/home/forms/search.py +++ b/home/forms/search.py @@ -17,7 +17,8 @@ class SearchForm(forms.Form): new = forms.BooleanField(default=False) query = forms.CharField(max_length=100, strip=False, required=False) domains = forms.MultipleChoiceField( - choices=get_domain_choices, required=False) + choices=get_domain_choices, required=False + ) sort = forms.CharField(max_length=15, default="ascending") clear_filter = forms.BooleanField(default=False) clear_lable = forms.BooleanField(default=False) From a25d59a9d74e8bd798d729d7c15df601b3ffabfd Mon Sep 17 00:00:00 2001 From: Mitch Dawson Date: Tue, 6 Feb 2024 10:22:18 +0000 Subject: [PATCH 078/221] addition --- home/forms/search.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/home/forms/search.py b/home/forms/search.py index 7328341a..07213443 100644 --- a/home/forms/search.py +++ b/home/forms/search.py @@ -16,9 +16,7 @@ class SearchForm(forms.Form): new = forms.BooleanField(default=False) query = forms.CharField(max_length=100, strip=False, required=False) - domains = forms.MultipleChoiceField( - choices=get_domain_choices, required=False - ) + domains = forms.MultipleChoiceField(choices=get_domain_choices, required=False) sort = forms.CharField(max_length=15, default="ascending") clear_filter = forms.BooleanField(default=False) clear_lable = forms.BooleanField(default=False) From 882bf512f4540704bda3b8844282c6c2ebc13b9e Mon Sep 17 00:00:00 2001 From: Mitch Dawson Date: Tue, 6 Feb 2024 10:34:07 +0000 Subject: [PATCH 079/221] update test folder structure --- tests/__init__.py | 0 tests/home/__init__.py | 0 tests/home/views/__init__.py | 0 {home => tests/home/views}/test_views.py | 31 ------------------------ 4 files changed, 31 deletions(-) create mode 100644 tests/__init__.py create mode 100644 tests/home/__init__.py create mode 100644 tests/home/views/__init__.py rename {home => tests/home/views}/test_views.py (72%) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/home/__init__.py b/tests/home/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/home/views/__init__.py b/tests/home/views/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/home/test_views.py b/tests/home/views/test_views.py similarity index 72% rename from home/test_views.py rename to tests/home/views/test_views.py index 908cb49b..afed0094 100644 --- a/home/test_views.py +++ b/tests/home/views/test_views.py @@ -87,13 +87,6 @@ def test_exposes_results(self): self.assertEqual(response.status_code, 200) self.assertEqual(len(response.context["results"]), 20) - @skip("possibly broken") - def test_exposes_domains(self): - response = self.client.get(reverse("home:search"), data={}) - self.assertEqual(response.status_code, 200) - self.assertEqual(response.context["selected_domain"], {}) - self.assertGreater(len(response.context["domains"]), 0) - def test_exposes_empty_query(self): response = self.client.get(reverse("home:search"), data={}) self.assertEqual(response.status_code, 200) @@ -104,27 +97,3 @@ def test_exposes_query(self): reverse("home:search"), data={"query": "foo"}) self.assertEqual(response.status_code, 200) self.assertEqual(response.context["query"], "foo") - - @skip("possibly broken") - def test_exposes_filter(self): - response = self.client.get( - reverse("home:search"), data={"domain": ["urn:li:domain:HMCTS"]} - ) - self.assertEqual(response.status_code, 200) - self.assertEqual( - response.context["selected_domain"], { - "urn:li:domain:HMCTS": "HMCTS"} - ) - self.assertEqual(len(response.context["domains"]), 0) - - @skip("possibly broken") - def test_exposes_filter_and_query(self): - response = self.client.get( - reverse("home:search"), - data={"domain": ["urn:li:domain:HMCTS"], "query": "courts"}, - ) - self.assertEqual( - response.context["selected_domain"], { - "urn:li:domain:HMCTS": "HMCTS"} - ) - self.assertEqual(response.context["query"], "courts") From 40119ba06336bf5f6fc93e0ea8ea3cada1a4deee Mon Sep 17 00:00:00 2001 From: Mitch Dawson Date: Tue, 6 Feb 2024 10:34:29 +0000 Subject: [PATCH 080/221] update test folder structure --- tests/home/views/test_views.py | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/tests/home/views/test_views.py b/tests/home/views/test_views.py index afed0094..839bcc87 100644 --- a/tests/home/views/test_views.py +++ b/tests/home/views/test_views.py @@ -3,13 +3,9 @@ from unittest.mock import MagicMock, patch from data_platform_catalogue.client import BaseCatalogueClient -from data_platform_catalogue.search_types import ( - FacetOption, - ResultType, - SearchFacets, - SearchResponse, - SearchResult, -) +from data_platform_catalogue.search_types import (FacetOption, ResultType, + SearchFacets, SearchResponse, + SearchResult) from django.test import SimpleTestCase from django.urls import reverse from faker import Faker @@ -26,8 +22,7 @@ def generate_page(page_size=20): results.append( SearchResult( id=fake.unique.name(), - result_type=choice( - (ResultType.DATA_PRODUCT, ResultType.TABLE)), + result_type=choice((ResultType.DATA_PRODUCT, ResultType.TABLE)), name=fake.name(), description=fake.paragraphs(), ) @@ -61,8 +56,7 @@ def setUp(self): mock_fn = self.patcher.start() self.mock_client = MagicMock(spec=BaseCatalogueClient) mock_fn.return_value = self.mock_client - self.mock_search_response( - page_results=generate_page(), total_results=100) + self.mock_search_response(page_results=generate_page(), total_results=100) self.mock_search_facets_response(domains=generate_options()) def tearDown(self): @@ -75,8 +69,7 @@ def mock_search_response(self, total_results=0, page_results=()): self.mock_client.search.return_value = search_response def mock_search_facets_response(self, domains): - self.mock_client.search_facets.return_value = SearchFacets( - {"domains": domains}) + self.mock_client.search_facets.return_value = SearchFacets({"domains": domains}) def test_renders_200(self): response = self.client.get(reverse("home:search"), data={}) @@ -93,7 +86,6 @@ def test_exposes_empty_query(self): self.assertEqual(response.context["query"], "") def test_exposes_query(self): - response = self.client.get( - reverse("home:search"), data={"query": "foo"}) + response = self.client.get(reverse("home:search"), data={"query": "foo"}) self.assertEqual(response.status_code, 200) self.assertEqual(response.context["query"], "foo") From ae0bc261e6799a21dd2571576ddf96c4f7bb1f2b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 6 Feb 2024 10:35:10 +0000 Subject: [PATCH 081/221] Commit changes made by code formatters --- tests/home/views/test_views.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/home/views/test_views.py b/tests/home/views/test_views.py index 839bcc87..7d0dddf2 100644 --- a/tests/home/views/test_views.py +++ b/tests/home/views/test_views.py @@ -22,7 +22,8 @@ def generate_page(page_size=20): results.append( SearchResult( id=fake.unique.name(), - result_type=choice((ResultType.DATA_PRODUCT, ResultType.TABLE)), + result_type=choice( + (ResultType.DATA_PRODUCT, ResultType.TABLE)), name=fake.name(), description=fake.paragraphs(), ) @@ -56,7 +57,8 @@ def setUp(self): mock_fn = self.patcher.start() self.mock_client = MagicMock(spec=BaseCatalogueClient) mock_fn.return_value = self.mock_client - self.mock_search_response(page_results=generate_page(), total_results=100) + self.mock_search_response( + page_results=generate_page(), total_results=100) self.mock_search_facets_response(domains=generate_options()) def tearDown(self): @@ -69,7 +71,8 @@ def mock_search_response(self, total_results=0, page_results=()): self.mock_client.search.return_value = search_response def mock_search_facets_response(self, domains): - self.mock_client.search_facets.return_value = SearchFacets({"domains": domains}) + self.mock_client.search_facets.return_value = SearchFacets( + {"domains": domains}) def test_renders_200(self): response = self.client.get(reverse("home:search"), data={}) @@ -86,6 +89,7 @@ def test_exposes_empty_query(self): self.assertEqual(response.context["query"], "") def test_exposes_query(self): - response = self.client.get(reverse("home:search"), data={"query": "foo"}) + response = self.client.get( + reverse("home:search"), data={"query": "foo"}) self.assertEqual(response.status_code, 200) self.assertEqual(response.context["query"], "foo") From 567f5c831ef0913690313d111bef021d5ee697da Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Fri, 2 Feb 2024 15:35:41 +0000 Subject: [PATCH 082/221] Add some starter tests --- home/test_views.py | 60 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 home/test_views.py diff --git a/home/test_views.py b/home/test_views.py new file mode 100644 index 00000000..69322733 --- /dev/null +++ b/home/test_views.py @@ -0,0 +1,60 @@ +from unittest import skip + +from django.test import SimpleTestCase +from django.urls import reverse + + +class SearchViewTests(SimpleTestCase): + """ + Test the view renders the correct context depending on query parameters and session + + TODO: this should stub out the search client and use dummy results + """ + + def test_renders_200(self): + response = self.client.get(reverse("home:search"), data={}) + self.assertEqual(response.status_code, 200) + + def test_exposes_results(self): + response = self.client.get(reverse("home:search"), data={}) + self.assertEqual(response.status_code, 200) + self.assertEqual(len(response.context["results"]), 20) + + @skip("possibly broken") + def test_exposes_domains(self): + response = self.client.get(reverse("home:search"), data={}) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context["selected_domain"], {}) + self.assertGreater(len(response.context["domains"]), 0) + + def test_exposes_empty_query(self): + response = self.client.get(reverse("home:search"), data={}) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context["query"], "") + + def test_exposes_query(self): + response = self.client.get(reverse("home:search"), data={"query": "foo"}) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context["query"], "foo") + + @skip("possibly broken") + def test_exposes_filter(self): + response = self.client.get( + reverse("home:search"), data={"domain": ["urn:li:domain:HMCTS"]} + ) + self.assertEqual(response.status_code, 200) + self.assertEqual( + response.context["selected_domain"], {"urn:li:domain:HMCTS": "HMCTS"} + ) + self.assertEqual(len(response.context["domains"]), 0) + + @skip("possibly broken") + def test_exposes_filter_and_query(self): + response = self.client.get( + reverse("home:search"), + data={"domain": ["urn:li:domain:HMCTS"], "query": "courts"}, + ) + self.assertEqual( + response.context["selected_domain"], {"urn:li:domain:HMCTS": "HMCTS"} + ) + self.assertEqual(response.context["query"], "courts") From 189e0904109d2cc521250a2db9719ea782faa4c2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 2 Feb 2024 15:36:36 +0000 Subject: [PATCH 083/221] Commit changes made by code formatters --- home/test_views.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/home/test_views.py b/home/test_views.py index 69322733..3b027df5 100644 --- a/home/test_views.py +++ b/home/test_views.py @@ -33,7 +33,8 @@ def test_exposes_empty_query(self): self.assertEqual(response.context["query"], "") def test_exposes_query(self): - response = self.client.get(reverse("home:search"), data={"query": "foo"}) + response = self.client.get( + reverse("home:search"), data={"query": "foo"}) self.assertEqual(response.status_code, 200) self.assertEqual(response.context["query"], "foo") @@ -44,7 +45,8 @@ def test_exposes_filter(self): ) self.assertEqual(response.status_code, 200) self.assertEqual( - response.context["selected_domain"], {"urn:li:domain:HMCTS": "HMCTS"} + response.context["selected_domain"], { + "urn:li:domain:HMCTS": "HMCTS"} ) self.assertEqual(len(response.context["domains"]), 0) @@ -55,6 +57,7 @@ def test_exposes_filter_and_query(self): data={"domain": ["urn:li:domain:HMCTS"], "query": "courts"}, ) self.assertEqual( - response.context["selected_domain"], {"urn:li:domain:HMCTS": "HMCTS"} + response.context["selected_domain"], { + "urn:li:domain:HMCTS": "HMCTS"} ) self.assertEqual(response.context["query"], "courts") From 4833321a9cd104e72ace994fed5e454af9e873e4 Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Fri, 2 Feb 2024 17:07:32 +0000 Subject: [PATCH 084/221] Speed up tests by mocking out the catalogue client --- home/test_views.py | 68 +++++++++++++++++++++- poetry.lock | 141 +++++++++++++++++++++++++-------------------- pyproject.toml | 1 + 3 files changed, 144 insertions(+), 66 deletions(-) diff --git a/home/test_views.py b/home/test_views.py index 3b027df5..23d3af0e 100644 --- a/home/test_views.py +++ b/home/test_views.py @@ -1,16 +1,80 @@ +from random import choice from unittest import skip +from unittest.mock import MagicMock, patch +from data_platform_catalogue.client import BaseCatalogueClient +from data_platform_catalogue.search_types import ( + FacetOption, + ResultType, + SearchFacets, + SearchResponse, + SearchResult, +) from django.test import SimpleTestCase from django.urls import reverse +from faker import Faker + +fake = Faker() + + +def generate_page(page_size=20): + """ + Generate a fake search page + """ + results = [] + for _ in range(page_size): + results.append( + SearchResult( + id=fake.unique.name(), + result_type=choice((ResultType.DATA_PRODUCT, ResultType.TABLE)), + name=fake.name(), + description=fake.paragraphs(), + ) + ) + return results + + +def generate_options(num_options=5): + """ + Generate a list of options for the search facets + """ + results = [] + for _ in range(num_options): + results.append( + FacetOption( + value=fake.name(), + label=fake.name(), + count=fake.random_int(min=0, max=100), + ) + ) + return results class SearchViewTests(SimpleTestCase): """ Test the view renders the correct context depending on query parameters and session - - TODO: this should stub out the search client and use dummy results """ + def setUp(self): + self.patcher = patch("home.views.get_catalogue_client") + mock_fn = self.patcher.start() + self.mock_client = MagicMock(spec=BaseCatalogueClient) + mock_fn.return_value = self.mock_client + self.mock_search_response(page_results=generate_page(), total_results=100) + self.mock_search_facets_response(domains=generate_options()) + + def tearDown(self): + self.patcher.stop() + + def mock_search_response(self, total_results=0, page_results=()): + search_response = SearchResponse( + total_results=total_results, page_results=page_results + ) + self.mock_client.search.return_value = search_response + + def mock_search_facets_response(self, domains): + self.mock_client.search_facets.return_value = SearchFacets({"domains": domains}) + def test_renders_200(self): response = self.client.get(reverse("home:search"), data={}) self.assertEqual(response.status_code, 200) diff --git a/poetry.lock b/poetry.lock index 8caca685..e48a14a1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] name = "acryl-datahub" @@ -952,6 +952,20 @@ files = [ [package.extras] tests = ["black", "pytest", "pytest-cov", "tox"] +[[package]] +name = "faker" +version = "22.6.0" +description = "Faker is a Python package that generates fake data for you." +optional = false +python-versions = ">=3.8" +files = [ + {file = "Faker-22.6.0-py3-none-any.whl", hash = "sha256:2b57f0256da6b45b7851dca87836ef5e2ae2fbb64d63d8697f1e47830d7b505d"}, + {file = "Faker-22.6.0.tar.gz", hash = "sha256:fa6d969728ef3da6229da91267a1bd4e6b902044c4822012d4fc46c71bb92b26"}, +] + +[package.dependencies] +python-dateutil = ">=2.4" + [[package]] name = "filelock" version = "3.13.1" @@ -1613,71 +1627,71 @@ testing = ["coverage", "pyyaml"] [[package]] name = "markupsafe" -version = "2.1.4" +version = "2.1.5" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.7" files = [ - {file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de8153a7aae3835484ac168a9a9bdaa0c5eee4e0bc595503c95d53b942879c84"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e888ff76ceb39601c59e219f281466c6d7e66bd375b4ec1ce83bcdc68306796b"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0b838c37ba596fcbfca71651a104a611543077156cb0a26fe0c475e1f152ee8"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac1ebf6983148b45b5fa48593950f90ed6d1d26300604f321c74a9ca1609f8e"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fbad3d346df8f9d72622ac71b69565e621ada2ce6572f37c2eae8dacd60385d"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5291d98cd3ad9a562883468c690a2a238c4a6388ab3bd155b0c75dd55ece858"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a7cc49ef48a3c7a0005a949f3c04f8baa5409d3f663a1b36f0eba9bfe2a0396e"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b83041cda633871572f0d3c41dddd5582ad7d22f65a72eacd8d3d6d00291df26"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-win32.whl", hash = "sha256:0c26f67b3fe27302d3a412b85ef696792c4a2386293c53ba683a89562f9399b0"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-win_amd64.whl", hash = "sha256:a76055d5cb1c23485d7ddae533229039b850db711c554a12ea64a0fd8a0129e2"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9e9e3c4020aa2dc62d5dd6743a69e399ce3de58320522948af6140ac959ab863"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0042d6a9880b38e1dd9ff83146cc3c9c18a059b9360ceae207805567aacccc69"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55d03fea4c4e9fd0ad75dc2e7e2b6757b80c152c032ea1d1de487461d8140efc"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ab3a886a237f6e9c9f4f7d272067e712cdb4efa774bef494dccad08f39d8ae6"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abf5ebbec056817057bfafc0445916bb688a255a5146f900445d081db08cbabb"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e1a0d1924a5013d4f294087e00024ad25668234569289650929ab871231668e7"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e7902211afd0af05fbadcc9a312e4cf10f27b779cf1323e78d52377ae4b72bea"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c669391319973e49a7c6230c218a1e3044710bc1ce4c8e6eb71f7e6d43a2c131"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-win32.whl", hash = "sha256:31f57d64c336b8ccb1966d156932f3daa4fee74176b0fdc48ef580be774aae74"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-win_amd64.whl", hash = "sha256:54a7e1380dfece8847c71bf7e33da5d084e9b889c75eca19100ef98027bd9f56"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a76cd37d229fc385738bd1ce4cba2a121cf26b53864c1772694ad0ad348e509e"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:987d13fe1d23e12a66ca2073b8d2e2a75cec2ecb8eab43ff5624ba0ad42764bc"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5244324676254697fe5c181fc762284e2c5fceeb1c4e3e7f6aca2b6f107e60dc"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78bc995e004681246e85e28e068111a4c3f35f34e6c62da1471e844ee1446250"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4d176cfdfde84f732c4a53109b293d05883e952bbba68b857ae446fa3119b4f"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f9917691f410a2e0897d1ef99619fd3f7dd503647c8ff2475bf90c3cf222ad74"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:f06e5a9e99b7df44640767842f414ed5d7bedaaa78cd817ce04bbd6fd86e2dd6"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:396549cea79e8ca4ba65525470d534e8a41070e6b3500ce2414921099cb73e8d"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-win32.whl", hash = "sha256:f6be2d708a9d0e9b0054856f07ac7070fbe1754be40ca8525d5adccdbda8f475"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-win_amd64.whl", hash = "sha256:5045e892cfdaecc5b4c01822f353cf2c8feb88a6ec1c0adef2a2e705eef0f656"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7a07f40ef8f0fbc5ef1000d0c78771f4d5ca03b4953fc162749772916b298fc4"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d18b66fe626ac412d96c2ab536306c736c66cf2a31c243a45025156cc190dc8a"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:698e84142f3f884114ea8cf83e7a67ca8f4ace8454e78fe960646c6c91c63bfa"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a3b78a5af63ec10d8604180380c13dcd870aba7928c1fe04e881d5c792dc4e"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:15866d7f2dc60cfdde12ebb4e75e41be862348b4728300c36cdf405e258415ec"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6aa5e2e7fc9bc042ae82d8b79d795b9a62bd8f15ba1e7594e3db243f158b5565"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:54635102ba3cf5da26eb6f96c4b8c53af8a9c0d97b64bdcb592596a6255d8518"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-win32.whl", hash = "sha256:3583a3a3ab7958e354dc1d25be74aee6228938312ee875a22330c4dc2e41beb0"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-win_amd64.whl", hash = "sha256:d6e427c7378c7f1b2bef6a344c925b8b63623d3321c09a237b7cc0e77dd98ceb"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:bf1196dcc239e608605b716e7b166eb5faf4bc192f8a44b81e85251e62584bd2"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4df98d4a9cd6a88d6a585852f56f2155c9cdb6aec78361a19f938810aa020954"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b835aba863195269ea358cecc21b400276747cc977492319fd7682b8cd2c253d"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23984d1bdae01bee794267424af55eef4dfc038dc5d1272860669b2aa025c9e3"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c98c33ffe20e9a489145d97070a435ea0679fddaabcafe19982fe9c971987d5"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9896fca4a8eb246defc8b2a7ac77ef7553b638e04fbf170bff78a40fa8a91474"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b0fe73bac2fed83839dbdbe6da84ae2a31c11cfc1c777a40dbd8ac8a6ed1560f"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c7556bafeaa0a50e2fe7dc86e0382dea349ebcad8f010d5a7dc6ba568eaaa789"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-win32.whl", hash = "sha256:fc1a75aa8f11b87910ffd98de62b29d6520b6d6e8a3de69a70ca34dea85d2a8a"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-win_amd64.whl", hash = "sha256:3a66c36a3864df95e4f62f9167c734b3b1192cb0851b43d7cc08040c074c6279"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:765f036a3d00395a326df2835d8f86b637dbaf9832f90f5d196c3b8a7a5080cb"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:21e7af8091007bf4bebf4521184f4880a6acab8df0df52ef9e513d8e5db23411"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5c31fe855c77cad679b302aabc42d724ed87c043b1432d457f4976add1c2c3e"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7653fa39578957bc42e5ebc15cf4361d9e0ee4b702d7d5ec96cdac860953c5b4"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47bb5f0142b8b64ed1399b6b60f700a580335c8e1c57f2f15587bd072012decc"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fe8512ed897d5daf089e5bd010c3dc03bb1bdae00b35588c49b98268d4a01e00"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:36d7626a8cca4d34216875aee5a1d3d654bb3dac201c1c003d182283e3205949"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b6f14a9cd50c3cb100eb94b3273131c80d102e19bb20253ac7bd7336118a673a"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-win32.whl", hash = "sha256:c8f253a84dbd2c63c19590fa86a032ef3d8cc18923b8049d91bcdeeb2581fbf6"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-win_amd64.whl", hash = "sha256:8b570a1537367b52396e53325769608f2a687ec9a4363647af1cded8928af959"}, - {file = "MarkupSafe-2.1.4.tar.gz", hash = "sha256:3aae9af4cac263007fd6309c64c6ab4506dd2b79382d9d19a1994f9240b8db4f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] [[package]] @@ -2395,7 +2409,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -3403,4 +3416,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "429ad4f0963ec675ccf5649e25e685103ac516030f18c6fe5e4dc11e63124afc" +content-hash = "0ae06695e2ac3dedebe33805f20a25c4cf72a2395ce547f5cbb66f4f1f8cc6e7" diff --git a/pyproject.toml b/pyproject.toml index 360ad6b2..68694726 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,7 @@ whitenoise = "^6.6.0" ministryofjustice-data-platform-catalogue = "^0.10.0" markdown = "^3.5.2" python-dotenv = "^1.0.1" +faker = "^22.6.0" [tool.poetry.group.dev] # dev group definition From cdaef9ce8f8fd1b88868eb9b0e51ba65d9be19a3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 2 Feb 2024 17:15:36 +0000 Subject: [PATCH 085/221] Commit changes made by code formatters --- home/test_views.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/home/test_views.py b/home/test_views.py index 23d3af0e..908cb49b 100644 --- a/home/test_views.py +++ b/home/test_views.py @@ -26,7 +26,8 @@ def generate_page(page_size=20): results.append( SearchResult( id=fake.unique.name(), - result_type=choice((ResultType.DATA_PRODUCT, ResultType.TABLE)), + result_type=choice( + (ResultType.DATA_PRODUCT, ResultType.TABLE)), name=fake.name(), description=fake.paragraphs(), ) @@ -60,7 +61,8 @@ def setUp(self): mock_fn = self.patcher.start() self.mock_client = MagicMock(spec=BaseCatalogueClient) mock_fn.return_value = self.mock_client - self.mock_search_response(page_results=generate_page(), total_results=100) + self.mock_search_response( + page_results=generate_page(), total_results=100) self.mock_search_facets_response(domains=generate_options()) def tearDown(self): @@ -73,7 +75,8 @@ def mock_search_response(self, total_results=0, page_results=()): self.mock_client.search.return_value = search_response def mock_search_facets_response(self, domains): - self.mock_client.search_facets.return_value = SearchFacets({"domains": domains}) + self.mock_client.search_facets.return_value = SearchFacets( + {"domains": domains}) def test_renders_200(self): response = self.client.get(reverse("home:search"), data={}) From 1ba35841538864293364dea2754d80ca41207805 Mon Sep 17 00:00:00 2001 From: Mitch Dawson Date: Tue, 6 Feb 2024 10:34:07 +0000 Subject: [PATCH 086/221] update test folder structure --- tests/__init__.py | 0 tests/home/__init__.py | 0 tests/home/views/__init__.py | 0 {home => tests/home/views}/test_views.py | 31 ------------------------ 4 files changed, 31 deletions(-) create mode 100644 tests/__init__.py create mode 100644 tests/home/__init__.py create mode 100644 tests/home/views/__init__.py rename {home => tests/home/views}/test_views.py (72%) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/home/__init__.py b/tests/home/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/home/views/__init__.py b/tests/home/views/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/home/test_views.py b/tests/home/views/test_views.py similarity index 72% rename from home/test_views.py rename to tests/home/views/test_views.py index 908cb49b..afed0094 100644 --- a/home/test_views.py +++ b/tests/home/views/test_views.py @@ -87,13 +87,6 @@ def test_exposes_results(self): self.assertEqual(response.status_code, 200) self.assertEqual(len(response.context["results"]), 20) - @skip("possibly broken") - def test_exposes_domains(self): - response = self.client.get(reverse("home:search"), data={}) - self.assertEqual(response.status_code, 200) - self.assertEqual(response.context["selected_domain"], {}) - self.assertGreater(len(response.context["domains"]), 0) - def test_exposes_empty_query(self): response = self.client.get(reverse("home:search"), data={}) self.assertEqual(response.status_code, 200) @@ -104,27 +97,3 @@ def test_exposes_query(self): reverse("home:search"), data={"query": "foo"}) self.assertEqual(response.status_code, 200) self.assertEqual(response.context["query"], "foo") - - @skip("possibly broken") - def test_exposes_filter(self): - response = self.client.get( - reverse("home:search"), data={"domain": ["urn:li:domain:HMCTS"]} - ) - self.assertEqual(response.status_code, 200) - self.assertEqual( - response.context["selected_domain"], { - "urn:li:domain:HMCTS": "HMCTS"} - ) - self.assertEqual(len(response.context["domains"]), 0) - - @skip("possibly broken") - def test_exposes_filter_and_query(self): - response = self.client.get( - reverse("home:search"), - data={"domain": ["urn:li:domain:HMCTS"], "query": "courts"}, - ) - self.assertEqual( - response.context["selected_domain"], { - "urn:li:domain:HMCTS": "HMCTS"} - ) - self.assertEqual(response.context["query"], "courts") From fa1398af6883854f8e6acfc5c9ea72613942ba63 Mon Sep 17 00:00:00 2001 From: Mitch Dawson Date: Tue, 6 Feb 2024 10:34:29 +0000 Subject: [PATCH 087/221] update test folder structure --- tests/home/views/test_views.py | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/tests/home/views/test_views.py b/tests/home/views/test_views.py index afed0094..839bcc87 100644 --- a/tests/home/views/test_views.py +++ b/tests/home/views/test_views.py @@ -3,13 +3,9 @@ from unittest.mock import MagicMock, patch from data_platform_catalogue.client import BaseCatalogueClient -from data_platform_catalogue.search_types import ( - FacetOption, - ResultType, - SearchFacets, - SearchResponse, - SearchResult, -) +from data_platform_catalogue.search_types import (FacetOption, ResultType, + SearchFacets, SearchResponse, + SearchResult) from django.test import SimpleTestCase from django.urls import reverse from faker import Faker @@ -26,8 +22,7 @@ def generate_page(page_size=20): results.append( SearchResult( id=fake.unique.name(), - result_type=choice( - (ResultType.DATA_PRODUCT, ResultType.TABLE)), + result_type=choice((ResultType.DATA_PRODUCT, ResultType.TABLE)), name=fake.name(), description=fake.paragraphs(), ) @@ -61,8 +56,7 @@ def setUp(self): mock_fn = self.patcher.start() self.mock_client = MagicMock(spec=BaseCatalogueClient) mock_fn.return_value = self.mock_client - self.mock_search_response( - page_results=generate_page(), total_results=100) + self.mock_search_response(page_results=generate_page(), total_results=100) self.mock_search_facets_response(domains=generate_options()) def tearDown(self): @@ -75,8 +69,7 @@ def mock_search_response(self, total_results=0, page_results=()): self.mock_client.search.return_value = search_response def mock_search_facets_response(self, domains): - self.mock_client.search_facets.return_value = SearchFacets( - {"domains": domains}) + self.mock_client.search_facets.return_value = SearchFacets({"domains": domains}) def test_renders_200(self): response = self.client.get(reverse("home:search"), data={}) @@ -93,7 +86,6 @@ def test_exposes_empty_query(self): self.assertEqual(response.context["query"], "") def test_exposes_query(self): - response = self.client.get( - reverse("home:search"), data={"query": "foo"}) + response = self.client.get(reverse("home:search"), data={"query": "foo"}) self.assertEqual(response.status_code, 200) self.assertEqual(response.context["query"], "foo") From a6a974de5bbfa6b56745b70176500e31907d6def Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 6 Feb 2024 10:35:10 +0000 Subject: [PATCH 088/221] Commit changes made by code formatters --- tests/home/views/test_views.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/home/views/test_views.py b/tests/home/views/test_views.py index 839bcc87..7d0dddf2 100644 --- a/tests/home/views/test_views.py +++ b/tests/home/views/test_views.py @@ -22,7 +22,8 @@ def generate_page(page_size=20): results.append( SearchResult( id=fake.unique.name(), - result_type=choice((ResultType.DATA_PRODUCT, ResultType.TABLE)), + result_type=choice( + (ResultType.DATA_PRODUCT, ResultType.TABLE)), name=fake.name(), description=fake.paragraphs(), ) @@ -56,7 +57,8 @@ def setUp(self): mock_fn = self.patcher.start() self.mock_client = MagicMock(spec=BaseCatalogueClient) mock_fn.return_value = self.mock_client - self.mock_search_response(page_results=generate_page(), total_results=100) + self.mock_search_response( + page_results=generate_page(), total_results=100) self.mock_search_facets_response(domains=generate_options()) def tearDown(self): @@ -69,7 +71,8 @@ def mock_search_response(self, total_results=0, page_results=()): self.mock_client.search.return_value = search_response def mock_search_facets_response(self, domains): - self.mock_client.search_facets.return_value = SearchFacets({"domains": domains}) + self.mock_client.search_facets.return_value = SearchFacets( + {"domains": domains}) def test_renders_200(self): response = self.client.get(reverse("home:search"), data={}) @@ -86,6 +89,7 @@ def test_exposes_empty_query(self): self.assertEqual(response.context["query"], "") def test_exposes_query(self): - response = self.client.get(reverse("home:search"), data={"query": "foo"}) + response = self.client.get( + reverse("home:search"), data={"query": "foo"}) self.assertEqual(response.status_code, 200) self.assertEqual(response.context["query"], "foo") From 59961407f5e3e169ec4264656fac92e10fb72ab3 Mon Sep 17 00:00:00 2001 From: Mitch Dawson Date: Tue, 6 Feb 2024 14:03:13 +0000 Subject: [PATCH 089/221] implement sort --- .vscode/launch.json | 21 +++++++++++++++++++++ home/forms/__init__.py | 0 home/forms/search.py | 34 ++++++++++++++++++++++++++++------ home/service/__init__.py | 0 home/views.py | 17 ++++++++++++----- templates/partial/sort.html | 30 ++++++++++++++++++++++++++++++ templates/search.html | 35 ++++++----------------------------- 7 files changed, 97 insertions(+), 40 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 home/forms/__init__.py create mode 100644 home/service/__init__.py create mode 100644 templates/partial/sort.html diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..ce9b6907 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python Debugger: Django", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/manage.py", + "args": [ + "poetry", + "run", + "python", + "runserver" + ], + "django": true + } + ] +} diff --git a/home/forms/__init__.py b/home/forms/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/home/forms/search.py b/home/forms/search.py index 07213443..2fbc5559 100644 --- a/home/forms/search.py +++ b/home/forms/search.py @@ -1,8 +1,11 @@ -from django.forms import forms +from django import forms def get_domain_choices(): """Make API call to obtain domain choices""" + # TODO: pull in the domains from the catalogue client + # facets = client.search_facets() + # domain_list = facets.options("domains") return [ ("HMCTS", "HMCTS"), ("HMPPS", "HMPPS"), @@ -11,15 +14,34 @@ def get_domain_choices(): ] +def get_sort_choices(): + return [ + ("relevance", "Relevance"), + ("ascending", "Ascending"), + ("descending", "Descending") + ] + + class SearchForm(forms.Form): """Django form to represent data product search page inputs""" - new = forms.BooleanField(default=False) + new = forms.BooleanField(initial=False) query = forms.CharField(max_length=100, strip=False, required=False) - domains = forms.MultipleChoiceField(choices=get_domain_choices, required=False) - sort = forms.CharField(max_length=15, default="ascending") - clear_filter = forms.BooleanField(default=False) - clear_lable = forms.BooleanField(default=False) + domains = forms.MultipleChoiceField( + choices=get_domain_choices, required=False) + sort = forms.ChoiceField( + choices=get_sort_choices, + widget=forms.RadioSelect( + attrs={"class": "govuk-radios__input", "form": "searchform"} + ), + initial="relevance" + ) + clear_filter = forms.BooleanField(initial=False) + clear_label = forms.BooleanField(initial=False) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.initial["sort"] = "relevance" def clean_query(self): """Example clean method to apply custom validation to input fields""" diff --git a/home/service/__init__.py b/home/service/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/home/views.py b/home/views.py index e36c3e70..5977072f 100644 --- a/home/views.py +++ b/home/views.py @@ -8,8 +8,11 @@ from django.core.paginator import Paginator from .services import get_catalogue_client +from home.forms.search import SearchForm # Create your views here. + + def home_view(request): context = {} return render(request, "home.html", context) @@ -32,21 +35,25 @@ def details_view(request, id): def search_view(request, page: str = "1"): new_search = request.GET.get("new", "") + if new_search: + form = SearchForm() + else: + form = SearchForm(request.GET) + print(form) query = request.GET.get("query", "") page_for_search = str(int(page) - 1) client = get_catalogue_client() domain_list = get_domain_list(client) context = {} + context["form"] = form context["domainlist"] = domain_list domains = request.GET.getlist("domain", []) - sortby = request.GET.get("sortby", None) - context["sortby"] = sortby - if sortby == "ascending": + if form.sort == "ascending": sort = SortOption(field="name", ascending=True) - elif sortby == "descending": + elif form.sort == "descending": sort = SortOption(field="name", ascending=False) else: sort = None @@ -134,7 +141,7 @@ def search_view(request, page: str = "1"): page, on_each_side=2, on_ends=1 ) context["paginator"] = paginator - context["sortby"] = sortby + context["sortby"] = sort if query: context["page_title"] = f'Search for "{query}" - Data catalogue' diff --git a/templates/partial/sort.html b/templates/partial/sort.html new file mode 100644 index 00000000..3e5b9b86 --- /dev/null +++ b/templates/partial/sort.html @@ -0,0 +1,30 @@ +
    +
    + + Sort results + +
    + {% for radio in form.sort %} +
    + {{radio.tag}} + + +
    + {% endfor %} +
    + +
    +
    diff --git a/templates/search.html b/templates/search.html index 8173550e..b6e27347 100644 --- a/templates/search.html +++ b/templates/search.html @@ -24,35 +24,12 @@

    Find MOJ Data

    {% include "partial/filter.html" %}

    {{total_results|intcomma}} Results

    -
    -
    - - Sort results - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    -
    -
    - {% include "partial/search_result.html" %} - {% include "partial/pagination.html" %} + {% include "partial/sort.html" %} + +
    {% endblock content %} From 8e6bf4ad10e377d52c8bb7808148143633e12bbe Mon Sep 17 00:00:00 2001 From: Mitch Dawson Date: Tue, 6 Feb 2024 14:03:28 +0000 Subject: [PATCH 090/221] implement sort --- home/forms/search.py | 7 +++---- home/views.py | 14 ++++++-------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/home/forms/search.py b/home/forms/search.py index 2fbc5559..8a30418c 100644 --- a/home/forms/search.py +++ b/home/forms/search.py @@ -18,7 +18,7 @@ def get_sort_choices(): return [ ("relevance", "Relevance"), ("ascending", "Ascending"), - ("descending", "Descending") + ("descending", "Descending"), ] @@ -27,14 +27,13 @@ class SearchForm(forms.Form): new = forms.BooleanField(initial=False) query = forms.CharField(max_length=100, strip=False, required=False) - domains = forms.MultipleChoiceField( - choices=get_domain_choices, required=False) + domains = forms.MultipleChoiceField(choices=get_domain_choices, required=False) sort = forms.ChoiceField( choices=get_sort_choices, widget=forms.RadioSelect( attrs={"class": "govuk-radios__input", "form": "searchform"} ), - initial="relevance" + initial="relevance", ) clear_filter = forms.BooleanField(initial=False) clear_label = forms.BooleanField(initial=False) diff --git a/home/views.py b/home/views.py index 5977072f..1b10af67 100644 --- a/home/views.py +++ b/home/views.py @@ -1,15 +1,14 @@ -from data_platform_catalogue.search_types import ( - MultiSelectFilter, ResultType, SortOption -) +from data_platform_catalogue.search_types import (MultiSelectFilter, + ResultType, SortOption) from django.conf import settings +from django.core.paginator import Paginator from django.shortcuts import render +from home.forms.search import SearchForm + from .helper import filter_seleted_domains, get_domain_list -from django.core.paginator import Paginator from .services import get_catalogue_client -from home.forms.search import SearchForm - # Create your views here. @@ -118,8 +117,7 @@ def search_view(request, page: str = "1"): else: domains = request.session.get("domains", []) filter_value = [] - context["selected_domain"] = filter_seleted_domains( - domain_list, domains) + context["selected_domain"] = filter_seleted_domains(domain_list, domains) context["domains"] = domains query = request.session.get("query", "") From d3d7d5a5a0dd56da02906f777e76c212a3018873 Mon Sep 17 00:00:00 2001 From: Mitch Dawson Date: Tue, 6 Feb 2024 14:21:56 +0000 Subject: [PATCH 091/221] add comments to search view --- home/views.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/home/views.py b/home/views.py index 1b10af67..110bd5db 100644 --- a/home/views.py +++ b/home/views.py @@ -36,9 +36,19 @@ def search_view(request, page: str = "1"): new_search = request.GET.get("new", "") if new_search: form = SearchForm() + # I think we could populate context and return render here + # return render(request, "search.html", context) else: form = SearchForm(request.GET) - print(form) + + # We need to call form.is_valid() to populate the form with the data, I believe this is why the attribute is not present. + if not form.is_valid(): + pass + # Populate context with form and Return + # return render(request, "search.html", context) + + # Pass the populated form to the get_search_results service + query = request.GET.get("query", "") page_for_search = str(int(page) - 1) client = get_catalogue_client() @@ -117,7 +127,8 @@ def search_view(request, page: str = "1"): else: domains = request.session.get("domains", []) filter_value = [] - context["selected_domain"] = filter_seleted_domains(domain_list, domains) + context["selected_domain"] = filter_seleted_domains( + domain_list, domains) context["domains"] = domains query = request.session.get("query", "") From 36691eaa38cc8ddb119fc690a6fb0a07cdbfd28c Mon Sep 17 00:00:00 2001 From: Mitch Dawson Date: Tue, 6 Feb 2024 15:16:51 +0000 Subject: [PATCH 092/221] update --- home/views.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/home/views.py b/home/views.py index 110bd5db..4a08a06d 100644 --- a/home/views.py +++ b/home/views.py @@ -41,10 +41,13 @@ def search_view(request, page: str = "1"): else: form = SearchForm(request.GET) - # We need to call form.is_valid() to populate the form with the data, I believe this is why the attribute is not present. + # I believe the reason we were receiving the sort attribute error is because we had an unbound form (form with no data). If we return render when new = True we should avoid this scenario. + + # Where we have a populated form, check if the form is valid. if not form.is_valid(): pass - # Populate context with form and Return + # Return the context and form + # context = {"form": form} # return render(request, "search.html", context) # Pass the populated form to the get_search_results service From 5fe142b4210ab2fa6fed0810042a6234cc38ca3d Mon Sep 17 00:00:00 2001 From: Mitch Dawson Date: Wed, 7 Feb 2024 14:53:21 +0000 Subject: [PATCH 093/221] search results with form --- .vscode/launch.json | 3 - home/forms/search.py | 16 ++- home/views.py | 195 ++++++++++++++++++---------------- templates/partial/filter.html | 31 ++++-- templates/search.html | 7 +- 5 files changed, 143 insertions(+), 109 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index ce9b6907..b703144f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,9 +10,6 @@ "request": "launch", "program": "${workspaceFolder}/manage.py", "args": [ - "poetry", - "run", - "python", "runserver" ], "django": true diff --git a/home/forms/search.py b/home/forms/search.py index 8a30418c..eca62ac6 100644 --- a/home/forms/search.py +++ b/home/forms/search.py @@ -1,5 +1,7 @@ from django import forms +# from home.helper import get_domain_list + def get_domain_choices(): """Make API call to obtain domain choices""" @@ -25,18 +27,24 @@ def get_sort_choices(): class SearchForm(forms.Form): """Django form to represent data product search page inputs""" - new = forms.BooleanField(initial=False) query = forms.CharField(max_length=100, strip=False, required=False) - domains = forms.MultipleChoiceField(choices=get_domain_choices, required=False) + domains = forms.MultipleChoiceField( + choices=get_domain_choices, + required=False, + widget=forms.CheckboxSelectMultiple( + attrs={"class": "govuk-checkboxes__input", "form": "searchform"} + ), + ) sort = forms.ChoiceField( choices=get_sort_choices, widget=forms.RadioSelect( attrs={"class": "govuk-radios__input", "form": "searchform"} ), initial="relevance", + required=False, ) - clear_filter = forms.BooleanField(initial=False) - clear_label = forms.BooleanField(initial=False) + clear_filter = forms.BooleanField(initial=False, required=False) + clear_label = forms.BooleanField(initial=False, required=False) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) diff --git a/home/views.py b/home/views.py index 4a08a06d..c433ac9b 100644 --- a/home/views.py +++ b/home/views.py @@ -34,108 +34,122 @@ def details_view(request, id): def search_view(request, page: str = "1"): new_search = request.GET.get("new", "") + client = get_catalogue_client() + context = {} + if new_search: form = SearchForm() - # I think we could populate context and return render here - # return render(request, "search.html", context) - else: - form = SearchForm(request.GET) - - # I believe the reason we were receiving the sort attribute error is because we had an unbound form (form with no data). If we return render when new = True we should avoid this scenario. - - # Where we have a populated form, check if the form is valid. + context["form"] = form + search_results = client.search(page=page) + + items_per_page = 20 + pages_list = list(range(search_results.total_results)) + paginator = Paginator(pages_list, items_per_page) + + context["results"] = search_results.page_results + context["total_results"] = search_results.total_results + context["page_obj"] = paginator.get_page(page) + context["page_range"] = paginator.get_elided_page_range( + page, on_each_side=2, on_ends=1 + ) + context["paginator"] = paginator + return render(request, "search.html", context) + + # Populated search scenario + form = SearchForm(request.GET) if not form.is_valid(): - pass - # Return the context and form - # context = {"form": form} - # return render(request, "search.html", context) - - # Pass the populated form to the get_search_results service - - query = request.GET.get("query", "") - page_for_search = str(int(page) - 1) - client = get_catalogue_client() - domain_list = get_domain_list(client) + print("form error on validation") + print(form.errors) - context = {} - context["form"] = form - context["domainlist"] = domain_list - - domains = request.GET.getlist("domain", []) + form_data = form.cleaned_data + query = form_data.get("query") + sortby = form_data.get("sort") - if form.sort == "ascending": + if sortby == "ascending": sort = SortOption(field="name", ascending=True) - elif form.sort == "descending": + elif sortby == "descending": sort = SortOption(field="name", ascending=False) else: sort = None + domains = form_data.get("domains") + print(f"Checked domains {domains}") + # if domains: + # selected_domain = filter_seleted_domains(domain_list, domains) + # context["selected_domain"] = selected_domain + # request.session["selected_domain"] = selected_domain + # request.session["domains"] = domains + # filter_value = [MultiSelectFilter("domains", domains)] + # query = request.session.get("query", "") + + page_for_search = str(int(page) - 1) + # client = get_catalogue_client() + + # elif request.GET.get("clear_filter") == "True": + # filter_value = [] + # context["selected_domain"] = {} + # request.session["selected_domain"] = {} + # request.session["domains"] = [] + # query = request.session.get("query", "") + # elif request.GET.get("clear_label") == "True": + # # Value to clear + # label_value = request.GET.getlist("value") + + # # Remove the selected value from list + # domains = request.session.get("domains", None) + # domains = list(set(domains) - set(label_value)) + # # Populated selected domain + # selected_domain = filter_seleted_domains(domain_list, domains) + # context["domains"] = domains + # context["selected_domain"] = selected_domain + + # # Reassign to session + # request.session["selected_domain"] = selected_domain + # request.session["domains"] = domains + # query = request.session.get("query", "") + + # if not domains: + # filter_value = [] + # else: + # filter_value = [MultiSelectFilter("domains", domains)] + + # elif request.GET.get("query"): + # query = request.GET.get("query") + # domains = request.session.get("domains", None) + # request.session["query"] = query + # context["query"] = query + # domains = request.session.get("domains", []) + + # # Preserve filter + # selected_domain = filter_seleted_domains(domain_list, domains) + # if not domains: + # filter_value = [] + # else: + # context["selected_domain"] = selected_domain + # context["domains"] = domains + # filter_value = [MultiSelectFilter("domains", domains)] + # else: + # if page == "1" and new_search: + # filter_value = [] + # request.session.clear() + # request.session["domains"] = domains + # context["selected_domain"] = {} + # context["query"] = "" + # else: + # domains = request.session.get("domains", []) + # filter_value = [] + # context["selected_domain"] = filter_seleted_domains( + # domain_list, domains) + # context["domains"] = domains + # query = request.session.get("query", "") + + # Search with filter if domains: - selected_domain = filter_seleted_domains(domain_list, domains) - context["selected_domain"] = selected_domain - request.session["selected_domain"] = selected_domain - request.session["domains"] = domains filter_value = [MultiSelectFilter("domains", domains)] - query = request.session.get("query", "") - elif request.GET.get("clear_filter") == "True": - filter_value = [] - context["selected_domain"] = {} - request.session["selected_domain"] = {} - request.session["domains"] = [] - query = request.session.get("query", "") - elif request.GET.get("clear_label") == "True": - # Value to clear - label_value = request.GET.getlist("value") - - # Remove the selected value from list - domains = request.session.get("domains", None) - domains = list(set(domains) - set(label_value)) - # Populated selected domain - selected_domain = filter_seleted_domains(domain_list, domains) - context["domains"] = domains - context["selected_domain"] = selected_domain - - # Reassign to session - request.session["selected_domain"] = selected_domain - request.session["domains"] = domains - query = request.session.get("query", "") - - if not domains: - filter_value = [] - else: - filter_value = [MultiSelectFilter("domains", domains)] - - elif request.GET.get("query"): - query = request.GET.get("query") - domains = request.session.get("domains", None) - request.session["query"] = query - context["query"] = query - domains = request.session.get("domains", []) - - # Preserve filter - selected_domain = filter_seleted_domains(domain_list, domains) - if not domains: - filter_value = [] - else: - context["selected_domain"] = selected_domain - context["domains"] = domains - filter_value = [MultiSelectFilter("domains", domains)] else: - if page == "1" and new_search: - filter_value = [] - request.session.clear() - request.session["domains"] = domains - context["selected_domain"] = {} - context["query"] = "" - else: - domains = request.session.get("domains", []) - filter_value = [] - context["selected_domain"] = filter_seleted_domains( - domain_list, domains) - context["domains"] = domains - query = request.session.get("query", "") + filter_value = None - # Search with filter + page_for_search = str(int(page) - 1) search_results = client.search( query=query, page=page_for_search, filters=filter_value, sort=sort @@ -145,7 +159,8 @@ def search_view(request, page: str = "1"): pages_list = list(range(search_results.total_results)) paginator = Paginator(pages_list, items_per_page) - context["query"] = query + context["form"] = form + # context["query"] = query context["results"] = search_results.page_results context["total_results"] = search_results.total_results context["page_obj"] = paginator.get_page(page) @@ -153,7 +168,7 @@ def search_view(request, page: str = "1"): page, on_each_side=2, on_ends=1 ) context["paginator"] = paginator - context["sortby"] = sort + # context["sortby"] = sort if query: context["page_title"] = f'Search for "{query}" - Data catalogue' diff --git a/templates/partial/filter.html b/templates/partial/filter.html index 7417547d..087c2855 100644 --- a/templates/partial/filter.html +++ b/templates/partial/filter.html @@ -7,7 +7,7 @@

    Filter

    - +
    @@ -25,7 +25,7 @@

    Selected filters

    - {% if selected_domain %} + + + + {% if form.domains.value %} +

    Domain

    + {% endif %}
    -
    +
    @@ -43,14 +56,18 @@

    Domain

    Domain
    - {% for option in domainlist%} + {% for domain_option in form.domains %}
    - - + {{ domain_option.tag}} + +
    {% endfor %}
    -
    +
    diff --git a/templates/search.html b/templates/search.html index b6e27347..4997ba91 100644 --- a/templates/search.html +++ b/templates/search.html @@ -25,11 +25,8 @@

    Find MOJ Data

    {{total_results|intcomma}} Results

    {% include "partial/sort.html" %} - - + {% include "partial/search_result.html" %} + {% include "partial/pagination.html" %}
    {% endblock content %} From f27cd95cbee704f3f3f9bbc079ef887b0cc50e79 Mon Sep 17 00:00:00 2001 From: LavMatt Date: Wed, 7 Feb 2024 15:54:14 +0000 Subject: [PATCH 094/221] add domain urns to get domain choices --- home/forms/search.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/home/forms/search.py b/home/forms/search.py index eca62ac6..77dc3f9f 100644 --- a/home/forms/search.py +++ b/home/forms/search.py @@ -9,10 +9,10 @@ def get_domain_choices(): # facets = client.search_facets() # domain_list = facets.options("domains") return [ - ("HMCTS", "HMCTS"), - ("HMPPS", "HMPPS"), - ("OPG", "OPG"), - ("HQ", "HQ"), + ("urn:li:domain:HMCTS", "HMCTS"), + ("urn:li:domain:HMPPS", "HMPPS"), + ("urn:li:domain:OPG", "OPG"), + ("urn:li:domain:HQ", "HQ"), ] From 81bc0450a039c75ce907026a267ff71fc8cecb32 Mon Sep 17 00:00:00 2001 From: LavMatt Date: Wed, 7 Feb 2024 15:55:29 +0000 Subject: [PATCH 095/221] get filtering working --- home/templatetags/future.py | 38 ++++++++++++++++++++++++++++ home/views.py | 21 +++++++++------ templates/partial/filter.html | 9 ++++--- templates/partial/pagination.html | 7 ++--- templates/partial/search_result.html | 2 +- 5 files changed, 61 insertions(+), 16 deletions(-) create mode 100644 home/templatetags/future.py diff --git a/home/templatetags/future.py b/home/templatetags/future.py new file mode 100644 index 00000000..759cdc33 --- /dev/null +++ b/home/templatetags/future.py @@ -0,0 +1,38 @@ +from django import template +from django.utils.itercompat import is_iterable + +register = template.Library() + + +# Backport from unreleased Django +# This can be removed after Django 5.1 is released +@register.simple_tag(takes_context=True) +def query_string(context, query_dict=None, **kwargs): + """ + Add, remove, and change parameters of a ``QueryDict`` and return the result + as a query string. If the ``query_dict`` argument is not provided, default + to ``request.GET``. + For example:: + {% query_string foo=3 %} + To remove a key:: + {% query_string foo=None %} + To use with pagination:: + {% query_string page=page_obj.next_page_number %} + A custom ``QueryDict`` can also be used:: + {% query_string my_query_dict foo=3 %} + """ + if query_dict is None: + query_dict = context.request.GET + query_dict = query_dict.copy() + for key, value in kwargs.items(): + if value is None: + if key in query_dict: + del query_dict[key] + elif is_iterable(value) and not isinstance(value, str): + query_dict.setlist(key, value) + else: + query_dict[key] = value + if not query_dict: + return "" + query_string = query_dict.urlencode() + return f"?{query_string}" diff --git a/home/views.py b/home/views.py index c433ac9b..00be98fb 100644 --- a/home/views.py +++ b/home/views.py @@ -1,5 +1,8 @@ -from data_platform_catalogue.search_types import (MultiSelectFilter, - ResultType, SortOption) +from data_platform_catalogue.search_types import ( + MultiSelectFilter, + ResultType, + SortOption, +) from django.conf import settings from django.core.paginator import Paginator from django.shortcuts import render @@ -36,13 +39,13 @@ def search_view(request, page: str = "1"): new_search = request.GET.get("new", "") client = get_catalogue_client() context = {} + items_per_page = 2 if new_search: form = SearchForm() context["form"] = form - search_results = client.search(page=page) + search_results = client.search(page=page, count=items_per_page) - items_per_page = 20 pages_list = list(range(search_results.total_results)) paginator = Paginator(pages_list, items_per_page) @@ -147,15 +150,17 @@ def search_view(request, page: str = "1"): if domains: filter_value = [MultiSelectFilter("domains", domains)] else: - filter_value = None + filter_value = [] page_for_search = str(int(page) - 1) search_results = client.search( - query=query, page=page_for_search, filters=filter_value, sort=sort + query=query, + page=page_for_search, + filters=filter_value, + sort=sort, + count=items_per_page, ) - - items_per_page = 20 pages_list = list(range(search_results.total_results)) paginator = Paginator(pages_list, items_per_page) diff --git a/templates/partial/filter.html b/templates/partial/filter.html index 087c2855..971403af 100644 --- a/templates/partial/filter.html +++ b/templates/partial/filter.html @@ -40,10 +40,11 @@

    Domain

    Domain

    {% endif %} diff --git a/templates/partial/pagination.html b/templates/partial/pagination.html index bcebe556..f4bc9ebb 100644 --- a/templates/partial/pagination.html +++ b/templates/partial/pagination.html @@ -1,7 +1,8 @@ +{% load future %} From 8f7b4e70ac0127a74fcb464e8fc34c07736b9a43 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 9 Feb 2024 16:02:47 +0000 Subject: [PATCH 108/221] Commit changes made by code formatters --- home/service/search.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/home/service/search.py b/home/service/search.py index 07083dc4..95f1092f 100644 --- a/home/service/search.py +++ b/home/service/search.py @@ -25,7 +25,8 @@ def _get_search_results(self, page: str, items_per_page: int): query = form_data.get("query", "") sort = form_data.get("sort", "relevance") domains = form_data.get("domains", []) - filter_value = [MultiSelectFilter("domains", domains)] if domains else [] + filter_value = [MultiSelectFilter( + "domains", domains)] if domains else [] page_for_search = str(int(page) - 1) if sort == "ascending": sort_option = SortOption(field="name", ascending=True) From 8db01d1789dbe4152cd8dca71b9d476500c813d9 Mon Sep 17 00:00:00 2001 From: Mitch Dawson Date: Mon, 12 Feb 2024 12:40:52 +0000 Subject: [PATCH 109/221] resolve page title display issue --- home/service/search.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/home/service/search.py b/home/service/search.py index 95f1092f..f6a7afa5 100644 --- a/home/service/search.py +++ b/home/service/search.py @@ -52,8 +52,8 @@ def _get_paginator(self, items_per_page: int) -> Paginator: def _get_context(self) -> dict[str, Any]: - if self.form["query"].value: - page_title = f'Search for "{self.form["query"].value}" - Data catalogue' + if self.form["query"].value(): + page_title = f'Search for "{self.form["query"].value()}" - Data catalogue' else: page_title = "Search - Data catalogue" From f432b88460d88a66578c425b1c6d357c9705d982 Mon Sep 17 00:00:00 2001 From: Murdo Moyse Date: Tue, 13 Feb 2024 12:22:45 +0000 Subject: [PATCH 110/221] Removed unneeded method --- home/forms/search.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/home/forms/search.py b/home/forms/search.py index ee4dae15..1939673f 100644 --- a/home/forms/search.py +++ b/home/forms/search.py @@ -2,8 +2,6 @@ from django import forms from urllib.parse import urlencode -# from home.helper import get_domain_list - def get_domain_choices(): """Make API call to obtain domain choices""" @@ -60,10 +58,6 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.initial["sort"] = "relevance" - def clean_query(self): - """Example clean method to apply custom validation to input fields""" - return str(self.cleaned_data["query"]).capitalize() - def encode_without_filter(self, filter_to_remove): """Preformat hrefs to drop individual filters""" # Deepcopy the cleaned data dict to avoid modifying it inplace From 931105fbed2892bec3ef90544c18d2d921e44ba0 Mon Sep 17 00:00:00 2001 From: Murdo Moyse Date: Tue, 13 Feb 2024 12:23:46 +0000 Subject: [PATCH 111/221] Added default value to fix dictionary generator --- home/service/search.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/home/service/search.py b/home/service/search.py index 95f1092f..3165635c 100644 --- a/home/service/search.py +++ b/home/service/search.py @@ -60,7 +60,7 @@ def _get_context(self) -> dict[str, Any]: if self.form.is_bound: label_clear_href = { filter.split(":")[-1]: self.form.encode_without_filter(filter) - for filter in self.form.cleaned_data.get("domains") + for filter in self.form.cleaned_data.get("domains", []) } else: label_clear_href = None From 16c58f5fd81ee13f6cd348d93e39c0bc7a1b0346 Mon Sep 17 00:00:00 2001 From: Murdo Moyse Date: Tue, 13 Feb 2024 12:24:07 +0000 Subject: [PATCH 112/221] Added pytest tests for forms and views --- .github/workflows/test.yml | 17 ++++ core/settings.py | 6 ++ home/views.py | 7 +- poetry.lock | 151 ++++++++++++++++++++++++++++++++- pyproject.toml | 6 ++ tests/__init__.py | 0 tests/conftest.py | 71 ++++++++++++++++ tests/home/__init__.py | 0 tests/home/views/__init__.py | 0 tests/home/views/test_views.py | 95 --------------------- tests/test_forms.py | 46 ++++++++++ tests/test_views.py | 46 ++++++++++ 12 files changed, 344 insertions(+), 101 deletions(-) create mode 100644 .github/workflows/test.yml delete mode 100644 tests/__init__.py create mode 100644 tests/conftest.py delete mode 100644 tests/home/__init__.py delete mode 100644 tests/home/views/__init__.py delete mode 100644 tests/home/views/test_views.py create mode 100644 tests/test_forms.py create mode 100644 tests/test_views.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..8d2bdeb1 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,17 @@ +name: test + +on: + pull_request: + types: [opened, edited, reopened, synchronize] + push: + branches: [main] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: test + run: python manage.py test tests + - name: Codecov + uses: codecov/codecov-action@v4.0.1 diff --git a/core/settings.py b/core/settings.py index 8813a6ed..c753d7f1 100644 --- a/core/settings.py +++ b/core/settings.py @@ -64,6 +64,12 @@ # Database # https://docs.djangoproject.com/en/5.0/ref/settings/#databases +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": "db", + } +} # Password validation diff --git a/home/views.py b/home/views.py index 45db819d..5937a65d 100644 --- a/home/views.py +++ b/home/views.py @@ -1,5 +1,5 @@ -from django.core.exceptions import ObjectDoesNotExist -from django.http import Http404 +from django.core.exceptions import ObjectDoesNotExist, ValidationError +from django.http import Http404, HttpResponseBadRequest from django.shortcuts import render from home.forms.search import SearchForm @@ -31,8 +31,7 @@ def search_view(request, page: str = "1"): # Populated search scenario form = SearchForm(request.GET) if not form.is_valid(): - print("form error on validation") - print(form.errors) + return HttpResponseBadRequest(form.errors) search_service = SearchService(form=form, page=page) return render(request, "search.html", search_service.context) diff --git a/poetry.lock b/poetry.lock index e48a14a1..8e0cdb01 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "acryl-datahub" @@ -1344,6 +1344,17 @@ gevent = ["gevent (>=1.4.0)"] setproctitle = ["setproctitle"] tornado = ["tornado (>=0.2)"] +[[package]] +name = "h11" +version = "0.14.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.7" +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] + [[package]] name = "humanfriendly" version = "10.0" @@ -2008,6 +2019,20 @@ files = [ [package.extras] dev = ["black", "mypy", "pytest"] +[[package]] +name = "outcome" +version = "1.3.0.post0" +description = "Capture the outcome of Python function calls." +optional = false +python-versions = ">=3.7" +files = [ + {file = "outcome-1.3.0.post0-py2.py3-none-any.whl", hash = "sha256:e771c5ce06d1415e356078d3bdd68523f284b4ce5419828922b6871e65eda82b"}, + {file = "outcome-1.3.0.post0.tar.gz", hash = "sha256:9dcf02e65f2971b80047b377468e72a268e15c0af3cf1238e6ff14f7f91143b8"}, +] + +[package.dependencies] +attrs = ">=19.2.0" + [[package]] name = "packaging" version = "23.2" @@ -2273,6 +2298,18 @@ files = [ {file = "pyreadline3-3.4.1.tar.gz", hash = "sha256:6f3d1f7b8a31ba32b73917cefc1f28cc660562f39aea8646d30bd6eff21f7bae"}, ] +[[package]] +name = "pysocks" +version = "1.7.1" +description = "A Python SOCKS client module. See https://github.com/Anorov/PySocks for more information." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "PySocks-1.7.1-py27-none-any.whl", hash = "sha256:08e69f092cc6dbe92a0fdd16eeb9b9ffbc13cadfe5ca4c7bd92ffb078b293299"}, + {file = "PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5"}, + {file = "PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0"}, +] + [[package]] name = "pytest" version = "8.0.0" @@ -2293,6 +2330,24 @@ pluggy = ">=1.3.0,<2.0" [package.extras] testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +[[package]] +name = "pytest-django" +version = "4.8.0" +description = "A Django plugin for pytest." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-django-4.8.0.tar.gz", hash = "sha256:5d054fe011c56f3b10f978f41a8efb2e5adfc7e680ef36fb571ada1f24779d90"}, + {file = "pytest_django-4.8.0-py3-none-any.whl", hash = "sha256:ca1ddd1e0e4c227cf9e3e40a6afc6d106b3e70868fd2ac5798a22501271cd0c7"}, +] + +[package.dependencies] +pytest = ">=7.0.0" + +[package.extras] +docs = ["sphinx", "sphinx-rtd-theme"] +testing = ["Django", "django-configurations (>=2.0)"] + [[package]] name = "python-dateutil" version = "2.8.2" @@ -2409,6 +2464,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -2829,6 +2885,24 @@ botocore = ">=1.33.2,<2.0a.0" [package.extras] crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"] +[[package]] +name = "selenium" +version = "4.17.2" +description = "" +optional = false +python-versions = ">=3.8" +files = [ + {file = "selenium-4.17.2-py3-none-any.whl", hash = "sha256:5aee79026c07985dc1b0c909f34084aa996dfe5b307602de9016d7a621a473f2"}, + {file = "selenium-4.17.2.tar.gz", hash = "sha256:d43d6972e516855fb242ef9ce4ce759057b115070e702e7b1c1032fe7b38d87b"}, +] + +[package.dependencies] +certifi = ">=2021.10.8" +trio = ">=0.17,<1.0" +trio-websocket = ">=0.9,<1.0" +typing_extensions = ">=4.9.0" +urllib3 = {version = ">=1.26,<3", extras = ["socks"]} + [[package]] name = "sentry-sdk" version = "1.40.0" @@ -2901,6 +2975,28 @@ files = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] +[[package]] +name = "sniffio" +version = "1.3.0" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +files = [ + {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, + {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, +] + +[[package]] +name = "sortedcontainers" +version = "2.4.0" +description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" +optional = false +python-versions = "*" +files = [ + {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, + {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, +] + [[package]] name = "soupsieve" version = "2.5" @@ -3103,6 +3199,40 @@ notebook = ["ipywidgets (>=6)"] slack = ["slack-sdk"] telegram = ["requests"] +[[package]] +name = "trio" +version = "0.24.0" +description = "A friendly Python library for async concurrency and I/O" +optional = false +python-versions = ">=3.8" +files = [ + {file = "trio-0.24.0-py3-none-any.whl", hash = "sha256:c3bd3a4e3e3025cd9a2241eae75637c43fe0b9e88b4c97b9161a55b9e54cd72c"}, + {file = "trio-0.24.0.tar.gz", hash = "sha256:ffa09a74a6bf81b84f8613909fb0beaee84757450183a7a2e0b47b455c0cac5d"}, +] + +[package.dependencies] +attrs = ">=20.1.0" +cffi = {version = ">=1.14", markers = "os_name == \"nt\" and implementation_name != \"pypy\""} +idna = "*" +outcome = "*" +sniffio = ">=1.3.0" +sortedcontainers = "*" + +[[package]] +name = "trio-websocket" +version = "0.11.1" +description = "WebSocket library for Trio" +optional = false +python-versions = ">=3.7" +files = [ + {file = "trio-websocket-0.11.1.tar.gz", hash = "sha256:18c11793647703c158b1f6e62de638acada927344d534e3c7628eedcb746839f"}, + {file = "trio_websocket-0.11.1-py3-none-any.whl", hash = "sha256:520d046b0d030cf970b8b2b2e00c4c2245b3807853ecd44214acd33d74581638"}, +] + +[package.dependencies] +trio = ">=0.11" +wsproto = ">=0.14" + [[package]] name = "typing-compat" version = "0.1.0" @@ -3162,6 +3292,9 @@ files = [ {file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"}, ] +[package.dependencies] +pysocks = {version = ">=1.5.6,<1.5.7 || >1.5.7,<2.0", optional = true, markers = "extra == \"socks\""} + [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] @@ -3295,6 +3428,20 @@ files = [ {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, ] +[[package]] +name = "wsproto" +version = "1.2.0" +description = "WebSockets state-machine based protocol implementation" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "wsproto-1.2.0-py3-none-any.whl", hash = "sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736"}, + {file = "wsproto-1.2.0.tar.gz", hash = "sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065"}, +] + +[package.dependencies] +h11 = ">=0.9.0,<1" + [[package]] name = "yarl" version = "1.9.4" @@ -3416,4 +3563,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "0ae06695e2ac3dedebe33805f20a25c4cf72a2395ce547f5cbb66f4f1f8cc6e7" +content-hash = "b833865181628affa1f1da6bd9834d2158f694392c8765a9294955034a33a419" diff --git a/pyproject.toml b/pyproject.toml index 68694726..8ef748e8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,8 @@ ministryofjustice-data-platform-catalogue = "^0.10.0" markdown = "^3.5.2" python-dotenv = "^1.0.1" faker = "^22.6.0" +selenium = "^4.17.2" +pytest-django = "^4.8.0" [tool.poetry.group.dev] # dev group definition @@ -25,3 +27,7 @@ pre-commit = "^3.6.0" [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" + +[tool.pytest.ini_options] +DJANGO_SETTINGS_MODULE = "core.settings" +python_files = ["test_*.py", "*_test.py", "testing/python/*.py"] diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 00000000..4433fae3 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,71 @@ +from random import choice +from unittest.mock import MagicMock, patch + +import pytest +from data_platform_catalogue.client import BaseCatalogueClient +from data_platform_catalogue.search_types import (FacetOption, ResultType, + SearchFacets, SearchResponse, + SearchResult) +from django.test import Client +from faker import Faker + +fake = Faker() + + +def generate_page(page_size=20): + """ + Generate a fake search page + """ + results = [] + for _ in range(page_size): + results.append( + SearchResult( + id=fake.unique.name(), + result_type=choice( + (ResultType.DATA_PRODUCT, ResultType.TABLE)), + name=fake.name(), + description=fake.paragraphs(), + ) + ) + return results + + +def generate_options(num_options=5): + """ + Generate a list of options for the search facets + """ + results = [] + for _ in range(num_options): + results.append( + FacetOption( + value=fake.name(), + label=fake.name(), + count=fake.random_int(min=0, max=100), + ) + ) + return results + +@pytest.fixture(autouse=True) +def client(): + client = Client() + return client + +@pytest.fixture(autouse=True) +def mock_catalogue(): + patcher = patch("home.service.base.GenericService._get_catalogue_client") + mock_fn = patcher.start() + mock_catalogue = MagicMock(spec=BaseCatalogueClient) + mock_fn.return_value = mock_catalogue + mock_search_response(mock_catalogue, page_results=generate_page(), total_results=100) + mock_search_facets_response(mock_catalogue, domains=generate_options()) + + yield mock_catalogue + + patcher.stop() + +def mock_search_response(mock_catalogue, total_results=0, page_results=()): + search_response = SearchResponse(total_results=total_results, page_results=page_results) + mock_catalogue.search.return_value = search_response + +def mock_search_facets_response(mock_catalogue, domains): + mock_catalogue.search_facets.return_value = SearchFacets({"domains": domains}) diff --git a/tests/home/__init__.py b/tests/home/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/home/views/__init__.py b/tests/home/views/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/home/views/test_views.py b/tests/home/views/test_views.py deleted file mode 100644 index 7d0dddf2..00000000 --- a/tests/home/views/test_views.py +++ /dev/null @@ -1,95 +0,0 @@ -from random import choice -from unittest import skip -from unittest.mock import MagicMock, patch - -from data_platform_catalogue.client import BaseCatalogueClient -from data_platform_catalogue.search_types import (FacetOption, ResultType, - SearchFacets, SearchResponse, - SearchResult) -from django.test import SimpleTestCase -from django.urls import reverse -from faker import Faker - -fake = Faker() - - -def generate_page(page_size=20): - """ - Generate a fake search page - """ - results = [] - for _ in range(page_size): - results.append( - SearchResult( - id=fake.unique.name(), - result_type=choice( - (ResultType.DATA_PRODUCT, ResultType.TABLE)), - name=fake.name(), - description=fake.paragraphs(), - ) - ) - return results - - -def generate_options(num_options=5): - """ - Generate a list of options for the search facets - """ - results = [] - for _ in range(num_options): - results.append( - FacetOption( - value=fake.name(), - label=fake.name(), - count=fake.random_int(min=0, max=100), - ) - ) - return results - - -class SearchViewTests(SimpleTestCase): - """ - Test the view renders the correct context depending on query parameters and session - """ - - def setUp(self): - self.patcher = patch("home.views.get_catalogue_client") - mock_fn = self.patcher.start() - self.mock_client = MagicMock(spec=BaseCatalogueClient) - mock_fn.return_value = self.mock_client - self.mock_search_response( - page_results=generate_page(), total_results=100) - self.mock_search_facets_response(domains=generate_options()) - - def tearDown(self): - self.patcher.stop() - - def mock_search_response(self, total_results=0, page_results=()): - search_response = SearchResponse( - total_results=total_results, page_results=page_results - ) - self.mock_client.search.return_value = search_response - - def mock_search_facets_response(self, domains): - self.mock_client.search_facets.return_value = SearchFacets( - {"domains": domains}) - - def test_renders_200(self): - response = self.client.get(reverse("home:search"), data={}) - self.assertEqual(response.status_code, 200) - - def test_exposes_results(self): - response = self.client.get(reverse("home:search"), data={}) - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.context["results"]), 20) - - def test_exposes_empty_query(self): - response = self.client.get(reverse("home:search"), data={}) - self.assertEqual(response.status_code, 200) - self.assertEqual(response.context["query"], "") - - def test_exposes_query(self): - response = self.client.get( - reverse("home:search"), data={"query": "foo"}) - self.assertEqual(response.status_code, 200) - self.assertEqual(response.context["query"], "foo") diff --git a/tests/test_forms.py b/tests/test_forms.py new file mode 100644 index 00000000..1348b1ae --- /dev/null +++ b/tests/test_forms.py @@ -0,0 +1,46 @@ +from django.test import TestCase +from home.forms.search import SearchForm + + +class SearchFormTest(TestCase): + def setUp(self): + self.valid_form = SearchForm( + data={ + "query": "test", + "domains": ["urn:li:domain:HMCTS"], + "sort": "ascending", + "clear_filter": False, + "clear_label": False, + } + ) + + assert self.valid_form.is_valid() + + def test_query_field_length(self): + over_100_characters = "a" * 101 + assert not SearchForm(data={"query": over_100_characters}).is_valid() + + def test_domain_is_from_domain_list_false(self): + assert not SearchForm(data={"domains": ["fake"]}).is_valid() + + def test_sort_is_from_sort_list_false(self): + assert not SearchForm(data={"sort": ["fake"]}).is_valid() + + def test_all_fields_nullable(self): + assert SearchForm(data={}).is_valid() + + + def test_form_encode_without_filter_for_one_filter(self): + assert (self.valid_form.encode_without_filter("urn:li:domain:HMCTS") == + "?query=test&sort=ascending&clear_filter=False&clear_label=False") + + def test_form_encode_without_filter_for_two_filters(self): + two_filter_form = SearchForm(data={ + "query": "test", + "domains": ["urn:li:domain:HMCTS", "urn:li:domain:HMPPS"] + }) + two_filter_form.is_valid() + + assert (two_filter_form.encode_without_filter("urn:li:domain:HMCTS") == + "?query=test&domains=urn%3Ali%3Adomain%3AHMPPS&sort=&clear_filter=False&clear_label=False") + diff --git a/tests/test_views.py b/tests/test_views.py new file mode 100644 index 00000000..8db493d3 --- /dev/null +++ b/tests/test_views.py @@ -0,0 +1,46 @@ + +from data_platform_catalogue.search_types import SearchResponse +from django.urls import reverse + + +class TestSearchView: + """ + Test the view renders the correct context depending on query parameters and session + """ + def test_renders_200(self, client): + response = client.get(reverse("home:search"), data={}) + assert response.status_code == 200 + + def test_exposes_results(self, client): + response = client.get(reverse("home:search"), data={}) + assert response.status_code == 200 + assert len(response.context["results"]) == 20 + + def test_exposes_empty_query(self, client): + response = client.get(reverse("home:search"), data={}) + assert response.status_code == 200 + assert response.context["form"].cleaned_data["query"] == "" + + def test_exposes_query(self, client): + response = client.get(reverse("home:search"), data={"query": "foo"}) + assert response.status_code == 200 + assert response.context["form"].cleaned_data["query"] == "foo" + + def test_bad_form(self, client): + response = client.get(reverse("home:search"), data={"domains": "fake"}) + assert response.status_code == 400 + + +class TestDetailsView: + def test_details(self, client): + response = client.get( + reverse("home:details", kwargs={"id": "urn:li:dataProduct:common-platform"}) + ) + assert response.status_code == 200 + + def test_details_not_found(self, client, mock_catalogue): + mock_catalogue.search.return_value = SearchResponse( + total_results=0, page_results=[] + ) + response = client.get(reverse("home:details", kwargs={"id": "fake"})) + assert response.status_code == 404 From 7b1294280ce3ea4d61345aeff56993d7bdae6219 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 13 Feb 2024 12:25:32 +0000 Subject: [PATCH 113/221] Commit changes made by code formatters --- tests/conftest.py | 13 ++++++++++--- tests/test_forms.py | 6 ++---- tests/test_views.py | 4 +++- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 4433fae3..48849efc 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -45,27 +45,34 @@ def generate_options(num_options=5): ) return results + @pytest.fixture(autouse=True) def client(): client = Client() return client + @pytest.fixture(autouse=True) def mock_catalogue(): patcher = patch("home.service.base.GenericService._get_catalogue_client") mock_fn = patcher.start() mock_catalogue = MagicMock(spec=BaseCatalogueClient) mock_fn.return_value = mock_catalogue - mock_search_response(mock_catalogue, page_results=generate_page(), total_results=100) + mock_search_response( + mock_catalogue, page_results=generate_page(), total_results=100) mock_search_facets_response(mock_catalogue, domains=generate_options()) yield mock_catalogue patcher.stop() + def mock_search_response(mock_catalogue, total_results=0, page_results=()): - search_response = SearchResponse(total_results=total_results, page_results=page_results) + search_response = SearchResponse( + total_results=total_results, page_results=page_results) mock_catalogue.search.return_value = search_response + def mock_search_facets_response(mock_catalogue, domains): - mock_catalogue.search_facets.return_value = SearchFacets({"domains": domains}) + mock_catalogue.search_facets.return_value = SearchFacets( + {"domains": domains}) diff --git a/tests/test_forms.py b/tests/test_forms.py index 1348b1ae..bcfb6cba 100644 --- a/tests/test_forms.py +++ b/tests/test_forms.py @@ -29,10 +29,9 @@ def test_sort_is_from_sort_list_false(self): def test_all_fields_nullable(self): assert SearchForm(data={}).is_valid() - def test_form_encode_without_filter_for_one_filter(self): assert (self.valid_form.encode_without_filter("urn:li:domain:HMCTS") == - "?query=test&sort=ascending&clear_filter=False&clear_label=False") + "?query=test&sort=ascending&clear_filter=False&clear_label=False") def test_form_encode_without_filter_for_two_filters(self): two_filter_form = SearchForm(data={ @@ -42,5 +41,4 @@ def test_form_encode_without_filter_for_two_filters(self): two_filter_form.is_valid() assert (two_filter_form.encode_without_filter("urn:li:domain:HMCTS") == - "?query=test&domains=urn%3Ali%3Adomain%3AHMPPS&sort=&clear_filter=False&clear_label=False") - + "?query=test&domains=urn%3Ali%3Adomain%3AHMPPS&sort=&clear_filter=False&clear_label=False") diff --git a/tests/test_views.py b/tests/test_views.py index 8db493d3..1f46c9ba 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -7,6 +7,7 @@ class TestSearchView: """ Test the view renders the correct context depending on query parameters and session """ + def test_renders_200(self, client): response = client.get(reverse("home:search"), data={}) assert response.status_code == 200 @@ -34,7 +35,8 @@ def test_bad_form(self, client): class TestDetailsView: def test_details(self, client): response = client.get( - reverse("home:details", kwargs={"id": "urn:li:dataProduct:common-platform"}) + reverse("home:details", kwargs={ + "id": "urn:li:dataProduct:common-platform"}) ) assert response.status_code == 200 From bcebdfa5ad13f622072b4687279540e1facaf4a9 Mon Sep 17 00:00:00 2001 From: Murdo Moyse Date: Tue, 13 Feb 2024 12:34:53 +0000 Subject: [PATCH 114/221] Trying testing workflow --- .github/workflows/test.yml | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8d2bdeb1..d5d5c2fe 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,15 +3,32 @@ name: test on: pull_request: types: [opened, edited, reopened, synchronize] - push: - branches: [main] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: test - run: python manage.py test tests - - name: Codecov - uses: codecov/codecov-action@v4.0.1 + - uses: actions/setup-python@v2 + with: + python-version: 3.10 + - name: cache poetry install + uses: actions/cache@v2 + with: + path: ~/.local + key: poetry-1.1.12-0 + - uses: snok/install-poetry@v1 + with: + version: 1.1.12 + virtualenvs-create: true + virtualenvs-in-project: true + - name: cache deps + id: cache-deps + uses: actions/cache@v2 + with: + path: .venv + key: pydeps-${{ hashFiles('**/poetry.lock') }} + - run: poetry install --no-interaction --no-root + if: steps.cache-deps.outputs.cache-hit != 'true' + - run: poetry install --no-interaction + - run: poetry run pytest From 247290c176712c82a4a57dbbb3163ba90f14417f Mon Sep 17 00:00:00 2001 From: Murdo Moyse Date: Tue, 13 Feb 2024 12:38:18 +0000 Subject: [PATCH 115/221] Used 3.11.1 --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d5d5c2fe..9cecbe90 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,4 +1,5 @@ name: test +# based on https://jacobian.org/til/github-actions-poetry/ on: pull_request: @@ -11,7 +12,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-python@v2 with: - python-version: 3.10 + python-version: 3.11.1 - name: cache poetry install uses: actions/cache@v2 with: From 65c357311c1178b8bf42a6203fcf3a7be3787504 Mon Sep 17 00:00:00 2001 From: Murdo Moyse Date: Tue, 13 Feb 2024 12:42:56 +0000 Subject: [PATCH 116/221] Trying newer poetry version --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9cecbe90..75920b5f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,10 +17,10 @@ jobs: uses: actions/cache@v2 with: path: ~/.local - key: poetry-1.1.12-0 + key: poetry-1.7.1-0 - uses: snok/install-poetry@v1 with: - version: 1.1.12 + version: 1.7.1 virtualenvs-create: true virtualenvs-in-project: true - name: cache deps From 9c918a47218375de8e83f0eb77826bc9a86307ff Mon Sep 17 00:00:00 2001 From: Murdo Moyse Date: Tue, 13 Feb 2024 12:51:58 +0000 Subject: [PATCH 117/221] Added coverage report --- .github/workflows/test.yml | 2 + poetry.lock | 84 +++++++++++++++++++++++++++++++++++++- pyproject.toml | 1 + 3 files changed, 86 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 75920b5f..f9ac5695 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -33,3 +33,5 @@ jobs: if: steps.cache-deps.outputs.cache-hit != 'true' - run: poetry install --no-interaction - run: poetry run pytest + - name: coverage + run: poetry run pytest --cov diff --git a/poetry.lock b/poetry.lock index 8e0cdb01..1b541012 100644 --- a/poetry.lock +++ b/poetry.lock @@ -710,6 +710,70 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "coverage" +version = "7.4.1" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "coverage-7.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:077d366e724f24fc02dbfe9d946534357fda71af9764ff99d73c3c596001bbd7"}, + {file = "coverage-7.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0193657651f5399d433c92f8ae264aff31fc1d066deee4b831549526433f3f61"}, + {file = "coverage-7.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d17bbc946f52ca67adf72a5ee783cd7cd3477f8f8796f59b4974a9b59cacc9ee"}, + {file = "coverage-7.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3277f5fa7483c927fe3a7b017b39351610265308f5267ac6d4c2b64cc1d8d25"}, + {file = "coverage-7.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6dceb61d40cbfcf45f51e59933c784a50846dc03211054bd76b421a713dcdf19"}, + {file = "coverage-7.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6008adeca04a445ea6ef31b2cbaf1d01d02986047606f7da266629afee982630"}, + {file = "coverage-7.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c61f66d93d712f6e03369b6a7769233bfda880b12f417eefdd4f16d1deb2fc4c"}, + {file = "coverage-7.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b9bb62fac84d5f2ff523304e59e5c439955fb3b7f44e3d7b2085184db74d733b"}, + {file = "coverage-7.4.1-cp310-cp310-win32.whl", hash = "sha256:f86f368e1c7ce897bf2457b9eb61169a44e2ef797099fb5728482b8d69f3f016"}, + {file = "coverage-7.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:869b5046d41abfea3e381dd143407b0d29b8282a904a19cb908fa24d090cc018"}, + {file = "coverage-7.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b8ffb498a83d7e0305968289441914154fb0ef5d8b3157df02a90c6695978295"}, + {file = "coverage-7.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3cacfaefe6089d477264001f90f55b7881ba615953414999c46cc9713ff93c8c"}, + {file = "coverage-7.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d6850e6e36e332d5511a48a251790ddc545e16e8beaf046c03985c69ccb2676"}, + {file = "coverage-7.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18e961aa13b6d47f758cc5879383d27b5b3f3dcd9ce8cdbfdc2571fe86feb4dd"}, + {file = "coverage-7.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfd1e1b9f0898817babf840b77ce9fe655ecbe8b1b327983df485b30df8cc011"}, + {file = "coverage-7.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6b00e21f86598b6330f0019b40fb397e705135040dbedc2ca9a93c7441178e74"}, + {file = "coverage-7.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:536d609c6963c50055bab766d9951b6c394759190d03311f3e9fcf194ca909e1"}, + {file = "coverage-7.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7ac8f8eb153724f84885a1374999b7e45734bf93a87d8df1e7ce2146860edef6"}, + {file = "coverage-7.4.1-cp311-cp311-win32.whl", hash = "sha256:f3771b23bb3675a06f5d885c3630b1d01ea6cac9e84a01aaf5508706dba546c5"}, + {file = "coverage-7.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:9d2f9d4cc2a53b38cabc2d6d80f7f9b7e3da26b2f53d48f05876fef7956b6968"}, + {file = "coverage-7.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f68ef3660677e6624c8cace943e4765545f8191313a07288a53d3da188bd8581"}, + {file = "coverage-7.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:23b27b8a698e749b61809fb637eb98ebf0e505710ec46a8aa6f1be7dc0dc43a6"}, + {file = "coverage-7.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e3424c554391dc9ef4a92ad28665756566a28fecf47308f91841f6c49288e66"}, + {file = "coverage-7.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0860a348bf7004c812c8368d1fc7f77fe8e4c095d661a579196a9533778e156"}, + {file = "coverage-7.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe558371c1bdf3b8fa03e097c523fb9645b8730399c14fe7721ee9c9e2a545d3"}, + {file = "coverage-7.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3468cc8720402af37b6c6e7e2a9cdb9f6c16c728638a2ebc768ba1ef6f26c3a1"}, + {file = "coverage-7.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:02f2edb575d62172aa28fe00efe821ae31f25dc3d589055b3fb64d51e52e4ab1"}, + {file = "coverage-7.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ca6e61dc52f601d1d224526360cdeab0d0712ec104a2ce6cc5ccef6ed9a233bc"}, + {file = "coverage-7.4.1-cp312-cp312-win32.whl", hash = "sha256:ca7b26a5e456a843b9b6683eada193fc1f65c761b3a473941efe5a291f604c74"}, + {file = "coverage-7.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:85ccc5fa54c2ed64bd91ed3b4a627b9cce04646a659512a051fa82a92c04a448"}, + {file = "coverage-7.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8bdb0285a0202888d19ec6b6d23d5990410decb932b709f2b0dfe216d031d218"}, + {file = "coverage-7.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:918440dea04521f499721c039863ef95433314b1db00ff826a02580c1f503e45"}, + {file = "coverage-7.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:379d4c7abad5afbe9d88cc31ea8ca262296480a86af945b08214eb1a556a3e4d"}, + {file = "coverage-7.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b094116f0b6155e36a304ff912f89bbb5067157aff5f94060ff20bbabdc8da06"}, + {file = "coverage-7.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2f5968608b1fe2a1d00d01ad1017ee27efd99b3437e08b83ded9b7af3f6f766"}, + {file = "coverage-7.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:10e88e7f41e6197ea0429ae18f21ff521d4f4490aa33048f6c6f94c6045a6a75"}, + {file = "coverage-7.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a4a3907011d39dbc3e37bdc5df0a8c93853c369039b59efa33a7b6669de04c60"}, + {file = "coverage-7.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6d224f0c4c9c98290a6990259073f496fcec1b5cc613eecbd22786d398ded3ad"}, + {file = "coverage-7.4.1-cp38-cp38-win32.whl", hash = "sha256:23f5881362dcb0e1a92b84b3c2809bdc90db892332daab81ad8f642d8ed55042"}, + {file = "coverage-7.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:a07f61fc452c43cd5328b392e52555f7d1952400a1ad09086c4a8addccbd138d"}, + {file = "coverage-7.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8e738a492b6221f8dcf281b67129510835461132b03024830ac0e554311a5c54"}, + {file = "coverage-7.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:46342fed0fff72efcda77040b14728049200cbba1279e0bf1188f1f2078c1d70"}, + {file = "coverage-7.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9641e21670c68c7e57d2053ddf6c443e4f0a6e18e547e86af3fad0795414a628"}, + {file = "coverage-7.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aeb2c2688ed93b027eb0d26aa188ada34acb22dceea256d76390eea135083950"}, + {file = "coverage-7.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d12c923757de24e4e2110cf8832d83a886a4cf215c6e61ed506006872b43a6d1"}, + {file = "coverage-7.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0491275c3b9971cdbd28a4595c2cb5838f08036bca31765bad5e17edf900b2c7"}, + {file = "coverage-7.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8dfc5e195bbef80aabd81596ef52a1277ee7143fe419efc3c4d8ba2754671756"}, + {file = "coverage-7.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1a78b656a4d12b0490ca72651fe4d9f5e07e3c6461063a9b6265ee45eb2bdd35"}, + {file = "coverage-7.4.1-cp39-cp39-win32.whl", hash = "sha256:f90515974b39f4dea2f27c0959688621b46d96d5a626cf9c53dbc653a895c05c"}, + {file = "coverage-7.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:64e723ca82a84053dd7bfcc986bdb34af8d9da83c521c19d6b472bc6880e191a"}, + {file = "coverage-7.4.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:32a8d985462e37cfdab611a6f95b09d7c091d07668fdc26e47a725ee575fe166"}, + {file = "coverage-7.4.1.tar.gz", hash = "sha256:1ed4b95480952b1a26d863e546fa5094564aa0065e1e5f0d4d0041f293251d04"}, +] + +[package.extras] +toml = ["tomli"] + [[package]] name = "croniter" version = "1.3.15" @@ -2330,6 +2394,24 @@ pluggy = ">=1.3.0,<2.0" [package.extras] testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +[[package]] +name = "pytest-cov" +version = "4.1.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, + {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, +] + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] + [[package]] name = "pytest-django" version = "4.8.0" @@ -3563,4 +3645,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "b833865181628affa1f1da6bd9834d2158f694392c8765a9294955034a33a419" +content-hash = "a4d98d014ad783d7aa3e211393315b4bafc61e1fead6d2be706872b1a0858793" diff --git a/pyproject.toml b/pyproject.toml index 8ef748e8..53ed3e6c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,6 +17,7 @@ python-dotenv = "^1.0.1" faker = "^22.6.0" selenium = "^4.17.2" pytest-django = "^4.8.0" +pytest-cov = "^4.1.0" [tool.poetry.group.dev] # dev group definition From a9ecb28bc2b31717364f42960fd5d4ae776a4213 Mon Sep 17 00:00:00 2001 From: Murdo Moyse Date: Tue, 13 Feb 2024 13:57:44 +0000 Subject: [PATCH 118/221] Removed django classes from test forms --- core/settings.py | 10 ---------- tests/test_forms.py | 33 +++++++++++++++++---------------- 2 files changed, 17 insertions(+), 26 deletions(-) diff --git a/core/settings.py b/core/settings.py index c753d7f1..ae416197 100644 --- a/core/settings.py +++ b/core/settings.py @@ -62,16 +62,6 @@ WSGI_APPLICATION = "core.wsgi.application" -# Database -# https://docs.djangoproject.com/en/5.0/ref/settings/#databases -DATABASES = { - "default": { - "ENGINE": "django.db.backends.sqlite3", - "NAME": "db", - } -} - - # Password validation # https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators diff --git a/tests/test_forms.py b/tests/test_forms.py index bcfb6cba..84ed681a 100644 --- a/tests/test_forms.py +++ b/tests/test_forms.py @@ -1,21 +1,22 @@ -from django.test import TestCase from home.forms.search import SearchForm +import pytest +@pytest.fixture +def valid_form(): + valid_form = SearchForm( + data={ + "query": "test", + "domains": ["urn:li:domain:HMCTS"], + "sort": "ascending", + "clear_filter": False, + "clear_label": False, + } + ) + assert valid_form.is_valid() -class SearchFormTest(TestCase): - def setUp(self): - self.valid_form = SearchForm( - data={ - "query": "test", - "domains": ["urn:li:domain:HMCTS"], - "sort": "ascending", - "clear_filter": False, - "clear_label": False, - } - ) - - assert self.valid_form.is_valid() + return valid_form +class TestSearchForm: def test_query_field_length(self): over_100_characters = "a" * 101 assert not SearchForm(data={"query": over_100_characters}).is_valid() @@ -29,8 +30,8 @@ def test_sort_is_from_sort_list_false(self): def test_all_fields_nullable(self): assert SearchForm(data={}).is_valid() - def test_form_encode_without_filter_for_one_filter(self): - assert (self.valid_form.encode_without_filter("urn:li:domain:HMCTS") == + def test_form_encode_without_filter_for_one_filter(self, valid_form): + assert (valid_form.encode_without_filter("urn:li:domain:HMCTS") == "?query=test&sort=ascending&clear_filter=False&clear_label=False") def test_form_encode_without_filter_for_two_filters(self): From 61ea3d6391397fc10b5397fc8be134988cabc35d Mon Sep 17 00:00:00 2001 From: Murdo Moyse Date: Tue, 13 Feb 2024 13:58:14 +0000 Subject: [PATCH 119/221] Include coverage report with tests --- .github/workflows/test.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f9ac5695..2e17dd84 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,6 +32,5 @@ jobs: - run: poetry install --no-interaction --no-root if: steps.cache-deps.outputs.cache-hit != 'true' - run: poetry install --no-interaction - - run: poetry run pytest - - name: coverage + - name: test with coverage run: poetry run pytest --cov From fe15015963365fc0af455f508090036343006dcd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 13 Feb 2024 13:58:57 +0000 Subject: [PATCH 120/221] Commit changes made by code formatters --- tests/test_forms.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_forms.py b/tests/test_forms.py index 84ed681a..51addcf6 100644 --- a/tests/test_forms.py +++ b/tests/test_forms.py @@ -1,6 +1,7 @@ from home.forms.search import SearchForm import pytest + @pytest.fixture def valid_form(): valid_form = SearchForm( @@ -16,6 +17,7 @@ def valid_form(): return valid_form + class TestSearchForm: def test_query_field_length(self): over_100_characters = "a" * 101 From dc8b658d628726330db5921cea613293218feff2 Mon Sep 17 00:00:00 2001 From: LavMatt Date: Tue, 13 Feb 2024 16:41:07 +0000 Subject: [PATCH 121/221] tests for search and detail services --- tests/test_services.py | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 tests/test_services.py diff --git a/tests/test_services.py b/tests/test_services.py new file mode 100644 index 00000000..164ae97c --- /dev/null +++ b/tests/test_services.py @@ -0,0 +1,40 @@ +from types import GeneratorType +from data_platform_catalogue.search_types import ResultType + + +class TestSearchService: + def test_get_context_form(self, valid_form, search_context): + assert search_context["form"] == valid_form + + def test_get_context_search_result(self, mock_catalogue, search_context): + assert search_context["results"] == mock_catalogue.search().page_results + assert search_context["total_results"] == 100 + + def test_get_context_paginator(self, search_context): + assert search_context["page_obj"].number == 1 + assert isinstance(search_context["page_range"], GeneratorType) + assert search_context["paginator"].num_pages == 5 + + def test_get_context_page_title(self, search_context): + assert search_context["page_title"] == 'Search for "test" - Data catalogue' + + def test_get_context_label_clear_href(self, search_context): + assert search_context["label_clear_href"] == { + "HMCTS": "?query=test&sort=ascending&clear_filter=False&clear_label=False" + } + + +class TestDetailsService: + def test_get_context(self, detail_context, mock_catalogue): + assert detail_context["result"] == mock_catalogue.search().page_results[0] + result_type = ( + "Data product" + if mock_catalogue.search().page_results[0].result_type + == ResultType.DATA_PRODUCT + else "Table" + ) + assert detail_context["result_type"] == result_type + assert ( + detail_context["page_title"] + == f"{mock_catalogue.search().page_results[0].name} - Data catalogue" + ) From 2b3375a127981f938deab7b4e6661ddd65c23bb6 Mon Sep 17 00:00:00 2001 From: LavMatt Date: Tue, 13 Feb 2024 16:42:09 +0000 Subject: [PATCH 122/221] move valid form and add service fixtures to conftest --- tests/conftest.py | 58 ++++++++++++++++++++++++++++++++++++++------- tests/test_forms.py | 39 +++++++++++------------------- 2 files changed, 63 insertions(+), 34 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 48849efc..4d7db4dd 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,11 +3,18 @@ import pytest from data_platform_catalogue.client import BaseCatalogueClient -from data_platform_catalogue.search_types import (FacetOption, ResultType, - SearchFacets, SearchResponse, - SearchResult) +from data_platform_catalogue.search_types import ( + FacetOption, + ResultType, + SearchFacets, + SearchResponse, + SearchResult, +) from django.test import Client from faker import Faker +from home.service.search import SearchService +from home.service.details import DetailsService +from home.forms.search import SearchForm fake = Faker() @@ -21,8 +28,7 @@ def generate_page(page_size=20): results.append( SearchResult( id=fake.unique.name(), - result_type=choice( - (ResultType.DATA_PRODUCT, ResultType.TABLE)), + result_type=choice((ResultType.DATA_PRODUCT, ResultType.TABLE)), name=fake.name(), description=fake.paragraphs(), ) @@ -59,7 +65,8 @@ def mock_catalogue(): mock_catalogue = MagicMock(spec=BaseCatalogueClient) mock_fn.return_value = mock_catalogue mock_search_response( - mock_catalogue, page_results=generate_page(), total_results=100) + mock_catalogue, page_results=generate_page(), total_results=100 + ) mock_search_facets_response(mock_catalogue, domains=generate_options()) yield mock_catalogue @@ -69,10 +76,43 @@ def mock_catalogue(): def mock_search_response(mock_catalogue, total_results=0, page_results=()): search_response = SearchResponse( - total_results=total_results, page_results=page_results) + total_results=total_results, page_results=page_results + ) mock_catalogue.search.return_value = search_response def mock_search_facets_response(mock_catalogue, domains): - mock_catalogue.search_facets.return_value = SearchFacets( - {"domains": domains}) + mock_catalogue.search_facets.return_value = SearchFacets({"domains": domains}) + + +@pytest.fixture +def valid_form(): + valid_form = SearchForm( + data={ + "query": "test", + "domains": ["urn:li:domain:HMCTS"], + "sort": "ascending", + "clear_filter": False, + "clear_label": False, + } + ) + assert valid_form.is_valid() + + return valid_form + + +@pytest.fixture +def search_context(valid_form): + search_service = SearchService(form=valid_form, page="1") + context = search_service._get_context() + return context + + +@pytest.fixture +def detail_context(mock_catalogue): + mock_catalogue.search.return_value = SearchResponse( + total_results=1, page_results=generate_page(page_size=1) + ) + details_service = DetailsService(urn="urn:li:dataProduct:test") + context = details_service._get_context() + return context diff --git a/tests/test_forms.py b/tests/test_forms.py index 51addcf6..89fb5d91 100644 --- a/tests/test_forms.py +++ b/tests/test_forms.py @@ -1,21 +1,4 @@ from home.forms.search import SearchForm -import pytest - - -@pytest.fixture -def valid_form(): - valid_form = SearchForm( - data={ - "query": "test", - "domains": ["urn:li:domain:HMCTS"], - "sort": "ascending", - "clear_filter": False, - "clear_label": False, - } - ) - assert valid_form.is_valid() - - return valid_form class TestSearchForm: @@ -33,15 +16,21 @@ def test_all_fields_nullable(self): assert SearchForm(data={}).is_valid() def test_form_encode_without_filter_for_one_filter(self, valid_form): - assert (valid_form.encode_without_filter("urn:li:domain:HMCTS") == - "?query=test&sort=ascending&clear_filter=False&clear_label=False") + assert ( + valid_form.encode_without_filter("urn:li:domain:HMCTS") + == "?query=test&sort=ascending&clear_filter=False&clear_label=False" + ) def test_form_encode_without_filter_for_two_filters(self): - two_filter_form = SearchForm(data={ - "query": "test", - "domains": ["urn:li:domain:HMCTS", "urn:li:domain:HMPPS"] - }) + two_filter_form = SearchForm( + data={ + "query": "test", + "domains": ["urn:li:domain:HMCTS", "urn:li:domain:HMPPS"], + } + ) two_filter_form.is_valid() - assert (two_filter_form.encode_without_filter("urn:li:domain:HMCTS") == - "?query=test&domains=urn%3Ali%3Adomain%3AHMPPS&sort=&clear_filter=False&clear_label=False") + assert ( + two_filter_form.encode_without_filter("urn:li:domain:HMCTS") + == "?query=test&domains=urn%3Ali%3Adomain%3AHMPPS&sort=&clear_filter=False&clear_label=False" + ) From 48d9493d02e61e5b440ab74ce47d511bbabec670 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 13 Feb 2024 16:43:31 +0000 Subject: [PATCH 123/221] Commit changes made by code formatters --- tests/conftest.py | 6 ++++-- tests/test_services.py | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 4d7db4dd..546eb565 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -28,7 +28,8 @@ def generate_page(page_size=20): results.append( SearchResult( id=fake.unique.name(), - result_type=choice((ResultType.DATA_PRODUCT, ResultType.TABLE)), + result_type=choice( + (ResultType.DATA_PRODUCT, ResultType.TABLE)), name=fake.name(), description=fake.paragraphs(), ) @@ -82,7 +83,8 @@ def mock_search_response(mock_catalogue, total_results=0, page_results=()): def mock_search_facets_response(mock_catalogue, domains): - mock_catalogue.search_facets.return_value = SearchFacets({"domains": domains}) + mock_catalogue.search_facets.return_value = SearchFacets( + {"domains": domains}) @pytest.fixture diff --git a/tests/test_services.py b/tests/test_services.py index 164ae97c..60160f5e 100644 --- a/tests/test_services.py +++ b/tests/test_services.py @@ -7,7 +7,8 @@ def test_get_context_form(self, valid_form, search_context): assert search_context["form"] == valid_form def test_get_context_search_result(self, mock_catalogue, search_context): - assert search_context["results"] == mock_catalogue.search().page_results + assert search_context["results"] == mock_catalogue.search( + ).page_results assert search_context["total_results"] == 100 def test_get_context_paginator(self, search_context): @@ -26,7 +27,8 @@ def test_get_context_label_clear_href(self, search_context): class TestDetailsService: def test_get_context(self, detail_context, mock_catalogue): - assert detail_context["result"] == mock_catalogue.search().page_results[0] + assert detail_context["result"] == mock_catalogue.search( + ).page_results[0] result_type = ( "Data product" if mock_catalogue.search().page_results[0].result_type From 016fa86d745fbccedb87b6b0a40664dc24a930ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Feb 2024 23:04:54 +0000 Subject: [PATCH 124/221] Bump actions/setup-python from 2 to 5 Bumps [actions/setup-python](https://github.com/actions/setup-python) from 2 to 5. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v2...v5) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2e17dd84..ba0383a9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v5 with: python-version: 3.11.1 - name: cache poetry install From 58a89475a56ad4543b2c4c5ae3ea675d9eb70d24 Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Mon, 12 Feb 2024 16:57:38 +0000 Subject: [PATCH 125/221] Add selenium test --- core/settings.py | 11 +++- poetry.lock | 5 +- pyproject.toml | 1 + templates/partial/search_result.html | 6 ++- tests/home/end-to-end/__init__.py | 0 .../home/end-to-end/test_search_scenarios.py | 54 +++++++++++++++++++ 6 files changed, 70 insertions(+), 7 deletions(-) create mode 100644 tests/home/end-to-end/__init__.py create mode 100644 tests/home/end-to-end/test_search_scenarios.py diff --git a/core/settings.py b/core/settings.py index ae416197..847c29f7 100644 --- a/core/settings.py +++ b/core/settings.py @@ -113,8 +113,7 @@ "django.contrib.staticfiles.finders.AppDirectoriesFinder", ) -SAMPLE_SEARCH_RESULTS_FILENAME = BASE_DIR / \ - "sample_data/sample_search_page.yaml" +SAMPLE_SEARCH_RESULTS_FILENAME = BASE_DIR / "sample_data/sample_search_page.yaml" with open(SAMPLE_SEARCH_RESULTS_FILENAME) as f: SAMPLE_SEARCH_RESULTS = yaml.safe_load(f) @@ -125,3 +124,11 @@ # session SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies" + +# Not actually used - Just required for LiveServerTestCase +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": ":memory:", + } +} diff --git a/poetry.lock b/poetry.lock index 1b541012..d1aa58aa 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] name = "acryl-datahub" @@ -2546,7 +2546,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -3645,4 +3644,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "a4d98d014ad783d7aa3e211393315b4bafc61e1fead6d2be706872b1a0858793" +content-hash = "5cd66d8abbeaa1b06f98ce3820d1c076aed4aa1606f435184323085384cec037" diff --git a/pyproject.toml b/pyproject.toml index 53ed3e6c..eaea6591 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ pytest-cov = "^4.1.0" [tool.poetry.group.dev.dependencies] black = "^23.12.1" pre-commit = "^3.6.0" +selenium = ">=4.8.0" [build-system] requires = ["poetry-core"] diff --git a/templates/partial/search_result.html b/templates/partial/search_result.html index 99d4ddd8..5c738db6 100644 --- a/templates/partial/search_result.html +++ b/templates/partial/search_result.html @@ -1,8 +1,9 @@ {% load markdown %} {% load humanize %} +
    {% for result in results %} -
    +

    {{result.name}} @@ -51,4 +52,5 @@

    -{%endfor%} \ No newline at end of file +{%endfor%} +
    \ No newline at end of file diff --git a/tests/home/end-to-end/__init__.py b/tests/home/end-to-end/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/home/end-to-end/test_search_scenarios.py b/tests/home/end-to-end/test_search_scenarios.py new file mode 100644 index 00000000..acaa7954 --- /dev/null +++ b/tests/home/end-to-end/test_search_scenarios.py @@ -0,0 +1,54 @@ +from django.contrib.staticfiles.testing import LiveServerTestCase +from selenium.webdriver.common.by import By +from selenium.webdriver.firefox.webdriver import WebDriver + + +class TestSearchWithoutJavascriptAndCss(LiveServerTestCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.selenium = WebDriver() + cls.selenium.implicitly_wait(10) + + @classmethod + def tearDownClass(cls): + cls.selenium.quit() + super().tearDownClass() + + def test_browse_to_first_item(self): + """ + TODO: incorporate screenshots for debugging + Convert to pytest + Tag the test so it doesn't slow down the main CI job + Factor out steps + """ + # Navigate to search page + self.selenium.get(f"{self.live_server_url}") + self.assertIn("Data catalogue", self.selenium.title) + search_link = self.selenium.find_element(By.LINK_TEXT, "Search") + search_link.click() + self.assertIn("Search", self.selenium.title) + + # Read number of results + secondary_title = self.selenium.find_element( + By.CSS_SELECTOR, "h2.govuk-heading-l" + ) + self.assertRegex(secondary_title.text, r"\d+ Results") + + # Read first result + first_result = self.selenium.find_element(By.ID, "search-results").find_element( + By.CSS_SELECTOR, ".govuk-grid-row" + ) + self.assertTrue(first_result.text) + + # Click the link + first_link = first_result.find_element(By.CSS_SELECTOR, "h3 a") + item_name = first_link.text + first_link.click() + + # Verify we are on the details page + self.assertIn(item_name, self.selenium.title) + secondary_title = self.selenium.find_element( + By.CSS_SELECTOR, "h2.govuk-heading-l" + ) + self.assertEquals(secondary_title.text, item_name) From 8c17e885d527631b559c7c1eb4e5ceb49eb7e6a7 Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Tue, 13 Feb 2024 10:24:05 +0000 Subject: [PATCH 126/221] Add page helpers --- templates/search.html | 2 +- .../home/end-to-end/test_search_scenarios.py | 78 +++++++++++++++---- 2 files changed, 63 insertions(+), 17 deletions(-) diff --git a/templates/search.html b/templates/search.html index 148b01a5..bf0126aa 100644 --- a/templates/search.html +++ b/templates/search.html @@ -23,7 +23,7 @@

    Find MOJ Data

    {% include "partial/filter.html" %}
    -

    {{total_results|intcomma}} Results

    +

    {{total_results|intcomma}} Results

    {% include "partial/sort.html" %} {% include "partial/search_result.html" %} {% include "partial/pagination.html" %} diff --git a/tests/home/end-to-end/test_search_scenarios.py b/tests/home/end-to-end/test_search_scenarios.py index acaa7954..b9e8fe6e 100644 --- a/tests/home/end-to-end/test_search_scenarios.py +++ b/tests/home/end-to-end/test_search_scenarios.py @@ -1,9 +1,60 @@ +from typing import Protocol + from django.contrib.staticfiles.testing import LiveServerTestCase from selenium.webdriver.common.by import By from selenium.webdriver.firefox.webdriver import WebDriver +from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver +from selenium.webdriver.remote.webelement import WebElement + + +class HasSelenium(Protocol): + @property + def selenium(self) -> RemoteWebDriver: ... + + +class LayoutHelpers: + def primary_heading(self: HasSelenium): + return self.selenium.find_element(By.TAG_NAME, "h1") + + def secondary_heading(self: HasSelenium): + return self.selenium.find_element(By.TAG_NAME, "h2") + + @property + def title(self: HasSelenium): + return self.selenium.title + + +class HomePage: + def search_nav_link(self: HasSelenium) -> WebElement: + return self.selenium.find_element(By.LINK_TEXT, "Search") + + +class SearchResultWrapper: + def __init__(self, element: WebElement): + self.element = element + def __getattr__(self, name): + return getattr(self.element, name) -class TestSearchWithoutJavascriptAndCss(LiveServerTestCase): + def link(self): + return self.element.find_element(By.CSS_SELECTOR, "h3 a") + + +class SearchPage: + def result_count(self: HasSelenium) -> WebElement: + return self.selenium.find_element(By.ID, "result-count") + + def first_search_result(self: HasSelenium) -> SearchResultWrapper: + return SearchResultWrapper( + self.selenium.find_element(By.ID, "search-results").find_element( + By.CSS_SELECTOR, ".govuk-grid-row" + ) + ) + + +class TestSearchWithoutJavascriptAndCss( + LiveServerTestCase, HomePage, SearchPage, LayoutHelpers +): @classmethod def setUpClass(cls): super().setUpClass() @@ -25,30 +76,25 @@ def test_browse_to_first_item(self): # Navigate to search page self.selenium.get(f"{self.live_server_url}") self.assertIn("Data catalogue", self.selenium.title) - search_link = self.selenium.find_element(By.LINK_TEXT, "Search") - search_link.click() + + self.search_nav_link().click() self.assertIn("Search", self.selenium.title) + self.assertIn("Find MOJ Data", self.primary_heading().text) # Read number of results - secondary_title = self.selenium.find_element( - By.CSS_SELECTOR, "h2.govuk-heading-l" - ) - self.assertRegex(secondary_title.text, r"\d+ Results") + result_count = self.result_count().text + self.assertRegex(result_count, r"\d+ Results") # Read first result - first_result = self.selenium.find_element(By.ID, "search-results").find_element( - By.CSS_SELECTOR, ".govuk-grid-row" - ) + first_result = self.first_search_result() self.assertTrue(first_result.text) # Click the link - first_link = first_result.find_element(By.CSS_SELECTOR, "h3 a") + first_link = first_result.link() item_name = first_link.text first_link.click() # Verify we are on the details page - self.assertIn(item_name, self.selenium.title) - secondary_title = self.selenium.find_element( - By.CSS_SELECTOR, "h2.govuk-heading-l" - ) - self.assertEquals(secondary_title.text, item_name) + self.assertIn(item_name, self.title) + secondary_heading_text = self.secondary_heading().text + self.assertEquals(secondary_heading_text, item_name) From 90278ec5d444140cc9286ba81fa5d55ea2ea2465 Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Tue, 13 Feb 2024 10:34:32 +0000 Subject: [PATCH 127/221] Split out test steps into methods --- .../home/end-to-end/test_search_scenarios.py | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/tests/home/end-to-end/test_search_scenarios.py b/tests/home/end-to-end/test_search_scenarios.py index b9e8fe6e..84da92a8 100644 --- a/tests/home/end-to-end/test_search_scenarios.py +++ b/tests/home/end-to-end/test_search_scenarios.py @@ -66,35 +66,45 @@ def tearDownClass(cls): cls.selenium.quit() super().tearDownClass() - def test_browse_to_first_item(self): - """ - TODO: incorporate screenshots for debugging - Convert to pytest - Tag the test so it doesn't slow down the main CI job - Factor out steps - """ - # Navigate to search page + def start_on_the_home_page(self): self.selenium.get(f"{self.live_server_url}") self.assertIn("Data catalogue", self.selenium.title) + def click_on_the_search_button(self): self.search_nav_link().click() + + def verify_i_am_on_the_search_page(self): self.assertIn("Search", self.selenium.title) self.assertIn("Find MOJ Data", self.primary_heading().text) - # Read number of results + def verify_i_have_results(self): result_count = self.result_count().text self.assertRegex(result_count, r"\d+ Results") - # Read first result + def click_on_the_first_result(self): first_result = self.first_search_result() self.assertTrue(first_result.text) - # Click the link first_link = first_result.link() item_name = first_link.text first_link.click() + return item_name - # Verify we are on the details page + def verify_i_am_on_the_details_page(self, item_name): self.assertIn(item_name, self.title) secondary_heading_text = self.secondary_heading().text self.assertEquals(secondary_heading_text, item_name) + + def test_browse_to_first_item(self): + """ + TODO: incorporate screenshots for debugging + Convert to pytest + Tag the test so it doesn't slow down the main CI job + """ + self.start_on_the_home_page() + self.click_on_the_search_button() + self.verify_i_am_on_the_search_page() + self.verify_i_have_results() + + item_name = self.click_on_the_first_result() + self.verify_i_am_on_the_details_page(item_name) From e944cdc901622529807a57679835a235b6162e66 Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Tue, 13 Feb 2024 15:03:18 +0000 Subject: [PATCH 128/221] Add tests --- templates/partial/filter.html | 8 +- .../home/end-to-end/test_search_scenarios.py | 78 ++++++++++++++++++- 2 files changed, 79 insertions(+), 7 deletions(-) diff --git a/templates/partial/filter.html b/templates/partial/filter.html index 4d2302e3..6ab6f185 100644 --- a/templates/partial/filter.html +++ b/templates/partial/filter.html @@ -31,14 +31,14 @@

    Domain

    {% for label, href in label_clear_href.items %}
  • - {{label}}Remove this filter + {{label}} Remove this filter
  • {% endfor %} {% endif %}
    -
    @@ -48,9 +48,7 @@

    Domain

    {% for domain_option in form.domains %}
    {{ domain_option.tag}} - +
    {% endfor %}
    diff --git a/tests/home/end-to-end/test_search_scenarios.py b/tests/home/end-to-end/test_search_scenarios.py index 84da92a8..ca4eff8e 100644 --- a/tests/home/end-to-end/test_search_scenarios.py +++ b/tests/home/end-to-end/test_search_scenarios.py @@ -2,6 +2,7 @@ from django.contrib.staticfiles.testing import LiveServerTestCase from selenium.webdriver.common.by import By +from selenium.webdriver.common.keys import Keys from selenium.webdriver.firefox.webdriver import WebDriver from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver from selenium.webdriver.remote.webelement import WebElement @@ -51,6 +52,27 @@ def first_search_result(self: HasSelenium) -> SearchResultWrapper: ) ) + def search_bar(self: HasSelenium) -> WebElement: + return self.selenium.find_element(By.NAME, "query") + + def checked_domain_checkboxes(self: HasSelenium) -> list[WebElement]: + return self.selenium.find_elements( + By.CSS_SELECTOR, "input:checked[name='domains']" + ) + + def domain_label(self: HasSelenium, name) -> WebElement: + return self.selenium.find_element(By.XPATH, f"//label[ text() = '{name}' ]") + + def selected_filter_tags(self: HasSelenium) -> list[WebElement]: + return self.selenium.find_elements( + By.CSS_SELECTOR, ".moj-filter__tag [data-test-id='selected-domain-label']" + ) + + def apply_filters_button(self: HasSelenium): + return self.selenium.find_element( + By.CSS_SELECTOR, 'button[data-test-id="apply-filters"]' + ) + class TestSearchWithoutJavascriptAndCss( LiveServerTestCase, HomePage, SearchPage, LayoutHelpers @@ -68,7 +90,11 @@ def tearDownClass(cls): def start_on_the_home_page(self): self.selenium.get(f"{self.live_server_url}") - self.assertIn("Data catalogue", self.selenium.title) + self.assertIn("Data catalogue", self.title) + + def start_on_the_search_page(self): + self.selenium.get(f"{self.live_server_url}/search") + self.assertIn("Search", self.title) def click_on_the_search_button(self): self.search_nav_link().click() @@ -79,7 +105,7 @@ def verify_i_am_on_the_search_page(self): def verify_i_have_results(self): result_count = self.result_count().text - self.assertRegex(result_count, r"\d+ Results") + self.assertRegex(result_count, r"[1-9]\d* Results") def click_on_the_first_result(self): first_result = self.first_search_result() @@ -95,10 +121,42 @@ def verify_i_am_on_the_details_page(self, item_name): secondary_heading_text = self.secondary_heading().text self.assertEquals(secondary_heading_text, item_name) + def enter_a_query_and_submit(self, query): + search_bar = self.search_bar() + search_bar.send_keys(query) + search_bar.send_keys(Keys.ENTER) + + def select_domain(self, domains): + for domain in domains: + self.domain_label(domain).click() + + def click_apply_filters(self): + self.apply_filters_button().click() + + def verify_the_search_bar_has_value(self, query): + search_bar = self.search_bar() + self.assertEquals(search_bar.get_attribute("value"), query) + + def verify_domain_selected(self, domains): + expected = set(domains) + checkboxes = self.checked_domain_checkboxes() + actual = set() + for checkbox in checkboxes: + value = checkbox.get_attribute("value") or "" + actual.add(value.replace("urn:li:domain:", "")) + + self.assertEquals(actual, expected) + + def verify_selected_filters_shown(self, domains): + actual = {i.text for i in self.selected_filter_tags()} + expected = set(domains) + self.assertEquals(actual, expected) + def test_browse_to_first_item(self): """ TODO: incorporate screenshots for debugging Convert to pytest + See if we can stub out the actual catalogue Tag the test so it doesn't slow down the main CI job """ self.start_on_the_home_page() @@ -108,3 +166,19 @@ def test_browse_to_first_item(self): item_name = self.click_on_the_first_result() self.verify_i_am_on_the_details_page(item_name) + + def test_search_with_query(self): + self.start_on_the_search_page() + self.enter_a_query_and_submit("nomis") + self.verify_i_am_on_the_search_page() + self.verify_the_search_bar_has_value("nomis") + self.verify_i_have_results() + + def test_apply_domain_filters(self): + self.start_on_the_search_page() + self.select_domain(["HMCTS", "HMPPS"]) + self.click_apply_filters() + self.verify_i_am_on_the_search_page() + self.verify_i_have_results() + self.verify_domain_selected(["HMCTS", "HMPPS"]) + self.verify_selected_filters_shown(["HMCTS", "HMPPS"]) From 1739bce64f76f5b83ad47ef29f41bc5627696838 Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Tue, 13 Feb 2024 15:40:58 +0000 Subject: [PATCH 129/221] Add sort test --- templates/partial/sort.html | 4 +- .../home/end-to-end/test_search_scenarios.py | 87 ++++++++++++++++++- 2 files changed, 86 insertions(+), 5 deletions(-) diff --git a/templates/partial/sort.html b/templates/partial/sort.html index d011e533..c0b007de 100644 --- a/templates/partial/sort.html +++ b/templates/partial/sort.html @@ -7,9 +7,7 @@ {% for radio in form.sort %}
    {{radio.tag}} - +
    {% endfor %}
    diff --git a/tests/home/end-to-end/test_search_scenarios.py b/tests/home/end-to-end/test_search_scenarios.py index ca4eff8e..c5de1b03 100644 --- a/tests/home/end-to-end/test_search_scenarios.py +++ b/tests/home/end-to-end/test_search_scenarios.py @@ -55,28 +55,57 @@ def first_search_result(self: HasSelenium) -> SearchResultWrapper: def search_bar(self: HasSelenium) -> WebElement: return self.selenium.find_element(By.NAME, "query") + def search_button(self: HasSelenium) -> WebElement: + return self.selenium.find_element(By.CLASS_NAME, "search-button") + def checked_domain_checkboxes(self: HasSelenium) -> list[WebElement]: return self.selenium.find_elements( By.CSS_SELECTOR, "input:checked[name='domains']" ) + def checked_sort_option(self: HasSelenium) -> WebElement: + return self.selenium.find_element(By.CSS_SELECTOR, "input:checked[name='sort']") + def domain_label(self: HasSelenium, name) -> WebElement: return self.selenium.find_element(By.XPATH, f"//label[ text() = '{name}' ]") + def sort_label(self: HasSelenium, name) -> WebElement: + return self.selenium.find_element(By.XPATH, f"//label[ text() = '{name}' ]") + def selected_filter_tags(self: HasSelenium) -> list[WebElement]: return self.selenium.find_elements( By.CSS_SELECTOR, ".moj-filter__tag [data-test-id='selected-domain-label']" ) - def apply_filters_button(self: HasSelenium): + def apply_filters_button(self: HasSelenium) -> WebElement: return self.selenium.find_element( By.CSS_SELECTOR, 'button[data-test-id="apply-filters"]' ) + def current_page(self: HasSelenium) -> WebElement: + return self.selenium.find_element( + By.CLASS_NAME, "govuk-pagination__item--current" + ) + + def next_page(self: HasSelenium) -> WebElement: + return self.selenium.find_element( + By.CLASS_NAME, "govuk-pagination__next" + ).find_element(By.TAG_NAME, "a") + + def previous_page(self: HasSelenium) -> WebElement: + return self.selenium.find_element( + By.CLASS_NAME, "govuk-pagination__prev" + ).find_element(By.TAG_NAME, "a") + class TestSearchWithoutJavascriptAndCss( LiveServerTestCase, HomePage, SearchPage, LayoutHelpers ): + """ + Test interacting with the search form through the browser, + as a user would + """ + @classmethod def setUpClass(cls): super().setUpClass() @@ -93,7 +122,7 @@ def start_on_the_home_page(self): self.assertIn("Data catalogue", self.title) def start_on_the_search_page(self): - self.selenium.get(f"{self.live_server_url}/search") + self.selenium.get(f"{self.live_server_url}/search?new=True") self.assertIn("Search", self.title) def click_on_the_search_button(self): @@ -130,6 +159,12 @@ def select_domain(self, domains): for domain in domains: self.domain_label(domain).click() + def click_sort_option(self, sortby): + self.sort_label(sortby).click() + + def click_search_button(self): + self.search_button().click() + def click_apply_filters(self): self.apply_filters_button().click() @@ -152,8 +187,24 @@ def verify_selected_filters_shown(self, domains): expected = set(domains) self.assertEquals(actual, expected) + def verify_page(self, expected): + current_page = self.current_page() + self.assertEquals(current_page.text, expected) + + def click_next_page(self): + self.next_page().click() + + def click_previous_page(self): + self.previous_page().click() + + def verify_sort_selected(self, expected): + value = self.checked_sort_option().get_attribute("value") or "" + self.assertEquals(value, expected.lower()) + def test_browse_to_first_item(self): """ + Browses from the home page -> search -> details page + TODO: incorporate screenshots for debugging Convert to pytest See if we can stub out the actual catalogue @@ -168,6 +219,9 @@ def test_browse_to_first_item(self): self.verify_i_am_on_the_details_page(item_name) def test_search_with_query(self): + """ + Types a search query and press enter + """ self.start_on_the_search_page() self.enter_a_query_and_submit("nomis") self.verify_i_am_on_the_search_page() @@ -175,6 +229,9 @@ def test_search_with_query(self): self.verify_i_have_results() def test_apply_domain_filters(self): + """ + Interacts with the filters on the left hand side + """ self.start_on_the_search_page() self.select_domain(["HMCTS", "HMPPS"]) self.click_apply_filters() @@ -182,3 +239,29 @@ def test_apply_domain_filters(self): self.verify_i_have_results() self.verify_domain_selected(["HMCTS", "HMPPS"]) self.verify_selected_filters_shown(["HMCTS", "HMPPS"]) + + def test_pagination(self): + """ + Interact with the pagination component + """ + self.start_on_the_search_page() + self.verify_page("1") + self.click_next_page() + self.verify_page("2") + self.click_previous_page() + self.verify_page("1") + + def test_sorting(self): + """ + Interact with the sort control. Note: without javascript, this requires + the form to be submitted by pressing a button. + """ + self.start_on_the_search_page() + + # FIXME: this isn't preselected if the `new` query param is missing + self.verify_sort_selected("Relevance") + + self.click_sort_option("Ascending") + self.click_search_button() + self.verify_i_have_results() + self.verify_sort_selected("Ascending") From 3bb28d60147988a9a80e5ce51caae59b1ee7a116 Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Tue, 13 Feb 2024 16:13:11 +0000 Subject: [PATCH 130/221] More tests --- .../home/end-to-end/test_search_scenarios.py | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/tests/home/end-to-end/test_search_scenarios.py b/tests/home/end-to-end/test_search_scenarios.py index c5de1b03..e1db775b 100644 --- a/tests/home/end-to-end/test_search_scenarios.py +++ b/tests/home/end-to-end/test_search_scenarios.py @@ -6,6 +6,8 @@ from selenium.webdriver.firefox.webdriver import WebDriver from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver from selenium.webdriver.remote.webelement import WebElement +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.support.wait import WebDriverWait class HasSelenium(Protocol): @@ -77,6 +79,18 @@ def selected_filter_tags(self: HasSelenium) -> list[WebElement]: By.CSS_SELECTOR, ".moj-filter__tag [data-test-id='selected-domain-label']" ) + def selected_filter_tag(self: HasSelenium, value) -> WebElement: + for result in self.selenium.find_elements( + By.CSS_SELECTOR, ".moj-filter__tag [data-test-id='selected-domain-label']" + ): + if result.text == value: + return result + + raise Exception(f"No selected filter with text {value}") + + def clear_filters(self: HasSelenium) -> WebElement: + return self.selenium.find_element(By.ID, "clear_filter") + def apply_filters_button(self: HasSelenium) -> WebElement: return self.selenium.find_element( By.CSS_SELECTOR, 'button[data-test-id="apply-filters"]' @@ -117,6 +131,9 @@ def tearDownClass(cls): cls.selenium.quit() super().tearDownClass() + def wait_for_url_change(self, current_url): + WebDriverWait(self.selenium, 10).until(EC.url_changes(current_url)) + def start_on_the_home_page(self): self.selenium.get(f"{self.live_server_url}") self.assertIn("Data catalogue", self.title) @@ -168,6 +185,12 @@ def click_search_button(self): def click_apply_filters(self): self.apply_filters_button().click() + def click_clear_selected_filter(self, name): + self.selected_filter_tag(name).click() + + def click_clear_filters(self): + self.clear_filters().click() + def verify_the_search_bar_has_value(self, query): search_bar = self.search_bar() self.assertEquals(search_bar.get_attribute("value"), query) @@ -265,3 +288,53 @@ def test_sorting(self): self.click_search_button() self.verify_i_have_results() self.verify_sort_selected("Ascending") + + def test_filters_query_and_sort_persist(self): + self.start_on_the_search_page() + self.select_domain(["HMCTS", "HMPPS"]) + self.click_apply_filters() + self.enter_a_query_and_submit("nomis") + self.click_sort_option("Ascending") + self.click_search_button() + + self.verify_i_have_results() + self.verify_the_search_bar_has_value("nomis") + self.verify_domain_selected(["HMCTS", "HMPPS"]) + self.verify_sort_selected("Ascending") + + def test_adding_a_query_resets_pagination(self): + self.start_on_the_search_page() + self.click_next_page() + self.verify_page("2") + current_url = self.selenium.current_url + + self.enter_a_query_and_submit("nomis") + self.wait_for_url_change(current_url) + self.verify_page("1") + + def test_adding_a_filter_resets_pagination(self): + self.start_on_the_search_page() + self.click_next_page() + self.verify_page("2") + current_url = self.selenium.current_url + + self.select_domain(["HMPPS"]) + self.click_apply_filters() + self.wait_for_url_change(current_url) + self.verify_page("1") + + def test_clear_single_filter(self): + self.start_on_the_search_page() + self.select_domain(["HMPPS", "HMCTS"]) + self.click_apply_filters() + self.click_clear_selected_filter("HMPPS") + + self.verify_domain_selected(["HMCTS"]) + + def test_clear_all_filters(self): + self.start_on_the_search_page() + self.select_domain(["HMPPS", "HMCTS"]) + self.click_apply_filters() + self.click_clear_filters() + + self.verify_domain_selected([]) From b29bd60aa0eb35b2194c5c2b812647162a43e021 Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Tue, 13 Feb 2024 16:39:39 +0000 Subject: [PATCH 131/221] Run axe-core against the selenium controlled browser Note: this is currently failing! --- tests/home/end-to-end/test_search_scenarios.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/home/end-to-end/test_search_scenarios.py b/tests/home/end-to-end/test_search_scenarios.py index e1db775b..21aa3cd8 100644 --- a/tests/home/end-to-end/test_search_scenarios.py +++ b/tests/home/end-to-end/test_search_scenarios.py @@ -1,3 +1,4 @@ +import subprocess from typing import Protocol from django.contrib.staticfiles.testing import LiveServerTestCase @@ -120,6 +121,11 @@ class TestSearchWithoutJavascriptAndCss( as a user would """ + def check_for_accessibility_issues(self): + command = ["npx", "@axe-core/cli", "-q", self.selenium.current_url] + output = subprocess.run(command, capture_output=True, text=True) + self.assertEqual(output.returncode, 0, output.stdout) + @classmethod def setUpClass(cls): super().setUpClass() @@ -338,3 +344,11 @@ def test_clear_all_filters(self): self.click_clear_filters() self.verify_domain_selected([]) + + def test_automated_accessibility_home(self): + self.start_on_the_home_page() + self.check_for_accessibility_issues() + + def test_automated_accessibility_search(self): + self.start_on_the_search_page() + self.check_for_accessibility_issues() From 21a1884c6fb13cc84583d8e4c3e324600178890d Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Tue, 13 Feb 2024 17:07:27 +0000 Subject: [PATCH 132/221] Correct accessibility issues flagged by axe-core --- home/forms/search.py | 7 +++++-- templates/base/base.html | 2 +- templates/home.html | 5 ++--- templates/partial/pagination.html | 3 ++- templates/partial/search_result.html | 2 +- templates/search.html | 2 +- 6 files changed, 12 insertions(+), 9 deletions(-) diff --git a/home/forms/search.py b/home/forms/search.py index 1939673f..6a9b2514 100644 --- a/home/forms/search.py +++ b/home/forms/search.py @@ -1,7 +1,8 @@ from copy import deepcopy -from django import forms from urllib.parse import urlencode +from django import forms + def get_domain_choices(): """Make API call to obtain domain choices""" @@ -31,7 +32,9 @@ class SearchForm(forms.Form): max_length=100, strip=False, required=False, - widget=forms.TextInput(attrs={"class": "govuk-input search-input"}), + widget=forms.TextInput( + attrs={"class": "govuk-input search-input", "aria-label": "Search"} + ), ) domains = forms.MultipleChoiceField( choices=get_domain_choices, diff --git a/templates/base/base.html b/templates/base/base.html index 32f4a675..70a587e6 100644 --- a/templates/base/base.html +++ b/templates/base/base.html @@ -13,7 +13,7 @@ {% include "base/navigation.html" %}
    -
    +

    diff --git a/templates/home.html b/templates/home.html index ff381bf9..0bb8fb40 100644 --- a/templates/home.html +++ b/templates/home.html @@ -4,8 +4,7 @@ {% block content %} Back -

    -

    Customised page template

    -
    +

    Customised page template

    + {% endblock content %} diff --git a/templates/partial/pagination.html b/templates/partial/pagination.html index 552c2d4e..85251911 100644 --- a/templates/partial/pagination.html +++ b/templates/partial/pagination.html @@ -9,6 +9,7 @@ Previous page
    {% endif %} +
      {% for p in page_range %} {% if paginator.ELLIPSIS != p %} {% if page_obj.number == p %} @@ -20,11 +21,11 @@ {{ p }} -
    {% else %}
  • {% endif %} {% endfor %} + {% if page_obj.has_next %}
    Back
    -
    +
    {{result_type}}

    {{result.name}}

    @@ -28,16 +28,16 @@

    {{result.name}}

    {{result.metadata.owner_email}}
    - - + +
    Domain name
    - {{result.metadata.domain.properties.name}} + {{result.metadata.domain.properties.name|markdown}}
    - - + +
    Last updated date
    @@ -46,24 +46,24 @@

    {{result.name}}

    {% endif %}
    - +
    Refresh period
    - +
    - +
    Retention period
    - +
    DPIA Status
    - +
    @@ -109,7 +109,7 @@

    {{result.name}}

    - +

    IAO or Data Owner

    @@ -126,7 +126,7 @@

    {{result.name}}

    Access requirement

    - Processing the data might require + Processing the data might require permission from IAO or Data owner
    From 8c32a9e4e344b0ef47020fc48eae09469007e128 Mon Sep 17 00:00:00 2001 From: Murdo Moyse Date: Mon, 19 Feb 2024 14:03:25 +0000 Subject: [PATCH 156/221] Added matched fields row for search results --- templates/partial/search_result.html | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/templates/partial/search_result.html b/templates/partial/search_result.html index 1a409614..eeefd5ce 100644 --- a/templates/partial/search_result.html +++ b/templates/partial/search_result.html @@ -21,7 +21,7 @@

    {{result.metadata.search_summary|markdown}}
    {% endif %} - +
    @@ -50,7 +50,13 @@

    {{ result.tags |join:", " }}

    +
    +
    Matched fields
    +
    + {{ result.matches |join:", " }} +
    +

    {%endfor%} -
    \ No newline at end of file +
    From 773baf59ba325e5f99ff6fef6ad13f117dd2edb0 Mon Sep 17 00:00:00 2001 From: Murdo Moyse Date: Mon, 19 Feb 2024 14:20:14 +0000 Subject: [PATCH 157/221] Implement search highlighting for description fields --- home/service/search.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/home/service/search.py b/home/service/search.py index 7e4a54c4..ffad5a14 100644 --- a/home/service/search.py +++ b/home/service/search.py @@ -42,8 +42,13 @@ def _get_search_results(self, page: str, items_per_page: int): sort=sort_option, count=items_per_page, ) + highlighted_results = ( + self._highlight_results(results, query) + if query != "" + else results + ) - return results + return highlighted_results def _get_paginator(self, items_per_page: int) -> Paginator: pages_list = list(range(self.results.total_results)) @@ -79,3 +84,20 @@ def _get_context(self) -> dict[str, Any]: } return context + + def _highlight_results(self, results, string_to_highlight): + "Take a SearchResponse and add bold markdown where a string appears" + for result in results.page_results: + metadata = getattr(result, "metadata") + highlighted_search_summary = metadata.get("search_summary", "").replace( + string_to_highlight, f"**{string_to_highlight}**" + ) + setattr(result, "metadata", metadata) + + name = getattr(result, "description") + highlighted_description = name.replace( + string_to_highlight, f"**{string_to_highlight}**" + ) + setattr(result, "description", highlighted_description) + + return results From 65fc8c5a24e75a5881cfa4f42270e83eed529223 Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Mon, 19 Feb 2024 14:16:15 +0000 Subject: [PATCH 158/221] Include subdomains in the filter when we filter by a parent domain I've just hardcoded the domains for now, since I just want to get the top-level domain filter working as expected again after assigning assets to subdomains. --- home/forms/search.py | 50 ++++++++++++++++++++++++++++++++++++++---- home/service/search.py | 19 ++++++++++++---- tests/test_services.py | 28 +++++++++++++++++++---- 3 files changed, 85 insertions(+), 12 deletions(-) diff --git a/home/forms/search.py b/home/forms/search.py index 2dec2484..b54b435f 100644 --- a/home/forms/search.py +++ b/home/forms/search.py @@ -12,11 +12,55 @@ def get_domain_choices(): return [ ("urn:li:domain:HMCTS", "HMCTS"), ("urn:li:domain:HMPPS", "HMPPS"), - ("urn:li:domain:OPG", "OPG"), ("urn:li:domain:HQ", "HQ"), + ("urn:li:domain:LAA", "LAA"), + ("urn:li:domain:OPG", "OPG"), ] +def get_subdomain_choices(domain): + # TODO: pull in the subdomains from the catalogue client so we don't need to hardcode + return { + "urn:li:domain:HMPPS": [ + ("urn:li:domain:2feb789b-44d3-4412-b998-1f26819fabf9", "Prisons"), + ("urn:li:domain:abe153c1-416b-4abb-be7f-6accf2abb10a", "Probation"), + ], + "urn:li:domain:HMCTS": [ + ("urn:li:domain:4d77af6d-9eca-4c44-b189-5f1addffae55", "Civil courts"), + ("urn:li:domain:31754f66-33df-4a73-b039-532518bc765e", "Crown courts"), + ("urn:li:domain:81adfe94-1284-46a2-9179-945ad2a76c14", "Family courts"), + ( + "urn:li:domain:b261176c-d8eb-4111-8454-c0a1fa95005f", + "Magistrates courts", + ), + ], + "urn:li:domain:OPG": [ + ( + "urn:li:domain:bc091f6c-7674-4c82-a315-f5489398f099", + "Lasting power of attourney", + ), + ( + "urn:li:domain:efb9ade3-3c5d-4c5c-b451-df9f2d8136f5", + "Supervision orders", + ), + ], + "urn:li:domain:HQ": [ + ("urn:li:domain:9fb7ff13-6c7e-47ef-bef1-b13b23fd8c7a", "Estates"), + ("urn:li:domain:e4476e66-37a1-40fd-83b9-c908f805d8f4", "Finance"), + ("urn:li:domain:0985731b-8e1c-4b4a-bfc0-38e58d8ba8a1", "People"), + ("urn:li:domain:a320c915-0b43-4277-9769-66615aab4adc", "Performance"), + ], + "urn:li:domain:LAA": [ + ( + "urn:li:domain:24344488-d770-437a-ba6f-e6129203b927", + "Civil legal advice", + ), + ("urn:li:domain:Legal%20Aid", "Legal aid"), + ("urn:li:domain:5c423c06-d328-431f-8634-7a7e86928819", "Public defender"), + ], + }.get(domain, []) + + def get_sort_choices(): return [ ("relevance", "Relevance"), @@ -32,9 +76,7 @@ class SearchForm(forms.Form): max_length=100, strip=False, required=False, - widget=forms.TextInput( - attrs={"class": "govuk-input search-input"} - ), + widget=forms.TextInput(attrs={"class": "govuk-input search-input"}), ) domains = forms.MultipleChoiceField( choices=get_domain_choices, diff --git a/home/service/search.py b/home/service/search.py index 7e4a54c4..40c4c5da 100644 --- a/home/service/search.py +++ b/home/service/search.py @@ -3,11 +3,23 @@ from data_platform_catalogue.search_types import MultiSelectFilter, SortOption from django.core.paginator import Paginator -from home.forms.search import SearchForm +from home.forms.search import SearchForm, get_subdomain_choices from .base import GenericService +def domains_with_their_subdomains(domains: list[str]) -> list[str]: + """ + When assets are tagged to subdomains, they are not included in search results if + we filter by domain alone. We need to include all possible subdomains in the filter. + """ + return [ + subdomain + for domain in domains + for (subdomain, _) in get_subdomain_choices(domain) + ] + domains + + class SearchService(GenericService): def __init__(self, form: SearchForm, page: str, items_per_page: int = 20): self.form = form @@ -24,9 +36,8 @@ def _get_search_results(self, page: str, items_per_page: int): form_data = {} query = form_data.get("query", "") sort = form_data.get("sort", "relevance") - domains = form_data.get("domains", []) - filter_value = [MultiSelectFilter( - "domains", domains)] if domains else [] + domains = domains_with_their_subdomains(form_data.get("domains", [])) + filter_value = [MultiSelectFilter("domains", domains)] if domains else [] page_for_search = str(int(page) - 1) if sort == "ascending": sort_option = SortOption(field="name", ascending=True) diff --git a/tests/test_services.py b/tests/test_services.py index 60160f5e..f4392336 100644 --- a/tests/test_services.py +++ b/tests/test_services.py @@ -1,14 +1,17 @@ from types import GeneratorType + +import pytest from data_platform_catalogue.search_types import ResultType +from home.service.search import domains_with_their_subdomains + class TestSearchService: def test_get_context_form(self, valid_form, search_context): assert search_context["form"] == valid_form def test_get_context_search_result(self, mock_catalogue, search_context): - assert search_context["results"] == mock_catalogue.search( - ).page_results + assert search_context["results"] == mock_catalogue.search().page_results assert search_context["total_results"] == 100 def test_get_context_paginator(self, search_context): @@ -27,8 +30,7 @@ def test_get_context_label_clear_href(self, search_context): class TestDetailsService: def test_get_context(self, detail_context, mock_catalogue): - assert detail_context["result"] == mock_catalogue.search( - ).page_results[0] + assert detail_context["result"] == mock_catalogue.search().page_results[0] result_type = ( "Data product" if mock_catalogue.search().page_results[0].result_type @@ -40,3 +42,21 @@ def test_get_context(self, detail_context, mock_catalogue): detail_context["page_title"] == f"{mock_catalogue.search().page_results[0].name} - Data catalogue" ) + + +@pytest.mark.parametrize( + "domain, expected_subdomains", + [ + ("does-not-exist", ["does-not-exist"]), + ( + "urn:li:domain:HMPPS", + [ + "urn:li:domain:2feb789b-44d3-4412-b998-1f26819fabf9", + "urn:li:domain:abe153c1-416b-4abb-be7f-6accf2abb10a", + "urn:li:domain:HMPPS", + ], + ), + ], +) +def test_domain_expansion(domain, expected_subdomains): + assert domains_with_their_subdomains([domain]) == expected_subdomains From 69b332b2724dfee0bdd9a640ff8229a27903c452 Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Mon, 19 Feb 2024 14:23:23 +0000 Subject: [PATCH 159/221] Remove redundant formatter Instead of using this, we can either use the pre-commit hook, or setup black/ruff in the editor. --- .github/workflows/format-code.yml | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 .github/workflows/format-code.yml diff --git a/.github/workflows/format-code.yml b/.github/workflows/format-code.yml deleted file mode 100644 index 5a82751b..00000000 --- a/.github/workflows/format-code.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: code-formatter - -on: - pull_request: - types: [opened, edited, reopened, synchronize] - -jobs: - format-code: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: ministryofjustice/github-actions/code-formatter@v14 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 0a94047c7e55f7e63277c80c4c039299eb2c5d1c Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Mon, 19 Feb 2024 15:02:39 +0000 Subject: [PATCH 160/221] Add new crown 5.1.0 of the design system updated the GOV.UK logo to use the tudor crown. See https://github.com/alphagov/govuk-frontend/blob/main/CHANGELOG.md#510-feature-release --- package-lock.json | 8 +- package.json | 2 +- static/assets/css/base.css | 237 +++++++----------- static/assets/css/base.css.map | 2 +- static/assets/css/search.css.map | 2 +- static/assets/images/favicon.ico | Bin 6318 -> 14254 bytes static/assets/images/favicon.svg | 5 +- static/assets/images/govuk-icon-180.png | Bin 10046 -> 1605 bytes static/assets/images/govuk-icon-192.png | Bin 1720 -> 1678 bytes static/assets/images/govuk-icon-512.png | Bin 4780 -> 4682 bytes static/assets/images/govuk-icon-mask.svg | 4 +- .../assets/images/govuk-opengraph-image.png | Bin 15380 -> 8677 bytes static/assets/js/govuk-frontend-5.0.0.min.js | 1 - .../assets/js/govuk-frontend-5.0.0.min.js.map | 1 - static/assets/js/govuk-frontend.min.js | 1 + static/assets/js/govuk-frontend.min.js.map | 1 + templates/base/base.html | 2 +- templates/base/navigation.html | 19 +- 18 files changed, 109 insertions(+), 176 deletions(-) delete mode 100644 static/assets/js/govuk-frontend-5.0.0.min.js delete mode 100644 static/assets/js/govuk-frontend-5.0.0.min.js.map create mode 100644 static/assets/js/govuk-frontend.min.js create mode 100644 static/assets/js/govuk-frontend.min.js.map diff --git a/package-lock.json b/package-lock.json index 8be152aa..4aa189b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "": { "dependencies": { "@ministryofjustice/frontend": "^2.1.0", - "govuk-frontend": "^5.0.0", + "govuk-frontend": "^5.1.0", "sass": "^1.70.0" } }, @@ -118,9 +118,9 @@ } }, "node_modules/govuk-frontend": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/govuk-frontend/-/govuk-frontend-5.0.0.tgz", - "integrity": "sha512-3WSfvQ+3kw/q/m8jrq/t8XnMUA8D2r0uhGyZaDbIh1gWTJBQzJBHbHiKYI9nc9ixIXdCFsc9RozkgEm57a795g==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/govuk-frontend/-/govuk-frontend-5.1.0.tgz", + "integrity": "sha512-Dc3J+uOI4i2VR3BVyfxbf6qVjTT4n4bBqbD0/Io6feP8pt/4IfKdP1vWimZf+BwMKKMXacw10hmdy5UcD6Cr8w==", "engines": { "node": ">= 4.2.0" } diff --git a/package.json b/package.json index ece087f8..f9d4a7a8 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "dependencies": { "@ministryofjustice/frontend": "^2.1.0", - "govuk-frontend": "^5.0.0", + "govuk-frontend": "^5.1.0", "sass": "^1.70.0" }, "scripts": { diff --git a/static/assets/css/base.css b/static/assets/css/base.css index 830d15a6..d21d1767 100644 --- a/static/assets/css/base.css +++ b/static/assets/css/base.css @@ -43,7 +43,10 @@ :root { - --govuk-frontend-version: "5.0.0"; + --govuk-frontend-version: "5.1.0"; + --govuk-frontend-breakpoint-mobile: 20rem; + --govuk-frontend-breakpoint-tablet: 40.0625rem; + --govuk-frontend-breakpoint-desktop: 48.0625rem; } @@ -2451,25 +2454,10 @@ p + .govuk-heading-s, } .govuk-character-count__message { - font-family: "GDS Transport", arial, sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - font-feature-settings: "tnum" 1; - font-weight: 400; + font-variant-numeric: tabular-nums; margin-top: 0; margin-bottom: 0; } -@media print { - .govuk-character-count__message { - font-family: sans-serif; - } -} -@supports (font-variant-numeric: tabular-nums) { - .govuk-character-count__message { - font-feature-settings: normal; - font-variant-numeric: tabular-nums; - } -} .govuk-character-count__message::after { content: "​"; } @@ -2608,12 +2596,10 @@ p + .govuk-heading-s, .govuk-checkboxes__item { - display: block; + display: flex; + flex-wrap: wrap; position: relative; - min-height: 40px; margin-bottom: 10px; - padding-left: 40px; - clear: left; } .govuk-checkboxes__item:last-child, @@ -2622,10 +2608,6 @@ p + .govuk-heading-s, } .govuk-checkboxes__input { - position: absolute; - z-index: 1; - top: -2px; - left: -2px; width: 44px; height: 44px; margin: 0; @@ -2634,9 +2616,10 @@ p + .govuk-heading-s, } .govuk-checkboxes__label { - display: inline-block; + align-self: center; + max-width: calc(100% - 74px); margin-bottom: 0; - padding: 8px 15px 5px; + padding: 7px 15px; cursor: pointer; touch-action: manipulation; } @@ -2645,8 +2628,8 @@ p + .govuk-heading-s, content: ""; box-sizing: border-box; position: absolute; - top: 0; - left: 0; + top: 2px; + left: 2px; width: 40px; height: 40px; border: 2px solid currentcolor; @@ -2657,8 +2640,8 @@ p + .govuk-heading-s, content: ""; box-sizing: border-box; position: absolute; - top: 11px; - left: 9px; + top: 13px; + left: 10px; width: 23px; height: 12px; transform: rotate(-45deg); @@ -2671,8 +2654,14 @@ p + .govuk-heading-s, .govuk-checkboxes__hint { display: block; + width: 100%; + margin-top: -5px; padding-right: 15px; - padding-left: 15px; + padding-left: 59px; +} + +.govuk-label:not(.govuk-label--m):not(.govuk-label--l):not(.govuk-label--xl) + .govuk-checkboxes__hint { + margin-bottom: 0; } .govuk-checkboxes__input:focus + .govuk-checkboxes__label::before { @@ -2755,49 +2744,33 @@ p + .govuk-heading-s, } .govuk-checkboxes--small .govuk-checkboxes__item { - min-height: 0; margin-bottom: 0; - padding-left: 34px; - float: left; -} -.govuk-checkboxes--small .govuk-checkboxes__item::after { - content: ""; - display: block; - clear: both; } .govuk-checkboxes--small .govuk-checkboxes__input { - left: -10px; + margin-left: -10px; } .govuk-checkboxes--small .govuk-checkboxes__label { - margin-top: -2px; - padding: 13px 15px 13px 1px; - float: left; -} -@media (min-width: 40.0625em) { - .govuk-checkboxes--small .govuk-checkboxes__label { - padding: 11px 15px 10px 1px; - } + padding-left: 1px; } .govuk-checkboxes--small .govuk-checkboxes__label::before { - top: 8px; + top: 10px; + left: 0; width: 24px; height: 24px; } .govuk-checkboxes--small .govuk-checkboxes__label::after { - top: 15px; + top: 17px; left: 6px; width: 12px; height: 6.5px; border-width: 0 0 3px 3px; } .govuk-checkboxes--small .govuk-checkboxes__hint { - padding: 0; - clear: both; + padding-left: 34px; } .govuk-checkboxes--small .govuk-checkboxes__conditional { margin-left: 10px; padding-left: 20px; - clear: both; } .govuk-checkboxes--small .govuk-checkboxes__item:hover .govuk-checkboxes__input:not(:disabled) + .govuk-checkboxes__label::before { outline: 3px dashed transparent; @@ -2911,24 +2884,9 @@ p + .govuk-heading-s, } .govuk-input--extra-letter-spacing { - font-family: "GDS Transport", arial, sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - font-feature-settings: "tnum" 1; - font-weight: 400; + font-variant-numeric: tabular-nums; letter-spacing: 0.05em; } -@media print { - .govuk-input--extra-letter-spacing { - font-family: sans-serif; - } -} -@supports (font-variant-numeric: tabular-nums) { - .govuk-input--extra-letter-spacing { - font-feature-settings: normal; - font-variant-numeric: tabular-nums; - } -} .govuk-input--width-30 { max-width: 29.5em; @@ -2985,7 +2943,9 @@ p + .govuk-heading-s, font-size: 1rem; line-height: 1.25; box-sizing: border-box; - display: inline-block; + display: flex; + align-items: center; + justify-content: center; min-width: 2.5rem; height: 2.5rem; padding: 5px; @@ -3016,12 +2976,6 @@ p + .govuk-heading-s, line-height: 1.15; } } -@media (max-width: 40.0525em) { - .govuk-input__prefix, - .govuk-input__suffix { - line-height: 1.6; - } -} @media (max-width: 19.99em) { .govuk-input__prefix, .govuk-input__suffix { @@ -3921,7 +3875,7 @@ p + .govuk-heading-s, .govuk-header__logo { margin-bottom: 10px; - padding-right: 50px; + padding-right: 80px; } @media (min-width: 48.0625em) { .govuk-header__logo { @@ -3953,13 +3907,16 @@ p + .govuk-heading-s, font-size: 0.875rem; line-height: 1.1428571429; position: absolute; - top: 20px; + top: 13px; right: 0; + max-width: 80px; + min-height: 24px; margin: 0; padding: 0; border: 0; color: #ffffff; background: none; + word-break: break-all; cursor: pointer; } @media print { @@ -4835,12 +4792,10 @@ p + .govuk-heading-s, .govuk-radios__item { - display: block; + display: flex; + flex-wrap: wrap; position: relative; - min-height: 40px; margin-bottom: 10px; - padding-left: 40px; - clear: left; } .govuk-radios__item:last-child, @@ -4849,10 +4804,6 @@ p + .govuk-heading-s, } .govuk-radios__input { - position: absolute; - z-index: 1; - top: -2px; - left: -2px; width: 44px; height: 44px; margin: 0; @@ -4861,9 +4812,10 @@ p + .govuk-heading-s, } .govuk-radios__label { - display: inline-block; + align-self: center; + max-width: calc(100% - 74px); margin-bottom: 0; - padding: 8px 15px 5px; + padding: 7px 15px; cursor: pointer; touch-action: manipulation; } @@ -4872,8 +4824,8 @@ p + .govuk-heading-s, content: ""; box-sizing: border-box; position: absolute; - top: 0; - left: 0; + top: 2px; + left: 2px; width: 40px; height: 40px; border: 2px solid currentcolor; @@ -4884,8 +4836,8 @@ p + .govuk-heading-s, .govuk-radios__label::after { content: ""; position: absolute; - top: 10px; - left: 10px; + top: 12px; + left: 12px; width: 0; height: 0; border: 10px solid currentcolor; @@ -4896,8 +4848,14 @@ p + .govuk-heading-s, .govuk-radios__hint { display: block; + width: 100%; + margin-top: -5px; padding-right: 15px; - padding-left: 15px; + padding-left: 59px; +} + +.govuk-label:not(.govuk-label--m):not(.govuk-label--l):not(.govuk-label--xl) + .govuk-radios__hint { + margin-bottom: 0; } .govuk-radios__input:focus + .govuk-radios__label::before { @@ -4927,15 +4885,13 @@ p + .govuk-heading-s, } @media (min-width: 40.0625em) { - .govuk-radios--inline::after { - content: ""; - display: block; - clear: both; + .govuk-radios--inline { + display: flex; + flex-wrap: wrap; + align-items: flex-start; } .govuk-radios--inline .govuk-radios__item { margin-right: 20px; - float: left; - clear: none; } } @@ -4993,48 +4949,31 @@ p + .govuk-heading-s, } .govuk-radios--small .govuk-radios__item { - min-height: 0; margin-bottom: 0; - padding-left: 34px; - float: left; -} -.govuk-radios--small .govuk-radios__item::after { - content: ""; - display: block; - clear: both; } .govuk-radios--small .govuk-radios__input { - left: -10px; + margin-left: -10px; } .govuk-radios--small .govuk-radios__label { - margin-top: -2px; - padding: 13px 15px 13px 1px; - float: left; -} -@media (min-width: 40.0625em) { - .govuk-radios--small .govuk-radios__label { - padding: 11px 15px 10px 1px; - } + padding-left: 1px; } .govuk-radios--small .govuk-radios__label::before { - top: 8px; + top: 10px; + left: 0; width: 24px; height: 24px; } .govuk-radios--small .govuk-radios__label::after { - top: 15px; + top: 17px; left: 7px; border-width: 5px; } .govuk-radios--small .govuk-radios__hint { - padding: 0; - clear: both; - pointer-events: none; + padding-left: 34px; } .govuk-radios--small .govuk-radios__conditional { margin-left: 10px; padding-left: 20px; - clear: both; } .govuk-radios--small .govuk-radios__divider { width: 24px; @@ -5604,22 +5543,7 @@ p + .govuk-heading-s, } .govuk-table__cell--numeric { - font-family: "GDS Transport", arial, sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - font-feature-settings: "tnum" 1; - font-weight: 400; -} -@media print { - .govuk-table__cell--numeric { - font-family: sans-serif; - } -} -@supports (font-variant-numeric: tabular-nums) { - .govuk-table__cell--numeric { - font-feature-settings: normal; - font-variant-numeric: tabular-nums; - } + font-variant-numeric: tabular-nums; } .govuk-table__header--numeric, @@ -9659,7 +9583,7 @@ span.moj-header__link:hover { color: #1d70b8; } .moj-primary-navigation__link:hover { - color: #5694ca; + color: #003078; } .moj-primary-navigation__link:focus { color: #0b0c0c; @@ -9693,6 +9617,12 @@ span.moj-header__link:hover { left: 0; width: 100%; } +.moj-primary-navigation__link[aria-current]:hover { + color: #003078; +} +.moj-primary-navigation__link[aria-current]:hover:before { + background-color: #003078; +} .moj-primary-navigation__link[aria-current]:focus { color: #0b0c0c; position: relative; @@ -10197,14 +10127,12 @@ span.moj-header__link:hover { } } .moj-side-navigation__item a:hover { - border-color: #5694ca; + color: #003078; } .moj-side-navigation__item a:focus { color: #0b0c0c; background-color: #ffdd00; - box-shadow: 0 -2px #ffdd00, 0 4px #0b0c0c; border-color: #0b0c0c; - border-left-color: transparent; position: relative; } @@ -10214,12 +10142,14 @@ span.moj-header__link:hover { color: #1d70b8; font-weight: bold; } +.moj-side-navigation__item--active a:hover { + color: #003078; + border-color: #003078; +} .moj-side-navigation__item--active a:focus { color: #0b0c0c; background-color: #ffdd00; - box-shadow: 0 -2px #ffdd00, 0 4px #0b0c0c; border-color: #0b0c0c; - border-left-color: transparent; } @media (min-width: 40.0625em) { .moj-side-navigation__item--active a:link, @@ -10229,7 +10159,6 @@ span.moj-header__link:hover { .moj-side-navigation__item--active a:focus { color: #0b0c0c; background-color: #ffdd00; - border-color: transparent; } } @@ -10419,7 +10348,7 @@ span.moj-header__link:hover { color: #1d70b8; } .moj-sub-navigation__link:hover { - color: #5694ca; + color: #003078; } .moj-sub-navigation__link:focus { color: #0b0c0c; @@ -10430,12 +10359,17 @@ span.moj-header__link:hover { background-color: #0b0c0c; content: ""; display: block; - width: 100%; + height: 100%; position: absolute; bottom: 0; left: 0; - right: 0; - height: 5px; + width: 5px; +} +@media (min-width: 40.0625em) { + .moj-sub-navigation__link:focus:before { + height: 5px; + width: 100%; + } } .moj-sub-navigation__link[aria-current=page] { @@ -10459,6 +10393,9 @@ span.moj-header__link:hover { width: 100%; } } +.moj-sub-navigation__link[aria-current=page]:hover { + color: #003078; +} .moj-sub-navigation__link[aria-current=page]:focus:before { background-color: #0b0c0c; } diff --git a/static/assets/css/base.css.map b/static/assets/css/base.css.map index 678157ee..6446a3e0 100644 --- a/static/assets/css/base.css.map +++ b/static/assets/css/base.css.map @@ -1 +1 @@ -{"version":3,"sourceRoot":"","sources":["../../../node_modules/govuk-frontend/dist/govuk/core/_govuk-frontend-version.scss","../../../node_modules/govuk-frontend/dist/govuk/core/_links.scss","../../../node_modules/govuk-frontend/dist/govuk/helpers/_typography.scss","../../../node_modules/govuk-frontend/dist/govuk/settings/_typography-font.scss","../../../node_modules/govuk-frontend/dist/govuk/helpers/_links.scss","../../../node_modules/govuk-frontend/dist/govuk/settings/_links.scss","../../../node_modules/govuk-frontend/dist/govuk/helpers/_font-faces.scss","../../../node_modules/govuk-frontend/dist/govuk/vendor/_sass-mq.scss","../../../node_modules/govuk-frontend/dist/govuk/helpers/_focused.scss","../../../node_modules/govuk-frontend/dist/govuk/settings/_colours-applied.scss","../../../node_modules/govuk-frontend/dist/govuk/core/_lists.scss","../../../node_modules/govuk-frontend/dist/govuk/helpers/_spacing.scss","../../../node_modules/govuk-frontend/dist/govuk/core/_typography.scss","../../../node_modules/govuk-frontend/dist/govuk/core/_section-break.scss","../../../node_modules/govuk-frontend/dist/govuk/objects/_button-group.scss","../../../node_modules/govuk-frontend/dist/govuk/objects/_form-group.scss","../../../node_modules/govuk-frontend/dist/govuk/helpers/_clearfix.scss","../../../node_modules/govuk-frontend/dist/govuk/objects/_grid.scss","../../../node_modules/govuk-frontend/dist/govuk/helpers/_grid.scss","../../../node_modules/govuk-frontend/dist/govuk/objects/_main-wrapper.scss","../../../node_modules/govuk-frontend/dist/govuk/objects/_template.scss","../../../node_modules/govuk-frontend/dist/govuk/objects/_width-container.scss","../../../node_modules/govuk-frontend/dist/govuk/settings/_measurements.scss","../../../node_modules/govuk-frontend/dist/govuk/components/accordion/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/back-link/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/breadcrumbs/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/button/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/error-message/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/hint/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/label/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/textarea/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/character-count/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/fieldset/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/checkboxes/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/cookie-banner/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/input/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/date-input/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/details/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/helpers/_shape-arrow.scss","../../../node_modules/govuk-frontend/dist/govuk/components/error-summary/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/exit-this-page/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/file-upload/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/footer/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/helpers/_device-pixels.scss","../../../node_modules/govuk-frontend/dist/govuk/components/header/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/inset-text/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/notification-banner/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/pagination/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/panel/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/tag/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/phase-banner/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/radios/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/select/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/skip-link/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/helpers/_visually-hidden.scss","../../../node_modules/govuk-frontend/dist/govuk/components/summary-list/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/table/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/tabs/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/task-list/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/warning-text/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/utilities/_visually-hidden.scss","../../../node_modules/govuk-frontend/dist/govuk/overrides/_display.scss","../../../node_modules/govuk-frontend/dist/govuk/overrides/_spacing.scss","../../../node_modules/govuk-frontend/dist/govuk/overrides/_text-align.scss","../../../node_modules/govuk-frontend/dist/govuk/overrides/_typography.scss","../../../node_modules/govuk-frontend/dist/govuk/overrides/_width.scss","../../../node_modules/@ministryofjustice/frontend/moj/settings/_assets.scss","../../../node_modules/@ministryofjustice/frontend/moj/settings/_measurements.scss","../../../node_modules/@ministryofjustice/frontend/moj/settings/_colours.scss","../../../node_modules/@ministryofjustice/frontend/moj/objects/_filter-layout.scss","../../../node_modules/@ministryofjustice/frontend/moj/objects/_scrollable-pane.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/action-bar/_action-bar.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/add-another/_add-another.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/badge/_badge.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/banner/_banner.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/button-menu/_button-menu.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/cookie-banner/_cookie-banner.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/currency-input/_currency-input.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/filter/_filter.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/header/_header.scss","../../../node_modules/@ministryofjustice/frontend/moj/objects/_width-container.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/identity-bar/_identity-bar.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/messages/_messages.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/multi-file-upload/_multi-file-upload.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/multi-select/_multi-select.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/notification-badge/_notification-badge.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/organisation-switcher/_organisation-switcher.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/page-header-actions/_page-header-actions.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/pagination/_pagination.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/password-reveal/_password-reveal.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/primary-navigation/_primary-navigation.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/progress-bar/_progress-bar.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/rich-text-editor/_rich-text-editor.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/search-toggle/search-toggle.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/search/_search.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/side-navigation/_side-navigation.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/sortable-table/_sortable-table.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/sub-navigation/_sub-navigation.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/tag/_tag.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/task-list/_task-list.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/timeline/_timeline.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/ticket-panel/_ticket-panel.scss","../../../node_modules/@ministryofjustice/frontend/moj/utilities/_hidden.scss","../../../node_modules/@ministryofjustice/frontend/moj/helpers/_hidden.scss","../../../node_modules/@ministryofjustice/frontend/moj/utilities/_width-container.scss"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;EAGE;;;;ACFA;ECcA,aCFkB;EDGlB;EACA;EEaA;EAGE,2BChB6B;EDoB7B,uBCP0B;;ACdxB;AACA;EACE;EACA;EACA;EACA,KACE;EAEF;;AAGF;EACE;EACA;EACA;EACA,KACE;EAEF;;ACkMA;ENnON;ICyBE,aCHsB;;;ACTxB;EAqCE,2BCLmC;EDQnC;EACQ;EACR;EACQ;;AAvCV;EIFA;EACA,OC4DwB;ED3DxB,kBCiDmB;EDhDnB,YACE;EAIF;EAIA;EACQ;;AJgDR;EACE,OKuDgB;;ALpDlB;EACE,OK0DwB;;ALvD1B;EACE,OK6DsB;;AL1DxB;EACE,OKgEuB;;AL3DzB;EACE,OKnBsB;;AFuJlB;EH+HF;IACE;IACA;IAKA;;;;AA3KN;EAEE,OKxI0B;;AL2I5B;EAEE,OKhLgB;;ALqLlB;EACE,OK/HsB;;;ALoJxB;EF5LA,OOfkB;;AF8MZ;EHHN;IFzLE,OOQsB;;;ALwLxB;EAEI;;AAIJ;EFzMA,OOfkB;;AF8MZ;EHUN;IFtME,OOQsB;;;;ALqNxB;EAEE;;AAKF;EAEE;;AAGF;EACE,OKrMsB;;;ALoQxB;EACE;;;AAvCF;EACE,OKvKgB;;AL0KlB;EACE,OK3KgB;;AL8KlB;EACE,OKjKsB;;ALoKxB;EACE,OK9JuB;;ALmKzB;EACE,OKjPsB;;;ARzCxB;EGqVA;EAGA;EAGA;;AAEA;EIvVA;EACA,YACE;;;;AE3CF;ERcA,aCFkB;EDGlB;EACA;EAkCA;EAyFI,WAJc;EAKd,aAJY;EApGhB,OOfkB;EClBhB;ECsGI;EDpGJ;EACA;;AH6NI;EGnON;IRyBE,aCHsB;;;AI6MlB;EGnON;IRoJM,WAbY;IAcZ,aAbU;;;AK2FV;EGnON;IR+IM,WATQ;IAUR,aARU;;;AK2FV;EGnON;IRuCE,OOQsB;;;AFoLlB;EGnON;ICgHQ;;;ADvGN;EACE;;;AAIJ;EAIE;;;AAOF;EACE;EACA;;;AAGF;EACE;EACA;;;AAGF;AAAA;EAEE;;AH8LI;EGhMN;AAAA;IAKI;;;;AAIJ;EACE;;AHsLI;EGvLN;IAII;;;;;AE9CJ;EVkCA,OOfkB;EPPlB,aCFkB;EDGlB;EACA;EA4CA;EA+EI,WAJc;EAKd,aAJY;EUlId;EAEA;EDiGI;;AJ0HA;EKjON;IVqCE,OOQsB;;;AFoLlB;EKjON;IVuBE,aCHsB;;;AI6MlB;EKjON;IVkJM,WAbY;IAcZ,aAbU;;;AK2FV;EKjON;IV6IM,WATQ;IAUR,aARU;;;AK2FV;EKjON;ID8GQ;;;;AChGR;EVoBA,OOfkB;EPPlB,aCFkB;EDGlB;EACA;EA4CA;EA+EI,WAJc;EAKd,aAJY;EUpHd;EAEA;EDmFI;;AJ0HA;EKnNN;IVuBE,OOQsB;;;AFoLlB;EKnNN;IVSE,aCHsB;;;AI6MlB;EKnNN;IVoIM,WAbY;IAcZ,aAbU;;;AK2FV;EKnNN;IV+HM,WATQ;IAUR,aARU;;;AK2FV;EKnNN;IDgGQ;;;;AClFR;EVMA,OOfkB;EPPlB,aCFkB;EDGlB;EACA;EA4CA;EA+EI,WAJc;EAKd,aAJY;EUtGd;EAEA;EDqEI;;AJ0HA;EKrMN;IVSE,OOQsB;;;AFoLlB;EKrMN;IVLE,aCHsB;;;AI6MlB;EKrMN;IVsHM,WAbY;IAcZ,aAbU;;;AK2FV;EKrMN;IViHM,WATQ;IAUR,aARU;;;AK2FV;EKrMN;IDkFQ;;;;ACpER;EVRA,OOfkB;EPPlB,aCFkB;EDGlB;EACA;EA4CA;EA+EI,WAJc;EAKd,aAJY;EUxFd;EAEA;EDuDI;;AJ0HA;EKvLN;IVLE,OOQsB;;;AFoLlB;EKvLN;IVnBE,aCHsB;;;AI6MlB;EKvLN;IVwGM,WAbY;IAcZ,aAbU;;;AK2FV;EKvLN;IVmGM,WATQ;IAUR,aARU;;;AK2FV;EKvLN;IDoEQ;;;;ACpDR;EV9CA,aCFkB;EDGlB;EACA;EAkCA;EAyFI,WAJc;EAKd,aAJY;EUzEd;EAEA;EAEA,OHX0B;;AF2KtB;EKvKN;IVnCE,aCHsB;;;AI6MlB;EKvKN;IVwFM,WAbY;IAcZ,aAbU;;;AK2FV;EKvKN;IVmFM,WATQ;IAUR,aARU;;;;AUlEhB;EVxDA,aCFkB;EDGlB;EACA;EAkCA;EAyFI,WAJc;EAKd,aAJY;EU/Dd;EAEA;EACA,OHpB0B;;AF2KtB;EK7JN;IV7CE,aCHsB;;;AI6MlB;EK7JN;IV8EM,WAbY;IAcZ,aAbU;;;AK2FV;EK7JN;IVyEM,WATQ;IAUR,aARU;;;AK2FV;EK7JN;IASI;;;;AAIJ;EVrEA,aCFkB;EDGlB;EACA;EAkCA;EAyFI,WAJc;EAKd,aAJY;EUlDd;EAEA,OHhC0B;;AF2KtB;EKhJN;IV1DE,aCHsB;;;AI6MlB;EKhJN;IViEM,WAbY;IAcZ,aAbU;;;AK2FV;EKhJN;IV4DM,WATQ;IAUR,aARU;;;;AU3ChB;EVzDA,OOfkB;EPPlB,aCFkB;EDGlB;EACA;EAkCA;EAyFI,WAJc;EAKd,aAJY;EUvCd;EDQI;;AJ0HA;EKtIN;IVtDE,OOQsB;;;AFoLlB;EKtIN;IVpEE,aCHsB;;;AI6MlB;EKtIN;IVuDM,WAbY;IAcZ,aAbU;;;AK2FV;EKtIN;IVkDM,WATQ;IAUR,aARU;;;AK2FV;EKtIN;IDmBQ;;;;ACPR;EVrEA,OOfkB;EPPlB,aCFkB;EDGlB;EACA;EAkCA;EAyFI,WAJc;EAKd,aAJY;EU3Bd;EDJI;;AJ0HA;EK1HN;IVlEE,OOQsB;;;AFoLlB;EK1HN;IVhFE,aCHsB;;;AI6MlB;EK1HN;IV2CM,WAbY;IAcZ,aAbU;;;AK2FV;EK1HN;IVsCM,WATQ;IAUR,aARU;;;AK2FV;EK1HN;IDOQ;;;;ACKR;EVjFA,OOfkB;EPPlB,aCFkB;EDGlB;EACA;EAkCA;EAyFI,WAJc;EAKd,aAJY;EUfd;EDhBI;;AJ0HA;EK9GN;IV9EE,OOQsB;;;AFoLlB;EK9GN;IV5FE,aCHsB;;;AI6MlB;EK9GN;IV+BM,WAbY;IAcZ,aAbU;;;AK2FV;EK9GN;IV0BM,WATQ;IAUR,aARU;;;AK2FV;EK9GN;IDLQ;;;;ACiBR;EV7FA,OOfkB;EPPlB,aCFkB;EDGlB;EACA;EAkCA;EAyFI,WAJc;EAKd,aAJY;EUHd;ED5BI;;AJ0HA;EKlGN;IV1FE,OOQsB;;;AFoLlB;EKlGN;IVxGE,aCHsB;;;AI6MlB;EKlGN;IVmBM,WAbY;IAcZ,aAbU;;;AK2FV;EKlGN;IVcM,WATQ;IAUR,aARU;;;AK2FV;EKlGN;IDjBQ;;;;AC6CR;EACE;;ALqEI;EKtEN;IAII;;;;AAIJ;AAAA;AAAA;ED5DM;;AJ0HA;EK9DN;AAAA;AAAA;IDrDQ;;;;AC2DR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAME;;ALkDI;EKxDN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;IASI;;;;;ACpLJ;EACE;EACA;;;AASF;EF8FM;EAAA;;AJ0HA;EMxNN;IFqGQ;;;AJmHF;EMxNN;IFqGQ;;;;AE5FR;EFqFM;EAAA;;AJ0HA;EM/MN;IF4FQ;;;AJmHF;EM/MN;IF4FQ;;;;AEnFR;EF4EM;EAAA;;AJ0HA;EMtMN;IFmFQ;;;AJmHF;EMtMN;IFmFQ;;;;AExER;EACE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/BF;EH+FM;EG3EJ;EACA;EACA;;APmMI;EOzNN;IHsGQ;;;AGzEN;EZzBF,aCFkB;EDGlB;EACA;EAkCA;EAyFI,WAJc;EAKd,aAJY;EY/FZ;EAGA;EACA,YA3Ba;EA4Bb;EACA;;APoLE;EO5LJ;IZdA,aCHsB;;;AI6MlB;EO5LJ;IZ6GI,WAbY;IAcZ,aAbU;;;AK2FV;EO5LJ;IZwGI,WATQ;IAUR,aARU;;;AYpFd;EACE;;AP8KE;EOzNN;IAkDI;IAEA;IACA;IACA;;EAEA;AAAA;IAEE,cAzDa;;EA4Df;IACE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtEN;EJuGM;;AKjGN;EACE;EACA;EACA;;ATwNI;EQjON;IJ8GQ;;;AI1GN;EACE;;;AAIJ;EACE;EACA;;AAEA;EAEE;EACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AEhBJ;EAEE;EACA;;ADGF;EACE;EACA;EACA;;;ACFA;ECyCF;EAEE;EAEF;;AX6KM;EU1NJ;IC+CA;IACA,OAR2C;;;;ADxC3C;ECyCF;EAEE;EAEF;;AX6KM;EU1NJ;IC+CA;IACA,OAR2C;;;;ADxC3C;ECyCF;EAEE;EAEF;;AX6KM;EU1NJ;IC+CA;IACA,OAR2C;;;;ADxC3C;ECyCF;EAEE;EAEF;;AX6KM;EU1NJ;IC+CA;IACA,OAR2C;;;;ADxC3C;ECyCF;EAEE;EAEF;;AX6KM;EU1NJ;IC+CA;IACA,OAR2C;;;;ADxC3C;ECyCF;EAEE;EAEF;;AX6KM;EU1NJ;IC+CA;IACA,OAR2C;;;;AD/B3C;ECgCF;EAIA;;AX6KM;EUjNJ;ICsCA;IACA,OAR2C;;;;AD/B3C;ECgCF;EAIA;;AX6KM;EUjNJ;ICsCA;IACA,OAR2C;;;;AD/B3C;ECgCF;EAIA;;AX6KM;EUjNJ;ICsCA;IACA,OAR2C;;;;AD/B3C;ECgCF;EAIA;;AX6KM;EUjNJ;ICsCA;IACA,OAR2C;;;;AD/B3C;ECgCF;EAIA;;AX6KM;EUjNJ;ICsCA;IACA,OAR2C;;;;AD/B3C;ECgCF;EAIA;;AX6KM;EUjNJ;ICsCA;IACA,OAR2C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1B7C;EAIE;EACA;EACA;;AZsMI;EY5MN;IAYI;IACA;;;;AAWJ;AAAA;ER0DM;;AJ0HA;EYpLN;AAAA;IRiEQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AS7GR;EAGE,kBXyB6B;EWrB7B;EACG;EACK;;AAcR;EAvBF;IAwBI;;EAEA;IACE;;;AbqMA;EahON;IAkCI;;;;AAKJ;EAGE;EAEA,kBXT2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AYgC7B;EAlDA,WCRiB;EDWjB,cC2BkB;ED1BlB,aC0BkB;;ADvBlB;EA2CA;IArCE;IACA;;;AdiMI;Ec7JN;IA/BE,cCIW;IDHX,aCGW;;EDAX;IA2BF;MArBI;MACA;;;;AdiLE;Ec7JN;IAbE;IACA;;EAIA;IAQF;MAPI;MACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AE3DJ;EZoGM;;AJ0HA;EgB9NN;IZ2GQ;;;;AYvGR;EACE;;;AAGF;EAEE;EACA;EAEA;EACA;;;AAGF;ErBRA,aCFkB;EDGlB;EACA;EA4CA;EA+EI,WAJc;EAKd,aAJY;EApGhB,OOfkB;EcKhB;EACA;EACA;;AhBuMI;EgB7MN;IrBGE,aCHsB;;;AI6MlB;EgB7MN;IrB8HM,WAbY;IAcZ,aAbU;;;AK2FV;EgB7MN;IrByHM,WATQ;IAUR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sDtJJ;AAAA;EAEE;;;AAGF;AAAA;EAEE;;;AAGF;EtDwBA;EsDrBE;EACA;;;AAIF;AAAA;AAAA;EAGE;;;AAGF;EtDyFI,WAJc;EAKd,aAJY;;AK2FV;EiDjLN;ItDkGM,WAbY;IAcZ,aAbU;;;AK2FV;EiDjLN;ItD6FM,WATQ;IAUR,aARU;;;;AsDlFhB;EtDqFI,WAJc;EAKd,aAJY;;AK2FV;EiD7KN;ItD8FM,WAbY;IAcZ,aAbU;;;AK2FV;EiD7KN;ItDyFM,WATQ;IAUR,aARU;;;;AsD9EhB;EtDiFI,WAJc;EAKd,aAJY;;AK2FV;EiDzKN;ItD0FM,WAbY;IAcZ,aAbU;;;AK2FV;EiDzKN;ItDqFM,WATQ;IAUR,aARU;;;;;AuDxIhB;E9CyGM;EAAA;ET3FN,aCFkB;EDGlB;EACA;EAkCA;EAyFI,WAJc;EAKd,aAJY;;AK2FV;EkDnON;I9CgHQ;;;AJmHF;EkDnON;IvDyBE,aCHsB;;;AI6MlB;EkDnON;IvDoJM,WAbY;IAcZ,aAbU;;;AK2FV;EkDnON;IvD+IM,WATQ;IAUR,aARU;;;;AuDlIhB;EvDqII,WAJc;EAKd,aAJY;EAtFhB;EAdA,OOfkB;EgDThB;;AlDuNI;EkD7NN;IvD8IM,WAbY;IAcZ,aAbU;;;AK2FV;EkD7NN;IvDyIM,WATQ;IAUR,aARU;;;AK2FV;EkD7NN;IvDiCE,OOQsB;;;;AgDhCxB;EACE;EACA;EACA;E9CuFI;;AJ0HA;EkDpNN;I9CiGQ;;;;A8C1FR;EACE;;AAEA;EvDWF,OOfkB;EgDMd;EACA;EACA;;AlDsME;EkD1MJ;IvDcA,OOQsB;;;;AgDdxB;EvDnBA,aCFkB;EDGlB;EACA;EEaA;EAGE,2BChB6B;EDoB7B,uBCP0B;EoDQ1B;EACA;;AlD6LI;EkDlMN;IvDRE,aCHsB;;;ACTxB;EAqCE,2BCLmC;EDQnC;EACQ;EACR;EACQ;;AAvCV;EIFA;EACA,OC4DwB;ED3DxB,kBCiDmB;EDhDnB,YACE;EAIF;EAIA;EACQ;;AJgDR;EACE,OKuDgB;;ALpDlB;EACE,OK0DwB;;ALvD1B;EACE,OK6DsB;;AL1DxB;EACE,OKgEuB;;AL3DzB;EACE,OKnBsB;;;AgDnCxB;E9CgEM;;AJ0HA;EkD1LN;I9CuEQ;;;;AJmHF;EkDnLF;IAEE;IACA;;EzC3CN;IACE;IACA;IACA;;EyC2CE;IACE;;EAGF;IACE;IAEA;IACA;IACA;IACA;IAEA;IACA;IACA;;EAEA;IACE;;EAIJ;IAGE;IAEA;IAGA;IACA;IACA;IACA;IACA;IAEA;IACA;IAEA,kBhDtDuB;;EgDwDvB;IACE;;EAIJ;IAGE;;ErD0HN;IF5LA,OOfkB;;;AF8MZ;EHHN;IFzLE,OOQsB;;;AFoLlB;EHIN;IAEI;;EAIJ;IFzMA,OOfkB;;;AF8MZ;EHUN;IFtME,OOQsB;;;AFoLlB;EkD3HA;IACE;IACA;IACA;IACA;IACA;IACA;;EAIJ;I9CTE;I8CWA;IACA;IACA;;EAEA;IACE;;EAIJ;IACE;;;;;;;AC1HN;ExDUA,aCFkB;EDGlB;EACA;EAkCA;EAyFI,WAJc;EAKd,aAJY;EwDlId;E/CmGI;E+CjGJ;EACA;;AnD0NI;EmD/NN;IxDqBE,aCHsB;;;AI6MlB;EmD/NN;IxDgJM,WAbY;IAcZ,aAbU;;;AK2FV;EmD/NN;IxD2IM,WATQ;IAUR,aARU;;;AK2FV;EmD/NN;I/C4GQ;;;;A+C/FR;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAMF;EACE,YAjC6B;;;AAoC/B;EACE;EACA;ExDJF,OOfkB;;AF8MZ;EmD7LN;IxDCE,OOQsB;;;;AiDHxB;EACE;EACA;EACA;EACA;ExDZF,OOfkB;;AF8MZ;EmDvLN;IxDLE,OOQsB;;;;AiDKxB;EACE,OjDG0B;;;AiDG5B;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA,OjDf0B;;;;;;;;AkDxD5B;EzDcA,aCFkB;EDGlB;EACA;EAkCA;EAyFI,WAJc;EAKd,aAJY;ES/BV;EgDtGJ;EACA;;ApD+NI;EoDnON;IzDyBE,aCHsB;;;AI6MlB;EoDnON;IzDoJM,WAbY;IAcZ,aAbU;;;AK2FV;EoDnON;IzD+IM,WATQ;IAUR,aARU;;;AK2FV;EoDnON;IhDgHQ;;;;AgDzGR;EzDqDA;EyDjDE;EAEA;EAEA;EACA;EAEA;EACA;EACA;EAQA;EACA;EAEA;EACA;EAEA;EACA;EAEA;EAIA;EACI;EACI;EAIR;;ApDoLI;EoD5NN;IAgBI;;;AA0BF;EA1CF;IA2CI;IACA;IACA;;;;AAIJ;EzDpBA,OOfkB;EkDqChB;EACA;;ApDwKI;EoD3KN;IzDjBE,OOQsB;;;;;;AOvCxB;EACE;EACA;EACA;;;;A4CXF;ENeA;EAcA;EACA;EAGA;EACA;EAEA;EACA;EACA;EACQ;EAER;EAKA;EAKA;EACI;EACI;;AAhCR;EACE;;AAGF;EACE;;;AMtBF;ENgEA;EAEA;EACA;EAGA;EAEA;EACA;EACA;EACQ;EAKR;EAKA;EACI;EACI;;AAER;EAEE;EAEA;EACA;EACA;EAEA;EACA;EACA;EACQ;EAER;EAGA;EACI;EACI;;;;;AO9GV;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AtDqNI;EsDjNJ;IACE;;;;ACiBF;EnDmEI;;;AmD7DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmDrEJ;EnDmEI;;;AmD7DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmDrEJ;EnDmEI;;;AmD7DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmDrEJ;EnDmEI;;;AmD7DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmDrEJ;EnDmEI;;AJ4HA;EuD/LJ;InD0EM;;;;AmDpEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmD5EN;EnDmEI;;AJ4HA;EuD/LJ;InD0EM;;;;AmDpEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmD5EN;EnDmEI;;AJ4HA;EuD/LJ;InD0EM;;;;AmDpEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmD5EN;EnDmEI;;AJ4HA;EuD/LJ;InD0EM;;;;AmDpEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmD5EN;EnDmEI;;AJ4HA;EuD/LJ;InD0EM;;;;AmDpEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmD5EN;EnDmEI;;AJ4HA;EuD/LJ;InD0EM;;;;AmDpEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmD5EN;EnDmEI;;;AmD7DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmDrEJ;EnDmEI;;;AmD7DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmDrEJ;EnDmEI;;;AmD7DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmDrEJ;EnDmEI;;;AmD7DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmDrEJ;EnDmEI;;AJ4HA;EuD/LJ;InD0EM;;;;AmDpEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmD5EN;EnDmEI;;AJ4HA;EuD/LJ;InD0EM;;;;AmDpEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmD5EN;EnDmEI;;AJ4HA;EuD/LJ;InD0EM;;;;AmDpEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmD5EN;EnDmEI;;AJ4HA;EuD/LJ;InD0EM;;;;AmDpEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmD5EN;EnDmEI;;AJ4HA;EuD/LJ;InD0EM;;;;AmDpEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmD5EN;EnDmEI;;AJ4HA;EuD/LJ;InD0EM;;;;AmDpEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDhDN;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;;ACrEN;EACE;;;AAGF;EACE;;;AAGF;EACE;;;;ACLA;E9DsIE,WAJc;EAKd,aAJY;;AK2FV;EyD9NJ;I9D+II,WAbY;IAcZ,aAbU;;;AK2FV;EyD9NJ;I9D0II,WATQ;IAUR,aARU;;;;A8DnId;E9DsIE,WAJc;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","file":"base.css"} +{"version":3,"sourceRoot":"","sources":["../../../node_modules/govuk-frontend/dist/govuk/core/_govuk-frontend-properties.scss","../../../node_modules/govuk-frontend/dist/govuk/core/_links.scss","../../../node_modules/govuk-frontend/dist/govuk/helpers/_typography.scss","../../../node_modules/govuk-frontend/dist/govuk/settings/_typography-font.scss","../../../node_modules/govuk-frontend/dist/govuk/helpers/_links.scss","../../../node_modules/govuk-frontend/dist/govuk/settings/_links.scss","../../../node_modules/govuk-frontend/dist/govuk/helpers/_font-faces.scss","../../../node_modules/govuk-frontend/dist/govuk/vendor/_sass-mq.scss","../../../node_modules/govuk-frontend/dist/govuk/helpers/_focused.scss","../../../node_modules/govuk-frontend/dist/govuk/settings/_colours-applied.scss","../../../node_modules/govuk-frontend/dist/govuk/core/_lists.scss","../../../node_modules/govuk-frontend/dist/govuk/helpers/_spacing.scss","../../../node_modules/govuk-frontend/dist/govuk/core/_typography.scss","../../../node_modules/govuk-frontend/dist/govuk/core/_section-break.scss","../../../node_modules/govuk-frontend/dist/govuk/objects/_button-group.scss","../../../node_modules/govuk-frontend/dist/govuk/objects/_form-group.scss","../../../node_modules/govuk-frontend/dist/govuk/helpers/_clearfix.scss","../../../node_modules/govuk-frontend/dist/govuk/objects/_grid.scss","../../../node_modules/govuk-frontend/dist/govuk/helpers/_grid.scss","../../../node_modules/govuk-frontend/dist/govuk/objects/_main-wrapper.scss","../../../node_modules/govuk-frontend/dist/govuk/objects/_template.scss","../../../node_modules/govuk-frontend/dist/govuk/objects/_width-container.scss","../../../node_modules/govuk-frontend/dist/govuk/settings/_measurements.scss","../../../node_modules/govuk-frontend/dist/govuk/components/accordion/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/back-link/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/breadcrumbs/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/button/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/error-message/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/hint/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/label/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/textarea/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/character-count/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/fieldset/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/checkboxes/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/cookie-banner/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/input/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/date-input/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/details/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/helpers/_shape-arrow.scss","../../../node_modules/govuk-frontend/dist/govuk/components/error-summary/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/exit-this-page/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/file-upload/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/footer/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/helpers/_device-pixels.scss","../../../node_modules/govuk-frontend/dist/govuk/components/header/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/inset-text/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/notification-banner/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/pagination/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/panel/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/tag/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/phase-banner/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/radios/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/select/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/skip-link/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/helpers/_visually-hidden.scss","../../../node_modules/govuk-frontend/dist/govuk/components/summary-list/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/table/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/tabs/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/task-list/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/components/warning-text/_index.scss","../../../node_modules/govuk-frontend/dist/govuk/utilities/_visually-hidden.scss","../../../node_modules/govuk-frontend/dist/govuk/overrides/_display.scss","../../../node_modules/govuk-frontend/dist/govuk/overrides/_spacing.scss","../../../node_modules/govuk-frontend/dist/govuk/overrides/_text-align.scss","../../../node_modules/govuk-frontend/dist/govuk/overrides/_typography.scss","../../../node_modules/govuk-frontend/dist/govuk/overrides/_width.scss","../../../node_modules/@ministryofjustice/frontend/moj/settings/_assets.scss","../../../node_modules/@ministryofjustice/frontend/moj/settings/_measurements.scss","../../../node_modules/@ministryofjustice/frontend/moj/settings/_colours.scss","../../../node_modules/@ministryofjustice/frontend/moj/objects/_filter-layout.scss","../../../node_modules/@ministryofjustice/frontend/moj/objects/_scrollable-pane.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/action-bar/_action-bar.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/add-another/_add-another.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/badge/_badge.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/banner/_banner.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/button-menu/_button-menu.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/cookie-banner/_cookie-banner.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/currency-input/_currency-input.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/filter/_filter.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/header/_header.scss","../../../node_modules/@ministryofjustice/frontend/moj/objects/_width-container.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/identity-bar/_identity-bar.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/messages/_messages.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/multi-file-upload/_multi-file-upload.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/multi-select/_multi-select.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/notification-badge/_notification-badge.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/organisation-switcher/_organisation-switcher.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/page-header-actions/_page-header-actions.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/pagination/_pagination.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/password-reveal/_password-reveal.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/primary-navigation/_primary-navigation.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/progress-bar/_progress-bar.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/rich-text-editor/_rich-text-editor.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/search-toggle/search-toggle.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/search/_search.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/side-navigation/_side-navigation.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/sortable-table/_sortable-table.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/sub-navigation/_sub-navigation.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/tag/_tag.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/task-list/_task-list.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/timeline/_timeline.scss","../../../node_modules/@ministryofjustice/frontend/moj/components/ticket-panel/_ticket-panel.scss","../../../node_modules/@ministryofjustice/frontend/moj/utilities/_hidden.scss","../../../node_modules/@ministryofjustice/frontend/moj/helpers/_hidden.scss","../../../node_modules/@ministryofjustice/frontend/moj/utilities/_width-container.scss"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;EAGE;EAIE;EAAA;EAAA;;;;ACNF;ECcA,aCFkB;EDGlB;EACA;EEaA;EAGE,2BChB6B;EDoB7B,uBCP0B;;ACdxB;AACA;EACE;EACA;EACA;EACA,KACE;EAEF;;AAGF;EACE;EACA;EACA;EACA,KACE;EAEF;;ACkMA;ENnON;ICyBE,aCHsB;;;ACTxB;EAqCE,2BCLmC;EDQnC;EACQ;EACR;EACQ;;AAvCV;EIFA;EACA,OC4DwB;ED3DxB,kBCiDmB;EDhDnB,YACE;EAIF;EAIA;EACQ;;AJgDR;EACE,OKuDgB;;ALpDlB;EACE,OK0DwB;;ALvD1B;EACE,OK6DsB;;AL1DxB;EACE,OKgEuB;;AL3DzB;EACE,OKnBsB;;AFuJlB;EH+HF;IACE;IACA;IAKA;;;;AA3KN;EAEE,OKxI0B;;AL2I5B;EAEE,OKhLgB;;ALqLlB;EACE,OK/HsB;;;ALoJxB;EF5LA,OOfkB;;AF8MZ;EHHN;IFzLE,OOQsB;;;ALwLxB;EAEI;;AAIJ;EFzMA,OOfkB;;AF8MZ;EHUN;IFtME,OOQsB;;;;ALqNxB;EAEE;;AAKF;EAEE;;AAGF;EACE,OKrMsB;;;ALoQxB;EACE;;;AAvCF;EACE,OKvKgB;;AL0KlB;EACE,OK3KgB;;AL8KlB;EACE,OKjKsB;;ALoKxB;EACE,OK9JuB;;ALmKzB;EACE,OKjPsB;;;ARzCxB;EGqVA;EAGA;EAGA;;AAEA;EIvVA;EACA,YACE;;;;AE3CF;ERcA,aCFkB;EDGlB;EACA;EAkCA;EAyKI,WAJc;EAKd,aAJuB;EApL3B,OOfkB;EClBhB;ECsGI;EDpGJ;EACA;;AH6NI;EGnON;IRyBE,aCHsB;;;AI6MlB;EGnON;IRoOM,WAbY;IAcZ,aAbqB;;;AKWrB;EGnON;IR+NM,WATQ;IAUR,aARqB;;;AKWrB;EGnON;IRuCE,OOQsB;;;AFoLlB;EGnON;ICgHQ;;;ADvGN;EACE;;;AAIJ;EAIE;;;AAOF;EACE;EACA;;;AAGF;EACE;EACA;;;AAGF;AAAA;EAEE;;AH8LI;EGhMN;AAAA;IAKI;;;;AAIJ;EACE;;AHsLI;EGvLN;IAII;;;;;AE9CJ;EVkCA,OOfkB;EPPlB,aCFkB;EDGlB;EACA;EA4CA;EA+JI,WAJc;EAKd,aAJuB;EUlNzB;EAEA;EDiGI;;AJ0HA;EKjON;IVqCE,OOQsB;;;AFoLlB;EKjON;IVuBE,aCHsB;;;AI6MlB;EKjON;IVkOM,WAbY;IAcZ,aAbqB;;;AKWrB;EKjON;IV6NM,WATQ;IAUR,aARqB;;;AKWrB;EKjON;ID8GQ;;;;AChGR;EVoBA,OOfkB;EPPlB,aCFkB;EDGlB;EACA;EA4CA;EA+JI,WAJc;EAKd,aAJuB;EUpMzB;EAEA;EDmFI;;AJ0HA;EKnNN;IVuBE,OOQsB;;;AFoLlB;EKnNN;IVSE,aCHsB;;;AI6MlB;EKnNN;IVoNM,WAbY;IAcZ,aAbqB;;;AKWrB;EKnNN;IV+MM,WATQ;IAUR,aARqB;;;AKWrB;EKnNN;IDgGQ;;;;AClFR;EVMA,OOfkB;EPPlB,aCFkB;EDGlB;EACA;EA4CA;EA+JI,WAJc;EAKd,aAJuB;EUtLzB;EAEA;EDqEI;;AJ0HA;EKrMN;IVSE,OOQsB;;;AFoLlB;EKrMN;IVLE,aCHsB;;;AI6MlB;EKrMN;IVsMM,WAbY;IAcZ,aAbqB;;;AKWrB;EKrMN;IViMM,WATQ;IAUR,aARqB;;;AKWrB;EKrMN;IDkFQ;;;;ACpER;EVRA,OOfkB;EPPlB,aCFkB;EDGlB;EACA;EA4CA;EA+JI,WAJc;EAKd,aAJuB;EUxKzB;EAEA;EDuDI;;AJ0HA;EKvLN;IVLE,OOQsB;;;AFoLlB;EKvLN;IVnBE,aCHsB;;;AI6MlB;EKvLN;IVwLM,WAbY;IAcZ,aAbqB;;;AKWrB;EKvLN;IVmLM,WATQ;IAUR,aARqB;;;AKWrB;EKvLN;IDoEQ;;;;ACpDR;EV9CA,aCFkB;EDGlB;EACA;EAkCA;EAyKI,WAJc;EAKd,aAJuB;EUzJzB;EAEA;EAEA,OHX0B;;AF2KtB;EKvKN;IVnCE,aCHsB;;;AI6MlB;EKvKN;IVwKM,WAbY;IAcZ,aAbqB;;;AKWrB;EKvKN;IVmKM,WATQ;IAUR,aARqB;;;;AUlJ3B;EVxDA,aCFkB;EDGlB;EACA;EAkCA;EAyKI,WAJc;EAKd,aAJuB;EU/IzB;EAEA;EACA,OHpB0B;;AF2KtB;EK7JN;IV7CE,aCHsB;;;AI6MlB;EK7JN;IV8JM,WAbY;IAcZ,aAbqB;;;AKWrB;EK7JN;IVyJM,WATQ;IAUR,aARqB;;;AKWrB;EK7JN;IASI;;;;AAIJ;EVrEA,aCFkB;EDGlB;EACA;EAkCA;EAyKI,WAJc;EAKd,aAJuB;EUlIzB;EAEA,OHhC0B;;AF2KtB;EKhJN;IV1DE,aCHsB;;;AI6MlB;EKhJN;IViJM,WAbY;IAcZ,aAbqB;;;AKWrB;EKhJN;IV4IM,WATQ;IAUR,aARqB;;;;AU3H3B;EVzDA,OOfkB;EPPlB,aCFkB;EDGlB;EACA;EAkCA;EAyKI,WAJc;EAKd,aAJuB;EUvHzB;EDQI;;AJ0HA;EKtIN;IVtDE,OOQsB;;;AFoLlB;EKtIN;IVpEE,aCHsB;;;AI6MlB;EKtIN;IVuIM,WAbY;IAcZ,aAbqB;;;AKWrB;EKtIN;IVkIM,WATQ;IAUR,aARqB;;;AKWrB;EKtIN;IDmBQ;;;;ACPR;EVrEA,OOfkB;EPPlB,aCFkB;EDGlB;EACA;EAkCA;EAyKI,WAJc;EAKd,aAJuB;EU3GzB;EDJI;;AJ0HA;EK1HN;IVlEE,OOQsB;;;AFoLlB;EK1HN;IVhFE,aCHsB;;;AI6MlB;EK1HN;IV2HM,WAbY;IAcZ,aAbqB;;;AKWrB;EK1HN;IVsHM,WATQ;IAUR,aARqB;;;AKWrB;EK1HN;IDOQ;;;;ACKR;EVjFA,OOfkB;EPPlB,aCFkB;EDGlB;EACA;EAkCA;EAyKI,WAJc;EAKd,aAJuB;EU/FzB;EDhBI;;AJ0HA;EK9GN;IV9EE,OOQsB;;;AFoLlB;EK9GN;IV5FE,aCHsB;;;AI6MlB;EK9GN;IV+GM,WAbY;IAcZ,aAbqB;;;AKWrB;EK9GN;IV0GM,WATQ;IAUR,aARqB;;;AKWrB;EK9GN;IDLQ;;;;ACkBR;EV9FA,OOfkB;EPPlB,aCFkB;EDGlB;EACA;EAkCA;EAyKI,WAJc;EAKd,aAJuB;EUlFzB;ED7BI;;AJ0HA;EKjGN;IV3FE,OOQsB;;;AFoLlB;EKjGN;IVzGE,aCHsB;;;AI6MlB;EKjGN;IVkGM,WAbY;IAcZ,aAbqB;;;AKWrB;EKjGN;IV6FM,WATQ;IAUR,aARqB;;;AKWrB;EKjGN;IDlBQ;;;;AC+CR;EACE;;ALmEI;EKpEN;IAII;;;;AAIJ;AAAA;AAAA;ED9DM;;AJ0HA;EK5DN;AAAA;AAAA;IDvDQ;;;;AC6DR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAME;;ALgDI;EKtDN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;IASI;;;;;ACtLJ;EACE;EACA;;;AASF;EF8FM;EAAA;;AJ0HA;EMxNN;IFqGQ;;;AJmHF;EMxNN;IFqGQ;;;;AE5FR;EFqFM;EAAA;;AJ0HA;EM/MN;IF4FQ;;;AJmHF;EM/MN;IF4FQ;;;;AEnFR;EF4EM;EAAA;;AJ0HA;EMtMN;IFmFQ;;;AJmHF;EMtMN;IFmFQ;;;;AExER;EACE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/BF;EH+FM;EG3EJ;EACA;EACA;;APmMI;EOzNN;IHsGQ;;;AGzEN;EZzBF,aCFkB;EDGlB;EACA;EAkCA;EAyKI,WAJc;EAKd,aAJuB;EY/KvB;EAGA;EACA,YA3Ba;EA4Bb;EACA;;APoLE;EO5LJ;IZdA,aCHsB;;;AI6MlB;EO5LJ;IZ6LI,WAbY;IAcZ,aAbqB;;;AKWrB;EO5LJ;IZwLI,WATQ;IAUR,aARqB;;;AYpKzB;EACE;;AP8KE;EOzNN;IAkDI;IAEA;IACA;IACA;;EAEA;AAAA;IAEE,cAzDa;;EA4Df;IACE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtEN;EJuGM;;AKjGN;EACE;EACA;EACA;;ATwNI;EQjON;IJ8GQ;;;AI1GN;EACE;;;AAIJ;EACE;EACA;;AAEA;EAEE;EACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AEhBJ;EAEE;EACA;;ADGF;EACE;EACA;EACA;;;ACFA;ECyCF;EAEE;EAEF;;AX6KM;EU1NJ;IC+CA;IACA,OAR2C;;;;ADxC3C;ECyCF;EAEE;EAEF;;AX6KM;EU1NJ;IC+CA;IACA,OAR2C;;;;ADxC3C;ECyCF;EAEE;EAEF;;AX6KM;EU1NJ;IC+CA;IACA,OAR2C;;;;ADxC3C;ECyCF;EAEE;EAEF;;AX6KM;EU1NJ;IC+CA;IACA,OAR2C;;;;ADxC3C;ECyCF;EAEE;EAEF;;AX6KM;EU1NJ;IC+CA;IACA,OAR2C;;;;ADxC3C;ECyCF;EAEE;EAEF;;AX6KM;EU1NJ;IC+CA;IACA,OAR2C;;;;AD/B3C;ECgCF;EAIA;;AX6KM;EUjNJ;ICsCA;IACA,OAR2C;;;;AD/B3C;ECgCF;EAIA;;AX6KM;EUjNJ;ICsCA;IACA,OAR2C;;;;AD/B3C;ECgCF;EAIA;;AX6KM;EUjNJ;ICsCA;IACA,OAR2C;;;;AD/B3C;ECgCF;EAIA;;AX6KM;EUjNJ;ICsCA;IACA,OAR2C;;;;AD/B3C;ECgCF;EAIA;;AX6KM;EUjNJ;ICsCA;IACA,OAR2C;;;;AD/B3C;ECgCF;EAIA;;AX6KM;EUjNJ;ICsCA;IACA,OAR2C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1B7C;EAIE;EACA;EACA;;AZsMI;EY5MN;IAYI;IACA;;;;AAWJ;AAAA;ER0DM;;AJ0HA;EYpLN;AAAA;IRiEQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AS7GR;EAGE,kBXyB6B;EWrB7B;EACG;EACK;;AAcR;EAvBF;IAwBI;;EAEA;IACE;;;AbqMA;EahON;IAkCI;;;;AAKJ;EAGE;EAEA,kBXT2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AYgC7B;EAlDA,WCRiB;EDWjB,cC2BkB;ED1BlB,aC0BkB;;ADvBlB;EA2CA;IArCE;IACA;;;AdiMI;Ec7JN;IA/BE,cCIW;IDHX,aCGW;;EDAX;IA2BF;MArBI;MACA;;;;AdiLE;Ec7JN;IAbE;IACA;;EAIA;IAQF;MAPI;MACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AE3DJ;EZoGM;;AJ0HA;EgB9NN;IZ2GQ;;;;AYvGR;EACE;;;AAGF;EAEE;EACA;EAEA;EACA;;;AAGF;ErBRA,aCFkB;EDGlB;EACA;EA4CA;EA+JI,WAJc;EAKd,aAJuB;EApL3B,OOfkB;EcKhB;EACA;EACA;;AhBuMI;EgB7MN;IrBGE,aCHs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;;;AKWrB;EuCnON;InCgHQ;;;AmCxGN;EACE;;;AAIJ;EACE;EAGA;;AvCkNI;EuCtNN;IAOI;;;;AAIJ;E5CmMI,WAJc;EAKd,aAJuB;EA5J3B;E4C/BE;EACA;EACA;;AvCoMI;EuC3MN;I5C4MM,WAbY;IAcZ,aAbqB;;;AKWrB;EuC3MN;I5CuMM,WATQ;IAUR,aARqB;;;;A4CtL3B;E5CEA,OOfkB;EqCgBhB;EAEA,kBrCD2B;;AF6LvB;EuCjMN;I5CKE,OOQsB;;;AFoLlB;EuCjMN;IAQI,SAPe;;;AAYjB;EAGE;EAOA;;AAGF;EACE;;;AAIJ;E5C0JI,WAJc;EAKd,aAJuB;EA5J3B;E4CSE;EAEA;;AvC4JI;EuClKN;I5CmKM,WAbY;IAcZ,aAbqB;;;AKWrB;EuClKN;I5C8JM,WATQ;IAUR,aARqB;;;;A4C9I3B;E5C5DA,aCFkB;EDGlB;EACA;EEaA;EAGE,2BChB6B;EDoB7B,uBCP0B;;AEsMtB;EuCzJN;I5CjDE,aCHsB;;;ACTxB;EAqCE,2BCLmC;EDQnC;EACQ;EACR;EACQ;;AAvCV;EIFA;EACA,OC4DwB;ED3DxB,kBCiDmB;EDhDnB,YACE;EAIF;EAIA;EACQ;;AJ8QR;EACE,OKvKgB;;AL0KlB;EACE,OK3KgB;;AL8KlB;EACE,OKjKsB;;ALoKxB;EACE,OK9JuB;;ALmKzB;EACE,OKjPsB;;;AqCGxB;EACE,crCcmB;EqCZnB,kBrCYmB;;AL2DrB;EAEE,OK7DmB;;ALgErB;EACE;;AAGF;EACE,OKrEmB;;AL0ErB;EACE,OK7FsB;;;;AsC1ExB;EpCuGM;EoCrGJ;EACA;EACA;EACA;;AxC4NI;EwCjON;IpC8GQ;;;AJmHF;EwCjON;IAQI;IACA;;;;AAIJ;EACE;EACA;EACA;;;AAGF;AAAA;AAAA;E7CPA,aCFkB;EDGlB;EACA;EAkCA;EAyKI,WAJc;EAKd,aAJuB;E6C/LzB;EACA;EACA;EACA;EACA;EACA;;AxCqMI;EwC9MN;AAAA;AAAA;I7CIE,aCHsB;;;AI6MlB;EwC9MN;AAAA;AAAA;I7C+MM,WAbY;IAcZ,aAbqB;;;AKWrB;EwC9MN;AAAA;AAAA;I7C0MM,WATQ;IA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R,aARqB;;;;AsDlK3B;EtDqKI,WAJc;EAKd,aAJuB;;AKWrB;EiD7KN;ItD8KM,WAbY;IAcZ,aAbqB;;;AKWrB;EiD7KN;ItDyKM,WATQ;IAUR,aARqB;;;;AsD9J3B;EtDiKI,WAJc;EAKd,aAJuB;;AKWrB;EiDzKN;ItD0KM,WAbY;IAcZ,aAbqB;;;AKWrB;EiDzKN;ItDqKM,WATQ;IAUR,aARqB;;;;;AuDxN3B;E9CyGM;EAAA;ET3FN,aCFkB;EDGlB;EACA;EAkCA;EAyKI,WAJc;EAKd,aAJuB;;AKWrB;EkDnON;I9CgHQ;;;AJmHF;EkDnON;IvDyBE,aCHsB;;;AI6MlB;EkDnON;IvDoOM,WAbY;IAcZ,aAbqB;;;AKWrB;EkDnON;IvD+NM,WATQ;IAUR,aARqB;;;;AuDlN3B;EvDqNI,WAJc;EAKd,aAJuB;EAtK3B;EAdA,OOfkB;EgDThB;;AlDuNI;EkD7NN;IvD8NM,WAbY;IAcZ,aAbqB;;;AKWrB;EkD7NN;IvDyNM,WATQ;IAUR,aARqB;;;AKWrB;EkD7NN;IvDiCE,OOQsB;;;;AgDhCxB;EACE;EACA;EACA;E9CuFI;;AJ0HA;EkDpNN;I9CiGQ;;;;A8C1FR;EACE;;AAEA;EvDWF,OOfkB;EgDMd;EACA;EACA;;AlDsME;EkD1MJ;IvDcA,OOQsB;;;;AgDdxB;EvDnBA,aCFkB;EDGlB;EACA;EEaA;EAGE,2BChB6B;EDoB7B,uBCP0B;EoDQ1B;EACA;;AlD6LI;EkDlMN;IvDRE,aCHsB;;;ACTxB;EAqCE,2BCLmC;EDQnC;EACQ;EACR;EACQ;;AAvCV;EIFA;EACA,OC4DwB;ED3DxB,kBCiDmB;EDhDnB,YACE;EAIF;EAIA;EACQ;;AJgDR;EACE,OKuDgB;;ALpDlB;EACE,OK0DwB;;ALvD1B;EACE,OK6DsB;;AL1DxB;EACE,OKgEuB;;AL3DzB;EACE,OKnBsB;;;AgDnCxB;E9CgEM;;AJ0HA;EkD1LN;I9CuEQ;;;;AJmHF;EkDnLF;IAEE;IACA;;EzC3CN;IACE;IACA;IACA;;EyC2CE;IACE;;EAGF;IACE;IAEA;IACA;IACA;IACA;IAEA;IACA;IACA;;EAEA;IACE;;EAIJ;IAGE;IAEA;IAGA;IACA;IACA;IACA;IACA;IAEA;IACA;IAEA,kBhDtDuB;;EgDwDvB;IACE;;EAIJ;IAGE;;ErD0HN;IF5LA,OOfkB;;;AF8MZ;EHHN;IFzLE,OOQsB;;;AFoLlB;EHIN;IAEI;;EAIJ;IFzMA,OOfkB;;;AF8MZ;EHUN;IFtME,OOQsB;;;AFoLlB;EkD3HA;IACE;IACA;IACA;IACA;IACA;IACA;;EAIJ;I9CTE;I8CWA;IACA;IACA;;EAEA;IACE;;EAIJ;IACE;;;;;;;AC1HN;ExDUA,aCFkB;EDGlB;EACA;EAkCA;EAyKI,WAJc;EAKd,aAJuB;EwDlNzB;E/CmGI;E+CjGJ;EACA;;AnD0NI;EmD/NN;IxDqBE,aCHsB;;;AI6MlB;EmD/NN;IxDgOM,WAbY;IAcZ,aAbqB;;;AKWrB;EmD/NN;IxD2NM,WATQ;IAUR,aARqB;;;AKWrB;EmD/NN;I/C4GQ;;;;A+C/FR;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAMF;EACE,YAjC6B;;;AAoC/B;EACE;EACA;ExDJF,OOfkB;;AF8MZ;EmD7LN;IxDCE,OOQsB;;;;AiDHxB;EACE;EACA;EACA;EACA;ExDZF,OOfkB;;AF8MZ;EmDvLN;IxDLE,OOQsB;;;;AiDKxB;EACE,OjDG0B;;;AiDG5B;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA,OjDf0B;;;;;;;;AkDxD5B;EzDcA,aCFkB;EDGlB;EACA;EAkCA;EAyKI,WAJc;EAKd,aAJuB;ES/GrB;EgDtGJ;EACA;;ApD+NI;EoDnON;IzDyBE,aCHsB;;;AI6MlB;EoDnON;IzDoOM,WAbY;IAcZ,aAbqB;;;AKWrB;EoDnON;IzD+NM,WATQ;IAUR,aARqB;;;AKWrB;EoDnON;IhDgHQ;;;;AgDzGR;EzDqDA;EyDjDE;EAEA;EAEA;EACA;EAEA;EACA;EACA;EAQA;EACA;EAEA;EACA;EAEA;EACA;EAEA;EAIA;EACI;EACI;EAIR;;ApDoLI;EoD5NN;IAgBI;;;AA0BF;EA1CF;IA2CI;IACA;IACA;;;;AAIJ;EzDpBA,OOfkB;EkDqChB;EACA;;ApDwKI;EoD3KN;IzDjBE,OOQsB;;;;;;AOvCxB;EACE;EACA;EACA;;;;A4CXF;ENeA;EAcA;EACA;EAGA;EACA;EAEA;EACA;EACA;EACQ;EAER;EAKA;EAKA;EACI;EACI;;AAhCR;EACE;;AAGF;EACE;;;AMtBF;ENgEA;EAEA;EACA;EAGA;EAEA;EACA;EACA;EACQ;EAKR;EAKA;EACI;EACI;;AAER;EAEE;EAEA;EACA;EACA;EAEA;EACA;EACA;EACQ;EAER;EAGA;EACI;EACI;;;;;AO9GV;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AtDqNI;EsDjNJ;IACE;;;;ACiBF;EnDmEI;;;AmD7DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmDrEJ;EnDmEI;;;AmD7DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmDrEJ;EnDmEI;;;AmD7DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmDrEJ;EnDmEI;;;AmD7DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmDrEJ;EnDmEI;;AJ4HA;EuD/LJ;InD0EM;;;;AmDpEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmD5EN;EnDmEI;;AJ4HA;EuD/LJ;InD0EM;;;;AmDpEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmD5EN;EnDmEI;;AJ4HA;EuD/LJ;InD0EM;;;;AmDpEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmD5EN;EnDmEI;;AJ4HA;EuD/LJ;InD0EM;;;;AmDpEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmD5EN;EnDmEI;;AJ4HA;EuD/LJ;InD0EM;;;;AmDpEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmD5EN;EnDmEI;;AJ4HA;EuD/LJ;InD0EM;;;;AmDpEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmD5EN;EnDmEI;;;AmD7DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmDrEJ;EnDmEI;;;AmD7DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmDrEJ;EnDmEI;;;AmD7DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmDrEJ;EnDmEI;;;AmD7DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmD/DF;EnD+DE;;;AmDrEJ;EnDmEI;;AJ4HA;EuD/LJ;InD0EM;;;;AmDpEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmD5EN;EnDmEI;;AJ4HA;EuD/LJ;InD0EM;;;;AmDpEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmD5EN;EnDmEI;;AJ4HA;EuD/LJ;InD0EM;;;;AmDpEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmD5EN;EnDmEI;;AJ4HA;EuD/LJ;InD0EM;;;;AmDpEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmD5EN;EnDmEI;;AJ4HA;EuD/LJ;InD0EM;;;;AmDpEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmD5EN;EnDmEI;;AJ4HA;EuD/LJ;InD0EM;;;;AmDpEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDtEJ;EnD+DE;;AJ0HA;EuDzLF;InDsEI;;;;AmDhDN;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;AANJ;EACE;;;AAIA;EACE;;;AADF;EACE;;;AADF;EACE;;;AADF;EACE;;;;ACrEN;EACE;;;AAGF;EACE;;;AAGF;EACE;;;;ACHA;E9DoNE,WAJc;EAKd,aAJuB;;AKWrB;EyD5NJ;I9D6NI,WAbY;IAcZ,aAbqB;;;AKWrB;EyD5NJ;I9DwNI,WATQ;IAUR,aARqB;;;;A8DjNzB;E9DoNE,WAJc;EAKd,aAJuB;;AKWrB;EyD5NJ;I9D6NI,WAbY;IAcZ,aAbqB;;;AKWrB;EyD5NJ;I9DwNI,WATQ;IAUR,aARqB;;;;A8DjNzB;E9DoNE,WAJc;EAKd,aAJuB;;AKWrB;EyD5NJ;I9D6NI,WAbY;IAcZ,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","file":"base.css"} \ No newline at end of file diff --git a/static/assets/css/search.css.map b/static/assets/css/search.css.map index 273f05e0..554f4faf 100644 --- a/static/assets/css/search.css.map +++ b/static/assets/css/search.css.map @@ -1 +1 @@ -{"version":3,"sourceRoot":"","sources":["../../../scss/search.scss"],"names":[],"mappings":"AAAA;EACI;;;AAEJ;EACI;;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACI;EACA;;;AAGJ;EACI;EACA","file":"search.css"} +{"version":3,"sourceRoot":"","sources":["../../../scss/search.scss"],"names":[],"mappings":"AAAA;EACI;;;AAEJ;EACI;;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACI;EACA;;;AAGJ;EACI;EACA","file":"search.css"} \ No newline at end of file diff --git a/static/assets/images/favicon.ico b/static/assets/images/favicon.ico index 28004dd3f813ba4b16b4f72023a94603801ee813..20129a0bbab925707308d7681e4470f62a010b51 100644 GIT binary patch literal 14254 zcmeI0ziVVw6vt0+6|-0b3+spqTLxFH18O0Q5Lg9KSR?ocq_7pHv6Q5+m8215n>6I5enMr2Eci_%_@7{C1=jT1|y@}Y07h-2;C+BE&lPW~T1ub)NSPXqq^H0jHT zcOHKG?BV;d{l)hmKl}Z+lUJTUdGyO4KmHo=`41ocl&p_W?w@VHd$#@c(-#k(K01l` z?B&UKAb#-LSKlzlho5v)yz%zUyd}GDZkPKdPP;kwa}dvt>I$a0H;yp|8&d;$E~j~3 zr+I$6kv(FtZOBL-EHGQ^JkNi&iaKTAm}U>D4)*#8%vSx`ulisXUI(*9KXJnkM)t`r z4^o{ddU|@=?Q0!g*4TqbMBKp;UP~SodvYgxiMQKNF0*e-O?U12g%=sgg9WwZ z0Q(vFEa-IN6ZSKs6HNBGMhAmy*4RUrWbhwbzyd=&va6isyW&YqOF~8j9z*1NS_6Xt zCNwJs;=%5G9(Ml72K;0l|KL-u(Jz15g9ly+S!@D}bqLwgZ{6$ME6%LTChCZLc&H=p zMO?F{8ql8W0uvj=Bc1bR>F~ILfsZ~MS9wHs9{#+2;)@?GXGd7@B7>~fT4v;^Rfw5; za_aeL!GQ-EWNVmx81OrB-^U9sab|Gc$2SBMo1JF)P3}cp_vs&k35L#!&L4F}-7?%y z>DDa$@Q7bENsO>jnBr}j-A|ooQjEbYCU~;#Fin_ zeINgAtm_$v4P4)bj#-%0x%!OP|16ntFYY`~4KYua^%4J5?BzJjv8Deh-preS(OGF9UkV=&ghSOaUT0lu?%-{zf!_YuDPW_`ac+Oxm}Tkk*UT!kKgpVND#&wOL? zZL`SmZ#Bo%^(x*U`JZcDCdVJje(iTfr0td6$oi))4p*x@+Iv z>=AG2WQI@o<#)W+org6rAnh}w8$QLLjF0p7T~jL%|Dm7*dx!}=O}3G5XmW*ohAC(Fs3F19gq1@A(*=x0}l@Cm?;YXMH zCb=1^&vUBWg4b%xvV7{b(#?!bt+?fx5>Bf;eCPv*F+?}AH3Fwqzus>ghZBA7aT6u|AN#(OZ{oMIVo?0A+oUvAWOTL=@Wq&5; zC6#qhv;Qu7bj>zB+uT>Lq1xG{zMThu%lBEwTje!A@IFgTcz>Y728br INb8EgUlZ|}Qvd(} literal 6318 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 diff --git a/static/assets/images/favicon.svg b/static/assets/images/favicon.svg index d297513a..67d7ef91 100644 --- a/static/assets/images/favicon.svg +++ b/static/assets/images/favicon.svg @@ -1,4 +1 @@ - - - - + diff --git a/static/assets/images/govuk-icon-180.png b/static/assets/images/govuk-icon-180.png index c9f5978748e599ec5f1cb352c2c5c93ddbdddb26..7c33beba86ee3e6e00cd1183ef428a38fcc19d50 100644 GIT binary patch delta 1599 zcmV-F2Eh5gPQ?t68Gi!+000UT_5c6?05ecbR7DF64Dj&q|NsA_q@-6^ShKUUXJ=;` z8yiSTNh&HT!otGQ(b0Bxc9fNsIXXJw;o*gbhQA}<1^@sB%}GQ-RCodG!2tmP0003X z{+~8P6#xJL0N_{0u9>Jgssd5CC=d#e<^7*_dNfU`WqO4qet%#8_s*W>2#4Af8w#$1 z#)gKgV6b5>=nns0-}q7H)dRz z;SEz>T(q{Z5PxwY!h+Rs0X*LDa2;m6F~fC;cq78ALbc9WxkE}VUavAR6p~p3oK2w` zU}T);7bfdK?1;)Rk|HfE$te9R@sAoYeIj4IEhpK??B}{_HQpNZ~Bo=XcMHgP5Cc4USwnOFnZ+)6Q z>ivH@_dtD`J-iStRDJ%>9!BHrc|}q|5I(FV>iJ;JI_Qm^4&Pr-4kEdIg5#{`=;R>Q z!<9}JI%2fCm2637-VBWzZyL>E;OF8t`+v#aE#1lw2o;?@UQY@M z7cSMKQA*$HB8gT_1M%X|Fg_t&?g8^C%Wx`&x3QE|< zhzHI(VfRaVEIplG*GM;~uA-a!^?xc_yJP9P?`rL+JNfD+I)rVE(&pU&(Y1(UT7g~H z#M&Zdd;jhrlo8K)OsTAgCoUt8tav8r+)cFJoPyd01eIR{`n}4|5#xHOOPYA0J1=zs zFa;ApU5`B-&yK;sQIg|VKm$x|rF6y$kg%Bc@tvvfOHm_$Pp}XVqA5DQMt@e}A{{;{ z!b0)@OD$!`G%~LF*YCf70>9eJuuT=pKm^QgKk+(C(G|a!jVqkPZo6=bt5dF z1f?XE$$I+ideTWi%`ku{d+WlT4 literal 10046 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 Ls?t@GCc*y?_KHxF diff --git a/static/assets/images/govuk-icon-192.png b/static/assets/images/govuk-icon-192.png index cf4acb73630ae8dd15763d843be07e299a635380..35e51d7a7f917b6bc933da6432618e43f85757bc 100644 GIT binary patch delta 1650 zcmV-&295c+4UP?vFMt34|M2keq@<*0XJ;B48?&>s!otFZhK4FCDt2~u(b3W2;o(S0 zNtBh9IXXJsjm)V400tIGL_t(|0qns64FCWD0WkWP*2De>000000FHF*oQZDZJPd@X z(M{`m|EK-C_Qq6V`)`^?Net|VW3f)qYAlKzQ9{w7=!9sjXn#5*1}lcnh{cMfGvct~ z=#+T;#nU;l5<%z0Nd%pgfSEuiBYMm9hY2$i{ei8IXAuA(O-#g?VIrOqfb$5LNzq`& z#021c0($-l_$T0>fHMlv88ca*Q-E;}GtQY43NTEh*8L=#lL_$L?a2&%!Tv-7LXlmu z?1)P^ivV}qmw!<5!8v#JhR%sTcUOhfnfh8>6Ob$4(-&fsffOBm5LRQse%qOoI;}pu zg>}#ytsfXz3_)`rLE9KA5VWJuprWJp5wwjVkB*5xgN%+W5wsUW=n3>0;0lSLy%<7I z{$v3fSLnU(>JJW~h8x-khmhG>#058$4_?HK4n7j_Nq=dycnt(g7p83?W8A=-oGV4o zO##rp&}(o33yC)h?DfJB@}_F&^}8)&!8m#WE?vif7_@AdR^nktr5Jr>{F=rE|LU%f zp+nqtZgO-;fM97jPH!T6pVqt4Mu(Iam$rg?6Jc9pEw#J*c#TFAf6y$nvxH>7J%>81o|ujs?zfSKUvlt^srMrR~pCD947=&zTA4B0ISV>V5)@{@bBfOsgt{{Mbm;|m?>n3n8O*kKy8jnpKt{>JANYs)u& zNi(hRsO@EjP;WAgZol+<{vcSxm}XFRw~sZ`gRqvElqW+htkrwFF!RfrnYP8f=|L8p zjeiD^quXmx#9!tHM}nJIzOIg*4i|T@wlzJ3KB!n+m|jBso!z%@zs(qqEo#DsbX?!V z+XbZK(}Cj?g7kI)9xKN?`s1X6761Mly2lZIyh`x)HK4F^?-h`q*WbJ0sUGCP^hjGJ z9c1A;F%7`ku)Ij#dC8sxWp8bPm<_8)@P9kg!^=+%*3olOevM?qTjw&7P++e&a`Lf7 zAz>1EQt#K*^VCjh)ZJD^YHMFR*|v5pHlWcg>|D)<8cT}t78rkO}e_tSSYj*K`THIHlC z$q6_lY@0vxSe3XVa|xj`!Zws9c{^fDxko_3mMC?ll_B5{NqeTeZ{Z}HkEo)$sgT1(p+J!Yu6*O5@od6y<0Wt;oGT|1`k(=*Jv6L@E)Crg| zQquZD>>Ec7*h^66F%ux8nN6K1;=iLd8$VetI@on1bNjl5IN)`zhnsJ^2%IQM8%2C(A1OMD&@-RxkNo$?1C#q zsyg`{W8mEiX*XG$uPu~}hc`b>?N)rIL4-YzQV!o4Ycc!>^I7&hR~USDZT8Zu{pnx! zuzTs!j6N0DI|mO*>ejt~-G4?ZTiQ8`)8p@{+r7DuJ6!40PSu4ei;XR2oEYx^I z4GZr|qJqISX&$XDr8v41S4y$7ri5$E%PzF)5Moq?>DO>kF@~UDc0rb7ER6=xN{swp wdvHJl004k6$o{GA@c| delta 1693 zcmV;O24eY+4Y&=EFMq`f|Nj~r8`06xv$L~yc6MiHXW`-Dl$Di8NlAr< zhNPsV@bK{Pi+7#?00uxwL_t(|0qnss0RR910WkWP7Q(wNHvj+t000000Dz8N^FVf- zRibbUXrda}|7zc}?kM0R+4Wz8r&KlHWCx}X>WHKcXu2PU4}Vy?A&xgZ-I2f>k?x4* z4MVpi@gE%BlbQbz=$`1ic@U6p>Om51<3pJiY!tc&nb}7}L=!J)A~HcS=i3N);DXV- zpmlKk;9dfde*(tyPrx@3kzN9Dso|Ky4~qF*050_frpiB5eJvox$O}5wYXKUU8jr5L zQq6^c8n$N0kblh;1;A3@Q=oXqp9-ki?yW>1`jL=dFQvZTWiA*LP_xBm&XyAa2A2AM znw-{F%_~)we~3A6r;RM}Q!&Od7(ZTwvh0ucs@{{qc}8cmjU)~2CLm#%&ThiAn+l@N1m20Pl9IZhVV|c z2luFXdmjYM5a}r3xaAq@f>19!+G2uNK3MwUOh96cY!t99Wl*)JPJn%YLxq|fz&xC%CRWysy4L|0f@jJy=EA!0ArNKLQN4eZt4fCAoIgWX<7)~Pn> zU&YP!g#&crg*s7JY*0%1_#fluSA9YBN~vJ!FMng0u{hj{h%NSQ71T(76)8%oZ0NtD zJ^%L5&CE)vBGdz`em}7q$yx00?{9kB!G8CuGDc_VBaE9~Wia=-0{Q()eu+AD6X|-`rBDDC z+kg0Bp|B{RPY}RlsLu^ZA3n`84ZH%=ixH`O)+tO^M%J!PNW$Gf_nNVI0PZ^5tLv-o zdLC*ydnG_!&n4IW=q^%S%hx?-8L%G&q-)*RlN^HpP|#N01p_@`!ELDcXPBf02}?!wYKdh!v;r< zEy4DZZt6IG+x&T6YNF0erLL9OH(d)hEV4yje)jR$l=6%nmMyDi*3whMTn{^0C(PKU z%|E$yqO^Uw5uh=IV?89W6#73zywuMEex8Vo96iU$9_6dmk`CEQ#1K^|Rh}mzJAdG0 zOYH(YCn#9+lnzOIePWJ?(i-6=IDT*_EpD2jK-6V-20Srt>MFoA)lp1bOl;EOR=bpP zix#D}y45dE$mhNs&L{xUCogN0%3g?HFFH!J;x+sx7qzX|#2ZE$+WcS+0 zh~Nl;0)&ycH;!5kT6^E93~5U`hJR0pZv^-?eFA1nOD;nf*ZodqyfPyn%UhZyEUINr z>-(1i!c+THh91^>Jbm^eg?ZWytYQ7DJZ!7GfWTZt6iRm^A028fUIGq$BeLEEIJ5mV zFZ$h9v8DC2O@M9xIrI`tKelC=+;PM57Ttvw=G_=uwvrZ(6N8#${*e}O`hOX438D#U zu}}YrGX?Fm>>jL+1*t3ocIx5Mv0kDq1(P8Hx?xsRLw)?7^8Tu71^C9sO`U5!TkTt& z9TC+U*Rw7|Lr|+j7_W(<-P4n62SVGnYi8@5=t$bP+D=5`?HV#}H%OTSswtv0~$@$Dww^jNf@E?FFX=P}}@an)}g z^TLB8-0TP=@}PcVY6D}fybad#fnqOC?FH>GU%2rY&yL_y*sV0Vazo8#e={UrNfze5 ziN;}9v%H}NY3+1#juLW7d_pQYNX*5xuL>;~wMwNCpkMna5)^kp1%Hv?hxDPy#KW0r zB$h{0X)K-xQ)n#lULJ%P9*m{II39|k(ab!QK%)^Jil*W4Tht|gA&DYjMN+EdoaO&m z0uUo2Q_k5dmGII8EAbP;M60*{CKmOMq90&ja000Q` nw_ag@3IG5A0000002W{h*=uyx&9v{{00000NkvXXu0mjfS2ic@ diff --git a/static/assets/images/govuk-icon-512.png b/static/assets/images/govuk-icon-512.png index e201301e48144a654a09722c0998e64add8ff691..f5eb6f46163fd37544c46888a1817da6b11cf40c 100644 GIT binary patch delta 4588 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 - - + \ No newline at end of file diff --git a/static/assets/images/govuk-opengraph-image.png b/static/assets/images/govuk-opengraph-image.png index 355284fbf6a87a1288920ee3c66c1bad9f8c9a40..4d0e312ffbcdf40193e029a094bc2e3c9af55bcd 100644 GIT binary patch literal 8677 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 literal 15380 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 F{}(>uVqyRQ diff --git a/static/assets/js/govuk-frontend-5.0.0.min.js b/static/assets/js/govuk-frontend-5.0.0.min.js deleted file mode 100644 index 94f82e48..00000000 --- a/static/assets/js/govuk-frontend-5.0.0.min.js +++ /dev/null @@ -1 +0,0 @@ -const version="5.0.0";function mergeConfigs(...t){function flattenObject(t){const e={};return function flattenLoop(t,i){for(const[n,s]of Object.entries(t)){const t=i?`${i}.${n}`:n;s&&"object"==typeof s?flattenLoop(s,t):e[t]=s}}(t),e}const e={};for(const i of t){const t=flattenObject(i);for(const[i,n]of Object.entries(t))e[i]=n}return e}function extractConfigByNamespace(t,e){const i={};for(const[n,s]of Object.entries(t)){const t=n.split(".");if(t[0]===e){t.length>1&&t.shift();i[t.join(".")]=s}}return i}function getFragmentFromUrl(t){if(t.includes("#"))return t.split("#").pop()}function isSupported(t=document.body){return!!t&&t.classList.contains("govuk-frontend-supported")}function normaliseString(t){if("string"!=typeof t)return t;const e=t.trim();return"true"===e||"false"!==e&&(e.length>0&&isFinite(Number(e))?Number(e):t)}function normaliseDataset(t){const e={};for(const[i,n]of Object.entries(t))e[i]=normaliseString(n);return e}class GOVUKFrontendError extends Error{constructor(...t){super(...t),this.name="GOVUKFrontendError"}}class SupportError extends GOVUKFrontendError{constructor(t=document.body){const e="noModule"in HTMLScriptElement.prototype?'GOV.UK Frontend initialised without `` from template ` + +{% block scripts %} +{% endblock scripts %} \ No newline at end of file diff --git a/templates/partial/filter.html b/templates/partial/filter.html index 6ab6f185..f5a5b5fb 100644 --- a/templates/partial/filter.html +++ b/templates/partial/filter.html @@ -44,13 +44,27 @@

    Domain

    Domain -
    - {% for domain_option in form.domains %} -
    - {{ domain_option.tag}} - -
    - {% endfor %} +
    + + +
    +
    + +
    diff --git a/templates/search.html b/templates/search.html index 03436bea..358209be 100644 --- a/templates/search.html +++ b/templates/search.html @@ -33,3 +33,9 @@

    {{tot {% endblock content %} +{% block scripts %} + +{% endblock scripts %} \ No newline at end of file diff --git a/tests/javascript/jest-setup.js b/tests/javascript/jest-setup.js new file mode 100644 index 00000000..d0de870d --- /dev/null +++ b/tests/javascript/jest-setup.js @@ -0,0 +1 @@ +import "@testing-library/jest-dom"; diff --git a/tests/javascript/test_enhanced_search.js b/tests/javascript/test_enhanced_search.js new file mode 100644 index 00000000..4920b383 --- /dev/null +++ b/tests/javascript/test_enhanced_search.js @@ -0,0 +1,166 @@ +import { initDomainFilter } from "enhanced-search"; +import { expect, test } from "@jest/globals"; + +const widget_html = ` +
    + Domain +
    + + +
    +
    + + +
    +
    +`; + +let subdomainFilter; +let domainFilter; +const eventSpy = jest.fn(); + +describe("initialisation", () => { + beforeEach(() => { + document.body.innerHTML = widget_html; + subdomainFilter = document.querySelector("#subdomains-filter"); + initDomainFilter(); + }); + + test("subdomain select is disabled", () => { + expect(subdomainFilter).toBeDisabled(); + }); + + test("the only option is 'all subdomains'", () => { + expect(subdomainFilter).toHaveLength(1); + }); +}); + +describe("after selecting a domain", () => { + beforeEach(() => { + document.body.innerHTML = widget_html; + + subdomainFilter = document.querySelector("#subdomains-filter"); + domainFilter = document.querySelector("#domains-filter"); + + initDomainFilter(); + + // Listen to outgoing events + domainFilter.parentElement.addEventListener( + "domain-filter-updates", + eventSpy + ); + + // Emulate selecting a domain + domainFilter.value = "a"; + domainFilter.dispatchEvent(new Event("change")); + }); + + test("only the selected domain's options are available", () => { + const options = subdomainFilter.querySelectorAll("option"); + + const values = Array.from(options).map((el) => el.value); + + expect(values).toEqual(["*", "a1", "a2"]); + }); + + test("fires an event with the selected domain and null subdomain", () => { + expect(eventSpy.mock.calls[0][0].detail).toEqual({ + topLevelDomainValue: "a", + subdomainValue: null, + label: "Domain A", + }); + }); + + describe("after selecting a subdomain", () => { + beforeEach(() => { + // Emulate selecting a subdomain + subdomainFilter.value = "a1"; + subdomainFilter.dispatchEvent(new Event("change")); + }); + + test("fires an event with the selected domain/subdomain pair", () => { + expect(eventSpy.mock.calls[1][0].detail).toEqual({ + topLevelDomainValue: "a", + subdomainValue: "a1", + label: "Domain A - Subdomain of A 1", + }); + }); + + describe("after changing to another top level domain", () => { + beforeEach(() => { + domainFilter.value = "b"; + domainFilter.dispatchEvent(new Event("change")); + }); + + test("only the new domain's options are available", () => { + const options = subdomainFilter.querySelectorAll("option"); + + const values = Array.from(options).map((el) => el.value); + + expect(values).toEqual(["*", "b1", "b2"]); + }); + + test("selects all subdomains", () => { + expect(subdomainFilter.value).toEqual("*"); + }); + + test("fires an event with the selected domain and null subdomain", () => { + expect(eventSpy.mock.calls[2][0].detail).toEqual({ + topLevelDomainValue: "b", + subdomainValue: null, + label: "Domain B", + }); + }); + + describe("after changing back to the original top level domain", () => { + beforeEach(() => { + domainFilter.value = "a"; + domainFilter.dispatchEvent(new Event("change")); + }); + + test("selects all subdomains", () => { + expect(subdomainFilter.value).toEqual("*"); + }); + }); + }); + + describe("after clearing the top level domain", () => { + beforeEach(() => { + domainFilter.value = "*"; + domainFilter.dispatchEvent(new Event("change")); + }); + + test("subdomain select is disabled", () => { + expect(subdomainFilter).toBeDisabled(); + }); + + test("the only option is 'all subdomains'", () => { + expect(subdomainFilter.options).toHaveLength(1); + }); + + test("fires an event with null domain/subdomain", () => { + expect(eventSpy.mock.calls[2][0].detail).toEqual({ + topLevelDomainValue: null, + subdomainValue: null, + label: null, + }); + }); + }); + }); +}); + +// TODO: clear selected subdomain when choosing parent domain From 730c59e0aa80560ea1131dd7bd5fd17f5eee159d Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Thu, 22 Feb 2024 11:17:20 +0000 Subject: [PATCH 172/221] Revert template - will add backend later --- templates/partial/filter.html | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/templates/partial/filter.html b/templates/partial/filter.html index f5a5b5fb..6ab6f185 100644 --- a/templates/partial/filter.html +++ b/templates/partial/filter.html @@ -44,27 +44,13 @@

    Domain

    Domain -
    - - -
    -
    - - +
    + {% for domain_option in form.domains %} +
    + {{ domain_option.tag}} + +
    + {% endfor %}
    From 31d9d997f998e84861bd89e30d73393cad50b71d Mon Sep 17 00:00:00 2001 From: LavMatt Date: Wed, 21 Feb 2024 11:21:44 +0000 Subject: [PATCH 173/221] add service for dataproductdetails --- home/service/details.py | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/home/service/details.py b/home/service/details.py index da87f7f8..b7f79009 100644 --- a/home/service/details.py +++ b/home/service/details.py @@ -1,24 +1,54 @@ from data_platform_catalogue.search_types import MultiSelectFilter, ResultType from django.core.exceptions import ObjectDoesNotExist + from .base import GenericService -class DetailsService(GenericService): +class DetailsDataProductService(GenericService): def __init__(self, urn: str): self.urn = urn self.client = self._get_catalogue_client() filter_value = [MultiSelectFilter("urn", [urn])] - search_results = self.client.search( - query="", page=None, filters=filter_value) + search_results = self.client.search(query="", page=None, filters=filter_value) if not search_results.page_results: raise ObjectDoesNotExist(urn) self.result = search_results.page_results[0] + self.data_product_name = self.result.name + self.assets_in_data_product = self._get_data_product_entities() self.context = self._get_context() + def _get_data_product_entities(self): + # we might want to implement pagination for data product children + # details at some point + data_product_search = self.client.list_data_product_assets( + urn=self.urn, count=500 + ).page_results + + assets_in_data_product = [] + for result in data_product_search: + # name is like that as fully qualified name ({data_product}.{asset}) seems + # too verbose to display here. + assets_in_data_product.append( + { + "name": ( + result.name + if not result.name.split(".")[0] == self.data_product_name + else result.name.split(".")[1] + ), + "urn": result.id, + "description": result.description, + "type": "TABLE", + } + ) + + assets_in_data_product = sorted(assets_in_data_product, key=lambda d: d["name"]) + + return assets_in_data_product + def _get_context(self): context = { "result": self.result, @@ -27,6 +57,7 @@ def _get_context(self): if self.result.result_type == ResultType.DATA_PRODUCT else "Table" ), + "tables": self.assets_in_data_product, "page_title": f"{self.result.name} - Data catalogue", } From 0787db23393b7586b347e051af93c94ff4ab3ea0 Mon Sep 17 00:00:00 2001 From: LavMatt Date: Wed, 21 Feb 2024 11:22:49 +0000 Subject: [PATCH 174/221] update templates - data product details and search --- ...details.html => details_data_product.html} | 30 ++++++++----------- templates/partial/search_result.html | 4 ++- 2 files changed, 15 insertions(+), 19 deletions(-) rename templates/{details.html => details_data_product.html} (80%) diff --git a/templates/details.html b/templates/details_data_product.html similarity index 80% rename from templates/details.html rename to templates/details_data_product.html index 001e81d8..b30ad60b 100644 --- a/templates/details.html +++ b/templates/details_data_product.html @@ -33,7 +33,7 @@

    {{result.name}}

    Domain name
    - {{result.metadata.domain.properties.name}} + {{result.metadata.domain_name}}
    @@ -57,7 +57,7 @@

    {{result.name}}

    Retention period
    - + {{result.metadata.retention_period_in_days|intcomma}}
    @@ -82,7 +82,7 @@

    {{result.name}}


    - + @@ -91,21 +91,15 @@

    {{result.name}}

    - - - - - - - - - - - - - - - + {% for table in tables %} + {% with table_type=table.type|lower %} + + + + + + {% endwith %} + {% endfor %}
    Database contentData Product content
    Table name
    Table 1This is description about the table Schema details
    Table 2This is description about the table Schema details
    Table 3This is description about the table Schema details
    {{table.name}}{{table.description}} Schema details
    diff --git a/templates/partial/search_result.html b/templates/partial/search_result.html index 46996814..687ae625 100644 --- a/templates/partial/search_result.html +++ b/templates/partial/search_result.html @@ -6,7 +6,9 @@

    - {{result.name}} + {% with result_type=result.result_type.name|lower %} + {{result.name}} + {% endwith %} {% if result.result_type.name == "DATA_PRODUCT" %} Data product From 65be3a75842cb5065b9aa472b8a5bd92fd3a3cc3 Mon Sep 17 00:00:00 2001 From: LavMatt Date: Wed, 21 Feb 2024 11:23:50 +0000 Subject: [PATCH 175/221] url for search link and details redirect in views --- home/service/search.py | 7 +++++-- home/urls.py | 6 +++++- home/views.py | 16 ++++++++++++---- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/home/service/search.py b/home/service/search.py index a369348f..16e7f5c4 100644 --- a/home/service/search.py +++ b/home/service/search.py @@ -103,10 +103,13 @@ def _highlight_results(self): return highlighted_results else: - pattern = f'({re.escape(query)})' + pattern = f"({re.escape(query)})" for result in highlighted_results.page_results: result.description = re.sub( - pattern, r'**\1**', result.description, flags=re.IGNORECASE, + pattern, + r"**\1**", + result.description, + flags=re.IGNORECASE, ) return highlighted_results diff --git a/home/urls.py b/home/urls.py index d508c4f4..71bf78c1 100644 --- a/home/urls.py +++ b/home/urls.py @@ -6,6 +6,10 @@ urlpatterns = [ path("", views.home_view, name="home"), path("search", views.search_view, name="search"), - path("details//", views.details_view, name="details"), + path( + "details//", + views.redirect_details_view, + name="details", + ), path("pagination/", views.search_view, name="pagination"), ] diff --git a/home/views.py b/home/views.py index 5937a65d..c37a5fc6 100644 --- a/home/views.py +++ b/home/views.py @@ -3,7 +3,7 @@ from django.shortcuts import render from home.forms.search import SearchForm -from home.service.details import DetailsService +from home.service.details import DetailsDataProductService from home.service.search import SearchService @@ -12,15 +12,23 @@ def home_view(request): return render(request, "home.html", context) -def details_view(request, id): +def redirect_details_view(request, result_type, id): + if result_type == "data_product": + context = data_product_details(request, id) + return render(request, "details_data_product.html", context) + if result_type == "table": + pass + + +def data_product_details(request, id): try: - service = DetailsService(id) + service = DetailsDataProductService(id) except ObjectDoesNotExist: raise Http404("Asset does not exist") context = service.context - return render(request, "details.html", context) + return context def search_view(request, page: str = "1"): From 8e85768c1b951a19a4691a0f48450888f22f8632 Mon Sep 17 00:00:00 2001 From: LavMatt Date: Wed, 21 Feb 2024 11:27:10 +0000 Subject: [PATCH 176/221] add tests for data product details and view --- tests/conftest.py | 55 +++++++++++++++++++++++++++++++++++------- tests/test_services.py | 35 +++++++++++++++++++++------ tests/test_views.py | 20 ++++++++++----- 3 files changed, 87 insertions(+), 23 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index cf1af01c..988950ee 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,6 +3,7 @@ import pytest from data_platform_catalogue.client import BaseCatalogueClient +from data_platform_catalogue.client.datahub.datahub_client import DataHubCatalogueClient from data_platform_catalogue.search_types import ( FacetOption, ResultType, @@ -14,13 +15,18 @@ from faker import Faker from home.forms.search import SearchForm -from home.service.details import DetailsService +from home.service.details import DetailsDataProductService from home.service.search import SearchService +from datahub.metadata.schema_classes import ( + DataProductPropertiesClass, + DataProductAssociationClass, +) + fake = Faker() -def generate_page(page_size=20): +def generate_page(page_size=20, result_type: ResultType = None): """ Generate a fake search page """ @@ -29,8 +35,11 @@ def generate_page(page_size=20): results.append( SearchResult( id=fake.unique.name(), - result_type=choice( - (ResultType.DATA_PRODUCT, ResultType.TABLE)), + result_type=( + choice((ResultType.DATA_PRODUCT, ResultType.TABLE)) + if result_type is None + else result_type + ), name=fake.name(), description=fake.paragraph(), metadata={"search_summary":"a"}, @@ -71,7 +80,12 @@ def mock_catalogue(): mock_catalogue, page_results=generate_page(), total_results=100 ) mock_search_facets_response(mock_catalogue, domains=generate_options()) - + mock_list_data_product_response( + mock_catalogue, + page_results=generate_page(page_size=1, result_type=ResultType.TABLE), + total_results=1, + ) + # mock_get_dataproduct_aspect(mock_catalogue) yield mock_catalogue patcher.stop() @@ -85,8 +99,26 @@ def mock_search_response(mock_catalogue, total_results=0, page_results=()): def mock_search_facets_response(mock_catalogue, domains): - mock_catalogue.search_facets.return_value = SearchFacets( - {"domains": domains}) + mock_catalogue.search_facets.return_value = SearchFacets({"domains": domains}) + + +def mock_list_data_product_response(mock_catalogue, total_results, page_results=()): + search_response = SearchResponse( + total_results=total_results, page_results=page_results + ) + mock_catalogue.list_data_product_assets.return_value = search_response + + +def mock_get_dataproduct_aspect(mock_catalogue): + data_product_association = DataProductAssociationClass( + destinationUrn="urn:li:dataset:(urn:li:dataPlatform:glue,test.test,PROD)", + sourceUrn="urn:li:dataProduct:test", + ) + + response = DataProductPropertiesClass( + name="test", assets=[data_product_association], description="test" + ) + mock_catalogue.graph.get_aspect.return_value = response @pytest.fixture @@ -115,10 +147,15 @@ def search_context(search_service): @pytest.fixture -def detail_context(mock_catalogue): +def detail_dataproduct_context(mock_catalogue): mock_catalogue.search.return_value = SearchResponse( total_results=1, page_results=generate_page(page_size=1) ) - details_service = DetailsService(urn="urn:li:dataProduct:test") + # mock_catalogue.list_data_product_assets.return_value = SearchResponse( + # total_results=1, + # page_results=generate_page(page_size=1, result_type=ResultType.TABLE), + # ) + # with patch(): + details_service = DetailsDataProductService(urn="urn:li:dataProduct:test") context = details_service._get_context() return context diff --git a/tests/test_services.py b/tests/test_services.py index 0ca4c8b0..2675618c 100644 --- a/tests/test_services.py +++ b/tests/test_services.py @@ -49,34 +49,53 @@ def test_highlight_results_with_case_insensitive_query(self): service = SearchService(form=form, page="1") descriptions = [result.description for result in service.results.page_results] - highlighted_descriptions = [result.description for result in service.highlighted_results.page_results] + highlighted_descriptions = [ + result.description for result in service.highlighted_results.page_results + ] assert descriptions != highlighted_descriptions assert ( "**a**" or "**A**" in highlighted.description - for normal, highlighted - in zip( + for normal, highlighted in zip( service.results.page_results, service.highlighted_results.page_results, ) if "a" or "A" in normal.description ) -class TestDetailsService: - def test_get_context(self, detail_context, mock_catalogue): - assert detail_context["result"] == mock_catalogue.search().page_results[0] + +class TestDetailsDataProductService: + def test_get_context_data_product(self, detail_dataproduct_context, mock_catalogue): + assert ( + detail_dataproduct_context["result"] + == mock_catalogue.search().page_results[0] + ) result_type = ( "Data product" if mock_catalogue.search().page_results[0].result_type == ResultType.DATA_PRODUCT else "Table" ) - assert detail_context["result_type"] == result_type + assert detail_dataproduct_context["result_type"] == result_type assert ( - detail_context["page_title"] + detail_dataproduct_context["page_title"] == f"{mock_catalogue.search().page_results[0].name} - Data catalogue" ) + def test_get_context_data_product_tables( + self, detail_dataproduct_context, mock_catalogue + ): + name = mock_catalogue.list_data_product_assets().page_results[0].name + mock_table = { + "name": name, + "urn": mock_catalogue.list_data_product_assets().page_results[0].id, + "description": mock_catalogue.list_data_product_assets() + .page_results[0] + .description, + "type": "TABLE", + } + assert detail_dataproduct_context["tables"][0] == mock_table + @pytest.mark.parametrize( "domain, expected_subdomains", diff --git a/tests/test_views.py b/tests/test_views.py index 1f46c9ba..cc0196ec 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -1,4 +1,3 @@ - from data_platform_catalogue.search_types import SearchResponse from django.urls import reverse @@ -33,16 +32,25 @@ def test_bad_form(self, client): class TestDetailsView: - def test_details(self, client): + def test_details_data_product(self, client): response = client.get( - reverse("home:details", kwargs={ - "id": "urn:li:dataProduct:common-platform"}) + reverse( + "home:details", + kwargs={ + "id": "urn:li:dataProduct:common-platform", + "result_type": "data_product", + }, + ) ) assert response.status_code == 200 - def test_details_not_found(self, client, mock_catalogue): + def test_details_data_product_not_found(self, client, mock_catalogue): mock_catalogue.search.return_value = SearchResponse( total_results=0, page_results=[] ) - response = client.get(reverse("home:details", kwargs={"id": "fake"})) + response = client.get( + reverse( + "home:details", kwargs={"id": "fake", "result_type": "data_product"} + ) + ) assert response.status_code == 404 From 4fc487934736136b488b94c9be9ffb86b5c1be3a Mon Sep 17 00:00:00 2001 From: LavMatt Date: Wed, 21 Feb 2024 11:27:44 +0000 Subject: [PATCH 177/221] add selenium test for data product detail page --- tests/selenium/conftest.py | 12 ++++++++--- tests/selenium/test_search_scenarios.py | 27 ++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/tests/selenium/conftest.py b/tests/selenium/conftest.py index 13e03dab..74363f00 100644 --- a/tests/selenium/conftest.py +++ b/tests/selenium/conftest.py @@ -66,10 +66,16 @@ def __init__(self, selenium): self.selenium = selenium -class DetailsPage(Page): +class DetailsDataProductPage(Page): def secondary_heading(self): return self.selenium.find_element(By.TAG_NAME, "h2") + def data_product_details(self): + return self.selenium.find_element(By.TAG_NAME, "dl") + + def data_product_tables(self): + return self.selenium.find_element(By.TAG_NAME, "table") + class HomePage(Page): @@ -172,5 +178,5 @@ def search_page(selenium) -> SearchPage: @pytest.fixture -def details_page(selenium) -> DetailsPage: - return DetailsPage(selenium) +def details_data_product_page(selenium) -> DetailsDataProductPage: + return DetailsDataProductPage(selenium) diff --git a/tests/selenium/test_search_scenarios.py b/tests/selenium/test_search_scenarios.py index e8d80d63..a5c027af 100644 --- a/tests/selenium/test_search_scenarios.py +++ b/tests/selenium/test_search_scenarios.py @@ -13,12 +13,14 @@ class TestSearchWithoutJavascriptAndCss: """ @pytest.fixture(autouse=True) - def setup(self, live_server, selenium, home_page, search_page, details_page): + def setup( + self, live_server, selenium, home_page, search_page, details_data_product_page + ): self.selenium = selenium self.live_server_url = live_server.url self.home_page = home_page self.search_page = search_page - self.details_page = details_page + self.details_data_product_page = details_data_product_page def test_browse_to_first_item(self): """ @@ -152,6 +154,17 @@ def test_automated_accessibility_search(self): self.start_on_the_search_page() check_for_accessibility_issues(self.selenium.current_url) + def test_search_to_data_product_details(self): + """ + Users can search a data product and got to its details page + """ + self.start_on_the_search_page() + self.enter_a_query_and_submit("court timeliness data product") + item_name = self.click_on_the_first_result() + self.verify_i_am_on_the_details_page(item_name) + self.verify_data_product_details() + self.verify_data_product_tables_listed() + def start_on_the_home_page(self): self.selenium.get(f"{self.live_server_url}") assert "Data catalogue" in self.selenium.title @@ -186,7 +199,7 @@ def click_on_the_first_result(self): def verify_i_am_on_the_details_page(self, item_name): assert item_name in self.selenium.title - secondary_heading_text = self.details_page.secondary_heading().text + secondary_heading_text = self.details_data_product_page.secondary_heading().text assert secondary_heading_text == item_name @@ -245,3 +258,11 @@ def click_previous_page(self): def verify_sort_selected(self, expected): value = self.search_page.checked_sort_option().get_attribute("value") or "" assert value == expected.lower() + + def verify_data_product_tables_listed(self): + tables = self.details_data_product_page.data_product_tables() + assert tables.text + + def verify_data_product_details(self): + data_product_details = self.details_data_product_page.data_product_details() + assert data_product_details.text From 696034806bec7d4f020cd2dee4612a747e4598bd Mon Sep 17 00:00:00 2001 From: LavMatt Date: Wed, 21 Feb 2024 11:28:11 +0000 Subject: [PATCH 178/221] update poetry --- poetry.lock | 10 +++++----- pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index d1aa58aa..037c0b99 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "acryl-datahub" @@ -1785,13 +1785,13 @@ psutil = "*" [[package]] name = "ministryofjustice-data-platform-catalogue" -version = "0.10.0" +version = "0.15.0" description = "Library to integrate the MoJ data platform with the catalogue component." optional = false python-versions = ">=3.10,<4.0" files = [ - {file = "ministryofjustice_data_platform_catalogue-0.10.0-py3-none-any.whl", hash = "sha256:6818d4be3d7e87f655ee125f89ca3cc797aa2d79bc77b04fe1ec7f656a2c2ac0"}, - {file = "ministryofjustice_data_platform_catalogue-0.10.0.tar.gz", hash = "sha256:1d052dcd97afed31daef37a185d48dbbd1aedfdb81fe03227c9aea07727ad772"}, + {file = "ministryofjustice_data_platform_catalogue-0.15.0-py3-none-any.whl", hash = "sha256:032c197b03050fa11197c991301678ea690abc7c08e18a88c141cd8e44436271"}, + {file = "ministryofjustice_data_platform_catalogue-0.15.0.tar.gz", hash = "sha256:0658d0f444c2f755d593ac0ce28afcb027239ed6b3c57bb2247f5d5c64485cfc"}, ] [package.dependencies] @@ -3644,4 +3644,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "5cd66d8abbeaa1b06f98ce3820d1c076aed4aa1606f435184323085384cec037" +content-hash = "5ce756bb0eb9ff1946f3c628b3ac67572fdd742dea9980656080c9f689de1393" diff --git a/pyproject.toml b/pyproject.toml index 1c91a552..8d3bee75 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ django = "^5.0.1" pyyaml = "^6.0.1" gunicorn = "^21.2.0" whitenoise = "^6.6.0" -ministryofjustice-data-platform-catalogue = "^0.10.0" +ministryofjustice-data-platform-catalogue = "^0.15.0" markdown = "^3.5.2" python-dotenv = "^1.0.1" faker = "^22.6.0" From ac1915c3727ba56c7223b7dcca637094c4345999 Mon Sep 17 00:00:00 2001 From: Murdo Moyse Date: Thu, 22 Feb 2024 15:31:09 +0000 Subject: [PATCH 179/221] Added basics of a glossary page and context --- home/urls.py | 1 + home/views.py | 25 +++++++++++++++++++ templates/base/navigation.html | 6 +++++ templates/glossary.html | 44 ++++++++++++++++++++++++++++++++++ templates/home.html | 3 +++ 5 files changed, 79 insertions(+) create mode 100644 templates/glossary.html diff --git a/home/urls.py b/home/urls.py index d508c4f4..303e30dc 100644 --- a/home/urls.py +++ b/home/urls.py @@ -6,6 +6,7 @@ urlpatterns = [ path("", views.home_view, name="home"), path("search", views.search_view, name="search"), + path("glossary", views.glossary_view, name="glossary"), path("details//", views.details_view, name="details"), path("pagination/", views.search_view, name="pagination"), ] diff --git a/home/views.py b/home/views.py index 5937a65d..475cdd48 100644 --- a/home/views.py +++ b/home/views.py @@ -35,3 +35,28 @@ def search_view(request, page: str = "1"): search_service = SearchService(form=form, page=page) return render(request, "search.html", search_service.context) + +def glossary_view(request): + context = { + "results": { + "Key concepts": { + "description": "Explanation of key concepts used in the catalogue", + "members": [ + { + "name": "Data Steward", + "description": "I am a data steward", + }, + ], + }, + "Data governance terms": { + "description": "Data governance terms, people and processes referenced in the catalogue.", + "members": [ + { + "name": "Data Product", + "description": "Data Products are logical groupings of other data", + }, + ], + }, + } + } + return render(request, "glossary.html", context) diff --git a/templates/base/navigation.html b/templates/base/navigation.html index 0be4eff1..d82b8dd5 100644 --- a/templates/base/navigation.html +++ b/templates/base/navigation.html @@ -26,6 +26,7 @@

    diff --git a/templates/glossary.html b/templates/glossary.html new file mode 100644 index 00000000..d1103c8d --- /dev/null +++ b/templates/glossary.html @@ -0,0 +1,44 @@ +{% extends "base/base.html" %} + +{% block content %} +
    +
    +

    Glossary

    +
    +
    +
    +
    + +
    +
    +

    Key concepts used in the data catalog.

    + {% for parent_term, parent_term_details in results.items %} +
    +

    {{ parent_term }}

    +

    {{ parent_term_details.description }}

    +
    + {% for member in parent_term_details.members %} +
    +

    {{ member.name }}

    +

    {{ member.description }}

    +
    + {%endfor%} + {%endfor%} +
    +
    + +{% endblock content %} diff --git a/templates/home.html b/templates/home.html index 0bb8fb40..6d4cbfa4 100644 --- a/templates/home.html +++ b/templates/home.html @@ -6,5 +6,8 @@ Back

    Customised page template

    +

    + Glossary. +

    {% endblock content %} From 3349aed762f9fc49421596bd77ea975731a1c6bd Mon Sep 17 00:00:00 2001 From: Murdo Moyse Date: Thu, 22 Feb 2024 15:33:29 +0000 Subject: [PATCH 180/221] Remove glossary header --- templates/glossary.html | 1 - 1 file changed, 1 deletion(-) diff --git a/templates/glossary.html b/templates/glossary.html index d1103c8d..bc4db398 100644 --- a/templates/glossary.html +++ b/templates/glossary.html @@ -25,7 +25,6 @@

    Glossary

    -

    Key concepts used in the data catalog.

    {% for parent_term, parent_term_details in results.items %}

    {{ parent_term }}

    From 9c0020213a0569fe590bc2102f8bdc5c8f1203cb Mon Sep 17 00:00:00 2001 From: LavMatt Date: Fri, 23 Feb 2024 09:10:36 +0000 Subject: [PATCH 181/221] fix selenium tests that sometimes hit a dead end --- templates/partial/search_result.html | 4 ++-- tests/selenium/conftest.py | 8 ++++++++ tests/selenium/test_search_scenarios.py | 19 +++++++++++++++---- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/templates/partial/search_result.html b/templates/partial/search_result.html index 687ae625..eb97f27e 100644 --- a/templates/partial/search_result.html +++ b/templates/partial/search_result.html @@ -10,11 +10,11 @@

    {{result.name}} {% endwith %} {% if result.result_type.name == "DATA_PRODUCT" %} - + Data product {% elif result.result_type.name == "TABLE" %} - + Table {% endif %} diff --git a/tests/selenium/conftest.py b/tests/selenium/conftest.py index 74363f00..940a3782 100644 --- a/tests/selenium/conftest.py +++ b/tests/selenium/conftest.py @@ -109,6 +109,14 @@ def first_search_result(self) -> SearchResultWrapper: ) ) + def first_search_result_type(self) -> str: + return ( + self.selenium.find_element(By.ID, "search-results") + .find_element(By.CSS_SELECTOR, ".govuk-grid-row") + .find_element(By.ID, "result-type") + .text + ) + def search_bar(self) -> WebElement: return self.selenium.find_element(By.NAME, "query") diff --git a/tests/selenium/test_search_scenarios.py b/tests/selenium/test_search_scenarios.py index a5c027af..3958a93d 100644 --- a/tests/selenium/test_search_scenarios.py +++ b/tests/selenium/test_search_scenarios.py @@ -22,12 +22,16 @@ def setup( self.search_page = search_page self.details_data_product_page = details_data_product_page - def test_browse_to_first_item(self): + def test_browse_to_first_item_data_product(self): """ Browses from the home page -> search -> details page """ - self.start_on_the_home_page() - self.click_on_the_search_link() + while True: + self.start_on_the_home_page() + self.click_on_the_search_link() + result_type = self.get_search_first_result_type() + if result_type.lower() == "data product": + break self.verify_i_am_on_the_search_page() self.verify_i_have_results() @@ -159,12 +163,19 @@ def test_search_to_data_product_details(self): Users can search a data product and got to its details page """ self.start_on_the_search_page() - self.enter_a_query_and_submit("court timeliness data product") + while True: + self.enter_a_query_and_submit("court timeliness data product") + result_type = self.get_search_first_result_type() + if result_type.lower() == "data product": + break item_name = self.click_on_the_first_result() self.verify_i_am_on_the_details_page(item_name) self.verify_data_product_details() self.verify_data_product_tables_listed() + def get_search_first_result_type(self): + return self.search_page.first_search_result_type() + def start_on_the_home_page(self): self.selenium.get(f"{self.live_server_url}") assert "Data catalogue" in self.selenium.title From 21e83fe96e62853374e547b38f149910c659a8db Mon Sep 17 00:00:00 2001 From: LavMatt Date: Fri, 23 Feb 2024 14:42:14 +0000 Subject: [PATCH 182/221] actually make the tests work for data product details --- tests/conftest.py | 16 ++++------- tests/selenium/conftest.py | 15 +++------- tests/selenium/test_search_scenarios.py | 37 +++++++++++++------------ tests/test_services.py | 1 - 4 files changed, 30 insertions(+), 39 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 988950ee..8c7beb66 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,7 +3,6 @@ import pytest from data_platform_catalogue.client import BaseCatalogueClient -from data_platform_catalogue.client.datahub.datahub_client import DataHubCatalogueClient from data_platform_catalogue.search_types import ( FacetOption, ResultType, @@ -15,7 +14,7 @@ from faker import Faker from home.forms.search import SearchForm -from home.service.details import DetailsDataProductService +from home.service.details import DataProductDetailsService from home.service.search import SearchService from datahub.metadata.schema_classes import ( @@ -42,7 +41,7 @@ def generate_page(page_size=20, result_type: ResultType = None): ), name=fake.name(), description=fake.paragraph(), - metadata={"search_summary":"a"}, + metadata={"search_summary": "a"}, ) ) return results @@ -85,7 +84,7 @@ def mock_catalogue(): page_results=generate_page(page_size=1, result_type=ResultType.TABLE), total_results=1, ) - # mock_get_dataproduct_aspect(mock_catalogue) + yield mock_catalogue patcher.stop() @@ -141,6 +140,7 @@ def valid_form(): def search_service(valid_form): return SearchService(form=valid_form, page="1") + @pytest.fixture def search_context(search_service): return search_service.context @@ -151,11 +151,7 @@ def detail_dataproduct_context(mock_catalogue): mock_catalogue.search.return_value = SearchResponse( total_results=1, page_results=generate_page(page_size=1) ) - # mock_catalogue.list_data_product_assets.return_value = SearchResponse( - # total_results=1, - # page_results=generate_page(page_size=1, result_type=ResultType.TABLE), - # ) - # with patch(): - details_service = DetailsDataProductService(urn="urn:li:dataProduct:test") + + details_service = DataProductDetailsService(urn="urn:li:dataProduct:test") context = details_service._get_context() return context diff --git a/tests/selenium/conftest.py b/tests/selenium/conftest.py index 940a3782..476ed16e 100644 --- a/tests/selenium/conftest.py +++ b/tests/selenium/conftest.py @@ -10,6 +10,7 @@ from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver from selenium.webdriver.remote.webelement import WebElement + TMP_DIR = Path(__file__).parent / "../../tmp" @@ -66,7 +67,7 @@ def __init__(self, selenium): self.selenium = selenium -class DetailsDataProductPage(Page): +class DataProductDetailsPage(Page): def secondary_heading(self): return self.selenium.find_element(By.TAG_NAME, "h2") @@ -109,14 +110,6 @@ def first_search_result(self) -> SearchResultWrapper: ) ) - def first_search_result_type(self) -> str: - return ( - self.selenium.find_element(By.ID, "search-results") - .find_element(By.CSS_SELECTOR, ".govuk-grid-row") - .find_element(By.ID, "result-type") - .text - ) - def search_bar(self) -> WebElement: return self.selenium.find_element(By.NAME, "query") @@ -186,5 +179,5 @@ def search_page(selenium) -> SearchPage: @pytest.fixture -def details_data_product_page(selenium) -> DetailsDataProductPage: - return DetailsDataProductPage(selenium) +def details_data_product_page(selenium) -> DataProductDetailsPage: + return DataProductDetailsPage(selenium) diff --git a/tests/selenium/test_search_scenarios.py b/tests/selenium/test_search_scenarios.py index 3958a93d..19a139e2 100644 --- a/tests/selenium/test_search_scenarios.py +++ b/tests/selenium/test_search_scenarios.py @@ -3,6 +3,8 @@ import pytest from .helpers import check_for_accessibility_issues +from tests.conftest import mock_search_response, generate_page +from data_platform_catalogue.search_types import ResultType @pytest.mark.slow @@ -22,19 +24,22 @@ def setup( self.search_page = search_page self.details_data_product_page = details_data_product_page - def test_browse_to_first_item_data_product(self): + def test_browse_to_first_item_data_product(self, mock_catalogue): """ Browses from the home page -> search -> details page """ - while True: - self.start_on_the_home_page() - self.click_on_the_search_link() - result_type = self.get_search_first_result_type() - if result_type.lower() == "data product": - break + # we need to mock search response to be data products + mock_search_response( + mock_catalogue=mock_catalogue, + page_results=generate_page(result_type=ResultType.DATA_PRODUCT), + total_results=100, + ) + + self.start_on_the_home_page() + self.click_on_the_search_link() + self.verify_i_am_on_the_search_page() self.verify_i_have_results() - item_name = self.click_on_the_first_result() self.verify_i_am_on_the_details_page(item_name) @@ -158,24 +163,22 @@ def test_automated_accessibility_search(self): self.start_on_the_search_page() check_for_accessibility_issues(self.selenium.current_url) - def test_search_to_data_product_details(self): + def test_search_to_data_product_details(self, mock_catalogue): """ Users can search a data product and got to its details page """ + mock_search_response( + mock_catalogue=mock_catalogue, + page_results=generate_page(result_type=ResultType.DATA_PRODUCT), + total_results=100, + ) self.start_on_the_search_page() - while True: - self.enter_a_query_and_submit("court timeliness data product") - result_type = self.get_search_first_result_type() - if result_type.lower() == "data product": - break + self.enter_a_query_and_submit("court timeliness") item_name = self.click_on_the_first_result() self.verify_i_am_on_the_details_page(item_name) self.verify_data_product_details() self.verify_data_product_tables_listed() - def get_search_first_result_type(self): - return self.search_page.first_search_result_type() - def start_on_the_home_page(self): self.selenium.get(f"{self.live_server_url}") assert "Data catalogue" in self.selenium.title diff --git a/tests/test_services.py b/tests/test_services.py index 2675618c..a9b5a5b8 100644 --- a/tests/test_services.py +++ b/tests/test_services.py @@ -3,7 +3,6 @@ import pytest from data_platform_catalogue.search_types import ResultType from home.service.search import SearchForm, SearchService -from unittest.mock import patch from home.service.search import domains_with_their_subdomains From 92b26b2416ce463ec85bbf39700cec895da2d14e Mon Sep 17 00:00:00 2001 From: LavMatt Date: Fri, 23 Feb 2024 14:42:49 +0000 Subject: [PATCH 183/221] this template will always be data product and align case --- templates/details_data_product.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/details_data_product.html b/templates/details_data_product.html index b30ad60b..26ec9e62 100644 --- a/templates/details_data_product.html +++ b/templates/details_data_product.html @@ -9,7 +9,7 @@ Back
    - {{result_type}} + Data product

    {{result.name}}

    @@ -82,7 +82,7 @@

    {{result.name}}


    - + From 704f4e0de8f7ff69da9d29546973759570d1c1db Mon Sep 17 00:00:00 2001 From: LavMatt Date: Fri, 23 Feb 2024 14:44:10 +0000 Subject: [PATCH 184/221] rename view, service and add blank dataset template --- home/service/details.py | 10 +++++++++- home/urls.py | 2 +- home/views.py | 20 ++++++++++++++++---- templates/details_dataset.html | 1 + 4 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 templates/details_dataset.html diff --git a/home/service/details.py b/home/service/details.py index b7f79009..5a5fa9f6 100644 --- a/home/service/details.py +++ b/home/service/details.py @@ -5,7 +5,7 @@ from .base import GenericService -class DetailsDataProductService(GenericService): +class DataProductDetailsService(GenericService): def __init__(self, urn: str): self.urn = urn self.client = self._get_catalogue_client() @@ -62,3 +62,11 @@ def _get_context(self): } return context + + +class DatasetDetailsService(GenericService): + def __init__(self, urn: str): + self.context = self._get_context() + + def _get_context(self): + return {} diff --git a/home/urls.py b/home/urls.py index 71bf78c1..a97e938a 100644 --- a/home/urls.py +++ b/home/urls.py @@ -8,7 +8,7 @@ path("search", views.search_view, name="search"), path( "details//", - views.redirect_details_view, + views.details_view, name="details", ), path("pagination/", views.search_view, name="pagination"), diff --git a/home/views.py b/home/views.py index c37a5fc6..21330d2e 100644 --- a/home/views.py +++ b/home/views.py @@ -3,7 +3,7 @@ from django.shortcuts import render from home.forms.search import SearchForm -from home.service.details import DetailsDataProductService +from home.service.details import DataProductDetailsService, DatasetDetailsService from home.service.search import SearchService @@ -12,17 +12,29 @@ def home_view(request): return render(request, "home.html", context) -def redirect_details_view(request, result_type, id): +def details_view(request, result_type, id): if result_type == "data_product": context = data_product_details(request, id) return render(request, "details_data_product.html", context) if result_type == "table": - pass + context = dataset_details(request, id) + return render(request, "details_dataset.html", context) def data_product_details(request, id): try: - service = DetailsDataProductService(id) + service = DataProductDetailsService(id) + except ObjectDoesNotExist: + raise Http404("Asset does not exist") + + context = service.context + + return context + + +def dataset_details(request, id): + try: + service = DatasetDetailsService(id) except ObjectDoesNotExist: raise Http404("Asset does not exist") diff --git a/templates/details_dataset.html b/templates/details_dataset.html new file mode 100644 index 00000000..30404ce4 --- /dev/null +++ b/templates/details_dataset.html @@ -0,0 +1 @@ +TODO \ No newline at end of file From 99e200fa7dd566cb794a73d4bfbe854dc1816047 Mon Sep 17 00:00:00 2001 From: LavMatt Date: Fri, 23 Feb 2024 14:54:51 +0000 Subject: [PATCH 185/221] markdown and trim for table descriptions in data product detail page --- templates/details_data_product.html | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/templates/details_data_product.html b/templates/details_data_product.html index 26ec9e62..aacab300 100644 --- a/templates/details_data_product.html +++ b/templates/details_data_product.html @@ -95,7 +95,13 @@

    {{result.name}}

    {% with table_type=table.type|lower %}
    - + {% endwith %} From b67273490bfa75b484d16d280ac213a16a161a79 Mon Sep 17 00:00:00 2001 From: LavMatt Date: Fri, 23 Feb 2024 14:58:48 +0000 Subject: [PATCH 186/221] remove self.data_product_name from dataproductservice --- home/service/details.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/home/service/details.py b/home/service/details.py index 5a5fa9f6..31cdccaf 100644 --- a/home/service/details.py +++ b/home/service/details.py @@ -17,7 +17,6 @@ def __init__(self, urn: str): raise ObjectDoesNotExist(urn) self.result = search_results.page_results[0] - self.data_product_name = self.result.name self.assets_in_data_product = self._get_data_product_entities() self.context = self._get_context() @@ -36,7 +35,7 @@ def _get_data_product_entities(self): { "name": ( result.name - if not result.name.split(".")[0] == self.data_product_name + if not result.name.split(".")[0] == self.result.name else result.name.split(".")[1] ), "urn": result.id, From 4be38a5cf531c7ec0984a420e7cf62b5a33ac192 Mon Sep 17 00:00:00 2001 From: LavMatt Date: Mon, 26 Feb 2024 09:01:09 +0000 Subject: [PATCH 187/221] try reinstalling deps for selenium tests --- .github/workflows/test.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index eec7b7e3..ac51b498 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,15 +27,7 @@ jobs: version: 1.7.1 virtualenvs-create: true virtualenvs-in-project: true - - name: cache deps - id: cache-deps - uses: actions/cache@v2 - with: - path: .venv - key: pydeps-${{ hashFiles('**/poetry.lock') }} - run: poetry install --no-interaction --no-root - if: steps.cache-deps.outputs.cache-hit != 'true' - - run: poetry install --no-interaction - name: run unit tests with coverage id: fast-tests run: poetry run pytest --cov -m 'not slow' From 18c21ba41b7cc4b03b3f4e223cc02429103470a5 Mon Sep 17 00:00:00 2001 From: LavMatt Date: Mon, 26 Feb 2024 09:25:43 +0000 Subject: [PATCH 188/221] revert workflow change --- .github/workflows/test.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ac51b498..eec7b7e3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,7 +27,15 @@ jobs: version: 1.7.1 virtualenvs-create: true virtualenvs-in-project: true + - name: cache deps + id: cache-deps + uses: actions/cache@v2 + with: + path: .venv + key: pydeps-${{ hashFiles('**/poetry.lock') }} - run: poetry install --no-interaction --no-root + if: steps.cache-deps.outputs.cache-hit != 'true' + - run: poetry install --no-interaction - name: run unit tests with coverage id: fast-tests run: poetry run pytest --cov -m 'not slow' From 4eb5eadcf89b1c12cd7cbb74e16f0e6ccb1e42d9 Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Mon, 26 Feb 2024 09:44:40 +0000 Subject: [PATCH 189/221] Add test --- tests/javascript/test_enhanced_search.js | 44 ++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/tests/javascript/test_enhanced_search.js b/tests/javascript/test_enhanced_search.js index 4920b383..83d7ae8c 100644 --- a/tests/javascript/test_enhanced_search.js +++ b/tests/javascript/test_enhanced_search.js @@ -12,6 +12,7 @@ const widget_html = ` +
    @@ -49,6 +50,47 @@ describe("initialisation", () => { }); }); +describe("after selecting a domain with no subdomains", () => { + beforeEach(() => { + document.body.innerHTML = widget_html; + + subdomainFilter = document.querySelector("#subdomains-filter"); + domainFilter = document.querySelector("#domains-filter"); + + initDomainFilter(); + + // Listen to outgoing events + domainFilter.parentElement.addEventListener( + "domain-filter-updates", + eventSpy + ); + + // Emulate selecting a domain + domainFilter.value = "c"; + domainFilter.dispatchEvent(new Event("change")); + }); + + test("selects all subdomains", () => { + expect(subdomainFilter.value).toEqual("*"); + }); + + test("only the all subdomains option is available", () => { + const options = subdomainFilter.querySelectorAll("option"); + + const values = Array.from(options).map((el) => el.value); + + expect(values).toEqual(["*"]); + }); + + test("fires an event with the selected domain/subdomain pair", () => { + expect(eventSpy.mock.calls[0][0].detail).toEqual({ + topLevelDomainValue: "c", + subdomainValue: null, + label: "Domain C", + }); + }); +}); + describe("after selecting a domain", () => { beforeEach(() => { document.body.innerHTML = widget_html; @@ -162,5 +204,3 @@ describe("after selecting a domain", () => { }); }); }); - -// TODO: clear selected subdomain when choosing parent domain From 755477f66c47c3502b3de1da0eec2534df144a5f Mon Sep 17 00:00:00 2001 From: Mat Moore Date: Mon, 26 Feb 2024 10:14:55 +0000 Subject: [PATCH 190/221] Install a compatable version of chrome/chromedriver The chromedriver library updates more frequently than the chrome distributed in ubuntu-latest, but these need to be the same version, otherwise axe-core breaks. As a workaround, try to install a version that matches whatever chrome is on the path. See also https://github.com/dequelabs/axe-core-npm/issues/401#issuecomment-1917605607 --- .github/workflows/test.yml | 10 +++++++++- tests/conftest.py | 18 +++++++++++++----- tests/selenium/conftest.py | 2 +- tests/selenium/helpers.py | 15 +++++++++++++-- tests/selenium/test_search_scenarios.py | 19 ++++++++++++++++--- 5 files changed, 52 insertions(+), 12 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5f3441ea..a7c75df7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -40,10 +40,18 @@ jobs: id: fast-tests run: poetry run pytest --cov -m 'not slow' + - name: Get Chromium version 🌐 + run: | + CHROMIUM_VERSION=$(google-chrome --product-version) + echo "Chromium version: $CHROMIUM_VERSION" + echo "CHROMIUM_VERSION=$CHROMIUM_VERSION" >> $GITHUB_ENV + - name: Install chromedriver 🚗 + run: | + npm install -g chromedriver@${CHROMIUM_VERSION%.*.*} - name: run selenium tests id: slow-tests if: steps.fast-tests.outcome == 'success' - run: poetry run pytest -m 'slow' + run: poetry run pytest -m 'slow' --chromedriver-path=$(npm root -g)/chromedriver/bin/chromedriver test_javascript: runs-on: ubuntu-latest diff --git a/tests/conftest.py b/tests/conftest.py index cf1af01c..8fef0413 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -20,6 +20,15 @@ fake = Faker() +def pytest_addoption(parser): + parser.addoption("--chromedriver-path", action="store") + + +@pytest.fixture +def chromedriver_path(request): + return request.config.getoption("--chromedriver-path") + + def generate_page(page_size=20): """ Generate a fake search page @@ -29,11 +38,10 @@ def generate_page(page_size=20): results.append( SearchResult( id=fake.unique.name(), - result_type=choice( - (ResultType.DATA_PRODUCT, ResultType.TABLE)), + result_type=choice((ResultType.DATA_PRODUCT, ResultType.TABLE)), name=fake.name(), description=fake.paragraph(), - metadata={"search_summary":"a"}, + metadata={"search_summary": "a"}, ) ) return results @@ -85,8 +93,7 @@ def mock_search_response(mock_catalogue, total_results=0, page_results=()): def mock_search_facets_response(mock_catalogue, domains): - mock_catalogue.search_facets.return_value = SearchFacets( - {"domains": domains}) + mock_catalogue.search_facets.return_value = SearchFacets({"domains": domains}) @pytest.fixture @@ -109,6 +116,7 @@ def valid_form(): def search_service(valid_form): return SearchService(form=valid_form, page="1") + @pytest.fixture def search_context(search_service): return search_service.context diff --git a/tests/selenium/conftest.py b/tests/selenium/conftest.py index 13e03dab..7c7a5f18 100644 --- a/tests/selenium/conftest.py +++ b/tests/selenium/conftest.py @@ -1,9 +1,9 @@ -from pytest import CollectReport, StashKey import datetime from pathlib import Path from typing import Any, Generator import pytest +from pytest import CollectReport, StashKey from selenium.webdriver import ChromeOptions from selenium.webdriver.chrome.webdriver import WebDriver from selenium.webdriver.common.by import By diff --git a/tests/selenium/helpers.py b/tests/selenium/helpers.py index 21be4e61..48b10012 100644 --- a/tests/selenium/helpers.py +++ b/tests/selenium/helpers.py @@ -1,7 +1,18 @@ import subprocess -def check_for_accessibility_issues(url): - command = ["npx", "@axe-core/cli", "-q", url] +def check_for_accessibility_issues(url, chromedriver_path=None): + command = ["npx", "@axe-core/cli"] + + if chromedriver_path: + command.extend(["--chromedriver-path", chromedriver_path]) + + command.extend( + [ + "-q", + url, + ] + ) + output = subprocess.run(command, capture_output=True, text=True) assert output.returncode == 0, output.stdout diff --git a/tests/selenium/test_search_scenarios.py b/tests/selenium/test_search_scenarios.py index e8d80d63..e7cb26a3 100644 --- a/tests/selenium/test_search_scenarios.py +++ b/tests/selenium/test_search_scenarios.py @@ -13,12 +13,21 @@ class TestSearchWithoutJavascriptAndCss: """ @pytest.fixture(autouse=True) - def setup(self, live_server, selenium, home_page, search_page, details_page): + def setup( + self, + live_server, + selenium, + home_page, + search_page, + details_page, + chromedriver_path, + ): self.selenium = selenium self.live_server_url = live_server.url self.home_page = home_page self.search_page = search_page self.details_page = details_page + self.chromedriver_path = chromedriver_path def test_browse_to_first_item(self): """ @@ -146,11 +155,15 @@ def test_clear_all_filters(self): def test_automated_accessibility_home(self): self.start_on_the_home_page() - check_for_accessibility_issues(self.selenium.current_url) + check_for_accessibility_issues( + self.selenium.current_url, chromedriver_path=self.chromedriver_path + ) def test_automated_accessibility_search(self): self.start_on_the_search_page() - check_for_accessibility_issues(self.selenium.current_url) + check_for_accessibility_issues( + self.selenium.current_url, chromedriver_path=self.chromedriver_path + ) def start_on_the_home_page(self): self.selenium.get(f"{self.live_server_url}") From a5c2c8e89fae1f2f33a424aa5435ef80483e01fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Feb 2024 11:42:08 +0000 Subject: [PATCH 191/221] Bump actions/cache from 2 to 4 Bumps [actions/cache](https://github.com/actions/cache) from 2 to 4. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v2...v4) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a7c75df7..c6c1d2d7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,7 +18,7 @@ jobs: with: python-version: 3.11.1 - name: cache poetry install - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.local key: poetry-1.7.1-0 @@ -29,7 +29,7 @@ jobs: virtualenvs-in-project: true - name: cache deps id: cache-deps - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: .venv key: pydeps-${{ hashFiles('**/poetry.lock') }} @@ -67,7 +67,7 @@ jobs: shell: bash run: echo "dir=$(npm config get cache)" >> ${GITHUB_OUTPUT} - - uses: actions/cache@v3 + - uses: actions/cache@v4 id: npm-cache with: path: ${{ steps.npm-cache-dir.outputs.dir }} From 5b1648b51a6a080c39822a5b9eabdeec17d35167 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Feb 2024 11:42:17 +0000 Subject: [PATCH 192/221] Bump sass from 1.70.0 to 1.71.1 Bumps [sass](https://github.com/sass/dart-sass) from 1.70.0 to 1.71.1. - [Release notes](https://github.com/sass/dart-sass/releases) - [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md) - [Commits](https://github.com/sass/dart-sass/compare/1.70.0...1.71.1) --- updated-dependencies: - dependency-name: sass dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1f70a353..8d50c4ce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "babel-jest": "^29.7.0", "govuk-frontend": "^5.1.0", "jest-environment-jsdom": "^29.7.0", - "sass": "^1.70.0" + "sass": "^1.71.1" }, "devDependencies": { "@testing-library/jest-dom": "^6.4.2", @@ -4968,9 +4968,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/sass": { - "version": "1.70.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.70.0.tgz", - "integrity": "sha512-uUxNQ3zAHeAx5nRFskBnrWzDUJrrvpCPD5FNAoRvTi0WwremlheES3tg+56PaVtCs5QDRX5CBLxxKMDJMEa1WQ==", + "version": "1.71.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.71.1.tgz", + "integrity": "sha512-wovtnV2PxzteLlfNzbgm1tFXPLoZILYAMJtvoXXkD7/+1uP41eKkIt1ypWq5/q2uT94qHjXehEYfmjKOvjL9sg==", "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", diff --git a/package.json b/package.json index 65262e07..ea223556 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "babel-jest": "^29.7.0", "govuk-frontend": "^5.1.0", "jest-environment-jsdom": "^29.7.0", - "sass": "^1.70.0" + "sass": "^1.71.1" }, "scripts": { "sass": "sass --load-path=. scss:static/assets/css", From 1d3ad227683075fe850153a18547070d4d449ea4 Mon Sep 17 00:00:00 2001 From: Murdo Moyse Date: Mon, 26 Feb 2024 14:56:39 +0000 Subject: [PATCH 193/221] Added glossary service --- home/service/glossary.py | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 home/service/glossary.py diff --git a/home/service/glossary.py b/home/service/glossary.py new file mode 100644 index 00000000..3c0fbfc4 --- /dev/null +++ b/home/service/glossary.py @@ -0,0 +1,39 @@ +from data_platform_catalogue.search_types import MultiSelectFilter, ResultType +from django.core.exceptions import ObjectDoesNotExist +from copy import deepcopy +from itertools import groupby + +from .base import GenericService + + +class GlossaryService(GenericService): + def __init__(self): + # Can we put the client instantiation in the base class? + self.client = self._get_catalogue_client() + self.context = self._get_context() + + def _get_context(self): + glossary_search_results = self.client.get_glossary_terms() + total_results = glossary_search_results.total_results + page_results_copy = deepcopy(glossary_search_results.page_results) + + # The sort is required for the grouping to work correctly + page_results_copy.sort(key=lambda x: x.metadata["parentNodes"][0]["properties"]["name"]) + sorted_total_results = [ + { + "name": key, + "members": list(group), + } + for key, group + in groupby( + page_results_copy, + key=lambda x:x.metadata["parentNodes"][0]["properties"]["name"] + ) + ] + for parent_term in sorted_total_results: + parent_term["description"] = parent_term["members"][0].metadata["parentNodes"][0]["properties"]["description"] + + context = {"results": sorted_total_results} + + return context + From 2b75abaa4a398dcca60ec2fce54e951b1f70130f Mon Sep 17 00:00:00 2001 From: Murdo Moyse Date: Mon, 26 Feb 2024 14:56:49 +0000 Subject: [PATCH 194/221] Updated catalogue client library --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 1c91a552..48d80ecc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ django = "^5.0.1" pyyaml = "^6.0.1" gunicorn = "^21.2.0" whitenoise = "^6.6.0" -ministryofjustice-data-platform-catalogue = "^0.10.0" +ministryofjustice-data-platform-catalogue = "^0.16.0" markdown = "^3.5.2" python-dotenv = "^1.0.1" faker = "^22.6.0" From ba7ce724a6da3cdfa2a5d4a73269aa098c003624 Mon Sep 17 00:00:00 2001 From: Murdo Moyse Date: Mon, 26 Feb 2024 14:56:58 +0000 Subject: [PATCH 195/221] Added glossary view --- home/views.py | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/home/views.py b/home/views.py index 475cdd48..c6f18021 100644 --- a/home/views.py +++ b/home/views.py @@ -5,6 +5,7 @@ from home.forms.search import SearchForm from home.service.details import DetailsService from home.service.search import SearchService +from home.service.glossary import GlossaryService def home_view(request): @@ -37,26 +38,5 @@ def search_view(request, page: str = "1"): return render(request, "search.html", search_service.context) def glossary_view(request): - context = { - "results": { - "Key concepts": { - "description": "Explanation of key concepts used in the catalogue", - "members": [ - { - "name": "Data Steward", - "description": "I am a data steward", - }, - ], - }, - "Data governance terms": { - "description": "Data governance terms, people and processes referenced in the catalogue.", - "members": [ - { - "name": "Data Product", - "description": "Data Products are logical groupings of other data", - }, - ], - }, - } - } - return render(request, "glossary.html", context) + glossary_service = GlossaryService() + return render(request, "glossary.html", glossary_service.context) From ed81188c0491320f6d846383f34a52edcedcd5a4 Mon Sep 17 00:00:00 2001 From: Murdo Moyse Date: Mon, 26 Feb 2024 14:57:06 +0000 Subject: [PATCH 196/221] Added glossary template --- templates/glossary.html | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/templates/glossary.html b/templates/glossary.html index bc4db398..e7baeba4 100644 --- a/templates/glossary.html +++ b/templates/glossary.html @@ -1,4 +1,5 @@ {% extends "base/base.html" %} +{% load markdown %} {% block content %}
    @@ -9,12 +10,12 @@

    Glossary

    - {% for parent_term, parent_term_details in results.items %} + {% for parent_term in results %}
    -

    {{ parent_term }}

    -

    {{ parent_term_details.description }}

    +

    {{ parent_term.name }}

    +

    {{ parent_term.description }}

    - {% for member in parent_term_details.members %} + {% for member in parent_term.members %}

    {{ member.name }}

    -

    {{ member.description }}

    +

    {{ member.description|markdown }}

    {%endfor%} {%endfor%} From 922a24693a55dbcba6f944ac3aec5bd46e6f6254 Mon Sep 17 00:00:00 2001 From: Murdo Moyse Date: Mon, 26 Feb 2024 16:25:49 +0000 Subject: [PATCH 197/221] Accounted for a lack of a parent glossary term --- home/service/glossary.py | 29 +++++++++++++-------- templates/glossary.html | 2 ++ tests/conftest.py | 55 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 11 deletions(-) diff --git a/home/service/glossary.py b/home/service/glossary.py index 3c0fbfc4..2bfb782d 100644 --- a/home/service/glossary.py +++ b/home/service/glossary.py @@ -13,25 +13,32 @@ def __init__(self): self.context = self._get_context() def _get_context(self): + """Returns a glossary context which is grouped by parent term""" glossary_search_results = self.client.get_glossary_terms() total_results = glossary_search_results.total_results - page_results_copy = deepcopy(glossary_search_results.page_results) # The sort is required for the grouping to work correctly - page_results_copy.sort(key=lambda x: x.metadata["parentNodes"][0]["properties"]["name"]) + page_results_copy = deepcopy(glossary_search_results.page_results) + + def sorter(result): + first_parent = result.metadata.get("parentNodes", []) + if first_parent: + return first_parent[0]["properties"]["name"] + if not first_parent: + return "Unsorted" + + page_results_copy.sort(key=sorter) sorted_total_results = [ - { - "name": key, - "members": list(group), - } + {"name": key, "members": list(group)} for key, group - in groupby( - page_results_copy, - key=lambda x:x.metadata["parentNodes"][0]["properties"]["name"] - ) + in groupby(page_results_copy, key=sorter) ] + # Adding the description in the list comprehension doesn't seem to work for parent_term in sorted_total_results: - parent_term["description"] = parent_term["members"][0].metadata["parentNodes"][0]["properties"]["description"] + if parent_term["members"][0].metadata.get("parentNodes"): + parent_term["description"] = parent_term["members"][0].metadata["parentNodes"][0]["properties"]["description"] + else: + parent_term["description"] = "" context = {"results": sorted_total_results} diff --git a/templates/glossary.html b/templates/glossary.html index e7baeba4..4086dc09 100644 --- a/templates/glossary.html +++ b/templates/glossary.html @@ -30,6 +30,7 @@

    Glossary

    {{ parent_term.name }}

    {{ parent_term.description }}

    +
    {% for member in parent_term.members %}
    @@ -37,6 +38,7 @@

    {{ member.name }}

    {{ member.description|markdown }}

    {%endfor%} +
    {%endfor%}
    diff --git a/tests/conftest.py b/tests/conftest.py index 68c34893..619794d9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -16,6 +16,7 @@ from home.forms.search import SearchForm from home.service.details import DetailsService from home.service.search import SearchService +from home.service.glossary import GlossaryService fake = Faker() @@ -70,6 +71,7 @@ def mock_catalogue(): mock_catalogue, page_results=generate_page(), total_results=100 ) mock_search_facets_response(mock_catalogue, domains=generate_options()) + mock_get_glossary_terms_response(mock_catalogue) yield mock_catalogue @@ -87,6 +89,51 @@ def mock_search_facets_response(mock_catalogue, domains): mock_catalogue.search_facets.return_value = SearchFacets( {"domains": domains}) +def mock_get_glossary_terms_response(mock_catalogue): + mock_catalogue.get_glossary_terms.return_value = SearchResponse( + total_results=3, + page_results=[ + SearchResult( + id="urn:li:glossaryTerm:022b9b68-c211-47ae-aef0-2db13acfeca8", + name="IAO", + description="Information asset owner.\n", + metadata={ + "parentNodes": [ + { + "properties": { + "name": "Data protection terms", + "description": "Data protection terms", + } + } + ] + }, + result_type="GLOSSARY_TERM", + ), + SearchResult( + id="urn:li:glossaryTerm:022b9b68-c211-47ae-aef0-2db13acfeca8", + name="Other term", + description="Term description to test groupings work", + metadata={ + "parentNodes": [ + { + "properties": { + "name": "Data protection terms", + "description": "Data protection terms", + } + } + ] + }, + result_type="GLOSSARY_TERM", + ), + SearchResult( + id="urn:li:glossaryTerm:0eb7af28-62b4-4149-a6fa-72a8f1fea1e6", + name="Security classification", + description="Only data that is 'official'", + metadata={"parentNodes": []}, + result_type="GLOSSARY_TERM", + ), + ], + ) @pytest.fixture def valid_form(): @@ -119,3 +166,11 @@ def detail_context(mock_catalogue): details_service = DetailsService(urn="urn:li:dataProduct:test") context = details_service._get_context() return context + +# @pytest.fixture +# def glossary_context(mock_catalogue): +# mock_catalogue.search.return_value = SearchResponse( +# total_results=1, page_results=generate_page(page_size=1) +# ) +# glossary_service = GlossaryService() +# return glossary_service.context From d46e1355132b05cb7db09bc17580c2fd91d38814 Mon Sep 17 00:00:00 2001 From: Murdo Moyse Date: Mon, 26 Feb 2024 16:26:22 +0000 Subject: [PATCH 198/221] Added unit tests for glossary services and views --- tests/test_services.py | 80 ++++++++++++++++++++++++++++++++++++++++-- tests/test_views.py | 5 +++ 2 files changed, 83 insertions(+), 2 deletions(-) diff --git a/tests/test_services.py b/tests/test_services.py index f4392336..fff39228 100644 --- a/tests/test_services.py +++ b/tests/test_services.py @@ -1,9 +1,14 @@ from types import GeneratorType import pytest -from data_platform_catalogue.search_types import ResultType - +from data_platform_catalogue.search_types import ( + ResultType, + SearchResponse, + SearchResult, +) +from unittest.mock import patch from home.service.search import domains_with_their_subdomains +from home.service.glossary import GlossaryService class TestSearchService: @@ -44,6 +49,77 @@ def test_get_context(self, detail_context, mock_catalogue): ) +class TestGlossaryService: + def test_get_context(self): + glossary_context = GlossaryService() + expected_context = { + "results": [ + { + "name": "Data protection terms", + "members": [ + SearchResult( + id="urn:li:glossaryTerm:022b9b68-c211-47ae-aef0-2db13acfeca8", + result_type="GLOSSARY_TERM", + name="IAO", + description="Information asset owner.\n", + matches={}, + metadata={ + "parentNodes": [ + { + "properties": { + "name": "Data protection terms", + "description": "Data protection terms", + } + } + ] + }, + tags=[], + last_updated=None, + ), + SearchResult( + id="urn:li:glossaryTerm:022b9b68-c211-47ae-aef0-2db13acfeca8", + result_type="GLOSSARY_TERM", + name="Other term", + description="Term description to test groupings work", + matches={}, + metadata={ + "parentNodes": [ + { + "properties": { + "name": "Data protection terms", + "description": "Data protection terms", + } + } + ] + }, + tags=[], + last_updated=None, + ), + ], + "description": "Data protection terms", + }, + { + "name": "Unsorted", + "members": [ + SearchResult( + id="urn:li:glossaryTerm:0eb7af28-62b4-4149-a6fa-72a8f1fea1e6", + result_type="GLOSSARY_TERM", + name="Security classification", + description="Only data that is 'official'", + matches={}, + metadata={"parentNodes": []}, + tags=[], + last_updated=None, + ) + ], + "description": "", + }, + ] + } + + assert expected_context == glossary_context.context + + @pytest.mark.parametrize( "domain, expected_subdomains", [ diff --git a/tests/test_views.py b/tests/test_views.py index 1f46c9ba..f5cb49c7 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -46,3 +46,8 @@ def test_details_not_found(self, client, mock_catalogue): ) response = client.get(reverse("home:details", kwargs={"id": "fake"})) assert response.status_code == 404 + +class TestGlossaryView: + def test_details(self, client): + response = client.get(reverse("home:glossary")) + assert response.status_code == 200 From e02c45d45e3e6133e88d82b468bddcf0fced835c Mon Sep 17 00:00:00 2001 From: Murdo Moyse Date: Mon, 26 Feb 2024 16:32:48 +0000 Subject: [PATCH 199/221] Added selenium tests for glossary --- tests/selenium/conftest.py | 3 +++ tests/selenium/test_search_scenarios.py | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/tests/selenium/conftest.py b/tests/selenium/conftest.py index 13e03dab..33176dfc 100644 --- a/tests/selenium/conftest.py +++ b/tests/selenium/conftest.py @@ -76,6 +76,9 @@ class HomePage(Page): def search_nav_link(self) -> WebElement: return self.selenium.find_element(By.LINK_TEXT, "Search") + def glossary_nav_link(self) -> WebElement: + return self.selenium.find_element(By.LINK_TEXT, "Glossary") + class SearchResultWrapper: def __init__(self, element: WebElement): diff --git a/tests/selenium/test_search_scenarios.py b/tests/selenium/test_search_scenarios.py index e8d80d63..3537c27b 100644 --- a/tests/selenium/test_search_scenarios.py +++ b/tests/selenium/test_search_scenarios.py @@ -20,6 +20,11 @@ def setup(self, live_server, selenium, home_page, search_page, details_page): self.search_page = search_page self.details_page = details_page + def verify_glossary_link_from_homepage_works(self): + self.start_on_the_home_page() + self.click_on_the_glossary_link() + self.verify_i_am_on_the_glossary_page() + def test_browse_to_first_item(self): """ Browses from the home page -> search -> details page @@ -163,6 +168,9 @@ def start_on_the_search_page(self): def click_on_the_search_link(self): self.home_page.search_nav_link().click() + def click_on_the_glossary_link(self): + self.home_page.glossary_nav_link().click() + def click_on_the_search_button(self): self.search_page.search_button().click() @@ -170,6 +178,9 @@ def verify_i_am_on_the_search_page(self): assert "Search" in self.selenium.title assert "Find MOJ Data" in self.search_page.primary_heading().text + def verify_i_am_on_the_glossary_page(self): + assert "Glossary" in self.selenium.title + def verify_i_have_results(self): result_count = self.search_page.result_count().text assert re.match(r"[1-9]\d* Results", result_count) From 91ed261de1a3db270cfa8f49e175361099f4d5d2 Mon Sep 17 00:00:00 2001 From: Mitch Dawson <86007219+mitchdawson1982@users.noreply.github.com> Date: Mon, 26 Feb 2024 16:56:49 +0000 Subject: [PATCH 200/221] Dp 3047 present additional metadata items (#91) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update form with updated fields * update form with updated fields * implement custom property search * update pre-commit - add sync_with_poetry hook to keep pre-commit in sync with pyproject.toml - config flake8 - config isort to use black via pyproject.toml Add .secrets.baseline for detect-secrets move testing libraries to dev.dependencies in pyproject.toml * linting * linting and formatting for readability * revert domains (plural) -> domain (singular) changes (may be implemented in later PR) * add descriptions and code annotations for added helper functions add default for dict.get() [linting] * keep original indent for domain filters * linting * add pre-commit instructions/details to readme * Changed value for selection option an empty string and updated where_to_access choice value to 'Analytical_Platform' to avoid spaces. q exit quit() q [200~classifications~classifications * Make domain a single choice field * Removed admin.py as not required * Moved filter code to new partial template * refactor domain and subdomain choices to get the urn value * build filter strings method to create filter search strings * refactor classifications and where to access string generation, remove full query builder * refactor where to access href creation * add get_keys and format_label template filter functions * Update broken tests * add selected filters partial * update packages * refactor encode_without_filter function * remove redundant code * update tests with singular domain, classifications and where_to_access * Update dingular domain and add linting fixes * linter updates * add service for dataproductdetails * update templates - data product details and search * url for search link and details redirect in views * add tests for data product details and view * add selenium test for data product detail page * update poetry * fix selenium tests that sometimes hit a dead end * actually make the tests work for data product details * this template will always be data product and align case * rename view, service and add blank dataset template * markdown and trim for table descriptions in data product detail page * remove self.data_product_name from dataproductservice * try reinstalling deps for selenium tests * revert workflow change * Add javascript for domain filter widget Domain will have top level and subdomain selections, and work similarly to "Topic/Sub-Topic" on GOV.UK search. The form will submit domain and subdomain as separate fields, so we need to combine them on the backend. If javascript is not enabled, then the subdomain field is not displayed and it will work as before. This is tested using jest and jest-dom. * Revert template - will add backend later * Add test * Install a compatable version of chrome/chromedriver The chromedriver library updates more frequently than the chrome distributed in ubuntu-latest, but these need to be the same version, otherwise axe-core breaks. As a workaround, try to install a version that matches whatever chrome is on the path. See also https://github.com/dequelabs/axe-core-npm/issues/401#issuecomment-1917605607 * update form with updated fields * update form with updated fields * implement custom property search * revert domains (plural) -> domain (singular) changes (may be implemented in later PR) * Make domain a single choice field * refactor classifications and where to access string generation, remove full query builder * refactor where to access href creation * update packages * linter updates * remove duplicated function * update search result ui fields * fix result type in conftest * remove official-sensitive classification * add Custom Properties match display and rename 'list' to value_list --------- Co-authored-by: Tom Webber Co-authored-by: LavMatt Co-authored-by: Mat Moore --- .pre-commit-config.yaml | 26 +- .secrets.baseline | 122 ++ README.md | 14 +- core/__init__.py | 2 +- core/settings.py | 11 +- core/urls.py | 1 + home/admin.py | 3 - home/forms/search.py | 47 +- home/helper.py | 2 +- home/service/search.py | 88 +- home/templatetags/clear_filter.py | 25 + home/templatetags/lookup.py | 5 +- home/tests.py | 2 +- home/urls.py | 1 + home/views.py | 2 +- package-lock.json | 1314 +++++++++++++++++++++- package.json | 1 + poetry.lock | 221 ++++ pyproject.toml | 17 +- templates/base/base.html | 2 +- templates/base/error/page_not_found.html | 2 +- templates/base/head.html | 2 +- templates/home.html | 1 - templates/partial/filter.html | 59 +- templates/partial/search_result.html | 32 +- templates/partial/selected_filters.html | 35 + tests/conftest.py | 9 +- tests/selenium/conftest.py | 19 +- tests/selenium/test_search_scenarios.py | 51 +- tests/test_forms.py | 28 +- tests/test_services.py | 39 +- tests/test_views.py | 2 +- 32 files changed, 2005 insertions(+), 180 deletions(-) create mode 100644 .secrets.baseline delete mode 100644 home/admin.py create mode 100644 home/templatetags/clear_filter.py create mode 100644 templates/partial/selected_filters.html diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2881c581..52922b36 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,17 +11,30 @@ repos: exclude: tf$|j2$ - repo: https://github.com/psf/black - rev: 23.11.0 + rev: 23.12.1 hooks: - id: black name: black formatting # args: [--config=./pyproject.toml] - repo: https://github.com/PyCQA/flake8 - rev: 6.1.0 + rev: 7.0.0 hooks: - id: flake8 name: flake8 lint + args: [ + '--ignore=E203,E266,W503,F403', + '--exclude=".git, .mypy_cache, .pytest_cache, build, dist"', + '--max-line-length=89', + '--max-complexity=18', + '--select="B,C,E,F,W,T4,B9"' + ] + additional_dependencies: + - flake8-broken-line + - flake8-bugbear + - flake8-comprehensions + - flake8-debugger + - flake8-string-format - repo: https://github.com/Yelp/detect-secrets rev: v1.4.0 @@ -31,7 +44,14 @@ repos: exclude: package.lock.json - repo: https://github.com/pycqa/isort - rev: 5.12.0 + rev: 5.13.2 hooks: - id: isort name: isort (python) + additional_dependencies: ["toml"] + + - repo: https://github.com/floatingpurr/sync_with_poetry + rev: "1.1.0" + hooks: + - id: sync_with_poetry + args: [] diff --git a/.secrets.baseline b/.secrets.baseline new file mode 100644 index 00000000..47a49c0f --- /dev/null +++ b/.secrets.baseline @@ -0,0 +1,122 @@ +{ + "version": "1.4.0", + "plugins_used": [ + { + "name": "ArtifactoryDetector" + }, + { + "name": "AWSKeyDetector" + }, + { + "name": "AzureStorageKeyDetector" + }, + { + "name": "Base64HighEntropyString", + "limit": 4.5 + }, + { + "name": "BasicAuthDetector" + }, + { + "name": "CloudantDetector" + }, + { + "name": "DiscordBotTokenDetector" + }, + { + "name": "GitHubTokenDetector" + }, + { + "name": "HexHighEntropyString", + "limit": 3.0 + }, + { + "name": "IbmCloudIamDetector" + }, + { + "name": "IbmCosHmacDetector" + }, + { + "name": "JwtTokenDetector" + }, + { + "name": "KeywordDetector", + "keyword_exclude": "" + }, + { + "name": "MailchimpDetector" + }, + { + "name": "NpmDetector" + }, + { + "name": "PrivateKeyDetector" + }, + { + "name": "SendGridDetector" + }, + { + "name": "SlackDetector" + }, + { + "name": "SoftlayerDetector" + }, + { + "name": "SquareOAuthDetector" + }, + { + "name": "StripeDetector" + }, + { + "name": "TwilioKeyDetector" + } + ], + "filters_used": [ + { + "path": "detect_secrets.filters.allowlist.is_line_allowlisted" + }, + { + "path": "detect_secrets.filters.common.is_ignored_due_to_verification_policies", + "min_level": 2 + }, + { + "path": "detect_secrets.filters.heuristic.is_indirect_reference" + }, + { + "path": "detect_secrets.filters.heuristic.is_likely_id_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_lock_file" + }, + { + "path": "detect_secrets.filters.heuristic.is_not_alphanumeric_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_potential_uuid" + }, + { + "path": "detect_secrets.filters.heuristic.is_prefixed_with_dollar_sign" + }, + { + "path": "detect_secrets.filters.heuristic.is_sequential_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_swagger_file" + }, + { + "path": "detect_secrets.filters.heuristic.is_templated_secret" + } + ], + "results": { + "templates/base/base.html": [ + { + "type": "Base64 High Entropy String", + "filename": "templates/base/base.html", + "hashed_secret": "f6538b22f89b1e2b05570de751f2932c6bca9969", + "is_verified": false, + "line_number": 40 + } + ] + }, + "generated_at": "2024-02-21T10:23:47Z" +} diff --git a/README.md b/README.md index fa025d38..f72bfe5e 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ You will need npm (for javascript dependencies) and poetry (for python dependenc 1. Run `poetry install` to install python dependencies 2. Copy `.env.example` to `.env`. -3. You wil need to obtain an access token from Datahub catalogue and populate the `CATALOGUE_TOKEN` var in .env to be able to retrieve search data. - https://datahub.apps-tools.development.data-platform.service.justice.gov.uk/settings/tokens +3. You wil need to obtain an access token from Datahub catalogue and populate the +`CATALOGUE_TOKEN` var in .env to be able to retrieve search data. 4. Run `poetry run python manage.py runserver` Run `npm install` and then `npm run sass` to compile the stylesheets. @@ -16,6 +16,16 @@ Run `npm install` and then `npm run sass` to compile the stylesheets. ![Screenshot of the service showing the search page](image.png) +## Contributing + +Run `pre-commit install` from inside the poetry environment to set up pre commit hooks. + +- Linting and formatting handled by `black`, `flake8`, `pre-commit`, and `isort` + - `isort` is configured in `pyproject.toml` +- `detect-secrets` is used to prevent leakage of secrets +- `sync_with_poetry` ensures the versions of the modules in the pre-commit specification + are kept in line with those in the `pyproject.toml` config. + ## Testing - Python unit tests: `pytest -m 'not slow'` diff --git a/core/__init__.py b/core/__init__.py index a39da083..46a080bc 100644 --- a/core/__init__.py +++ b/core/__init__.py @@ -1,2 +1,2 @@ # -*- coding: utf-8 -*- -from .settings import * +from .settings import * # noqa: F401 diff --git a/core/settings.py b/core/settings.py index 70bdb09c..3d84b3ca 100644 --- a/core/settings.py +++ b/core/settings.py @@ -67,7 +67,7 @@ AUTH_PASSWORD_VALIDATORS = [ { - "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", # noqa: E501 }, { "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", @@ -86,10 +86,8 @@ LANGUAGE_CODE = "en-gb" -TIME_ZONE = "UTC" - -USE_I18N = True - +TIME_ZONE = "Europe/London" +USE_I18N = False USE_TZ = True @@ -113,8 +111,7 @@ "django.contrib.staticfiles.finders.AppDirectoriesFinder", ) -SAMPLE_SEARCH_RESULTS_FILENAME = BASE_DIR / \ - "sample_data/sample_search_page.yaml" +SAMPLE_SEARCH_RESULTS_FILENAME = BASE_DIR / "sample_data/sample_search_page.yaml" with open(SAMPLE_SEARCH_RESULTS_FILENAME) as f: SAMPLE_SEARCH_RESULTS = yaml.safe_load(f) diff --git a/core/urls.py b/core/urls.py index 796075bf..b04e5a6f 100644 --- a/core/urls.py +++ b/core/urls.py @@ -14,6 +14,7 @@ 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ + from django.contrib import admin from django.urls import include, path diff --git a/home/admin.py b/home/admin.py deleted file mode 100644 index 8c38f3f3..00000000 --- a/home/admin.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/home/forms/search.py b/home/forms/search.py index b54b435f..66ef02ee 100644 --- a/home/forms/search.py +++ b/home/forms/search.py @@ -4,12 +4,13 @@ from django import forms -def get_domain_choices(): +def get_domain_choices() -> list[tuple[str, str]]: """Make API call to obtain domain choices""" # TODO: pull in the domains from the catalogue client # facets = client.search_facets() # domain_list = facets.options("domains") return [ + ("", "All Domains"), ("urn:li:domain:HMCTS", "HMCTS"), ("urn:li:domain:HMPPS", "HMPPS"), ("urn:li:domain:HQ", "HQ"), @@ -69,6 +70,18 @@ def get_sort_choices(): ] +def get_classification_choices(): + return [ + ("OFFICIAL", "Official"), + ("SECRET", "Secret"), + ("TOP-SECRET", "Top-Secret"), + ] + + +def get_where_to_access_choices(): + return [("analytical_platform", "Analytical Platform")] + + class SearchForm(forms.Form): """Django form to represent data product search page inputs""" @@ -78,9 +91,27 @@ class SearchForm(forms.Form): required=False, widget=forms.TextInput(attrs={"class": "govuk-input search-input"}), ) - domains = forms.MultipleChoiceField( + domain = forms.ChoiceField( choices=get_domain_choices, required=False, + widget=forms.Select( + attrs={ + "form": "searchform", + "class": "govuk-select", + "aria-label": "domain", + } + ), + ) + classifications = forms.MultipleChoiceField( + choices=get_classification_choices, + required=False, + widget=forms.CheckboxSelectMultiple( + attrs={"class": "govuk-checkboxes__input", "form": "searchform"} + ), + ) + where_to_access = forms.MultipleChoiceField( + choices=get_where_to_access_choices, + required=False, widget=forms.CheckboxSelectMultiple( attrs={"class": "govuk-checkboxes__input", "form": "searchform"} ), @@ -103,13 +134,13 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.initial["sort"] = "relevance" - def encode_without_filter(self, filter_to_remove): + def encode_without_filter(self, filter_name: str, filter_value: str): """Preformat hrefs to drop individual filters""" # Deepcopy the cleaned data dict to avoid modifying it inplace query_params = deepcopy(self.cleaned_data) - - query_params["domains"].remove(filter_to_remove) - if len(query_params["domains"]) == 0: - query_params.pop("domains") - + value = query_params.get(filter_name) + if isinstance(value, list) and filter_value in value: + value.remove(filter_value) + elif isinstance(value, str) and filter_value == value: + query_params.pop(filter_name) return f"?{urlencode(query_params, doseq=True)}" diff --git a/home/helper.py b/home/helper.py index fecc2622..b5eb644e 100644 --- a/home/helper.py +++ b/home/helper.py @@ -8,5 +8,5 @@ def filter_seleted_domains(domain_list, domains): def get_domain_list(client): facets = client.search_facets() - domain_list = facets.options("domains") + domain_list = facets.options("domain") return domain_list diff --git a/home/service/search.py b/home/service/search.py index 16e7f5c4..48d055c3 100644 --- a/home/service/search.py +++ b/home/service/search.py @@ -1,24 +1,23 @@ -from typing import Any +import re from copy import deepcopy +from typing import Any + from data_platform_catalogue.search_types import MultiSelectFilter, SortOption from django.core.paginator import Paginator -import re from home.forms.search import SearchForm, get_subdomain_choices from .base import GenericService -def domains_with_their_subdomains(domains: list[str]) -> list[str]: +def domains_with_their_subdomains(domain: str) -> list[str]: """ When assets are tagged to subdomains, they are not included in search results if we filter by domain alone. We need to include all possible subdomains in the filter. """ - return [ - subdomain - for domain in domains - for (subdomain, _) in get_subdomain_choices(domain) - ] + domains + subdomains = get_subdomain_choices(domain) + subdomains = [subdomain[0] for subdomain in subdomains] + return [domain, *subdomains] if subdomains else [] class SearchService(GenericService): @@ -31,15 +30,36 @@ def __init__(self, form: SearchForm, page: str, items_per_page: int = 20): self.paginator = self._get_paginator(items_per_page) self.context = self._get_context() + @staticmethod + def _build_custom_property_filter( + filter_param: str, filter_value_list: list[str] + ) -> list[str]: + return [f"{filter_param}{filter_value}" for filter_value in filter_value_list] + def _get_search_results(self, page: str, items_per_page: int): if self.form.is_bound: form_data = self.form.cleaned_data else: form_data = {} + query = form_data.get("query", "") sort = form_data.get("sort", "relevance") - domains = domains_with_their_subdomains(form_data.get("domains", [])) - filter_value = [MultiSelectFilter("domains", domains)] if domains else [] + domain = form_data.get("domain", "") + domains_and_subdomains = domains_with_their_subdomains(domain) + classifications = self._build_custom_property_filter( + "sensitivityLevel=", form_data.get("classifications", []) + ) + where_to_access = self._build_custom_property_filter( + "whereToAccessDataset=", form_data.get("where_to_access", []) + ) + filter_value = [] + if domains_and_subdomains: + filter_value.append(MultiSelectFilter("domains", domains_and_subdomains)) + if classifications: + filter_value.append(MultiSelectFilter("customProperties", classifications)) + if where_to_access: + filter_value.append(MultiSelectFilter("customProperties", where_to_access)) + page_for_search = str(int(page) - 1) if sort == "ascending": sort_option = SortOption(field="name", ascending=True) @@ -63,20 +83,49 @@ def _get_paginator(self, items_per_page: int) -> Paginator: return Paginator(pages_list, items_per_page) + def _generate_label_clear_ref(self) -> dict[str, dict[str, str]]: + if self.form.is_bound: + domain = self.form.cleaned_data.get("domain", "") + classifications = self.form.cleaned_data.get("classifications", []) + where_to_access = self.form.cleaned_data.get("where_to_access", []) + label_clear_href = {} + if domain: + label_clear_href["domain"] = { + domain.split(":")[-1]: ( + self.form.encode_without_filter( + filter_name="domain", filter_value=domain + ) + ) + } + if classifications: + classifications_clear_href = {} + for classification in classifications: + classifications_clear_href[ + classification + ] = self.form.encode_without_filter( + filter_name="classifications", filter_value=classification + ) + label_clear_href["classifications"] = classifications_clear_href + + if where_to_access: + where_to_access_clear_href = {} + for access in where_to_access: + where_to_access_clear_href[ + access + ] = self.form.encode_without_filter( + filter_name="where_to_access", filter_value=access + ) + label_clear_href["availability"] = where_to_access_clear_href + else: + label_clear_href = None + return label_clear_href + def _get_context(self) -> dict[str, Any]: if self.form["query"].value(): page_title = f'Search for "{self.form["query"].value()}" - Data catalogue' else: page_title = "Search - Data catalogue" - if self.form.is_bound: - label_clear_href = { - filter.split(":")[-1]: self.form.encode_without_filter(filter) - for filter in self.form.cleaned_data.get("domains", []) - } - else: - label_clear_href = None - context = { "form": self.form, "results": self.results.page_results, @@ -88,7 +137,7 @@ def _get_context(self) -> dict[str, Any]: ), "paginator": self.paginator, "total_results": self.results.total_results, - "label_clear_href": label_clear_href, + "label_clear_href": self._generate_label_clear_ref(), "readable_match_reasons": self._get_match_reason_display_names(), } @@ -123,4 +172,5 @@ def _get_match_reason_display_names(self): "description": "Description", "fieldPaths": "Column name", "fieldDescriptions": "Column description", + "customProperties": "Custom properties", } diff --git a/home/templatetags/clear_filter.py b/home/templatetags/clear_filter.py new file mode 100644 index 00000000..6bdef7de --- /dev/null +++ b/home/templatetags/clear_filter.py @@ -0,0 +1,25 @@ +from django import template + +register = template.Library() + + +@register.filter +def get_item(dictionary: dict[str, dict], key: str) -> dict[str, list | str]: + return dictionary.get(key) + + +@register.filter +def get_items(dictionary: dict[str, dict], key: str) -> list: + return dictionary.get(key).items() + + +@register.filter +def get_keys(dictionary: dict[str, dict]) -> list[str] | list: + if dictionary: + return dictionary.keys() + return [] + + +@register.filter +def format_label(label: str) -> str: + return label.replace("_", " ").title() if "_" in label else label diff --git a/home/templatetags/lookup.py b/home/templatetags/lookup.py index 2f67d140..998d25e9 100644 --- a/home/templatetags/lookup.py +++ b/home/templatetags/lookup.py @@ -1,5 +1,6 @@ from home.templatetags.markdown import register + @register.filter -def lookup(list, lookup_dict): - return sorted([lookup_dict.get(item)for item in list]) +def lookup(value_list, lookup_dict): + return sorted([lookup_dict.get(item, "") for item in value_list]) diff --git a/home/tests.py b/home/tests.py index 7ce503c2..a79ca8be 100644 --- a/home/tests.py +++ b/home/tests.py @@ -1,3 +1,3 @@ -from django.test import TestCase +# from django.test import TestCase # Create your tests here. diff --git a/home/urls.py b/home/urls.py index a97e938a..7149e8bf 100644 --- a/home/urls.py +++ b/home/urls.py @@ -1,4 +1,5 @@ from django.urls import path + from . import views app_name = "home" diff --git a/home/views.py b/home/views.py index 21330d2e..4be2b8be 100644 --- a/home/views.py +++ b/home/views.py @@ -1,4 +1,4 @@ -from django.core.exceptions import ObjectDoesNotExist, ValidationError +from django.core.exceptions import ObjectDoesNotExist from django.http import Http404, HttpResponseBadRequest from django.shortcuts import render diff --git a/package-lock.json b/package-lock.json index 1f70a353..6e80f872 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,7 @@ "dependencies": { "@babel/preset-env": "^7.23.9", "@ministryofjustice/frontend": "^2.1.0", + "axe": "^12.2.3", "babel-jest": "^29.7.0", "govuk-frontend": "^5.1.0", "jest-environment-jsdom": "^29.7.0", @@ -1209,6 +1210,49 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.9.tgz", + "integrity": "sha512-KDlPRM6sLo4o1FkiSlXoAa8edLXFsKKIda779fbLrvmeuc3itnjCtaO6RrtoaANsIJANj+Vk1zqbZIMhkCAHVw==", + "dependencies": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20" + }, + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz", + "integrity": "sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", + "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-transform-modules-systemjs": { "version": "7.23.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.9.tgz", @@ -5130,9 +5174,19 @@ "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz", + "integrity": "sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" "node_modules/strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", @@ -5151,9 +5205,48 @@ "min-indent": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz", + "integrity": "sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.4.tgz", + "integrity": "sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -5203,58 +5296,1210 @@ "minimatch": "^3.0.4" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.23.4.tgz", + "integrity": "sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz", + "integrity": "sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==", + "dependencies": { + "@babel/compat-data": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.23.3" + }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz", + "integrity": "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==", "dependencies": { - "is-number": "^7.0.0" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20" }, "engines": { - "node": ">=8.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/tough-cookie": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", - "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.23.4.tgz", + "integrity": "sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==", "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" }, "engines": { - "node": ">=6" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz", + "integrity": "sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==", "dependencies": { - "punycode": "^2.1.1" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz", + "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.23.3.tgz", + "integrity": "sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.4.tgz", + "integrity": "sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz", + "integrity": "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz", + "integrity": "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz", + "integrity": "sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz", + "integrity": "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz", + "integrity": "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz", + "integrity": "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz", + "integrity": "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz", + "integrity": "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz", + "integrity": "sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.23.3.tgz", + "integrity": "sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz", + "integrity": "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.23.3.tgz", + "integrity": "sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.9.tgz", + "integrity": "sha512-3kBGTNBBk9DQiPoXYS0g0BYlwTQYUTifqgKTjxUwEUkduRT2QOa0FPGBJ+NROQhGyYO5BuTJwGvBnqKDykac6A==", + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.23.3", + "@babel/plugin-syntax-import-attributes": "^7.23.3", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.23.3", + "@babel/plugin-transform-async-generator-functions": "^7.23.9", + "@babel/plugin-transform-async-to-generator": "^7.23.3", + "@babel/plugin-transform-block-scoped-functions": "^7.23.3", + "@babel/plugin-transform-block-scoping": "^7.23.4", + "@babel/plugin-transform-class-properties": "^7.23.3", + "@babel/plugin-transform-class-static-block": "^7.23.4", + "@babel/plugin-transform-classes": "^7.23.8", + "@babel/plugin-transform-computed-properties": "^7.23.3", + "@babel/plugin-transform-destructuring": "^7.23.3", + "@babel/plugin-transform-dotall-regex": "^7.23.3", + "@babel/plugin-transform-duplicate-keys": "^7.23.3", + "@babel/plugin-transform-dynamic-import": "^7.23.4", + "@babel/plugin-transform-exponentiation-operator": "^7.23.3", + "@babel/plugin-transform-export-namespace-from": "^7.23.4", + "@babel/plugin-transform-for-of": "^7.23.6", + "@babel/plugin-transform-function-name": "^7.23.3", + "@babel/plugin-transform-json-strings": "^7.23.4", + "@babel/plugin-transform-literals": "^7.23.3", + "@babel/plugin-transform-logical-assignment-operators": "^7.23.4", + "@babel/plugin-transform-member-expression-literals": "^7.23.3", + "@babel/plugin-transform-modules-amd": "^7.23.3", + "@babel/plugin-transform-modules-commonjs": "^7.23.3", + "@babel/plugin-transform-modules-systemjs": "^7.23.9", + "@babel/plugin-transform-modules-umd": "^7.23.3", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.23.3", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.4", + "@babel/plugin-transform-numeric-separator": "^7.23.4", + "@babel/plugin-transform-object-rest-spread": "^7.23.4", + "@babel/plugin-transform-object-super": "^7.23.3", + "@babel/plugin-transform-optional-catch-binding": "^7.23.4", + "@babel/plugin-transform-optional-chaining": "^7.23.4", + "@babel/plugin-transform-parameters": "^7.23.3", + "@babel/plugin-transform-private-methods": "^7.23.3", + "@babel/plugin-transform-private-property-in-object": "^7.23.4", + "@babel/plugin-transform-property-literals": "^7.23.3", + "@babel/plugin-transform-regenerator": "^7.23.3", + "@babel/plugin-transform-reserved-words": "^7.23.3", + "@babel/plugin-transform-shorthand-properties": "^7.23.3", + "@babel/plugin-transform-spread": "^7.23.3", + "@babel/plugin-transform-sticky-regex": "^7.23.3", + "@babel/plugin-transform-template-literals": "^7.23.3", + "@babel/plugin-transform-typeof-symbol": "^7.23.3", + "@babel/plugin-transform-unicode-escapes": "^7.23.3", + "@babel/plugin-transform-unicode-property-regex": "^7.23.3", + "@babel/plugin-transform-unicode-regex": "^7.23.3", + "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.8", + "babel-plugin-polyfill-corejs3": "^0.9.0", + "babel-plugin-polyfill-regenerator": "^0.5.5", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" + }, + "node_modules/@babel/runtime": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz", + "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==", + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz", + "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==", + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz", + "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==", + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", + "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "node_modules/@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dependencies": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2""@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0""node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0""@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0""node": ">=6.9.0" + } + }, + "node_modules/@ladjs/format-util": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@ladjs/format-util/-/format-util-1.0.4.tgz", + "integrity": "sha512-hZere0rUga8kTzSTFbHREXpD9E/jwi94+B5RyLAmMIzl/w/EK1z7rFEnMHzPkU4AZkL42JWSsGXoV8LXMihybg==""node_modules/@ladjs/format-util": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@ladjs/format-util/-/format-util-1.0.4.tgz", + "integrity": "sha512-hZere0rUga8kTzSTFbHREXpD9E/jwi94+B5RyLAmMIzl/w/EK1z7rFEnMHzPkU4AZkL42JWSsGXoV8LXMihybg==" + }, + "node_modules/@ministryofjustice/frontend": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@ministryofjustice/frontend/-/frontend-2.1.0.tgz", + "integrity": "sha512-LekTR097OsFku0+sREn7gR3G7UvH7jATw40PvZH4mKtnE8hyyw0gDrCSvFYsRS4kPLDsoFqZ5l0Y3CZE9f364g==", + "node_modules/@ministryofjustice/frontend": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@ministryofjustice/frontend/-/frontend-2.1.0.tgz", + "integrity": "sha512-LekTR097OsFku0+sREn7gR3G7UvH7jATw40PvZH4mKtnE8hyyw0gDrCSvFYsRS4kPLDsoFqZ5l0Y3CZE9f364g==", + "dependencies": { + "govuk-frontend": "^5.0.0", + "moment": "^2.27.0""govuk-frontend": "^5.0.0", + "moment": "^2.27.0" + }, + "engines": { + "node": ">= 4.2.0" + }, + "peerDependencies": { + "jquery": "^3.6.0""node": ">= 4.2.0" + }, + "peerDependencies": { + "jquery": "^3.6.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/govuk-frontend": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/govuk-frontend/-/govuk-frontend-5.1.0.tgz", + "integrity": "sha512-Dc3J+uOI4i2VR3BVyfxbf6qVjTT4n4bBqbD0/Io6feP8pt/4IfKdP1vWimZf+BwMKKMXacw10hmdy5UcD6Cr8w==", + "engines": { + "node": ">= 4.2.0" + } + }, + "node_modules/immutable": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/jquery": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", + "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==", + "peer": true + }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "engines": { + "node": "*" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/sass": { + "version": "1.70.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.70.0.tgz", + "integrity": "sha512-uUxNQ3zAHeAx5nRFskBnrWzDUJrrvpCPD5FNAoRvTi0WwremlheES3tg+56PaVtCs5QDRX5CBLxxKMDJMEa1WQ==", + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + } + } +======= "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -5568,6 +6813,3 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } - } - } -} diff --git a/package.json b/package.json index 65262e07..33321117 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "@babel/preset-env": "^7.23.9", "@ministryofjustice/frontend": "^2.1.0", "babel-jest": "^29.7.0", + "axe": "^12.2.3", "govuk-frontend": "^5.1.0", "jest-environment-jsdom": "^29.7.0", "sass": "^1.70.0" diff --git a/poetry.lock b/poetry.lock index 037c0b99..c38f4dc1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4,6 +4,7 @@ name = "acryl-datahub" version = "0.12.1.4" description = "A CLI to work with DataHub metadata" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -125,6 +126,7 @@ vertica = ["Deprecated", "PyYAML", "acryl-sqlglot (==20.4.1.dev14)", "aiohttp (< name = "aiohttp" version = "3.9.3" description = "Async http client/server framework (asyncio)" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -220,6 +222,7 @@ speedups = ["Brotli", "aiodns", "brotlicffi"] name = "aiosignal" version = "1.3.1" description = "aiosignal: a list of registered asynchronous callbacks" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -234,6 +237,7 @@ frozenlist = ">=1.1.0" name = "antlr4-python3-runtime" version = "4.9.2" description = "ANTLR 4.9.2 runtime for Python 3.7" +category = "main" optional = false python-versions = "*" files = [ @@ -244,6 +248,7 @@ files = [ name = "appdirs" version = "1.4.4" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "main" optional = false python-versions = "*" files = [ @@ -255,6 +260,7 @@ files = [ name = "asgiref" version = "3.7.2" description = "ASGI specs, helper code, and adapters" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -269,6 +275,7 @@ tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] name = "attrs" version = "23.2.0" description = "Classes Without Boilerplate" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -288,6 +295,7 @@ tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "p name = "avro" version = "1.11.3" description = "Avro is a serialization and RPC framework." +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -302,6 +310,7 @@ zstandard = ["zstandard"] name = "avro-gen3" version = "0.7.11" description = "Avro record class and specific record reader generator" +category = "main" optional = false python-versions = "*" files = [ @@ -317,6 +326,7 @@ six = "*" name = "beautifulsoup4" version = "4.12.3" description = "Screen-scraping library" +category = "main" optional = false python-versions = ">=3.6.0" files = [ @@ -338,6 +348,7 @@ lxml = ["lxml"] name = "black" version = "23.12.1" description = "The uncompromising code formatter." +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -382,6 +393,7 @@ uvloop = ["uvloop (>=0.15.2)"] name = "boto3" version = "1.34.33" description = "The AWS SDK for Python" +category = "main" optional = false python-versions = ">= 3.8" files = [ @@ -401,6 +413,7 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] name = "botocore" version = "1.34.33" description = "Low-level, data-driven core of boto 3." +category = "main" optional = false python-versions = ">= 3.8" files = [ @@ -420,6 +433,7 @@ crt = ["awscrt (==0.19.19)"] name = "cached-property" version = "1.5.2" description = "A decorator for caching properties in classes." +category = "main" optional = false python-versions = "*" files = [ @@ -431,6 +445,7 @@ files = [ name = "cachetools" version = "5.3.2" description = "Extensible memoizing collections and decorators" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -442,6 +457,7 @@ files = [ name = "certifi" version = "2024.2.2" description = "Python package for providing Mozilla's CA Bundle." +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -453,6 +469,7 @@ files = [ name = "cffi" version = "1.16.0" description = "Foreign Function Interface for Python calling C code." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -517,6 +534,7 @@ pycparser = "*" name = "cfgv" version = "3.4.0" description = "Validate configuration and produce human readable error messages." +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -528,6 +546,7 @@ files = [ name = "chardet" version = "4.0.0" description = "Universal encoding detector for Python 2 and 3" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -539,6 +558,7 @@ files = [ name = "charset-normalizer" version = "3.3.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -638,6 +658,7 @@ files = [ name = "click" version = "8.1.7" description = "Composable command line interface toolkit" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -652,6 +673,7 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} name = "click-default-group" version = "1.2.4" description = "click_default_group" +category = "main" optional = false python-versions = ">=2.7" files = [ @@ -669,6 +691,7 @@ test = ["pytest"] name = "click-spinner" version = "0.1.10" description = "Spinner for Click" +category = "main" optional = false python-versions = "*" files = [ @@ -683,6 +706,7 @@ test = ["click", "pytest", "six"] name = "collate-sqllineage" version = "1.2.6" description = "Collate SQL Lineage for Analysis Tool powered by Python and sqlfluff based on sqllineage." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -703,6 +727,7 @@ docs = ["Sphinx (>=3.2.0)", "sphinx-rtd-theme (>=0.5.0)"] name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." +category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -714,6 +739,7 @@ files = [ name = "coverage" version = "7.4.1" description = "Code coverage measurement for Python" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -778,6 +804,7 @@ toml = ["tomli"] name = "croniter" version = "1.3.15" description = "croniter provides iteration for datetime object with cron like format" +category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -792,6 +819,7 @@ python-dateutil = "*" name = "cryptography" version = "42.0.2" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -846,6 +874,7 @@ test-randomorder = ["pytest-randomly"] name = "deepdiff" version = "6.7.1" description = "Deep Difference and Search of any Python object/data. Recreate objects by adding adding deltas to each other." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -864,6 +893,7 @@ optimize = ["orjson"] name = "deprecated" version = "1.2.14" description = "Python @deprecated decorator to deprecate old python classes, functions or methods." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -881,6 +911,7 @@ dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] name = "diff-cover" version = "8.0.3" description = "Run coverage and linting reports on diffs" +category = "main" optional = false python-versions = ">=3.8.10,<4.0.0" files = [ @@ -901,6 +932,7 @@ toml = ["tomli (>=1.2.1)"] name = "distlib" version = "0.3.8" description = "Distribution utilities" +category = "dev" optional = false python-versions = "*" files = [ @@ -912,6 +944,7 @@ files = [ name = "django" version = "5.0.1" description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." +category = "main" optional = false python-versions = ">=3.10" files = [ @@ -932,6 +965,7 @@ bcrypt = ["bcrypt"] name = "dnspython" version = "2.5.0" description = "DNS toolkit" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -952,6 +986,7 @@ wmi = ["wmi (>=1.5.1)"] name = "docker" version = "7.0.0" description = "A Python library for the Docker Engine API." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -973,6 +1008,7 @@ websockets = ["websocket-client (>=1.3.0)"] name = "ecdsa" version = "0.18.0" description = "ECDSA cryptographic signature library (pure python)" +category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -991,6 +1027,7 @@ gmpy2 = ["gmpy2"] name = "email-validator" version = "2.1.0.post1" description = "A robust email address syntax and deliverability validation library." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1006,6 +1043,7 @@ idna = ">=2.0.0" name = "expandvars" version = "0.12.0" description = "Expand system variables Unix style" +category = "main" optional = false python-versions = ">=3" files = [ @@ -1020,6 +1058,7 @@ tests = ["black", "pytest", "pytest-cov", "tox"] name = "faker" version = "22.6.0" description = "Faker is a Python package that generates fake data for you." +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1034,6 +1073,7 @@ python-dateutil = ">=2.4" name = "filelock" version = "3.13.1" description = "A platform independent file lock." +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1046,10 +1086,28 @@ docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1 testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] typing = ["typing-extensions (>=4.8)"] +[[package]] +name = "flake8" +version = "6.1.0" +description = "the modular source code checker: pep8 pyflakes and co" +category = "dev" +optional = false +python-versions = ">=3.8.1" +files = [ + {file = "flake8-6.1.0-py2.py3-none-any.whl", hash = "sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5"}, + {file = "flake8-6.1.0.tar.gz", hash = "sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23"}, +] + +[package.dependencies] +mccabe = ">=0.7.0,<0.8.0" +pycodestyle = ">=2.11.0,<2.12.0" +pyflakes = ">=3.1.0,<3.2.0" + [[package]] name = "freezegun" version = "1.4.0" description = "Let your Python tests travel through time" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1064,6 +1122,7 @@ python-dateutil = ">=2.7" name = "frozenlist" version = "1.4.1" description = "A list-like structure which implements collections.abc.MutableSequence" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1150,6 +1209,7 @@ files = [ name = "google" version = "3.0.0" description = "Python bindings to the Google search engine." +category = "main" optional = false python-versions = "*" files = [ @@ -1164,6 +1224,7 @@ beautifulsoup4 = "*" name = "google-auth" version = "2.27.0" description = "Google Authentication Library" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1187,6 +1248,7 @@ requests = ["requests (>=2.20.0,<3.0.0.dev0)"] name = "greenlet" version = "3.0.3" description = "Lightweight in-process concurrent programming" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1258,6 +1320,7 @@ test = ["objgraph", "psutil"] name = "grpcio" version = "1.60.1" description = "HTTP/2-based RPC framework" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1324,6 +1387,7 @@ protobuf = ["grpcio-tools (>=1.60.1)"] name = "grpcio-tools" version = "1.60.1" description = "Protobuf code generator for gRPC" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1392,6 +1456,7 @@ setuptools = "*" name = "gunicorn" version = "21.2.0" description = "WSGI HTTP Server for UNIX" +category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1412,6 +1477,7 @@ tornado = ["tornado (>=0.2)"] name = "h11" version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1423,6 +1489,7 @@ files = [ name = "humanfriendly" version = "10.0" description = "Human friendly output for text interfaces using Python" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -1437,6 +1504,7 @@ pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_ve name = "identify" version = "2.5.33" description = "File identification library for Python" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1451,6 +1519,7 @@ license = ["ukkonen"] name = "idna" version = "2.10" description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1462,6 +1531,7 @@ files = [ name = "ijson" version = "3.2.3" description = "Iterative JSON parser with standard Python iterator interfaces" +category = "main" optional = false python-versions = "*" files = [ @@ -1560,6 +1630,7 @@ files = [ name = "importlib-metadata" version = "7.0.1" description = "Read metadata from Python packages" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1579,6 +1650,7 @@ testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1586,10 +1658,26 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "isort" +version = "5.13.2" +description = "A Python utility / library to sort Python imports." +category = "dev" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, + {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, +] + +[package.extras] +colors = ["colorama (>=0.4.6)"] + [[package]] name = "jinja2" version = "3.1.3" description = "A very fast and expressive template engine." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1607,6 +1695,7 @@ i18n = ["Babel (>=2.7)"] name = "jmespath" version = "1.0.1" description = "JSON Matching Expressions" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1618,6 +1707,7 @@ files = [ name = "jsonpatch" version = "1.32" description = "Apply JSON-Patches (RFC 6902)" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -1632,6 +1722,7 @@ jsonpointer = ">=1.9" name = "jsonpointer" version = "2.4" description = "Identify specific nodes in a JSON document (RFC 6901)" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" files = [ @@ -1643,6 +1734,7 @@ files = [ name = "jsonref" version = "1.1.0" description = "jsonref is a library for automatic dereferencing of JSON Reference objects for Python." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1654,6 +1746,7 @@ files = [ name = "jsonschema" version = "4.21.1" description = "An implementation of JSON Schema validation for Python" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1675,6 +1768,7 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339- name = "jsonschema-specifications" version = "2023.12.1" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1689,6 +1783,7 @@ referencing = ">=0.31.0" name = "markdown" version = "3.5.2" description = "Python implementation of John Gruber's Markdown." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1704,6 +1799,7 @@ testing = ["coverage", "pyyaml"] name = "markupsafe" version = "2.1.5" description = "Safely add untrusted strings to HTML/XML markup." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1769,10 +1865,23 @@ files = [ {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + [[package]] name = "memory-profiler" version = "0.61.0" description = "A module for monitoring memory usage of a python program" +category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1787,6 +1896,7 @@ psutil = "*" name = "ministryofjustice-data-platform-catalogue" version = "0.15.0" description = "Library to integrate the MoJ data platform with the catalogue component." +category = "main" optional = false python-versions = ">=3.10,<4.0" files = [ @@ -1804,6 +1914,7 @@ openmetadata-ingestion = ">=1.2.0.1,<1.3.0.0" name = "mixpanel" version = "4.10.0" description = "Official Mixpanel library for Python" +category = "main" optional = false python-versions = ">=2.7, !=3.4.*" files = [ @@ -1820,6 +1931,7 @@ urllib3 = "*" name = "multidict" version = "6.0.5" description = "multidict implementation" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1919,6 +2031,7 @@ files = [ name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." +category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1930,6 +2043,7 @@ files = [ name = "networkx" version = "3.2.1" description = "Python package for creating and manipulating graphs and networks" +category = "main" optional = false python-versions = ">=3.9" files = [ @@ -1948,6 +2062,7 @@ test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] name = "nodeenv" version = "1.8.0" description = "Node.js virtual environment builder" +category = "dev" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" files = [ @@ -1962,6 +2077,7 @@ setuptools = "*" name = "openmetadata-ingestion" version = "1.2.5.1" description = "Ingestion Framework for OpenMetadata" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2073,6 +2189,7 @@ vertica = ["sqlalchemy-vertica[vertica-python] (>=0.0.5)"] name = "ordered-set" version = "4.1.0" description = "An OrderedSet is a custom MutableSet that remembers its order, so that every" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2087,6 +2204,7 @@ dev = ["black", "mypy", "pytest"] name = "outcome" version = "1.3.0.post0" description = "Capture the outcome of Python function calls." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2101,6 +2219,7 @@ attrs = ">=19.2.0" name = "packaging" version = "23.2" description = "Core utilities for Python packages" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2112,6 +2231,7 @@ files = [ name = "pathspec" version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2123,6 +2243,7 @@ files = [ name = "platformdirs" version = "4.2.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -2138,6 +2259,7 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest- name = "pluggy" version = "1.4.0" description = "plugin and hook calling mechanisms for python" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2153,6 +2275,7 @@ testing = ["pytest", "pytest-benchmark"] name = "pre-commit" version = "3.6.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." +category = "dev" optional = false python-versions = ">=3.9" files = [ @@ -2171,6 +2294,7 @@ virtualenv = ">=20.10.0" name = "progressbar2" version = "4.3.2" description = "A Python Progressbar library to provide visual (yet text based) progress to long running operations." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2189,6 +2313,7 @@ tests = ["dill (>=0.3.6)", "flake8 (>=3.7.7)", "freezegun (>=0.3.11)", "pytest ( name = "protobuf" version = "4.25.2" description = "" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2209,6 +2334,7 @@ files = [ name = "psutil" version = "5.9.8" description = "Cross-platform lib for process and system monitoring in Python." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ @@ -2237,6 +2363,7 @@ test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] name = "pyasn1" version = "0.5.1" description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" +category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ @@ -2248,6 +2375,7 @@ files = [ name = "pyasn1-modules" version = "0.3.0" description = "A collection of ASN.1-based protocols modules" +category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ @@ -2258,10 +2386,23 @@ files = [ [package.dependencies] pyasn1 = ">=0.4.6,<0.6.0" +[[package]] +name = "pycodestyle" +version = "2.11.1" +description = "Python style guide checker" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"}, + {file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"}, +] + [[package]] name = "pycparser" version = "2.21" description = "C parser in Python" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2273,6 +2414,7 @@ files = [ name = "pydantic" version = "1.10.14" description = "Data validation and settings management using python type hints" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2321,10 +2463,23 @@ typing-extensions = ">=4.2.0" dotenv = ["python-dotenv (>=0.10.4)"] email = ["email-validator (>=1.0.3)"] +[[package]] +name = "pyflakes" +version = "3.1.0" +description = "passive checker of Python programs" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pyflakes-3.1.0-py2.py3-none-any.whl", hash = "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774"}, + {file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"}, +] + [[package]] name = "pygments" version = "2.17.2" description = "Pygments is a syntax highlighting package written in Python." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2340,6 +2495,7 @@ windows-terminal = ["colorama (>=0.4.6)"] name = "pymysql" version = "1.1.0" description = "Pure Python MySQL Driver" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2351,10 +2507,26 @@ files = [ ed25519 = ["PyNaCl (>=1.4.0)"] rsa = ["cryptography"] +[[package]] +name = "pyproject-flake8" +version = "6.1.0" +description = "pyproject-flake8 (`pflake8`), a monkey patching wrapper to connect flake8 with pyproject.toml configuration" +category = "dev" +optional = false +python-versions = ">=3.8.1" +files = [ + {file = "pyproject_flake8-6.1.0-py3-none-any.whl", hash = "sha256:86ea5559263c098e1aa4f866776aa2cf45362fd91a576b9fd8fbbbb55db12c4e"}, + {file = "pyproject_flake8-6.1.0.tar.gz", hash = "sha256:6da8e5a264395e0148bc11844c6fb50546f1fac83ac9210f7328664135f9e70f"}, +] + +[package.dependencies] +flake8 = "6.1.0" + [[package]] name = "pyreadline3" version = "3.4.1" description = "A python implementation of GNU readline." +category = "main" optional = false python-versions = "*" files = [ @@ -2366,6 +2538,7 @@ files = [ name = "pysocks" version = "1.7.1" description = "A Python SOCKS client module. See https://github.com/Anorov/PySocks for more information." +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2378,6 +2551,7 @@ files = [ name = "pytest" version = "8.0.0" description = "pytest: simple powerful testing with Python" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2398,6 +2572,7 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no name = "pytest-cov" version = "4.1.0" description = "Pytest plugin for measuring coverage." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2416,6 +2591,7 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale name = "pytest-django" version = "4.8.0" description = "A Django plugin for pytest." +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -2434,6 +2610,7 @@ testing = ["Django", "django-configurations (>=2.0)"] name = "python-dateutil" version = "2.8.2" description = "Extensions to the standard Python datetime module" +category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ @@ -2448,6 +2625,7 @@ six = ">=1.5" name = "python-dotenv" version = "1.0.1" description = "Read key-value pairs from a .env file and set them as environment variables" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2462,6 +2640,7 @@ cli = ["click (>=5.0)"] name = "python-jose" version = "3.3.0" description = "JOSE implementation in Python" +category = "main" optional = false python-versions = "*" files = [ @@ -2483,6 +2662,7 @@ pycryptodome = ["pyasn1", "pycryptodome (>=3.3.1,<4.0.0)"] name = "python-utils" version = "3.8.2" description = "Python Utils is a module with some convenient utilities not included with the standard Python install" +category = "main" optional = false python-versions = ">3.8.0" files = [ @@ -2502,6 +2682,7 @@ tests = ["flake8", "loguru", "pytest", "pytest-asyncio", "pytest-cov", "pytest-m name = "pywin32" version = "306" description = "Python for Window Extensions" +category = "main" optional = false python-versions = "*" files = [ @@ -2525,6 +2706,7 @@ files = [ name = "pyyaml" version = "6.0.1" description = "YAML parser and emitter for Python" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -2584,6 +2766,7 @@ files = [ name = "referencing" version = "0.33.0" description = "JSON Referencing + Python" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2599,6 +2782,7 @@ rpds-py = ">=0.7.0" name = "regex" version = "2023.12.25" description = "Alternative regular expression module, to replace re." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2701,6 +2885,7 @@ files = [ name = "requests" version = "2.31.0" description = "Python HTTP for Humans." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2722,6 +2907,7 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] name = "requests-aws4auth" version = "1.2.3" description = "AWS4 authentication for Requests" +category = "main" optional = false python-versions = ">=3.3" files = [ @@ -2740,6 +2926,7 @@ httpx = ["httpx"] name = "requests-file" version = "2.0.0" description = "File transport adapter for Requests" +category = "main" optional = false python-versions = "*" files = [ @@ -2754,6 +2941,7 @@ requests = ">=1.0.0" name = "rpds-py" version = "0.17.1" description = "Python bindings to Rust's persistent data structures (rpds)" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2862,6 +3050,7 @@ files = [ name = "rsa" version = "4.9" description = "Pure-Python RSA implementation" +category = "main" optional = false python-versions = ">=3.6,<4" files = [ @@ -2876,6 +3065,7 @@ pyasn1 = ">=0.1.3" name = "ruamel-yaml" version = "0.18.5" description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2894,6 +3084,7 @@ jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] name = "ruamel-yaml-clib" version = "0.2.8" description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -2953,6 +3144,7 @@ files = [ name = "s3transfer" version = "0.10.0" description = "An Amazon S3 Transfer Manager" +category = "main" optional = false python-versions = ">= 3.8" files = [ @@ -2970,6 +3162,7 @@ crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"] name = "selenium" version = "4.17.2" description = "" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -2988,6 +3181,7 @@ urllib3 = {version = ">=1.26,<3", extras = ["socks"]} name = "sentry-sdk" version = "1.40.0" description = "Python client for Sentry (https://sentry.io)" +category = "main" optional = false python-versions = "*" files = [ @@ -3033,6 +3227,7 @@ tornado = ["tornado (>=5)"] name = "setuptools" version = "66.0.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3049,6 +3244,7 @@ testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs ( name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -3060,6 +3256,7 @@ files = [ name = "sniffio" version = "1.3.0" description = "Sniff out which async library your code is running under" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3071,6 +3268,7 @@ files = [ name = "sortedcontainers" version = "2.4.0" description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" +category = "dev" optional = false python-versions = "*" files = [ @@ -3082,6 +3280,7 @@ files = [ name = "soupsieve" version = "2.5" description = "A modern CSS selector implementation for Beautiful Soup." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -3093,6 +3292,7 @@ files = [ name = "sqlalchemy" version = "1.4.51" description = "Database Abstraction Library" +category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ @@ -3172,6 +3372,7 @@ sqlcipher = ["sqlcipher3_binary"] name = "sqlfluff" version = "2.3.5" description = "The SQL Linter for Humans" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3198,6 +3399,7 @@ typing-extensions = "*" name = "sqlparse" version = "0.4.4" description = "A non-validating SQL parser." +category = "main" optional = false python-versions = ">=3.5" files = [ @@ -3214,6 +3416,7 @@ test = ["pytest", "pytest-cov"] name = "tabulate" version = "0.9.0" description = "Pretty-print tabular data" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3228,6 +3431,7 @@ widechars = ["wcwidth"] name = "tblib" version = "3.0.0" description = "Traceback serialization library." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -3239,6 +3443,7 @@ files = [ name = "termcolor" version = "2.4.0" description = "ANSI color formatting for output in terminal" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -3253,6 +3458,7 @@ tests = ["pytest", "pytest-cov"] name = "toml" version = "0.10.2" description = "Python Library for Tom's Obvious, Minimal Language" +category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -3264,6 +3470,7 @@ files = [ name = "tqdm" version = "4.66.1" description = "Fast, Extensible Progress Meter" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3284,6 +3491,7 @@ telegram = ["requests"] name = "trio" version = "0.24.0" description = "A friendly Python library for async concurrency and I/O" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -3303,6 +3511,7 @@ sortedcontainers = "*" name = "trio-websocket" version = "0.11.1" description = "WebSocket library for Trio" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3318,6 +3527,7 @@ wsproto = ">=0.14" name = "typing-compat" version = "0.1.0" description = "Python typing compatibility library" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -3329,6 +3539,7 @@ files = [ name = "typing-extensions" version = "4.9.0" description = "Backported and Experimental Type Hints for Python 3.8+" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -3340,6 +3551,7 @@ files = [ name = "typing-inspect" version = "0.9.0" description = "Runtime inspection utilities for typing module." +category = "main" optional = false python-versions = "*" files = [ @@ -3355,6 +3567,7 @@ typing-extensions = ">=3.7.4" name = "tzdata" version = "2023.4" description = "Provider of IANA time zone data" +category = "main" optional = false python-versions = ">=2" files = [ @@ -3366,6 +3579,7 @@ files = [ name = "urllib3" version = "2.0.7" description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3386,6 +3600,7 @@ zstd = ["zstandard (>=0.18.0)"] name = "virtualenv" version = "20.25.0" description = "Virtual Python Environment builder" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3406,6 +3621,7 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess name = "wheel" version = "0.38.4" description = "A built-package format for Python" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3420,6 +3636,7 @@ test = ["pytest (>=3.0.0)"] name = "whitenoise" version = "6.6.0" description = "Radically simplified static file serving for WSGI applications" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -3434,6 +3651,7 @@ brotli = ["Brotli"] name = "wrapt" version = "1.16.0" description = "Module for decorators, wrappers and monkey patching." +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -3513,6 +3731,7 @@ files = [ name = "wsproto" version = "1.2.0" description = "WebSockets state-machine based protocol implementation" +category = "dev" optional = false python-versions = ">=3.7.0" files = [ @@ -3527,6 +3746,7 @@ h11 = ">=0.9.0,<1" name = "yarl" version = "1.9.4" description = "Yet another URL library" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3630,6 +3850,7 @@ multidict = ">=4.0" name = "zipp" version = "3.17.0" description = "Backport of pathlib-compatible object wrapper for zip files" +category = "main" optional = false python-versions = ">=3.8" files = [ diff --git a/pyproject.toml b/pyproject.toml index 8d3bee75..b29b195c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,17 +14,17 @@ whitenoise = "^6.6.0" ministryofjustice-data-platform-catalogue = "^0.15.0" markdown = "^3.5.2" python-dotenv = "^1.0.1" -faker = "^22.6.0" -selenium = "^4.17.2" -pytest-django = "^4.8.0" -pytest-cov = "^4.1.0" - -[tool.poetry.group.dev] # dev group definition [tool.poetry.group.dev.dependencies] black = "^23.12.1" pre-commit = "^3.6.0" -selenium = ">=4.8.0" +selenium = "^4.17.2" +flake8 = ">=6.1.0" +pytest-django = "^4.8.0" +pytest-cov = "^4.1.0" +faker = "^22.6.0" +isort = "^5.13.2" +pyproject-flake8 = "^6.1.0" [build-system] requires = ["poetry-core"] @@ -34,3 +34,6 @@ build-backend = "poetry.core.masonry.api" DJANGO_SETTINGS_MODULE = "core.settings" python_files = ["test_*.py", "*_test.py", "testing/python/*.py"] markers = ["slow: marks tests as slow (deselect with '-m \"not slow\"')"] + +[tool.isort] +profile = "black" diff --git a/templates/base/base.html b/templates/base/base.html index 05f235e1..4441cbd2 100644 --- a/templates/base/base.html +++ b/templates/base/base.html @@ -48,4 +48,4 @@ {% block scripts %} {% endblock scripts %} - \ No newline at end of file + diff --git a/templates/base/error/page_not_found.html b/templates/base/error/page_not_found.html index 9e8db9b9..45d239e9 100644 --- a/templates/base/error/page_not_found.html +++ b/templates/base/error/page_not_found.html @@ -15,4 +15,4 @@

    Page not found

    - \ No newline at end of file + diff --git a/templates/base/head.html b/templates/base/head.html index 452857ef..da3dfed9 100644 --- a/templates/base/head.html +++ b/templates/base/head.html @@ -12,4 +12,4 @@ - \ No newline at end of file + diff --git a/templates/home.html b/templates/home.html index 0bb8fb40..ba8879e8 100644 --- a/templates/home.html +++ b/templates/home.html @@ -6,5 +6,4 @@ Back

    Customised page template

    - {% endblock content %} diff --git a/templates/partial/filter.html b/templates/partial/filter.html index 6ab6f185..e7af7286 100644 --- a/templates/partial/filter.html +++ b/templates/partial/filter.html @@ -1,4 +1,5 @@ {% load future %} +{% load clear_filter %}
    @@ -8,35 +9,8 @@

    Filter

    -
    -
    -
    -
    -

    Selected filters

    -
    - -
    - {% if form.domains.value %} -

    Domain

    - - {% endif %} -
    + {% include "partial/selected_filters.html" %}
    Data Product contentData product content
    Table name
    {{table.name}}{{table.description}} + {% if table.description|length > 200 %} + {{ table.description|slice:":200"|add:"..."|markdown }} + {% else %} + {{ table.description|markdown }} + {% endif %} + Schema details