Make monasca-ui python3 compatible

In order to make monasca-ui python3 compatible this
patch set:
- Add six to requirements.txt
- Add py35 to tox.ini
- Replace dict.iteritems() with six.iteritems(dict)
- Replace prit msg with print(msg)
- Replace unicode with six.text_type(msg)
- Replaces urlparse with six.moves.urllib
- Python 3 getting the keys() of a dict returns
  a dict_keys object instead of a list
- python 2.x calling keys makes a copy of the key
  that you can iterate over while modifying the dict.
  This doesn't work in python 3.x because keys
  returns an iterator instead of a list.
  Another way is to use list to force a copy of the keys
  to be made.

Story: 2000975
Task: 4129

Signed-off-by: Charles Short <zulcss@gmail.com>

Change-Id: Ibc644a734edceea0b36f2df2c73300d1e4db925f
This commit is contained in:
Charles Short 2018-03-26 14:05:14 +00:00
parent c0ab99a070
commit 4cfdc71d70
9 changed files with 46 additions and 40 deletions

View File

@ -19,6 +19,7 @@ from django.core.paginator import Paginator, EmptyPage
from django.core.urlresolvers import reverse_lazy, reverse # noqa from django.core.urlresolvers import reverse_lazy, reverse # noqa
from django.utils.translation import ugettext as _ # noqa from django.utils.translation import ugettext as _ # noqa
from django.views.generic import TemplateView # noqa from django.views.generic import TemplateView # noqa
import six
from horizon import exceptions from horizon import exceptions
from horizon import forms from horizon import forms
@ -154,7 +155,7 @@ class AlarmDetailView(TemplateView):
except exc.HttpError: except exc.HttpError:
msg = _("Notification %s has already been deleted.") % id msg = _("Notification %s has already been deleted.") % id
notifications.append({"id": id, notifications.append({"id": id,
"name": unicode(msg), "name": six.text_type(msg),
"type": "", "type": "",
"address": ""}) "address": ""})

View File

@ -19,6 +19,7 @@ from django import forms as django_forms
from django.template.loader import get_template from django.template.loader import get_template
from django.utils import html from django.utils import html
from django.utils.translation import ugettext_lazy as _ # noqa from django.utils.translation import ugettext_lazy as _ # noqa
import six
from horizon import exceptions from horizon import exceptions
from horizon import forms from horizon import forms
@ -116,7 +117,7 @@ class NotificationCreateWidget(forms.Select):
output = '<table id="notification_table" ' + \ output = '<table id="notification_table" ' + \
'class="table table-condensed">' 'class="table table-condensed">'
output += '<thead><tr><th>%s</th></tr></thead>' % \ output += '<thead><tr><th>%s</th></tr></thead>' % \
unicode(_("Name")) six.text_type(_("Name"))
if value: if value:
idx = 1 idx = 1
for notification in value: for notification in value:
@ -143,7 +144,7 @@ class NotificationCreateWidget(forms.Select):
output += '<td><a href="" id="remove_notif_button">X</a></td>' output += '<td><a href="" id="remove_notif_button">X</a></td>'
output += '</td></tr>' output += '</td></tr>'
output += '</table>' output += '</table>'
label = unicode(_("+ Add more")) label = six.text_type(_("+ Add more"))
output += '<a href="" id="add_notification_button">%s</a>' % (label) output += '<a href="" id="add_notification_button">%s</a>' % (label)
return html.format_html(output) return html.format_html(output)
@ -221,10 +222,10 @@ class BaseAlarmForm(forms.SelfHandlingForm):
if notification_choices: if notification_choices:
if len(notification_choices) > 1: if len(notification_choices) > 1:
notification_choices.insert( notification_choices.insert(
0, ("", unicode(_("Select Notification")))) 0, ("", six.text_type(_("Select Notification"))))
else: else:
notification_choices.insert( notification_choices.insert(
0, ("", unicode(_("No notifications available.")))) 0, ("", six.text_type(_("No notifications available."))))
self.fields['notifications'].choices = notification_choices self.fields['notifications'].choices = notification_choices

View File

@ -166,7 +166,7 @@ class GraphMetric(tables.LinkAction):
metric = datum['metrics'][0]['name'] metric = datum['metrics'][0]['name']
dimensions = datum['metrics'][0].get('dimensions', {}) dimensions = datum['metrics'][0].get('dimensions', {})
query = "?metric=%s" % metric query = "?metric=%s" % metric
for key, value in dimensions.iteritems(): for key, value in dimensions.items():
query += "&dim_%s=%s" % (key, value) query += "&dim_%s=%s" % (key, value)
except AttributeError: except AttributeError:
# Catches case where Grafana 2 is not enabled. # Catches case where Grafana 2 is not enabled.

View File

@ -25,6 +25,7 @@ from django.utils.dateparse import parse_datetime
from django.utils.translation import ugettext as _ # noqa from django.utils.translation import ugettext as _ # noqa
from django.utils.translation import ugettext_lazy from django.utils.translation import ugettext_lazy
from django.views.generic import View # noqa from django.views.generic import View # noqa
import six
from horizon import exceptions from horizon import exceptions
from horizon import forms from horizon import forms
@ -100,12 +101,12 @@ def generate_status(request):
service_alarms = alarms_by_service.setdefault(service, []) service_alarms = alarms_by_service.setdefault(service, [])
service_alarms.append(a) service_alarms.append(a)
for row in SERVICES: for row in SERVICES:
row['name'] = unicode(row['name']) row['name'] = six.text_type(row['name'])
for service in row['services']: for service in row['services']:
service_alarms = alarms_by_service.get(service['name'], []) service_alarms = alarms_by_service.get(service['name'], [])
service['class'] = get_status(service_alarms) service['class'] = get_status(service_alarms)
service['icon'] = get_icon(service['class']) service['icon'] = get_icon(service['class'])
service['display'] = unicode(service['display']) service['display'] = six.text_type(service['display'])
return SERVICES return SERVICES

View File

@ -43,7 +43,7 @@ class KibanaProxyViewTest(helpers.TestCase):
def test_get_relative_url_with_unicode(self): def test_get_relative_url_with_unicode(self):
"""Tests if it properly converts multibyte characters.""" """Tests if it properly converts multibyte characters."""
import urlparse from six.moves.urllib import parse as urlparse
self.view.request = self.request_factory.get( self.view.request = self.request_factory.get(
'/', data={'a': 1, 'b': 2} '/', data={'a': 1, 'b': 2}

View File

@ -16,8 +16,6 @@ import base64
import copy import copy
import json import json
import logging import logging
import urllib
import urllib2
from django import http from django import http
from django.contrib import messages from django.contrib import messages
@ -29,6 +27,8 @@ from django.views.decorators.csrf import csrf_exempt
from django.views.generic import TemplateView # noqa from django.views.generic import TemplateView # noqa
from openstack_auth import utils as auth_utils from openstack_auth import utils as auth_utils
from openstack_dashboard import policy from openstack_dashboard import policy
import six
from six.moves import urllib
from horizon import exceptions from horizon import exceptions
@ -79,8 +79,8 @@ def get_dashboard_links(request):
non_project_keys = {'fileName', 'title'} non_project_keys = {'fileName', 'title'}
try: try:
for project_link in settings.DASHBOARDS: for project_link in settings.DASHBOARDS:
key = project_link.keys()[0] key = list(project_link)[0]
value = project_link.values()[0] value = list(project_link.values())[0]
if key in non_project_keys: if key in non_project_keys:
# #
# we're not indexed by project, just return # we're not indexed by project, just return
@ -129,8 +129,8 @@ def get_monitoring_services(request):
non_project_keys = {'name', 'groupBy'} non_project_keys = {'name', 'groupBy'}
try: try:
for group in settings.MONITORING_SERVICES: for group in settings.MONITORING_SERVICES:
key = group.keys()[0] key = list(group.keys())[0]
value = group.values()[0] value = list(group.values())[0]
if key in non_project_keys: if key in non_project_keys:
# #
# we're not indexed by project, just return # we're not indexed by project, just return
@ -194,7 +194,7 @@ def generate_status(request):
service_alarms.append(a) service_alarms.append(a)
monitoring_services = copy.deepcopy(get_monitoring_services(request)) monitoring_services = copy.deepcopy(get_monitoring_services(request))
for row in monitoring_services: for row in monitoring_services:
row['name'] = unicode(row['name']) row['name'] = six.text_type(row['name'])
if 'groupBy' in row: if 'groupBy' in row:
alarms_by_group = {} alarms_by_group = {}
for a in alarms: for a in alarms:
@ -220,7 +220,7 @@ def generate_status(request):
service_alarms = alarms_by_service.get(service['name'], []) service_alarms = alarms_by_service.get(service['name'], [])
service['class'] = get_status(service_alarms) service['class'] = get_status(service_alarms)
service['icon'] = get_icon(service['class']) service['icon'] = get_icon(service['class'])
service['display'] = unicode(service['display']) service['display'] = six.text_type(service['display'])
return monitoring_services return monitoring_services
@ -271,7 +271,7 @@ class MonascaProxyView(TemplateView):
if len(dimension_name_value) == 2: if len(dimension_name_value) == 2:
name = dimension_name_value[0].encode('utf8') name = dimension_name_value[0].encode('utf8')
value = dimension_name_value[1].encode('utf8') value = dimension_name_value[1].encode('utf8')
dim_dict[name] = urllib.unquote(value) dim_dict[name] = urllib.parse.unquote(value)
else: else:
raise Exception('Dimensions are malformed') raise Exception('Dimensions are malformed')
@ -329,10 +329,10 @@ class StatusView(TemplateView):
content_type='application/json') content_type='application/json')
class _HttpMethodRequest(urllib2.Request): class _HttpMethodRequest(urllib.request.Request):
def __init__(self, method, url, **kwargs): def __init__(self, method, url, **kwargs):
urllib2.Request.__init__(self, url, **kwargs) urllib.request.Request.__init__(self, url, **kwargs)
self.method = method self.method = method
def get_method(self): def get_method(self):
@ -359,15 +359,15 @@ class KibanaProxyView(generic.View):
method, proxy_request_url, data=data, headers=headers method, proxy_request_url, data=data, headers=headers
) )
try: try:
response = urllib2.urlopen(proxy_request) response = urllib.request.urlopen(proxy_request)
except urllib2.HTTPError as e: except urllib.error.HTTPError as e:
return http.HttpResponse( return http.HttpResponse(
e.read(), e.read(),
status=e.code, status=e.code,
content_type=e.hdrs['content-type'] content_type=e.hdrs['content-type']
) )
except urllib2.URLError as e: except urllib.error.URLError as e:
return http.HttpResponse(e.reason, 404) return http.HttpResponse(e.reason, 404)
else: else:
@ -406,7 +406,7 @@ class KibanaProxyView(generic.View):
return self.read(request.method, url, request.body, headers) return self.read(request.method, url, request.body, headers)
def get_relative_url(self, url): def get_relative_url(self, url):
url = urllib.quote(url.encode('utf-8')) url = urllib.parse.quote(url.encode('utf-8'))
params_str = self.request.GET.urlencode() params_str = self.request.GET.urlencode()
if params_str: if params_str:

View File

@ -5,3 +5,4 @@ oslo.log>=3.36.0 # Apache-2.0
python-monascaclient>=1.7.0 # Apache-2.0 python-monascaclient>=1.7.0 # Apache-2.0
Django<2.0,>=1.8 # BSD Django<2.0,>=1.8 # BSD
horizon>=13.0.0 # Apache-2.0 horizon>=13.0.0 # Apache-2.0
six>=1.10.0 # MIT

View File

@ -22,6 +22,8 @@
Installation script for the OpenStack Dashboard development virtualenv. Installation script for the OpenStack Dashboard development virtualenv.
""" """
from __future__ import print_function
import os import os
import subprocess import subprocess
import sys import sys
@ -69,12 +71,12 @@ HAS_VIRTUALENV = bool(run_command(['which', 'virtualenv'],
def check_dependencies(): def check_dependencies():
"""Make sure virtualenv is in the path.""" """Make sure virtualenv is in the path."""
print 'Checking dependencies...' print('Checking dependencies...')
if not HAS_VIRTUALENV: if not HAS_VIRTUALENV:
print 'Virtual environment not found.' print('Virtual environment not found.')
# Try installing it via easy_install... # Try installing it via easy_install...
if HAS_EASY_INSTALL: if HAS_EASY_INSTALL:
print 'Installing virtualenv via easy_install...', print('Installing virtualenv via easy_install...', end=' ')
run_command(['easy_install', 'virtualenv'], run_command(['easy_install', 'virtualenv'],
die_message='easy_install failed to install virtualenv' die_message='easy_install failed to install virtualenv'
'\ndevelopment requires virtualenv, please' '\ndevelopment requires virtualenv, please'
@ -84,28 +86,28 @@ def check_dependencies():
' requires virtualenv, please install it using your' ' requires virtualenv, please install it using your'
' favorite package management tool and ensure' ' favorite package management tool and ensure'
' virtualenv is in your path') ' virtualenv is in your path')
print 'virtualenv installation done.' print('virtualenv installation done.')
else: else:
die('easy_install not found.\n\nInstall easy_install' die('easy_install not found.\n\nInstall easy_install'
' (python-setuptools in ubuntu) or virtualenv by hand,' ' (python-setuptools in ubuntu) or virtualenv by hand,'
' then rerun.') ' then rerun.')
print 'dependency check done.' print('dependency check done.')
def create_virtualenv(venv=VENV): def create_virtualenv(venv=VENV):
"""Creates the virtual environment and installs PIP only into the """Creates the virtual environment and installs PIP only into the
virtual environment virtual environment
""" """
print 'Creating venv...', print('Creating venv...', end=' ')
run_command(['virtualenv', '-q', '--no-site-packages', VENV]) run_command(['virtualenv', '-q', '--no-site-packages', VENV])
print 'done.' print('done.')
print 'Installing pip in virtualenv...', print('Installing pip in virtualenv...', end=' ')
if not run_command([WITH_VENV, 'easy_install', 'pip']).strip(): if not run_command([WITH_VENV, 'easy_install', 'pip']).strip():
die("Failed to install pip.") die("Failed to install pip.")
print 'done.' print('done.')
print 'Installing distribute in virtualenv...' print('Installing distribute in virtualenv...')
pip_install('distribute>=0.6.24') pip_install('distribute>=0.6.24')
print 'done.' print('done.')
def pip_install(*args): def pip_install(*args):
@ -114,8 +116,8 @@ def pip_install(*args):
def install_dependencies(venv=VENV): def install_dependencies(venv=VENV):
print "Installing dependencies..." print("Installing dependencies...")
print "(This may take several minutes, don't panic)" print("(This may take several minutes, don't panic)")
pip_install('-r', TEST_REQUIRES) pip_install('-r', TEST_REQUIRES)
pip_install('-r', PIP_REQUIRES) pip_install('-r', PIP_REQUIRES)
@ -127,7 +129,7 @@ def install_dependencies(venv=VENV):
def install_horizon(): def install_horizon():
print 'Installing horizon module in development mode...' print('Installing horizon module in development mode...')
run_command([WITH_VENV, 'python', 'setup.py', 'develop'], cwd=ROOT) run_command([WITH_VENV, 'python', 'setup.py', 'develop'], cwd=ROOT)
@ -140,7 +142,7 @@ can run:
$ source .venv/bin/activate $ source .venv/bin/activate
""" """
print summary print(summary)
def main(): def main():

View File

@ -1,5 +1,5 @@
[tox] [tox]
envlist = py27,pep8 envlist = py27,pep8,py35
minversion = 2.6 minversion = 2.6
skipsdist = True skipsdist = True