Remove six usage
This repo does not support Python 2 anymore, so we don't need six for compatibility between Python2 and 3, convert six usage to Python 3 code. Change-Id: Ibc743a552a43147153dd0ca3a46ab8d977c7ca0d
This commit is contained in:
parent
8ab6fbd0cf
commit
a85d874748
|
@ -22,7 +22,6 @@ import string
|
||||||
import iso8601
|
import iso8601
|
||||||
from muranodashboard.dynamic_ui import yaql_expression
|
from muranodashboard.dynamic_ui import yaql_expression
|
||||||
import pytz
|
import pytz
|
||||||
import six
|
|
||||||
import yaql
|
import yaql
|
||||||
|
|
||||||
from django.template import Context
|
from django.template import Context
|
||||||
|
@ -78,7 +77,7 @@ class Bunch(object):
|
||||||
object-like attribute access.
|
object-like attribute access.
|
||||||
"""
|
"""
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
for key, value in six.iteritems(kwargs):
|
for key, value in kwargs.items():
|
||||||
setattr(self, key, value)
|
setattr(self, key, value)
|
||||||
|
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
|
@ -94,7 +93,7 @@ class Bunch(object):
|
||||||
return hasattr(self, item)
|
return hasattr(self, item)
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return iter(six.itervalues(self.__dict__))
|
return iter(self.__dict__.values())
|
||||||
|
|
||||||
|
|
||||||
class BlankFormatter(string.Formatter):
|
class BlankFormatter(string.Formatter):
|
||||||
|
|
|
@ -17,7 +17,6 @@ from collections import defaultdict
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
import six
|
|
||||||
from yaql import legacy
|
from yaql import legacy
|
||||||
|
|
||||||
import muranodashboard.dynamic_ui.fields as fields
|
import muranodashboard.dynamic_ui.fields as fields
|
||||||
|
@ -88,7 +87,7 @@ def _collect_fields(field_specs, form_name, service):
|
||||||
return key, fields.RawProperty(key, spec)
|
return key, fields.RawProperty(key, spec)
|
||||||
elif isinstance(spec, dict):
|
elif isinstance(spec, dict):
|
||||||
items = []
|
items = []
|
||||||
for k, v in six.iteritems(spec):
|
for k, v in spec.items():
|
||||||
k = helpers.decamelize(k)
|
k = helpers.decamelize(k)
|
||||||
new_key, v = parse_spec(v, keys + [k])
|
new_key, v = parse_spec(v, keys + [k])
|
||||||
if new_key:
|
if new_key:
|
||||||
|
@ -97,8 +96,7 @@ def _collect_fields(field_specs, form_name, service):
|
||||||
return key, dict(items)
|
return key, dict(items)
|
||||||
elif isinstance(spec, list):
|
elif isinstance(spec, list):
|
||||||
return key, [parse_spec(_spec, keys)[1] for _spec in spec]
|
return key, [parse_spec(_spec, keys)[1] for _spec in spec]
|
||||||
elif isinstance(spec,
|
elif isinstance(spec, str) and helpers.is_localizable(keys):
|
||||||
six.string_types) and helpers.is_localizable(keys):
|
|
||||||
return key, spec
|
return key, spec
|
||||||
else:
|
else:
|
||||||
if key == 'hidden':
|
if key == 'hidden':
|
||||||
|
@ -154,7 +152,7 @@ class UpdatableFieldsForm(forms.Form):
|
||||||
# collections.OrderedDict for Django >= 1.7
|
# collections.OrderedDict for Django >= 1.7
|
||||||
updated_fields = self.fields.__class__()
|
updated_fields = self.fields.__class__()
|
||||||
|
|
||||||
for name, field in six.iteritems(self.fields):
|
for name, field in self.fields.items():
|
||||||
updated_fields[name] = field
|
updated_fields[name] = field
|
||||||
if isinstance(field, fields.PasswordField) and field.confirm_input:
|
if isinstance(field, fields.PasswordField) and field.confirm_input:
|
||||||
if not field.has_clone and field.original:
|
if not field.has_clone and field.original:
|
||||||
|
@ -163,7 +161,7 @@ class UpdatableFieldsForm(forms.Form):
|
||||||
|
|
||||||
self.fields = updated_fields
|
self.fields = updated_fields
|
||||||
|
|
||||||
for name, field in six.iteritems(self.fields):
|
for name, field in self.fields.items():
|
||||||
if hasattr(field, 'update'):
|
if hasattr(field, 'update'):
|
||||||
field.update(self.initial, form=self, request=request)
|
field.update(self.initial, form=self, request=request)
|
||||||
if not field.required:
|
if not field.required:
|
||||||
|
@ -183,7 +181,7 @@ class ServiceConfigurationForm(UpdatableFieldsForm):
|
||||||
self.update_fields()
|
self.update_fields()
|
||||||
|
|
||||||
def finalize_fields(self):
|
def finalize_fields(self):
|
||||||
for field_name, field in six.iteritems(self.fields):
|
for field_name, field in self.fields.items():
|
||||||
field.form = self
|
field.form = self
|
||||||
|
|
||||||
validators = []
|
validators = []
|
||||||
|
@ -210,7 +208,7 @@ class ServiceConfigurationForm(UpdatableFieldsForm):
|
||||||
if error_messages:
|
if error_messages:
|
||||||
raise forms.ValidationError(error_messages)
|
raise forms.ValidationError(error_messages)
|
||||||
|
|
||||||
for name, field in six.iteritems(self.fields):
|
for name, field in self.fields.items():
|
||||||
if (isinstance(field, fields.PasswordField) and
|
if (isinstance(field, fields.PasswordField) and
|
||||||
getattr(field, 'enabled', True) and
|
getattr(field, 'enabled', True) and
|
||||||
field.confirm_input):
|
field.confirm_input):
|
||||||
|
|
|
@ -18,8 +18,6 @@ import string
|
||||||
import types
|
import types
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from django.core import validators
|
from django.core import validators
|
||||||
|
|
||||||
_LOCALIZABLE_KEYS = set(['label', 'help_text', 'error_messages'])
|
_LOCALIZABLE_KEYS = set(['label', 'help_text', 'error_messages'])
|
||||||
|
@ -55,7 +53,7 @@ def decamelize(name):
|
||||||
|
|
||||||
def explode(_string):
|
def explode(_string):
|
||||||
"""Explodes a string into a list of one-character strings."""
|
"""Explodes a string into a list of one-character strings."""
|
||||||
if not _string or not isinstance(_string, six.string_types):
|
if not _string or not isinstance(_string, str):
|
||||||
return _string
|
return _string
|
||||||
else:
|
else:
|
||||||
return list(_string)
|
return list(_string)
|
||||||
|
@ -85,7 +83,7 @@ def recursive_apply(predicate, transformer, value, *args):
|
||||||
if predicate(val, *args):
|
if predicate(val, *args):
|
||||||
return rec(transformer(val, *args))
|
return rec(transformer(val, *args))
|
||||||
elif isinstance(val, dict):
|
elif isinstance(val, dict):
|
||||||
return dict((rec(k), rec(v)) for (k, v) in six.iteritems(val))
|
return dict((rec(k), rec(v)) for (k, v) in val.items())
|
||||||
elif isinstance(val, list):
|
elif isinstance(val, list):
|
||||||
return [rec(v) for v in val]
|
return [rec(v) for v in val]
|
||||||
elif isinstance(val, tuple):
|
elif isinstance(val, tuple):
|
||||||
|
@ -115,7 +113,7 @@ def insert_hidden_ids(application):
|
||||||
|
|
||||||
def rec(val):
|
def rec(val):
|
||||||
if isinstance(val, dict):
|
if isinstance(val, dict):
|
||||||
return dict(wrap(k, v) for k, v in six.iteritems(val))
|
return dict(wrap(k, v) for k, v in val.items())
|
||||||
elif isinstance(val, list):
|
elif isinstance(val, list):
|
||||||
return [rec(v) for v in val]
|
return [rec(v) for v in val]
|
||||||
elif isinstance(val, ObjectID):
|
elif isinstance(val, ObjectID):
|
||||||
|
@ -154,10 +152,10 @@ def int2base(x, base):
|
||||||
def to_str(text):
|
def to_str(text):
|
||||||
if not isinstance(text, str):
|
if not isinstance(text, str):
|
||||||
# unicode in python2
|
# unicode in python2
|
||||||
if isinstance(text, six.text_type):
|
if isinstance(text, str):
|
||||||
text = text.encode('utf-8')
|
text = text.encode('utf-8')
|
||||||
# bytes in python3
|
# bytes in python3
|
||||||
elif isinstance(text, six.binary_type):
|
elif isinstance(text, bytes):
|
||||||
text = text.decode('utf-8')
|
text = text.decode('utf-8')
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ import semantic_version
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
import six
|
|
||||||
from yaql import legacy
|
from yaql import legacy
|
||||||
|
|
||||||
from muranodashboard import api
|
from muranodashboard import api
|
||||||
|
@ -75,7 +74,7 @@ class Service(object):
|
||||||
|
|
||||||
params = parameters or {}
|
params = parameters or {}
|
||||||
self.parameters = {}
|
self.parameters = {}
|
||||||
for k, v in six.iteritems(params):
|
for k, v in params.items():
|
||||||
if not k or not k[0].isalpha():
|
if not k or not k[0].isalpha():
|
||||||
continue
|
continue
|
||||||
v = helpers.evaluate(v, self.context)
|
v = helpers.evaluate(v, self.context)
|
||||||
|
@ -83,7 +82,7 @@ class Service(object):
|
||||||
self.context[k] = v
|
self.context[k] = v
|
||||||
|
|
||||||
self.forms = []
|
self.forms = []
|
||||||
for key, value in six.iteritems(kwargs):
|
for key, value in kwargs.items():
|
||||||
setattr(self, key, value)
|
setattr(self, key, value)
|
||||||
|
|
||||||
for form in forms:
|
for form in forms:
|
||||||
|
@ -109,8 +108,8 @@ class Service(object):
|
||||||
_region=None):
|
_region=None):
|
||||||
import muranodashboard.dynamic_ui.forms as forms
|
import muranodashboard.dynamic_ui.forms as forms
|
||||||
|
|
||||||
class Form(six.with_metaclass(forms.DynamicFormMetaclass,
|
class Form(forms.ServiceConfigurationForm,
|
||||||
forms.ServiceConfigurationForm)):
|
metaclass=forms.DynamicFormMetaclass):
|
||||||
service = self
|
service = self
|
||||||
name = _name
|
name = _name
|
||||||
verbose_name = _verbose_name
|
verbose_name = _verbose_name
|
||||||
|
@ -122,7 +121,7 @@ class Service(object):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def extract_form_data(data):
|
def extract_form_data(data):
|
||||||
for form_name, form_data in six.iteritems(data):
|
for form_name, form_data in data.items():
|
||||||
return (form_name, form_data['fields'],
|
return (form_name, form_data['fields'],
|
||||||
form_data.get('validators', []), form_data.get('region'))
|
form_data.get('validators', []), form_data.get('region'))
|
||||||
|
|
||||||
|
@ -131,7 +130,7 @@ class Service(object):
|
||||||
context['$'] = self.cleaned_data
|
context['$'] = self.cleaned_data
|
||||||
context['$forms'] = self.cleaned_data
|
context['$forms'] = self.cleaned_data
|
||||||
|
|
||||||
for name, template in six.iteritems(self.templates):
|
for name, template in self.templates.items():
|
||||||
context[name] = template
|
context[name] = template
|
||||||
if semantic_version.Version.coerce(self.spec_version) \
|
if semantic_version.Version.coerce(self.spec_version) \
|
||||||
>= semantic_version.Version.coerce('2.2'):
|
>= semantic_version.Version.coerce('2.2'):
|
||||||
|
@ -171,7 +170,7 @@ def import_app(request, app_id):
|
||||||
app_version = ui_desc.pop('Version', version.LATEST_FORMAT_VERSION)
|
app_version = ui_desc.pop('Version', version.LATEST_FORMAT_VERSION)
|
||||||
version.check_version(app_version)
|
version.check_version(app_version)
|
||||||
service = dict(
|
service = dict(
|
||||||
(helpers.decamelize(k), v) for (k, v) in six.iteritems(ui_desc))
|
(helpers.decamelize(k), v) for (k, v) in ui_desc.items())
|
||||||
parameters = service.pop('parameters', {})
|
parameters = service.pop('parameters', {})
|
||||||
parameters_source = service.pop('parameters_source', None)
|
parameters_source = service.pop('parameters_source', None)
|
||||||
if parameters_source is not None:
|
if parameters_source is not None:
|
||||||
|
@ -277,7 +276,7 @@ def get_app_field_descriptions(request, app_id, index):
|
||||||
form_cls = app.forms[index]
|
form_cls = app.forms[index]
|
||||||
descriptions = []
|
descriptions = []
|
||||||
no_field_descriptions = []
|
no_field_descriptions = []
|
||||||
for name, field in six.iteritems(form_cls.base_fields):
|
for name, field in form_cls.base_fields.items():
|
||||||
title = field.description_title
|
title = field.description_title
|
||||||
description = field.description
|
description = field.description
|
||||||
if description:
|
if description:
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import six
|
|
||||||
|
|
||||||
import yaql
|
import yaql
|
||||||
from yaql.language import exceptions as yaql_exc
|
from yaql.language import exceptions as yaql_exc
|
||||||
|
@ -45,7 +44,7 @@ class YaqlExpression(object):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def match(expr):
|
def match(expr):
|
||||||
if not isinstance(expr, six.string_types):
|
if not isinstance(expr, str):
|
||||||
return False
|
return False
|
||||||
if re.match('^[\s\w\d.:]*$', expr):
|
if re.match('^[\s\w\d.:]*$', expr):
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -18,8 +18,6 @@ from django.contrib.staticfiles.templatetags.staticfiles import static
|
||||||
from django.template import loader
|
from django.template import loader
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from muranodashboard.api import packages as pkg_cli
|
from muranodashboard.api import packages as pkg_cli
|
||||||
from muranodashboard.environments import consts
|
from muranodashboard.environments import consts
|
||||||
|
|
||||||
|
@ -151,7 +149,7 @@ def _create_ext_network_node(name):
|
||||||
|
|
||||||
|
|
||||||
def _convert_lists(node_data):
|
def _convert_lists(node_data):
|
||||||
for key, value in six.iteritems(node_data):
|
for key, value in node_data.items():
|
||||||
if isinstance(value, list) and all(
|
if isinstance(value, list) and all(
|
||||||
map(lambda s: not isinstance(s, (dict, list)), value)):
|
map(lambda s: not isinstance(s, (dict, list)), value)):
|
||||||
new_value = ', '.join(str(v) for v in value)
|
new_value = ', '.join(str(v) for v in value)
|
||||||
|
@ -214,7 +212,7 @@ def render_d3_data(request, environment):
|
||||||
node_type = node_data.get('?', {}).get('type')
|
node_type = node_data.get('?', {}).get('type')
|
||||||
node_id = node_data.get('?', {}).get('id')
|
node_id = node_data.get('?', {}).get('id')
|
||||||
atomics, containers = _split_seq_by_predicate(
|
atomics, containers = _split_seq_by_predicate(
|
||||||
six.iteritems(node_data), _is_atomic)
|
node_data.items(), _is_atomic)
|
||||||
if node_type and node_data is not parent_node:
|
if node_type and node_data is not parent_node:
|
||||||
node = _create_empty_node()
|
node = _create_empty_node()
|
||||||
node_refs[node_id] = node
|
node_refs[node_id] = node
|
||||||
|
@ -249,7 +247,7 @@ def render_d3_data(request, environment):
|
||||||
node = node_refs[node_id]
|
node = node_refs[node_id]
|
||||||
|
|
||||||
atomics, containers = _split_seq_by_predicate(
|
atomics, containers = _split_seq_by_predicate(
|
||||||
six.iteritems(node_data), _is_atomic)
|
node_data.items(), _is_atomic)
|
||||||
|
|
||||||
# the actual second pass of node linking
|
# the actual second pass of node linking
|
||||||
if parent_node is not None:
|
if parent_node is not None:
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import sys
|
import urllib.parse as urlparse
|
||||||
|
|
||||||
from django.core.files import storage
|
from django.core.files import storage
|
||||||
from django import http
|
from django import http
|
||||||
|
@ -37,8 +37,6 @@ from muranoclient.common import utils as muranoclient_utils
|
||||||
from openstack_dashboard.api import glance
|
from openstack_dashboard.api import glance
|
||||||
from openstack_dashboard.api import keystone
|
from openstack_dashboard.api import keystone
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
import six
|
|
||||||
import six.moves.urllib.parse as urlparse
|
|
||||||
|
|
||||||
from muranodashboard import api
|
from muranodashboard import api
|
||||||
from muranodashboard.api import packages as pkg_api
|
from muranodashboard.api import packages as pkg_api
|
||||||
|
@ -267,7 +265,7 @@ class ImportBundleWizard(horizon_views.PageTitleMixin, views.ModalFormMixin,
|
||||||
continue
|
continue
|
||||||
|
|
||||||
reqs = package.requirements(base_url=base_url)
|
reqs = package.requirements(base_url=base_url)
|
||||||
for dep_name, dep_package in six.iteritems(reqs):
|
for dep_name, dep_package in reqs.items():
|
||||||
_ensure_images(dep_name, dep_package,
|
_ensure_images(dep_name, dep_package,
|
||||||
self.request)
|
self.request)
|
||||||
|
|
||||||
|
@ -309,7 +307,7 @@ class ImportBundleWizard(horizon_views.PageTitleMixin, views.ModalFormMixin,
|
||||||
msg = _('Bundle successfully imported.')
|
msg = _('Bundle successfully imported.')
|
||||||
LOG.info(msg)
|
LOG.info(msg)
|
||||||
messages.success(self.request, msg)
|
messages.success(self.request, msg)
|
||||||
return http.HttpResponseRedirect(six.text_type(redirect))
|
return http.HttpResponseRedirect(str(redirect))
|
||||||
|
|
||||||
|
|
||||||
class ImportPackageWizard(horizon_views.PageTitleMixin, views.ModalFormMixin,
|
class ImportPackageWizard(horizon_views.PageTitleMixin, views.ModalFormMixin,
|
||||||
|
@ -408,10 +406,9 @@ class ImportPackageWizard(horizon_views.PageTitleMixin, views.ModalFormMixin,
|
||||||
msg = _('Package parameters successfully updated.')
|
msg = _('Package parameters successfully updated.')
|
||||||
LOG.info(msg)
|
LOG.info(msg)
|
||||||
messages.success(self.request, msg)
|
messages.success(self.request, msg)
|
||||||
return http.HttpResponseRedirect(six.text_type(redirect))
|
return http.HttpResponseRedirect(str(redirect))
|
||||||
|
|
||||||
def _handle_exception(self, original_e):
|
def _handle_exception(self, original_e):
|
||||||
exc_info = sys.exc_info()
|
|
||||||
reason = ''
|
reason = ''
|
||||||
if hasattr(original_e, 'details'):
|
if hasattr(original_e, 'details'):
|
||||||
try:
|
try:
|
||||||
|
@ -419,10 +416,7 @@ class ImportPackageWizard(horizon_views.PageTitleMixin, views.ModalFormMixin,
|
||||||
if error:
|
if error:
|
||||||
reason = error.get('message')
|
reason = error.get('message')
|
||||||
except ValueError:
|
except ValueError:
|
||||||
# Let horizon operate with original exception
|
raise
|
||||||
six.reraise(original_e.__class__,
|
|
||||||
original_e.__class__(original_e),
|
|
||||||
exc_info[2])
|
|
||||||
msg = _('Uploading package failed. {0}').format(reason)
|
msg = _('Uploading package failed. {0}').format(reason)
|
||||||
LOG.exception(msg)
|
LOG.exception(msg)
|
||||||
exceptions.handle(
|
exceptions.handle(
|
||||||
|
@ -477,7 +471,7 @@ class ImportPackageWizard(horizon_views.PageTitleMixin, views.ModalFormMixin,
|
||||||
original_package = reqs.pop(name)
|
original_package = reqs.pop(name)
|
||||||
step_data['dependencies'] = []
|
step_data['dependencies'] = []
|
||||||
step_data['images'] = []
|
step_data['images'] = []
|
||||||
for dep_name, dep_package in six.iteritems(reqs):
|
for dep_name, dep_package in reqs.items():
|
||||||
_ensure_images(dep_name, dep_package, self.request, step_data)
|
_ensure_images(dep_name, dep_package, self.request, step_data)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -10,10 +10,11 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from urllib import parse
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django import template
|
from django import template
|
||||||
from django.template import defaultfilters
|
from django.template import defaultfilters
|
||||||
from six.moves.urllib import parse as urlparse
|
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
@ -38,4 +39,4 @@ def last_half(seq):
|
||||||
@register.filter(name='unquote')
|
@register.filter(name='unquote')
|
||||||
@defaultfilters.stringfilter
|
@defaultfilters.stringfilter
|
||||||
def unquote_raw(value):
|
def unquote_raw(value):
|
||||||
return urlparse.unquote(value)
|
return parse.unquote(value)
|
||||||
|
|
|
@ -485,7 +485,7 @@ class TestImportPackageWizard(helpers.APITestCase):
|
||||||
mock_json.loads.side_effect = ValueError('test_error_message')
|
mock_json.loads.side_effect = ValueError('test_error_message')
|
||||||
original_e = ValueError('original_error_message')
|
original_e = ValueError('original_error_message')
|
||||||
setattr(original_e, 'details', 'error_details')
|
setattr(original_e, 'details', 'error_details')
|
||||||
with self.assertRaisesRegex(ValueError, 'original_error_message'):
|
with self.assertRaisesRegex(ValueError, 'test_error_message'):
|
||||||
self.import_pkg_wizard._handle_exception(original_e)
|
self.import_pkg_wizard._handle_exception(original_e)
|
||||||
|
|
||||||
@mock.patch.object(views, 'glance')
|
@mock.patch.object(views, 'glance')
|
||||||
|
|
|
@ -6,7 +6,6 @@ pbr!=2.1.0,>=2.0.0 # Apache-2.0
|
||||||
beautifulsoup4>=4.6.0 # MIT
|
beautifulsoup4>=4.6.0 # MIT
|
||||||
django-formtools>=2.2 # BSD
|
django-formtools>=2.2 # BSD
|
||||||
iso8601>=0.1.11 # MIT
|
iso8601>=0.1.11 # MIT
|
||||||
six>=1.10.0 # MIT
|
|
||||||
python-muranoclient>=0.8.2 # Apache-2.0
|
python-muranoclient>=0.8.2 # Apache-2.0
|
||||||
pytz>=2013.6 # MIT
|
pytz>=2013.6 # MIT
|
||||||
PyYAML>=3.12 # MIT
|
PyYAML>=3.12 # MIT
|
||||||
|
|
Loading…
Reference in New Issue