diff --git a/horizon/templatetags/shellfilter.py b/horizon/templatetags/shellfilter.py index d3f2ac599b..167a2220c0 100644 --- a/horizon/templatetags/shellfilter.py +++ b/horizon/templatetags/shellfilter.py @@ -22,7 +22,7 @@ register = template.Library() def shellfilter(value): """Replace HTML chars for shell usage.""" replacements = {'\\': '\\\\', - '`': '\`', + '`': '\\`', "'": "\\'", '"': '\\"'} for search, repl in replacements.items(): diff --git a/horizon/utils/functions.py b/horizon/utils/functions.py index a5514fdeec..dc9f6417d8 100644 --- a/horizon/utils/functions.py +++ b/horizon/utils/functions.py @@ -30,6 +30,7 @@ def _lazy_join(separator, strings): return separator.join([force_text(s) for s in strings]) + lazy_join = lazy(_lazy_join, six.text_type) diff --git a/horizon/utils/memoized.py b/horizon/utils/memoized.py index a853be10b3..1f9db9c11c 100644 --- a/horizon/utils/memoized.py +++ b/horizon/utils/memoized.py @@ -131,6 +131,7 @@ def memoized(func=None, max_size=None): return decorate(func) return decorate + # We can use @memoized for methods now too, because it uses weakref and so # it doesn't keep the instances in memory forever. We might want to separate # them in the future, however. diff --git a/horizon/utils/validators.py b/horizon/utils/validators.py index a72de0ab94..70f7de7aa6 100644 --- a/horizon/utils/validators.py +++ b/horizon/utils/validators.py @@ -76,6 +76,7 @@ def validate_metadata(value): if not len(keyval) == 2 or not keyval[0]: raise ValidationError(error_msg) + # Same as POSIX [:print:]. Accordingly, diacritics are disallowed. PRINT_REGEX = re.compile(r'^[\x20-\x7E]*$') diff --git a/openstack_auth/tests/unit/test_auth.py b/openstack_auth/tests/unit/test_auth.py index 016956692d..f5d2ce03be 100644 --- a/openstack_auth/tests/unit/test_auth.py +++ b/openstack_auth/tests/unit/test_auth.py @@ -1266,7 +1266,7 @@ class OpenStackAuthTestsWebSSO(OpenStackAuthTestsMixin, settings.WEBSSO_DEFAULT_REDIRECT = True settings.WEBSSO_DEFAULT_REDIRECT_PROTOCOL = 'oidc' settings.WEBSSO_DEFAULT_REDIRECT_REGION = ( - settings.OPENSTACK_KEYSTONE_URL) + settings.OPENSTACK_KEYSTONE_URL) url = reverse('login') @@ -1286,4 +1286,5 @@ class OpenStackAuthTestsWebSSO(OpenStackAuthTestsMixin, self.assertRedirects(response, settings.WEBSSO_DEFAULT_REDIRECT_LOGOUT, status_code=302, target_status_code=301) + load_tests = load_tests_apply_scenarios diff --git a/openstack_auth/views.py b/openstack_auth/views.py index 9af337810a..abd2f40ae7 100644 --- a/openstack_auth/views.py +++ b/openstack_auth/views.py @@ -198,7 +198,7 @@ def logout(request, login_url=None, **kwargs): utils.get_websso_default_redirect_logout()): auth_user.unset_session_user_variables(request) return django_http.HttpResponseRedirect( - utils.get_websso_default_redirect_logout()) + utils.get_websso_default_redirect_logout()) else: return django_auth_views.logout_then_login(request, login_url=login_url, diff --git a/openstack_dashboard/api/neutron.py b/openstack_dashboard/api/neutron.py index 8b3889c235..e62b12c4c8 100644 --- a/openstack_dashboard/api/neutron.py +++ b/openstack_dashboard/api/neutron.py @@ -1841,6 +1841,7 @@ def is_router_enabled(request): return (is_enabled_by_config('enable_router') and is_extension_supported(request, 'router')) + # FEATURE_MAP is used to define: # - related neutron extension name (key: "extension") # - corresponding dashboard config (key: "config") diff --git a/openstack_dashboard/api/rest/utils.py b/openstack_dashboard/api/rest/utils.py index 6f2fb8a165..68e6e19bd7 100644 --- a/openstack_dashboard/api/rest/utils.py +++ b/openstack_dashboard/api/rest/utils.py @@ -31,6 +31,7 @@ class AjaxError(Exception): self.http_status = http_status super(AjaxError, self).__init__(msg) + http_errors = exceptions.UNAUTHORIZED + exceptions.NOT_FOUND + \ exceptions.RECOVERABLE + (AjaxError, ) @@ -147,6 +148,7 @@ def ajax(authenticated=True, data_required=False, return _wrapped return decorator + PARAM_MAPPING = { 'None': None, 'True': True, diff --git a/openstack_dashboard/dashboards/admin/dashboard.py b/openstack_dashboard/dashboards/admin/dashboard.py index f526d957b7..aebef71ce3 100644 --- a/openstack_dashboard/dashboards/admin/dashboard.py +++ b/openstack_dashboard/dashboards/admin/dashboard.py @@ -32,4 +32,5 @@ class Admin(horizon.Dashboard): else: permissions = (tuple(utils.get_admin_permissions()),) + horizon.register(Admin) diff --git a/openstack_dashboard/dashboards/admin/instances/views.py b/openstack_dashboard/dashboards/admin/instances/views.py index 4825d2c42d..63454d89cf 100644 --- a/openstack_dashboard/dashboards/admin/instances/views.py +++ b/openstack_dashboard/dashboards/admin/instances/views.py @@ -150,9 +150,9 @@ class AdminIndexView(tables.DataTableView): instances = self._get_instances(search_opts) results = futurist_utils.call_functions_parallel( - (self._get_images, [tuple(instances)]), - self._get_flavors, - self._get_tenants) + (self._get_images, [tuple(instances)]), + self._get_flavors, + self._get_tenants) image_dict, flavor_dict, tenant_dict = results non_api_filter_info = ( diff --git a/openstack_dashboard/dashboards/admin/networks/urls.py b/openstack_dashboard/dashboards/admin/networks/urls.py index 7535491323..6332201ecf 100644 --- a/openstack_dashboard/dashboards/admin/networks/urls.py +++ b/openstack_dashboard/dashboards/admin/networks/urls.py @@ -36,11 +36,11 @@ urlpatterns = [ url(r'^create/$', views.CreateView.as_view(), name='create'), url(NETWORKS % 'update', views.UpdateView.as_view(), name='update'), url(NETWORKS % 'detail', views.DetailView.as_view(), name='detail'), - url(NETWORKS % 'detail\?tab=network_tabs__ports_tab$', + url(NETWORKS % r'detail\?tab=network_tabs__ports_tab$', views.DetailView.as_view(), name='ports_tab'), - url(NETWORKS % 'detail\?tab=network_tabs__agents_tab$', + url(NETWORKS % r'detail\?tab=network_tabs__agents_tab$', views.DetailView.as_view(), name='agents_tab'), - url(NETWORKS % 'detail\?tab=network_tabs__subnets_tab$', + url(NETWORKS % r'detail\?tab=network_tabs__subnets_tab$', views.DetailView.as_view(), name='subnets_tab'), url(NETWORKS % 'agents/add', agent_views.AddView.as_view(), name='adddhcpagent'), diff --git a/openstack_dashboard/dashboards/identity/identity_providers/urls.py b/openstack_dashboard/dashboards/identity/identity_providers/urls.py index 71912e15ef..8d6aa553ab 100644 --- a/openstack_dashboard/dashboards/identity/identity_providers/urls.py +++ b/openstack_dashboard/dashboards/identity/identity_providers/urls.py @@ -25,7 +25,7 @@ urlpatterns = [ url(r'^(?P[^/]+)/detail/$', views.DetailView.as_view(), name='detail'), url(r'^(?P[^/]+)/detail/' - '\?tab=idp_details__protocols$', + r'\?tab=idp_details__protocols$', views.DetailView.as_view(), name='protocols_tab'), url(r'^(?P[^/]+)/update/$', diff --git a/openstack_dashboard/dashboards/project/dashboard.py b/openstack_dashboard/dashboards/project/dashboard.py index 90473e1fec..fdd8e7f8cf 100644 --- a/openstack_dashboard/dashboards/project/dashboard.py +++ b/openstack_dashboard/dashboards/project/dashboard.py @@ -26,4 +26,5 @@ class Project(horizon.Dashboard): has_project = request.user.token.project.get('id') is not None return super(Project, self).can_access(context) and has_project + horizon.register(Project) diff --git a/openstack_dashboard/dashboards/project/images/images/forms.py b/openstack_dashboard/dashboards/project/images/images/forms.py index ce6b2847ca..09a00cf483 100644 --- a/openstack_dashboard/dashboards/project/images/images/forms.py +++ b/openstack_dashboard/dashboards/project/images/images/forms.py @@ -43,6 +43,7 @@ IMAGE_FORMAT_CHOICES = IMAGE_BACKEND_SETTINGS.get('image_formats', []) class ImageURLField(forms.URLField): default_validators = [validators.URLValidator(schemes=["http", "https"])] + if api.glance.get_image_upload_mode() == 'direct': FileField = forms.ExternalFileField CreateParent = six.with_metaclass(forms.ExternalUploadMeta, diff --git a/openstack_dashboard/dashboards/project/networks/urls.py b/openstack_dashboard/dashboards/project/networks/urls.py index 72521d1312..8b7ba019d1 100644 --- a/openstack_dashboard/dashboards/project/networks/urls.py +++ b/openstack_dashboard/dashboards/project/networks/urls.py @@ -32,12 +32,12 @@ NETWORKS = r'^(?P[^/]+)/%s$' urlpatterns = [ url(r'^$', views.IndexView.as_view(), name='index'), url(r'^create$', views.CreateView.as_view(), name='create'), - url(NETWORKS % 'detail(\?tab=network_tabs__overview)?$', + url(NETWORKS % r'detail(\?tab=network_tabs__overview)?$', views.DetailView.as_view(), name='detail'), - url(NETWORKS % 'detail\?tab=network_tabs__ports_tab$', + url(NETWORKS % r'detail\?tab=network_tabs__ports_tab$', views.DetailView.as_view(), name='ports_tab'), - url(NETWORKS % 'detail\?tab=network_tabs__subnets_tab$', + url(NETWORKS % r'detail\?tab=network_tabs__subnets_tab$', views.DetailView.as_view(), name='subnets_tab'), url(NETWORKS % 'update', views.UpdateView.as_view(), name='update'), url(NETWORKS % 'subnets/create', subnet_views.CreateView.as_view(), diff --git a/openstack_dashboard/management/commands/make_web_conf.py b/openstack_dashboard/management/commands/make_web_conf.py index 080e88f59e..a1fe7d59bc 100644 --- a/openstack_dashboard/management/commands/make_web_conf.py +++ b/openstack_dashboard/management/commands/make_web_conf.py @@ -139,6 +139,8 @@ def find_apache_log_dir(): if os.path.exists(log_dir) and os.path.isdir(log_dir): return log_dir return DEFAULT_LOG_DIR + + context['LOGDIR'] = find_apache_log_dir() diff --git a/openstack_dashboard/test/integration_tests/pages/project/network/floatingipspage.py b/openstack_dashboard/test/integration_tests/pages/project/network/floatingipspage.py index 270ce2c1a8..0a8fe9fa6f 100644 --- a/openstack_dashboard/test/integration_tests/pages/project/network/floatingipspage.py +++ b/openstack_dashboard/test/integration_tests/pages/project/network/floatingipspage.py @@ -72,9 +72,9 @@ class FloatingipsPage(basepage.BaseNavigationPage): def allocate_floatingip(self): floatingip_form = self.floatingips_table.allocate_ip() floatingip_form.submit() - ip = re.compile('(([2][5][0-5]\.)|([2][0-4][0-9]\.)' - '|([0-1]?[0-9]?[0-9]\.)){3}(([2][5][0-5])|' - '([2][0-4][0-9])|([0-1]?[0-9]?[0-9]))') + ip = re.compile(r'(([2][5][0-5]\.)|([2][0-4][0-9]\.)' + r'|([0-1]?[0-9]?[0-9]\.)){3}(([2][5][0-5])|' + r'([2][0-4][0-9])|([0-1]?[0-9]?[0-9]))') match = ip.search((self._get_element( *self._floatingips_fadein_popup_locator)).text) floatingip = str(match.group()) diff --git a/openstack_dashboard/test/unit/api/rest/test_keystone.py b/openstack_dashboard/test/unit/api/rest/test_keystone.py index 245a245304..e3d728b1f5 100644 --- a/openstack_dashboard/test/unit/api/rest/test_keystone.py +++ b/openstack_dashboard/test/unit/api/rest/test_keystone.py @@ -688,48 +688,48 @@ class KeystoneRestTestCase(test.TestCase): def test_service_catalog_get(self): request = self.mock_rest_request() request.user = mock.MagicMock(**{'service_catalog': [ - {'endpoints': [ - {'url': 'http://cool_url/image', - 'interface': 'admin', - 'region': 'RegionOne', - 'region_id': 'RegionOne', - 'id': 'test'}, - {'url': 'http://cool_url/image', - 'interface': 'public', - 'region': 'RegionOne', - 'region_id': 'RegionOne', - 'id': 'test'}, - {'url': 'http://cool_url/image', - 'interface': 'internal', - 'region': 'RegionOne', - 'region_id': 'RegionOne', - 'id': 'test'}], - 'type': 'image', - 'id': '2b5bc2e59b094f898a43f5e8ce446240', - 'name': 'glance'}, - {'endpoints': [ - {'url': 'http://cool_url/volume/v2/test', - 'interface': 'public', - 'region': 'RegionOne', - 'region_id': 'RegionOne', - 'id': '29a629afb80547ea9baa4266e97b4cb5'}, - {'url': 'http://cool_url/volume/v2/test', - 'interface': 'admin', - 'region': 'RegionOne', - 'region_id': 'RegionOne', - 'id': '29a629afb80547ea9baa4266e97b4cb5'}], - 'type': 'volumev2', - 'id': '55ef272cfa714e54b8f2046c157b027d', - 'name': 'cinderv2'}, - {'endpoints': [ - {'url': 'http://cool_url/compute/v2/check', - 'interface': 'internal', - 'region': 'RegionOne', - 'region_id': 'RegionOne', - 'id': 'e8c440e025d94355ab82c78cc2062129'}], - 'type': 'compute_legacy', - 'id': 'b7f1d3f4119643508d5ca2325eb8af87', - 'name': 'nova_legacy'}]}) + {'endpoints': [ + {'url': 'http://cool_url/image', + 'interface': 'admin', + 'region': 'RegionOne', + 'region_id': 'RegionOne', + 'id': 'test'}, + {'url': 'http://cool_url/image', + 'interface': 'public', + 'region': 'RegionOne', + 'region_id': 'RegionOne', + 'id': 'test'}, + {'url': 'http://cool_url/image', + 'interface': 'internal', + 'region': 'RegionOne', + 'region_id': 'RegionOne', + 'id': 'test'}], + 'type': 'image', + 'id': '2b5bc2e59b094f898a43f5e8ce446240', + 'name': 'glance'}, + {'endpoints': [ + {'url': 'http://cool_url/volume/v2/test', + 'interface': 'public', + 'region': 'RegionOne', + 'region_id': 'RegionOne', + 'id': '29a629afb80547ea9baa4266e97b4cb5'}, + {'url': 'http://cool_url/volume/v2/test', + 'interface': 'admin', + 'region': 'RegionOne', + 'region_id': 'RegionOne', + 'id': '29a629afb80547ea9baa4266e97b4cb5'}], + 'type': 'volumev2', + 'id': '55ef272cfa714e54b8f2046c157b027d', + 'name': 'cinderv2'}, + {'endpoints': [ + {'url': 'http://cool_url/compute/v2/check', + 'interface': 'internal', + 'region': 'RegionOne', + 'region_id': 'RegionOne', + 'id': 'e8c440e025d94355ab82c78cc2062129'}], + 'type': 'compute_legacy', + 'id': 'b7f1d3f4119643508d5ca2325eb8af87', + 'name': 'nova_legacy'}]}) response = keystone.ServiceCatalog().get(request) self.assertStatusCode(response, 200) content = [{'endpoints': [ diff --git a/openstack_dashboard/test/unit/api/test_glance.py b/openstack_dashboard/test/unit/api/test_glance.py index 72482f3ecb..0ceab4059f 100644 --- a/openstack_dashboard/test/unit/api/test_glance.py +++ b/openstack_dashboard/test/unit/api/test_glance.py @@ -33,11 +33,11 @@ class GlanceApiTests(test.APIMockTestCase): @override_settings(API_RESULT_PAGE_SIZE=2) @mock.patch.object(api.glance, 'glanceclient') def test_long_url(self, mock_glanceclient): - servers = self.servers.list()*100 - api_images = self.images_api.list()*100 + servers = self.servers.list() * 100 + api_images = self.images_api.list() * 100 instances_img_ids = [instance.image.get('id') for instance in servers if hasattr(instance, 'image')] - expected_images = self.images.list()*100 + expected_images = self.images.list() * 100 glanceclient = mock_glanceclient.return_value mock_images_list = glanceclient.images.list mock_images_list.return_value = iter(api_images) diff --git a/test-requirements.txt b/test-requirements.txt index c480480dea..09503f77fb 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -7,7 +7,7 @@ # be installed in a specific order. # # Hacking should appear first in case something else depends on pep8 -hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0 +hacking>=1.1.0 # Apache-2.0 # bandit>=1.4.0 # Apache-2.0 coverage!=4.4,>=4.0 # Apache-2.0 diff --git a/tox.ini b/tox.ini index f5f6879a75..7def53269d 100644 --- a/tox.ini +++ b/tox.ini @@ -173,7 +173,12 @@ basepython = python3 [flake8] filename = *.py,django.wsgi exclude = .git,.tox,dist,*lib/python*,*egg,build,panel_template,dash_template,local_settings.py,*/local/*,*/test/test_plugins/*,.ropeproject,node_modules,openstack_dashboard/enabled/* -ignore = +# W504 line break after binary operator +# (W503 and W504 are incompatible and we need to choose one of them. +# Existing codes follows W503, so we disable W504.) +# F405 TEMPLATES may be undefined, or defined from star imports +# (because it is not easy to avoid this in openstack_dashboard.test.settings) +ignore = W504,F405 # Enable the following hacking rules which are disabled by default # H106 Do not put vim configuration in source files. # H203 Use assertIs(Not)None to check for None. @@ -182,6 +187,7 @@ ignore = # H904 Delay string interpolations at logging calls. enable-extensions=H106,H203,H204,H205,H904 max-complexity = 20 +max_line_length = 80 # flake8-import-order configurations import-order-style = pep8