From 9b88ab906b4d77a98fe509d295af2d7d08861612 Mon Sep 17 00:00:00 2001 From: Sushil Tiwari Date: Thu, 20 Feb 2025 15:37:48 +0545 Subject: [PATCH 01/17] Remove title generation for emergency --- api/admin.py | 5 +- api/factories/event.py | 1 - ...nt_title_remove_event_title_ar_and_more.py | 82 ++++++++++++ api/models.py | 68 ++++------ api/receivers.py | 9 -- api/serializers.py | 4 +- api/test_models.py | 14 +- api/test_views.py | 4 +- api/translation.py | 3 +- deployments/snapshots/snap_tests.py | 122 +++++++++--------- deployments/tests.py | 2 +- lang/tests.py | 2 + 12 files changed, 186 insertions(+), 130 deletions(-) create mode 100644 api/migrations/0218_remove_event_title_remove_event_title_ar_and_more.py diff --git a/api/admin.py b/api/admin.py index 9ce4fa618..a37287c2a 100644 --- a/api/admin.py +++ b/api/admin.py @@ -225,7 +225,6 @@ class EventAdmin(CompareVersionAdmin, RegionRestrictedAdmin, TranslationAdmin): "districts", "parent_event", ) - readonly_fields = ("name",) def appeals(self, instance): if getattr(instance, "appeals").exists(): @@ -249,14 +248,12 @@ def changeform_view(self, request, *args, **kwargs): "field_reports", "auto_generated_source", "parent_event", - "name", ) else: self.readonly_fields = ( "appeals", "field_reports", "auto_generated_source", - "name", ) return super(EventAdmin, self).changeform_view(request, *args, **kwargs) @@ -340,7 +337,7 @@ class FieldReportAdmin(CompareVersionAdmin, RegionRestrictedAdmin, TranslationAd def create_events(self, request, queryset): for report in queryset: event = models.Event.objects.create( - title=report.title, + name=report.summary, dtype=getattr(report, "dtype"), disaster_start_date=getattr(report, "created_at"), auto_generated=True, diff --git a/api/factories/event.py b/api/factories/event.py index 71bf55b62..f3656a2e6 100644 --- a/api/factories/event.py +++ b/api/factories/event.py @@ -23,7 +23,6 @@ class Meta: model = Event name = fuzzy.FuzzyText(length=50) - title = fuzzy.FuzzyText(length=10) slug = fuzzy.FuzzyText(length=50) dtype = factory.SubFactory(DisasterTypeFactory) diff --git a/api/migrations/0218_remove_event_title_remove_event_title_ar_and_more.py b/api/migrations/0218_remove_event_title_remove_event_title_ar_and_more.py new file mode 100644 index 000000000..11783d683 --- /dev/null +++ b/api/migrations/0218_remove_event_title_remove_event_title_ar_and_more.py @@ -0,0 +1,82 @@ +# Generated by Django 4.2.17 on 2025-02-20 09:14 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("api", "0217_merge_20250107_1019"), + ] + + operations = [ + migrations.RemoveField( + model_name="event", + name="title", + ), + migrations.RemoveField( + model_name="event", + name="title_ar", + ), + migrations.RemoveField( + model_name="event", + name="title_en", + ), + migrations.RemoveField( + model_name="event", + name="title_es", + ), + migrations.RemoveField( + model_name="event", + name="title_fr", + ), + migrations.AlterField( + model_name="fieldreport", + name="title", + field=models.CharField( + blank=True, + help_text="Title is used to generate the summary/name of the Field Report.
The summary is constructed as: Country IS03: Disaster Type - Start Date - Title - Field Report Number - (date)", + max_length=256, + ), + ), + migrations.AlterField( + model_name="fieldreport", + name="title_ar", + field=models.CharField( + blank=True, + help_text="Title is used to generate the summary/name of the Field Report.
The summary is constructed as: Country IS03: Disaster Type - Start Date - Title - Field Report Number - (date)", + max_length=256, + null=True, + ), + ), + migrations.AlterField( + model_name="fieldreport", + name="title_en", + field=models.CharField( + blank=True, + help_text="Title is used to generate the summary/name of the Field Report.
The summary is constructed as: Country IS03: Disaster Type - Start Date - Title - Field Report Number - (date)", + max_length=256, + null=True, + ), + ), + migrations.AlterField( + model_name="fieldreport", + name="title_es", + field=models.CharField( + blank=True, + help_text="Title is used to generate the summary/name of the Field Report.
The summary is constructed as: Country IS03: Disaster Type - Start Date - Title - Field Report Number - (date)", + max_length=256, + null=True, + ), + ), + migrations.AlterField( + model_name="fieldreport", + name="title_fr", + field=models.CharField( + blank=True, + help_text="Title is used to generate the summary/name of the Field Report.
The summary is constructed as: Country IS03: Disaster Type - Start Date - Title - Field Report Number - (date)", + max_length=256, + null=True, + ), + ), + ] diff --git a/api/models.py b/api/models.py index 0a6872f76..d174f7fb0 100644 --- a/api/models.py +++ b/api/models.py @@ -742,6 +742,16 @@ class Event(models.Model): """A disaster, which could cover multiple countries""" name = models.CharField(verbose_name=_("name"), max_length=256) + dtype = models.ForeignKey(DisasterType, verbose_name=_("disaster type"), null=True, on_delete=models.SET_NULL) + disaster_start_date = models.DateTimeField(verbose_name=_("disaster start date")) + regions = models.ManyToManyField(Region, verbose_name=_("regions")) + countries = models.ManyToManyField(Country, verbose_name=_("countries")) + countries_for_preview = models.ManyToManyField( + Country, verbose_name=_("countries for preview"), blank=True, related_name="countries_for_preview" + ) + districts = models.ManyToManyField(District, verbose_name=_("districts"), blank=True) + # visibility + visibility = models.IntegerField(choices=VisibilityChoices.choices, verbose_name=_("visibility"), default=1) # Obsolete: slug is not editable until we resolve https://github.com/IFRCGo/go-frontend/issues/1013 slug = models.CharField( verbose_name=_("slug"), @@ -758,13 +768,6 @@ class Event(models.Model): " Recommend using hyphens over underscores. Special characters like # is not allowed." ), ) - dtype = models.ForeignKey(DisasterType, verbose_name=_("disaster type"), null=True, on_delete=models.SET_NULL) - districts = models.ManyToManyField(District, verbose_name=_("districts"), blank=True) - countries = models.ManyToManyField(Country, verbose_name=_("countries")) - countries_for_preview = models.ManyToManyField( - Country, verbose_name=_("countries for preview"), blank=True, related_name="countries_for_preview" - ) - regions = models.ManyToManyField(Region, verbose_name=_("regions")) parent_event = models.ForeignKey( "self", null=True, @@ -778,7 +781,6 @@ class Event(models.Model): ) image = models.ImageField(verbose_name=_("image"), null=True, blank=True, upload_to=snippet_image_path) summary = HTMLField(verbose_name=_("summary"), blank=True, default="") - title = models.CharField(max_length=256, blank=True) num_injured = models.IntegerField(verbose_name=_("number of injured"), null=True, blank=True) num_dead = models.IntegerField(verbose_name=_("number of dead"), null=True, blank=True) @@ -789,7 +791,6 @@ class Event(models.Model): ifrc_severity_level = models.IntegerField(choices=AlertLevel.choices, default=0, verbose_name=_("IFRC Severity level")) glide = models.CharField(verbose_name=_("glide"), max_length=18, blank=True) - disaster_start_date = models.DateTimeField(verbose_name=_("disaster start date")) created_at = models.DateTimeField(verbose_name=_("created at"), auto_now_add=True) updated_at = models.DateTimeField(verbose_name=_("updated at"), auto_now=True) previous_update = models.DateTimeField(verbose_name=_("previous update"), null=True, blank=True) @@ -816,8 +817,6 @@ class Event(models.Model): tab_two_title = models.CharField(verbose_name=_("tab two title"), max_length=50, null=True, blank=True) tab_three_title = models.CharField(verbose_name=_("tab three title"), max_length=50, null=True, blank=True) - # visibility - visibility = models.IntegerField(choices=VisibilityChoices.choices, verbose_name=_("visibility"), default=1) emergency_response_contact_email = models.CharField( verbose_name=_("emergency response contact email"), null=True, blank=True, max_length=255 ) @@ -873,15 +872,6 @@ def record_type(self): def to_dict(self): return to_dict(self) - def generate_formatted_name(self): - country_iso3 = self.countries.first().iso3 if self.id and self.countries.first() else "N/A" - disaster_start_date = self.disaster_start_date.strftime("%m-%Y") - for lang in AVAILABLE_LANGUAGES: - with translation_override(lang): - dtype = self.dtype.name if self.dtype else "N/A" - self.name = f"{country_iso3}: {dtype} - {disaster_start_date} - {self.title}" - yield build_localized_fieldname("name", lang) - def save(self, *args, **kwargs): # Make the slug lowercase @@ -892,15 +882,6 @@ def save(self, *args, **kwargs): if not self.id and not self.disaster_start_date: self.disaster_start_date = timezone.now() - updated_name_fields = list(self.generate_formatted_name()) - - # Updating the updated_fields with the fields that are updated - if kwargs.get("update_fields"): - kwargs["update_fields"] = ( - *kwargs["update_fields"], - *updated_name_fields, - ) - return super(Event, self).save(*args, **kwargs) def __str__(self): @@ -1479,21 +1460,31 @@ class RecentAffected(models.IntegerChoices): default=False, help_text=_("Is this a Field Report specific to the COVID-19 emergency?"), ) - - # Used to differentiate reports that have and have not been synced from DMIS - rid = models.CharField(verbose_name=_("r id"), max_length=100, null=True, blank=True, editable=False) - summary = models.TextField(verbose_name=_("summary"), blank=True) # Title field is used for the translation and later adding formated into the summary - title = models.CharField(max_length=256, blank=True) - fr_num = models.IntegerField(verbose_name=_("field report number"), null=True, blank=True) + title = models.CharField( + max_length=256, + blank=True, + help_text=_( + "Title is used to generate the summary/name of the Field Report.
" + "The summary is constructed as: " + "Country IS03: Disaster Type - Start Date - Title - Field Report Number - (date)" + ), + ) description = HTMLField(verbose_name=_("description"), blank=True, default="") dtype = models.ForeignKey(DisasterType, verbose_name=_("disaster type"), on_delete=models.PROTECT) event = models.ForeignKey( Event, verbose_name=_("event"), related_name="field_reports", null=True, blank=True, on_delete=models.SET_NULL ) - districts = models.ManyToManyField(District, verbose_name=_("districts"), blank=True) - countries = models.ManyToManyField(Country, verbose_name=_("countries")) regions = models.ManyToManyField(Region, verbose_name=_("regions"), blank=True) + countries = models.ManyToManyField(Country, verbose_name=_("countries")) + districts = models.ManyToManyField(District, verbose_name=_("districts"), blank=True) + # visibility + visibility = models.IntegerField(choices=VisibilityChoices.choices, verbose_name=_("visibility"), default=1) + # Used to differentiate reports that have and have not been synced from DMIS + rid = models.CharField(verbose_name=_("r id"), max_length=100, null=True, blank=True, editable=False) + summary = models.TextField(verbose_name=_("summary"), blank=True) + + fr_num = models.IntegerField(verbose_name=_("field report number"), null=True, blank=True) # This entity is more a type than a status, so let's label it this way on admin page: status = models.IntegerField( choices=Status.choices, @@ -1582,9 +1573,6 @@ class RecentAffected(models.IntegerChoices): # actions taken actions_others = models.TextField(verbose_name=_("actions taken (others)"), null=True, blank=True) - # visibility - visibility = models.IntegerField(choices=VisibilityChoices.choices, verbose_name=_("visibility"), default=1) - # information bulletin = models.IntegerField(choices=RequestChoices.choices, verbose_name=_("bulletin"), default=0, null=True) dref = models.IntegerField(choices=RequestChoices.choices, verbose_name=_("DREF"), default=0, null=True) diff --git a/api/receivers.py b/api/receivers.py index b8f182e3f..dfa57a304 100644 --- a/api/receivers.py +++ b/api/receivers.py @@ -288,15 +288,6 @@ def remove_appeal_filter(sender, instance, using, **kwargs): appealFilter.save() -@receiver(m2m_changed, sender=Event.countries.through) -def update_event_name(sender, instance, action, **kwargs): - """ - Update the event name when the countries are changed. - """ - if action in ["post_add", "post_remove"]: - instance.save() - - @receiver(m2m_changed, sender=FieldReport.countries.through) def update_fieldreport_summary(sender, instance, action, **kwargs): """ diff --git a/api/serializers.py b/api/serializers.py index 75e1ac9d9..60cccc9d8 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -1164,7 +1164,6 @@ class Meta: "dtype", "countries", "summary", - "title", "num_affected", "ifrc_severity_level", "ifrc_severity_level_display", @@ -1300,7 +1299,6 @@ class Meta: "countries", "districts", "summary", - "title", "num_affected", "tab_two_title", "tab_three_title", @@ -2058,7 +2056,7 @@ class Meta: def create_event(self, report): event = Event.objects.create( - title=report.title, + name=report.summary, dtype=report.dtype, summary=report.description or "", disaster_start_date=report.start_date, diff --git a/api/test_models.py b/api/test_models.py index 1038f3505..f63d3355c 100644 --- a/api/test_models.py +++ b/api/test_models.py @@ -26,14 +26,14 @@ class EventTest(TestCase): def setUp(self): dtype = models.DisasterType.objects.get(pk=1) - models.Event.objects.create(title="disaster1", summary="test disaster", dtype=dtype) - event = models.Event.objects.create(title="disaster2", summary="another test disaster", dtype=dtype) + models.Event.objects.create(name="disaster1", summary="test disaster", dtype=dtype) + event = models.Event.objects.create(name="disaster2", summary="another test disaster", dtype=dtype) models.KeyFigure.objects.create(event=event, number=7, deck="things", source="website") models.Snippet.objects.create(event=event, snippet="this is a snippet") def test_disaster_create(self): - obj1 = models.Event.objects.get(title="disaster1") - obj2 = models.Event.objects.get(title="disaster2") + obj1 = models.Event.objects.get(name="disaster1") + obj2 = models.Event.objects.get(name="disaster2") self.assertEqual(obj1.summary, "test disaster") self.assertEqual(obj2.summary, "another test disaster") keyfig = obj2.key_figures.all() @@ -68,7 +68,7 @@ def test_profile_create(self): class AppealTest(APITestCase): def setUp(self): # An appeal with needs_confirmation=True should not return the event in the API response. - event = models.Event.objects.create(title="associated event", summary="foo") + event = models.Event.objects.create(name="associated event", summary="foo") country = models.Country.objects.create(name="country") models.Appeal.objects.create( aid="test1", name="appeal", atype=1, code="abc", needs_confirmation=True, event=event, country=country @@ -87,13 +87,13 @@ class FieldReportTest(TestCase): def setUp(self): dtype = models.DisasterType.objects.get(pk=1) - event = models.Event.objects.create(title="disaster1", summary="test disaster", dtype=dtype) + event = models.Event.objects.create(name="disaster1", summary="test disaster", dtype=dtype) country = models.Country.objects.create(name="country") report = models.FieldReport.objects.create(rid="test1", event=event, dtype=dtype) report.countries.add(country) def test_field_report_create(self): - event = models.Event.objects.get(title="disaster1") + event = models.Event.objects.get(name="disaster1") country = models.Country.objects.get(name="country") self.assertEqual(event.field_reports.all()[0].countries.all()[0], country) obj = models.FieldReport.objects.get(rid="test1") diff --git a/api/test_views.py b/api/test_views.py index 4b9cff70c..f4f67b945 100644 --- a/api/test_views.py +++ b/api/test_views.py @@ -308,7 +308,7 @@ def test_sit_rep_types(self): type1 = models.SituationReportType.objects.create(type="Lyric") type2 = models.SituationReportType.objects.create(type="Epic") dtype1 = models.DisasterType.objects.get(pk=1) - event1 = models.Event.objects.create(title="disaster1", summary="test disaster1", dtype=dtype1) + event1 = models.Event.objects.create(name="disaster1", summary="test disaster1", dtype=dtype1) models.SituationReport.objects.create(name="test1", event=event1, type=type1, visibility=3) models.SituationReport.objects.create(name="test2", event=event1, type=type2, visibility=3) @@ -386,7 +386,7 @@ def test_create_and_update(self): self.assertEqual(created.title_en, "test") # created an emergency automatically - self.assertEqual(created.event.title, "test") + self.assertEqual(created.event.name, response["summary"]) # event_pk = created.event.id # body['countries'] = [country2.id] diff --git a/api/translation.py b/api/translation.py index a68847800..c801b355b 100644 --- a/api/translation.py +++ b/api/translation.py @@ -78,8 +78,7 @@ class DisasterTypeTO(TranslationOptions): @register(Event) class EventTO(TranslationOptions): - fields = ("name", "summary", "title") - skip_fields = ("name",) # XXX: CUSTOM field Not used by TranslationOptions, but used in lang/tasks.py + fields = ("name", "summary") @register(ExternalPartner) diff --git a/deployments/snapshots/snap_tests.py b/deployments/snapshots/snap_tests.py index 13256c5da..efb4e9f1b 100644 --- a/deployments/snapshots/snap_tests.py +++ b/deployments/snapshots/snap_tests.py @@ -91,16 +91,16 @@ snapshots[ "TestProjectAPI::test_project_csv_api 1" ] = """actual_expenditure,budget_amount,description,document,dtype,dtype_detail.id,dtype_detail.name,dtype_detail.summary,dtype_detail.translation_module_original_language,end_date,event,event_detail.dtype,event_detail.emergency_response_contact_email,event_detail.id,event_detail.name,event_detail.parent_event,event_detail.slug,event_detail.start_date,event_detail.translation_module_original_language,id,modified_at,modified_by,modified_by_detail,name,operation_type,operation_type_display,primary_sector,primary_sector_display,programme_type,programme_type_display,project_country,project_country_detail.id,project_country_detail.iso,project_country_detail.iso3,project_country_detail.name,project_country_detail.society_name,project_districts_detail.code,project_districts_detail.id,project_districts_detail.is_deprecated,project_districts_detail.is_enclave,project_districts_detail.name,reached_female,reached_male,reached_other,reached_total,regional_project,regional_project_detail.created_at,regional_project_detail.id,regional_project_detail.modified_at,regional_project_detail.name,regional_project_detail.translation_module_original_language,regional_project_detail.translation_module_skip_auto_translation,reporting_ns,reporting_ns_contact_email,reporting_ns_contact_name,reporting_ns_contact_role,reporting_ns_detail.id,reporting_ns_detail.iso,reporting_ns_detail.iso3,reporting_ns_detail.name,reporting_ns_detail.society_name,secondary_sectors,secondary_sectors_display,start_date,status,status_display,target_female,target_male,target_other,target_total,translation_module_original_language,translation_module_skip_auto_translation,user,visibility,visibility_display\r -0,100000,,,1,1,disaster-type-1,summary,en,2008-01-01,2,1,,2,rpo: disaster-type-1 - 03-2016 - event-1,1,event-slug,,en,1,2008-01-01T00:00:00.123456Z,,,project-1,1,Emergency Operation,1,sect-1,0,Bilateral,1,1,bV,rpo,country-1,society-name-1,"dct1, dct2","1, 2","True, False","False, True","district-1, district-2",0,0,0,0,1,2008-01-01T00:00:00.123456Z,1,2008-01-01T00:00:00.123456Z,regional-project-1,en,False,1,,,,1,bV,rpo,country-1,society-name-1,"1, 2","sec-tag-1, sec-tag-2",2008-01-01,1,Ongoing,0,0,0,0,en,False,5,public,Public\r -0,100000,,,1,1,disaster-type-1,summary,en,2008-01-01,2,1,,2,rpo: disaster-type-1 - 03-2016 - event-1,1,event-slug,,en,2,2008-01-01T00:00:00.123456Z,,,project-1,1,Emergency Operation,1,sect-1,0,Bilateral,1,1,bV,rpo,country-1,society-name-1,"dct1, dct2","1, 2","True, False","False, True","district-1, district-2",0,0,0,0,1,2008-01-01T00:00:00.123456Z,1,2008-01-01T00:00:00.123456Z,regional-project-1,en,False,1,,,,1,bV,rpo,country-1,society-name-1,"1, 2","sec-tag-1, sec-tag-2",2008-01-01,1,Ongoing,0,0,0,0,en,False,6,public,Public\r -0,100000,,,1,1,disaster-type-1,summary,en,2008-01-01,2,1,,2,rpo: disaster-type-1 - 03-2016 - event-1,1,event-slug,,en,3,2008-01-01T00:00:00.123456Z,,,project-1,1,Emergency Operation,1,sect-1,0,Bilateral,1,1,bV,rpo,country-1,society-name-1,"dct1, dct2","1, 2","True, False","False, True","district-1, district-2",0,0,0,0,1,2008-01-01T00:00:00.123456Z,1,2008-01-01T00:00:00.123456Z,regional-project-1,en,False,1,,,,1,bV,rpo,country-1,society-name-1,"1, 2","sec-tag-1, sec-tag-2",2008-01-01,1,Ongoing,0,0,0,0,en,False,7,public,Public\r -0,100000,,,1,1,disaster-type-1,summary,en,2008-01-01,2,1,,2,rpo: disaster-type-1 - 03-2016 - event-1,1,event-slug,,en,4,2008-01-01T00:00:00.123456Z,,,project-1,1,Emergency Operation,1,sect-1,0,Bilateral,1,1,bV,rpo,country-1,society-name-1,"dct1, dct2","1, 2","True, False","False, True","district-1, district-2",0,0,0,0,1,2008-01-01T00:00:00.123456Z,1,2008-01-01T00:00:00.123456Z,regional-project-1,en,False,1,,,,1,bV,rpo,country-1,society-name-1,"1, 2","sec-tag-1, sec-tag-2",2008-01-01,1,Ongoing,0,0,0,0,en,False,8,public,Public\r -0,100000,,,1,1,disaster-type-1,summary,en,2008-01-01,2,1,,2,rpo: disaster-type-1 - 03-2016 - event-1,1,event-slug,,en,5,2008-01-01T00:00:00.123456Z,,,project-1,1,Emergency Operation,1,sect-1,0,Bilateral,1,1,bV,rpo,country-1,society-name-1,"dct1, dct2","1, 2","True, False","False, True","district-1, district-2",0,0,0,0,1,2008-01-01T00:00:00.123456Z,1,2008-01-01T00:00:00.123456Z,regional-project-1,en,False,1,,,,1,bV,rpo,country-1,society-name-1,"1, 2","sec-tag-1, sec-tag-2",2008-01-01,1,Ongoing,0,0,0,0,en,False,9,public,Public\r -0,100000,,,1,1,disaster-type-1,summary,en,2008-01-01,2,1,,2,rpo: disaster-type-1 - 03-2016 - event-1,1,event-slug,,en,6,2008-01-01T00:00:00.123456Z,,,project-1,1,Emergency Operation,1,sect-1,0,Bilateral,1,1,bV,rpo,country-1,society-name-1,"dct1, dct2","1, 2","True, False","False, True","district-1, district-2",0,0,0,0,1,2008-01-01T00:00:00.123456Z,1,2008-01-01T00:00:00.123456Z,regional-project-1,en,False,1,,,,1,bV,rpo,country-1,society-name-1,"1, 2","sec-tag-1, sec-tag-2",2008-01-01,1,Ongoing,0,0,0,0,en,False,10,public,Public\r -0,100000,,,1,1,disaster-type-1,summary,en,2008-01-01,2,1,,2,rpo: disaster-type-1 - 03-2016 - event-1,1,event-slug,,en,7,2008-01-01T00:00:00.123456Z,,,project-1,1,Emergency Operation,1,sect-1,0,Bilateral,1,1,bV,rpo,country-1,society-name-1,"dct1, dct2","1, 2","True, False","False, True","district-1, district-2",0,0,0,0,1,2008-01-01T00:00:00.123456Z,1,2008-01-01T00:00:00.123456Z,regional-project-1,en,False,1,,,,1,bV,rpo,country-1,society-name-1,"1, 2","sec-tag-1, sec-tag-2",2008-01-01,1,Ongoing,0,0,0,0,en,False,11,public,Public\r -0,100000,,,1,1,disaster-type-1,summary,en,2008-01-01,2,1,,2,rpo: disaster-type-1 - 03-2016 - event-1,1,event-slug,,en,8,2008-01-01T00:00:00.123456Z,,,project-1,1,Emergency Operation,1,sect-1,0,Bilateral,1,1,bV,rpo,country-1,society-name-1,"dct1, dct2","1, 2","True, False","False, True","district-1, district-2",0,0,0,0,1,2008-01-01T00:00:00.123456Z,1,2008-01-01T00:00:00.123456Z,regional-project-1,en,False,1,,,,1,bV,rpo,country-1,society-name-1,"1, 2","sec-tag-1, sec-tag-2",2008-01-01,1,Ongoing,0,0,0,0,en,False,12,public,Public\r -0,100000,,,1,1,disaster-type-1,summary,en,2008-01-01,2,1,,2,rpo: disaster-type-1 - 03-2016 - event-1,1,event-slug,,en,9,2008-01-01T00:00:00.123456Z,,,project-1,1,Emergency Operation,1,sect-1,0,Bilateral,1,1,bV,rpo,country-1,society-name-1,"dct1, dct2","1, 2","True, False","False, True","district-1, district-2",0,0,0,0,1,2008-01-01T00:00:00.123456Z,1,2008-01-01T00:00:00.123456Z,regional-project-1,en,False,1,,,,1,bV,rpo,country-1,society-name-1,"1, 2","sec-tag-1, sec-tag-2",2008-01-01,1,Ongoing,0,0,0,0,en,False,13,public,Public\r -0,100000,,,1,1,disaster-type-1,summary,en,2008-01-01,2,1,,2,rpo: disaster-type-1 - 03-2016 - event-1,1,event-slug,,en,10,2008-01-01T00:00:00.123456Z,,,project-1,1,Emergency Operation,1,sect-1,0,Bilateral,1,1,bV,rpo,country-1,society-name-1,"dct1, dct2","1, 2","True, False","False, True","district-1, district-2",0,0,0,0,1,2008-01-01T00:00:00.123456Z,1,2008-01-01T00:00:00.123456Z,regional-project-1,en,False,1,,,,1,bV,rpo,country-1,society-name-1,"1, 2","sec-tag-1, sec-tag-2",2008-01-01,1,Ongoing,0,0,0,0,en,False,14,public,Public\r +0,100000,,,1,1,disaster-type-1,summary,en,2008-01-01,2,1,,2,event-1,1,event-slug,,en,1,2008-01-01T00:00:00.123456Z,,,project-1,1,Emergency Operation,1,sect-1,0,Bilateral,1,1,bV,rpo,country-1,society-name-1,"dct1, dct2","1, 2","True, False","False, True","district-1, district-2",0,0,0,0,1,2008-01-01T00:00:00.123456Z,1,2008-01-01T00:00:00.123456Z,regional-project-1,en,False,1,,,,1,bV,rpo,country-1,society-name-1,"1, 2","sec-tag-1, sec-tag-2",2008-01-01,1,Ongoing,0,0,0,0,en,False,5,public,Public\r +0,100000,,,1,1,disaster-type-1,summary,en,2008-01-01,2,1,,2,event-1,1,event-slug,,en,2,2008-01-01T00:00:00.123456Z,,,project-1,1,Emergency Operation,1,sect-1,0,Bilateral,1,1,bV,rpo,country-1,society-name-1,"dct1, dct2","1, 2","True, False","False, True","district-1, district-2",0,0,0,0,1,2008-01-01T00:00:00.123456Z,1,2008-01-01T00:00:00.123456Z,regional-project-1,en,False,1,,,,1,bV,rpo,country-1,society-name-1,"1, 2","sec-tag-1, sec-tag-2",2008-01-01,1,Ongoing,0,0,0,0,en,False,6,public,Public\r +0,100000,,,1,1,disaster-type-1,summary,en,2008-01-01,2,1,,2,event-1,1,event-slug,,en,3,2008-01-01T00:00:00.123456Z,,,project-1,1,Emergency Operation,1,sect-1,0,Bilateral,1,1,bV,rpo,country-1,society-name-1,"dct1, dct2","1, 2","True, False","False, True","district-1, district-2",0,0,0,0,1,2008-01-01T00:00:00.123456Z,1,2008-01-01T00:00:00.123456Z,regional-project-1,en,False,1,,,,1,bV,rpo,country-1,society-name-1,"1, 2","sec-tag-1, sec-tag-2",2008-01-01,1,Ongoing,0,0,0,0,en,False,7,public,Public\r +0,100000,,,1,1,disaster-type-1,summary,en,2008-01-01,2,1,,2,event-1,1,event-slug,,en,4,2008-01-01T00:00:00.123456Z,,,project-1,1,Emergency Operation,1,sect-1,0,Bilateral,1,1,bV,rpo,country-1,society-name-1,"dct1, dct2","1, 2","True, False","False, True","district-1, district-2",0,0,0,0,1,2008-01-01T00:00:00.123456Z,1,2008-01-01T00:00:00.123456Z,regional-project-1,en,False,1,,,,1,bV,rpo,country-1,society-name-1,"1, 2","sec-tag-1, sec-tag-2",2008-01-01,1,Ongoing,0,0,0,0,en,False,8,public,Public\r +0,100000,,,1,1,disaster-type-1,summary,en,2008-01-01,2,1,,2,event-1,1,event-slug,,en,5,2008-01-01T00:00:00.123456Z,,,project-1,1,Emergency Operation,1,sect-1,0,Bilateral,1,1,bV,rpo,country-1,society-name-1,"dct1, dct2","1, 2","True, False","False, True","district-1, district-2",0,0,0,0,1,2008-01-01T00:00:00.123456Z,1,2008-01-01T00:00:00.123456Z,regional-project-1,en,False,1,,,,1,bV,rpo,country-1,society-name-1,"1, 2","sec-tag-1, sec-tag-2",2008-01-01,1,Ongoing,0,0,0,0,en,False,9,public,Public\r +0,100000,,,1,1,disaster-type-1,summary,en,2008-01-01,2,1,,2,event-1,1,event-slug,,en,6,2008-01-01T00:00:00.123456Z,,,project-1,1,Emergency Operation,1,sect-1,0,Bilateral,1,1,bV,rpo,country-1,society-name-1,"dct1, dct2","1, 2","True, False","False, True","district-1, district-2",0,0,0,0,1,2008-01-01T00:00:00.123456Z,1,2008-01-01T00:00:00.123456Z,regional-project-1,en,False,1,,,,1,bV,rpo,country-1,society-name-1,"1, 2","sec-tag-1, sec-tag-2",2008-01-01,1,Ongoing,0,0,0,0,en,False,10,public,Public\r +0,100000,,,1,1,disaster-type-1,summary,en,2008-01-01,2,1,,2,event-1,1,event-slug,,en,7,2008-01-01T00:00:00.123456Z,,,project-1,1,Emergency Operation,1,sect-1,0,Bilateral,1,1,bV,rpo,country-1,society-name-1,"dct1, dct2","1, 2","True, False","False, True","district-1, district-2",0,0,0,0,1,2008-01-01T00:00:00.123456Z,1,2008-01-01T00:00:00.123456Z,regional-project-1,en,False,1,,,,1,bV,rpo,country-1,society-name-1,"1, 2","sec-tag-1, sec-tag-2",2008-01-01,1,Ongoing,0,0,0,0,en,False,11,public,Public\r +0,100000,,,1,1,disaster-type-1,summary,en,2008-01-01,2,1,,2,event-1,1,event-slug,,en,8,2008-01-01T00:00:00.123456Z,,,project-1,1,Emergency Operation,1,sect-1,0,Bilateral,1,1,bV,rpo,country-1,society-name-1,"dct1, dct2","1, 2","True, False","False, True","district-1, district-2",0,0,0,0,1,2008-01-01T00:00:00.123456Z,1,2008-01-01T00:00:00.123456Z,regional-project-1,en,False,1,,,,1,bV,rpo,country-1,society-name-1,"1, 2","sec-tag-1, sec-tag-2",2008-01-01,1,Ongoing,0,0,0,0,en,False,12,public,Public\r +0,100000,,,1,1,disaster-type-1,summary,en,2008-01-01,2,1,,2,event-1,1,event-slug,,en,9,2008-01-01T00:00:00.123456Z,,,project-1,1,Emergency Operation,1,sect-1,0,Bilateral,1,1,bV,rpo,country-1,society-name-1,"dct1, dct2","1, 2","True, False","False, True","district-1, district-2",0,0,0,0,1,2008-01-01T00:00:00.123456Z,1,2008-01-01T00:00:00.123456Z,regional-project-1,en,False,1,,,,1,bV,rpo,country-1,society-name-1,"1, 2","sec-tag-1, sec-tag-2",2008-01-01,1,Ongoing,0,0,0,0,en,False,13,public,Public\r +0,100000,,,1,1,disaster-type-1,summary,en,2008-01-01,2,1,,2,event-1,1,event-slug,,en,10,2008-01-01T00:00:00.123456Z,,,project-1,1,Emergency Operation,1,sect-1,0,Bilateral,1,1,bV,rpo,country-1,society-name-1,"dct1, dct2","1, 2","True, False","False, True","district-1, district-2",0,0,0,0,1,2008-01-01T00:00:00.123456Z,1,2008-01-01T00:00:00.123456Z,regional-project-1,en,False,1,,,,1,bV,rpo,country-1,society-name-1,"1, 2","sec-tag-1, sec-tag-2",2008-01-01,1,Ongoing,0,0,0,0,en,False,14,public,Public\r """ snapshots["TestProjectAPI::test_project_delete 1"] = b"" @@ -113,14 +113,14 @@ { "actual_expenditure": 0, "annual_splits": [], - "budget_amount": 8500000, + "budget_amount": 6440000, "description": "", "document": None, "dtype": 3, "dtype_detail": { "id": 3, - "name": "disaster-type-SOuThWwJELKQTARVIsBZaHgbyjdQdmrWYksRqjdSYsnWIcwCgN", - "summary": "RVJoVPJypGYYZSsSQdyyAYRuJdaVqmNXCoOTTPxWLIVMmXUmsClRellVGhycBrJqikLqavDTjcjuMdXONQtFYKJweYTuHolHeYGkAIIzfwonQvvxsnWNHEJWPahQwCpPNNpcRuyYhyqIUsbHXxGZGCFcsPmuGfgkXIIaOenQOXnRBgnISVXBPeVRjbDTvcfedlYqJeKoqAyCOzBubyRhIaPUNeWVLcSewGgsYRtMfsWCyzQbEkIoiVzYZIsOjtRYUPxaJJjhcaKMzIJftnVVUwnAPGjkloNqmhlQZKdWJDPJesQeqgmULFvwiQPpgsNemuFCvNQtSLjKKxZuBkaupYoTVPBrxiRUvEDCwXtFJglPMfriImqUOeUebGObLLzXLncJqIIEPXjxzoXLUsiDGGfzxGaQpZNRkWGiCklKKQjVUEwcoWFoeqxocQnHYxyEDccPugTHOrVqLIKlyPyxLPeHqyoHzwwFYEMaGiCkoeGPrnjlkxMT", + "name": "disaster-type-MSVGtSJuTVJOnmnNTsRwRiTPlGISOuThWwJELKQTARVIsBZaHg", + "summary": "byjdQdmrWYksRqjdSYsnWIcwCgNRVJoVPJypGYYZSsSQdyyAYRuJdaVqmNXCoOTTPxWLIVMmXUmsClRellVGhycBrJqikLqavDTjcjuMdXONQtFYKJweYTuHolHeYGkAIIzfwonQvvxsnWNHEJWPahQwCpPNNpcRuyYhyqIUsbHXxGZGCFcsPmuGfgkXIIaOenQOXnRBgnISVXBPeVRjbDTvcfedlYqJeKoqAyCOzBubyRhIaPUNeWVLcSewGgsYRtMfsWCyzQbEkIoiVzYZIsOjtRYUPxaJJjhcaKMzIJftnVVUwnAPGjkloNqmhlQZKdWJDPJesQeqgmULFvwiQPpgsNemuFCvNQtSLjKKxZuBkaupYoTVPBrxiRUvEDCwXtFJglPMfriImqUOeUebGObLLzXLncJqIIEPXjxzoXLUsiDGGfzxGaQpZNRkWGiCklKKQjVUEwcoWFoeqxocQnHYxyEDccPugTHOrVqLIKlyPyxLPeHq", "translation_module_original_language": "en", }, "end_date": "2008-01-01", @@ -130,9 +130,9 @@ "dtype": 1, "emergency_response_contact_email": None, "id": 2, - "name": "N/A: disaster-type-hlIzHiUoaWbtDRUIBIyopDwjrmUWhcZQANXbpnegMcCMRTdpVc - 12-2019 - LFfGCZdDiG", + "name": "xNooiEjDVMxASJEWIZQnWpRWMYfHCHTxeKhdJGmKIjkuHChRnT", "parent_event": 1, - "slug": "adkdjdrztubzqavnlecbwseideecsalxixpupaxycyyfrqiipw", + "slug": "lffgczddigadkdjdrztubzqavnlecbwseideecsalxixpupaxy", "start_date": None, "translation_module_original_language": "en", }, @@ -140,7 +140,7 @@ "modified_at": "2008-01-01T00:00:00.123456Z", "modified_by": None, "modified_by_detail": None, - "name": "project-hQoAZvUhEREEnLkPAbpciKLkiOGcKjdkqlHzMKObUUQsfnCMEE", + "name": "project-yoHzwwFYEMaGiCkoeGPrnjlkxMThQoAZvUhEREEnLkPAbpciKL", "operation_type": 0, "operation_type_display": "Programme", "primary_sector": 1, @@ -168,7 +168,7 @@ "created_at": "2008-01-01T00:00:00.123456Z", "id": 1, "modified_at": "2008-01-01T00:00:00.123456Z", - "name": "regional-project-yyigbmHGRAjMglENMcYIGWhfEQiMIaXRPBHAxcSHBoZEYXywLZ", + "name": "regional-project-fnCMEEkoAMjYLXlNQGqkURvDMLeoyyigbmHGRAjMglENMcYIGW", "translation_module_original_language": "en", "translation_module_skip_auto_translation": False, }, @@ -209,14 +209,14 @@ { "actual_expenditure": 0, "annual_splits": [], - "budget_amount": 8500000, + "budget_amount": 6440000, "description": "", "document": None, "dtype": 3, "dtype_detail": { "id": 3, - "name": "disaster-type-SOuThWwJELKQTARVIsBZaHgbyjdQdmrWYksRqjdSYsnWIcwCgN", - "summary": "RVJoVPJypGYYZSsSQdyyAYRuJdaVqmNXCoOTTPxWLIVMmXUmsClRellVGhycBrJqikLqavDTjcjuMdXONQtFYKJweYTuHolHeYGkAIIzfwonQvvxsnWNHEJWPahQwCpPNNpcRuyYhyqIUsbHXxGZGCFcsPmuGfgkXIIaOenQOXnRBgnISVXBPeVRjbDTvcfedlYqJeKoqAyCOzBubyRhIaPUNeWVLcSewGgsYRtMfsWCyzQbEkIoiVzYZIsOjtRYUPxaJJjhcaKMzIJftnVVUwnAPGjkloNqmhlQZKdWJDPJesQeqgmULFvwiQPpgsNemuFCvNQtSLjKKxZuBkaupYoTVPBrxiRUvEDCwXtFJglPMfriImqUOeUebGObLLzXLncJqIIEPXjxzoXLUsiDGGfzxGaQpZNRkWGiCklKKQjVUEwcoWFoeqxocQnHYxyEDccPugTHOrVqLIKlyPyxLPeHqyoHzwwFYEMaGiCkoeGPrnjlkxMT", + "name": "disaster-type-MSVGtSJuTVJOnmnNTsRwRiTPlGISOuThWwJELKQTARVIsBZaHg", + "summary": "byjdQdmrWYksRqjdSYsnWIcwCgNRVJoVPJypGYYZSsSQdyyAYRuJdaVqmNXCoOTTPxWLIVMmXUmsClRellVGhycBrJqikLqavDTjcjuMdXONQtFYKJweYTuHolHeYGkAIIzfwonQvvxsnWNHEJWPahQwCpPNNpcRuyYhyqIUsbHXxGZGCFcsPmuGfgkXIIaOenQOXnRBgnISVXBPeVRjbDTvcfedlYqJeKoqAyCOzBubyRhIaPUNeWVLcSewGgsYRtMfsWCyzQbEkIoiVzYZIsOjtRYUPxaJJjhcaKMzIJftnVVUwnAPGjkloNqmhlQZKdWJDPJesQeqgmULFvwiQPpgsNemuFCvNQtSLjKKxZuBkaupYoTVPBrxiRUvEDCwXtFJglPMfriImqUOeUebGObLLzXLncJqIIEPXjxzoXLUsiDGGfzxGaQpZNRkWGiCklKKQjVUEwcoWFoeqxocQnHYxyEDccPugTHOrVqLIKlyPyxLPeHq", "translation_module_original_language": "en", }, "end_date": "2008-01-01", @@ -226,9 +226,9 @@ "dtype": 1, "emergency_response_contact_email": None, "id": 2, - "name": "N/A: disaster-type-hlIzHiUoaWbtDRUIBIyopDwjrmUWhcZQANXbpnegMcCMRTdpVc - 12-2019 - LFfGCZdDiG", + "name": "xNooiEjDVMxASJEWIZQnWpRWMYfHCHTxeKhdJGmKIjkuHChRnT", "parent_event": 1, - "slug": "adkdjdrztubzqavnlecbwseideecsalxixpupaxycyyfrqiipw", + "slug": "lffgczddigadkdjdrztubzqavnlecbwseideecsalxixpupaxy", "start_date": None, "translation_module_original_language": "en", }, @@ -236,7 +236,7 @@ "modified_at": "2008-01-01T00:00:00.123456Z", "modified_by": None, "modified_by_detail": None, - "name": "project-hQoAZvUhEREEnLkPAbpciKLkiOGcKjdkqlHzMKObUUQsfnCMEE", + "name": "project-yoHzwwFYEMaGiCkoeGPrnjlkxMThQoAZvUhEREEnLkPAbpciKL", "operation_type": 0, "operation_type_display": "Programme", "primary_sector": 1, @@ -264,7 +264,7 @@ "created_at": "2008-01-01T00:00:00.123456Z", "id": 1, "modified_at": "2008-01-01T00:00:00.123456Z", - "name": "regional-project-yyigbmHGRAjMglENMcYIGWhfEQiMIaXRPBHAxcSHBoZEYXywLZ", + "name": "regional-project-fnCMEEkoAMjYLXlNQGqkURvDMLeoyyigbmHGRAjMglENMcYIGW", "translation_module_original_language": "en", "translation_module_skip_auto_translation": False, }, @@ -297,14 +297,14 @@ { "actual_expenditure": 0, "annual_splits": [], - "budget_amount": 9540000, + "budget_amount": 6090000, "description": "", "document": None, "dtype": 6, "dtype_detail": { "id": 6, - "name": "disaster-type-swYzzLWPaEPGWjzooUVnEoHLYJWDUDvYfumBXSAnCCJbxiKitV", - "summary": "aFZQwvoABRWzWXSItuLbKYcijvKOZMMKzynzeIymEgvKCOtfkgRJlcSMFblmeysnosQHeDdxHakuAzkhiIAEVeynintBTQEkMKtLmGTRDrmajCezMZpHvKFDDKcVfsPDwSTYtzNZlAplNUBDyQlSKgzScpkrOIsQeSUUnFAWJhxeWgGXXuACkqnGcDbeOSRVDyvVzmzcaqhTiuQVDFDefJQpTCiErkkbMglshIVzkeQWaRrjCwlnTcRInCSdOZHPQTQgyStCdMadXyXmpxpmfbAbavmRQeogZQkUkcAGguuJOmNnIzBhongwulazPuaynDoeQrPNxcenAtXMFgTIYKkqgMuOSyRXSivlOWSuQEevbMLCyGOVoGLTaobNWhtpVBWpNfdixFsmjynPcpUMCVviruPYWcHYAPsWboUvvpnIdQpZRSUoMyHulCOaeFemdOjniflLJYnpGfBUDtkUmpBlMptsKCOmrYEfxzykECBGNVBWjYEb", + "name": "disaster-type-blCoqPewfsGGIPfYroghexcImvmRvqtVXRrmTMiWTVIqaXtswY", + "summary": "zzLWPaEPGWjzooUVnEoHLYJWDUDvYfumBXSAnCCJbxiKitVaFZQwvoABRWzWXSItuLbKYcijvKOZMMKzynzeIymEgvKCOtfkgRJlcSMFblmeysnosQHeDdxHakuAzkhiIAEVeynintBTQEkMKtLmGTRDrmajCezMZpHvKFDDKcVfsPDwSTYtzNZlAplNUBDyQlSKgzScpkrOIsQeSUUnFAWJhxeWgGXXuACkqnGcDbeOSRVDyvVzmzcaqhTiuQVDFDefJQpTCiErkkbMglshIVzkeQWaRrjCwlnTcRInCSdOZHPQTQgyStCdMadXyXmpxpmfbAbavmRQeogZQkUkcAGguuJOmNnIzBhongwulazPuaynDoeQrPNxcenAtXMFgTIYKkqgMuOSyRXSivlOWSuQEevbMLCyGOVoGLTaobNWhtpVBWpNfdixFsmjynPcpUMCVviruPYWcHYAPsWboUvvpnIdQpZRSUoMyHulCOaeFemdOjni", "translation_module_original_language": "en", }, "end_date": "2008-01-01", @@ -314,9 +314,9 @@ "dtype": 4, "emergency_response_contact_email": None, "id": 4, - "name": "N/A: disaster-type-bfICRQfGzmFuMMGdQxzjTBxyxaswwtCJfnUCVAZCskZUBUAiLM - 05-2014 - kIthbzFXjD", + "name": "ZoHPvALvPPYuFLQSHJCDtKiYtkYqoExsXdjwsDkNkTIsllTSQY", "parent_event": 3, - "slug": "ujavigvptseswkqjzkucvshuecirjhtbznocwfudmpmlhoyxrm", + "slug": "jkphcukicqxlnjtcquwjxcikithbzfxjdujavigvptseswkqjz", "start_date": None, "translation_module_original_language": "en", }, @@ -324,7 +324,7 @@ "modified_at": "2008-01-01T00:00:00.123456Z", "modified_by": None, "modified_by_detail": None, - "name": "project-WyBfWtMIjJUlqyDtDsyJMEeviTEmjmaaGUUxFzAzVxyFtPLeAc", + "name": "project-flLJYnpGfBUDtkUmpBlMptsKCOmrYEfxzykECBGNVBWjYEbWyB", "operation_type": 1, "operation_type_display": "Emergency Operation", "primary_sector": 1, @@ -336,10 +336,10 @@ "project_country": 4, "project_country_detail": { "id": 4, - "iso": "Al", - "iso3": "kRs", - "name": "country-imaNWqaDFFIZaMFpnLQEDACfMMapJrNOJndljdPwcjcQKMtvfd", - "society_name": "society-name-NQSSMKYJlDVLxcfXtuxyeWBJesEihSrvHAHnSnNdgKUOHfEUSM", + "iso": "rN", + "iso3": "OJn", + "name": "country-XkvKQjkjlXTdAttUXCsOlhimaNWqaDFFIZaMFpnLQEDACfMMap", + "society_name": "society-name-dljdPwcjcQKMtvfdgAlkRsNQSSMKYJlDVLxcfXtuxyeWBJesEi", }, "project_districts": [], "project_districts_detail": [], @@ -352,7 +352,7 @@ "created_at": "2008-01-01T00:00:00.123456Z", "id": 2, "modified_at": "2008-01-01T00:00:00.123456Z", - "name": "regional-project-VppEcxOTRbSQPjqMDRjqpMLQkahXfPTyzTLfHmBkBqStGIQyLt", + "name": "regional-project-JMEeviTEmjmaaGUUxFzAzVxyFtPLeAchyKkmWBqXWUwGTFOSxS", "translation_module_original_language": "en", "translation_module_skip_auto_translation": False, }, @@ -362,10 +362,10 @@ "reporting_ns_contact_role": None, "reporting_ns_detail": { "id": 3, - "iso": "YJ", - "iso3": "Elx", - "name": "country-gBiqEXofsMIAqmaTVYaKHhHayPnSZuAxgjBPLqqIBKxNrRzWnA", - "society_name": "society-name-JJEqtKwXTzViQhVoCYSkgnGzYvZJNSRTdkyOaZfjEMBfeqoxfM", + "iso": "yP", + "iso3": "nSZ", + "name": "country-MIaXRPBHAxcSHBoZEYXywLZVWSKgBiqEXofsMIAqmaTVYaKHhH", + "society_name": "society-name-uAxgjBPLqqIBKxNrRzWnAJYJElxJJEqtKwXTzViQhVoCYSkgnG", }, "secondary_sectors": [], "secondary_sectors_display": [], @@ -390,14 +390,14 @@ snapshots["TestProjectAPI::test_project_read 1"] = { "actual_expenditure": 0, "annual_splits": [], - "budget_amount": 8500000, + "budget_amount": 6440000, "description": "", "document": None, "dtype": 3, "dtype_detail": { "id": 3, - "name": "disaster-type-SOuThWwJELKQTARVIsBZaHgbyjdQdmrWYksRqjdSYsnWIcwCgN", - "summary": "RVJoVPJypGYYZSsSQdyyAYRuJdaVqmNXCoOTTPxWLIVMmXUmsClRellVGhycBrJqikLqavDTjcjuMdXONQtFYKJweYTuHolHeYGkAIIzfwonQvvxsnWNHEJWPahQwCpPNNpcRuyYhyqIUsbHXxGZGCFcsPmuGfgkXIIaOenQOXnRBgnISVXBPeVRjbDTvcfedlYqJeKoqAyCOzBubyRhIaPUNeWVLcSewGgsYRtMfsWCyzQbEkIoiVzYZIsOjtRYUPxaJJjhcaKMzIJftnVVUwnAPGjkloNqmhlQZKdWJDPJesQeqgmULFvwiQPpgsNemuFCvNQtSLjKKxZuBkaupYoTVPBrxiRUvEDCwXtFJglPMfriImqUOeUebGObLLzXLncJqIIEPXjxzoXLUsiDGGfzxGaQpZNRkWGiCklKKQjVUEwcoWFoeqxocQnHYxyEDccPugTHOrVqLIKlyPyxLPeHqyoHzwwFYEMaGiCkoeGPrnjlkxMT", + "name": "disaster-type-MSVGtSJuTVJOnmnNTsRwRiTPlGISOuThWwJELKQTARVIsBZaHg", + "summary": "byjdQdmrWYksRqjdSYsnWIcwCgNRVJoVPJypGYYZSsSQdyyAYRuJdaVqmNXCoOTTPxWLIVMmXUmsClRellVGhycBrJqikLqavDTjcjuMdXONQtFYKJweYTuHolHeYGkAIIzfwonQvvxsnWNHEJWPahQwCpPNNpcRuyYhyqIUsbHXxGZGCFcsPmuGfgkXIIaOenQOXnRBgnISVXBPeVRjbDTvcfedlYqJeKoqAyCOzBubyRhIaPUNeWVLcSewGgsYRtMfsWCyzQbEkIoiVzYZIsOjtRYUPxaJJjhcaKMzIJftnVVUwnAPGjkloNqmhlQZKdWJDPJesQeqgmULFvwiQPpgsNemuFCvNQtSLjKKxZuBkaupYoTVPBrxiRUvEDCwXtFJglPMfriImqUOeUebGObLLzXLncJqIIEPXjxzoXLUsiDGGfzxGaQpZNRkWGiCklKKQjVUEwcoWFoeqxocQnHYxyEDccPugTHOrVqLIKlyPyxLPeHq", "translation_module_original_language": "en", }, "end_date": "2008-01-01", @@ -407,9 +407,9 @@ "dtype": 1, "emergency_response_contact_email": None, "id": 2, - "name": "N/A: disaster-type-hlIzHiUoaWbtDRUIBIyopDwjrmUWhcZQANXbpnegMcCMRTdpVc - 12-2019 - LFfGCZdDiG", + "name": "xNooiEjDVMxASJEWIZQnWpRWMYfHCHTxeKhdJGmKIjkuHChRnT", "parent_event": 1, - "slug": "adkdjdrztubzqavnlecbwseideecsalxixpupaxycyyfrqiipw", + "slug": "lffgczddigadkdjdrztubzqavnlecbwseideecsalxixpupaxy", "start_date": None, "translation_module_original_language": "en", }, @@ -417,7 +417,7 @@ "modified_at": "2008-01-01T00:00:00.123456Z", "modified_by": None, "modified_by_detail": None, - "name": "project-hQoAZvUhEREEnLkPAbpciKLkiOGcKjdkqlHzMKObUUQsfnCMEE", + "name": "project-yoHzwwFYEMaGiCkoeGPrnjlkxMThQoAZvUhEREEnLkPAbpciKL", "operation_type": 0, "operation_type_display": "Programme", "primary_sector": 1, @@ -445,7 +445,7 @@ "created_at": "2008-01-01T00:00:00.123456Z", "id": 1, "modified_at": "2008-01-01T00:00:00.123456Z", - "name": "regional-project-yyigbmHGRAjMglENMcYIGWhfEQiMIaXRPBHAxcSHBoZEYXywLZ", + "name": "regional-project-fnCMEEkoAMjYLXlNQGqkURvDMLeoyyigbmHGRAjMglENMcYIGW", "translation_module_original_language": "en", "translation_module_skip_auto_translation": False, }, @@ -479,14 +479,14 @@ snapshots["TestProjectAPI::test_project_update 1"] = { "actual_expenditure": 0, "annual_splits": [], - "budget_amount": 8500000, + "budget_amount": 6440000, "description": "", "document": None, "dtype": 3, "dtype_detail": { "id": 3, - "name": "disaster-type-SOuThWwJELKQTARVIsBZaHgbyjdQdmrWYksRqjdSYsnWIcwCgN", - "summary": "RVJoVPJypGYYZSsSQdyyAYRuJdaVqmNXCoOTTPxWLIVMmXUmsClRellVGhycBrJqikLqavDTjcjuMdXONQtFYKJweYTuHolHeYGkAIIzfwonQvvxsnWNHEJWPahQwCpPNNpcRuyYhyqIUsbHXxGZGCFcsPmuGfgkXIIaOenQOXnRBgnISVXBPeVRjbDTvcfedlYqJeKoqAyCOzBubyRhIaPUNeWVLcSewGgsYRtMfsWCyzQbEkIoiVzYZIsOjtRYUPxaJJjhcaKMzIJftnVVUwnAPGjkloNqmhlQZKdWJDPJesQeqgmULFvwiQPpgsNemuFCvNQtSLjKKxZuBkaupYoTVPBrxiRUvEDCwXtFJglPMfriImqUOeUebGObLLzXLncJqIIEPXjxzoXLUsiDGGfzxGaQpZNRkWGiCklKKQjVUEwcoWFoeqxocQnHYxyEDccPugTHOrVqLIKlyPyxLPeHqyoHzwwFYEMaGiCkoeGPrnjlkxMT", + "name": "disaster-type-MSVGtSJuTVJOnmnNTsRwRiTPlGISOuThWwJELKQTARVIsBZaHg", + "summary": "byjdQdmrWYksRqjdSYsnWIcwCgNRVJoVPJypGYYZSsSQdyyAYRuJdaVqmNXCoOTTPxWLIVMmXUmsClRellVGhycBrJqikLqavDTjcjuMdXONQtFYKJweYTuHolHeYGkAIIzfwonQvvxsnWNHEJWPahQwCpPNNpcRuyYhyqIUsbHXxGZGCFcsPmuGfgkXIIaOenQOXnRBgnISVXBPeVRjbDTvcfedlYqJeKoqAyCOzBubyRhIaPUNeWVLcSewGgsYRtMfsWCyzQbEkIoiVzYZIsOjtRYUPxaJJjhcaKMzIJftnVVUwnAPGjkloNqmhlQZKdWJDPJesQeqgmULFvwiQPpgsNemuFCvNQtSLjKKxZuBkaupYoTVPBrxiRUvEDCwXtFJglPMfriImqUOeUebGObLLzXLncJqIIEPXjxzoXLUsiDGGfzxGaQpZNRkWGiCklKKQjVUEwcoWFoeqxocQnHYxyEDccPugTHOrVqLIKlyPyxLPeHq", "translation_module_original_language": "en", }, "end_date": "2008-01-01", @@ -496,9 +496,9 @@ "dtype": 1, "emergency_response_contact_email": None, "id": 2, - "name": "N/A: disaster-type-hlIzHiUoaWbtDRUIBIyopDwjrmUWhcZQANXbpnegMcCMRTdpVc - 12-2019 - LFfGCZdDiG", + "name": "xNooiEjDVMxASJEWIZQnWpRWMYfHCHTxeKhdJGmKIjkuHChRnT", "parent_event": 1, - "slug": "adkdjdrztubzqavnlecbwseideecsalxixpupaxycyyfrqiipw", + "slug": "lffgczddigadkdjdrztubzqavnlecbwseideecsalxixpupaxy", "start_date": None, "translation_module_original_language": "en", }, @@ -518,13 +518,13 @@ "project_country": 3, "project_country_detail": { "id": 3, - "iso": "AJ", - "iso3": "YJE", - "name": "country-SKgBiqEXofsMIAqmaTVYaKHhHayPnSZuAxgjBPLqqIBKxNrRzW", - "society_name": "society-name-lxJJEqtKwXTzViQhVoCYSkgnGzYvZJNSRTdkyOaZfjEMBfeqox", + "iso": "ay", + "iso3": "PnS", + "name": "country-iMIaXRPBHAxcSHBoZEYXywLZVWSKgBiqEXofsMIAqmaTVYaKHh", + "society_name": "society-name-ZuAxgjBPLqqIBKxNrRzWnAJYJElxJJEqtKwXTzViQhVoCYSkgn", }, "project_districts": [1], - "project_districts_detail": [{"id": 1, "name": "district-imaNWqaDFFIZaMFpnLQEDACfMMapJrNOJndljdPwcjcQKMtvfd"}], + "project_districts_detail": [{"id": 1, "name": "district-kyJycXkvKQjkjlXTdAttUXCsOlhimaNWqaDFFIZaMFpnLQEDAC"}], "reached_female": 0, "reached_male": 0, "reached_other": 0, @@ -534,7 +534,7 @@ "created_at": "2008-01-01T00:00:00.123456Z", "id": 1, "modified_at": "2008-01-01T00:00:00.123456Z", - "name": "regional-project-yyigbmHGRAjMglENMcYIGWhfEQiMIaXRPBHAxcSHBoZEYXywLZ", + "name": "regional-project-fnCMEEkoAMjYLXlNQGqkURvDMLeoyyigbmHGRAjMglENMcYIGW", "translation_module_original_language": "en", "translation_module_skip_auto_translation": False, }, @@ -544,10 +544,10 @@ "reporting_ns_contact_role": None, "reporting_ns_detail": { "id": 3, - "iso": "AJ", - "iso3": "YJE", - "name": "country-SKgBiqEXofsMIAqmaTVYaKHhHayPnSZuAxgjBPLqqIBKxNrRzW", - "society_name": "society-name-lxJJEqtKwXTzViQhVoCYSkgnGzYvZJNSRTdkyOaZfjEMBfeqox", + "iso": "ay", + "iso3": "PnS", + "name": "country-iMIaXRPBHAxcSHBoZEYXywLZVWSKgBiqEXofsMIAqmaTVYaKHh", + "society_name": "society-name-ZuAxgjBPLqqIBKxNrRzWnAJYJElxJJEqtKwXTzViQhVoCYSkgn", }, "secondary_sectors": [], "secondary_sectors_display": [], diff --git a/deployments/tests.py b/deployments/tests.py index 2c8609d76..853ea418e 100644 --- a/deployments/tests.py +++ b/deployments/tests.py @@ -204,7 +204,7 @@ def test_project_csv_api(self): slug="event-slug", districts=[district1.id, district2.id], dtype=dtype, - title="event-1", + name="event-1", ) ProjectFactory.create_batch( 10, diff --git a/lang/tests.py b/lang/tests.py index 7e9a337d7..685816ce8 100644 --- a/lang/tests.py +++ b/lang/tests.py @@ -244,6 +244,8 @@ def test_ifrc_translator(self, requests_mock): ]: with override_settings( AUTO_TRANSLATION_TRANSLATOR="lang.translation.IfrcTranslator", + IFRC_TRANSLATION_DOMAIN=None, + IFRC_TRANSLATION_API_KEY=None, **settings_params, ): with self.assertRaises(Exception): From b2e757c2ae210778632dcadb2dbd5f12d7741ca0 Mon Sep 17 00:00:00 2001 From: Sushil Tiwari Date: Thu, 20 Feb 2025 16:18:30 +0545 Subject: [PATCH 02/17] Add country name on search for emergency --- api/views.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/api/views.py b/api/views.py index 09fd61920..cdfa64b02 100644 --- a/api/views.py +++ b/api/views.py @@ -165,7 +165,7 @@ def get(self, request): emergency_response = ( SearchQuerySet() .models(Event) - .filter(SQ(name__content=phrase) | SQ(iso3__content=phrase)) + .filter(SQ(name__content=phrase) | SQ(iso3__content=phrase) | SQ(countries__content=phrase)) .order_by("-_score") ) fieldreport_response = ( @@ -215,7 +215,10 @@ def get(self, request): emergency_response = ( SearchQuerySet() .models(Event) - .filter((SQ(name__content=phrase) | SQ(iso3__content=phrase)) & ~SQ(visibility="IFRC Only")) + .filter( + (SQ(name__content=phrase) | SQ(country__iso3__content=phrase) | SQ(countries__content=phrase)) + & ~SQ(visibility="IFRC Only") + ) .order_by("-_score") ) fieldreport_response = ( From 540d96196e7c18a0b1df09c40c56cd3bf2561c24 Mon Sep 17 00:00:00 2001 From: thenav56 Date: Mon, 17 Feb 2025 16:54:04 +0545 Subject: [PATCH 03/17] Change GO_API_FQDN/BASE_URL to GO_API_URL - Add http scheme to the GO_API_URL --- api/management/commands/index_and_notify.py | 8 +++---- api/views.py | 4 ++-- main/settings.py | 23 +++++++++++++++++---- registrations/tasks.py | 4 ++-- registrations/views.py | 4 ++-- 5 files changed, 29 insertions(+), 14 deletions(-) diff --git a/api/management/commands/index_and_notify.py b/api/management/commands/index_and_notify.py index e9e40ad8f..9314f89e9 100644 --- a/api/management/commands/index_and_notify.py +++ b/api/management/commands/index_and_notify.py @@ -264,8 +264,8 @@ def get_admin_uri(self, record, rtype): RecordType.SURGE_DEPLOYMENT_MESSAGES: "deployments/personneldeployment", RecordType.SURGE_ALERT: "notifications/surgealert", }[rtype] - return "https://%s/admin/%s/%s/change" % ( - settings.BASE_URL, + return "%s/admin/%s/%s/change" % ( + settings.GO_API_URL, admin_page, record.id, ) @@ -960,8 +960,8 @@ def check_ingest_issues(self, having_ingest_issue): ( "Ingest issue(s) occured, one of them is " + ingestor_name - + ", via CronJob log record id: https://" - + settings.BASE_URL + + ", via CronJob log record id: " + + settings.GO_API_URL + "/admin/api/cronjob/" + str(ingest_issue_id) + ". Please fix it ASAP." diff --git a/api/views.py b/api/views.py index cdfa64b02..5e64ec9b3 100644 --- a/api/views.py +++ b/api/views.py @@ -958,9 +958,9 @@ def post(self, request): # Construct and re-send the email email_context = { - "confirmation_link": "https://%s/verify_email/?token=%s&user=%s" + "confirmation_link": "%s/verify_email/?token=%s&user=%s" % ( - settings.BASE_URL, # on PROD it should point to goadmin... + settings.GO_API_URL, # on PROD it should point to goadmin... pending_user.token, username, ) diff --git a/main/settings.py b/main/settings.py index 2b30b25b4..d6a412e11 100644 --- a/main/settings.py +++ b/main/settings.py @@ -3,6 +3,7 @@ import os import sys from datetime import datetime +from urllib.parse import urlparse import environ import pytz @@ -29,8 +30,8 @@ DJANGO_ADDITIONAL_ALLOWED_HOSTS=(list, []), # Eg: api.go.ifrc.org, goadmin.ifrc.org, dsgocdnapi.azureedge.net GO_ENVIRONMENT=(str, "development"), # staging, production # - API_FQDN=str, # sub-domain.domain.domain-extension FRONTEND_URL=str, + API_FQDN=str, # https://goadmin.ifrc.org # Database DJANGO_DB_NAME=str, DJANGO_DB_USER=str, @@ -128,8 +129,22 @@ # Requires uppercase variable https://docs.djangoproject.com/en/2.1/topics/settings/#creating-your-own-settings -BASE_URL = GO_API_FQDN = env("API_FQDN") + +def parse_domain(env_key: str) -> str: + """ + NOTE: This is used for to avoid breaking due to existing config value + Update this using django validation + """ + raw_domain = env(env_key) + domain = raw_domain + if not domain.startswith("http"): + domain = f"https://{domain}" # Add https as default + logger.warning(f"Provided {env_key}: {raw_domain} is missing schema.. Adding https -> {domain}") + return domain.strip("/") + + +GO_API_URL = parse_domain("API_FQDN") INTERNAL_IPS = ["127.0.0.1"] if env("DOCKER_HOST_IP"): INTERNAL_IPS.append(env("DOCKER_HOST_IP")) @@ -146,7 +161,7 @@ ALLOWED_HOSTS = [ "localhost", "0.0.0.0", - GO_API_FQDN, + urlparse(GO_API_URL).hostname, *env("DJANGO_ADDITIONAL_ALLOWED_HOSTS"), ] @@ -645,7 +660,7 @@ def log_render_extra_context(record): "environment": GO_ENVIRONMENT, "debug": DEBUG, "tags": { - "site": GO_API_FQDN, + "site": GO_API_URL, }, } if SENTRY_DSN: diff --git a/registrations/tasks.py b/registrations/tasks.py index c4ba9b945..159fa57c5 100644 --- a/registrations/tasks.py +++ b/registrations/tasks.py @@ -8,9 +8,9 @@ @shared_task def send_notification_create(token, username, is_staff, email): email_context = { - "confirmation_link": "https://%s/verify_email/?token=%s&user=%s" + "confirmation_link": "%s/verify_email/?token=%s&user=%s" % ( - settings.BASE_URL, # on PROD it should point to goadmin... + settings.GO_API_URL, # on PROD it should point to goadmin... token, username, ) diff --git a/registrations/views.py b/registrations/views.py index 0a7586145..34c7c43e1 100644 --- a/registrations/views.py +++ b/registrations/views.py @@ -68,9 +68,9 @@ def get(self, request): for admin in admins: token = pending_user.admin_token_1 email_context = { - "validation_link": "https://%s/validate_user/?token=%s&user=%s" + "validation_link": "%s/validate_user/?token=%s&user=%s" % ( - settings.BASE_URL, # on PROD it should point to goadmin... + settings.GO_API_URL, # on PROD it should point to goadmin... token, user, ), From f29c3c3cfe61944351a755b1fd8c3add5253c359 Mon Sep 17 00:00:00 2001 From: thenav56 Date: Mon, 17 Feb 2025 17:17:43 +0545 Subject: [PATCH 04/17] Add GO_WEB_URL to replace FRONTEND_URL internally GO_WEB_URL includes scheme --- api/management/commands/cron_job_monitor.py | 2 +- main/settings.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/api/management/commands/cron_job_monitor.py b/api/management/commands/cron_job_monitor.py index 9c540b34d..820bf4ed9 100644 --- a/api/management/commands/cron_job_monitor.py +++ b/api/management/commands/cron_job_monitor.py @@ -36,7 +36,7 @@ def handle(self, *args, **options): project_id = parsed_url.path.strip("/") api_key = parsed_url.username - SENTRY_INGEST = f"https://{parsed_url.hostname}" + SENTRY_INGEST = f"{parsed_url.scheme}://{parsed_url.hostname}" for cronjob in SentryMonitor.choices: job, schedule = cronjob diff --git a/main/settings.py b/main/settings.py index d6a412e11..5dedf23fc 100644 --- a/main/settings.py +++ b/main/settings.py @@ -30,8 +30,8 @@ DJANGO_ADDITIONAL_ALLOWED_HOSTS=(list, []), # Eg: api.go.ifrc.org, goadmin.ifrc.org, dsgocdnapi.azureedge.net GO_ENVIRONMENT=(str, "development"), # staging, production # - FRONTEND_URL=str, API_FQDN=str, # https://goadmin.ifrc.org + FRONTEND_URL=str, # https://go.ifrc.org # Database DJANGO_DB_NAME=str, DJANGO_DB_USER=str, @@ -145,6 +145,9 @@ def parse_domain(env_key: str) -> str: GO_API_URL = parse_domain("API_FQDN") +GO_WEB_URL = parse_domain("FRONTEND_URL") +FRONTEND_URL = urlparse(GO_WEB_URL).hostname # XXX: Deprecated. Slowly remove this from codebase + INTERNAL_IPS = ["127.0.0.1"] if env("DOCKER_HOST_IP"): INTERNAL_IPS.append(env("DOCKER_HOST_IP")) @@ -627,8 +630,6 @@ def log_render_extra_context(record): GO_FTPPASS = env("GO_FTPPASS") GO_DBPASS = env("GO_DBPASS") -# MISC -FRONTEND_URL = env("FRONTEND_URL") # COUNTRY PAGE NS_CONTACT_USERNAME = env("NS_CONTACT_USERNAME") From e7a814ed6bbddf274b02f72211acbcc8bbd39f59 Mon Sep 17 00:00:00 2001 From: thenav56 Date: Mon, 17 Feb 2025 17:40:28 +0545 Subject: [PATCH 05/17] Add GO_WEB_INTERNAL_URL for local development To test playwright exports using local running go-web-app --- api/serializers.py | 4 ++-- api/tasks.py | 2 +- docker-compose.yml | 6 ++++-- main/settings.py | 12 +++++++++++- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/api/serializers.py b/api/serializers.py index 60cccc9d8..70d28e7be 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -2436,9 +2436,9 @@ def create(self, validated_data): title = "Export" user = self.context["request"].user if export_type == Export.ExportType.PER: - validated_data["url"] = f"https://{settings.FRONTEND_URL}/countries/{country_id}/{export_type}/{export_id}/export/" + validated_data["url"] = f"{settings.GO_WEB_INTERNAL_URL}/countries/{country_id}/{export_type}/{export_id}/export/" else: - validated_data["url"] = f"https://{settings.FRONTEND_URL}/{export_type}/{export_id}/export/" + validated_data["url"] = f"{settings.GO_WEB_INTERNAL_URL}/{export_type}/{export_id}/export/" # Adding is_pga to the url is_pga = validated_data.pop("is_pga") diff --git a/api/tasks.py b/api/tasks.py index b72bb6d9f..b277252b0 100644 --- a/api/tasks.py +++ b/api/tasks.py @@ -25,7 +25,7 @@ def build_storage_state(tmp_dir, user, token): state = { "origins": [ { - "origin": "https://" + settings.FRONTEND_URL + "/", + "origin": settings.GO_WEB_INTERNAL_URL + "/", "localStorage": [ { "name": "user", diff --git a/docker-compose.yml b/docker-compose.yml index 0f9ec8bef..be733cf19 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,8 +15,10 @@ x-server: &base_server_setup # Other development defaults configs DJANGO_DEBUG: ${DJANGO_DEBUG:-true} GO_ENVIRONMENT: ${GO_ENVIRONMENT:-development} - API_FQDN: ${API_FQDN:-localhost:8000} - FRONTEND_URL: ${FRONTEND_URL:-localhost:3000} + API_FQDN: ${API_FQDN:-http://localhost:8000} + FRONTEND_URL: ${FRONTEND_URL:-http://localhost:3000} + GO_WEB_INTERNAL_URL: ${GO_WEB_INTERNAL_URL:-http://host.docker.internal:3000} + DJANGO_ADDITIONAL_ALLOWED_HOSTS: ${DJANGO_ADDITIONAL_ALLOWED_HOSTS:-host.docker.internal} DEBUG_EMAIL: ${DEBUG_EMAIL:-true} MOLNIX_API_BASE: ${MOLNIX_API_BASE:-https://api.ifrc-staging.rpm.molnix.com/api/} ERP_API_ENDPOINT: ${ERP_API_ENDPOINT:-https://ifrctintapim001.azure-api.net/GoAPI/ExtractGoEmergency} diff --git a/main/settings.py b/main/settings.py index 5dedf23fc..133bd6ab0 100644 --- a/main/settings.py +++ b/main/settings.py @@ -32,6 +32,7 @@ # API_FQDN=str, # https://goadmin.ifrc.org FRONTEND_URL=str, # https://go.ifrc.org + GO_WEB_INTERNAL_URL=(str, None), # http://host.docker.internal # Database DJANGO_DB_NAME=str, DJANGO_DB_USER=str, @@ -130,12 +131,18 @@ # Requires uppercase variable https://docs.djangoproject.com/en/2.1/topics/settings/#creating-your-own-settings +def find_env_with_value(*keys: str) -> None | str: + for key in keys: + if env(key): + return key -def parse_domain(env_key: str) -> str: + +def parse_domain(*env_keys: str) -> str: """ NOTE: This is used for to avoid breaking due to existing config value Update this using django validation """ + env_key = find_env_with_value(*env_keys) raw_domain = env(env_key) domain = raw_domain if not domain.startswith("http"): @@ -146,6 +153,9 @@ def parse_domain(env_key: str) -> str: GO_API_URL = parse_domain("API_FQDN") GO_WEB_URL = parse_domain("FRONTEND_URL") +# NOTE: Used in local development to get to the frontend service from within go-api container +# GO_WEB_URL will be used if GO_WEB_INTERNAL_URL is not provided +GO_WEB_INTERNAL_URL = parse_domain("GO_WEB_INTERNAL_URL", "FRONTEND_URL") FRONTEND_URL = urlparse(GO_WEB_URL).hostname # XXX: Deprecated. Slowly remove this from codebase INTERNAL_IPS = ["127.0.0.1"] From 64d218a0d97f9652d3b2a8662fb6f7674fe1ecc9 Mon Sep 17 00:00:00 2001 From: thenav56 Date: Tue, 18 Feb 2025 15:36:30 +0545 Subject: [PATCH 06/17] Playwright task updates - Fix logger.error usages - Add environment variable to switch playwright debug --- api/admin.py | 2 +- api/tasks.py | 22 +++++++++++++++------- main/settings.py | 2 ++ 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/api/admin.py b/api/admin.py index a37287c2a..02bd8bcac 100644 --- a/api/admin.py +++ b/api/admin.py @@ -1044,5 +1044,5 @@ class ExportTokenAdmin(admin.ModelAdmin): admin.site.register(models.CountryOfFieldReportToReview, CountryOfFieldReportToReviewAdmin) # admin.site.register(Revision, RevisionAdmin) -admin.site.site_url = "https://" + settings.FRONTEND_URL +admin.site.site_url = settings.GO_WEB_URL admin.widgets.RelatedFieldWidgetWrapper.template_name = "related_widget_wrapper.html" diff --git a/api/tasks.py b/api/tasks.py index b277252b0..ed00ea508 100644 --- a/api/tasks.py +++ b/api/tasks.py @@ -12,10 +12,11 @@ from playwright.sync_api import sync_playwright from rest_framework.authtoken.models import Token +from main.utils import logger_context + from .logger import logger from .models import Export - -# from .utils import DebugPlaywright +from .utils import DebugPlaywright def build_storage_state(tmp_dir, user, token): @@ -51,9 +52,10 @@ def build_storage_state(tmp_dir, user, token): @shared_task def generate_url(url, export_id, user, title): - export = Export.objects.filter(id=export_id).first() - user = User.objects.filter(id=user).first() + export = Export.objects.get(id=export_id) + user = User.objects.get(id=user) token = Token.objects.filter(user=user).last() + footer_template = """ """ # noqa: E501 + try: with tempfile.TemporaryDirectory() as tmp_dir: with sync_playwright() as p: @@ -103,7 +106,8 @@ def generate_url(url, export_id, user, title): ) context = browser.new_context(storage_state=storage_state) page = context.new_page() - # DebugPlaywright.debug(page) + if settings.DEBUG_PLAYWRIGHT: + DebugPlaywright.debug(page) timeout = 300000 page.goto(url, timeout=timeout) time.sleep(5) @@ -131,7 +135,11 @@ def generate_url(url, export_id, user, title): "completed_at", ] ) - except Exception as e: - logger.error(e) + except Exception: + logger.error( + "Failed to export PDF", + exc_info=True, + extra=logger_context(dict(export_id=export.pk)), + ) export.status = Export.ExportStatus.ERRORED export.save(update_fields=["status"]) diff --git a/main/settings.py b/main/settings.py index 133bd6ab0..d9d9705b0 100644 --- a/main/settings.py +++ b/main/settings.py @@ -82,6 +82,7 @@ FDRS_CREDENTIAL=(str, None), HPC_CREDENTIAL=(str, None), APPLICATION_INSIGHTS_INSTRUMENTATION_KEY=(str, None), + DEBUG_PLAYWRIGHT=(bool, False), # Pytest (Only required when running tests) PYTEST_XDIST_WORKER=(str, None), # Elastic-Cache @@ -180,6 +181,7 @@ def parse_domain(*env_keys: str) -> str: SECRET_KEY = env("DJANGO_SECRET_KEY") DEBUG = env("DJANGO_DEBUG") +DEBUG_PLAYWRIGHT = env("DEBUG_PLAYWRIGHT") GO_ENVIRONMENT = env("GO_ENVIRONMENT") # See if we are inside a test environment From 9bea17af74c829230d7abf5ffe209021767d27f1 Mon Sep 17 00:00:00 2001 From: thenav56 Date: Tue, 18 Feb 2025 16:06:13 +0545 Subject: [PATCH 07/17] Azure blob storage additional config - Add additional options to use Azure blob storage (Not used right now) - Use django new storages configuration structure https://docs.djangoproject.com/en/5.1/ref/settings/#std-setting-STORAGES --- main/settings.py | 86 +++++++++++++++++++++++---------- poetry.lock | 123 ++++++++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 4 +- 3 files changed, 184 insertions(+), 29 deletions(-) diff --git a/main/settings.py b/main/settings.py index d9d9705b0..307d66f42 100644 --- a/main/settings.py +++ b/main/settings.py @@ -7,6 +7,7 @@ import environ import pytz +from azure.identity import DefaultAzureCredential from corsheaders.defaults import default_headers from django.utils.translation import gettext_lazy as _ from urllib3.util.retry import Retry @@ -24,9 +25,7 @@ DOCKER_HOST_IP=(str, None), DJANGO_SECRET_KEY=str, DJANGO_MEDIA_URL=(str, "/media/"), - DJANGO_MEDIA_ROOT=(str, os.path.join(BASE_DIR, "media")), DJANGO_STATIC_URL=(str, "/static/"), - DJANGO_STATIC_ROOT=(str, os.path.join(BASE_DIR, "static")), DJANGO_ADDITIONAL_ALLOWED_HOSTS=(list, []), # Eg: api.go.ifrc.org, goadmin.ifrc.org, dsgocdnapi.azureedge.net GO_ENVIRONMENT=(str, "development"), # staging, production # @@ -39,9 +38,17 @@ DJANGO_DB_PASS=str, DJANGO_DB_HOST=str, DJANGO_DB_PORT=(int, 5432), - # Azure storage + # Storage + # -- Azure storage + AZURE_STORAGE_ENABLED=(bool, False), + AZURE_STORAGE_CONNECTION_STRING=(str, None), AZURE_STORAGE_ACCOUNT=(str, None), AZURE_STORAGE_KEY=(str, None), + AZURE_STORAGE_TOKEN_CREDENTIAL=(str, None), + AZURE_STORAGE_MANAGED_IDENTITY=(bool, False), + # -- Filesystem (default) XXX: Don't use for production + DJANGO_MEDIA_ROOT=(str, os.path.join(BASE_DIR, "media")), + DJANGO_STATIC_ROOT=(str, os.path.join(BASE_DIR, "static")), # Email EMAIL_USE_TLS=(bool, True), FORCE_USE_SMTP=(bool, False), @@ -132,6 +139,7 @@ # Requires uppercase variable https://docs.djangoproject.com/en/2.1/topics/settings/#creating-your-own-settings + def find_env_with_value(*keys: str) -> None | str: for key in keys: if env(key): @@ -437,39 +445,65 @@ def parse_domain(*env_keys: str) -> str: IFRC_TRANSLATION_DOMAIN = env("IFRC_TRANSLATION_DOMAIN") IFRC_TRANSLATION_HEADER_API_KEY = env("IFRC_TRANSLATION_HEADER_API_KEY") -MEDIA_URL = env("DJANGO_MEDIA_URL") -MEDIA_ROOT = env("DJANGO_MEDIA_ROOT") +# Needed to generate correct https links when running behind a reverse proxy +# when SSL is terminated at the proxy +USE_X_FORWARDED_HOST = True +SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_SCHEME", "https") +# Storage +MEDIA_URL = env("DJANGO_MEDIA_URL") STATIC_URL = env("DJANGO_STATIC_URL") -STATIC_ROOT = env("DJANGO_STATIC_ROOT") STATICFILES_DIRS = [ os.path.join(BASE_DIR, "go-static"), ] -# Needed to generate correct https links when running behind a reverse proxy -# when SSL is terminated at the proxy -USE_X_FORWARDED_HOST = True -SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_SCHEME", "https") - +# NOTE: This is used by api/logger.py which sends logs to azure storage +# FIXME: Do we need this? We are also using loki for log collections AZURE_STORAGE_ACCOUNT = env("AZURE_STORAGE_ACCOUNT") AZURE_STORAGE_KEY = env("AZURE_STORAGE_KEY") -AZURE_STORAGE = { - "CONTAINER": "api", - "ACCOUNT_NAME": AZURE_STORAGE_ACCOUNT, - "ACCOUNT_KEY": AZURE_STORAGE_KEY, - "CDN_HOST": None, - "USE_SSL": False, -} -# instead of: if AZURE_STORAGE_ACCOUNT: DEFAULT_FILE_STORAGE = "api.storage.AzureStorage" -# > https://django-storages.readthedocs.io/en/latest/backends/azure.html - -AZURE_ACCOUNT_NAME = env("AZURE_STORAGE_ACCOUNT") -AZURE_ACCOUNT_KEY = env("AZURE_STORAGE_KEY") -AZURE_CONTAINER = "api" -if AZURE_STORAGE_ACCOUNT: - DEFAULT_FILE_STORAGE = "storages.backends.azure_storage.AzureStorage" +if env("AZURE_STORAGE_ENABLED"): + + AZURE_STORAGE_CONFIG_OPTIONS = { + "connection_string": env("AZURE_STORAGE_CONNECTION_STRING"), + "overwrite_files": False, + } + + if not env("AZURE_STORAGE_CONNECTION_STRING"): + AZURE_STORAGE_CONFIG_OPTIONS.update( + { + "account_name": env("AZURE_STORAGE_ACCOUNT"), + "account_key": env("AZURE_STORAGE_KEY"), + "token_credential": env("AZURE_STORAGE_TOKEN_CREDENTIAL"), + } + ) + + if env("AZURE_STORAGE_MANAGED_IDENTITY"): + AZURE_STORAGE_CONFIG_OPTIONS["token_credential"] = DefaultAzureCredential() + + STORAGES = { + "default": { + "BACKEND": "storages.backends.azure_storage.AzureStorage", + "OPTIONS": { + **AZURE_STORAGE_CONFIG_OPTIONS, + "azure_container": "api", + }, + }, + # TODO: Use this instead of nginx for staticfiles + # "staticfiles": { + # "BACKEND": "storages.backends.azure_storage.AzureStorage", + # "OPTIONS": { + # **AZURE_STORAGE_CONFIG_OPTIONS, + # "azure_container": env("AZURE_STORAGE_STATIC_CONTAINER"), + # "overwrite_files": True, + # }, + # }, + } +else: + # Filesystem + MEDIA_ROOT = env("DJANGO_MEDIA_ROOT") + STATIC_ROOT = env("DJANGO_STATIC_ROOT") # Email config FORCE_USE_SMTP = env("FORCE_USE_SMTP") diff --git a/poetry.lock b/poetry.lock index 60529cc45..d6f939acc 100644 --- a/poetry.lock +++ b/poetry.lock @@ -154,6 +154,43 @@ files = [ {file = "azure_common-1.1.19-py2.py3-none-any.whl", hash = "sha256:14722caf6c3ed81d2cfdd3e448635fdc78f214dc6f17558dd1ca5b87bccc0631"}, ] +[[package]] +name = "azure-core" +version = "1.32.0" +description = "Microsoft Azure Core Library for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "azure_core-1.32.0-py3-none-any.whl", hash = "sha256:eac191a0efb23bfa83fddf321b27b122b4ec847befa3091fa736a5c32c50d7b4"}, + {file = "azure_core-1.32.0.tar.gz", hash = "sha256:22b3c35d6b2dae14990f6c1be2912bf23ffe50b220e708a28ab1bb92b1c730e5"}, +] + +[package.dependencies] +requests = ">=2.21.0" +six = ">=1.11.0" +typing-extensions = ">=4.6.0" + +[package.extras] +aio = ["aiohttp (>=3.0)"] + +[[package]] +name = "azure-identity" +version = "1.20.0" +description = "Microsoft Azure Identity Library for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "azure_identity-1.20.0-py3-none-any.whl", hash = "sha256:5f23fc4889a66330e840bd78830287e14f3761820fe3c5f77ac875edcb9ec998"}, + {file = "azure_identity-1.20.0.tar.gz", hash = "sha256:40597210d56c83e15031b0fe2ea3b26420189e1e7f3e20bdbb292315da1ba014"}, +] + +[package.dependencies] +azure-core = ">=1.31.0" +cryptography = ">=2.5" +msal = ">=1.30.0" +msal-extensions = ">=1.2.0" +typing-extensions = ">=4.0.0" + [[package]] name = "azure-nspkg" version = "3.0.2" @@ -1190,6 +1227,7 @@ files = [ ] [package.dependencies] +azure-storage-blob = {version = ">=1.3.1,<12.0.0", optional = true, markers = "extra == \"azure\""} Django = ">=2.2" [package.extras] @@ -2197,6 +2235,40 @@ click = ">=3.0" dev = ["check-manifest"] test = ["coveralls", "hypothesis", "pydocstyle", "pytest-cov"] +[[package]] +name = "msal" +version = "1.31.1" +description = "The Microsoft Authentication Library (MSAL) for Python library enables your app to access the Microsoft Cloud by supporting authentication of users with Microsoft Azure Active Directory accounts (AAD) and Microsoft Accounts (MSA) using industry standard OAuth2 and OpenID Connect." +optional = false +python-versions = ">=3.7" +files = [ + {file = "msal-1.31.1-py3-none-any.whl", hash = "sha256:29d9882de247e96db01386496d59f29035e5e841bcac892e6d7bf4390bf6bd17"}, + {file = "msal-1.31.1.tar.gz", hash = "sha256:11b5e6a3f802ffd3a72107203e20c4eac6ef53401961b880af2835b723d80578"}, +] + +[package.dependencies] +cryptography = ">=2.5,<46" +PyJWT = {version = ">=1.0.0,<3", extras = ["crypto"]} +requests = ">=2.0.0,<3" + +[package.extras] +broker = ["pymsalruntime (>=0.14,<0.18)", "pymsalruntime (>=0.17,<0.18)"] + +[[package]] +name = "msal-extensions" +version = "1.2.0" +description = "Microsoft Authentication Library extensions (MSAL EX) provides a persistence API that can save your data on disk, encrypted on Windows, macOS and Linux. Concurrent data access will be coordinated by a file lock mechanism." +optional = false +python-versions = ">=3.7" +files = [ + {file = "msal_extensions-1.2.0-py3-none-any.whl", hash = "sha256:cf5ba83a2113fa6dc011a254a72f1c223c88d7dfad74cc30617c4679a417704d"}, + {file = "msal_extensions-1.2.0.tar.gz", hash = "sha256:6f41b320bfd2933d631a215c91ca0dd3e67d84bd1a2f50ce917d5874ec646bef"}, +] + +[package.dependencies] +msal = ">=1.29,<2" +portalocker = ">=1.4,<3" + [[package]] name = "numpy" version = "1.26.4" @@ -2596,6 +2668,25 @@ files = [ {file = "polib-1.1.0.tar.gz", hash = "sha256:fad87d13696127ffb27ea0882d6182f1a9cf8a5e2b37a587751166c51e5a332a"}, ] +[[package]] +name = "portalocker" +version = "2.10.1" +description = "Wraps the portalocker recipe for easy usage" +optional = false +python-versions = ">=3.8" +files = [ + {file = "portalocker-2.10.1-py3-none-any.whl", hash = "sha256:53a5984ebc86a025552264b459b46a2086e269b21823cb572f8f28ee759e45bf"}, + {file = "portalocker-2.10.1.tar.gz", hash = "sha256:ef1bf844e878ab08aee7e40184156e1151f228f103aa5c6bd0724cc330960f8f"}, +] + +[package.dependencies] +pywin32 = {version = ">=226", markers = "platform_system == \"Windows\""} + +[package.extras] +docs = ["sphinx (>=1.7.1)"] +redis = ["redis"] +tests = ["pytest (>=5.4.1)", "pytest-cov (>=2.8.1)", "pytest-mypy (>=0.8.0)", "pytest-timeout (>=2.1.0)", "redis", "sphinx (>=6.0.0)", "types-redis"] + [[package]] name = "promise" version = "2.3" @@ -3108,6 +3199,9 @@ files = [ {file = "pyjwt-2.9.0.tar.gz", hash = "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c"}, ] +[package.dependencies] +cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"crypto\""} + [package.extras] crypto = ["cryptography (>=3.4.0)"] dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"] @@ -3455,6 +3549,33 @@ files = [ {file = "pytz-2019.1.tar.gz", hash = "sha256:d747dd3d23d77ef44c6a3526e274af6efeb0a6f1afd5a69ba4d5be4098c8e141"}, ] +[[package]] +name = "pywin32" +version = "308" +description = "Python for Window Extensions" +optional = false +python-versions = "*" +files = [ + {file = "pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e"}, + {file = "pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e"}, + {file = "pywin32-308-cp310-cp310-win_arm64.whl", hash = "sha256:a5ab5381813b40f264fa3495b98af850098f814a25a63589a8e9eb12560f450c"}, + {file = "pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a"}, + {file = "pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b"}, + {file = "pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6"}, + {file = "pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897"}, + {file = "pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47"}, + {file = "pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091"}, + {file = "pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed"}, + {file = "pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4"}, + {file = "pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd"}, + {file = "pywin32-308-cp37-cp37m-win32.whl", hash = "sha256:1f696ab352a2ddd63bd07430080dd598e6369152ea13a25ebcdd2f503a38f1ff"}, + {file = "pywin32-308-cp37-cp37m-win_amd64.whl", hash = "sha256:13dcb914ed4347019fbec6697a01a0aec61019c1046c2b905410d197856326a6"}, + {file = "pywin32-308-cp38-cp38-win32.whl", hash = "sha256:5794e764ebcabf4ff08c555b31bd348c9025929371763b2183172ff4708152f0"}, + {file = "pywin32-308-cp38-cp38-win_amd64.whl", hash = "sha256:3b92622e29d651c6b783e368ba7d6722b1634b8e70bd376fd7610fe1992e19de"}, + {file = "pywin32-308-cp39-cp39-win32.whl", hash = "sha256:7873ca4dc60ab3287919881a7d4f88baee4a6e639aa6962de25a98ba6b193341"}, + {file = "pywin32-308-cp39-cp39-win_amd64.whl", hash = "sha256:71b3322d949b4cc20776436a9c9ba0eeedcbc9c650daa536df63f0ff111bb920"}, +] + [[package]] name = "pyyaml" version = "6.0.2" @@ -4380,4 +4501,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "37c91e4e89aefb6510e90679a03c13aad13768fb89962a602f29312a4bfff58e" +content-hash = "80527c9b7d116e6c22ad4737c1fda95bebf49d0deca884a195db9e4bfccaa7b8" diff --git a/pyproject.toml b/pyproject.toml index efb9464f9..f86accba5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,7 @@ django-modeltranslation = "==0.17.5" django-read-only = "==1.12.0" django-reversion-compare = "==0.16.2" django-reversion = "==5.0.12" -django-storages = "==1.11.1" +django-storages = { version = "==1.11.1", extras = ["azure"] } django-tinymce = "==4.1.0" django-oauth-toolkit = "3.0.1" djangorestframework-csv = "==2.1.1" @@ -88,7 +88,7 @@ drf-spectacular = "*" pyjwt = "*" shapely = "*" colorlog = "*" - +azure-identity = "*" # Required by django-storages[azure] if used mapbox-tilesets = "*" ipython = "*" tiktoken = "*" From 359748951baf7e6ec2806a67db83731efaa1af20 Mon Sep 17 00:00:00 2001 From: thenav56 Date: Tue, 18 Feb 2025 16:11:42 +0545 Subject: [PATCH 08/17] Replace custom redis with bitnami redis with persistence storage --- deploy/helm/ifrcgo-helm/.gitignore | 1 + deploy/helm/ifrcgo-helm/Chart.yaml | 6 ++++ deploy/helm/ifrcgo-helm/requirements.lock | 6 ++++ .../templates/config/configmap.yaml | 11 ++++++-- deploy/helm/ifrcgo-helm/values.yaml | 28 ++++++++++++------- 5 files changed, 40 insertions(+), 12 deletions(-) create mode 100644 deploy/helm/ifrcgo-helm/requirements.lock diff --git a/deploy/helm/ifrcgo-helm/.gitignore b/deploy/helm/ifrcgo-helm/.gitignore index 452299a25..3c72606c4 100644 --- a/deploy/helm/ifrcgo-helm/.gitignore +++ b/deploy/helm/ifrcgo-helm/.gitignore @@ -1,2 +1,3 @@ .helm-charts values-local.yaml +charts diff --git a/deploy/helm/ifrcgo-helm/Chart.yaml b/deploy/helm/ifrcgo-helm/Chart.yaml index c1cb05b22..ebec36a27 100644 --- a/deploy/helm/ifrcgo-helm/Chart.yaml +++ b/deploy/helm/ifrcgo-helm/Chart.yaml @@ -5,3 +5,9 @@ version: 0.0.2-SET-BY-CICD sources: - https://github.com/IFRCGo/go-api + +dependencies: + - name: redis + version: "20.7.1" + repository: https://charts.bitnami.com/bitnami + condition: redis.enabled diff --git a/deploy/helm/ifrcgo-helm/requirements.lock b/deploy/helm/ifrcgo-helm/requirements.lock new file mode 100644 index 000000000..e18430071 --- /dev/null +++ b/deploy/helm/ifrcgo-helm/requirements.lock @@ -0,0 +1,6 @@ +dependencies: +- name: redis + repository: https://charts.bitnami.com/bitnami + version: 20.7.1 +digest: sha256:1852c9489ae647e0394ccb39fa70787bb29ebbdbe24b89b914ce01a2adc6ff29 +generated: "2025-02-18T16:08:53.322089326+05:45" diff --git a/deploy/helm/ifrcgo-helm/templates/config/configmap.yaml b/deploy/helm/ifrcgo-helm/templates/config/configmap.yaml index 0005122b5..2fa5e258e 100644 --- a/deploy/helm/ifrcgo-helm/templates/config/configmap.yaml +++ b/deploy/helm/ifrcgo-helm/templates/config/configmap.yaml @@ -7,8 +7,15 @@ metadata: environment: {{ .Values.environment }} release: {{ .Release.Name }} data: - CELERY_REDIS_URL: "redis://{{ template "ifrcgo-helm.fullname" . }}-redis:6379/0" - CACHE_REDIS_URL: "redis://{{ template "ifrcgo-helm.fullname" . }}-redis:6379/1" + # Redis + {{- if .Values.redis.enabled }} + CELERY_REDIS_URL: "redis://{{ printf "%s-master" (include "common.names.fullname" .Subcharts.redis) }}:6379/0" + CACHE_REDIS_URL: "redis://{{ printf "%s-master" (include "common.names.fullname" .Subcharts.redis) }}:6379/1" + {{- else }} + CELERY_REDIS_URL: {{ required "env.CELERY_REDIS_URL" .Values.env.CELERY_REDIS_URL | quote }} + CACHE_REDIS_URL: {{ required "env.CACHE_REDIS_URL" .Values.env.CACHE_REDIS_URL | quote }} + {{- end }} + CACHE_MIDDLEWARE_SECONDS: {{ .Values.env.CACHE_MIDDLEWARE_SECONDS | quote }} DJANGO_DEBUG: {{ .Values.env.DJANGO_DEBUG | quote }} ELASTIC_SEARCH_HOST: {{ default (printf "elasticsearch://%s-elasticsearch:9200" (include "ifrcgo-helm.fullname" .)) .Values.env.ELASTIC_SEARCH_HOST | quote }} diff --git a/deploy/helm/ifrcgo-helm/values.yaml b/deploy/helm/ifrcgo-helm/values.yaml index 63ffde1a7..b4c01725b 100644 --- a/deploy/helm/ifrcgo-helm/values.yaml +++ b/deploy/helm/ifrcgo-helm/values.yaml @@ -84,6 +84,24 @@ secretsAdditional: # Additional secrets # EXAMPLE: MY_SECRET: "my-secret-value" +redis: + enabled: true + architecture: standalone + fullnameOverride: go-redis + auth: + enabled: false + master: + persistence: + enabled: true + size: 1Gi + resources: + requests: + cpu: "0.5" + memory: 1Gi + limits: + cpu: "1" + memory: 2Gi + api: domain: "go-staging.ifrc.org" tls: @@ -104,16 +122,6 @@ api: cpu: "2" memory: 4Gi -redis: - enabled: true - resources: - requests: - cpu: "0.5" - memory: 1Gi - limits: - cpu: "1" - memory: 2Gi - celery: enabled: true resources: From 050c32dd858eba6699c719de6be17b52222122a6 Mon Sep 17 00:00:00 2001 From: thenav56 Date: Tue, 18 Feb 2025 16:16:48 +0545 Subject: [PATCH 09/17] Add bitnami postgresql as helm dependency - Use for alpha instances --- deploy/helm/ifrcgo-helm/Chart.yaml | 4 ++++ deploy/helm/ifrcgo-helm/requirements.lock | 7 +++++-- .../ifrcgo-helm/templates/config/secret.yaml | 21 ++++++++++++++----- deploy/helm/ifrcgo-helm/values.yaml | 9 ++++++++ 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/deploy/helm/ifrcgo-helm/Chart.yaml b/deploy/helm/ifrcgo-helm/Chart.yaml index ebec36a27..27abbcddb 100644 --- a/deploy/helm/ifrcgo-helm/Chart.yaml +++ b/deploy/helm/ifrcgo-helm/Chart.yaml @@ -11,3 +11,7 @@ dependencies: version: "20.7.1" repository: https://charts.bitnami.com/bitnami condition: redis.enabled + - name: postgresql + version: 16.4.9 + condition: postgresql.enabled + repository: https://charts.bitnami.com/bitnami diff --git a/deploy/helm/ifrcgo-helm/requirements.lock b/deploy/helm/ifrcgo-helm/requirements.lock index e18430071..4e04c0e52 100644 --- a/deploy/helm/ifrcgo-helm/requirements.lock +++ b/deploy/helm/ifrcgo-helm/requirements.lock @@ -2,5 +2,8 @@ dependencies: - name: redis repository: https://charts.bitnami.com/bitnami version: 20.7.1 -digest: sha256:1852c9489ae647e0394ccb39fa70787bb29ebbdbe24b89b914ce01a2adc6ff29 -generated: "2025-02-18T16:08:53.322089326+05:45" +- name: postgresql + repository: https://charts.bitnami.com/bitnami + version: 16.4.9 +digest: sha256:ccb7b5c911cae85ec6358f0cf09db34c2fa53a0ebb11fa8ba0426ba991e89c18 +generated: "2025-02-18T16:12:59.123394069+05:45" diff --git a/deploy/helm/ifrcgo-helm/templates/config/secret.yaml b/deploy/helm/ifrcgo-helm/templates/config/secret.yaml index 0be17f286..c5d3925b1 100644 --- a/deploy/helm/ifrcgo-helm/templates/config/secret.yaml +++ b/deploy/helm/ifrcgo-helm/templates/config/secret.yaml @@ -9,11 +9,22 @@ metadata: type: Opaque stringData: DJANGO_SECRET_KEY: "{{ .Values.env.DJANGO_SECRET_KEY }}" - DJANGO_DB_NAME: "{{ .Values.env.DJANGO_DB_NAME }}" - DJANGO_DB_USER: "{{ .Values.env.DJANGO_DB_USER }}" - DJANGO_DB_PASS: "{{ .Values.env.DJANGO_DB_PASS }}" - DJANGO_DB_HOST: "{{ .Values.env.DJANGO_DB_HOST }}" - DJANGO_DB_PORT: "{{ .Values.env.DJANGO_DB_PORT }}" + + # Database + {{- if .Values.postgresql.enabled }} + DJANGO_DB_HOST: {{ include "postgresql.v1.primary.fullname" .Subcharts.postgresql }} + DJANGO_DB_PORT: {{ include "postgresql.v1.service.port" .Subcharts.postgresql | quote }} + DJANGO_DB_NAME: {{ .Values.postgresql.auth.database | quote }} + DJANGO_DB_USER: {{ default "postgres" .Values.postgresql.auth.username | quote }} + DJANGO_DB_PASS: {{ default .Values.postgresql.auth.postgresPassword .Values.postgresql.auth.password | quote }} + {{- else }} + DJANGO_DB_NAME: {{ .Values.env.DJANGO_DB_NAME | quote }} + DJANGO_DB_USER: {{ .Values.env.DJANGO_DB_USER | quote }} + DJANGO_DB_PASS: {{ .Values.env.DJANGO_DB_PASS | quote }} + DJANGO_DB_HOST: {{ .Values.env.DJANGO_DB_HOST | quote }} + DJANGO_DB_PORT: {{ .Values.env.DJANGO_DB_PORT | quote }} + {{- end }} + AZURE_STORAGE_ACCOUNT: "{{ .Values.env.AZURE_STORAGE_ACCOUNT }}" AZURE_STORAGE_KEY: "{{ .Values.env.AZURE_STORAGE_KEY }}" EMAIL_API_ENDPOINT: "{{ .Values.env.EMAIL_API_ENDPOINT }}" diff --git a/deploy/helm/ifrcgo-helm/values.yaml b/deploy/helm/ifrcgo-helm/values.yaml index b4c01725b..ed7fa4017 100644 --- a/deploy/helm/ifrcgo-helm/values.yaml +++ b/deploy/helm/ifrcgo-helm/values.yaml @@ -102,6 +102,15 @@ redis: cpu: "1" memory: 2Gi +postgresql: + enabled: false # XXX: Used for alpha instances running outside Azure + fullnameOverride: "go-pg" + architecture: standalone + primary: + persistence: + enabled: true + size: 8Gi + api: domain: "go-staging.ifrc.org" tls: From df54fb643a08a0a12c1a2ba6e36444081009d5c8 Mon Sep 17 00:00:00 2001 From: thenav56 Date: Tue, 18 Feb 2025 16:17:50 +0545 Subject: [PATCH 10/17] Add support for S3 storage backend - Use for alpha instances - Add minio as helm chart dependency --- deploy/helm/ifrcgo-helm/Chart.yaml | 4 ++ deploy/helm/ifrcgo-helm/requirements.lock | 7 +++- .../ifrcgo-helm/templates/config/secret.yaml | 11 +++++ deploy/helm/ifrcgo-helm/values.yaml | 31 ++++++++++++++ main/settings.py | 40 +++++++++++++++++++ poetry.lock | 2 +- pyproject.toml | 2 +- 7 files changed, 93 insertions(+), 4 deletions(-) diff --git a/deploy/helm/ifrcgo-helm/Chart.yaml b/deploy/helm/ifrcgo-helm/Chart.yaml index 27abbcddb..8a5c889cc 100644 --- a/deploy/helm/ifrcgo-helm/Chart.yaml +++ b/deploy/helm/ifrcgo-helm/Chart.yaml @@ -15,3 +15,7 @@ dependencies: version: 16.4.9 condition: postgresql.enabled repository: https://charts.bitnami.com/bitnami + - name: minio + version: 15.0.3 + condition: minio.enabled + repository: https://charts.bitnami.com/bitnami diff --git a/deploy/helm/ifrcgo-helm/requirements.lock b/deploy/helm/ifrcgo-helm/requirements.lock index 4e04c0e52..7c548243e 100644 --- a/deploy/helm/ifrcgo-helm/requirements.lock +++ b/deploy/helm/ifrcgo-helm/requirements.lock @@ -5,5 +5,8 @@ dependencies: - name: postgresql repository: https://charts.bitnami.com/bitnami version: 16.4.9 -digest: sha256:ccb7b5c911cae85ec6358f0cf09db34c2fa53a0ebb11fa8ba0426ba991e89c18 -generated: "2025-02-18T16:12:59.123394069+05:45" +- name: minio + repository: https://charts.bitnami.com/bitnami + version: 15.0.3 +digest: sha256:a4d204e014228cb7670468d6ec03f567918084eb4bc2f7429b2ec6531bdc2681 +generated: "2025-02-18T16:16:13.450899724+05:45" diff --git a/deploy/helm/ifrcgo-helm/templates/config/secret.yaml b/deploy/helm/ifrcgo-helm/templates/config/secret.yaml index c5d3925b1..42e657822 100644 --- a/deploy/helm/ifrcgo-helm/templates/config/secret.yaml +++ b/deploy/helm/ifrcgo-helm/templates/config/secret.yaml @@ -25,6 +25,17 @@ stringData: DJANGO_DB_PORT: {{ .Values.env.DJANGO_DB_PORT | quote }} {{- end }} + # Minio + {{- if .Values.minio.enabled }} + AWS_S3_ENABLED: "true" + AWS_S3_ENDPOINT_URL: "https://{{ .Values.minio.apiIngress.hostname }}/" + AWS_S3_ACCESS_KEY_ID: {{ required ".Values.minio.auth.rootUser" .Values.minio.auth.rootUser }} + AWS_S3_SECRET_ACCESS_KEY: {{ required ".Values.minio.auth.rootPassword" .Values.minio.auth.rootPassword }} + AWS_S3_REGION_NAME: "us-east-1" + AWS_S3_MEDIA_BUCKET_NAME: "go-data" + AWS_S3_STATIC_BUCKET_NAME: "go-static" + {{- end }} + AZURE_STORAGE_ACCOUNT: "{{ .Values.env.AZURE_STORAGE_ACCOUNT }}" AZURE_STORAGE_KEY: "{{ .Values.env.AZURE_STORAGE_KEY }}" EMAIL_API_ENDPOINT: "{{ .Values.env.EMAIL_API_ENDPOINT }}" diff --git a/deploy/helm/ifrcgo-helm/values.yaml b/deploy/helm/ifrcgo-helm/values.yaml index ed7fa4017..a909f0bb8 100644 --- a/deploy/helm/ifrcgo-helm/values.yaml +++ b/deploy/helm/ifrcgo-helm/values.yaml @@ -102,6 +102,37 @@ redis: cpu: "1" memory: 2Gi +# https://artifacthub.io/packages/helm/bitnami/minio +# extraEnvVars: https://github.com/bitnami/containers/blob/main/bitnami/minio/README.md#environment-variables +minio: + enabled: false # XXX: Used for alpha instances running outside Azure + disableWebUI: true + mode: standalone + fullnameOverride: go-minio + global: + defaultStorageClass: + apiIngress: + enabled: true + ingressClassName: + hostname: + annotations: + nginx.ingress.kubernetes.io/proxy-body-size: "50m" + auth: + forceNewKeys: True + rootUser: go + rootPassword: + persistence: + enabled: true + size: 1Gi + defaultBuckets: go-data,go-static + provisioning: + enabled: true + resourcesPreset: "nano" + cleanupAfterFinished: + enabled: true + extraCommands: + - "mc anonymous set download provisioning/go-static" + postgresql: enabled: false # XXX: Used for alpha instances running outside Azure fullnameOverride: "go-pg" diff --git a/main/settings.py b/main/settings.py index 307d66f42..fbedec46e 100644 --- a/main/settings.py +++ b/main/settings.py @@ -46,6 +46,14 @@ AZURE_STORAGE_KEY=(str, None), AZURE_STORAGE_TOKEN_CREDENTIAL=(str, None), AZURE_STORAGE_MANAGED_IDENTITY=(bool, False), + # -- S3 storage + AWS_S3_ENABLED=(bool, False), + AWS_S3_ENDPOINT_URL=(str, None), + AWS_S3_ACCESS_KEY_ID=str, + AWS_S3_SECRET_ACCESS_KEY=str, + AWS_S3_REGION_NAME=str, + AWS_S3_MEDIA_BUCKET_NAME=str, + AWS_S3_STATIC_BUCKET_NAME=str, # -- Filesystem (default) XXX: Don't use for production DJANGO_MEDIA_ROOT=(str, os.path.join(BASE_DIR, "media")), DJANGO_STATIC_ROOT=(str, os.path.join(BASE_DIR, "static")), @@ -500,6 +508,38 @@ def parse_domain(*env_keys: str) -> str: # }, # }, } + +# NOTE: This is used for instances outside azure environment +elif env("AWS_S3_ENABLED"): + AWS_S3_CONFIG_OPTIONS = { + "endpoint_url": env("AWS_S3_ENDPOINT_URL"), + "access_key": env("AWS_S3_ACCESS_KEY_ID"), + "secret_key": env("AWS_S3_SECRET_ACCESS_KEY"), + "region_name": env("AWS_S3_REGION_NAME"), + } + + STORAGES = { + "default": { + "BACKEND": "storages.backends.s3boto3.S3Boto3Storage", + "OPTIONS": { + **AWS_S3_CONFIG_OPTIONS, + "bucket_name": env("AWS_S3_MEDIA_BUCKET_NAME"), + "location": "media/", + "file_overwrite": False, + }, + }, + "staticfiles": { + "BACKEND": "storages.backends.s3boto3.S3Boto3Storage", + "OPTIONS": { + **AWS_S3_CONFIG_OPTIONS, + "bucket_name": env("AWS_S3_STATIC_BUCKET_NAME"), + "querystring_auth": False, + "location": "static/", + "file_overwrite": True, + }, + }, + } + else: # Filesystem MEDIA_ROOT = env("DJANGO_MEDIA_ROOT") diff --git a/poetry.lock b/poetry.lock index d6f939acc..b49a596a4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4501,4 +4501,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "80527c9b7d116e6c22ad4737c1fda95bebf49d0deca884a195db9e4bfccaa7b8" +content-hash = "9ff1ef3b0a1403e97dab266291ec7875f7b65361dc78c21f02bfcb7e6c95ec49" diff --git a/pyproject.toml b/pyproject.toml index f86accba5..4d8d9274c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,7 @@ django-modeltranslation = "==0.17.5" django-read-only = "==1.12.0" django-reversion-compare = "==0.16.2" django-reversion = "==5.0.12" -django-storages = { version = "==1.11.1", extras = ["azure"] } +django-storages = { version = "==1.11.1", extras = ["s3", "azure"] } django-tinymce = "==4.1.0" django-oauth-toolkit = "3.0.1" djangorestframework-csv = "==2.1.1" From ca166104aeaf902de8ca2a0eee6d53b3bd51331e Mon Sep 17 00:00:00 2001 From: thenav56 Date: Tue, 18 Feb 2025 16:29:21 +0545 Subject: [PATCH 11/17] Add helm dependencies step in CI - Upgrade helm chart version to v2 --- .github/workflows/build-publish-docker-helm.yml | 2 +- .github/workflows/ci.yml | 12 ++++++++++-- .../ifrcgo-helm/{requirements.lock => Chart.lock} | 2 +- deploy/helm/ifrcgo-helm/Chart.yaml | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) rename deploy/helm/ifrcgo-helm/{requirements.lock => Chart.lock} (87%) diff --git a/.github/workflows/build-publish-docker-helm.yml b/.github/workflows/build-publish-docker-helm.yml index f18803c3f..9099d9614 100644 --- a/.github/workflows/build-publish-docker-helm.yml +++ b/.github/workflows/build-publish-docker-helm.yml @@ -42,7 +42,7 @@ jobs: - name: 🐳 Helm dependency working-directory: deploy/helm/ifrcgo-helm run: | - yq --indent 0 '.dependencies | map(["helm", "repo", "add", .name, .repository] | join(" ")) | .[]' ./helm/Chart.lock | sh -- + yq --indent 0 '.dependencies | map(["helm", "repo", "add", .name, .repository] | join(" ")) | .[]' ./Chart.lock | sh -- helm dependency build ./ - name: Tag docker image in Helm Chart values.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 52b5cccdc..d5b7375c3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -136,8 +136,16 @@ jobs: - name: Install Helm uses: azure/setup-helm@v4 + - name: 🐳 Helm dependency + working-directory: deploy/helm/ifrcgo-helm + run: | + yq --indent 0 '.dependencies | map(["helm", "repo", "add", .name, .repository] | join(" ")) | .[]' ./Chart.lock | sh -- + helm dependency build ./ + - name: 🐳 Helm lint - run: helm lint deploy/helm/ifrcgo-helm --values ./deploy/helm/ifrcgo-helm/values-staging.yaml + working-directory: deploy/helm/ifrcgo-helm + run: helm lint ./ --values ./values-staging.yaml - name: 🐳 Helm template - run: helm template deploy/helm/ifrcgo-helm --values ./deploy/helm/ifrcgo-helm/values-staging.yaml + working-directory: deploy/helm/ifrcgo-helm + run: helm template ./ --values ./values-staging.yaml diff --git a/deploy/helm/ifrcgo-helm/requirements.lock b/deploy/helm/ifrcgo-helm/Chart.lock similarity index 87% rename from deploy/helm/ifrcgo-helm/requirements.lock rename to deploy/helm/ifrcgo-helm/Chart.lock index 7c548243e..9d132bdc2 100644 --- a/deploy/helm/ifrcgo-helm/requirements.lock +++ b/deploy/helm/ifrcgo-helm/Chart.lock @@ -9,4 +9,4 @@ dependencies: repository: https://charts.bitnami.com/bitnami version: 15.0.3 digest: sha256:a4d204e014228cb7670468d6ec03f567918084eb4bc2f7429b2ec6531bdc2681 -generated: "2025-02-18T16:16:13.450899724+05:45" +generated: "2025-02-18T16:46:12.682756654+05:45" diff --git a/deploy/helm/ifrcgo-helm/Chart.yaml b/deploy/helm/ifrcgo-helm/Chart.yaml index 8a5c889cc..7d46a00bf 100644 --- a/deploy/helm/ifrcgo-helm/Chart.yaml +++ b/deploy/helm/ifrcgo-helm/Chart.yaml @@ -1,4 +1,4 @@ -apiVersion: v1 +apiVersion: v2 description: "Helm Chart to deploy the IFRC GO Infrastructure" name: ifrcgo-helm version: 0.0.2-SET-BY-CICD From bfb23d2f6a556d6e48d06b11a5bc3f38745ab638 Mon Sep 17 00:00:00 2001 From: thenav56 Date: Tue, 18 Feb 2025 21:24:30 +0545 Subject: [PATCH 12/17] Use static template tags for go-logo in admin panel Additional label changes --- api/tasks.py | 2 +- api/templates/admin/base_site.html | 2 +- main/settings.py | 15 ++++++--------- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/api/tasks.py b/api/tasks.py index ed00ea508..b2508da1d 100644 --- a/api/tasks.py +++ b/api/tasks.py @@ -137,7 +137,7 @@ def generate_url(url, export_id, user, title): ) except Exception: logger.error( - "Failed to export PDF", + f"Failed to export PDF: {export.export_type}", exc_info=True, extra=logger_context(dict(export_id=export.pk)), ) diff --git a/api/templates/admin/base_site.html b/api/templates/admin/base_site.html index aac57c477..2c4015dea 100644 --- a/api/templates/admin/base_site.html +++ b/api/templates/admin/base_site.html @@ -8,7 +8,7 @@

- + {% if HAVING_INGEST_ISSUE and request.user.is_superuser %} diff --git a/main/settings.py b/main/settings.py index fbedec46e..d9a34e374 100644 --- a/main/settings.py +++ b/main/settings.py @@ -54,7 +54,7 @@ AWS_S3_REGION_NAME=str, AWS_S3_MEDIA_BUCKET_NAME=str, AWS_S3_STATIC_BUCKET_NAME=str, - # -- Filesystem (default) XXX: Don't use for production + # -- Filesystem (default) XXX: Don't use in production DJANGO_MEDIA_ROOT=(str, os.path.join(BASE_DIR, "media")), DJANGO_STATIC_ROOT=(str, os.path.join(BASE_DIR, "static")), # Email @@ -155,10 +155,7 @@ def find_env_with_value(*keys: str) -> None | str: def parse_domain(*env_keys: str) -> str: - """ - NOTE: This is used for to avoid breaking due to existing config value - Update this using django validation - """ + # FIXME: This is for backward compatibility for the existing config value env_key = find_env_with_value(*env_keys) raw_domain = env(env_key) domain = raw_domain @@ -170,10 +167,10 @@ def parse_domain(*env_keys: str) -> str: GO_API_URL = parse_domain("API_FQDN") GO_WEB_URL = parse_domain("FRONTEND_URL") -# NOTE: Used in local development to get to the frontend service from within go-api container -# GO_WEB_URL will be used if GO_WEB_INTERNAL_URL is not provided +# NOTE: Used in local development to point to the frontend service from within go-api container +# Default to GO_WEB_URL if GO_WEB_INTERNAL_URL is not provided GO_WEB_INTERNAL_URL = parse_domain("GO_WEB_INTERNAL_URL", "FRONTEND_URL") -FRONTEND_URL = urlparse(GO_WEB_URL).hostname # XXX: Deprecated. Slowly remove this from codebase +FRONTEND_URL = urlparse(GO_WEB_URL).hostname # FIXME: Deprecated. Slowly remove this from codebase INTERNAL_IPS = ["127.0.0.1"] if env("DOCKER_HOST_IP"): @@ -498,7 +495,7 @@ def parse_domain(*env_keys: str) -> str: "azure_container": "api", }, }, - # TODO: Use this instead of nginx for staticfiles + # FIXME: Use this instead of nginx for staticfiles # "staticfiles": { # "BACKEND": "storages.backends.azure_storage.AzureStorage", # "OPTIONS": { From a4dbbcae4ac068f1e07469984983d35e482a0baa Mon Sep 17 00:00:00 2001 From: thenav56 Date: Fri, 21 Feb 2025 09:39:25 +0545 Subject: [PATCH 13/17] Default to AZURE_STORAGE in helm chart config --- deploy/helm/ifrcgo-helm/templates/config/configmap.yaml | 6 ++++++ deploy/helm/ifrcgo-helm/templates/config/secret.yaml | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/deploy/helm/ifrcgo-helm/templates/config/configmap.yaml b/deploy/helm/ifrcgo-helm/templates/config/configmap.yaml index 2fa5e258e..dafd238e7 100644 --- a/deploy/helm/ifrcgo-helm/templates/config/configmap.yaml +++ b/deploy/helm/ifrcgo-helm/templates/config/configmap.yaml @@ -16,6 +16,12 @@ data: CACHE_REDIS_URL: {{ required "env.CACHE_REDIS_URL" .Values.env.CACHE_REDIS_URL | quote }} {{- end }} + {{- if .Values.minio.enabled }} + AWS_S3_ENABLED: "true" + {{- else }} + AZURE_STORAGE_ENABLED: "true" + {{- end }} + CACHE_MIDDLEWARE_SECONDS: {{ .Values.env.CACHE_MIDDLEWARE_SECONDS | quote }} DJANGO_DEBUG: {{ .Values.env.DJANGO_DEBUG | quote }} ELASTIC_SEARCH_HOST: {{ default (printf "elasticsearch://%s-elasticsearch:9200" (include "ifrcgo-helm.fullname" .)) .Values.env.ELASTIC_SEARCH_HOST | quote }} diff --git a/deploy/helm/ifrcgo-helm/templates/config/secret.yaml b/deploy/helm/ifrcgo-helm/templates/config/secret.yaml index 42e657822..1615a00e3 100644 --- a/deploy/helm/ifrcgo-helm/templates/config/secret.yaml +++ b/deploy/helm/ifrcgo-helm/templates/config/secret.yaml @@ -25,9 +25,8 @@ stringData: DJANGO_DB_PORT: {{ .Values.env.DJANGO_DB_PORT | quote }} {{- end }} - # Minio {{- if .Values.minio.enabled }} - AWS_S3_ENABLED: "true" + # Minio AWS_S3_ENDPOINT_URL: "https://{{ .Values.minio.apiIngress.hostname }}/" AWS_S3_ACCESS_KEY_ID: {{ required ".Values.minio.auth.rootUser" .Values.minio.auth.rootUser }} AWS_S3_SECRET_ACCESS_KEY: {{ required ".Values.minio.auth.rootPassword" .Values.minio.auth.rootPassword }} @@ -38,6 +37,7 @@ stringData: AZURE_STORAGE_ACCOUNT: "{{ .Values.env.AZURE_STORAGE_ACCOUNT }}" AZURE_STORAGE_KEY: "{{ .Values.env.AZURE_STORAGE_KEY }}" + EMAIL_API_ENDPOINT: "{{ .Values.env.EMAIL_API_ENDPOINT }}" EMAIL_HOST: "{{ .Values.env.EMAIL_HOST }}" EMAIL_PORT: "{{ .Values.env.EMAIL_PORT }}" From b36154c5458f3f368ecb58c817fd4d4e84748149 Mon Sep 17 00:00:00 2001 From: thenav56 Date: Fri, 21 Feb 2025 09:39:50 +0545 Subject: [PATCH 14/17] Add documentation for playwright exports --- README.md | 4 ++++ docs/playwright-exports.md | 39 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 docs/playwright-exports.md diff --git a/README.md b/README.md index 8d2f08231..67fcbdf29 100644 --- a/README.md +++ b/README.md @@ -293,3 +293,7 @@ To import GEC codes along with country ids, run `python manage.py import-gec-cod ## SSO setup For more info checkout [GO-SSO](./docs/go-sso.md) + +## Playwright exports + +For more info checkout [Playwright exports](./docs/playwright-exports.md) diff --git a/docs/playwright-exports.md b/docs/playwright-exports.md new file mode 100644 index 000000000..d7626ac66 --- /dev/null +++ b/docs/playwright-exports.md @@ -0,0 +1,39 @@ +## Backend + +Update `.env` with the following: +```bash +GO_WEB_INTERNAL_URL=http://host.docker.internal:3001 +# To enable playwright console/network logs +DEBUG_PLAYWRIGHT=True +``` +> [!IMPORTANT] +> A second instance of the go-web-app will run at **port 3001** for Playwright. + +Start or update containers with: +```bash +# In the background +docker compose up -d serve celery + +# In the foreground - Use this to view Playwright logs +docker compose up serve celery +``` + +## Frontend + +For setup instructions, refer to: https://github.com/IFRCGo/go-web-app/?tab=readme-ov-file#local-development + +**We need two instances of the go-web-app:** +1. For the host system (browser) on port 3000. +2. For Celery workers (Playwright browser) on port 3001. + +To start the regular go-web-app: +```bash +pnpm start:app +``` + +For the additional go-web-app instance for Playwright: +```bash +APP_API_ENDPOINT=http://host.docker.internal:8000/ pnpm start:app --host --port 3001 +``` +> [!IMPORTANT] +> The backend will be available at `host.docker.internal:8000` inside the Playwright container running within Celery. From aa7851e1c9f0c81fcc421518a52672547be1a846 Mon Sep 17 00:00:00 2001 From: thenav56 Date: Fri, 21 Feb 2025 14:37:25 +0545 Subject: [PATCH 15/17] Revert back azure blob dependencies - Add STATIC_ROOT for local static files --- main/settings.py | 27 +-- poetry.lock | 415 +++++++++++++++++++++++++++++------------------ pyproject.toml | 4 +- 3 files changed, 270 insertions(+), 176 deletions(-) diff --git a/main/settings.py b/main/settings.py index d9a34e374..0128ac149 100644 --- a/main/settings.py +++ b/main/settings.py @@ -7,7 +7,8 @@ import environ import pytz -from azure.identity import DefaultAzureCredential + +# from azure.identity import DefaultAzureCredential from corsheaders.defaults import default_headers from django.utils.translation import gettext_lazy as _ from urllib3.util.retry import Retry @@ -470,6 +471,7 @@ def parse_domain(*env_keys: str) -> str: if env("AZURE_STORAGE_ENABLED"): + STATIC_ROOT = env("DJANGO_STATIC_ROOT") AZURE_STORAGE_CONFIG_OPTIONS = { "connection_string": env("AZURE_STORAGE_CONNECTION_STRING"), "overwrite_files": False, @@ -484,8 +486,8 @@ def parse_domain(*env_keys: str) -> str: } ) - if env("AZURE_STORAGE_MANAGED_IDENTITY"): - AZURE_STORAGE_CONFIG_OPTIONS["token_credential"] = DefaultAzureCredential() + # if env("AZURE_STORAGE_MANAGED_IDENTITY"): + # AZURE_STORAGE_CONFIG_OPTIONS["token_credential"] = DefaultAzureCredential() STORAGES = { "default": { @@ -495,15 +497,16 @@ def parse_domain(*env_keys: str) -> str: "azure_container": "api", }, }, - # FIXME: Use this instead of nginx for staticfiles - # "staticfiles": { - # "BACKEND": "storages.backends.azure_storage.AzureStorage", - # "OPTIONS": { - # **AZURE_STORAGE_CONFIG_OPTIONS, - # "azure_container": env("AZURE_STORAGE_STATIC_CONTAINER"), - # "overwrite_files": True, - # }, - # }, + "staticfiles": { + "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", + # FIXME: Use this instead of nginx for staticfiles + # "BACKEND": "storages.backends.azure_storage.AzureStorage", + # "OPTIONS": { + # **AZURE_STORAGE_CONFIG_OPTIONS, + # "azure_container": env("AZURE_STORAGE_STATIC_CONTAINER"), + # "overwrite_files": True, + # }, + }, } # NOTE: This is used for instances outside azure environment diff --git a/poetry.lock b/poetry.lock index b49a596a4..b2ad3b80e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. [[package]] name = "amqp" @@ -6,6 +6,7 @@ version = "5.2.0" description = "Low-level AMQP client for Python (fork of amqplib)." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "amqp-5.2.0-py3-none-any.whl", hash = "sha256:827cb12fb0baa892aad844fd95258143bce4027fdac4fccddbc43330fd281637"}, {file = "amqp-5.2.0.tar.gz", hash = "sha256:a1ecff425ad063ad42a486c902807d1482311481c8ad95a72694b2975e75f7fd"}, @@ -20,6 +21,7 @@ version = "7.0.0" description = "A library for parsing ISO 8601 strings." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "aniso8601-7.0.0-py2.py3-none-any.whl", hash = "sha256:d10a4bf949f619f719b227ef5386e31f49a2b6d453004b21f02661ccc8670c7b"}, {file = "aniso8601-7.0.0.tar.gz", hash = "sha256:513d2b6637b7853806ae79ffaca6f3e8754bdd547048f5ccc1420aec4b714f1e"}, @@ -31,6 +33,7 @@ version = "0.7.0" description = "Reusable constraint types to use with typing.Annotated" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, @@ -42,6 +45,7 @@ version = "4.4.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "anyio-4.4.0-py3-none-any.whl", hash = "sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7"}, {file = "anyio-4.4.0.tar.gz", hash = "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94"}, @@ -53,7 +57,7 @@ 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)"] +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) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\""] trio = ["trio (>=0.23)"] [[package]] @@ -62,6 +66,7 @@ version = "3.0.0" description = "Reconstruct Arabic sentences to be used in applications that do not support Arabic" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "arabic_reshaper-3.0.0-py3-none-any.whl", hash = "sha256:3f71d5034bb694204a239a6f1ebcf323ac3c5b059de02259235e2016a1a5e2dc"}, {file = "arabic_reshaper-3.0.0.tar.gz", hash = "sha256:ffcd13ba5ec007db71c072f5b23f420da92ac7f268512065d49e790e62237099"}, @@ -76,6 +81,7 @@ version = "3.8.1" description = "ASGI specs, helper code, and adapters" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47"}, {file = "asgiref-3.8.1.tar.gz", hash = "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590"}, @@ -90,6 +96,7 @@ version = "1.5.1" description = "Fast ASN.1 parser and serializer with definitions for private keys, public keys, certificates, CRL, OCSP, CMS, PKCS#3, PKCS#7, PKCS#8, PKCS#12, PKCS#5, X.509 and TSP" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "asn1crypto-1.5.1-py2.py3-none-any.whl", hash = "sha256:db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67"}, {file = "asn1crypto-1.5.1.tar.gz", hash = "sha256:13ae38502be632115abf8a24cbe5f4da52e3b5231990aff31123c805306ccb9c"}, @@ -101,6 +108,7 @@ version = "2.4.1" description = "Annotate AST trees with source code positions" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, @@ -110,8 +118,8 @@ files = [ six = ">=1.12.0" [package.extras] -astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] -test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] +astroid = ["astroid (>=1,<2) ; python_version < \"3\"", "astroid (>=2,<4) ; python_version >= \"3\""] +test = ["astroid (>=1,<2) ; python_version < \"3\"", "astroid (>=2,<4) ; python_version >= \"3\"", "pytest"] [[package]] name = "async-timeout" @@ -119,6 +127,8 @@ version = "4.0.3" description = "Timeout context manager for asyncio programs" optional = false python-versions = ">=3.7" +groups = ["main"] +markers = "python_full_version < \"3.11.3\"" files = [ {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, @@ -130,18 +140,19 @@ version = "24.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, ] [package.extras] -benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.9\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.9\" and python_version < \"3.13\"", "pytest-xdist[psutil]"] +cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.9\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.9\" and python_version < \"3.13\"", "pytest-xdist[psutil]"] +dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.9\"", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.9\" and python_version < \"3.13\"", "pytest-xdist[psutil]"] docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] -tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] +tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.9\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.9\" and python_version < \"3.13\"", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.9\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.9\" and python_version < \"3.13\""] [[package]] name = "azure-common" @@ -149,54 +160,19 @@ version = "1.1.19" description = "Microsoft Azure Client Library for Python (Common)" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "azure-common-1.1.19.zip", hash = "sha256:622d9360a1b61172b4c0d1cc58f939c68402aa19ca44872ab3d224d913aa6d0c"}, {file = "azure_common-1.1.19-py2.py3-none-any.whl", hash = "sha256:14722caf6c3ed81d2cfdd3e448635fdc78f214dc6f17558dd1ca5b87bccc0631"}, ] -[[package]] -name = "azure-core" -version = "1.32.0" -description = "Microsoft Azure Core Library for Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "azure_core-1.32.0-py3-none-any.whl", hash = "sha256:eac191a0efb23bfa83fddf321b27b122b4ec847befa3091fa736a5c32c50d7b4"}, - {file = "azure_core-1.32.0.tar.gz", hash = "sha256:22b3c35d6b2dae14990f6c1be2912bf23ffe50b220e708a28ab1bb92b1c730e5"}, -] - -[package.dependencies] -requests = ">=2.21.0" -six = ">=1.11.0" -typing-extensions = ">=4.6.0" - -[package.extras] -aio = ["aiohttp (>=3.0)"] - -[[package]] -name = "azure-identity" -version = "1.20.0" -description = "Microsoft Azure Identity Library for Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "azure_identity-1.20.0-py3-none-any.whl", hash = "sha256:5f23fc4889a66330e840bd78830287e14f3761820fe3c5f77ac875edcb9ec998"}, - {file = "azure_identity-1.20.0.tar.gz", hash = "sha256:40597210d56c83e15031b0fe2ea3b26420189e1e7f3e20bdbb292315da1ba014"}, -] - -[package.dependencies] -azure-core = ">=1.31.0" -cryptography = ">=2.5" -msal = ">=1.30.0" -msal-extensions = ">=1.2.0" -typing-extensions = ">=4.0.0" - [[package]] name = "azure-nspkg" version = "3.0.2" description = "Microsoft Azure Namespace Package [Internal]" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "azure-nspkg-3.0.2.zip", hash = "sha256:e7d3cea6af63e667d87ba1ca4f8cd7cb4dfca678e4c55fc1cedb320760e39dd0"}, {file = "azure_nspkg-3.0.2-py2-none-any.whl", hash = "sha256:1d0bbb2157cf57b1bef6c8c8e5b41133957364456c43b0a43599890023cca0a8"}, @@ -209,6 +185,7 @@ version = "0.36.0" description = "Microsoft Azure Storage Client Library for Python" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "azure-storage-0.36.0.tar.gz", hash = "sha256:fb6212dcbed91b49d9637aa5e8888eafdfcd523b7e560c8044d2d838bbd3ca5f"}, {file = "azure_storage-0.36.0-py2.py3-none-any.whl", hash = "sha256:4c406422e3edd41920bb1f0c3930c34fee3eb0d55258ef7ec7308ccbb9385ad5"}, @@ -227,6 +204,7 @@ version = "1.5.0" description = "Microsoft Azure Storage Blob Client Library for Python" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "azure-storage-blob-1.5.0.tar.gz", hash = "sha256:f187a878e7a191f4e098159904f72b4146cf70e1aabaf6484ab4ba72fc6f252c"}, {file = "azure_storage_blob-1.5.0-py2.py3-none-any.whl", hash = "sha256:6577e9ebca6fd1cf47795f88a1f0949c003fae62eeb6479a05631b765cf73b80"}, @@ -242,6 +220,7 @@ version = "1.4.0" description = "Microsoft Azure Storage Common Client Library for Python" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "azure-storage-common-1.4.0.tar.gz", hash = "sha256:7ab607f9b8fd27b817482194b1e7d43484c65dcf2605aae21ad8706c6891934d"}, {file = "azure_storage_common-1.4.0-py2.py3-none-any.whl", hash = "sha256:69bba6aad1e8a717eeee0f95c2feeeed72ef802001e66d6d15bf8446c4f53e6a"}, @@ -259,6 +238,7 @@ version = "0.5.1" description = "Logging handlers to send logs to Microsoft Azure Storage" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "azure-storage-logging-0.5.1.zip", hash = "sha256:ff60ef6703725e18ae7afec42666eaf334549eb701d28d497b15b25fc21204e3"}, ] @@ -272,6 +252,7 @@ version = "3.1.0" description = "Microsoft Azure Storage Namespace Package [Internal]" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "azure-storage-nspkg-3.1.0.tar.gz", hash = "sha256:6f3bbe8652d5f542767d8433e7f96b8df7f518774055ac7c92ed7ca85f653811"}, {file = "azure_storage_nspkg-3.1.0-py2.py3-none-any.whl", hash = "sha256:7da3bd6c73b8c464a57f53ae9af8328490d2267c66430d8a7621997e52a9703e"}, @@ -286,6 +267,7 @@ version = "4.6.3" description = "Screen-scraping library" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "beautifulsoup4-4.6.3-py2-none-any.whl", hash = "sha256:f0abd31228055d698bb392a826528ea08ebb9959e6bea17c606fd9c9009db938"}, {file = "beautifulsoup4-4.6.3-py3-none-any.whl", hash = "sha256:194ec62a25438adcb3fdb06378b26559eda1ea8a747367d34c33cef9c7f48d57"}, @@ -302,6 +284,7 @@ version = "3.6.4.0" description = "Python multiprocessing fork with improvements and bugfixes" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "billiard-3.6.4.0-py3-none-any.whl", hash = "sha256:87103ea78fa6ab4d5c751c4909bcff74617d985de7fa8b672cf8618afd5a875b"}, {file = "billiard-3.6.4.0.tar.gz", hash = "sha256:299de5a8da28a783d51b197d496bef4f1595dd023a93a4f59dde1886ae905547"}, @@ -313,6 +296,7 @@ version = "1.20.38" description = "The AWS SDK for Python" optional = false python-versions = ">= 3.6" +groups = ["main"] files = [ {file = "boto3-1.20.38-py3-none-any.whl", hash = "sha256:22b243302f526df9c599c6b81092cb3c62f785bc06cedceeff9054489df4ffb3"}, {file = "boto3-1.20.38.tar.gz", hash = "sha256:edeae6d38c98691cb9da187c541f3033e0f30d6b2a0b54b5399a44d9b3ba4f61"}, @@ -332,6 +316,7 @@ version = "1.23.54" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">= 3.6" +groups = ["main"] files = [ {file = "botocore-1.23.54-py3-none-any.whl", hash = "sha256:06ae8076c4dcf3d72bec4d37e5f2dce4a92a18a8cdaa3bfaa6e3b7b5e30a8d7e"}, {file = "botocore-1.23.54.tar.gz", hash = "sha256:4bb9ba16cccee5f5a2602049bc3e2db6865346b2550667f3013bdf33b0a01ceb"}, @@ -351,6 +336,7 @@ version = "5.5.0" description = "Extensible memoizing collections and decorators" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "cachetools-5.5.0-py3-none-any.whl", hash = "sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292"}, {file = "cachetools-5.5.0.tar.gz", hash = "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a"}, @@ -362,6 +348,7 @@ version = "5.1.2" description = "Distributed Task Queue." optional = false python-versions = ">=3.6," +groups = ["main"] files = [ {file = "celery-5.1.2-py3-none-any.whl", hash = "sha256:9dab2170b4038f7bf10ef2861dbf486ddf1d20592290a1040f7b7a1259705d42"}, {file = "celery-5.1.2.tar.gz", hash = "sha256:8d9a3de9162965e97f8e8cc584c67aad83b3f7a267584fa47701ed11c3e0d4b0"}, @@ -383,11 +370,11 @@ vine = ">=5.0.0,<6.0" arangodb = ["pyArango (>=1.3.2)"] auth = ["cryptography"] azureblockblob = ["azure-storage-blob (==12.6.0)"] -brotli = ["brotli (>=1.0.0)", "brotlipy (>=0.7.0)"] +brotli = ["brotli (>=1.0.0) ; platform_python_implementation == \"CPython\"", "brotlipy (>=0.7.0) ; platform_python_implementation == \"PyPy\""] cassandra = ["cassandra-driver (<3.21.0)"] consul = ["python-consul2"] cosmosdbsql = ["pydocumentdb (==2.3.2)"] -couchbase = ["couchbase (>=3.0.0)"] +couchbase = ["couchbase (>=3.0.0) ; platform_python_implementation != \"PyPy\""] couchdb = ["pycouchdb"] django = ["Django (>=1.11)"] dynamodb = ["boto3 (>=1.9.178)"] @@ -395,7 +382,7 @@ elasticsearch = ["elasticsearch"] eventlet = ["eventlet (>=0.26.1)"] gevent = ["gevent (>=1.0.0)"] librabbitmq = ["librabbitmq (>=1.5.0)"] -memcache = ["pylibmc"] +memcache = ["pylibmc ; platform_system != \"Windows\""] mongodb = ["pymongo[srv] (>=3.3.0)"] msgpack = ["msgpack"] pymemcache = ["python-memcached"] @@ -404,10 +391,10 @@ pytest = ["pytest-celery"] redis = ["redis (>=3.2.0)"] s3 = ["boto3 (>=1.9.125)"] slmq = ["softlayer-messaging (>=1.0.3)"] -solar = ["ephem"] +solar = ["ephem ; platform_python_implementation != \"PyPy\""] sqlalchemy = ["sqlalchemy"] sqs = ["boto3 (>=1.9.125)", "pycurl (==7.43.0.5)"] -tblib = ["tblib (>=1.3.0)", "tblib (>=1.5.0)"] +tblib = ["tblib (>=1.3.0) ; python_version < \"3.8.0\"", "tblib (>=1.5.0) ; python_version >= \"3.8.0\""] yaml = ["PyYAML (>=3.10)"] zookeeper = ["kazoo (>=1.3.1)"] zstd = ["zstandard"] @@ -418,6 +405,7 @@ version = "2024.8.30" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, @@ -429,6 +417,8 @@ version = "1.17.1" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "platform_python_implementation != \"PyPy\"" files = [ {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, @@ -508,6 +498,7 @@ version = "5.2.0" description = "Universal encoding detector for Python 3" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"}, {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"}, @@ -519,6 +510,7 @@ version = "3.4.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" +groups = ["main"] files = [ {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, @@ -633,6 +625,7 @@ version = "0.7.0" description = "Python's Enum with extra powers to play nice with labels and choices fields" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "choicesenum-0.7.0-py2.py3-none-any.whl", hash = "sha256:8b8c1f8a374f537441303992009907234c36a587d3a93d248c878c2f104a2b7d"}, {file = "choicesenum-0.7.0.tar.gz", hash = "sha256:37d53174a66405ff178ac44396be9f3a71fe8f5b43d3a5a6ebfaa9593543d36a"}, @@ -647,6 +640,7 @@ version = "7.1.2" description = "Composable command line interface toolkit" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["main"] files = [ {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, @@ -658,6 +652,7 @@ version = "0.3.1" description = "Enables git-like *did-you-mean* feature in click" optional = false python-versions = ">=3.6.2" +groups = ["main"] files = [ {file = "click_didyoumean-0.3.1-py3-none-any.whl", hash = "sha256:5c4bb6007cfea5f2fd6583a2fb6701a22a41eb98957e63d0fac41c10e7c3117c"}, {file = "click_didyoumean-0.3.1.tar.gz", hash = "sha256:4f82fdff0dbe64ef8ab2279bd6aa3f6a99c3b28c05aa09cbfc07c9d7fbb5a463"}, @@ -672,6 +667,7 @@ version = "1.1.1" description = "An extension module for click to enable registering CLI commands via setuptools entry-points." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "click-plugins-1.1.1.tar.gz", hash = "sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b"}, {file = "click_plugins-1.1.1-py2.py3-none-any.whl", hash = "sha256:5d262006d3222f5057fd81e1623d4443e41dcda5dc815c06b442aa3c02889fc8"}, @@ -689,6 +685,7 @@ version = "0.3.0" description = "REPL plugin for Click" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "click-repl-0.3.0.tar.gz", hash = "sha256:17849c23dba3d667247dc4defe1757fff98694e90fe37474f3feebb69ced26a9"}, {file = "click_repl-0.3.0-py3-none-any.whl", hash = "sha256:fb7e06deb8da8de86180a33a9da97ac316751c094c6899382da7feeeeb51b812"}, @@ -707,6 +704,7 @@ version = "0.7.2" description = "Click params for commmand line interfaces to GeoJSON" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, <4" +groups = ["main"] files = [ {file = "cligj-0.7.2-py3-none-any.whl", hash = "sha256:c1ca117dbce1fe20a5809dc96f01e1c2840f6dcc939b3ddbb1111bf330ba82df"}, {file = "cligj-0.7.2.tar.gz", hash = "sha256:a4bc13d623356b373c2c27c53dbd9c68cae5d526270bfa71f6c6fa69669c6b27"}, @@ -724,10 +722,12 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main", "dev"] files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +markers = {main = "sys_platform == \"win32\" or platform_system == \"Windows\"", dev = "sys_platform == \"win32\""} [[package]] name = "colorlog" @@ -735,6 +735,7 @@ version = "6.8.2" description = "Add colours to the output of Python's logging module." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "colorlog-6.8.2-py3-none-any.whl", hash = "sha256:4dcbb62368e2800cb3c5abd348da7e53f6c362dda502ec27c560b2e58a66bd33"}, {file = "colorlog-6.8.2.tar.gz", hash = "sha256:3e3e079a41feb5a1b64f978b5ea4f46040a94f11f0e8bbb8261e3dbbeca64d44"}, @@ -752,6 +753,7 @@ version = "2.3.3" description = "Python client library for Core API." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "coreapi-2.3.3-py2.py3-none-any.whl", hash = "sha256:bf39d118d6d3e171f10df9ede5666f63ad80bba9a29a8ec17726a66cf52ee6f3"}, {file = "coreapi-2.3.3.tar.gz", hash = "sha256:46145fcc1f7017c076a2ef684969b641d18a2991051fddec9458ad3f78ffc1cb"}, @@ -769,6 +771,7 @@ version = "0.0.4" description = "Core Schema." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "coreschema-0.0.4-py2-none-any.whl", hash = "sha256:5e6ef7bf38c1525d5e55a895934ab4273548629f16aed5c0a6caa74ebf45551f"}, {file = "coreschema-0.0.4.tar.gz", hash = "sha256:9503506007d482ab0867ba14724b93c18a33b22b6d19fb419ef2d239dd4a1607"}, @@ -783,6 +786,7 @@ version = "4.4.2" description = "Code coverage measurement for Python" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "coverage-4.4.2-cp26-cp26m-macosx_10_10_x86_64.whl", hash = "sha256:d1ee76f560c3c3e8faada866a07a32485445e16ed2206ac8378bd90dadffb9f0"}, {file = "coverage-4.4.2-cp26-cp26m-manylinux1_i686.whl", hash = "sha256:007eeef7e23f9473622f7d94a3e029a45d55a92a1f083f0f3512f5ab9a669b05"}, @@ -824,6 +828,7 @@ version = "44.0.1" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = "!=3.9.0,!=3.9.1,>=3.7" +groups = ["main"] files = [ {file = "cryptography-44.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf688f615c29bfe9dfc44312ca470989279f0e94bb9f631f85e3459af8efc009"}, {file = "cryptography-44.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd7c7e2d71d908dc0f8d2027e1604102140d84b155e658c20e8ad1304317691f"}, @@ -862,10 +867,10 @@ files = [ cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} [package.extras] -docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=3.0.0)"] +docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=3.0.0) ; python_version >= \"3.8\""] docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"] -nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2)"] -pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] +nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2) ; python_version >= \"3.8\""] +pep8test = ["check-sdist ; python_version >= \"3.8\"", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] sdist = ["build (>=1.0.0)"] ssh = ["bcrypt (>=3.1.5)"] test = ["certifi (>=2024)", "cryptography-vectors (==44.0.1)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] @@ -877,6 +882,7 @@ version = "0.7.0" description = "CSS selectors for Python ElementTree" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "cssselect2-0.7.0-py3-none-any.whl", hash = "sha256:fd23a65bfd444595913f02fc71f6b286c29261e354c41d722ca7a261a49b5969"}, {file = "cssselect2-0.7.0.tar.gz", hash = "sha256:1ccd984dab89fc68955043aca4e1b03e0cf29cad9880f6e28e3ba7a74b14aa5a"}, @@ -896,6 +902,7 @@ version = "5.1.1" description = "Decorators for Humans" optional = false python-versions = ">=3.5" +groups = ["main"] files = [ {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, @@ -907,6 +914,7 @@ version = "20230430" description = "Diff Match and Patch" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "diff-match-patch-20230430.tar.gz", hash = "sha256:953019cdb9c9d2c9e47b5b12bcff3cf4746fc4598eb406076fa1fc27e6a1f15c"}, {file = "diff_match_patch-20230430-py3-none-any.whl", hash = "sha256:dce43505fb7b1b317de7195579388df0746d90db07015ed47a85e5e44930ef93"}, @@ -921,6 +929,7 @@ version = "1.9.0" description = "Distro - an OS platform information API" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2"}, {file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"}, @@ -932,6 +941,7 @@ version = "4.2.17" description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "Django-4.2.17-py3-none-any.whl", hash = "sha256:3a93350214ba25f178d4045c0786c61573e7dbfa3c509b3551374f1e11ba8de0"}, {file = "Django-4.2.17.tar.gz", hash = "sha256:6b56d834cc94c8b21a8f4e775064896be3b4a4ca387f2612d4406a5927cd2fdc"}, @@ -952,6 +962,7 @@ version = "0.7.1" description = "A simple Django app to render list filters in django admin using autocomplete widget" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "django-admin-autocomplete-filter-0.7.1.tar.gz", hash = "sha256:5a8c9a7016e03104627b80b40811dcc567f26759971e4407f933951546367ba0"}, {file = "django_admin_autocomplete_filter-0.7.1-py3-none-any.whl", hash = "sha256:b2a71be2c4a68f828289eb51f71316dbdfac00a1843f53df1fbe4767aad2e3c0"}, @@ -966,6 +977,7 @@ version = "1.0.3" description = "Use dropdowns in Django admin list filter" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "django-admin-list-filter-dropdown-1.0.3.tar.gz", hash = "sha256:07cd37b6a9be1b08f11d4a92957c69b67bc70b1f87a2a7d4ae886c93ea51eb53"}, {file = "django_admin_list_filter_dropdown-1.0.3-py3-none-any.whl", hash = "sha256:bf1b48bab9772dad79db71efef17e78782d4f2421444d5e49bb10e0da71cd6bb"}, @@ -977,6 +989,7 @@ version = "3.11.0" description = "django-cors-headers is a Django application for handling the server headers required for Cross-Origin Resource Sharing (CORS)." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "django-cors-headers-3.11.0.tar.gz", hash = "sha256:eb98389bf7a2afc5d374806af4a9149697e3a6955b5a2dc2bf049f7d33647456"}, {file = "django_cors_headers-3.11.0-py3-none-any.whl", hash = "sha256:a22be2befd4069c4fc174f11cf067351df5c061a3a5f94a01650b4e928b0372b"}, @@ -991,6 +1004,7 @@ version = "1.2.4" description = "Django Test Coverage App" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "django-coverage-1.2.4.tar.gz", hash = "sha256:eee56c1465b2ece0a066ea2514c50039462f8fe1ea58e59adc0dfda14b30628b"}, ] @@ -1001,6 +1015,7 @@ version = "4.1.0" description = "A configurable set of panels that display various debug information about the current request/response." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "django_debug_toolbar-4.1.0-py3-none-any.whl", hash = "sha256:a0b532ef5d52544fd745d1dcfc0557fa75f6f0d1962a8298bd568427ef2fa436"}, {file = "django_debug_toolbar-4.1.0.tar.gz", hash = "sha256:f57882e335593cb8e74c2bda9f1116bbb9ca8fc0d81b50a75ace0f83de5173c7"}, @@ -1016,6 +1031,7 @@ version = "2.0.2" description = "Custom Django field for using enumerations of named constants" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "django-enumfield-2.0.2.tar.gz", hash = "sha256:e5fe9826b5f6c5372c70ab82d9afa126fac932a88af2ae46b530b9ef520b1c8f"}, {file = "django_enumfield-2.0.2-py2.py3-none-any.whl", hash = "sha256:4a237885151bf36b94f084cdb652fda6dcf1b2d3796b8d31764c33d30cfd478f"}, @@ -1033,6 +1049,7 @@ version = "0.8.1" description = "A package that allows you to utilize 12factor inspired environment variables to configure your Django application." optional = false python-versions = ">=3.4,<4" +groups = ["main"] files = [ {file = "django-environ-0.8.1.tar.gz", hash = "sha256:6f0bc902b43891656b20486938cba0861dc62892784a44919170719572a534cb"}, {file = "django_environ-0.8.1-py2.py3-none-any.whl", hash = "sha256:42593bee519a527602a467c7b682aee1a051c2597f98c45f4f4f44169ecdb6e5"}, @@ -1049,6 +1066,7 @@ version = "2.0.6" description = "Extensions for Django" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "django-extensions-2.0.6.tar.gz", hash = "sha256:bc9f2946c117bb2f49e5e0633eba783787790ae810ea112fe7fd82fa64de2ff1"}, {file = "django_extensions-2.0.6-py2.py3-none-any.whl", hash = "sha256:37a543af370ee3b0721ff50442d33c357dd083e6ea06c5b94a199283b6f9e361"}, @@ -1063,6 +1081,7 @@ version = "2.4.0" description = "Django-filter is a reusable Django application for allowing users to filter querysets dynamically." optional = false python-versions = ">=3.5" +groups = ["main"] files = [ {file = "django-filter-2.4.0.tar.gz", hash = "sha256:84e9d5bb93f237e451db814ed422a3a625751cbc9968b484ecc74964a8696b06"}, {file = "django_filter-2.4.0-py3-none-any.whl", hash = "sha256:e00d32cebdb3d54273c48f4f878f898dced8d5dfaad009438fe61ebdf535ace1"}, @@ -1077,6 +1096,7 @@ version = "0.1.4" description = "GeoJSON support for Django GraphQL" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "django-graphql-geojson-0.1.4.tar.gz", hash = "sha256:08acffff153316f8b0ab4ac7a621b9981a2f2bc4eda4539bf0997ba83d42c2ed"}, {file = "django_graphql_geojson-0.1.4-py2.py3-none-any.whl", hash = "sha256:dbd4b940d869cf5a0f7a969d64684e41bd60695b36328c33d52f3f1364de4ef8"}, @@ -1092,6 +1112,7 @@ version = "2.4.0" description = "Implementation of per object permissions for Django." optional = false python-versions = ">=3.5" +groups = ["main"] files = [ {file = "django-guardian-2.4.0.tar.gz", hash = "sha256:c58a68ae76922d33e6bdc0e69af1892097838de56e93e78a8361090bcd9f89a0"}, {file = "django_guardian-2.4.0-py3-none-any.whl", hash = "sha256:440ca61358427e575323648b25f8384739e54c38b3d655c81d75e0cd0d61b697"}, @@ -1106,6 +1127,7 @@ version = "3.3.0" description = "Pluggable search for Django." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "django_haystack-3.3.0.tar.gz", hash = "sha256:e3ceed6b8000625da14d409eb4dac69894905e2ac8ac18f9bfdb59323ca02eab"}, ] @@ -1125,6 +1147,7 @@ version = "0.17.5" description = "Translates Django models using a registration approach." optional = false python-versions = ">=3.6.2" +groups = ["main"] files = [ {file = "django-modeltranslation-0.17.5.tar.gz", hash = "sha256:d9b3278dc3a799261861e090c27a3e1c46b3471e979e07b01cdd4ea2696a9f41"}, ] @@ -1139,6 +1162,7 @@ version = "3.0.1" description = "OAuth2 Provider for Django" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "django_oauth_toolkit-3.0.1-py3-none-any.whl", hash = "sha256:3ef00b062a284f2031b0732b32dc899e3bbf0eac221bbb1cffcb50b8932e55ed"}, {file = "django_oauth_toolkit-3.0.1.tar.gz", hash = "sha256:7200e4a9fb229b145a6d808cbf0423b6d69a87f68557437733eec3c0cf71db02"}, @@ -1156,6 +1180,7 @@ version = "1.12.0" description = "Disable Django database writes." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "django_read_only-1.12.0-py3-none-any.whl", hash = "sha256:4938012353ed36da6e05994176b580889f6da4242f11e3c73357e038c95e2984"}, {file = "django_read_only-1.12.0.tar.gz", hash = "sha256:1d06cfcde14d91732b65c161dbef2603442593e9bdca6043350df3fa9aa51d43"}, @@ -1170,6 +1195,7 @@ version = "5.0.0" description = "Full featured redis cache backend for Django." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "django-redis-5.0.0.tar.gz", hash = "sha256:048f665bbe27f8ff2edebae6aa9c534ab137f1e8fa7234147ef470df3f3aa9b8"}, {file = "django_redis-5.0.0-py3-none-any.whl", hash = "sha256:97739ca9de3f964c51412d1d7d8aecdfd86737bb197fce6e1ff12620c63c97ee"}, @@ -1185,6 +1211,7 @@ version = "5.0.12" description = "An extension to the Django web framework that provides version control for model instances." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "django-reversion-5.0.12.tar.gz", hash = "sha256:c047cc99a9f1ba4aae6db89c3ac243478d6de98ec8a60c7073fcc875d89c5cdb"}, {file = "django_reversion-5.0.12-py3-none-any.whl", hash = "sha256:5884e9f77f55c341b3f0a8d3b0af000f060530653776997267c8b1e5349d8fee"}, @@ -1199,6 +1226,7 @@ version = "0.16.2" description = "Add compare view to django-reversion for comparing two versions of a reversion model." optional = false python-versions = "<4,>=3.9" +groups = ["main"] files = [ {file = "django-reversion-compare-0.16.2.tar.gz", hash = "sha256:9d7d096534f5d0e49d7419a8a29b4517580e6a7855529e594d10bfb373f980ab"}, {file = "django_reversion_compare-0.16.2-py3-none-any.whl", hash = "sha256:5629f226fc73bd7b95de47b2e21e2eba2fa39f004ba0fee6d460e96676c0dc9b"}, @@ -1221,13 +1249,13 @@ version = "1.11.1" description = "Support for many storage backends in Django" optional = false python-versions = ">=3.5" +groups = ["main"] files = [ {file = "django-storages-1.11.1.tar.gz", hash = "sha256:c823dbf56c9e35b0999a13d7e05062b837bae36c518a40255d522fbe3750fbb4"}, {file = "django_storages-1.11.1-py3-none-any.whl", hash = "sha256:f28765826d507a0309cfaa849bd084894bc71d81bf0d09479168d44785396f80"}, ] [package.dependencies] -azure-storage-blob = {version = ">=1.3.1,<12.0.0", optional = true, markers = "extra == \"azure\""} Django = ">=2.2" [package.extras] @@ -1244,6 +1272,7 @@ version = "5.1.0" description = "Mypy stubs for Django" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "django_stubs-5.1.0-py3-none-any.whl", hash = "sha256:b98d49a80aa4adf1433a97407102d068de26c739c405431d93faad96dd282c40"}, {file = "django_stubs-5.1.0.tar.gz", hash = "sha256:86128c228b65e6c9a85e5dc56eb1c6f41125917dae0e21e6cfecdf1b27e630c5"}, @@ -1267,6 +1296,7 @@ version = "5.1.0" description = "Monkey-patching and extensions for django-stubs" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "django_stubs_ext-5.1.0-py3-none-any.whl", hash = "sha256:a455fc222c90b30b29ad8c53319559f5b54a99b4197205ddbb385aede03b395d"}, {file = "django_stubs_ext-5.1.0.tar.gz", hash = "sha256:ed7d51c0b731651879fc75f331fb0806d98b67bfab464e96e2724db6b46ef926"}, @@ -1282,6 +1312,7 @@ version = "4.1.0" description = "A Django application that contains a widget to render a" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "django_tinymce-4.1.0-py3-none-any.whl", hash = "sha256:9804836e6d2b08de3b03a27c100f8c2e9633549913eff8b323678a10cd48b94e"}, {file = "django_tinymce-4.1.0.tar.gz", hash = "sha256:02e3b70e940fd299f0fbef4315aee5c185664e1eb8cd396b176963954e4357c9"}, @@ -1296,6 +1327,7 @@ version = "3.14.0" description = "Web APIs for Django, made easy." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "djangorestframework-3.14.0-py3-none-any.whl", hash = "sha256:eb63f58c9f218e1a7d064d17a70751f528ed4e1d35547fdade9aaf4cd103fd08"}, {file = "djangorestframework-3.14.0.tar.gz", hash = "sha256:579a333e6256b09489cbe0a067e66abe55c6595d8926be6b99423786334350c8"}, @@ -1311,6 +1343,7 @@ version = "1.2.0" description = "Camel case JSON support for Django REST framework." optional = false python-versions = ">=3.5" +groups = ["main"] files = [ {file = "djangorestframework-camel-case-1.2.0.tar.gz", hash = "sha256:9714d43fba5bb654057c29501649684d3d9f11a92319ae417fd4d65e80d1159d"}, ] @@ -1321,6 +1354,7 @@ version = "2.1.1" description = "CSV Tools for Django REST Framework" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "djangorestframework-csv-2.1.1.tar.gz", hash = "sha256:aa0ee4c894fe319c68e042b05c61dace43a9fb6e6872e1abe1724ca7ea4d15f7"}, ] @@ -1336,6 +1370,7 @@ version = "0.1.1" description = "django-guardian support for Django REST Framework" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "djangorestframework_guardian-0.1.1-py2.py3-none-any.whl", hash = "sha256:32d723a5c62f75b72c618312358b1c186ec1c1fa95ffc2169e125df62ef20015"}, ] @@ -1351,6 +1386,7 @@ version = "0.27.2" description = "Sane and flexible OpenAPI 3 schema generation for Django REST framework" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "drf-spectacular-0.27.2.tar.gz", hash = "sha256:a199492f2163c4101055075ebdbb037d59c6e0030692fc83a1a8c0fc65929981"}, {file = "drf_spectacular-0.27.2-py3-none-any.whl", hash = "sha256:b1c04bf8b2fbbeaf6f59414b4ea448c8787aba4d32f76055c3b13335cf7ec37b"}, @@ -1374,6 +1410,7 @@ version = "7.0.0" description = "Python client for Elasticsearch" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "elasticsearch-7.0.0-py2.py3-none-any.whl", hash = "sha256:c621f2272bb2f000d228dc7016d058a1f90f15babdc938240b9f2d13690222db"}, {file = "elasticsearch-7.0.0.tar.gz", hash = "sha256:cf6cf834b6d0172dac5e704c398a11d1917cf61f15d32b79b1ddad4cd673c4b1"}, @@ -1392,6 +1429,7 @@ version = "1.1.0" description = "An implementation of lxml.xmlfile for the standard library" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "et_xmlfile-1.1.0-py3-none-any.whl", hash = "sha256:a2ba85d1d6a74ef63837eed693bcb89c3f752169b0e3e7ae5b16ca5e1b3deada"}, {file = "et_xmlfile-1.1.0.tar.gz", hash = "sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c"}, @@ -1403,13 +1441,14 @@ version = "2.1.0" description = "Get the currently executing AST node of a frame, and other information" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "executing-2.1.0-py2.py3-none-any.whl", hash = "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf"}, {file = "executing-2.1.0.tar.gz", hash = "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab"}, ] [package.extras] -tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] +tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich ; python_version >= \"3.11\""] [[package]] name = "factory-boy" @@ -1417,6 +1456,7 @@ version = "2.12.0" description = "A versatile test fixtures replacement based on thoughtbot's factory_bot for Ruby." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main"] files = [ {file = "factory_boy-2.12.0-py2.py3-none-any.whl", hash = "sha256:728df59b372c9588b83153facf26d3d28947fc750e8e3c95cefa9bed0e6394ee"}, {file = "factory_boy-2.12.0.tar.gz", hash = "sha256:faf48d608a1735f0d0a3c9cbf536d64f9132b547dae7ba452c4d99a79e84a370"}, @@ -1431,6 +1471,7 @@ version = "30.3.0" description = "Faker is a Python package that generates fake data for you." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "Faker-30.3.0-py3-none-any.whl", hash = "sha256:e8a15fd1b0f72992b008f5ea94c70d3baa0cb51b0d5a0e899c17b1d1b23d2771"}, {file = "faker-30.3.0.tar.gz", hash = "sha256:8760fbb34564fbb2f394345eef24aec5b8f6506b6cfcefe8195ed66dd1032bdb"}, @@ -1446,6 +1487,7 @@ version = "0.3.0" description = "A fast native implementation of diff algorithm with a pure python fallback" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "fastdiff-0.3.0-py2.py3-none-any.whl", hash = "sha256:ca5f61f6ddf5a1564ddfd98132ad28e7abe4a88a638a8b014a2214f71e5918ec"}, {file = "fastdiff-0.3.0.tar.gz", hash = "sha256:4dfa09c47832a8c040acda3f1f55fc0ab4d666f0e14e6951e6da78d59acd945a"}, @@ -1461,6 +1503,7 @@ version = "0.17.0" description = "Fuzzy string matching in python" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "fuzzywuzzy-0.17.0-py2.py3-none-any.whl", hash = "sha256:5ac7c0b3f4658d2743aa17da53a55598144edbc5bee3c6863840636e6926f254"}, {file = "fuzzywuzzy-0.17.0.tar.gz", hash = "sha256:6f49de47db00e1c71d40ad16da42284ac357936fa9b66bea1df63fed07122d62"}, @@ -1475,6 +1518,7 @@ version = "2.21.0" description = "Google API client core library" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "google_api_core-2.21.0-py3-none-any.whl", hash = "sha256:6869eacb2a37720380ba5898312af79a4d30b8bca1548fb4093e0697dc4bdf5d"}, {file = "google_api_core-2.21.0.tar.gz", hash = "sha256:4a152fd11a9f774ea606388d423b68aa7e6d6a0ffe4c8266f74979613ec09f81"}, @@ -1489,7 +1533,7 @@ requests = ">=2.18.0,<3.0.0.dev0" [package.extras] async-rest = ["google-auth[aiohttp] (>=2.35.0,<3.0.dev0)"] -grpc = ["grpcio (>=1.33.2,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "grpcio-status (>=1.33.2,<2.0.dev0)", "grpcio-status (>=1.49.1,<2.0.dev0)"] +grpc = ["grpcio (>=1.33.2,<2.0dev)", "grpcio (>=1.49.1,<2.0dev) ; python_version >= \"3.11\"", "grpcio-status (>=1.33.2,<2.0.dev0)", "grpcio-status (>=1.49.1,<2.0.dev0) ; python_version >= \"3.11\""] grpcgcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] @@ -1499,6 +1543,7 @@ version = "2.35.0" description = "Google Authentication Library" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "google_auth-2.35.0-py2.py3-none-any.whl", hash = "sha256:25df55f327ef021de8be50bad0dfd4a916ad0de96da86cd05661c9297723ad3f"}, {file = "google_auth-2.35.0.tar.gz", hash = "sha256:f4c64ed4e01e8e8b646ef34c018f8bf3338df0c8e37d8b3bba40e7f574a3278a"}, @@ -1522,6 +1567,7 @@ version = "1.65.0" description = "Common protobufs used in Google APIs" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "googleapis_common_protos-1.65.0-py2.py3-none-any.whl", hash = "sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63"}, {file = "googleapis_common_protos-1.65.0.tar.gz", hash = "sha256:334a29d07cddc3aa01dee4988f9afd9b2916ee2ff49d6b757155dc0d197852c0"}, @@ -1539,6 +1585,7 @@ version = "2024.6.6" description = "Generate a dot graph from the output of several profilers." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "gprof2dot-2024.6.6-py2.py3-none-any.whl", hash = "sha256:45b14ad7ce64e299c8f526881007b9eb2c6b75505d5613e96e66ee4d5ab33696"}, {file = "gprof2dot-2024.6.6.tar.gz", hash = "sha256:fa1420c60025a9eb7734f65225b4da02a10fc6dd741b37fa129bc6b41951e5ab"}, @@ -1550,6 +1597,7 @@ version = "2.1.9" description = "GraphQL Framework for Python" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "graphene-2.1.9-py2.py3-none-any.whl", hash = "sha256:3d446eb1237c551052bc31155cf1a3a607053e4f58c9172b83a1b597beaa0868"}, {file = "graphene-2.1.9.tar.gz", hash = "sha256:b9f2850e064eebfee9a3ef4a1f8aa0742848d97652173ab44c82cc8a62b9ed93"}, @@ -1572,6 +1620,7 @@ version = "2.16.0" description = "Graphene Django integration" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "graphene-django-2.16.0.tar.gz", hash = "sha256:dcf650ebfae52c2e9927d6e8bb005d06366f710b17a015c821c920eda1270566"}, {file = "graphene_django-2.16.0-py2.py3-none-any.whl", hash = "sha256:ec89469ec94507c1ed998f85ee087d634ec489e20fe08a72893c3ca5e646fc14"}, @@ -1596,6 +1645,7 @@ version = "2.3.2" description = "GraphQL implementation for Python" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "graphql-core-2.3.2.tar.gz", hash = "sha256:aac46a9ac524c9855910c14c48fc5d60474def7f99fd10245e76608eba7af746"}, {file = "graphql_core-2.3.2-py2.py3-none-any.whl", hash = "sha256:44c9bac4514e5e30c5a595fac8e3c76c1975cae14db215e8174c7fe995825bad"}, @@ -1616,6 +1666,7 @@ version = "2.0.1" description = "Relay implementation for Python" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "graphql-relay-2.0.1.tar.gz", hash = "sha256:870b6b5304123a38a0b215a79eace021acce5a466bf40cd39fa18cb8528afabb"}, {file = "graphql_relay-2.0.1-py3-none-any.whl", hash = "sha256:ac514cb86db9a43014d7e73511d521137ac12cf0101b2eaa5f0a3da2e10d913d"}, @@ -1632,6 +1683,7 @@ version = "22.0.0" description = "WSGI HTTP Server for UNIX" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "gunicorn-22.0.0-py3-none-any.whl", hash = "sha256:350679f91b24062c86e386e198a15438d53a7a8207235a78ba1b53df4c4378d9"}, {file = "gunicorn-22.0.0.tar.gz", hash = "sha256:4a0b436239ff76fb33f11c07a16482c521a7e09c1ce3cc293c2330afe01bec63"}, @@ -1653,6 +1705,7 @@ version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, @@ -1664,6 +1717,7 @@ version = "1.1" description = "HTML parser based on the WHATWG HTML specification" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["main"] files = [ {file = "html5lib-1.1-py2.py3-none-any.whl", hash = "sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d"}, {file = "html5lib-1.1.tar.gz", hash = "sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f"}, @@ -1674,10 +1728,10 @@ six = ">=1.9" webencodings = "*" [package.extras] -all = ["chardet (>=2.2)", "genshi", "lxml"] +all = ["chardet (>=2.2)", "genshi", "lxml ; platform_python_implementation == \"CPython\""] chardet = ["chardet (>=2.2)"] genshi = ["genshi"] -lxml = ["lxml"] +lxml = ["lxml ; platform_python_implementation == \"CPython\""] [[package]] name = "httpcore" @@ -1685,6 +1739,7 @@ version = "1.0.5" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "httpcore-1.0.5-py3-none-any.whl", hash = "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"}, {file = "httpcore-1.0.5.tar.gz", hash = "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61"}, @@ -1706,6 +1761,7 @@ version = "0.27.0" description = "The next generation HTTP client." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5"}, {file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"}, @@ -1719,7 +1775,7 @@ idna = "*" sniffio = "*" [package.extras] -brotli = ["brotli", "brotlicffi"] +brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""] cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] @@ -1730,6 +1786,7 @@ version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, @@ -1744,6 +1801,7 @@ version = "0.5.1" description = "A port of Ruby on Rails inflector to Python" optional = false python-versions = ">=3.5" +groups = ["main"] files = [ {file = "inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"}, {file = "inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417"}, @@ -1755,6 +1813,7 @@ version = "2.0.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, @@ -1766,6 +1825,7 @@ version = "8.28.0" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.10" +groups = ["main"] files = [ {file = "ipython-8.28.0-py3-none-any.whl", hash = "sha256:530ef1e7bb693724d3cdc37287c80b07ad9b25986c007a53aa1857272dac3f35"}, {file = "ipython-8.28.0.tar.gz", hash = "sha256:0d0d15ca1e01faeb868ef56bc7ee5a0de5bd66885735682e8a322ae289a13d1a"}, @@ -1786,7 +1846,7 @@ typing-extensions = {version = ">=4.6", markers = "python_version < \"3.12\""} [package.extras] all = ["ipython[black,doc,kernel,matplotlib,nbconvert,nbformat,notebook,parallel,qtconsole]", "ipython[test,test-extra]"] black = ["black"] -doc = ["docrepr", "exceptiongroup", "intersphinx-registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "tomli", "typing-extensions"] +doc = ["docrepr", "exceptiongroup", "intersphinx-registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "tomli ; python_version < \"3.11\"", "typing-extensions"] kernel = ["ipykernel"] matplotlib = ["matplotlib"] nbconvert = ["nbconvert"] @@ -1803,6 +1863,7 @@ version = "1.2.0" description = "Simple immutable types for python." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "itypes-1.2.0-py2.py3-none-any.whl", hash = "sha256:03da6872ca89d29aef62773672b2d408f490f80db48b23079a4b194c86dd04c6"}, {file = "itypes-1.2.0.tar.gz", hash = "sha256:af886f129dea4a2a1e3d36595a2d139589e4dd287f5cab0b40e799ee81570ff1"}, @@ -1814,6 +1875,7 @@ version = "0.19.1" description = "An autocompletion tool for Python that can be used for text editors." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, @@ -1833,6 +1895,7 @@ version = "3.1.4" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, @@ -1850,6 +1913,7 @@ version = "0.10.0" description = "JSON Matching Expressions" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +groups = ["main"] files = [ {file = "jmespath-0.10.0-py2.py3-none-any.whl", hash = "sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"}, {file = "jmespath-0.10.0.tar.gz", hash = "sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9"}, @@ -1861,6 +1925,7 @@ version = "3.2.0" description = "An implementation of JSON Schema validation for Python" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "jsonschema-3.2.0-py2.py3-none-any.whl", hash = "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163"}, {file = "jsonschema-3.2.0.tar.gz", hash = "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"}, @@ -1882,6 +1947,7 @@ version = "1.0.0" description = "Python support for RFC 7464 JSON text sequences" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "jsonseq-1.0.0-py3-none-any.whl", hash = "sha256:d4add916420fc02796a503e59ce4d8008152830fd1625cc70692b1f980a32231"}, {file = "jsonseq-1.0.0.tar.gz", hash = "sha256:238f51aa741132d2a41d1fb89e58eb8d43c6da9d34845c9499dd882a4cd0253a"}, @@ -1897,6 +1963,7 @@ version = "1.5.6" description = "Implementation of JOSE Web standards" optional = false python-versions = ">= 3.8" +groups = ["main"] files = [ {file = "jwcrypto-1.5.6-py3-none-any.whl", hash = "sha256:150d2b0ebbdb8f40b77f543fb44ffd2baeff48788be71f67f03566692fd55789"}, {file = "jwcrypto-1.5.6.tar.gz", hash = "sha256:771a87762a0c081ae6166958a954f80848820b2ab066937dc8b8379d65b1b039"}, @@ -1912,6 +1979,7 @@ version = "5.4.2" description = "Messaging library for Python." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "kombu-5.4.2-py3-none-any.whl", hash = "sha256:14212f5ccf022fc0a70453bb025a1dcc32782a588c49ea866884047d66e14763"}, {file = "kombu-5.4.2.tar.gz", hash = "sha256:eef572dd2fd9fc614b37580e3caeafdd5af46c1eff31e7fba89138cdb406f2cf"}, @@ -1927,7 +1995,7 @@ azureservicebus = ["azure-servicebus (>=7.10.0)"] azurestoragequeues = ["azure-identity (>=1.12.0)", "azure-storage-queue (>=12.6.0)"] confluentkafka = ["confluent-kafka (>=2.2.0)"] consul = ["python-consul2 (==0.1.5)"] -librabbitmq = ["librabbitmq (>=2.0.0)"] +librabbitmq = ["librabbitmq (>=2.0.0) ; python_version < \"3.11\""] mongodb = ["pymongo (>=4.1.1)"] msgpack = ["msgpack (==1.1.0)"] pyro = ["pyro4 (==4.82)"] @@ -1935,7 +2003,7 @@ qpid = ["qpid-python (>=0.26)", "qpid-tools (>=0.26)"] redis = ["redis (>=4.5.2,!=4.5.5,!=5.0.2)"] slmq = ["softlayer-messaging (>=1.0.3)"] sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"] -sqs = ["boto3 (>=1.26.143)", "pycurl (>=7.43.0.5)", "urllib3 (>=1.26.16)"] +sqs = ["boto3 (>=1.26.143)", "pycurl (>=7.43.0.5) ; sys_platform != \"win32\" and platform_python_implementation == \"CPython\"", "urllib3 (>=1.26.16)"] yaml = ["PyYAML (>=3.10)"] zookeeper = ["kazoo (>=2.8.0)"] @@ -1945,6 +2013,7 @@ version = "5.3.0" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656"}, {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d"}, @@ -2099,6 +2168,7 @@ version = "1.7.3" description = "CLI for interacting with and preparing data for the Tilesets API" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "mapbox-tilesets-1.7.3.tar.gz", hash = "sha256:ac71370293ab1895cd8bfa333d808f45f13313a99c5378fa82c8427d45e5f57c"}, {file = "mapbox_tilesets-1.7.3-py3-none-any.whl", hash = "sha256:c2881fa302c7b2877b024efcb8a0f98577fe718d3e3c4e85c64c68644877a6d6"}, @@ -2125,6 +2195,7 @@ version = "3.3.4" description = "Python implementation of Markdown." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "Markdown-3.3.4-py3-none-any.whl", hash = "sha256:96c3ba1261de2f7547b46a00ea8463832c921d3f9d6aba3f255a6f71386db20c"}, {file = "Markdown-3.3.4.tar.gz", hash = "sha256:31b5b491868dcc87d6c24b7e3d19a0d730d59d3e46f4eea6430a321bed387a49"}, @@ -2139,6 +2210,7 @@ version = "3.0.1" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "MarkupSafe-3.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:db842712984e91707437461930e6011e60b39136c7331e971952bb30465bc1a1"}, {file = "MarkupSafe-3.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3ffb4a8e7d46ed96ae48805746755fadd0909fea2306f93d5d8233ba23dda12a"}, @@ -2209,6 +2281,7 @@ version = "0.1.7" description = "Inline Matplotlib backend for Jupyter" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"}, {file = "matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90"}, @@ -2223,6 +2296,7 @@ version = "1.1.6" description = "Web mercator XYZ tile utilities" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "mercantile-1.1.6-py3-none-any.whl", hash = "sha256:20895bcee8cb346f384d8a1161fde4773f5b2aa937d90a23aebde766a0d1a536"}, {file = "mercantile-1.1.6.tar.gz", hash = "sha256:0dff4cbc2c92ceca0e0dfbb3dc74392a96d33cfa29afb1bdfcc80283d3ef4207"}, @@ -2235,46 +2309,13 @@ click = ">=3.0" dev = ["check-manifest"] test = ["coveralls", "hypothesis", "pydocstyle", "pytest-cov"] -[[package]] -name = "msal" -version = "1.31.1" -description = "The Microsoft Authentication Library (MSAL) for Python library enables your app to access the Microsoft Cloud by supporting authentication of users with Microsoft Azure Active Directory accounts (AAD) and Microsoft Accounts (MSA) using industry standard OAuth2 and OpenID Connect." -optional = false -python-versions = ">=3.7" -files = [ - {file = "msal-1.31.1-py3-none-any.whl", hash = "sha256:29d9882de247e96db01386496d59f29035e5e841bcac892e6d7bf4390bf6bd17"}, - {file = "msal-1.31.1.tar.gz", hash = "sha256:11b5e6a3f802ffd3a72107203e20c4eac6ef53401961b880af2835b723d80578"}, -] - -[package.dependencies] -cryptography = ">=2.5,<46" -PyJWT = {version = ">=1.0.0,<3", extras = ["crypto"]} -requests = ">=2.0.0,<3" - -[package.extras] -broker = ["pymsalruntime (>=0.14,<0.18)", "pymsalruntime (>=0.17,<0.18)"] - -[[package]] -name = "msal-extensions" -version = "1.2.0" -description = "Microsoft Authentication Library extensions (MSAL EX) provides a persistence API that can save your data on disk, encrypted on Windows, macOS and Linux. Concurrent data access will be coordinated by a file lock mechanism." -optional = false -python-versions = ">=3.7" -files = [ - {file = "msal_extensions-1.2.0-py3-none-any.whl", hash = "sha256:cf5ba83a2113fa6dc011a254a72f1c223c88d7dfad74cc30617c4679a417704d"}, - {file = "msal_extensions-1.2.0.tar.gz", hash = "sha256:6f41b320bfd2933d631a215c91ca0dd3e67d84bd1a2f50ce917d5874ec646bef"}, -] - -[package.dependencies] -msal = ">=1.29,<2" -portalocker = ">=1.4,<3" - [[package]] name = "numpy" version = "1.26.4" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, @@ -2320,6 +2361,7 @@ version = "3.2.2" description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca"}, {file = "oauthlib-3.2.2.tar.gz", hash = "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918"}, @@ -2336,6 +2378,7 @@ version = "1.37.0" description = "The official Python library for the openai API" optional = false python-versions = ">=3.7.1" +groups = ["main"] files = [ {file = "openai-1.37.0-py3-none-any.whl", hash = "sha256:a903245c0ecf622f2830024acdaa78683c70abb8e9d37a497b851670864c9f73"}, {file = "openai-1.37.0.tar.gz", hash = "sha256:dc8197fc40ab9d431777b6620d962cc49f4544ffc3011f03ce0a805e6eb54adb"}, @@ -2359,6 +2402,7 @@ version = "0.11.4" description = "A stats collection and distributed tracing framework" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "opencensus-0.11.4-py2.py3-none-any.whl", hash = "sha256:a18487ce68bc19900336e0ff4655c5a116daf10c1b3685ece8d971bddad6a864"}, {file = "opencensus-0.11.4.tar.gz", hash = "sha256:cbef87d8b8773064ab60e5c2a1ced58bbaa38a6d052c41aec224958ce544eff2"}, @@ -2375,6 +2419,7 @@ version = "0.1.3" description = "OpenCensus Runtime Context" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "opencensus-context-0.1.3.tar.gz", hash = "sha256:a03108c3c10d8c80bb5ddf5c8a1f033161fa61972a9917f9b9b3a18517f0088c"}, {file = "opencensus_context-0.1.3-py2.py3-none-any.whl", hash = "sha256:073bb0590007af276853009fac7e4bab1d523c3f03baf4cb4511ca38967c6039"}, @@ -2386,6 +2431,7 @@ version = "1.0.7" description = "OpenCensus Azure Monitor Exporter" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "opencensus-ext-azure-1.0.7.tar.gz", hash = "sha256:4b08a5da92d935df375a9a38bbf8f6fe70713a7911bea7844c71df527c163d89"}, {file = "opencensus_ext_azure-1.0.7-py2.py3-none-any.whl", hash = "sha256:50d24ac185a422760db0dd07a33f545125642855005ffd9bab84ab57be9b9a21"}, @@ -2402,6 +2448,7 @@ version = "0.7.4" description = "OpenCensus Django Integration" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "opencensus-ext-django-0.7.4.tar.gz", hash = "sha256:ab2d22d876c811c5897c90d44cf225efe49c6fd255a7640e3d0063dd9d7f85d3"}, {file = "opencensus_ext_django-0.7.4-py2.py3-none-any.whl", hash = "sha256:e5b8f156ac3705c8e8c2cedf2084c934070bdb81d7d1cf88aca8393b8ab93999"}, @@ -2417,6 +2464,7 @@ version = "3.0.10" description = "A Python library to read/write Excel 2010 xlsx/xlsm files" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "openpyxl-3.0.10-py2.py3-none-any.whl", hash = "sha256:0ab6d25d01799f97a9464630abacbb34aafecdcaa0ef3cba6d6b3499867d0355"}, {file = "openpyxl-3.0.10.tar.gz", hash = "sha256:e47805627aebcf860edb4edf7987b1309c1b3632f3750538ed962bbcc3bd7449"}, @@ -2431,6 +2479,7 @@ version = "1.3.0" description = "TLS (SSL) sockets, key generation, encryption, decryption, signing, verification and KDFs using the OS crypto libraries. Does not require a compiler, and relies on the OS for patching. Works on Windows, OS X and Linux/BSD." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "oscrypto-1.3.0-py2.py3-none-any.whl", hash = "sha256:2b2f1d2d42ec152ca90ccb5682f3e051fb55986e1b170ebde472b133713e7085"}, {file = "oscrypto-1.3.0.tar.gz", hash = "sha256:6f5fef59cb5b3708321db7cca56aed8ad7e662853351e7991fcf60ec606d47a4"}, @@ -2445,6 +2494,7 @@ version = "24.1" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, @@ -2456,6 +2506,7 @@ version = "1.3.5" description = "Powerful data structures for data analysis, time series, and statistics" optional = false python-versions = ">=3.7.1" +groups = ["main"] files = [ {file = "pandas-1.3.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:62d5b5ce965bae78f12c1c0df0d387899dd4211ec0bdc52822373f13a3a022b9"}, {file = "pandas-1.3.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:adfeb11be2d54f275142c8ba9bf67acee771b7186a5745249c7d5a06c670136b"}, @@ -2498,6 +2549,7 @@ version = "0.8.4" description = "A Python Parser" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"}, {file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"}, @@ -2513,6 +2565,7 @@ version = "1.16.0" description = "A wrapper around the pdftoppm and pdftocairo command line tools to convert PDF to a PIL Image list." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "pdf2image-1.16.0-py3-none-any.whl", hash = "sha256:84f79f2b8fad943e36323ea4e937fcb05f26ded0caa0a01181df66049e42fb65"}, {file = "pdf2image-1.16.0.tar.gz", hash = "sha256:d58ed94d978a70c73c2bb7fdf8acbaf2a7089c29ff8141be5f45433c0c4293bb"}, @@ -2527,6 +2580,7 @@ version = "20191110" description = "PDF parser and analyzer" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "pdfminer.six-20191110-py2.py3-none-any.whl", hash = "sha256:ca2ca58f3ac66a486bce53a6ddba95dc2b27781612915fa41c444790ba9cd2a8"}, {file = "pdfminer.six-20191110.tar.gz", hash = "sha256:141a53ec491bee6d45bf9b2c7f82601426fb5d32636bcf6b9c8a8f3b6431fea6"}, @@ -2548,6 +2602,8 @@ version = "4.9.0" description = "Pexpect allows easy control of interactive console applications." optional = false python-versions = "*" +groups = ["main"] +markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\"" files = [ {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, @@ -2562,6 +2618,7 @@ version = "10.3.0" description = "Python Imaging Library (Fork)" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pillow-10.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45"}, {file = "pillow-10.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c"}, @@ -2639,7 +2696,7 @@ docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline fpx = ["olefile"] mic = ["olefile"] tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] -typing = ["typing-extensions"] +typing = ["typing-extensions ; python_version < \"3.10\""] xmp = ["defusedxml"] [[package]] @@ -2648,6 +2705,7 @@ version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, @@ -2663,36 +2721,19 @@ version = "1.1.0" description = "A library to manipulate gettext files (po and mo files)." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "polib-1.1.0-py2.py3-none-any.whl", hash = "sha256:93b730477c16380c9a96726c54016822ff81acfa553977fdd131f2b90ba858d7"}, {file = "polib-1.1.0.tar.gz", hash = "sha256:fad87d13696127ffb27ea0882d6182f1a9cf8a5e2b37a587751166c51e5a332a"}, ] -[[package]] -name = "portalocker" -version = "2.10.1" -description = "Wraps the portalocker recipe for easy usage" -optional = false -python-versions = ">=3.8" -files = [ - {file = "portalocker-2.10.1-py3-none-any.whl", hash = "sha256:53a5984ebc86a025552264b459b46a2086e269b21823cb572f8f28ee759e45bf"}, - {file = "portalocker-2.10.1.tar.gz", hash = "sha256:ef1bf844e878ab08aee7e40184156e1151f228f103aa5c6bd0724cc330960f8f"}, -] - -[package.dependencies] -pywin32 = {version = ">=226", markers = "platform_system == \"Windows\""} - -[package.extras] -docs = ["sphinx (>=1.7.1)"] -redis = ["redis"] -tests = ["pytest (>=5.4.1)", "pytest-cov (>=2.8.1)", "pytest-mypy (>=0.8.0)", "pytest-timeout (>=2.1.0)", "redis", "sphinx (>=6.0.0)", "types-redis"] - [[package]] name = "promise" version = "2.3" description = "Promises/A+ implementation for Python" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "promise-2.3.tar.gz", hash = "sha256:dfd18337c523ba4b6a58801c164c1904a9d4d1b1747c7d5dbf45b693a49d93d0"}, ] @@ -2709,6 +2750,7 @@ version = "3.0.48" description = "Library for building powerful interactive command lines in Python" optional = false python-versions = ">=3.7.0" +groups = ["main"] files = [ {file = "prompt_toolkit-3.0.48-py3-none-any.whl", hash = "sha256:f49a827f90062e411f1ce1f854f2aedb3c23353244f8108b89283587397ac10e"}, {file = "prompt_toolkit-3.0.48.tar.gz", hash = "sha256:d6623ab0477a80df74e646bdbc93621143f5caf104206aa29294d53de1a03d90"}, @@ -2723,6 +2765,7 @@ version = "1.24.0" description = "Beautiful, Pythonic protocol buffers." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "proto-plus-1.24.0.tar.gz", hash = "sha256:30b72a5ecafe4406b0d339db35b56c4059064e69227b8c3bda7462397f966445"}, {file = "proto_plus-1.24.0-py3-none-any.whl", hash = "sha256:402576830425e5f6ce4c2a6702400ac79897dab0b4343821aa5188b0fab81a12"}, @@ -2740,6 +2783,7 @@ version = "5.28.2" description = "" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "protobuf-5.28.2-cp310-abi3-win32.whl", hash = "sha256:eeea10f3dc0ac7e6b4933d32db20662902b4ab81bf28df12218aa389e9c2102d"}, {file = "protobuf-5.28.2-cp310-abi3-win_amd64.whl", hash = "sha256:2c69461a7fcc8e24be697624c09a839976d82ae75062b11a0972e41fd2cd9132"}, @@ -2760,6 +2804,7 @@ version = "6.0.0" description = "Cross-platform lib for process and system monitoring in Python." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +groups = ["main"] files = [ {file = "psutil-6.0.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a021da3e881cd935e64a3d0a20983bda0bb4cf80e4f74fa9bfcb1bc5785360c6"}, {file = "psutil-6.0.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:1287c2b95f1c0a364d23bc6f2ea2365a8d4d9b726a3be7294296ff7ba97c17f0"}, @@ -2781,7 +2826,7 @@ files = [ ] [package.extras] -test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] +test = ["enum34 ; python_version <= \"3.4\"", "ipaddress ; python_version < \"3.0\"", "mock ; python_version < \"3.0\"", "pywin32 ; sys_platform == \"win32\"", "wmi ; sys_platform == \"win32\""] [[package]] name = "psycopg2-binary" @@ -2789,6 +2834,7 @@ version = "2.9.9" description = "psycopg2 - Python-PostgreSQL Database Adapter" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "psycopg2-binary-2.9.9.tar.gz", hash = "sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c"}, {file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202"}, @@ -2870,6 +2916,8 @@ version = "0.7.0" description = "Run a subprocess in a pseudo terminal" optional = false python-versions = "*" +groups = ["main"] +markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\"" files = [ {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, @@ -2881,6 +2929,7 @@ version = "0.2.3" description = "Safely evaluate AST nodes without side effects" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0"}, {file = "pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42"}, @@ -2895,6 +2944,7 @@ version = "0.6.1" description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629"}, {file = "pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034"}, @@ -2906,6 +2956,7 @@ version = "0.4.1" description = "A collection of ASN.1-based protocols modules" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pyasn1_modules-0.4.1-py3-none-any.whl", hash = "sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd"}, {file = "pyasn1_modules-0.4.1.tar.gz", hash = "sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c"}, @@ -2920,6 +2971,7 @@ version = "19.8.18" description = "ISO country, subdivision, language, currency and script definitions and their translations" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "pycountry-19.8.18.tar.gz", hash = "sha256:3c57aa40adcf293d59bebaffbe60d8c39976fba78d846a018dc0c2ec9c6cb3cb"}, ] @@ -2930,6 +2982,8 @@ version = "2.22" description = "C parser in Python" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "platform_python_implementation != \"PyPy\"" files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, @@ -2941,6 +2995,7 @@ version = "3.21.0" description = "Cryptographic library for Python" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +groups = ["main"] files = [ {file = "pycryptodome-3.21.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:dad9bf36eda068e89059d1f07408e397856be9511d7113ea4b586642a429a4fd"}, {file = "pycryptodome-3.21.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:a1752eca64c60852f38bb29e2c86fca30d7672c024128ef5d70cc15868fa10f4"}, @@ -2982,6 +3037,7 @@ version = "2.9.2" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12"}, {file = "pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f"}, @@ -2997,7 +3053,7 @@ typing-extensions = [ [package.extras] email = ["email-validator (>=2.0.0)"] -timezone = ["tzdata"] +timezone = ["tzdata ; python_version >= \"3.9\" and sys_platform == \"win32\""] [[package]] name = "pydantic-core" @@ -3005,6 +3061,7 @@ version = "2.23.4" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pydantic_core-2.23.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b"}, {file = "pydantic_core-2.23.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166"}, @@ -3106,6 +3163,7 @@ version = "8.0.4" description = "The kitchen sink of Python utility libraries for doing \"stuff\" in a functional way. Based on the Lo-Dash Javascript library." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pydash-8.0.4-py3-none-any.whl", hash = "sha256:59d0c9ca0d22b4f8bcfab01bfe2e89b49f4c9e9fa75961caf156094670260999"}, {file = "pydash-8.0.4.tar.gz", hash = "sha256:a33fb17b4b06c617da5c57c711605d2dc8723311ee5388c8371f87cd44bf4112"}, @@ -3123,6 +3181,7 @@ version = "2.18.0" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, @@ -3137,6 +3196,7 @@ version = "0.20.1" description = "Tools for stamping and signing PDF files" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "pyHanko-0.20.1-py3-none-any.whl", hash = "sha256:463068cbea01792037cacbad11141cc9070c80b63cf738f488167bb6700d36fa"}, {file = "pyHanko-0.20.1.tar.gz", hash = "sha256:93de44061c0907c9121cf35f20294930f31f22cf71334907ddde8e8fefbafcbc"}, @@ -3162,7 +3222,7 @@ mypy = ["pyHanko[async-http,extra-pubkey-algs,image-support,opentype,pkcs11,xmp] opentype = ["fonttools (>=4.33.3)", "uharfbuzz (>=0.25.0,<0.38.0)"] pkcs11 = ["python-pkcs11 (>=0.7.0,<0.8.0)"] testing = ["certomancer-csc-dummy (==0.2.2)", "pyHanko[async-http,extra-pubkey-algs,image-support,opentype,pkcs11,testing-basic,xmp]", "pytest-aiohttp (>=1.0.4,<1.1.0)"] -testing-basic = ["backports.zoneinfo[tzdata]", "certomancer (==0.11.*)", "freezegun (>=1.1.0)", "pytest (>=6.1.1)", "pytest-asyncio (==0.21.1)", "pytest-cov (>=4.0,<4.2)", "requests-mock (>=1.8.0)"] +testing-basic = ["backports.zoneinfo[tzdata] ; python_version < \"3.9\"", "certomancer (==0.11.*)", "freezegun (>=1.1.0)", "pytest (>=6.1.1)", "pytest-asyncio (==0.21.1)", "pytest-cov (>=4.0,<4.2)", "requests-mock (>=1.8.0)"] xmp = ["defusedxml (>=0.7.1,<0.8.0)"] [[package]] @@ -3171,6 +3231,7 @@ version = "0.24.1" description = "Validates X.509 certificates and paths; forked from wbond/certvalidator" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "pyhanko-certvalidator-0.24.1.tar.gz", hash = "sha256:4c6de2c2372751df8d449451583a84da6b01cd2e3156b0a3da2b06613cbbf25d"}, {file = "pyhanko_certvalidator-0.24.1-py3-none-any.whl", hash = "sha256:46d093df4768319a8c54ce3edb5c4df42f06de010907ff01630e75378561b5ca"}, @@ -3194,14 +3255,12 @@ version = "2.9.0" description = "JSON Web Token implementation in Python" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "PyJWT-2.9.0-py3-none-any.whl", hash = "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850"}, {file = "pyjwt-2.9.0.tar.gz", hash = "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c"}, ] -[package.dependencies] -cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"crypto\""} - [package.extras] crypto = ["cryptography (>=3.4.0)"] dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"] @@ -3214,16 +3273,17 @@ version = "5.0.1" description = "A pure-python PDF library capable of splitting, merging, cropping, and transforming PDF files" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pypdf-5.0.1-py3-none-any.whl", hash = "sha256:ff8a32da6c7a63fea9c32fa4dd837cdd0db7966adf6c14f043e3f12592e992db"}, {file = "pypdf-5.0.1.tar.gz", hash = "sha256:a361c3c372b4a659f9c8dd438d5ce29a753c79c620dc6e1fd66977651f5547ea"}, ] [package.extras] -crypto = ["PyCryptodome", "cryptography"] +crypto = ["PyCryptodome ; python_version == \"3.6\"", "cryptography ; python_version >= \"3.7\""] dev = ["black", "flit", "pip-tools", "pre-commit (<2.18.0)", "pytest-cov", "pytest-socket", "pytest-timeout", "pytest-xdist", "wheel"] docs = ["myst_parser", "sphinx", "sphinx_rtd_theme"] -full = ["Pillow (>=8.0.0)", "PyCryptodome", "cryptography"] +full = ["Pillow (>=8.0.0)", "PyCryptodome ; python_version == \"3.6\"", "cryptography ; python_version >= \"3.7\""] image = ["Pillow (>=8.0.0)"] [[package]] @@ -3232,6 +3292,7 @@ version = "1.27.9" description = "A pure-python PDF library capable of splitting, merging, cropping, and transforming PDF files" optional = false python-versions = ">=2.7" +groups = ["main"] files = [ {file = "PyPDF2-1.27.9-py3-none-any.whl", hash = "sha256:5e29ffaf2efcfb77c25206e3b8df517a18af84e64ebe1b3a93abac8d01176374"}, {file = "PyPDF2-1.27.9.tar.gz", hash = "sha256:5f7937fd94ba387a2a241db8858770e53091d8ffab9922512c0bf48e3f4cc615"}, @@ -3243,6 +3304,7 @@ version = "0.20.0" description = "Persistent/Functional/Immutable data structures" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pyrsistent-0.20.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8c3aba3e01235221e5b229a6c05f585f344734bd1ad42a8ac51493d74722bbce"}, {file = "pyrsistent-0.20.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1beb78af5423b879edaf23c5591ff292cf7c33979734c99aa66d5914ead880f"}, @@ -3284,6 +3346,7 @@ version = "8.3.3" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, @@ -3304,6 +3367,7 @@ version = "4.9.0" description = "A Django plugin for pytest." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pytest_django-4.9.0-py3-none-any.whl", hash = "sha256:1d83692cb39188682dbb419ff0393867e9904094a549a7d38a3154d5731b2b99"}, {file = "pytest_django-4.9.0.tar.gz", hash = "sha256:8bf7bc358c9ae6f6fc51b6cebb190fe20212196e6807121f11bd6a3b03428314"}, @@ -3322,6 +3386,7 @@ version = "0.6" description = "pytest plugin to run your tests in a specific order" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "pytest-ordering-0.6.tar.gz", hash = "sha256:561ad653626bb171da78e682f6d39ac33bb13b3e272d406cd555adb6b006bda6"}, {file = "pytest_ordering-0.6-py2-none-any.whl", hash = "sha256:27fba3fc265f5d0f8597e7557885662c1bdc1969497cd58aff6ed21c3b617de2"}, @@ -3337,6 +3402,7 @@ version = "1.7.0" description = "Profiling plugin for py.test" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "pytest-profiling-1.7.0.tar.gz", hash = "sha256:93938f147662225d2b8bd5af89587b979652426a8a6ffd7e73ec4a23e24b7f29"}, {file = "pytest_profiling-1.7.0-py2.py3-none-any.whl", hash = "sha256:999cc9ac94f2e528e3f5d43465da277429984a1c237ae9818f8cfd0b06acb019"}, @@ -3356,6 +3422,7 @@ version = "0.6.0" description = "Python Bidi layout wrapping the Rust crate unicode-bidi" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "python_bidi-0.6.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:032b16f70c5d4f48c8dc5a4ade071826a0fb64172e0435d49deba6ea66fc5d42"}, {file = "python_bidi-0.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:53b50f6ad3e633dcc74fc96bb959bf375a84db36db380d76f9c189ce33099ede"}, @@ -3485,6 +3552,7 @@ version = "2.8.0" description = "Extensions to the standard Python datetime module" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +groups = ["main"] files = [ {file = "python-dateutil-2.8.0.tar.gz", hash = "sha256:c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e"}, {file = "python_dateutil-2.8.0-py2.py3-none-any.whl", hash = "sha256:7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493df2fb"}, @@ -3499,6 +3567,7 @@ version = "0.12.1" description = "Python extension for computing string edit distances and similarities." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "python-Levenshtein-0.12.1.tar.gz", hash = "sha256:554e273a88060d177e7b3c1e6ea9158dde11563bfae8f7f661f73f47e5ff0911"}, ] @@ -3512,6 +3581,7 @@ version = "0.4.27" description = "File type identification using libmagic" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["main"] files = [ {file = "python-magic-0.4.27.tar.gz", hash = "sha256:c1ba14b08e4a5f5c31a302b7721239695b2f0f058d125bd5ce1ee36b9d9d3c3b"}, {file = "python_magic-0.4.27-py2.py3-none-any.whl", hash = "sha256:c212960ad306f700aa0d01e5d7a325d20548ff97eb9920dcd29513174f0294d3"}, @@ -3523,6 +3593,7 @@ version = "1.6.0" description = "A module provides basic functions for parsing mime-type names and matching them against a list of media-ranges." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "python-mimeparse-1.6.0.tar.gz", hash = "sha256:76e4b03d700a641fd7761d3cd4fdbbdcd787eade1ebfac43f877016328334f78"}, {file = "python_mimeparse-1.6.0-py2.py3-none-any.whl", hash = "sha256:a295f03ff20341491bfe4717a39cd0a8cc9afad619ba44b77e86b0ab8a2b8282"}, @@ -3534,6 +3605,7 @@ version = "0.3.2" description = "Python wrapper for HTML Tidy (tidylib) on Python 2 and 3" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "pytidylib-0.3.2.tar.gz", hash = "sha256:22b1c8d75970d8064ff999c2369e98af1d0685417eda4c829a5c9f56764b0af3"}, ] @@ -3544,44 +3616,19 @@ version = "2019.1" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "pytz-2019.1-py2.py3-none-any.whl", hash = "sha256:303879e36b721603cc54604edcac9d20401bdbe31e1e4fdee5b9f98d5d31dfda"}, {file = "pytz-2019.1.tar.gz", hash = "sha256:d747dd3d23d77ef44c6a3526e274af6efeb0a6f1afd5a69ba4d5be4098c8e141"}, ] -[[package]] -name = "pywin32" -version = "308" -description = "Python for Window Extensions" -optional = false -python-versions = "*" -files = [ - {file = "pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e"}, - {file = "pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e"}, - {file = "pywin32-308-cp310-cp310-win_arm64.whl", hash = "sha256:a5ab5381813b40f264fa3495b98af850098f814a25a63589a8e9eb12560f450c"}, - {file = "pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a"}, - {file = "pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b"}, - {file = "pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6"}, - {file = "pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897"}, - {file = "pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47"}, - {file = "pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091"}, - {file = "pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed"}, - {file = "pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4"}, - {file = "pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd"}, - {file = "pywin32-308-cp37-cp37m-win32.whl", hash = "sha256:1f696ab352a2ddd63bd07430080dd598e6369152ea13a25ebcdd2f503a38f1ff"}, - {file = "pywin32-308-cp37-cp37m-win_amd64.whl", hash = "sha256:13dcb914ed4347019fbec6697a01a0aec61019c1046c2b905410d197856326a6"}, - {file = "pywin32-308-cp38-cp38-win32.whl", hash = "sha256:5794e764ebcabf4ff08c555b31bd348c9025929371763b2183172ff4708152f0"}, - {file = "pywin32-308-cp38-cp38-win_amd64.whl", hash = "sha256:3b92622e29d651c6b783e368ba7d6722b1634b8e70bd376fd7610fe1992e19de"}, - {file = "pywin32-308-cp39-cp39-win32.whl", hash = "sha256:7873ca4dc60ab3287919881a7d4f88baee4a6e639aa6962de25a98ba6b193341"}, - {file = "pywin32-308-cp39-cp39-win_amd64.whl", hash = "sha256:71b3322d949b4cc20776436a9c9ba0eeedcbc9c650daa536df63f0ff111bb920"}, -] - [[package]] name = "pyyaml" version = "6.0.2" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, @@ -3644,6 +3691,7 @@ version = "8.0" description = "QR Code image generator" optional = false python-versions = "<4.0,>=3.9" +groups = ["main"] files = [ {file = "qrcode-8.0-py3-none-any.whl", hash = "sha256:9fc05f03305ad27a709eb742cf3097fa19e6f6f93bb9e2f039c0979190f6f1b1"}, {file = "qrcode-8.0.tar.gz", hash = "sha256:025ce2b150f7fe4296d116ee9bad455a6643ab4f6e7dce541613a4758cbce347"}, @@ -3663,6 +3711,7 @@ version = "5.1.1" description = "Python client for Redis database and key-value store" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "redis-5.1.1-py3-none-any.whl", hash = "sha256:f8ea06b7482a668c6475ae202ed8d9bcaa409f6e87fb77ed1043d912afd62e24"}, {file = "redis-5.1.1.tar.gz", hash = "sha256:f6c997521fedbae53387307c5d0bf784d9acc28d9f1d058abeac566ec4dbed72"}, @@ -3681,6 +3730,7 @@ version = "2024.9.11" description = "Alternative regular expression module, to replace re." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "regex-2024.9.11-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1494fa8725c285a81d01dc8c06b55287a1ee5e0e382d8413adc0a9197aac6408"}, {file = "regex-2024.9.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0e12c481ad92d129c78f13a2a3662317e46ee7ef96c94fd332e1c29131875b7d"}, @@ -3784,6 +3834,7 @@ version = "4.2.5" description = "The Reportlab Toolkit" optional = false python-versions = "<4,>=3.7" +groups = ["main"] files = [ {file = "reportlab-4.2.5-py3-none-any.whl", hash = "sha256:eb2745525a982d9880babb991619e97ac3f661fae30571b7d50387026ca765ee"}, {file = "reportlab-4.2.5.tar.gz", hash = "sha256:5cf35b8fd609b68080ac7bbb0ae1e376104f7d5f7b2d3914c7adc63f2593941f"}, @@ -3804,6 +3855,7 @@ version = "2.32.2" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "requests-2.32.2-py3-none-any.whl", hash = "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c"}, {file = "requests-2.32.2.tar.gz", hash = "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289"}, @@ -3825,6 +3877,7 @@ version = "1.0.0" description = "A utility belt for advanced users of python-requests" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main"] files = [ {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, @@ -3839,6 +3892,7 @@ version = "4.9" description = "Pure-Python RSA implementation" optional = false python-versions = ">=3.6,<4" +groups = ["main"] files = [ {file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"}, {file = "rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"}, @@ -3853,6 +3907,7 @@ version = "1.6.3" description = "Reactive Extensions (Rx) for Python" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "Rx-1.6.3.tar.gz", hash = "sha256:ca71b65d0fc0603a3b5cfaa9e33f5ba81e4aae10a58491133595088d7734b2da"}, ] @@ -3863,6 +3918,7 @@ version = "0.5.2" description = "An Amazon S3 Transfer Manager" optional = false python-versions = ">= 3.6" +groups = ["main"] files = [ {file = "s3transfer-0.5.2-py3-none-any.whl", hash = "sha256:7a6f4c4d1fdb9a2b640244008e142cbc2cd3ae34b386584ef044dd0f27101971"}, {file = "s3transfer-0.5.2.tar.gz", hash = "sha256:95c58c194ce657a5f4fb0b9e60a84968c808888aed628cd98ab8771fe1db98ed"}, @@ -3880,6 +3936,7 @@ version = "2.16.0" description = "Python client for Sentry (https://sentry.io)" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "sentry_sdk-2.16.0-py2.py3-none-any.whl", hash = "sha256:49139c31ebcd398f4f6396b18910610a0c1602f6e67083240c33019d1f6aa30c"}, {file = "sentry_sdk-2.16.0.tar.gz", hash = "sha256:90f733b32e15dfc1999e6b7aca67a38688a567329de4d6e184154a73f96c6892"}, @@ -3932,19 +3989,20 @@ version = "75.1.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "setuptools-75.1.0-py3-none-any.whl", hash = "sha256:35ab7fd3bcd95e6b7fd704e4a1539513edad446c097797f2985e0e4b960772f2"}, {file = "setuptools-75.1.0.tar.gz", hash = "sha256:d59a21b17a275fb872a9c3dae73963160ae079f1049ed956880cd7c09b120538"}, ] [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.5.2)"] -core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.collections", "jaraco.functools", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "ruff (>=0.5.2) ; sys_platform != \"cygwin\""] +core = ["importlib-metadata (>=6) ; python_version < \"3.10\"", "importlib-resources (>=5.10.2) ; python_version < \"3.9\"", "jaraco.collections", "jaraco.functools", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1) ; python_version < \"3.11\"", "wheel (>=0.43.0)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] enabler = ["pytest-enabler (>=2.2)"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] -type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.11.*)", "pytest-mypy"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21) ; python_version >= \"3.9\" and sys_platform != \"cygwin\"", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf ; sys_platform != \"cygwin\"", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib-metadata (>=7.0.2) ; python_version < \"3.10\"", "jaraco.develop (>=7.21) ; sys_platform != \"cygwin\"", "mypy (==1.11.*)", "pytest-mypy"] [[package]] name = "shapely" @@ -3952,6 +4010,7 @@ version = "2.0.6" description = "Manipulation and analysis of geometric objects" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "shapely-2.0.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29a34e068da2d321e926b5073539fd2a1d4429a2c656bd63f0bd4c8f5b236d0b"}, {file = "shapely-2.0.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c84c3f53144febf6af909d6b581bc05e8785d57e27f35ebaa5c1ab9baba13b"}, @@ -4010,6 +4069,7 @@ version = "4.1.0" description = "Backport functools.singledispatch to older Pythons." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "singledispatch-4.1.0-py2.py3-none-any.whl", hash = "sha256:6061bd291204beaeac90cdbc342b68d213b7a6efb44ae6c5e6422a78be351c8a"}, {file = "singledispatch-4.1.0.tar.gz", hash = "sha256:f3430b886d5b4213d07d715096a75da5e4a8105284c497b9aee6d6d48bfe90cb"}, @@ -4017,7 +4077,7 @@ files = [ [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +testing = ["pytest (>=6)", "pytest-black (>=0.3.7) ; platform_python_implementation != \"PyPy\"", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1) ; platform_python_implementation != \"PyPy\"", "pytest-ruff"] [[package]] name = "six" @@ -4025,6 +4085,7 @@ version = "1.16.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +groups = ["main", "dev"] files = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, @@ -4036,6 +4097,7 @@ version = "0.6.0" description = "Snapshot testing for pytest, unittest, Django, and Nose" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "snapshottest-0.6.0-py2.py3-none-any.whl", hash = "sha256:9b177cffe0870c589df8ddbee0a770149c5474b251955bdbde58b7f32a4ec429"}, {file = "snapshottest-0.6.0.tar.gz", hash = "sha256:bbcaf81d92d8e330042e5c928e13d9f035e99e91b314fe55fda949c2f17b653c"}, @@ -4057,6 +4119,7 @@ version = "1.3.1" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, @@ -4068,6 +4131,7 @@ version = "2.4.0" description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, @@ -4079,6 +4143,7 @@ version = "0.5.1" description = "A non-validating SQL parser." optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "sqlparse-0.5.1-py3-none-any.whl", hash = "sha256:773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4"}, {file = "sqlparse-0.5.1.tar.gz", hash = "sha256:bb6b4df465655ef332548e24f08e205afc81b9ab86cb1c45657a7ff173a3a00e"}, @@ -4094,6 +4159,7 @@ version = "0.6.3" description = "Extract data from python stack frames and tracebacks for informative displays" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, @@ -4113,6 +4179,7 @@ version = "1.5.1" description = "A pure-Python library for reading and converting SVG" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "svglib-1.5.1.tar.gz", hash = "sha256:3ae765d3a9409ee60c0fb4d24c2deb6a80617aa927054f5bcd7fc98f0695e587"}, ] @@ -4129,6 +4196,7 @@ version = "1.2.0" description = "Simple wrapper for tabula-java, read tables from PDF into DataFrame" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "tabula_py-1.2.0-py2.py3-none-any.whl", hash = "sha256:f87932ca3afb4a62fe6ebcddadc9f51151b1a8c375e151a17389974c0182ec37"}, ] @@ -4145,6 +4213,7 @@ version = "2.5.0" description = "ANSI color formatting for output in terminal" optional = false python-versions = ">=3.9" +groups = ["dev"] files = [ {file = "termcolor-2.5.0-py3-none-any.whl", hash = "sha256:37b17b5fc1e604945c2642c872a3764b5d547a48009871aea3edd3afa180afb8"}, {file = "termcolor-2.5.0.tar.gz", hash = "sha256:998d8d27da6d48442e8e1f016119076b690d962507531df4890fcd2db2ef8a6f"}, @@ -4159,6 +4228,7 @@ version = "1.3" description = "The most basic Text::Unidecode port" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"}, {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"}, @@ -4170,6 +4240,7 @@ version = "0.7.0" description = "tiktoken is a fast BPE tokeniser for use with OpenAI's models" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "tiktoken-0.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:485f3cc6aba7c6b6ce388ba634fbba656d9ee27f766216f45146beb4ac18b25f"}, {file = "tiktoken-0.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e54be9a2cd2f6d6ffa3517b064983fb695c9a9d8aa7d574d1ef3c3f931a99225"}, @@ -4222,6 +4293,7 @@ version = "1.3.0" description = "A tiny CSS parser" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "tinycss2-1.3.0-py3-none-any.whl", hash = "sha256:54a8dbdffb334d536851be0226030e9505965bb2f30f21a4a82c55fb2a80fae7"}, {file = "tinycss2-1.3.0.tar.gz", hash = "sha256:152f9acabd296a8375fbca5b84c961ff95971fcfc32e79550c8df8e29118c54d"}, @@ -4240,6 +4312,7 @@ version = "4.66.5" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "tqdm-4.66.5-py3-none-any.whl", hash = "sha256:90279a3770753eafc9194a0364852159802111925aa30eb3f9d85b0e805ac7cd"}, {file = "tqdm-4.66.5.tar.gz", hash = "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad"}, @@ -4260,6 +4333,7 @@ version = "5.14.3" description = "Traitlets Python configuration system" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"}, {file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"}, @@ -4275,6 +4349,7 @@ version = "6.0.12.20240917" description = "Typing stubs for PyYAML" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "types-PyYAML-6.0.12.20240917.tar.gz", hash = "sha256:d1405a86f9576682234ef83bcb4e6fff7c9305c8b1fbad5e0bcd4f7dbdc9c587"}, {file = "types_PyYAML-6.0.12.20240917-py3-none-any.whl", hash = "sha256:392b267f1c0fe6022952462bf5d6523f31e37f6cea49b14cee7ad634b6301570"}, @@ -4286,6 +4361,7 @@ version = "3.6.2" description = "Type Hints for Python" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "typing-3.6.2-py2-none-any.whl", hash = "sha256:349b1f9c109c84b53ac79ac1d822eaa68fc91d63b321bd9392df15098f746f53"}, {file = "typing-3.6.2-py3-none-any.whl", hash = "sha256:63a8255fe7c6269916baa440eb9b6a67139b0b97a01af632e7bd2842e1e02f15"}, @@ -4298,6 +4374,7 @@ version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, @@ -4309,10 +4386,12 @@ version = "2024.2" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" +groups = ["main", "dev"] files = [ {file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"}, {file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"}, ] +markers = {main = "sys_platform == \"win32\" or platform_system == \"Windows\"", dev = "sys_platform == \"win32\""} [[package]] name = "tzlocal" @@ -4320,6 +4399,7 @@ version = "5.2" description = "tzinfo object for the local timezone" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "tzlocal-5.2-py3-none-any.whl", hash = "sha256:49816ef2fe65ea8ac19d19aa7a1ae0551c834303d5014c6d5a62e4cbda8047b8"}, {file = "tzlocal-5.2.tar.gz", hash = "sha256:8d399205578f1a9342816409cc1e46a93ebd5755e39ea2d85334bea911bf0e6e"}, @@ -4337,6 +4417,7 @@ version = "0.14.1" description = "Python2's stdlib csv module is nice, but it doesn't support unicode. This module is a drop-in replacement which *does*." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "unicodecsv-0.14.1.tar.gz", hash = "sha256:018c08037d48649a0412063ff4eda26eaa81eff1546dbffa51fa5293276ff7fc"}, ] @@ -4347,6 +4428,7 @@ version = "4.1.1" description = "Implementation of RFC 6570 URI Templates" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "uritemplate-4.1.1-py2.py3-none-any.whl", hash = "sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e"}, {file = "uritemplate-4.1.1.tar.gz", hash = "sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0"}, @@ -4358,6 +4440,7 @@ version = "4.0.3" description = "URI parsing, classification and composition" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "uritools-4.0.3-py3-none-any.whl", hash = "sha256:bae297d090e69a0451130ffba6f2f1c9477244aa0a5543d66aed2d9f77d0dd9c"}, {file = "uritools-4.0.3.tar.gz", hash = "sha256:ee06a182a9c849464ce9d5fa917539aacc8edd2a4924d1b7aabeeecabcae3bc2"}, @@ -4369,14 +4452,15 @@ version = "1.26.20" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +groups = ["main"] files = [ {file = "urllib3-1.26.20-py2.py3-none-any.whl", hash = "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e"}, {file = "urllib3-1.26.20.tar.gz", hash = "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32"}, ] [package.extras] -brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +brotli = ["brotli (==1.0.9) ; os_name != \"nt\" and python_version < \"3\" and platform_python_implementation == \"CPython\"", "brotli (>=1.0.9) ; python_version >= \"3\" and platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; (os_name != \"nt\" or python_version >= \"3\") and platform_python_implementation != \"CPython\"", "brotlipy (>=0.6.0) ; os_name == \"nt\" and python_version < \"3\""] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress ; python_version == \"2.7\"", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] @@ -4385,6 +4469,7 @@ version = "5.1.0" description = "Python promises." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "vine-5.1.0-py3-none-any.whl", hash = "sha256:40fdf3c48b2cfe1c38a49e9ae2da6fda88e4794c810050a728bd7413811fb1dc"}, {file = "vine-5.1.0.tar.gz", hash = "sha256:8b62e981d35c41049211cf62a0a1242d8c1ee9bd15bb196ce38aefd6799e61e0"}, @@ -4396,6 +4481,7 @@ version = "1.1.0" description = "Python extension to run WebAssembly binaries" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "wasmer-1.1.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:c2af4b907ae2dabcac41e316e811d5937c93adf1f8b05c5d49427f8ce0f37630"}, {file = "wasmer-1.1.0-cp310-cp310-manylinux_2_24_x86_64.whl", hash = "sha256:ab1ae980021e5ec0bf0c6cdd3b979b1d15a5f3eb2b8a32da8dcb1156e4a1e484"}, @@ -4419,6 +4505,7 @@ version = "1.1.0" description = "The Cranelift compiler for the `wasmer` package (to compile WebAssembly module)" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "wasmer_compiler_cranelift-1.1.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:9869910179f39696a020edc5689f7759257ac1cce569a7a0fcf340c59788baad"}, {file = "wasmer_compiler_cranelift-1.1.0-cp310-cp310-manylinux_2_24_x86_64.whl", hash = "sha256:405546ee864ac158a4107f374dfbb1c8d6cfb189829bdcd13050143a4bd98f28"}, @@ -4442,6 +4529,7 @@ version = "0.2.13" description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, @@ -4453,6 +4541,7 @@ version = "0.5.1" description = "Character encoding aliases for legacy web content" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, @@ -4464,6 +4553,7 @@ version = "0.2.16" description = "PDF generator using HTML and CSS" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "xhtml2pdf-0.2.16-py3-none-any.whl", hash = "sha256:b37040127627aee42f76f25ebbd5798308ffc93edaf4850a4d3dd894160ebb53"}, {file = "xhtml2pdf-0.2.16.tar.gz", hash = "sha256:7391adac12afb086561667cdc8d6ef0ac4afe5097bd97383622d42b6343dee71"}, @@ -4485,7 +4575,7 @@ docs = ["sphinx (>=6)", "sphinx-rtd-theme (>=0.5.0)"] pycairo = ["reportlab[pycairo] (>=4.0.4,<5)"] release = ["build", "twine"] renderpm = ["reportlab[renderpm] (>=4.0.4,<5)"] -test = ["coverage (>=5.3)", "tomli (>=2.0.1)", "tox"] +test = ["coverage (>=5.3)", "tomli (>=2.0.1) ; python_version < \"3.11\"", "tox"] [[package]] name = "xmltodict" @@ -4493,12 +4583,13 @@ version = "0.11.0" description = "Makes working with XML feel like you are working with JSON" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "xmltodict-0.11.0-py2.py3-none-any.whl", hash = "sha256:add07d92089ff611badec526912747cf87afd4f9447af6661aca074eeaf32615"}, {file = "xmltodict-0.11.0.tar.gz", hash = "sha256:8f8d7d40aa28d83f4109a7e8aa86e67a4df202d9538be40c0cb1d70da527b0df"}, ] [metadata] -lock-version = "2.0" +lock-version = "2.1" python-versions = "^3.11" -content-hash = "9ff1ef3b0a1403e97dab266291ec7875f7b65361dc78c21f02bfcb7e6c95ec49" +content-hash = "8020750fc89ce1e4690fa65b48fca521d7b17b832bfe5af43bcb74a38cd4aed0" diff --git a/pyproject.toml b/pyproject.toml index 4d8d9274c..560ec2e85 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,7 @@ django-modeltranslation = "==0.17.5" django-read-only = "==1.12.0" django-reversion-compare = "==0.16.2" django-reversion = "==5.0.12" -django-storages = { version = "==1.11.1", extras = ["s3", "azure"] } +django-storages = { version = "==1.11.1", extras = ["s3"] } # FIXME: Add "azure" django-tinymce = "==4.1.0" django-oauth-toolkit = "3.0.1" djangorestframework-csv = "==2.1.1" @@ -88,7 +88,7 @@ drf-spectacular = "*" pyjwt = "*" shapely = "*" colorlog = "*" -azure-identity = "*" # Required by django-storages[azure] if used +# azure-identity = "*" # Required by django-storages[azure] if used mapbox-tilesets = "*" ipython = "*" tiktoken = "*" From dc6b805b62572d596c56f5888806e8475ff7ad47 Mon Sep 17 00:00:00 2001 From: thenav56 Date: Fri, 21 Feb 2025 15:08:34 +0545 Subject: [PATCH 16/17] Pin poetry version in Dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 62baf3c85..6bb20e8ac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,7 +22,7 @@ WORKDIR $HOME COPY pyproject.toml poetry.lock $HOME/ # Upgrade pip and install python packages for code -RUN pip install --upgrade --no-cache-dir pip poetry \ +RUN pip install --upgrade --no-cache-dir pip "poetry>=2.1,<2.2" \ && poetry --version \ # Configure to use system instead of virtualenvs && poetry config virtualenvs.create false \ From b0572d6e44647fb61c057d9974d8ec8971da7b4d Mon Sep 17 00:00:00 2001 From: thenav56 Date: Fri, 21 Feb 2025 16:49:09 +0545 Subject: [PATCH 17/17] Add missing static template tag --- api/templates/admin/base_site.html | 1 + 1 file changed, 1 insertion(+) diff --git a/api/templates/admin/base_site.html b/api/templates/admin/base_site.html index 2c4015dea..77fc2902b 100644 --- a/api/templates/admin/base_site.html +++ b/api/templates/admin/base_site.html @@ -1,6 +1,7 @@ {% extends "admin/base.html" %} {% load i18n %} +{% load static %} {% block title %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}