Bump neutron-lib to 2.17.0
Remove the QoS constants from Neutron code. QoS constants are now located in ``neutron_lib.services.qos.constants``. This patch also reverts [1]. This patch was merged in order to allow a newer neutron-lib release in "requirements". This test was failing because the element order of the "VALID_RULE_TYPES" list was different between Neutron and neutron-lib. That was modifying the "QosRuleType" OVO hash. [1]https://review.opendev.org/c/openstack/neutron/+/817940 Closes-Bug: #1950977 Related-Bug: #1922237 Change-Id: I31edea3cc0f4a284a773a35302997ca6069efc95
This commit is contained in:
parent
63f8a39d75
commit
4909c8c18d
@ -50,7 +50,7 @@ msgpack-python==0.4.0
|
||||
munch==2.1.0
|
||||
netaddr==0.7.18
|
||||
netifaces==0.10.4
|
||||
neutron-lib==2.16.0
|
||||
neutron-lib==2.17.0
|
||||
openstacksdk==0.31.2
|
||||
os-client-config==1.28.0
|
||||
os-ken==2.2.0
|
||||
|
@ -17,8 +17,6 @@ from neutron_lib import constants as n_consts
|
||||
from neutron_lib.exceptions import qos as qos_exc
|
||||
from neutron_lib.services.qos import constants as qos_consts
|
||||
|
||||
from neutron.services.qos import constants as qos_constants
|
||||
|
||||
|
||||
def check_bandwidth_rule_conflict(policy, rule_data):
|
||||
"""Implementation of the QoS Rule checker.
|
||||
@ -78,10 +76,10 @@ def check_min_pps_rule_conflict(policy, rule_obj):
|
||||
Raises an exception if conflict is identified.
|
||||
"""
|
||||
if (getattr(rule_obj, "rule_type", None) !=
|
||||
qos_constants.RULE_TYPE_MINIMUM_PACKET_RATE):
|
||||
qos_consts.RULE_TYPE_MINIMUM_PACKET_RATE):
|
||||
return
|
||||
for rule in policy.rules:
|
||||
if rule.rule_type == qos_constants.RULE_TYPE_MINIMUM_PACKET_RATE:
|
||||
if rule.rule_type == qos_consts.RULE_TYPE_MINIMUM_PACKET_RATE:
|
||||
# Just like in check_rules_conflict(), we need to avoid raising
|
||||
# exception when compared rules have got same ID.
|
||||
if rule.id == getattr(rule_obj, "id", None):
|
||||
|
@ -26,7 +26,6 @@ from oslo_versionedobjects import fields as obj_fields
|
||||
|
||||
from neutron.db.qos import models as qos_db_model
|
||||
from neutron.objects import base
|
||||
from neutron.services.qos import constants as qos_constants
|
||||
|
||||
DSCP_MARK = 'dscp_mark'
|
||||
|
||||
@ -37,7 +36,7 @@ def get_rules(obj_cls, context, qos_policy_id):
|
||||
return all_rules
|
||||
|
||||
with obj_cls.db_context_reader(context):
|
||||
for rule_type in qos_constants.VALID_RULE_TYPES:
|
||||
for rule_type in qos_consts.VALID_RULE_TYPES:
|
||||
rule_cls_name = 'Qos%sRule' % helpers.camelize(rule_type)
|
||||
rule_cls = getattr(sys.modules[__name__], rule_cls_name)
|
||||
|
||||
@ -186,7 +185,7 @@ class QosPacketRateLimitRule(QosRule):
|
||||
|
||||
duplicates_compare_fields = ['direction']
|
||||
|
||||
rule_type = qos_constants.RULE_TYPE_PACKET_RATE_LIMIT
|
||||
rule_type = qos_consts.RULE_TYPE_PACKET_RATE_LIMIT
|
||||
|
||||
|
||||
@base.NeutronObjectRegistry.register
|
||||
@ -201,4 +200,4 @@ class QosMinimumPacketRateRule(QosRule):
|
||||
|
||||
duplicates_compare_fields = ['direction']
|
||||
|
||||
rule_type = qos_constants.RULE_TYPE_MINIMUM_PACKET_RATE
|
||||
rule_type = qos_consts.RULE_TYPE_MINIMUM_PACKET_RATE
|
||||
|
@ -13,10 +13,10 @@
|
||||
from neutron_lib.objects import common_types
|
||||
from neutron_lib.plugins import constants
|
||||
from neutron_lib.plugins import directory
|
||||
from neutron_lib.services.qos import constants as qos_constants
|
||||
from oslo_versionedobjects import fields as obj_fields
|
||||
|
||||
from neutron.objects import base
|
||||
from neutron.services.qos import constants as qos_constants
|
||||
|
||||
|
||||
class RuleTypeField(obj_fields.BaseEnumField):
|
||||
|
@ -1,33 +0,0 @@
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from neutron_lib.services.qos import constants as qos_consts
|
||||
|
||||
# TODO(liuyulong): Because of the development sequence, the rule must
|
||||
# be implemented in Neutron first. Then the following can be moved
|
||||
# to neutron-lib after neutron has the new rule.
|
||||
# Add qos rule packet rate limit
|
||||
RULE_TYPE_PACKET_RATE_LIMIT = 'packet_rate_limit'
|
||||
RULE_TYPE_MINIMUM_PACKET_RATE = 'minimum_packet_rate'
|
||||
# NOTE(przszc): Ensure that there are no duplicates in the list. Order of the
|
||||
# items in the list must be stable, as QosRuleType OVO hash value depends on
|
||||
# it.
|
||||
# TODO(przszc): When a rule type is moved to neutron-lib, it can be removed
|
||||
# from the list below.
|
||||
VALID_RULE_TYPES = (qos_consts.VALID_RULE_TYPES +
|
||||
([RULE_TYPE_PACKET_RATE_LIMIT] if RULE_TYPE_PACKET_RATE_LIMIT not in
|
||||
qos_consts.VALID_RULE_TYPES else []) +
|
||||
([RULE_TYPE_MINIMUM_PACKET_RATE] if RULE_TYPE_MINIMUM_PACKET_RATE not in
|
||||
qos_consts.VALID_RULE_TYPES else [])
|
||||
)
|
@ -24,7 +24,6 @@ from neutron.api.rpc.callbacks.producer import registry as rpc_registry
|
||||
from neutron.api.rpc.callbacks import resources
|
||||
from neutron.api.rpc.handlers import resources_rpc
|
||||
from neutron.objects.qos import policy as policy_object
|
||||
from neutron.services.qos import constants as qos_constants
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -169,7 +168,7 @@ class QosServiceDriverManager(object):
|
||||
if not self._drivers:
|
||||
return []
|
||||
|
||||
rule_types = set(qos_constants.VALID_RULE_TYPES)
|
||||
rule_types = set(qos_consts.VALID_RULE_TYPES)
|
||||
|
||||
# Recalculate on every call to allow drivers determine supported rule
|
||||
# types dynamically
|
||||
|
@ -21,7 +21,6 @@ from neutron_lib.services.qos import constants as qos_consts
|
||||
from oslo_log import log as logging
|
||||
|
||||
from neutron.objects import network as network_object
|
||||
from neutron.services.qos import constants as neutron_qos_consts
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -45,7 +44,7 @@ SUPPORTED_RULES = {
|
||||
'type:range': [0, db_consts.DB_INTEGER_MAX_VALUE]},
|
||||
qos_consts.DIRECTION: {'type:values': constants.VALID_DIRECTIONS}
|
||||
},
|
||||
neutron_qos_consts.RULE_TYPE_MINIMUM_PACKET_RATE: {
|
||||
qos_consts.RULE_TYPE_MINIMUM_PACKET_RATE: {
|
||||
qos_consts.MIN_KPPS: {
|
||||
'type:range': [0, db_consts.DB_INTEGER_MAX_VALUE]},
|
||||
qos_consts.DIRECTION: {
|
||||
|
@ -58,7 +58,6 @@ from neutron.objects.qos import policy as policy_object
|
||||
from neutron.objects.qos import qos_policy_validator as checker
|
||||
from neutron.objects.qos import rule as rule_object
|
||||
from neutron.objects.qos import rule_type as rule_type_object
|
||||
from neutron.services.qos import constants as qos_constants
|
||||
from neutron.services.qos.drivers import manager
|
||||
|
||||
|
||||
@ -510,7 +509,7 @@ class QoSPlugin(qos.QoSPluginBase):
|
||||
|
||||
for group_uuid, rp in allocation.items():
|
||||
for rule_type in [qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH,
|
||||
qos_constants.RULE_TYPE_MINIMUM_PACKET_RATE]:
|
||||
qos_consts.RULE_TYPE_MINIMUM_PACKET_RATE]:
|
||||
o_filtered_rules = [r for r in original_rules
|
||||
if r.rule_type == rule_type]
|
||||
d_filtered_rules = [r for r in desired_rules
|
||||
@ -871,7 +870,7 @@ class QoSPlugin(qos.QoSPluginBase):
|
||||
self.validate_policy(context, policy)
|
||||
if rule.rule_type in (
|
||||
qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH,
|
||||
qos_constants.RULE_TYPE_MINIMUM_PACKET_RATE):
|
||||
qos_consts.RULE_TYPE_MINIMUM_PACKET_RATE):
|
||||
self.reject_rule_update_for_bound_port(context, policy)
|
||||
self.driver_manager.call(qos_consts.UPDATE_POLICY_PRECOMMIT,
|
||||
context, policy)
|
||||
@ -915,7 +914,7 @@ class QoSPlugin(qos.QoSPluginBase):
|
||||
self.validate_policy(context, policy)
|
||||
if rule.rule_type in (
|
||||
qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH,
|
||||
qos_constants.RULE_TYPE_MINIMUM_PACKET_RATE):
|
||||
qos_consts.RULE_TYPE_MINIMUM_PACKET_RATE):
|
||||
self.reject_rule_update_for_bound_port(context, policy)
|
||||
self.driver_manager.call(qos_consts.UPDATE_POLICY_PRECOMMIT,
|
||||
context, policy)
|
||||
@ -977,7 +976,7 @@ class QoSPlugin(qos.QoSPluginBase):
|
||||
policy.obj_load_attr('rules')
|
||||
if rule.rule_type in (
|
||||
qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH,
|
||||
qos_constants.RULE_TYPE_MINIMUM_PACKET_RATE):
|
||||
qos_consts.RULE_TYPE_MINIMUM_PACKET_RATE):
|
||||
self.reject_rule_update_for_bound_port(context, policy)
|
||||
self.driver_manager.call(qos_consts.UPDATE_POLICY_PRECOMMIT,
|
||||
context, policy)
|
||||
|
@ -25,7 +25,6 @@ from neutron.objects import ports as port_obj
|
||||
from neutron.objects.qos import binding
|
||||
from neutron.objects.qos import policy
|
||||
from neutron.objects.qos import rule
|
||||
from neutron.services.qos import constants as q_consts
|
||||
from neutron.tests.unit.objects import test_base
|
||||
from neutron.tests.unit import testlib_api
|
||||
|
||||
@ -34,8 +33,8 @@ RULE_OBJ_CLS = {
|
||||
qos_consts.RULE_TYPE_BANDWIDTH_LIMIT: rule.QosBandwidthLimitRule,
|
||||
qos_consts.RULE_TYPE_DSCP_MARKING: rule.QosDscpMarkingRule,
|
||||
qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH: rule.QosMinimumBandwidthRule,
|
||||
q_consts.RULE_TYPE_PACKET_RATE_LIMIT: rule.QosPacketRateLimitRule,
|
||||
q_consts.RULE_TYPE_MINIMUM_PACKET_RATE: rule.QosMinimumPacketRateRule,
|
||||
qos_consts.RULE_TYPE_PACKET_RATE_LIMIT: rule.QosPacketRateLimitRule,
|
||||
qos_consts.RULE_TYPE_MINIMUM_PACKET_RATE: rule.QosMinimumPacketRateRule,
|
||||
}
|
||||
|
||||
|
||||
@ -186,8 +185,8 @@ class QosPolicyDbObjectTestCase(test_base.BaseDbObjectTestCase,
|
||||
if (obj_cls.rule_type in [
|
||||
qos_consts.RULE_TYPE_BANDWIDTH_LIMIT,
|
||||
qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH,
|
||||
q_consts.RULE_TYPE_PACKET_RATE_LIMIT,
|
||||
q_consts.RULE_TYPE_MINIMUM_PACKET_RATE] and
|
||||
qos_consts.RULE_TYPE_PACKET_RATE_LIMIT,
|
||||
qos_consts.RULE_TYPE_MINIMUM_PACKET_RATE] and
|
||||
bwlimit_direction is not None):
|
||||
rule_fields['direction'] = bwlimit_direction
|
||||
rule_obj = obj_cls(self.context, **rule_fields)
|
||||
@ -480,7 +479,7 @@ class QosPolicyDbObjectTestCase(test_base.BaseDbObjectTestCase,
|
||||
[qos_consts.RULE_TYPE_BANDWIDTH_LIMIT,
|
||||
qos_consts.RULE_TYPE_DSCP_MARKING,
|
||||
qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH,
|
||||
q_consts.RULE_TYPE_PACKET_RATE_LIMIT], reload_rules=True,
|
||||
qos_consts.RULE_TYPE_PACKET_RATE_LIMIT], reload_rules=True,
|
||||
bwlimit_direction=lib_consts.INGRESS_DIRECTION)
|
||||
policy_obj_v1_8 = self._policy_through_version(policy_obj, '1.8')
|
||||
|
||||
@ -494,8 +493,8 @@ class QosPolicyDbObjectTestCase(test_base.BaseDbObjectTestCase,
|
||||
[qos_consts.RULE_TYPE_BANDWIDTH_LIMIT,
|
||||
qos_consts.RULE_TYPE_DSCP_MARKING,
|
||||
qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH,
|
||||
q_consts.RULE_TYPE_PACKET_RATE_LIMIT,
|
||||
q_consts.RULE_TYPE_MINIMUM_PACKET_RATE], reload_rules=True,
|
||||
qos_consts.RULE_TYPE_PACKET_RATE_LIMIT,
|
||||
qos_consts.RULE_TYPE_MINIMUM_PACKET_RATE], reload_rules=True,
|
||||
bwlimit_direction=lib_consts.INGRESS_DIRECTION)
|
||||
policy_obj_v1_9 = self._policy_through_version(policy_obj, '1.9')
|
||||
|
||||
|
@ -18,7 +18,6 @@ from oslo_versionedobjects import exception
|
||||
|
||||
from neutron.objects.qos import policy
|
||||
from neutron.objects.qos import rule
|
||||
from neutron.services.qos import constants as qos_constants
|
||||
from neutron.tests import base as neutron_test_base
|
||||
from neutron.tests.unit.objects import test_base
|
||||
from neutron.tests.unit import testlib_api
|
||||
@ -251,7 +250,7 @@ class QosPacketRateLimitRuleObjectTestCase(test_base.BaseObjectIfaceTestCase):
|
||||
def test_to_dict_returns_type(self):
|
||||
obj = rule.QosPacketRateLimitRule(self.context, **self.db_objs[0])
|
||||
dict_ = obj.to_dict()
|
||||
self.assertEqual(qos_constants.RULE_TYPE_PACKET_RATE_LIMIT,
|
||||
self.assertEqual(qos_consts.RULE_TYPE_PACKET_RATE_LIMIT,
|
||||
dict_['type'])
|
||||
|
||||
def test_duplicate_rules(self):
|
||||
@ -300,7 +299,7 @@ class QosMinimumPacketRateRuleObjectTestCase(
|
||||
def test_to_dict_returns_type(self):
|
||||
obj = rule.QosMinimumPacketRateRule(self.context, **self.db_objs[0])
|
||||
dict_ = obj.to_dict()
|
||||
self.assertEqual(qos_constants.RULE_TYPE_MINIMUM_PACKET_RATE,
|
||||
self.assertEqual(qos_consts.RULE_TYPE_MINIMUM_PACKET_RATE,
|
||||
dict_['type'])
|
||||
|
||||
def test_duplicate_rules(self):
|
||||
|
@ -22,7 +22,6 @@ from oslo_config import cfg
|
||||
|
||||
from neutron import manager
|
||||
from neutron.objects.qos import rule_type
|
||||
from neutron.services.qos import constants as qos_constants
|
||||
from neutron.services.qos import qos_plugin
|
||||
from neutron.tests import base as test_base
|
||||
|
||||
@ -79,11 +78,11 @@ class QosRuleTypeObjectTestCase(test_base.BaseTestCase):
|
||||
|
||||
def test_get_objects(self):
|
||||
rule_types_mock = mock.PropertyMock(
|
||||
return_value=set(qos_constants.VALID_RULE_TYPES))
|
||||
return_value=set(qos_consts.VALID_RULE_TYPES))
|
||||
with mock.patch.object(qos_plugin.QoSPlugin, 'supported_rule_types',
|
||||
new_callable=rule_types_mock):
|
||||
types = rule_type.QosRuleType.get_objects()
|
||||
self.assertEqual(sorted(qos_constants.VALID_RULE_TYPES),
|
||||
self.assertEqual(sorted(qos_consts.VALID_RULE_TYPES),
|
||||
sorted(type_['type'] for type_ in types))
|
||||
|
||||
def test_wrong_type(self):
|
||||
|
@ -15,7 +15,6 @@
|
||||
import os
|
||||
import pprint
|
||||
|
||||
from neutron_lib.utils import test
|
||||
from oslo_versionedobjects import fixture
|
||||
|
||||
from neutron import objects
|
||||
@ -89,7 +88,7 @@ object_data = {
|
||||
'QosMinimumPacketRateRule': '1.5-d0516c55aa2f310a2646c7d243cb8620',
|
||||
'QosPacketRateLimitRule': '1.5-18411fa95f54602b8c8a5da2d3194b31',
|
||||
'QosPolicyRBAC': '1.1-192845c5ed0718e1c54fac36936fcd7d',
|
||||
'QosRuleType': '1.5-56b25ec81e27aa5c8238b8c43e88aed6',
|
||||
'QosRuleType': '1.5-ea51a164013e05d5956d8bf538622b33',
|
||||
'QosRuleTypeDriver': '1.0-7d8cb9f0ef661ac03700eae97118e3db',
|
||||
'QosPolicy': '1.10-4adb0cde3102c10d8970ec9487fd7fe7',
|
||||
'QosPolicyDefault': '1.0-59e5060eedb1f06dd0935a244d27d11c',
|
||||
@ -137,8 +136,6 @@ class TestObjectVersions(test_base.BaseTestCase):
|
||||
# before validating the hashes
|
||||
objects.register_objects()
|
||||
|
||||
@test.unstable_test('Re-enable this test once n-lib 2.17.0 is released '
|
||||
'and QosRuleType hash type fixed')
|
||||
def test_versions(self):
|
||||
checker = fixture.ObjectVersionChecker(
|
||||
base.NeutronObjectRegistry.obj_classes())
|
||||
|
@ -39,7 +39,6 @@ from neutron.objects import network as network_object
|
||||
from neutron.objects import ports as ports_object
|
||||
from neutron.objects.qos import policy as policy_object
|
||||
from neutron.objects.qos import rule as rule_object
|
||||
from neutron.services.qos import constants as qos_constants
|
||||
from neutron.services.qos import qos_plugin
|
||||
from neutron.tests.unit.db import test_db_base_plugin_v2
|
||||
from neutron.tests.unit.services.qos import base
|
||||
@ -1310,12 +1309,12 @@ class TestQosPlugin(base.BaseQosTestCase):
|
||||
|
||||
def test_get_rule_types(self):
|
||||
rule_types_mock = mock.PropertyMock(
|
||||
return_value=qos_constants.VALID_RULE_TYPES)
|
||||
return_value=qos_consts.VALID_RULE_TYPES)
|
||||
filters = {'type': 'type_id'}
|
||||
with mock.patch.object(qos_plugin.QoSPlugin, 'supported_rule_types',
|
||||
new_callable=rule_types_mock):
|
||||
types = self.qos_plugin.get_rule_types(self.ctxt, filters=filters)
|
||||
self.assertEqual(sorted(qos_constants.VALID_RULE_TYPES),
|
||||
self.assertEqual(sorted(qos_consts.VALID_RULE_TYPES),
|
||||
sorted(type_['type'] for type_ in types))
|
||||
|
||||
@mock.patch('neutron.objects.ports.Port')
|
||||
@ -1524,9 +1523,9 @@ class TestQosPlugin(base.BaseQosTestCase):
|
||||
return_value=drivers_details
|
||||
):
|
||||
rule_type_details = self.qos_plugin.get_rule_type(
|
||||
admin_ctxt, qos_constants.RULE_TYPE_PACKET_RATE_LIMIT)
|
||||
admin_ctxt, qos_consts.RULE_TYPE_PACKET_RATE_LIMIT)
|
||||
self.assertEqual(
|
||||
qos_constants.RULE_TYPE_PACKET_RATE_LIMIT,
|
||||
qos_consts.RULE_TYPE_PACKET_RATE_LIMIT,
|
||||
rule_type_details['type'])
|
||||
self.assertEqual(
|
||||
drivers_details, rule_type_details['drivers'])
|
||||
@ -1535,7 +1534,7 @@ class TestQosPlugin(base.BaseQosTestCase):
|
||||
self.assertRaises(
|
||||
lib_exc.NotAuthorized,
|
||||
self.qos_plugin.get_rule_type,
|
||||
self.ctxt, qos_constants.RULE_TYPE_PACKET_RATE_LIMIT)
|
||||
self.ctxt, qos_consts.RULE_TYPE_PACKET_RATE_LIMIT)
|
||||
|
||||
def test_create_min_pps_rule_on_bound_port(self):
|
||||
_policy = self._get_policy()
|
||||
@ -1832,9 +1831,9 @@ class TestQosPlugin(base.BaseQosTestCase):
|
||||
return_value=drivers_details
|
||||
):
|
||||
rule_type_details = self.qos_plugin.get_rule_type(
|
||||
admin_ctxt, qos_constants.RULE_TYPE_MINIMUM_PACKET_RATE)
|
||||
admin_ctxt, qos_consts.RULE_TYPE_MINIMUM_PACKET_RATE)
|
||||
self.assertEqual(
|
||||
qos_constants.RULE_TYPE_MINIMUM_PACKET_RATE,
|
||||
qos_consts.RULE_TYPE_MINIMUM_PACKET_RATE,
|
||||
rule_type_details['type'])
|
||||
self.assertEqual(
|
||||
drivers_details, rule_type_details['drivers'])
|
||||
@ -1843,7 +1842,7 @@ class TestQosPlugin(base.BaseQosTestCase):
|
||||
self.assertRaises(
|
||||
lib_exc.NotAuthorized,
|
||||
self.qos_plugin.get_rule_type,
|
||||
self.ctxt, qos_constants.RULE_TYPE_MINIMUM_PACKET_RATE)
|
||||
self.ctxt, qos_consts.RULE_TYPE_MINIMUM_PACKET_RATE)
|
||||
|
||||
|
||||
class QoSRuleAliasTestExtensionManager(object):
|
||||
|
@ -16,7 +16,7 @@ Jinja2>=2.10 # BSD License (3 clause)
|
||||
keystonemiddleware>=5.1.0 # Apache-2.0
|
||||
netaddr>=0.7.18 # BSD
|
||||
netifaces>=0.10.4 # MIT
|
||||
neutron-lib>=2.16.0 # Apache-2.0
|
||||
neutron-lib>=2.17.0 # Apache-2.0
|
||||
python-neutronclient>=6.7.0 # Apache-2.0
|
||||
tenacity>=6.0.0 # Apache-2.0
|
||||
SQLAlchemy>=1.4.23 # MIT
|
||||
|
Loading…
Reference in New Issue
Block a user