From 636f37eb126bcb505aba24b6a050c3f6add0d34d Mon Sep 17 00:00:00 2001 From: Matt Griswold Date: Tue, 14 Sep 2021 08:59:09 -0500 Subject: [PATCH] Support 202108 (#1051) * add OPERATIONS_EMAIL setting * fixes #1019: redundant saves to deleted netixlans during ix-f import * private pocs are no longer valid (#944) * poetry relock (handleref update) * fixes #1032: __id api filter not working * Additional self-selection fields for Facilities #800 * advanced search fields for available voltage, property and diverse serving substations (#1016) * When network sets netixlan speed to 1200000 only 1T is shown instead of 1.2T ... sometimes #500 * add search-data * comment out mount points for api-cache, search-data, django-peeringdb * poetry relock (django-peeringdb 2.9.0) * linting Co-authored-by: Stefan Pratter --- .dockerignore | 1 + Ctl/dev/docker-compose.yml | 2 + peeringdb_server/admin.py | 6 + peeringdb_server/data_views.py | 16 + .../management/commands/pdb_api_test.py | 85 +++- .../commands/pdb_ixf_ixp_member_import.py | 2 +- .../migrations/0073_manual_ixf_import.py | 2 +- .../migrations/0074_facility_fields.py | 141 ++++++ peeringdb_server/mock.py | 9 + peeringdb_server/models.py | 46 +- peeringdb_server/rest.py | 10 +- peeringdb_server/serializers.py | 65 ++- peeringdb_server/signals.py | 1 - peeringdb_server/static/20c/twentyc.edit.js | 16 +- peeringdb_server/static/peeringdb.js | 142 ++++++ peeringdb_server/static/site.css | 6 + .../templates/site/advanced-search-fac.html | 39 ++ peeringdb_server/templates/site/view.html | 7 + .../templates/site/view_network_bottom.html | 8 +- peeringdb_server/templatetags/util.py | 12 + peeringdb_server/validators.py | 14 + peeringdb_server/views.py | 30 +- poetry.lock | 470 ++++++++++-------- pyproject.toml | 4 +- tests/test_data_views.py | 1 + tests/test_ixf_member_import_protocol.py | 101 ++++ tests/test_settings.py | 2 +- tests/test_views.py | 1 + 28 files changed, 998 insertions(+), 241 deletions(-) create mode 100644 peeringdb_server/migrations/0074_facility_fields.py diff --git a/.dockerignore b/.dockerignore index c85c6351..062dc5fc 100644 --- a/.dockerignore +++ b/.dockerignore @@ -3,6 +3,7 @@ *.tar __pycache__ Ctl/dev/peeringdb_database/ +search-data venv venv37 *.sql diff --git a/Ctl/dev/docker-compose.yml b/Ctl/dev/docker-compose.yml index d0d3c9a5..2c8e67b6 100644 --- a/Ctl/dev/docker-compose.yml +++ b/Ctl/dev/docker-compose.yml @@ -47,6 +47,8 @@ services: - ../../mainsite:/srv/www.peeringdb.com/mainsite:Z - ../../tests:/srv/www.peeringdb.com/tests:Z # - ../../search-data:/srv/www.peeringdb.com/search-data +# - ../../api-cache:/srv/www.peeringdb.com/api-cache +# - ../../../django-peeringdb/src/django_peeringdb:/srv/www.peeringdb.com/venv/lib/python3.9/site-packages/django_peeringdb:Z volumes: peeringdb_database: diff --git a/peeringdb_server/admin.py b/peeringdb_server/admin.py index f0ad2a16..95e61d0e 100644 --- a/peeringdb_server/admin.py +++ b/peeringdb_server/admin.py @@ -1173,6 +1173,12 @@ class FacilityAdmin(ModelAdminWithVQCtrl, SoftDeleteAdmin): "tech_phone", "sales_email", "sales_phone", + "property", + "diverse_serving_substations", + # django-admin doesnt seem to support multichoicefield automatically + # admins can edit this through the user-facing UX for now + # TODO: revisit enabling this field in django admin if AC communicates the need + # "available_voltage_services", "notes", "geocode_status", "geocode_date", diff --git a/peeringdb_server/data_views.py b/peeringdb_server/data_views.py index d2553daa..52b81e61 100644 --- a/peeringdb_server/data_views.py +++ b/peeringdb_server/data_views.py @@ -58,10 +58,22 @@ const.TERMS_TYPES_ADVS[0] = ( const.ORG_GROUPS = (("member", "member"), ("admin", "admin")) const.POC_ROLES = sorted(const.POC_ROLES, key=lambda x: x[1]) +const.POC_VISIBILITY = [r for r in const.VISIBILITY if r[0] != "Private"] BOOL_CHOICE = ((False, _("No")), (True, _("Yes"))) const.BOOL_CHOICE_STR = (("False", _("No")), ("True", _("Yes"))) +BOOL_CHOICE_WITH_OPT_OUT = ( + (None, _("Not Disclosed")), + (False, _("No")), + (True, _("Yes")), +) +const.BOOL_CHOICE_WITH_OPT_OUT_STR = ( + ("", _("Not Disclosed")), + ("False", _("No")), + ("True", _("Yes")), +) + def countries_w_blank(request): """ @@ -148,11 +160,15 @@ def enum(request, name): "PROTOCOLS", "ORG_GROUPS", "BOOL_CHOICE_STR", + "BOOL_CHOICE_WITH_OPT_OUT_STR", "VISIBILITY", + "POC_VISIBILITY", "SERVICE_LEVEL_TYPES_TRUNC", "TERMS_TYPES_TRUNC", "SERVICE_LEVEL_TYPES_ADVS", "TERMS_TYPES_ADVS", + "PROPERTY", + "AVAILABLE_VOLTAGE", ]: raise Exception("Unknown enum") diff --git a/peeringdb_server/management/commands/pdb_api_test.py b/peeringdb_server/management/commands/pdb_api_test.py index 628ee047..b7dd11c1 100644 --- a/peeringdb_server/management/commands/pdb_api_test.py +++ b/peeringdb_server/management/commands/pdb_api_test.py @@ -290,6 +290,9 @@ class TestJSON(unittest.TestCase): "tech_phone": PHONE, "sales_email": EMAIL, "sales_phone": PHONE, + "diverse_serving_substations": True, + "available_voltage_services": ["48 VDC", "240 VAC"], + "property": "Owner", } data.update(**kwargs) return data @@ -342,7 +345,7 @@ class TestJSON(unittest.TestCase): data = { "net_id": 1, "role": "Technical", - "visible": "Private", + "visible": "Users", "name": "NOC", "phone": PHONE, "email": EMAIL, @@ -1076,6 +1079,10 @@ class TestJSON(unittest.TestCase): data = self.db_guest.all("poc", limit=1000) for row in data: self.assertIn(row.get("visible"), ["Users", "Public"]) + + # next assert should remain as long as there are private pocs left + # in the database, once all private pocs have been changed/removed + # this test can be remove as well (#944) data = self.db_guest.all("poc", visible="Private", limit=100) self.assertEqual(0, len(data)) @@ -1395,6 +1402,35 @@ class TestJSON(unittest.TestCase): ########################################################################## + def test_org_admin_002_POST_PUT_fac_available_voltage(self): + + data = self.make_data_fac() + + r_data = self.assert_create( + self.db_org_admin, + "fac", + data, + test_failures={ + "invalid": [ + {"available_voltage_services": ["Invalid"]}, + ], + }, + ) + + SHARED["fac_id"] = r_data.get("id") + + self.assert_update( + self.db_org_admin, + "fac", + SHARED["fac_id"], + {"available_voltage_services": ["480 VAC"]}, + test_failures={ + "invalid": {"available_voltage_services": ["Invalid"]}, + }, + ) + + ########################################################################## + def test_org_admin_002_POST_PUT_DELETE_fac_zipcode(self): data = self.make_data_fac() @@ -1656,7 +1692,7 @@ class TestJSON(unittest.TestCase): SHARED["poc_id"], {"role": "Sales"}, test_failures={ - "invalid": {"role": "NOPE"}, + "invalid": {"role": "INVALID"}, "perms": {"net_id": SHARED["net_r_ok"].id}, }, ) @@ -1677,6 +1713,28 @@ class TestJSON(unittest.TestCase): assert poc["email"] == "" assert poc["url"] == "" + # pocs can no longer be made private (#944) + + self.assert_update( + self.db_org_admin, + "poc", + SHARED["poc_rw_ok_users"].id, + {}, + test_success=False, + test_failures={ + "invalid": {"visible": "Private"}, + }, + ) + r_data = self.assert_create( + self.db_org_admin, + "poc", + {}, + test_success=False, + test_failures={ + "invalid": {"visible": "Private"}, + }, + ) + ########################################################################## def test_org_admin_002_POST_PUT_DELETE_ixlan(self): @@ -2453,12 +2511,29 @@ class TestJSON(unittest.TestCase): for row in data: self.assertEqual(row.get("net_id"), SHARED["net_r_ok"].id) + # also test __id filter (bug issue #1032) + + data = self.db_user.all("poc", net__id=SHARED["net_r_ok"].id) + self.assertEqual(len(data), 2) + + for row in data: + self.assertEqual(row.get("net_id"), SHARED["net_r_ok"].id) + + # also test __id__in filter (bug issue #1032) + + data = self.db_user.all("poc", net__id__in=SHARED["net_r_ok"].id) + self.assertEqual(len(data), 2) + + for row in data: + self.assertEqual(row.get("net_id"), SHARED["net_r_ok"].id) + ########################################################################## def test_guest_005_list_poc(self): data = self.db_guest.all("poc", limit=100) for row in data: self.assertEqual(row.get("visible"), "Public") + data = self.db_guest.all("poc", visible__in="Private,Users", limit=100) self.assertEqual(0, len(data)) @@ -4482,9 +4557,13 @@ class Command(BaseCommand): visibility = { "rw": "Public", "rw2": "Users", + # TODO: "Private" can be removed once all private pocs are + # cleared out of production database "rw3": "Private", "r": "Public", "r2": "Users", + # TODO: "Private" can be removed once all private pocs are + # cleared out of production database "r3": "Private", } @@ -4539,6 +4618,8 @@ class Command(BaseCommand): network_id=SHARED[f"net_{prefix}_{status}"].id, ) + # TODO: private can be removed once all private pocs have been + # cleared out of production database for v in ["Private", "Users", "Public"]: cls.create_entity( NetworkContact, diff --git a/peeringdb_server/management/commands/pdb_ixf_ixp_member_import.py b/peeringdb_server/management/commands/pdb_ixf_ixp_member_import.py index 844d6dcd..2f414fca 100644 --- a/peeringdb_server/management/commands/pdb_ixf_ixp_member_import.py +++ b/peeringdb_server/management/commands/pdb_ixf_ixp_member_import.py @@ -9,10 +9,10 @@ from django.db import transaction from peeringdb_server import ixf from peeringdb_server.models import ( DeskProTicket, + InternetExchange, IXFImportEmail, IXFMemberData, IXLan, - InternetExchange, Network, ) diff --git a/peeringdb_server/migrations/0073_manual_ixf_import.py b/peeringdb_server/migrations/0073_manual_ixf_import.py index 1e9ae53e..d76b86ae 100644 --- a/peeringdb_server/migrations/0073_manual_ixf_import.py +++ b/peeringdb_server/migrations/0073_manual_ixf_import.py @@ -1,8 +1,8 @@ # Generated by Django 3.2.5 on 2021-07-30 08:57 +import django.db.models.deletion from django.conf import settings from django.db import migrations, models -import django.db.models.deletion class Migration(migrations.Migration): diff --git a/peeringdb_server/migrations/0074_facility_fields.py b/peeringdb_server/migrations/0074_facility_fields.py new file mode 100644 index 00000000..929c99f3 --- /dev/null +++ b/peeringdb_server/migrations/0074_facility_fields.py @@ -0,0 +1,141 @@ +# Generated by Django 3.2.7 on 2021-09-07 10:42 + +import django.core.validators +import django_inet.models +import django_peeringdb.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("peeringdb_server", "0073_manual_ixf_import"), + ] + + operations = [ + migrations.AddField( + model_name="facility", + name="available_voltage_services", + field=django_peeringdb.fields.MultipleChoiceField( + blank=True, + choices=[ + ("48 VDC", "48 VDC"), + ("120 VAC", "120 VAC"), + ("208 VAC", "208 VAC"), + ("240 VAC", "240 VAC"), + ("480 VAC", "480 VAC"), + ], + help_text="The alternating current voltage available to users of the facility either directly from the landlord or delivered by the utility separately.", + max_length=255, + null=True, + verbose_name="Available Voltage Services", + ), + ), + migrations.AddField( + model_name="facility", + name="diverse_serving_substations", + field=models.BooleanField( + blank=True, + help_text="Two separate and distinct paths to individual substations which should maintain a separated path back to one or more utility generator stations.", + null=True, + verbose_name="Diverse Serving Substations", + ), + ), + migrations.AddField( + model_name="facility", + name="property", + field=models.CharField( + blank=True, + choices=[ + ("", "Not Disclosed"), + ("Owner", "Owner"), + ("Lessee", "Lessee"), + ], + help_text="A property owner is the individual or entity that has title to the property. A lessee is a user of a property who has a lease, an agreement, with the owner of the property.", + max_length=27, + null=True, + verbose_name="Property", + ), + ), + migrations.AlterField( + model_name="ixfmemberdata", + name="asn", + field=django_inet.models.ASNField( + validators=[ + django.core.validators.MinValueValidator(0), + django.core.validators.MinValueValidator(0), + django.core.validators.MinValueValidator(0), + ], + verbose_name="ASN", + ), + ), + migrations.AlterField( + model_name="ixlan", + name="rs_asn", + field=django_inet.models.ASNField( + blank=True, + default=0, + null=True, + validators=[ + django.core.validators.MinValueValidator(0), + django.core.validators.MinValueValidator(0), + django.core.validators.MinValueValidator(0), + ], + verbose_name="Route Server ASN", + ), + ), + migrations.AlterField( + model_name="network", + name="asn", + field=django_inet.models.ASNField( + unique=True, + validators=[ + django.core.validators.MinValueValidator(0), + django.core.validators.MinValueValidator(0), + django.core.validators.MinValueValidator(0), + ], + verbose_name="ASN", + ), + ), + migrations.AlterField( + model_name="networkfacility", + name="local_asn", + field=django_inet.models.ASNField( + blank=True, + null=True, + validators=[ + django.core.validators.MinValueValidator(0), + django.core.validators.MinValueValidator(0), + django.core.validators.MinValueValidator(0), + ], + verbose_name="Local ASN", + ), + ), + migrations.AlterField( + model_name="networkixlan", + name="asn", + field=django_inet.models.ASNField( + validators=[ + django.core.validators.MinValueValidator(0), + django.core.validators.MinValueValidator(0), + django.core.validators.MinValueValidator(0), + django.core.validators.MinValueValidator(0), + ], + verbose_name="ASN", + ), + ), + migrations.AlterField( + model_name="userorgaffiliationrequest", + name="asn", + field=django_inet.models.ASNField( + blank=True, + help_text="The ASN entered by the user", + null=True, + validators=[ + django.core.validators.MinValueValidator(0), + django.core.validators.MinValueValidator(0), + django.core.validators.MinValueValidator(0), + ], + ), + ), + ] diff --git a/peeringdb_server/mock.py b/peeringdb_server/mock.py index 546f422e..aba5d40a 100644 --- a/peeringdb_server/mock.py +++ b/peeringdb_server/mock.py @@ -302,3 +302,12 @@ class Mock: def role(self, data, reftag=None): return "Abuse" + + def diverse_serving_substations(self, data, reftag=None): + return False + + def available_voltage_services(self, data, reftag=None): + return None + + def property(self, data, reftag=None): + return None diff --git a/peeringdb_server/models.py b/peeringdb_server/models.py index 6e3920ae..a6a19c30 100644 --- a/peeringdb_server/models.py +++ b/peeringdb_server/models.py @@ -46,6 +46,7 @@ from peeringdb_server.validators import ( validate_info_prefixes6, validate_irr_as_set, validate_phonenumber, + validate_poc_visible, validate_prefix_overlap, ) @@ -2488,14 +2489,17 @@ class IXLan(pdb_models.IXLanBase): # we need to check if this ipaddress exists on a # soft-deleted netixlan elsewhere, and # reset if so. + # + # we only do this if ipaddr4 is not null - for other in NetworkIXLan.objects.filter( - ipaddr4=ipv4, status="deleted" - ).exclude(asn=asn): - other.ipaddr4 = None - other.notes = f"Ip address {ipv4} was claimed by other netixlan" - if save or save_others: - other.save() + if ipv4: + for other in NetworkIXLan.objects.filter( + ipaddr4=ipv4, status="deleted" + ).exclude(asn=asn): + other.ipaddr4 = None + other.notes = f"Ip address {ipv4} was claimed by other netixlan" + if save or save_others: + other.save() netixlan.ipaddr4 = ipv4 changed.append("ipaddr4") @@ -2506,14 +2510,18 @@ class IXLan(pdb_models.IXLanBase): # we need to check if this ipaddress exists on a # soft-deleted netixlan elsewhere, and # reset if so. + # + # we only do this if ipaddr6 is not None - for other in NetworkIXLan.objects.filter( - ipaddr6=ipv6, status="deleted" - ).exclude(asn=asn): - other.ipaddr6 = None - other.notes = f"Ip address {ipv6} was claimed by other netixlan" - if save or save_others: - other.save() + if ipv6: + + for other in NetworkIXLan.objects.filter( + ipaddr6=ipv6, status="deleted" + ).exclude(asn=asn): + other.ipaddr6 = None + other.notes = f"Ip address {ipv6} was claimed by other netixlan" + if save or save_others: + other.save() netixlan.ipaddr6 = ipv6 changed.append("ipaddr6") @@ -4335,6 +4343,7 @@ class NetworkContact(ProtectedMixin, pdb_models.ContactBase): def clean(self): self.phone = validate_phonenumber(self.phone) + self.visible = validate_poc_visible(self.visible) @grainy_model(namespace="netfac", parent="network") @@ -4428,11 +4437,14 @@ class NetworkFacility(pdb_models.NetworkFacilityBase): def format_speed(value): if value >= 1000000: - return "%dT" % (value / 10 ** 6) + value = value / 10 ** 6 + if not value % 1: + return f"{value:.0f}T" + return f"{value:.1f}T" elif value >= 1000: - return "%dG" % (value / 10 ** 3) + return f"{value / 10 ** 3:.0f}G" else: - return "%dM" % value + return f"{value:.0f}M" @grainy_model(namespace="ixlan", parent="network") diff --git a/peeringdb_server/rest.py b/peeringdb_server/rest.py index 88c45435..efd5e289 100644 --- a/peeringdb_server/rest.py +++ b/peeringdb_server/rest.py @@ -16,7 +16,8 @@ from django.utils.translation import ugettext_lazy as _ from django_grainy.rest import PermissionDenied from rest_framework import routers, status, viewsets from rest_framework.decorators import action -from rest_framework.exceptions import ParseError, ValidationError as RestValidationError +from rest_framework.exceptions import ParseError +from rest_framework.exceptions import ValidationError as RestValidationError from rest_framework.response import Response from rest_framework.views import exception_handler @@ -30,10 +31,10 @@ from peeringdb_server.permissions import ( get_org_key_from_request, get_user_key_from_request, ) +from peeringdb_server.rest_throttles import IXFImportThrottle from peeringdb_server.search import make_name_search_query from peeringdb_server.serializers import ParentStatusException from peeringdb_server.util import coerce_ipaddr -from peeringdb_server.rest_throttles import IXFImportThrottle class DataException(ValueError): @@ -367,7 +368,8 @@ class ModelViewSet(viewsets.ModelViewSet): if k == "ipaddr6": v = coerce_ipaddr(v) - if k[-3:] == "_id" and k not in field_names: + if re.match("^.+[^_]_id$", k) and k not in field_names: + # if k[-3:] == "_id" and k not in field_names: k = k[:-3] xl = self.serializer_class.queryable_field_xl @@ -384,7 +386,7 @@ class ModelViewSet(viewsets.ModelViewSet): if m: flt = xl(m.group(1)) k = k.replace(m.group(1), flt, 1) - if flt[-3:] == "_id" and flt not in field_names: + if re.match("^.+[^_]_id$", flt) and flt not in field_names: flt = flt[:-3] else: k = xl(k) diff --git a/peeringdb_server/serializers.py b/peeringdb_server/serializers.py index e10dc628..8ae89b7c 100644 --- a/peeringdb_server/serializers.py +++ b/peeringdb_server/serializers.py @@ -18,6 +18,7 @@ from django_grainy.rest import PermissionDenied # from drf_toolbox import serializers from django_handleref.rest.serializers import HandleRefSerializer from django_inet.rest import IPAddressField, IPNetworkField +from django_peeringdb.const import AVAILABLE_VOLTAGE from django_peeringdb.models.abstract import AddressModel from rest_framework import serializers, validators from rest_framework.exceptions import ValidationError as RestValidationError @@ -59,6 +60,7 @@ from peeringdb_server.validators import ( validate_info_prefixes6, validate_irr_as_set, validate_phonenumber, + validate_poc_visible, validate_prefix_overlap, validate_zipcode, ) @@ -281,20 +283,43 @@ def queryable_field_xl(fld): care of translating fac and net queries into "facility" and "network" queries - FIXME: should be renamed on models, but this will open - a pandora's box im not ready to open yet + FIXME: should be renamed on model schema """ - if re.match(".+_id", fld): + if re.match("^.+[^_]_id$", fld): + + # if field name is {rel}_id strip the `_id` suffix + fld = fld[:-3] + if fld == "fac": + + # if field name is `fac` rename to `facility` + # since the model relationship field is called `facility` + return "facility" + elif fld == "net": + + # if field name is `net` rename to `network` + # since the model relationship field is called `network` + return "network" + elif re.match("net_(.+)", fld): + + # if field name starts with `net_` rename to `network_` + # since the model relationship field is called `network` + return re.sub("^net_", "network_", fld) - elif re.match("fac(.+)", fld): + + elif re.match("fac_(.+)", fld): + + # if field name starts with `fac_` rename to `facility_` + # since the model relationship field is called `facility` + return re.sub("^fac_", "facility_", fld) + return fld @@ -1410,6 +1435,10 @@ class FacilitySerializer(SpatialSearchMixin, GeocodeSerializerMixin, ModelSerial latitude = serializers.FloatField(read_only=True) longitude = serializers.FloatField(read_only=True) + available_voltage_services = serializers.MultipleChoiceField( + choices=AVAILABLE_VOLTAGE, required=False, allow_null=True + ) + def validate_create(self, data): # we don't want users to be able to create facilities if the parent # organization status is pending or deleted @@ -1441,6 +1470,9 @@ class FacilitySerializer(SpatialSearchMixin, GeocodeSerializerMixin, ModelSerial "sales_phone", "tech_email", "tech_phone", + "available_voltage_services", + "diverse_serving_substations", + "property", ] + HandleRefSerializer.Meta.fields + AddressSerializer.Meta.fields @@ -1574,6 +1606,28 @@ class FacilitySerializer(SpatialSearchMixin, GeocodeSerializerMixin, ModelSerial return super().to_internal_value(data) + def to_representation(self, instance): + + representation = super().to_representation(instance) + + if not isinstance(representation, dict): + return representation + + # django-rest-framework multiplechoicefield maintains + # a set of values and thus looses sorting. + # + # we always want to return values sorted by choice + # definition order + if instance.available_voltage_services: + avs = [] + for choice, label in AVAILABLE_VOLTAGE: + if choice in instance.available_voltage_services: + avs.append(choice) + + representation["available_voltage_services"] = avs + + return representation + def get_org(self, inst): return self.sub_serializer(OrganizationSerializer, inst.org) @@ -1745,6 +1799,9 @@ class NetworkContactSerializer(ModelSerializer): def validate_phone(self, value): return validate_phonenumber(value) + def validate_visible(self, value): + return validate_poc_visible(value) + def to_representation(self, data): # When a network contact is marked as deleted we # want to return blank values for any sensitive diff --git a/peeringdb_server/signals.py b/peeringdb_server/signals.py index b24554f7..1fcffd20 100644 --- a/peeringdb_server/signals.py +++ b/peeringdb_server/signals.py @@ -34,7 +34,6 @@ from peeringdb_server.models import ( UserOrgAffiliationRequest, VerificationQueueItem, ) - from peeringdb_server.util import disable_auto_now_and_save diff --git a/peeringdb_server/static/20c/twentyc.edit.js b/peeringdb_server/static/20c/twentyc.edit.js index 97c838e3..cc8a5a61 100644 --- a/peeringdb_server/static/20c/twentyc.edit.js +++ b/peeringdb_server/static/20c/twentyc.edit.js @@ -1042,7 +1042,12 @@ twentyc.editable.input.register( }, value_to_label : function() { - return this.element.children('option:selected').text(); + return $.map( + this.element.children('option:selected'), + function(element) { + return $(element).text() + } + ).join(', ') }, apply : function(value) { @@ -1062,18 +1067,27 @@ twentyc.editable.input.register( if(id == value) opt.prop("selected", true); } + this.finalize_opt(opt) this.element.append(opt); }, + finalize_opt : function(opt) { + return opt; + }, + load : function(data) { var k, v; this.element.empty(); if(this.source.data("edit-data-all-entry")) { var allEntry = this.source.data("edit-data-all-entry").split(":") this.add_opt(allEntry[0], allEntry[1]); + } else { + var allEntry = null; } for(k in data) { v = data[k]; + if(allEntry && allEntry[0] == v.id) + continue this.add_opt(v.id, v.name); } this.element.trigger("change"); diff --git a/peeringdb_server/static/peeringdb.js b/peeringdb_server/static/peeringdb.js index d54e51aa..5e78d5bc 100644 --- a/peeringdb_server/static/peeringdb.js +++ b/peeringdb_server/static/peeringdb.js @@ -2850,6 +2850,144 @@ twentyc.editable.input.register( "unit_input" ); +/** + * a select input that forces to user to change + * its value if specific conditions are met. + * + * @class data_quality_select + */ + +twentyc.editable.input.register( + "data_quality_select", + { + + /** + * returns an array of values that are deemed bad + * and should force the user to make a change + * + * this is specified in the data-edit-bad-values + * html attribute + * + * @method bad_values + * @returns {Array|null} + */ + + bad_values : function() { + let bad_values = this.source.data("edit-bad-values"); + if(bad_values) + return bad_values.split(";"); + return null; + }, + + /** + * Checks if the specified value is a bad value + * If no value is specified the current element + * input value is used. + * + * @method has_bad_value + * @param {String} value + * @returns {Bool} + */ + + has_bad_value : function(value) { + + let bad_values = this.bad_values(); + + if(typeof(value) == "undefined") { + value = this.get(); + } + + if(bad_values) { + let i, bad_value; + for(i = 0; i < bad_values.length; i++) { + bad_value = bad_values[i] + if(value == bad_value) { + this.element.addClass("invalid-choice"); + return true; + } + } + } + + this.element.removeClass("invalid-choice"); + return false; + }, + + /** + * We override the change method to always + * return true if the current value is a bad value + * + * This forces the user to change it before the + * save can be made. + */ + + changed : function() { + if(this.has_bad_value()) + return true; + return this.select_changed() + }, + + /** + * When adding options to the select element we + * check each option to see if it contains a bad + * value and if it does, mark it as such + */ + + finalize_opt : function(opt) { + if(this.has_bad_value(opt.val())) { + opt.addClass("invalid-choice"); + } + return opt; + }, + + /** + * For inputs that have a good value, we don't want + * the option for a bad value to still exist in the dropdown + * + * We override load to check this and remove the options + * if necessary. + * + * Inputs that have a bad value still need the bad value option + * available in order to communicate to the user the the value + * is bad and needs changing + */ + + load : function(data) { + let k, bad_values = this.source.data("edit-bad-values"); + let value = this.source.data("edit-value") + if(!this.has_bad_value(value) && bad_values) { + bad_values = bad_values.split(";") + let _data = []; + for(k in data) { + if($.inArray(data[k].id, bad_values) == -1) + _data.push(data[k]) + } + data = _data; + } + + + this.select_load(data); + }, + + /** + * We wire a change event so that when a bad value is + * changed to a good value by the user, the error + * css is removed from the element (done through the + * has_bad_value() method) + */ + + wire : function() { + this.has_bad_value(); + this.element.on("change", () => { + this.has_bad_value(this.element.val()); + }) + } + + + }, + + "select" +); + /* * set up input templates @@ -2946,15 +3084,19 @@ twentyc.data.loaders.assign("enum/scopes_trunc", "data"); twentyc.data.loaders.assign("enum/scopes_advs", "data"); twentyc.data.loaders.assign("enum/protocols", "data"); twentyc.data.loaders.assign("enum/poc_roles", "data"); +twentyc.data.loaders.assign("enum/poc_visibility", "data"); twentyc.data.loaders.assign("enum/policy_general", "data"); twentyc.data.loaders.assign("enum/policy_locations", "data"); twentyc.data.loaders.assign("enum/policy_contracts", "data"); twentyc.data.loaders.assign("enum/visibility", "data"); twentyc.data.loaders.assign("enum/bool_choice_str", "data"); +twentyc.data.loaders.assign("enum/bool_choice_with_opt_out_str", "data"); twentyc.data.loaders.assign("enum/service_level_types_trunc", "data"); twentyc.data.loaders.assign("enum/service_level_types_advs", "data"); twentyc.data.loaders.assign("enum/terms_types_trunc", "data"); twentyc.data.loaders.assign("enum/terms_types_advs", "data"); +twentyc.data.loaders.assign("enum/property", "data"); +twentyc.data.loaders.assign("enum/available_voltage", "data"); $(twentyc.data).on("load-enum/traffic", function(e, payload) { var r = {}, i = 0, data=payload.data; diff --git a/peeringdb_server/static/site.css b/peeringdb_server/static/site.css index 69f8edff..02abd32b 100644 --- a/peeringdb_server/static/site.css +++ b/peeringdb_server/static/site.css @@ -986,6 +986,12 @@ div.editable.mode-edit div.view_field { border-color: #9e1e1e; } + +.editable select.invalid-choice, +.editable select option.invalid-choice { + color: #9e1e1e !important; +} + .input-note.validation-error + div[data-field] { border: #9e1e1e 1px solid; border-radius: 5px; diff --git a/peeringdb_server/templates/site/advanced-search-fac.html b/peeringdb_server/templates/site/advanced-search-fac.html index 43d89a0c..3ed0aed2 100644 --- a/peeringdb_server/templates/site/advanced-search-fac.html +++ b/peeringdb_server/templates/site/advanced-search-fac.html @@ -52,6 +52,45 @@ +
+
{% trans "Property" %}
+
+
+
+
+ + +
+
{% trans "Diverse Serving Substations" %}
+
+
+
+
+ +
+
{% trans "Available Voltage Services" %}
+
+
+
+
+ + + {% include "site/advanced-search-net-present.html" %} {% include "site/advanced-search-org-present.html" %} diff --git a/peeringdb_server/templates/site/view.html b/peeringdb_server/templates/site/view.html index 4807dd90..6f76b9b2 100644 --- a/peeringdb_server/templates/site/view.html +++ b/peeringdb_server/templates/site/view.html @@ -162,10 +162,17 @@
{{ row|editable_list_value }}
+ {% else %} data-edit-value="{{ row.value }}">{{ row|editable_list_value }} + {% endif %} {% elif row.type == "flags" %}
diff --git a/peeringdb_server/templates/site/view_network_bottom.html b/peeringdb_server/templates/site/view_network_bottom.html index 86b8e24a..78737677 100644 --- a/peeringdb_server/templates/site/view_network_bottom.html +++ b/peeringdb_server/templates/site/view_network_bottom.html @@ -89,8 +89,12 @@ data-edit-name="name"> {{ p.name }}
+ + +
{% trans "Visibility" %}
diff --git a/peeringdb_server/templatetags/util.py b/peeringdb_server/templatetags/util.py index 4b2fde31..00c7a799 100644 --- a/peeringdb_server/templatetags/util.py +++ b/peeringdb_server/templatetags/util.py @@ -27,8 +27,20 @@ countries_dict = dict(countries) register = template.Library() +@register.filter +def editable_list_join(value): + if not value: + return "" + return ",".join(value) + + @register.filter def editable_list_value(row): + if row.get("multiple"): + if row.get("value"): + return ", ".join(row.get("value")) + return "" + if row.get("value") or row.get("value_label"): return _(row.get("value_label", row.get("value"))) elif row.get("blank") and row.get("value") == "": diff --git a/peeringdb_server/validators.py b/peeringdb_server/validators.py index a1b4ae95..29553ace 100644 --- a/peeringdb_server/validators.py +++ b/peeringdb_server/validators.py @@ -14,6 +14,20 @@ from peeringdb_server.inet import IRR_SOURCE, network_is_pdb_valid from peeringdb_server.request import bypass_validation +def validate_poc_visible(visible): + + # we no longer allow "Private" network contacts + # however until all private network contacts have + # been either changed or deleted we cannot remove + # the value from the choices set for the field + # + # for now we handle validation here (see #944) + + if visible == "Private": + raise ValidationError(_("Private contacts are no longer supported.")) + return visible + + def validate_phonenumber(phonenumber, country=None): """ Validate a phonenumber to E.164 diff --git a/peeringdb_server/views.py b/peeringdb_server/views.py index 054d6b87..95dbdbfd 100644 --- a/peeringdb_server/views.py +++ b/peeringdb_server/views.py @@ -36,7 +36,7 @@ from ratelimit.decorators import ratelimit from peeringdb_server import settings from peeringdb_server.api_key_views import load_all_key_permissions -from peeringdb_server.data_views import BOOL_CHOICE +from peeringdb_server.data_views import BOOL_CHOICE, BOOL_CHOICE_WITH_OPT_OUT from peeringdb_server.deskpro import ticket_queue_rdap_error from peeringdb_server.forms import ( AffiliateToOrgForm, @@ -1276,6 +1276,34 @@ def view_facility(request, id): "value": data.get("sales_phone", dismiss), "help_text": field_help(Facility, "sales_phone"), }, + { + "name": "property", + "type": "list", + "data": "enum/property", + "label": _("Property"), + "value": data.get("property", dismiss), + "help_text": field_help(Facility, "property"), + }, + { + "name": "diverse_serving_substations", + "type": "list", + "data": "enum/bool_choice_with_opt_out_str", + "label": _("Diverse Serving Substations"), + "value": data.get("diverse_serving_substations", dismiss), + "value_label": dict(BOOL_CHOICE_WITH_OPT_OUT).get( + data.get("diverse_serving_substations") + ), + "help_text": field_help(Facility, "diverse_serving_substations"), + }, + { + "name": "available_voltage_services", + "type": "list", + "multiple": True, + "data": "enum/available_voltage", + "label": _("Available Voltage Services"), + "value": data.get("available_voltage_services", dismiss), + "help_text": field_help(Facility, "available_voltage_services"), + }, ], } diff --git a/poetry.lock b/poetry.lock index d4757635..342ceddb 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,11 +1,3 @@ -[[package]] -name = "appdirs" -version = "1.4.4" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" -optional = false -python-versions = "*" - [[package]] name = "asgiref" version = "3.4.1" @@ -69,29 +61,34 @@ typecheck = ["mypy"] [[package]] name = "black" -version = "21.7b0" +version = "21.9b0" description = "The uncompromising code formatter." category = "dev" optional = false python-versions = ">=3.6.2" [package.dependencies] -appdirs = "*" click = ">=7.1.2" mypy-extensions = ">=0.4.3" -pathspec = ">=0.8.1,<1" +pathspec = ">=0.9.0,<1" +platformdirs = ">=2" regex = ">=2020.1.8" tomli = ">=0.2.6,<2.0.0" +typing-extensions = [ + {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}, + {version = "!=3.10.0.1", markers = "python_version >= \"3.10\""}, +] [package.extras] colorama = ["colorama (>=0.4.3)"] d = ["aiohttp (>=3.6.0)", "aiohttp-cors (>=0.4.0)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] python2 = ["typed-ast (>=1.4.2)"] uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "bleach" -version = "4.0.0" +version = "4.1.0" description = "An easy safelist-based HTML-sanitizing tool." category = "main" optional = false @@ -123,7 +120,7 @@ pycparser = "*" [[package]] name = "cfgv" -version = "3.3.0" +version = "3.3.1" description = "Validate configuration and produce human readable error messages." category = "dev" optional = false @@ -208,7 +205,7 @@ toml = ["toml"] [[package]] name = "cryptography" -version = "3.4.7" +version = "3.4.8" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." category = "main" optional = false @@ -243,7 +240,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "deprecated" -version = "1.2.12" +version = "1.2.13" description = "Python @deprecated decorator to deprecate old python classes, functions or methods." category = "main" optional = false @@ -273,7 +270,7 @@ python-versions = "*" [[package]] name = "django" -version = "3.2.6" +version = "3.2.7" description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design." category = "main" optional = false @@ -428,7 +425,7 @@ python-versions = "*" [[package]] name = "django-handleref" -version = "1.0.0" +version = "1.0.1" description = "django object tracking" category = "main" optional = false @@ -448,7 +445,7 @@ passlib = ">=1.6.5" [[package]] name = "django-haystack" -version = "3.0" +version = "3.1.1" description = "Pluggable search for Django." category = "main" optional = false @@ -457,6 +454,9 @@ python-versions = "*" [package.dependencies] Django = ">=2.2" +[package.extras] +elasticsearch = ["elasticsearch (>=5,<6)"] + [[package]] name = "django-inet" version = "1.0.1" @@ -482,7 +482,7 @@ six = "*" [[package]] name = "django-otp" -version = "1.0.6" +version = "1.1.0" description = "A pluggable framework for adding two-factor authentication to Django using one-time passwords." category = "main" optional = false @@ -496,7 +496,7 @@ qrcode = ["qrcode"] [[package]] name = "django-peeringdb" -version = "2.8.0" +version = "2.9.0" description = "PeeringDB Django models" category = "main" optional = false @@ -648,7 +648,7 @@ python-versions = ">=3.6" [[package]] name = "docker" -version = "5.0.0" +version = "5.0.2" description = "A Python library for the Docker Engine API." category = "dev" optional = false @@ -758,7 +758,7 @@ python-versions = ">=3.6,<4.0" [[package]] name = "identify" -version = "2.2.13" +version = "2.2.14" description = "File identification library for Python" category = "dev" optional = false @@ -877,14 +877,14 @@ python-versions = "*" [[package]] name = "munge" -version = "1.2.0" +version = "1.2.1" description = "data manipulation library and client" category = "main" optional = false python-versions = ">=3.6,<4.0" [package.dependencies] -click = ">=8.0.1,<9.0.0" +click = ">=5.1" requests = ">=2.6,<3.0" [package.extras] @@ -1008,7 +1008,7 @@ PyYAML = ">=3.11" [[package]] name = "phonenumbers" -version = "8.12.30" +version = "8.12.32" description = "Python version of Google's common library for parsing, formatting, storing and validating international phone numbers." category = "main" optional = false @@ -1016,7 +1016,7 @@ python-versions = "*" [[package]] name = "pillow" -version = "8.3.1" +version = "8.3.2" description = "Python Imaging Library (Fork)" category = "main" optional = false @@ -1024,7 +1024,7 @@ python-versions = ">=3.6" [[package]] name = "platformdirs" -version = "2.2.0" +version = "2.3.0" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false @@ -1036,18 +1036,19 @@ test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock [[package]] name = "pluggy" -version = "0.13.1" +version = "1.0.0" description = "plugin and hook calling mechanisms for python" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.6" [package.extras] dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "2.14.0" +version = "2.15.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." category = "dev" optional = false @@ -1144,7 +1145,7 @@ python-versions = ">=3.6" [[package]] name = "pytest" -version = "6.2.4" +version = "6.2.5" description = "pytest: simple powerful testing with Python" category = "dev" optional = false @@ -1156,7 +1157,7 @@ attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} iniconfig = "*" packaging = "*" -pluggy = ">=0.12,<1.0.0a1" +pluggy = ">=0.12,<2.0" py = ">=1.8.2" toml = "*" @@ -1257,7 +1258,7 @@ python-versions = "*" [[package]] name = "pyupgrade" -version = "2.23.3" +version = "2.26.0" description = "A tool to automatically upgrade syntax for newer versions." category = "dev" optional = false @@ -1313,7 +1314,7 @@ munge = ">=1.0.0,<2.0.0" [[package]] name = "regex" -version = "2021.8.3" +version = "2021.8.28" description = "Alternative regular expression module, to replace re." category = "dev" optional = false @@ -1370,7 +1371,7 @@ rsa = ["oauthlib[signedtoken] (>=3.0.0)"] [[package]] name = "simplejson" -version = "3.17.3" +version = "3.17.5" description = "Simple, fast, extensible JSON encoder/decoder for Python" category = "main" optional = false @@ -1386,7 +1387,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "sqlparse" -version = "0.4.1" +version = "0.4.2" description = "A non-validating SQL parser." category = "main" optional = false @@ -1444,13 +1445,21 @@ python-versions = "*" requests = ">=2.10.0" six = ">=1.10,<2.0" +[[package]] +name = "typing-extensions" +version = "3.10.0.2" +description = "Backported and Experimental Type Hints for Python 3.5+" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "unidecode" -version = "1.2.0" +version = "1.3.1" description = "ASCII transliterations of Unicode text" category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.5" [[package]] name = "uritemplate" @@ -1538,13 +1547,9 @@ python-versions = "*" [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "ea974a9c93598d9222fd9bd19fd380e20e0ea94ff07d1388ae55742761d3cefe" +content-hash = "6d90ec9197ca0533ff6617552aed8eef002335f4995350f33c738809ce7a1c23" [metadata.files] -appdirs = [ - {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, - {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, -] asgiref = [ {file = "asgiref-3.4.1-py3-none-any.whl", hash = "sha256:ffc141aa908e6f175673e7b1b3b7af4fdb0ecb738fc5c8b88f69f055c2415214"}, {file = "asgiref-3.4.1.tar.gz", hash = "sha256:4ef1ab46b484e3c706329cedeff284a5d40824200638503f5768edb6de7d58e9"}, @@ -1571,12 +1576,12 @@ bcrypt = [ {file = "bcrypt-3.2.0.tar.gz", hash = "sha256:5b93c1726e50a93a033c36e5ca7fdcd29a5c7395af50a6892f5d9e7c6cfbfb29"}, ] black = [ - {file = "black-21.7b0-py3-none-any.whl", hash = "sha256:1c7aa6ada8ee864db745b22790a32f94b2795c253a75d6d9b5e439ff10d23116"}, - {file = "black-21.7b0.tar.gz", hash = "sha256:c8373c6491de9362e39271630b65b964607bc5c79c83783547d76c839b3aa219"}, + {file = "black-21.9b0-py3-none-any.whl", hash = "sha256:380f1b5da05e5a1429225676655dddb96f5ae8c75bdf91e53d798871b902a115"}, + {file = "black-21.9b0.tar.gz", hash = "sha256:7de4cfc7eb6b710de325712d40125689101d21d25283eed7e9998722cf10eb91"}, ] bleach = [ - {file = "bleach-4.0.0-py2.py3-none-any.whl", hash = "sha256:c1685a132e6a9a38bf93752e5faab33a9517a6c0bb2f37b785e47bf253bdb51d"}, - {file = "bleach-4.0.0.tar.gz", hash = "sha256:ffa9221c6ac29399cc50fcc33473366edd0cf8d5e2cbbbb63296dc327fb67cc8"}, + {file = "bleach-4.1.0-py2.py3-none-any.whl", hash = "sha256:4d2651ab93271d1129ac9cbc679f524565cc8a1b791909c4a51eac4446a15994"}, + {file = "bleach-4.1.0.tar.gz", hash = "sha256:0900d8b37eba61a802ee40ac0061f8c2b5dee29c1927dd1d233e075ebf5a71da"}, ] certifi = [ {file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"}, @@ -1590,6 +1595,11 @@ cffi = [ {file = "cffi-1.14.6-cp27-cp27m-win_amd64.whl", hash = "sha256:7bcac9a2b4fdbed2c16fa5681356d7121ecabf041f18d97ed5b8e0dd38a80224"}, {file = "cffi-1.14.6-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ed38b924ce794e505647f7c331b22a693bee1538fdf46b0222c4717b42f744e7"}, {file = "cffi-1.14.6-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e22dcb48709fc51a7b58a927391b23ab37eb3737a98ac4338e2448bef8559b33"}, + {file = "cffi-1.14.6-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:aedb15f0a5a5949ecb129a82b72b19df97bbbca024081ed2ef88bd5c0a610534"}, + {file = "cffi-1.14.6-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:48916e459c54c4a70e52745639f1db524542140433599e13911b2f329834276a"}, + {file = "cffi-1.14.6-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f627688813d0a4140153ff532537fbe4afea5a3dffce1f9deb7f91f848a832b5"}, + {file = "cffi-1.14.6-cp35-cp35m-win32.whl", hash = "sha256:f0010c6f9d1a4011e429109fda55a225921e3206e7f62a0c22a35344bfd13cca"}, + {file = "cffi-1.14.6-cp35-cp35m-win_amd64.whl", hash = "sha256:57e555a9feb4a8460415f1aac331a2dc833b1115284f7ded7278b54afc5bd218"}, {file = "cffi-1.14.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e8c6a99be100371dbb046880e7a282152aa5d6127ae01783e37662ef73850d8f"}, {file = "cffi-1.14.6-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:19ca0dbdeda3b2615421d54bef8985f72af6e0c47082a8d26122adac81a95872"}, {file = "cffi-1.14.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d950695ae4381ecd856bcaf2b1e866720e4ab9a1498cba61c602e56630ca7195"}, @@ -1625,8 +1635,8 @@ cffi = [ {file = "cffi-1.14.6.tar.gz", hash = "sha256:c9a875ce9d7fe32887784274dd533c57909b7b1dcadcc128a2ac21331a9765dd"}, ] cfgv = [ - {file = "cfgv-3.3.0-py2.py3-none-any.whl", hash = "sha256:b449c9c6118fe8cca7fa5e00b9ec60ba08145d281d52164230a69211c5d597a1"}, - {file = "cfgv-3.3.0.tar.gz", hash = "sha256:9e600479b3b99e8af981ecdfc80a0296104ee610cab48a5ae4ffd0b668650eb1"}, + {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, + {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, ] cfu = [ {file = "cfu-1.5.0.tar.gz", hash = "sha256:5052fdec7a808823893b73cb438c39a4f780d2c0bba8af06e02192af99424f60"}, @@ -1663,6 +1673,9 @@ coverage = [ {file = "coverage-5.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:8963a499849a1fc54b35b1c9f162f4108017b2e6db2c46c1bed93a72262ed083"}, {file = "coverage-5.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:869a64f53488f40fa5b5b9dcb9e9b2962a66a87dab37790f3fcfb5144b996ef5"}, {file = "coverage-5.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:4a7697d8cb0f27399b0e393c0b90f0f1e40c82023ea4d45d22bce7032a5d7b81"}, + {file = "coverage-5.5-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:8d0a0725ad7c1a0bcd8d1b437e191107d457e2ec1084b9f190630a4fb1af78e6"}, + {file = "coverage-5.5-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:51cb9476a3987c8967ebab3f0fe144819781fca264f57f89760037a2ea191cb0"}, + {file = "coverage-5.5-cp310-cp310-win_amd64.whl", hash = "sha256:c0891a6a97b09c1f3e073a890514d5012eb256845c451bd48f7968ef939bf4ae"}, {file = "coverage-5.5-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:3487286bc29a5aa4b93a072e9592f22254291ce96a9fbc5251f566b6b7343cdb"}, {file = "coverage-5.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:deee1077aae10d8fa88cb02c845cfba9b62c55e1183f52f6ae6a2df6a2187160"}, {file = "coverage-5.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f11642dddbb0253cc8853254301b51390ba0081750a8ac03f20ea8103f0c56b6"}, @@ -1703,18 +1716,23 @@ coverage = [ {file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"}, ] cryptography = [ - {file = "cryptography-3.4.7-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:3d8427734c781ea5f1b41d6589c293089704d4759e34597dce91014ac125aad1"}, - {file = "cryptography-3.4.7-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:8e56e16617872b0957d1c9742a3f94b43533447fd78321514abbe7db216aa250"}, - {file = "cryptography-3.4.7-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:37340614f8a5d2fb9aeea67fd159bfe4f5f4ed535b1090ce8ec428b2f15a11f2"}, - {file = "cryptography-3.4.7-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:240f5c21aef0b73f40bb9f78d2caff73186700bf1bc6b94285699aff98cc16c6"}, - {file = "cryptography-3.4.7-cp36-abi3-manylinux2014_x86_64.whl", hash = "sha256:1e056c28420c072c5e3cb36e2b23ee55e260cb04eee08f702e0edfec3fb51959"}, - {file = "cryptography-3.4.7-cp36-abi3-win32.whl", hash = "sha256:0f1212a66329c80d68aeeb39b8a16d54ef57071bf22ff4e521657b27372e327d"}, - {file = "cryptography-3.4.7-cp36-abi3-win_amd64.whl", hash = "sha256:de4e5f7f68220d92b7637fc99847475b59154b7a1b3868fb7385337af54ac9ca"}, - {file = "cryptography-3.4.7-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:26965837447f9c82f1855e0bc8bc4fb910240b6e0d16a664bb722df3b5b06873"}, - {file = "cryptography-3.4.7-pp36-pypy36_pp73-manylinux2014_x86_64.whl", hash = "sha256:eb8cc2afe8b05acbd84a43905832ec78e7b3873fb124ca190f574dca7389a87d"}, - {file = "cryptography-3.4.7-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:7ec5d3b029f5fa2b179325908b9cd93db28ab7b85bb6c1db56b10e0b54235177"}, - {file = "cryptography-3.4.7-pp37-pypy37_pp73-manylinux2014_x86_64.whl", hash = "sha256:ee77aa129f481be46f8d92a1a7db57269a2f23052d5f2433b4621bb457081cc9"}, - {file = "cryptography-3.4.7.tar.gz", hash = "sha256:3d10de8116d25649631977cb37da6cbdd2d6fa0e0281d014a5b7d337255ca713"}, + {file = "cryptography-3.4.8-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:a00cf305f07b26c351d8d4e1af84ad7501eca8a342dedf24a7acb0e7b7406e14"}, + {file = "cryptography-3.4.8-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:f44d141b8c4ea5eb4dbc9b3ad992d45580c1d22bf5e24363f2fbf50c2d7ae8a7"}, + {file = "cryptography-3.4.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0a7dcbcd3f1913f664aca35d47c1331fce738d44ec34b7be8b9d332151b0b01e"}, + {file = "cryptography-3.4.8-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34dae04a0dce5730d8eb7894eab617d8a70d0c97da76b905de9efb7128ad7085"}, + {file = "cryptography-3.4.8-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1eb7bb0df6f6f583dd8e054689def236255161ebbcf62b226454ab9ec663746b"}, + {file = "cryptography-3.4.8-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:9965c46c674ba8cc572bc09a03f4c649292ee73e1b683adb1ce81e82e9a6a0fb"}, + {file = "cryptography-3.4.8-cp36-abi3-win32.whl", hash = "sha256:21ca464b3a4b8d8e86ba0ee5045e103a1fcfac3b39319727bc0fc58c09c6aff7"}, + {file = "cryptography-3.4.8-cp36-abi3-win_amd64.whl", hash = "sha256:3520667fda779eb788ea00080124875be18f2d8f0848ec00733c0ec3bb8219fc"}, + {file = "cryptography-3.4.8-pp36-pypy36_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d2a6e5ef66503da51d2110edf6c403dc6b494cc0082f85db12f54e9c5d4c3ec5"}, + {file = "cryptography-3.4.8-pp36-pypy36_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a305600e7a6b7b855cd798e00278161b681ad6e9b7eca94c721d5f588ab212af"}, + {file = "cryptography-3.4.8-pp36-pypy36_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:3fa3a7ccf96e826affdf1a0a9432be74dc73423125c8f96a909e3835a5ef194a"}, + {file = "cryptography-3.4.8-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:d9ec0e67a14f9d1d48dd87a2531009a9b251c02ea42851c060b25c782516ff06"}, + {file = "cryptography-3.4.8-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5b0fbfae7ff7febdb74b574055c7466da334a5371f253732d7e2e7525d570498"}, + {file = "cryptography-3.4.8-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94fff993ee9bc1b2440d3b7243d488c6a3d9724cc2b09cdb297f6a886d040ef7"}, + {file = "cryptography-3.4.8-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:8695456444f277af73a4877db9fc979849cd3ee74c198d04fc0776ebc3db52b9"}, + {file = "cryptography-3.4.8-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:cd65b60cfe004790c795cc35f272e41a3df4631e2fb6b35aa7ac6ef2859d554e"}, + {file = "cryptography-3.4.8.tar.gz", hash = "sha256:94cc5ed4ceaefcbe5bf38c8fba6a21fc1d365bb8fb826ea1688e3370b2e24a1c"}, ] decorator = [ {file = "decorator-4.4.2-py2.py3-none-any.whl", hash = "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760"}, @@ -1725,8 +1743,8 @@ defusedxml = [ {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, ] deprecated = [ - {file = "Deprecated-1.2.12-py2.py3-none-any.whl", hash = "sha256:08452d69b6b5bc66e8330adde0a4f8642e969b9e1702904d137eeb29c8ffc771"}, - {file = "Deprecated-1.2.12.tar.gz", hash = "sha256:6d2de2de7931a968874481ef30208fd4e08da39177d61d3d4ebdf4366e7dbca1"}, + {file = "Deprecated-1.2.13-py2.py3-none-any.whl", hash = "sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d"}, + {file = "Deprecated-1.2.13.tar.gz", hash = "sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d"}, ] distlib = [ {file = "distlib-0.3.2-py2.py3-none-any.whl", hash = "sha256:23e223426b28491b1ced97dc3bbe183027419dfc7982b4fa2f05d5f3ff10711c"}, @@ -1737,8 +1755,8 @@ distro = [ {file = "distro-1.6.0.tar.gz", hash = "sha256:83f5e5a09f9c5f68f60173de572930effbcc0287bb84fdc4426cb4168c088424"}, ] django = [ - {file = "Django-3.2.6-py3-none-any.whl", hash = "sha256:7f92413529aa0e291f3be78ab19be31aefb1e1c9a52cd59e130f505f27a51f13"}, - {file = "Django-3.2.6.tar.gz", hash = "sha256:f27f8544c9d4c383bbe007c57e3235918e258364577373d4920e9162837be022"}, + {file = "Django-3.2.7-py3-none-any.whl", hash = "sha256:e93c93565005b37ddebf2396b4dc4b6913c1838baa82efdfb79acedd5816c240"}, + {file = "Django-3.2.7.tar.gz", hash = "sha256:95b318319d6997bac3595517101ad9cc83fe5672ac498ba48d1a410f47afecd2"}, ] django-allauth = [ {file = "django-allauth-0.45.0.tar.gz", hash = "sha256:6d46be0e1480316ccd45476db3aefb39db70e038d2a543112d314b76bb999a4e"}, @@ -1786,15 +1804,16 @@ django-grappelli = [ {file = "django_grappelli-2.15.1-py2.py3-none-any.whl", hash = "sha256:b9aa386d63a95c37f3741aac98bd545c70ff51cf9104a1419dd6568d2e2cf2ea"}, ] django-handleref = [ - {file = "django-handleref-1.0.0.tar.gz", hash = "sha256:3256a0d06d1324e40e3556fc16ab20bd1993db9effef118cf53f9eb4b7e285de"}, - {file = "django_handleref-1.0.0-py3-none-any.whl", hash = "sha256:2614cb7c2e1d9997d7c5ac9c2ff5991f4af7d6ac695ebc7bdf600031561e1701"}, + {file = "django-handleref-1.0.1.tar.gz", hash = "sha256:f822d98a896cfae6a8d3e70448b68e6ad0da0a2a6536d0d37b61342789d25054"}, + {file = "django_handleref-1.0.1-py3-none-any.whl", hash = "sha256:bc787708e57feed668822ca5ae12529db1eb83d41fa3299c8c1e3ea9a2fdb47e"}, ] django-hashers-passlib = [ {file = "django-hashers-passlib-0.4.tar.gz", hash = "sha256:c8f937cf4a9a21957e28735d1ffd8df242dff863c2e4b92665d98509cd6ae0c4"}, {file = "django_hashers_passlib-0.4-py2.py3-none-any.whl", hash = "sha256:2649634ada2f4de1cf17c3c3d43d8391220d68722aa64daee07d975dc210ef30"}, ] django-haystack = [ - {file = "django-haystack-3.0.tar.gz", hash = "sha256:d490f920afa85471dd1fa5000bc8eff4b704daacbe09aee1a64e75cbc426f3be"}, + {file = "django-haystack-3.1.1.tar.gz", hash = "sha256:6d05756b95d7d5ec1dbd4668eb999ced1504b47f588e2e54be53b1404c516a82"}, + {file = "django_haystack-3.1.1-py3-none-any.whl", hash = "sha256:970ebc6362f3f84861209154ec34b57f3e87d2d7922f948df80177f0e2e3ced7"}, ] django-inet = [ {file = "django-inet-1.0.1.tar.gz", hash = "sha256:9e78ae538ee66263d383f8425b650463e7759f7ae90a93cd6b41096f282d5382"}, @@ -1805,12 +1824,12 @@ django-oauth-toolkit = [ {file = "django_oauth_toolkit-1.5.0-py3-none-any.whl", hash = "sha256:b2e346a7c1e222774bfb370f21b556b92b408395b4c23914e2d1b241b2e5376a"}, ] django-otp = [ - {file = "django-otp-1.0.6.tar.gz", hash = "sha256:0d56dd2a7fbb6ee6e54557e036ca64add0bd3596f471794bad673b7637d5e935"}, - {file = "django_otp-1.0.6-py3-none-any.whl", hash = "sha256:01b5888f0bde5125e139433aacb947e52d5c406fa56c9db43c3e8d75b5c323c4"}, + {file = "django-otp-1.1.0.tar.gz", hash = "sha256:44b7dfbf0fb10223f708fa5c0ec182c248e1c251bb35a872375fcd8c29615f17"}, + {file = "django_otp-1.1.0-py3-none-any.whl", hash = "sha256:d19da92a825a1387c86d2e529418efea0f9b7025d882d2d3c1d05b958cf55fc5"}, ] django-peeringdb = [ - {file = "django-peeringdb-2.8.0.tar.gz", hash = "sha256:b8f19d23a486dc82ec72d57063887a3fd4b1b5325ab9064916005e25a7765fa5"}, - {file = "django_peeringdb-2.8.0-py3-none-any.whl", hash = "sha256:ffde1032480728a2943d1cd89a1d6d7af99d2c982009ff2a1204907d17b49748"}, + {file = "django-peeringdb-2.9.0.tar.gz", hash = "sha256:17ab2b29936f60d1453b2736e2ae26d6478f8f688b3ad42032fc5da88019c963"}, + {file = "django_peeringdb-2.9.0-py3-none-any.whl", hash = "sha256:0ff262df41ebd505a41d6160f228e3f6035837f31ad64bfe04559819661d8543"}, ] django-phonenumber-field = [ {file = "django-phonenumber-field-5.2.0.tar.gz", hash = "sha256:52b2e5970133ec5ab701218b802f7ab237229854dc95fd239b7e9e77dc43731d"}, @@ -1856,8 +1875,8 @@ djangorestframework-api-key = [ {file = "djangorestframework_api_key-2.0.0-py3-none-any.whl", hash = "sha256:631d1898510f6adfd4585539daf5f91630d3a92f1f4b1faa029bd45ccc379736"}, ] docker = [ - {file = "docker-5.0.0-py2.py3-none-any.whl", hash = "sha256:fc961d622160e8021c10d1bcabc388c57d55fb1f917175afbe24af442e6879bd"}, - {file = "docker-5.0.0.tar.gz", hash = "sha256:3e8bc47534e0ca9331d72c32f2881bb13b93ded0bcdeab3c833fb7cf61c0a9a5"}, + {file = "docker-5.0.2-py2.py3-none-any.whl", hash = "sha256:9b17f0723d83c1f3418d2aa17bf90b24dbe97deda06208dd4262fa30a6ee87eb"}, + {file = "docker-5.0.2.tar.gz", hash = "sha256:21ec4998e90dff7a7aaaa098ca8d839c7de412b89e6f6c30908372d58fecf663"}, ] docker-compose = [ {file = "docker-compose-1.29.2.tar.gz", hash = "sha256:4c8cd9d21d237412793d18bd33110049ee9af8dab3fe2c213bbd0733959b09b7"}, @@ -1887,8 +1906,8 @@ grainy = [ {file = "grainy-1.8.1.tar.gz", hash = "sha256:2cfd8d50b3f5cce3c463f3c5e86324442f61a7cd46dfe7b134ee926559e56556"}, ] identify = [ - {file = "identify-2.2.13-py2.py3-none-any.whl", hash = "sha256:7199679b5be13a6b40e6e19ea473e789b11b4e3b60986499b1f589ffb03c217c"}, - {file = "identify-2.2.13.tar.gz", hash = "sha256:7bc6e829392bd017236531963d2d937d66fc27cadc643ac0aba2ce9f26157c79"}, + {file = "identify-2.2.14-py2.py3-none-any.whl", hash = "sha256:113a76a6ba614d2a3dd408b3504446bcfac0370da5995aa6a17fd7c6dffde02d"}, + {file = "identify-2.2.14.tar.gz", hash = "sha256:32f465f3c48083f345ad29a9df8419a4ce0674bf4a8c3245191d65c83634bdbf"}, ] idna = [ {file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"}, @@ -1963,8 +1982,8 @@ mccabe = [ {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] munge = [ - {file = "munge-1.2.0-py3-none-any.whl", hash = "sha256:5190e5778ca909b9aaf716b923ad35cbe4cc917916016217f24c86188282fe4b"}, - {file = "munge-1.2.0.tar.gz", hash = "sha256:591da81f8c3a4e72f67c41b85327504b9b9bc3c2cfc716f22c7111a5f07a2de9"}, + {file = "munge-1.2.1-py3-none-any.whl", hash = "sha256:65fb76389b54970beeef6a80b9e1b45cb230d34743cf11565af926ebc8af2627"}, + {file = "munge-1.2.1.tar.gz", hash = "sha256:3daeb20c2964aa4136c57ebfd422ee7e059eb92fbb0ca1e0c3e392ee9a923853"}, ] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, @@ -2008,61 +2027,75 @@ peeringdb = [ {file = "peeringdb-1.1.0.tar.gz", hash = "sha256:927a34c31e5b93130a855bb4c8fd84dcf604b9939678f75918f7c1bd8a501471"}, ] phonenumbers = [ - {file = "phonenumbers-8.12.30-py2.py3-none-any.whl", hash = "sha256:f059f0555f1e47591406729b9e516af417e6a61aa0a5458fd01b2548232715e0"}, - {file = "phonenumbers-8.12.30.tar.gz", hash = "sha256:9ca65c36f437881a8f7dac979a5733ae8fb5a0a436aecd47bd2c06494bdf0a20"}, + {file = "phonenumbers-8.12.32-py2.py3-none-any.whl", hash = "sha256:8a3c19c38852980961cc380b17ff8aeae844ccff7c4aae7a3789688f0351a628"}, + {file = "phonenumbers-8.12.32.tar.gz", hash = "sha256:c52c9c3607483072303ba8d8759063edc44d2f8fe7b85afef40bd8d1aafb6483"}, ] pillow = [ - {file = "Pillow-8.3.1-1-cp36-cp36m-win_amd64.whl", hash = "sha256:fd7eef578f5b2200d066db1b50c4aa66410786201669fb76d5238b007918fb24"}, - {file = "Pillow-8.3.1-1-cp37-cp37m-win_amd64.whl", hash = "sha256:75e09042a3b39e0ea61ce37e941221313d51a9c26b8e54e12b3ececccb71718a"}, - {file = "Pillow-8.3.1-1-cp38-cp38-win_amd64.whl", hash = "sha256:c0e0550a404c69aab1e04ae89cca3e2a042b56ab043f7f729d984bf73ed2a093"}, - {file = "Pillow-8.3.1-1-cp39-cp39-win_amd64.whl", hash = "sha256:479ab11cbd69612acefa8286481f65c5dece2002ffaa4f9db62682379ca3bb77"}, - {file = "Pillow-8.3.1-1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:f156d6ecfc747ee111c167f8faf5f4953761b5e66e91a4e6767e548d0f80129c"}, - {file = "Pillow-8.3.1-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:196560dba4da7a72c5e7085fccc5938ab4075fd37fe8b5468869724109812edd"}, - {file = "Pillow-8.3.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c9569049d04aaacd690573a0398dbd8e0bf0255684fee512b413c2142ab723"}, - {file = "Pillow-8.3.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c088a000dfdd88c184cc7271bfac8c5b82d9efa8637cd2b68183771e3cf56f04"}, - {file = "Pillow-8.3.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:fc214a6b75d2e0ea7745488da7da3c381f41790812988c7a92345978414fad37"}, - {file = "Pillow-8.3.1-cp36-cp36m-win32.whl", hash = "sha256:a17ca41f45cf78c2216ebfab03add7cc350c305c38ff34ef4eef66b7d76c5229"}, - {file = "Pillow-8.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:67b3666b544b953a2777cb3f5a922e991be73ab32635666ee72e05876b8a92de"}, - {file = "Pillow-8.3.1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:ff04c373477723430dce2e9d024c708a047d44cf17166bf16e604b379bf0ca14"}, - {file = "Pillow-8.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9364c81b252d8348e9cc0cb63e856b8f7c1b340caba6ee7a7a65c968312f7dab"}, - {file = "Pillow-8.3.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a2f381932dca2cf775811a008aa3027671ace723b7a38838045b1aee8669fdcf"}, - {file = "Pillow-8.3.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d0da39795049a9afcaadec532e7b669b5ebbb2a9134576ebcc15dd5bdae33cc0"}, - {file = "Pillow-8.3.1-cp37-cp37m-win32.whl", hash = "sha256:2b6dfa068a8b6137da34a4936f5a816aba0ecc967af2feeb32c4393ddd671cba"}, - {file = "Pillow-8.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a4eef1ff2d62676deabf076f963eda4da34b51bc0517c70239fafed1d5b51500"}, - {file = "Pillow-8.3.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:660a87085925c61a0dcc80efb967512ac34dbb256ff7dd2b9b4ee8dbdab58cf4"}, - {file = "Pillow-8.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:15a2808e269a1cf2131930183dcc0419bc77bb73eb54285dde2706ac9939fa8e"}, - {file = "Pillow-8.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:969cc558cca859cadf24f890fc009e1bce7d7d0386ba7c0478641a60199adf79"}, - {file = "Pillow-8.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2ee77c14a0299d0541d26f3d8500bb57e081233e3fa915fa35abd02c51fa7fae"}, - {file = "Pillow-8.3.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c11003197f908878164f0e6da15fce22373ac3fc320cda8c9d16e6bba105b844"}, - {file = "Pillow-8.3.1-cp38-cp38-win32.whl", hash = "sha256:3f08bd8d785204149b5b33e3b5f0ebbfe2190ea58d1a051c578e29e39bfd2367"}, - {file = "Pillow-8.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:70af7d222df0ff81a2da601fab42decb009dc721545ed78549cb96e3a1c5f0c8"}, - {file = "Pillow-8.3.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:37730f6e68bdc6a3f02d2079c34c532330d206429f3cee651aab6b66839a9f0e"}, - {file = "Pillow-8.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4bc3c7ef940eeb200ca65bd83005eb3aae8083d47e8fcbf5f0943baa50726856"}, - {file = "Pillow-8.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c35d09db702f4185ba22bb33ef1751ad49c266534339a5cebeb5159d364f6f82"}, - {file = "Pillow-8.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b2efa07f69dc395d95bb9ef3299f4ca29bcb2157dc615bae0b42c3c20668ffc"}, - {file = "Pillow-8.3.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cc866706d56bd3a7dbf8bac8660c6f6462f2f2b8a49add2ba617bc0c54473d83"}, - {file = "Pillow-8.3.1-cp39-cp39-win32.whl", hash = "sha256:9a211b663cf2314edbdb4cf897beeb5c9ee3810d1d53f0e423f06d6ebbf9cd5d"}, - {file = "Pillow-8.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:c2a5ff58751670292b406b9f06e07ed1446a4b13ffced6b6cab75b857485cbc8"}, - {file = "Pillow-8.3.1-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:c379425c2707078dfb6bfad2430728831d399dc95a7deeb92015eb4c92345eaf"}, - {file = "Pillow-8.3.1-pp36-pypy36_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:114f816e4f73f9ec06997b2fde81a92cbf0777c9e8f462005550eed6bae57e63"}, - {file = "Pillow-8.3.1-pp36-pypy36_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8960a8a9f4598974e4c2aeb1bff9bdd5db03ee65fd1fce8adf3223721aa2a636"}, - {file = "Pillow-8.3.1-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:147bd9e71fb9dcf08357b4d530b5167941e222a6fd21f869c7911bac40b9994d"}, - {file = "Pillow-8.3.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1fd5066cd343b5db88c048d971994e56b296868766e461b82fa4e22498f34d77"}, - {file = "Pillow-8.3.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f4ebde71785f8bceb39dcd1e7f06bcc5d5c3cf48b9f69ab52636309387b097c8"}, - {file = "Pillow-8.3.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:1c03e24be975e2afe70dfc5da6f187eea0b49a68bb2b69db0f30a61b7031cee4"}, - {file = "Pillow-8.3.1.tar.gz", hash = "sha256:2cac53839bfc5cece8fdbe7f084d5e3ee61e1303cccc86511d351adcb9e2c792"}, + {file = "Pillow-8.3.2-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:c691b26283c3a31594683217d746f1dad59a7ae1d4cfc24626d7a064a11197d4"}, + {file = "Pillow-8.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f514c2717012859ccb349c97862568fdc0479aad85b0270d6b5a6509dbc142e2"}, + {file = "Pillow-8.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be25cb93442c6d2f8702c599b51184bd3ccd83adebd08886b682173e09ef0c3f"}, + {file = "Pillow-8.3.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d675a876b295afa114ca8bf42d7f86b5fb1298e1b6bb9a24405a3f6c8338811c"}, + {file = "Pillow-8.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59697568a0455764a094585b2551fd76bfd6b959c9f92d4bdec9d0e14616303a"}, + {file = "Pillow-8.3.2-cp310-cp310-win32.whl", hash = "sha256:2d5e9dc0bf1b5d9048a94c48d0813b6c96fccfa4ccf276d9c36308840f40c228"}, + {file = "Pillow-8.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:11c27e74bab423eb3c9232d97553111cc0be81b74b47165f07ebfdd29d825875"}, + {file = "Pillow-8.3.2-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:11eb7f98165d56042545c9e6db3ce394ed8b45089a67124298f0473b29cb60b2"}, + {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f23b2d3079522fdf3c09de6517f625f7a964f916c956527bed805ac043799b8"}, + {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19ec4cfe4b961edc249b0e04b5618666c23a83bc35842dea2bfd5dfa0157f81b"}, + {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5a31c07cea5edbaeb4bdba6f2b87db7d3dc0f446f379d907e51cc70ea375629"}, + {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:15ccb81a6ffc57ea0137f9f3ac2737ffa1d11f786244d719639df17476d399a7"}, + {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8f284dc1695caf71a74f24993b7c7473d77bc760be45f776a2c2f4e04c170550"}, + {file = "Pillow-8.3.2-cp36-cp36m-win32.whl", hash = "sha256:4abc247b31a98f29e5224f2d31ef15f86a71f79c7f4d2ac345a5d551d6393073"}, + {file = "Pillow-8.3.2-cp36-cp36m-win_amd64.whl", hash = "sha256:a048dad5ed6ad1fad338c02c609b862dfaa921fcd065d747194a6805f91f2196"}, + {file = "Pillow-8.3.2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:06d1adaa284696785375fa80a6a8eb309be722cf4ef8949518beb34487a3df71"}, + {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd24054aaf21e70a51e2a2a5ed1183560d3a69e6f9594a4bfe360a46f94eba83"}, + {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27a330bf7014ee034046db43ccbb05c766aa9e70b8d6c5260bfc38d73103b0ba"}, + {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13654b521fb98abdecec105ea3fb5ba863d1548c9b58831dd5105bb3873569f1"}, + {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a1bd983c565f92779be456ece2479840ec39d386007cd4ae83382646293d681b"}, + {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4326ea1e2722f3dc00ed77c36d3b5354b8fb7399fb59230249ea6d59cbed90da"}, + {file = "Pillow-8.3.2-cp37-cp37m-win32.whl", hash = "sha256:085a90a99404b859a4b6c3daa42afde17cb3ad3115e44a75f0d7b4a32f06a6c9"}, + {file = "Pillow-8.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:18a07a683805d32826c09acfce44a90bf474e6a66ce482b1c7fcd3757d588df3"}, + {file = "Pillow-8.3.2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:4e59e99fd680e2b8b11bbd463f3c9450ab799305d5f2bafb74fefba6ac058616"}, + {file = "Pillow-8.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4d89a2e9219a526401015153c0e9dd48319ea6ab9fe3b066a20aa9aee23d9fd3"}, + {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56fd98c8294f57636084f4b076b75f86c57b2a63a8410c0cd172bc93695ee979"}, + {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b11c9d310a3522b0fd3c35667914271f570576a0e387701f370eb39d45f08a4"}, + {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0412516dcc9de9b0a1e0ae25a280015809de8270f134cc2c1e32c4eeb397cf30"}, + {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bcb04ff12e79b28be6c9988f275e7ab69f01cc2ba319fb3114f87817bb7c74b6"}, + {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0b9911ec70731711c3b6ebcde26caea620cbdd9dcb73c67b0730c8817f24711b"}, + {file = "Pillow-8.3.2-cp38-cp38-win32.whl", hash = "sha256:ce2e5e04bb86da6187f96d7bab3f93a7877830981b37f0287dd6479e27a10341"}, + {file = "Pillow-8.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:35d27687f027ad25a8d0ef45dd5208ef044c588003cdcedf05afb00dbc5c2deb"}, + {file = "Pillow-8.3.2-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:04835e68ef12904bc3e1fd002b33eea0779320d4346082bd5b24bec12ad9c3e9"}, + {file = "Pillow-8.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:10e00f7336780ca7d3653cf3ac26f068fa11b5a96894ea29a64d3dc4b810d630"}, + {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cde7a4d3687f21cffdf5bb171172070bb95e02af448c4c8b2f223d783214056"}, + {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c3ff00110835bdda2b1e2b07f4a2548a39744bb7de5946dc8e95517c4fb2ca6"}, + {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35d409030bf3bd05fa66fb5fdedc39c521b397f61ad04309c90444e893d05f7d"}, + {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bff50ba9891be0a004ef48828e012babaaf7da204d81ab9be37480b9020a82b"}, + {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7dbfbc0020aa1d9bc1b0b8bcf255a7d73f4ad0336f8fd2533fcc54a4ccfb9441"}, + {file = "Pillow-8.3.2-cp39-cp39-win32.whl", hash = "sha256:963ebdc5365d748185fdb06daf2ac758116deecb2277ec5ae98139f93844bc09"}, + {file = "Pillow-8.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:cc9d0dec711c914ed500f1d0d3822868760954dce98dfb0b7382a854aee55d19"}, + {file = "Pillow-8.3.2-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:2c661542c6f71dfd9dc82d9d29a8386287e82813b0375b3a02983feac69ef864"}, + {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:548794f99ff52a73a156771a0402f5e1c35285bd981046a502d7e4793e8facaa"}, + {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8b68f565a4175e12e68ca900af8910e8fe48aaa48fd3ca853494f384e11c8bcd"}, + {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:838eb85de6d9307c19c655c726f8d13b8b646f144ca6b3771fa62b711ebf7624"}, + {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:feb5db446e96bfecfec078b943cc07744cc759893cef045aa8b8b6d6aaa8274e"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:fc0db32f7223b094964e71729c0361f93db43664dd1ec86d3df217853cedda87"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fd4fd83aa912d7b89b4b4a1580d30e2a4242f3936882a3f433586e5ab97ed0d5"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d0c8ebbfd439c37624db98f3877d9ed12c137cadd99dde2d2eae0dab0bbfc355"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6cb3dd7f23b044b0737317f892d399f9e2f0b3a02b22b2c692851fb8120d82c6"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a66566f8a22561fc1a88dc87606c69b84fa9ce724f99522cf922c801ec68f5c1"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ce651ca46d0202c302a535d3047c55a0131a720cf554a578fc1b8a2aff0e7d96"}, + {file = "Pillow-8.3.2.tar.gz", hash = "sha256:dde3f3ed8d00c72631bc19cbfff8ad3b6215062a5eed402381ad365f82f0c18c"}, ] platformdirs = [ - {file = "platformdirs-2.2.0-py3-none-any.whl", hash = "sha256:4666d822218db6a262bdfdc9c39d21f23b4cfdb08af331a81e92751daf6c866c"}, - {file = "platformdirs-2.2.0.tar.gz", hash = "sha256:632daad3ab546bd8e6af0537d09805cec458dce201bccfe23012df73332e181e"}, + {file = "platformdirs-2.3.0-py3-none-any.whl", hash = "sha256:8003ac87717ae2c7ee1ea5a84a1a61e87f3fbd16eb5aadba194ea30a9019f648"}, + {file = "platformdirs-2.3.0.tar.gz", hash = "sha256:15b056538719b1c94bdaccb29e5f81879c7f7f0f4a153f46086d155dffcd4f0f"}, ] pluggy = [ - {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, - {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, + {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, + {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, ] pre-commit = [ - {file = "pre_commit-2.14.0-py2.py3-none-any.whl", hash = "sha256:ec3045ae62e1aa2eecfb8e86fa3025c2e3698f77394ef8d2011ce0aedd85b2d4"}, - {file = "pre_commit-2.14.0.tar.gz", hash = "sha256:2386eeb4cf6633712c7cc9ede83684d53c8cafca6b59f79c738098b51c6d206c"}, + {file = "pre_commit-2.15.0-py2.py3-none-any.whl", hash = "sha256:a4ed01000afcb484d9eb8d504272e642c4c4099bbad3a6b27e519bd6a3e928a6"}, + {file = "pre_commit-2.15.0.tar.gz", hash = "sha256:3c25add78dbdfb6a28a651780d5c311ac40dd17f160eb3954a0c59da40a505a7"}, ] py = [ {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, @@ -2132,8 +2165,8 @@ pyrsistent = [ {file = "pyrsistent-0.18.0.tar.gz", hash = "sha256:773c781216f8c2900b42a7b638d5b517bb134ae1acbebe4d1e8f1f41ea60eb4b"}, ] pytest = [ - {file = "pytest-6.2.4-py3-none-any.whl", hash = "sha256:91ef2131a9bd6be8f76f1f08eac5c5317221d6ad1e143ae03894b862e8976890"}, - {file = "pytest-6.2.4.tar.gz", hash = "sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b"}, + {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, + {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, ] pytest-cov = [ {file = "pytest-cov-2.12.1.tar.gz", hash = "sha256:261ceeb8c227b726249b376b8526b600f38667ee314f910353fa318caa01f4d7"}, @@ -2163,8 +2196,8 @@ pytz = [ {file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da"}, ] pyupgrade = [ - {file = "pyupgrade-2.23.3-py2.py3-none-any.whl", hash = "sha256:ee2355a5f4bf8541eed3687545c59640e50789268cf1802cf214540e5bcc860a"}, - {file = "pyupgrade-2.23.3.tar.gz", hash = "sha256:c5262dcfea5b464bd0e4eb9c3b402bee604b9414885df11cf44ed1eca3037dc4"}, + {file = "pyupgrade-2.26.0-py2.py3-none-any.whl", hash = "sha256:fcfde421775d356eb1e7da443fb23fad6dceca411d8c014acebaed1c2bfeed52"}, + {file = "pyupgrade-2.26.0.tar.gz", hash = "sha256:03eba5ee3494c334d634a272774a30b0aa28af4f5f07f1d3f5d5bedee86c5bcb"}, ] pywin32 = [ {file = "pywin32-227-cp27-cp27m-win32.whl", hash = "sha256:371fcc39416d736401f0274dd64c2302728c9e034808e37381b5e1b22be4a6b0"}, @@ -2187,18 +2220,26 @@ pyyaml = [ {file = "PyYAML-5.4.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185"}, {file = "PyYAML-5.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253"}, {file = "PyYAML-5.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541"}, {file = "PyYAML-5.4.1-cp36-cp36m-win32.whl", hash = "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5"}, {file = "PyYAML-5.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df"}, {file = "PyYAML-5.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018"}, {file = "PyYAML-5.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"}, {file = "PyYAML-5.4.1-cp37-cp37m-win32.whl", hash = "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b"}, {file = "PyYAML-5.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf"}, {file = "PyYAML-5.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46"}, {file = "PyYAML-5.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc"}, {file = "PyYAML-5.4.1-cp38-cp38-win32.whl", hash = "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc"}, {file = "PyYAML-5.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696"}, {file = "PyYAML-5.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77"}, {file = "PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6"}, {file = "PyYAML-5.4.1-cp39-cp39-win32.whl", hash = "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10"}, {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"}, {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, @@ -2212,39 +2253,47 @@ rdap = [ {file = "rdap-1.2.1.tar.gz", hash = "sha256:f2b2d379ba6f9d19027d5cca05ffe35424259754c702f0ab48c2960f4c52d21b"}, ] regex = [ - {file = "regex-2021.8.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8764a78c5464ac6bde91a8c87dd718c27c1cabb7ed2b4beaf36d3e8e390567f9"}, - {file = "regex-2021.8.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4551728b767f35f86b8e5ec19a363df87450c7376d7419c3cac5b9ceb4bce576"}, - {file = "regex-2021.8.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:577737ec3d4c195c4aef01b757905779a9e9aee608fa1cf0aec16b5576c893d3"}, - {file = "regex-2021.8.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c856ec9b42e5af4fe2d8e75970fcc3a2c15925cbcc6e7a9bcb44583b10b95e80"}, - {file = "regex-2021.8.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3835de96524a7b6869a6c710b26c90e94558c31006e96ca3cf6af6751b27dca1"}, - {file = "regex-2021.8.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cea56288eeda8b7511d507bbe7790d89ae7049daa5f51ae31a35ae3c05408531"}, - {file = "regex-2021.8.3-cp36-cp36m-win32.whl", hash = "sha256:a4eddbe2a715b2dd3849afbdeacf1cc283160b24e09baf64fa5675f51940419d"}, - {file = "regex-2021.8.3-cp36-cp36m-win_amd64.whl", hash = "sha256:57fece29f7cc55d882fe282d9de52f2f522bb85290555b49394102f3621751ee"}, - {file = "regex-2021.8.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a5c6dbe09aff091adfa8c7cfc1a0e83fdb8021ddb2c183512775a14f1435fe16"}, - {file = "regex-2021.8.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff4a8ad9638b7ca52313d8732f37ecd5fd3c8e3aff10a8ccb93176fd5b3812f6"}, - {file = "regex-2021.8.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b63e3571b24a7959017573b6455e05b675050bbbea69408f35f3cb984ec54363"}, - {file = "regex-2021.8.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fbc20975eee093efa2071de80df7f972b7b35e560b213aafabcec7c0bd00bd8c"}, - {file = "regex-2021.8.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14caacd1853e40103f59571f169704367e79fb78fac3d6d09ac84d9197cadd16"}, - {file = "regex-2021.8.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bb350eb1060591d8e89d6bac4713d41006cd4d479f5e11db334a48ff8999512f"}, - {file = "regex-2021.8.3-cp37-cp37m-win32.whl", hash = "sha256:18fdc51458abc0a974822333bd3a932d4e06ba2a3243e9a1da305668bd62ec6d"}, - {file = "regex-2021.8.3-cp37-cp37m-win_amd64.whl", hash = "sha256:026beb631097a4a3def7299aa5825e05e057de3c6d72b139c37813bfa351274b"}, - {file = "regex-2021.8.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:16d9eaa8c7e91537516c20da37db975f09ac2e7772a0694b245076c6d68f85da"}, - {file = "regex-2021.8.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3905c86cc4ab6d71635d6419a6f8d972cab7c634539bba6053c47354fd04452c"}, - {file = "regex-2021.8.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:937b20955806381e08e54bd9d71f83276d1f883264808521b70b33d98e4dec5d"}, - {file = "regex-2021.8.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:28e8af338240b6f39713a34e337c3813047896ace09d51593d6907c66c0708ba"}, - {file = "regex-2021.8.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c09d88a07483231119f5017904db8f60ad67906efac3f1baa31b9b7f7cca281"}, - {file = "regex-2021.8.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:85f568892422a0e96235eb8ea6c5a41c8ccbf55576a2260c0160800dbd7c4f20"}, - {file = "regex-2021.8.3-cp38-cp38-win32.whl", hash = "sha256:bf6d987edd4a44dd2fa2723fca2790f9442ae4de2c8438e53fcb1befdf5d823a"}, - {file = "regex-2021.8.3-cp38-cp38-win_amd64.whl", hash = "sha256:8fe58d9f6e3d1abf690174fd75800fda9bdc23d2a287e77758dc0e8567e38ce6"}, - {file = "regex-2021.8.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7976d410e42be9ae7458c1816a416218364e06e162b82e42f7060737e711d9ce"}, - {file = "regex-2021.8.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9569da9e78f0947b249370cb8fadf1015a193c359e7e442ac9ecc585d937f08d"}, - {file = "regex-2021.8.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:459bbe342c5b2dec5c5223e7c363f291558bc27982ef39ffd6569e8c082bdc83"}, - {file = "regex-2021.8.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4f421e3cdd3a273bace013751c345f4ebeef08f05e8c10757533ada360b51a39"}, - {file = "regex-2021.8.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea212df6e5d3f60341aef46401d32fcfded85593af1d82b8b4a7a68cd67fdd6b"}, - {file = "regex-2021.8.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a3b73390511edd2db2d34ff09aa0b2c08be974c71b4c0505b4a048d5dc128c2b"}, - {file = "regex-2021.8.3-cp39-cp39-win32.whl", hash = "sha256:f35567470ee6dbfb946f069ed5f5615b40edcbb5f1e6e1d3d2b114468d505fc6"}, - {file = "regex-2021.8.3-cp39-cp39-win_amd64.whl", hash = "sha256:bfa6a679410b394600eafd16336b2ce8de43e9b13f7fb9247d84ef5ad2b45e91"}, - {file = "regex-2021.8.3.tar.gz", hash = "sha256:8935937dad2c9b369c3d932b0edbc52a62647c2afb2fafc0c280f14a8bf56a6a"}, + {file = "regex-2021.8.28-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9d05ad5367c90814099000442b2125535e9d77581855b9bee8780f1b41f2b1a2"}, + {file = "regex-2021.8.28-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3bf1bc02bc421047bfec3343729c4bbbea42605bcfd6d6bfe2c07ade8b12d2a"}, + {file = "regex-2021.8.28-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f6a808044faae658f546dd5f525e921de9fa409de7a5570865467f03a626fc0"}, + {file = "regex-2021.8.28-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a617593aeacc7a691cc4af4a4410031654f2909053bd8c8e7db837f179a630eb"}, + {file = "regex-2021.8.28-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79aef6b5cd41feff359acaf98e040844613ff5298d0d19c455b3d9ae0bc8c35a"}, + {file = "regex-2021.8.28-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0fc1f8f06977c2d4f5e3d3f0d4a08089be783973fc6b6e278bde01f0544ff308"}, + {file = "regex-2021.8.28-cp310-cp310-win32.whl", hash = "sha256:6eebf512aa90751d5ef6a7c2ac9d60113f32e86e5687326a50d7686e309f66ed"}, + {file = "regex-2021.8.28-cp310-cp310-win_amd64.whl", hash = "sha256:ac88856a8cbccfc14f1b2d0b829af354cc1743cb375e7f04251ae73b2af6adf8"}, + {file = "regex-2021.8.28-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c206587c83e795d417ed3adc8453a791f6d36b67c81416676cad053b4104152c"}, + {file = "regex-2021.8.28-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8690ed94481f219a7a967c118abaf71ccc440f69acd583cab721b90eeedb77c"}, + {file = "regex-2021.8.28-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:328a1fad67445550b982caa2a2a850da5989fd6595e858f02d04636e7f8b0b13"}, + {file = "regex-2021.8.28-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c7cb4c512d2d3b0870e00fbbac2f291d4b4bf2634d59a31176a87afe2777c6f0"}, + {file = "regex-2021.8.28-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66256b6391c057305e5ae9209941ef63c33a476b73772ca967d4a2df70520ec1"}, + {file = "regex-2021.8.28-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8e44769068d33e0ea6ccdf4b84d80c5afffe5207aa4d1881a629cf0ef3ec398f"}, + {file = "regex-2021.8.28-cp36-cp36m-win32.whl", hash = "sha256:08d74bfaa4c7731b8dac0a992c63673a2782758f7cfad34cf9c1b9184f911354"}, + {file = "regex-2021.8.28-cp36-cp36m-win_amd64.whl", hash = "sha256:abb48494d88e8a82601af905143e0de838c776c1241d92021e9256d5515b3645"}, + {file = "regex-2021.8.28-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b4c220a1fe0d2c622493b0a1fd48f8f991998fb447d3cd368033a4b86cf1127a"}, + {file = "regex-2021.8.28-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4a332404baa6665b54e5d283b4262f41f2103c255897084ec8f5487ce7b9e8e"}, + {file = "regex-2021.8.28-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c61dcc1cf9fd165127a2853e2c31eb4fb961a4f26b394ac9fe5669c7a6592892"}, + {file = "regex-2021.8.28-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ee329d0387b5b41a5dddbb6243a21cb7896587a651bebb957e2d2bb8b63c0791"}, + {file = "regex-2021.8.28-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f60667673ff9c249709160529ab39667d1ae9fd38634e006bec95611f632e759"}, + {file = "regex-2021.8.28-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b844fb09bd9936ed158ff9df0ab601e2045b316b17aa8b931857365ea8586906"}, + {file = "regex-2021.8.28-cp37-cp37m-win32.whl", hash = "sha256:4cde065ab33bcaab774d84096fae266d9301d1a2f5519d7bd58fc55274afbf7a"}, + {file = "regex-2021.8.28-cp37-cp37m-win_amd64.whl", hash = "sha256:1413b5022ed6ac0d504ba425ef02549a57d0f4276de58e3ab7e82437892704fc"}, + {file = "regex-2021.8.28-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ed4b50355b066796dacdd1cf538f2ce57275d001838f9b132fab80b75e8c84dd"}, + {file = "regex-2021.8.28-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28fc475f560d8f67cc8767b94db4c9440210f6958495aeae70fac8faec631797"}, + {file = "regex-2021.8.28-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdc178caebd0f338d57ae445ef8e9b737ddf8fbc3ea187603f65aec5b041248f"}, + {file = "regex-2021.8.28-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:999ad08220467b6ad4bd3dd34e65329dd5d0df9b31e47106105e407954965256"}, + {file = "regex-2021.8.28-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:808ee5834e06f57978da3e003ad9d6292de69d2bf6263662a1a8ae30788e080b"}, + {file = "regex-2021.8.28-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d5111d4c843d80202e62b4fdbb4920db1dcee4f9366d6b03294f45ed7b18b42e"}, + {file = "regex-2021.8.28-cp38-cp38-win32.whl", hash = "sha256:473858730ef6d6ff7f7d5f19452184cd0caa062a20047f6d6f3e135a4648865d"}, + {file = "regex-2021.8.28-cp38-cp38-win_amd64.whl", hash = "sha256:31a99a4796bf5aefc8351e98507b09e1b09115574f7c9dbb9cf2111f7220d2e2"}, + {file = "regex-2021.8.28-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:04f6b9749e335bb0d2f68c707f23bb1773c3fb6ecd10edf0f04df12a8920d468"}, + {file = "regex-2021.8.28-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b006628fe43aa69259ec04ca258d88ed19b64791693df59c422b607b6ece8bb"}, + {file = "regex-2021.8.28-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:121f4b3185feaade3f85f70294aef3f777199e9b5c0c0245c774ae884b110a2d"}, + {file = "regex-2021.8.28-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a577a21de2ef8059b58f79ff76a4da81c45a75fe0bfb09bc8b7bb4293fa18983"}, + {file = "regex-2021.8.28-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1743345e30917e8c574f273f51679c294effba6ad372db1967852f12c76759d8"}, + {file = "regex-2021.8.28-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e1e8406b895aba6caa63d9fd1b6b1700d7e4825f78ccb1e5260551d168db38ed"}, + {file = "regex-2021.8.28-cp39-cp39-win32.whl", hash = "sha256:ed283ab3a01d8b53de3a05bfdf4473ae24e43caee7dcb5584e86f3f3e5ab4374"}, + {file = "regex-2021.8.28-cp39-cp39-win_amd64.whl", hash = "sha256:610b690b406653c84b7cb6091facb3033500ee81089867ee7d59e675f9ca2b73"}, + {file = "regex-2021.8.28.tar.gz", hash = "sha256:f585cbbeecb35f35609edccb95efd95a3e35824cd7752b586503f7e6087303f1"}, ] requests = [ {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"}, @@ -2260,52 +2309,60 @@ requests-oauthlib = [ {file = "requests_oauthlib-1.3.0-py3.7.egg", hash = "sha256:fa6c47b933f01060936d87ae9327fead68768b69c6c9ea2109c48be30f2d4dbc"}, ] simplejson = [ - {file = "simplejson-3.17.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:18302970ce341c3626433d4ffbdac19c7cca3d6e2d54b12778bcb8095f695473"}, - {file = "simplejson-3.17.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:8f174567c53413383b8b7ec2fbe88d41e924577bc854051f265d4c210cd72999"}, - {file = "simplejson-3.17.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:6ff6710b824947ef5a360a5a5ae9809c32cedc6110df3b64f01080c1bc1a1f08"}, - {file = "simplejson-3.17.3-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:02c04b89b0a456a97d5313357dd9f2259c163a82c5307e39e7d35bb38d7fd085"}, - {file = "simplejson-3.17.3-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:a52b80b9d1085db6e216980d1d28a8f090b8f2203a8c71b4ea13441bd7a2e86e"}, - {file = "simplejson-3.17.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:3c80b343503da8b13fa7d48d1a2395be67e97b67a849eb79d88ad3b12783e7da"}, - {file = "simplejson-3.17.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e7433c604077a17dd71e8b29c96a15e486a70a97f4ed9c7f5e0df6e428af2f0b"}, - {file = "simplejson-3.17.3-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:88a69c7e8059a4fd7aa2a31d2b3d89077eaae72eb741f18a32cb57d04018ff4c"}, - {file = "simplejson-3.17.3-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d61fb151be068127a0ce7758341cbe778495819622bc1e15eadf59fdb3a0481e"}, - {file = "simplejson-3.17.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c91d0f2fc2ee1bd376f5a991c24923f12416d8c31a9b74a82c4b38b942fc2640"}, - {file = "simplejson-3.17.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e056056718246c9cdd82d1e3d4ad854a7ceb057498bf994b529750a190a6bd98"}, - {file = "simplejson-3.17.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:02bc0b7b643fa255048862f580bb4b7121b88b456bc64dabf9bf11df116b05d7"}, - {file = "simplejson-3.17.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e3aa10cce4053f3c1487aaf847a0faa4ae208e11f85a8e6f98de2291713a6616"}, - {file = "simplejson-3.17.3-cp36-cp36m-win32.whl", hash = "sha256:b45b5f6c9962953250534217b18002261c5b9383349b95fb0140899cdac2bf95"}, - {file = "simplejson-3.17.3-cp36-cp36m-win_amd64.whl", hash = "sha256:dbcd6cd1a9abb5a13c5df93cdc5687f6877efcfefdc9350c22d4094dc4a7dd86"}, - {file = "simplejson-3.17.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:05cd392c1c9b284bda91cf9d7b6f3f46631da459e8546fe823622e42cf4794bb"}, - {file = "simplejson-3.17.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f32a703fe10cfc2d1020e296eeeeb650faa039678f6b79d9b820413a4c015ddc"}, - {file = "simplejson-3.17.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:b4ed7b233e812ef1244a29fb0dfd3e149dbc34a2bd13b174a84c92d0cb580277"}, - {file = "simplejson-3.17.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b25748e71c5df3c67b5bda2cdece373762d319cb5f773f14ae2f90dfb4320314"}, - {file = "simplejson-3.17.3-cp37-cp37m-win32.whl", hash = "sha256:b60f48f780130f27f8d9751599925c3b78cf045f5d62dd918003effb65b45bda"}, - {file = "simplejson-3.17.3-cp37-cp37m-win_amd64.whl", hash = "sha256:32edf4e491fe174c54bf6682d794daf398736158d1082dbcae526e4a5af6890b"}, - {file = "simplejson-3.17.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2104475a0263ff2a3dffca214c9676eb261e90d06d604ac7063347bd289ac84c"}, - {file = "simplejson-3.17.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fed5e862d9b501c5673c163c8593ebdb2c5422386089c529dfac28d70cd55858"}, - {file = "simplejson-3.17.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ff7fe042169dd6fce8213c173a4c337f2e807ed5178093143c778eb0484c12ec"}, - {file = "simplejson-3.17.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1331a54fda3c957b9136402943cf8ebcd29c0c92101ba70fa8c2fc9cdf1b8476"}, - {file = "simplejson-3.17.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6510e886d9e9006213de2090c55f504b12f915178a2056b94840ed1d89abe68e"}, - {file = "simplejson-3.17.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:391a8206e698557a4155354cf6996c002aa447a21c5c50fb94a0d26fd6cca586"}, - {file = "simplejson-3.17.3-cp38-cp38-win32.whl", hash = "sha256:f02db159e0afa9cb350f15f4f7b86755eae95267b9012ee90bde329aa643f76c"}, - {file = "simplejson-3.17.3-cp38-cp38-win_amd64.whl", hash = "sha256:6285b91cfa37e024f372b9b77d14f279380eebc4f709db70c593c069602e1926"}, - {file = "simplejson-3.17.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3dddd31857d8230aee88c24f485ebca36d1d875404b2ef11ac15fa3c8a01dc34"}, - {file = "simplejson-3.17.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1ebbaa48447b60a68043f58e612021e8893ebcf1662a1b18a2595ca262776d7e"}, - {file = "simplejson-3.17.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:79545a6d93bb38f86a00fbc6129cb091a86bb858e7d53b1aaa10d927d3b6732e"}, - {file = "simplejson-3.17.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23169d78f74fd25f891e89c779a63fcb857e66ab210096f4069a5b1c9e2dc732"}, - {file = "simplejson-3.17.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:56f57c231cdd01b6a1c0532ea9088dff2afe7f4f4bda61c060bcb1a853e6b564"}, - {file = "simplejson-3.17.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3904b528e3dc0facab73a4406ebf17f007f32f0a8d7f4c6aa9ed5cbad3ea0f34"}, - {file = "simplejson-3.17.3-cp39-cp39-win32.whl", hash = "sha256:c69a213ae72b75e8948f06a87d3675855bccb3037671222ffd235095e62f5a61"}, - {file = "simplejson-3.17.3-cp39-cp39-win_amd64.whl", hash = "sha256:5b080be7de4c647fa84252cf565298a13842658123bd1a322a8c32b6359c8f1e"}, - {file = "simplejson-3.17.3.tar.gz", hash = "sha256:da72a452bcf4349fc467a12b54ab0e63e654a571cacc44084826d52bde12b6ee"}, + {file = "simplejson-3.17.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:376023f51edaf7290332dacfb055bc00ce864cb013c0338d0dea48731f37e42f"}, + {file = "simplejson-3.17.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b2a5688606dffbe95e1347a05b77eb90489fe337edde888e23bbb7fd81b0d93b"}, + {file = "simplejson-3.17.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:3ba82f8b421886f4a2311c43fb98faaf36c581976192349fef2a89ed0fcdbdef"}, + {file = "simplejson-3.17.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:7332f7b06d42153255f7bfeb10266141c08d48cc1a022a35473c95238ff2aebc"}, + {file = "simplejson-3.17.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:c2d5334d935af711f6d6dfeec2d34e071cdf73ec0df8e8bd35ac435b26d8da97"}, + {file = "simplejson-3.17.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:417b7e119d66085dc45bdd563dcb2c575ee10a3b1c492dd3502a029448d4be1c"}, + {file = "simplejson-3.17.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:42b7c7264229860fe879be961877f7466d9f7173bd6427b3ba98144a031d49fb"}, + {file = "simplejson-3.17.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5fe8c6dcb9e6f7066bdc07d3c410a2fca78c0d0b4e0e72510ffd20a60a20eb8e"}, + {file = "simplejson-3.17.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:b92fbc2bc549c5045c8233d954f3260ccf99e0f3ec9edfd2372b74b350917752"}, + {file = "simplejson-3.17.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5f7f53b1edd4b23fb112b89208377480c0bcee45d43a03ffacf30f3290e0ed85"}, + {file = "simplejson-3.17.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:40ece8fa730d1a947bff792bcc7824bd02d3ce6105432798e9a04a360c8c07b0"}, + {file = "simplejson-3.17.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:10defa88dd10a0a4763f16c1b5504e96ae6dc68953cfe5fc572b4a8fcaf9409b"}, + {file = "simplejson-3.17.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa86cfdeb118795875855589934013e32895715ec2d9e8eb7a59be3e7e07a7e1"}, + {file = "simplejson-3.17.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ce66f730031b9b3683b2fc6ad4160a18db86557c004c3d490a29bf8d450d7ab9"}, + {file = "simplejson-3.17.5-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:352c11582aa1e49a2f0f7f7d8fd5ec5311da890d1354287e83c63ab6af857cf5"}, + {file = "simplejson-3.17.5-cp310-cp310-win32.whl", hash = "sha256:8e595de17178dd3bbeb2c5b8ea97536341c63b7278639cb8ee2681a84c0ef037"}, + {file = "simplejson-3.17.5-cp310-cp310-win_amd64.whl", hash = "sha256:cb0afc3bad49eb89a579103616574a54b523856d20fc539a4f7a513a0a8ba4b2"}, + {file = "simplejson-3.17.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ade09aa3c284d11f39640aebdcbb748e1996f0c60504f8c4a0c5a9fec821e67a"}, + {file = "simplejson-3.17.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87572213965fd8a4fb7a97f837221e01d8fddcfb558363c671b8aa93477fb6a2"}, + {file = "simplejson-3.17.5-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2b59acd09b02da97728d0bae8ff48876d7efcbbb08e569c55e2d0c2e018324f5"}, + {file = "simplejson-3.17.5-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e29b9cea4216ec130df85d8c36efb9985fda1c9039e4706fb30e0fb6a67602ff"}, + {file = "simplejson-3.17.5-cp36-cp36m-win32.whl", hash = "sha256:f550730d18edec4ff9d4252784b62adfe885d4542946b6d5a54c8a6521b56afd"}, + {file = "simplejson-3.17.5-cp36-cp36m-win_amd64.whl", hash = "sha256:1c2688365743b0f190392e674af5e313ebe9d621813d15f9332e874b7c1f2d04"}, + {file = "simplejson-3.17.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f13c48cc4363829bdfecc0c181b6ddf28008931de54908a492dc8ccd0066cd60"}, + {file = "simplejson-3.17.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a6943816e10028eeed512ea03be52b54ea83108b408d1049b999f58a760089b"}, + {file = "simplejson-3.17.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3d72aa9e73134dacd049a2d6f9bd219f7be9c004d03d52395831611d66cedb71"}, + {file = "simplejson-3.17.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5b94df70bd34a3b946c0eb272022fb0f8a9eb27cad76e7f313fedbee2ebe4317"}, + {file = "simplejson-3.17.5-cp37-cp37m-win32.whl", hash = "sha256:065230b9659ac38c8021fa512802562d122afb0cf8d4b89e257014dcddb5730a"}, + {file = "simplejson-3.17.5-cp37-cp37m-win_amd64.whl", hash = "sha256:86fcffc06f1125cb443e2bed812805739d64ceb78597ac3c1b2d439471a09717"}, + {file = "simplejson-3.17.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:78c6f0ed72b440ebe1892d273c1e5f91e55e6861bea611d3b904e673152a7a4c"}, + {file = "simplejson-3.17.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:36b08b886027eac67e7a0e822e3a5bf419429efad7612e69501669d6252a21f2"}, + {file = "simplejson-3.17.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fe1c33f78d2060719d52ea9459d97d7ae3a5b707ec02548575c4fbed1d1d345b"}, + {file = "simplejson-3.17.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:140eb58809f24d843736edb8080b220417e22c82ac07a3dfa473f57e78216b5f"}, + {file = "simplejson-3.17.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:7c9b30a2524ae6983b708f12741a31fbc2fb8d6fecd0b6c8584a62fd59f59e09"}, + {file = "simplejson-3.17.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:24e413bd845bd17d4d72063d64e053898543fb7abc81afeae13e5c43cef9c171"}, + {file = "simplejson-3.17.5-cp38-cp38-win32.whl", hash = "sha256:5f5051a13e7d53430a990604b532c9124253c5f348857e2d5106d45fc8533860"}, + {file = "simplejson-3.17.5-cp38-cp38-win_amd64.whl", hash = "sha256:188f2c78a8ac1eb7a70a4b2b7b9ad11f52181044957bf981fb3e399c719e30ee"}, + {file = "simplejson-3.17.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:457d9cfe7ece1571770381edccdad7fc255b12cd7b5b813219441146d4f47595"}, + {file = "simplejson-3.17.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa843ee0d34c7193f5a816e79df8142faff851549cab31e84b526f04878ac778"}, + {file = "simplejson-3.17.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e2cc4b68e59319e3de778325e34fbff487bfdb2225530e89995402989898d681"}, + {file = "simplejson-3.17.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e90d2e219c3dce1500dda95f5b893c293c4d53c4e330c968afbd4e7a90ff4a5b"}, + {file = "simplejson-3.17.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:917f01db71d5e720b731effa3ff4a2c702a1b6dacad9bcdc580d86a018dfc3ca"}, + {file = "simplejson-3.17.5-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:07707ba69324eaf58f0c6f59d289acc3e0ed9ec528dae5b0d4219c0d6da27dc5"}, + {file = "simplejson-3.17.5-cp39-cp39-win32.whl", hash = "sha256:2df15814529a4625ea6f7b354a083609b3944c269b954ece0d0e7455872e1b2a"}, + {file = "simplejson-3.17.5-cp39-cp39-win_amd64.whl", hash = "sha256:71a54815ec0212b0cba23adc1b2a731bdd2df7b9e4432718b2ed20e8aaf7f01a"}, + {file = "simplejson-3.17.5.tar.gz", hash = "sha256:91cfb43fb91ff6d1e4258be04eee84b51a4ef40a28d899679b9ea2556322fb50"}, ] six = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] sqlparse = [ - {file = "sqlparse-0.4.1-py3-none-any.whl", hash = "sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0"}, - {file = "sqlparse-0.4.1.tar.gz", hash = "sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8"}, + {file = "sqlparse-0.4.2-py3-none-any.whl", hash = "sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d"}, + {file = "sqlparse-0.4.2.tar.gz", hash = "sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae"}, ] texttable = [ {file = "texttable-1.6.4-py2.py3-none-any.whl", hash = "sha256:dd2b0eaebb2a9e167d1cefedab4700e5dcbdb076114eed30b58b97ed6b37d6f2"}, @@ -2335,9 +2392,14 @@ tomli = [ "twentyc.rpc" = [ {file = "twentyc.rpc-0.4.0.tar.gz", hash = "sha256:c6a08a0fa8610332f430911061a662efee8c251a5568c1ffd592c566d9da0768"}, ] +typing-extensions = [ + {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, + {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, + {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, +] unidecode = [ - {file = "Unidecode-1.2.0-py2.py3-none-any.whl", hash = "sha256:12435ef2fc4cdfd9cf1035a1db7e98b6b047fe591892e81f34e94959591fad00"}, - {file = "Unidecode-1.2.0.tar.gz", hash = "sha256:8d73a97d387a956922344f6b74243c2c6771594659778744b2dbdaad8f6b727d"}, + {file = "Unidecode-1.3.1-py3-none-any.whl", hash = "sha256:5f58926b9125b499f8ab6816828e737578fa3e31fa24d351a3ab7f4b7c064ab0"}, + {file = "Unidecode-1.3.1.tar.gz", hash = "sha256:6efac090bf8f29970afc90caf4daae87b172709b786cb1b4da2d0c0624431ecc"}, ] uritemplate = [ {file = "uritemplate-3.0.1-py2.py3-none-any.whl", hash = "sha256:07620c3f3f8eed1f12600845892b0e036a2420acf513c53f7de0abd911a5894f"}, diff --git a/pyproject.toml b/pyproject.toml index 9298a660..b78e3073 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,8 +12,8 @@ python = "^3.9" # core requirements django = ">=3.2, <4" django-inet = "^1.0" -django-handleref = "^1.0" -django-peeringdb = "==2.8.0" +django-handleref = "^1.0.1" +django-peeringdb = "==2.9.0" djangorestframework = ">=3.12,<3.13" mysqlclient = ">=1.3.9" peeringdb = ">=1.1.0, <2" diff --git a/tests/test_data_views.py b/tests/test_data_views.py index 3774cf50..462df268 100644 --- a/tests/test_data_views.py +++ b/tests/test_data_views.py @@ -29,6 +29,7 @@ from peeringdb_server.models import ( "POLICY_CONTRACTS", "REGIONS", "POC_ROLES", + "POC_VISIBILITY", "MEDIA", "PROTOCOLS", "ORG_GROUPS", diff --git a/tests/test_ixf_member_import_protocol.py b/tests/test_ixf_member_import_protocol.py index 01e4133f..96966524 100644 --- a/tests/test_ixf_member_import_protocol.py +++ b/tests/test_ixf_member_import_protocol.py @@ -2789,6 +2789,107 @@ def test_send_email(entities, use_ip): assert importer.emails == 2 +@pytest.mark.django_db +def test_ixlan_add_netixlan_no_redundant_save_on_null_ip(entities): + + """ + Tests that if ixlan.add_netixlan receives a netixlan which + has either ipaddr4 or ipaddr6 nulled will not cause redundant + saves to already deleted netixlans that also have that same field + nulled (#1019) + """ + + network = entities["net"]["UPDATE_ENABLED"] + ixlan = entities["ixlan"][0] + + # create deleted netixlans + + with reversion.create_revision(): + NetworkIXLan.objects.create( + ixlan=ixlan, + network=network, + asn=network.asn + 1, + ipaddr4="195.69.147.253", + ipaddr6="2001:7f8:1::a500:2906:10", + speed=1000, + status="deleted", + ) + + NetworkIXLan.objects.create( + ixlan=ixlan, + network=network, + asn=network.asn + 1, + ipaddr4="195.69.147.252", + ipaddr6="2001:7f8:1::a500:2906:11", + speed=1000, + status="deleted", + ) + + netixlan6 = NetworkIXLan.objects.create( + ixlan=ixlan, + network=network, + asn=network.asn + 1, + ipaddr4=None, + ipaddr6="2001:7f8:1::a500:2906:9", + speed=1000, + status="deleted", + ) + + netixlan4 = NetworkIXLan.objects.create( + ixlan=ixlan, + network=network, + asn=network.asn + 1, + ipaddr4="195.69.147.251", + ipaddr6=None, + speed=1000, + status="deleted", + ) + + netixlan4.refresh_from_db() + netixlan6.refresh_from_db() + + assert netixlan4.version == 1 + assert netixlan6.version == 1 + + # create netixlans + + netixlan6_new = NetworkIXLan( + ixlan=ixlan, + network=network, + asn=network.asn, + ipaddr4=None, + ipaddr6="2001:7f8:1::a500:2906:10", + speed=1000, + status="deleted", + ) + + netixlan4_new = NetworkIXLan( + ixlan=ixlan, + network=network, + asn=network.asn, + ipaddr4="195.69.147.252", + ipaddr6=None, + speed=1000, + status="deleted", + ) + + with reversion.create_revision(): + netixlan6_new = ixlan.add_netixlan(netixlan6_new) + netixlan4_new = ixlan.add_netixlan(netixlan4_new) + + netixlan4.refresh_from_db() + netixlan6.refresh_from_db() + + # No further saves should have happened to the already + # deleted netixlans + + assert not netixlan4.notes + assert not netixlan6.notes + + assert netixlan4.version == 1 + assert netixlan6.version == 1 + + # FIXTURES @pytest.fixture(params=[True, False]) def save(request): diff --git a/tests/test_settings.py b/tests/test_settings.py index dfc418e4..4396ae77 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -1,6 +1,7 @@ import os import pytest +from allauth.account.signals import email_confirmed, user_signed_up from django.conf import settings from django.contrib.auth import get_user_model from django.test import TestCase @@ -8,7 +9,6 @@ from django.test import TestCase from mainsite.settings import _set_bool, _set_option from peeringdb_server import models, serializers from peeringdb_server import settings as pdb_settings -from allauth.account.signals import email_confirmed, user_signed_up from .util import SettingsCase diff --git a/tests/test_views.py b/tests/test_views.py index 7a4f839f..4919ec16 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -1,4 +1,5 @@ import re + import pytest from django.test import Client from rest_framework.test import APIClient