From a23e362d18a942efe37c4f33959ec3d7f127701d Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Tue, 5 Jan 2021 14:34:19 +0100 Subject: [PATCH] VC/Zoom: Switch to Python 3 --- vc_zoom/indico_vc_zoom/__init__.py | 2 -- vc_zoom/indico_vc_zoom/api/client.py | 44 ++++++++++++------------- vc_zoom/indico_vc_zoom/blueprint.py | 2 -- vc_zoom/indico_vc_zoom/cli.py | 4 +-- vc_zoom/indico_vc_zoom/controllers.py | 2 -- vc_zoom/indico_vc_zoom/forms.py | 4 +-- vc_zoom/indico_vc_zoom/notifications.py | 2 -- vc_zoom/indico_vc_zoom/plugin.py | 24 +++++++------- vc_zoom/indico_vc_zoom/util.py | 8 ++--- vc_zoom/setup.cfg | 4 +-- vc_zoom/setup.py | 5 ++- 11 files changed, 41 insertions(+), 60 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/__init__.py b/vc_zoom/indico_vc_zoom/__init__.py index cd6162ccb..c59b8b4cd 100644 --- a/vc_zoom/indico_vc_zoom/__init__.py +++ b/vc_zoom/indico_vc_zoom/__init__.py @@ -5,8 +5,6 @@ # them and/or modify them under the terms of the MIT License; # see the LICENSE file for more details. -from __future__ import unicode_literals - from indico.util.i18n import make_bound_gettext diff --git a/vc_zoom/indico_vc_zoom/api/client.py b/vc_zoom/indico_vc_zoom/api/client.py index ad223c3d0..dc725a7d4 100644 --- a/vc_zoom/indico_vc_zoom/api/client.py +++ b/vc_zoom/indico_vc_zoom/api/client.py @@ -5,8 +5,6 @@ # them and/or modify them under the terms of the MIT License; # see the LICENSE file for more details. -from __future__ import absolute_import, unicode_literals - import time import jwt @@ -28,7 +26,7 @@ def _handle_response(resp, expected_code=200, expects_json=True): try: resp.raise_for_status() if resp.status_code != expected_code: - raise HTTPError('Unexpected status code {}'.format(resp.status_code), response=resp) + raise HTTPError(f'Unexpected status code {resp.status_code}', response=resp) except HTTPError: from indico_vc_zoom.plugin import ZoomPlugin ZoomPlugin.logger.error('Error in API call to %s: %s', resp.url, resp.content) @@ -40,7 +38,7 @@ class APIException(Exception): pass -class BaseComponent(object): +class BaseComponent: def __init__(self, base_uri, config, timeout): self.base_uri = base_uri self.config = config @@ -58,7 +56,7 @@ def session(self): session = Session() session.headers = { 'Content-Type': 'application/json', - 'Authorization': 'Bearer {}'.format(self.token) + 'Authorization': f'Bearer {self.token}' } return session @@ -66,60 +64,60 @@ def session(self): class MeetingComponent(BaseComponent): def list(self, user_id, **kwargs): return self.get( - '{}/users/{}/meetings'.format(self.base_uri, user_id), params=kwargs + f'{self.base_uri}/users/{user_id}/meetings', params=kwargs ) def create(self, user_id, **kwargs): if kwargs.get('start_time'): kwargs['start_time'] = format_iso_dt(kwargs['start_time']) return self.session.post( - '{}/users/{}/meetings'.format(self.base_uri, user_id), + f'{self.base_uri}/users/{user_id}/meetings', json=kwargs ) def get(self, meeting_id, **kwargs): - return self.session.get('{}/meetings/{}'.format(self.base_uri, meeting_id), json=kwargs) + return self.session.get(f'{self.base_uri}/meetings/{meeting_id}', json=kwargs) def update(self, meeting_id, **kwargs): if kwargs.get('start_time'): kwargs['start_time'] = format_iso_dt(kwargs['start_time']) return self.session.patch( - '{}/meetings/{}'.format(self.base_uri, meeting_id), json=kwargs + f'{self.base_uri}/meetings/{meeting_id}', json=kwargs ) def delete(self, meeting_id, **kwargs): return self.session.delete( - '{}/meetings/{}'.format(self.base_uri, meeting_id), json=kwargs + f'{self.base_uri}/meetings/{meeting_id}', json=kwargs ) class WebinarComponent(BaseComponent): def list(self, user_id, **kwargs): return self.get( - '{}/users/{}/webinars'.format(self.base_uri, user_id), params=kwargs + f'{self.base_uri}/users/{user_id}/webinars', params=kwargs ) def create(self, user_id, **kwargs): if kwargs.get('start_time'): kwargs['start_time'] = format_iso_dt(kwargs['start_time']) return self.session.post( - '{}/users/{}/webinars'.format(self.base_uri, user_id), + f'{self.base_uri}/users/{user_id}/webinars', json=kwargs ) def get(self, meeting_id, **kwargs): - return self.session.get('{}/webinars/{}'.format(self.base_uri, meeting_id), json=kwargs) + return self.session.get(f'{self.base_uri}/webinars/{meeting_id}', json=kwargs) def update(self, meeting_id, **kwargs): if kwargs.get('start_time'): kwargs['start_time'] = format_iso_dt(kwargs['start_time']) return self.session.patch( - '{}/webinars/{}'.format(self.base_uri, meeting_id), json=kwargs + f'{self.base_uri}/webinars/{meeting_id}', json=kwargs ) def delete(self, meeting_id, **kwargs): return self.session.delete( - '{}/webinars/{}'.format(self.base_uri, meeting_id), json=kwargs + f'{self.base_uri}/webinars/{meeting_id}', json=kwargs ) @@ -128,22 +126,22 @@ def me(self): return self.get('me') def list(self, **kwargs): - return self.session.get('{}/users'.format(self.base_uri), params=kwargs) + return self.session.get(f'{self.base_uri}/users', params=kwargs) def create(self, **kwargs): - return self.session.post('{}/users'.format(self.base_uri), params=kwargs) + return self.session.post(f'{self.base_uri}/users', params=kwargs) def update(self, user_id, **kwargs): - return self.session.patch('{}/users/{}'.format(self.base_uri, user_id), params=kwargs) + return self.session.patch(f'{self.base_uri}/users/{user_id}', params=kwargs) def delete(self, user_id, **kwargs): - return self.session.delete('{}/users/{}'.format(self.base_uri, user_id), params=kwargs) + return self.session.delete(f'{self.base_uri}/users/{user_id}', params=kwargs) def get(self, user_id, **kwargs): - return self.session.get('{}/users/{}'.format(self.base_uri, user_id), params=kwargs) + return self.session.get(f'{self.base_uri}/users/{user_id}', params=kwargs) -class ZoomClient(object): +class ZoomClient: """Zoom REST API Python Client.""" BASE_URI = 'https://api.zoom.us/v2' @@ -170,7 +168,7 @@ def __init__(self, api_key, api_secret, timeout=15): # Instantiate the components self.components = { key: component(base_uri=self.BASE_URI, config=config, timeout=timeout) - for key, component in self._components.viewitems() + for key, component in self._components.items() } @property @@ -189,7 +187,7 @@ def webinar(self): return self.components['webinar'] -class ZoomIndicoClient(object): +class ZoomIndicoClient: def __init__(self): from indico_vc_zoom.plugin import ZoomPlugin self.client = ZoomClient( diff --git a/vc_zoom/indico_vc_zoom/blueprint.py b/vc_zoom/indico_vc_zoom/blueprint.py index 57cab6d61..38ed0ff16 100644 --- a/vc_zoom/indico_vc_zoom/blueprint.py +++ b/vc_zoom/indico_vc_zoom/blueprint.py @@ -5,8 +5,6 @@ # them and/or modify them under the terms of the MIT License; # see the LICENSE file for more details. -from __future__ import unicode_literals - from indico.core.plugins import IndicoPluginBlueprint from indico_vc_zoom.controllers import RHRoomAlternativeHost, RHWebhook diff --git a/vc_zoom/indico_vc_zoom/cli.py b/vc_zoom/indico_vc_zoom/cli.py index fe99cfd96..5107f0758 100644 --- a/vc_zoom/indico_vc_zoom/cli.py +++ b/vc_zoom/indico_vc_zoom/cli.py @@ -5,8 +5,6 @@ # them and/or modify them under the terms of the MIT License; # see the LICENSE file for more details. -from __future__ import print_function, unicode_literals - import click from terminaltables import AsciiTable @@ -31,7 +29,7 @@ def rooms(status=None): room_query = room_query.filter(VCRoom.status == VCRoomStatus.get(status)) for room in room_query: - table_data.append([unicode(room.id), room.name, room.status.name, unicode(room.data['zoom_id'])]) + table_data.append([str(room.id), room.name, room.status.name, str(room.data['zoom_id'])]) table = AsciiTable(table_data) for col in (0, 3, 4): diff --git a/vc_zoom/indico_vc_zoom/controllers.py b/vc_zoom/indico_vc_zoom/controllers.py index 86fddce5f..d3177d5d3 100644 --- a/vc_zoom/indico_vc_zoom/controllers.py +++ b/vc_zoom/indico_vc_zoom/controllers.py @@ -5,8 +5,6 @@ # them and/or modify them under the terms of the MIT License; # see the LICENSE file for more details. -from __future__ import unicode_literals - from flask import flash, jsonify, request, session from flask_pluginengine import current_plugin from sqlalchemy.orm.attributes import flag_modified diff --git a/vc_zoom/indico_vc_zoom/forms.py b/vc_zoom/indico_vc_zoom/forms.py index 75a028941..77d750ea7 100644 --- a/vc_zoom/indico_vc_zoom/forms.py +++ b/vc_zoom/indico_vc_zoom/forms.py @@ -5,8 +5,6 @@ # them and/or modify them under the terms of the MIT License; # see the LICENSE file for more details. -from __future__ import unicode_literals - from flask import session from flask_pluginengine import current_plugin from wtforms.fields.core import BooleanField, StringField @@ -100,7 +98,7 @@ def __init__(self, *args, **kwargs): for field_name in {'mute_audio', 'mute_participant_video', 'waiting_room'}: inject_validators(self, field_name, [HiddenUnless('meeting_type', 'regular')]) - super(VCRoomForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) if not allow_webinars: del self.meeting_type diff --git a/vc_zoom/indico_vc_zoom/notifications.py b/vc_zoom/indico_vc_zoom/notifications.py index 0e58d852e..49ab23937 100644 --- a/vc_zoom/indico_vc_zoom/notifications.py +++ b/vc_zoom/indico_vc_zoom/notifications.py @@ -5,8 +5,6 @@ # them and/or modify them under the terms of the MIT License; # see the LICENSE file for more details. -from __future__ import unicode_literals - from indico.core.notifications import make_email, send_email from indico.util.user import principal_from_identifier from indico.web.flask.templating import get_template_module diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index b3f17d28d..d641660c6 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -5,8 +5,6 @@ # them and/or modify them under the terms of the MIT License; # see the LICENSE file for more details. -from __future__ import unicode_literals - from flask import flash, session from markupsafe import escape from requests.exceptions import HTTPError @@ -147,7 +145,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): }) def init(self): - super(ZoomPlugin, self).init() + super().init() self.connect(signals.plugin.cli, self._extend_indico_cli) self.connect(signals.event.times_changed, self._times_changed) self.template_hook('event-vc-room-list-item-labels', self._render_vc_room_labels) @@ -165,7 +163,7 @@ def icon_url(self): def create_form(self, event, existing_vc_room=None, existing_event_vc_room=None): """Override the default room form creation mechanism.""" - form = super(ZoomPlugin, self).create_form( + form = super().create_form( event, existing_vc_room=existing_vc_room, existing_event_vc_room=existing_event_vc_room @@ -203,7 +201,7 @@ def update_data_association(self, event, vc_room, room_assoc, data): # in a new room, `meeting_type` comes in `data`, otherwise it's already in the VCRoom is_webinar = data.get('meeting_type', vc_room.data and vc_room.data.get('meeting_type')) == 'webinar' - super(ZoomPlugin, self).update_data_association(event, vc_room, room_assoc, data) + super().update_data_association(event, vc_room, room_assoc, data) if vc_room.data: # this is not a new room @@ -232,7 +230,7 @@ def update_data_association(self, event, vc_room, room_assoc, data): flag_modified(room_assoc, 'data') def update_data_vc_room(self, vc_room, data, is_new=False): - super(ZoomPlugin, self).update_data_vc_room(vc_room, data) + super().update_data_vc_room(vc_room, data) fields = {'description', 'password'} # we may end up not getting a meeting_type from the form @@ -319,7 +317,7 @@ def create_room(self, vc_room, event): raise VCRoomError(_('Could not create the room in Zoom. Please contact support if the error persists')) vc_room.data.update({ - 'zoom_id': unicode(meeting_obj['id']), + 'zoom_id': str(meeting_obj['id']), 'start_url': meeting_obj['start_url'], 'host': host.identifier, 'alternative_hosts': process_alternative_hosts(meeting_obj['settings'].get('alternative_hosts', '')) @@ -412,7 +410,7 @@ def clone_room(self, old_event_vc_room, link_object): vc_room = old_event_vc_room.vc_room is_webinar = vc_room.data.get('meeting_type', 'regular') == 'webinar' has_only_one_association = len({assoc.event_id for assoc in vc_room.events}) == 1 - new_assoc = super(ZoomPlugin, self).clone_room(old_event_vc_room, link_object) + new_assoc = super().clone_room(old_event_vc_room, link_object) if has_only_one_association: update_zoom_meeting(vc_room.data['zoom_id'], { @@ -431,7 +429,7 @@ def get_blueprints(self): return blueprint def get_vc_room_form_defaults(self, event): - defaults = super(ZoomPlugin, self).get_vc_room_form_defaults(event) + defaults = super().get_vc_room_form_defaults(event) defaults.update({ 'meeting_type': 'regular' if self.settings.get('allow_webinars') else None, 'mute_audio': self.settings.get('mute_audio'), @@ -445,18 +443,18 @@ def get_vc_room_form_defaults(self, event): return defaults def get_vc_room_attach_form_defaults(self, event): - defaults = super(ZoomPlugin, self).get_vc_room_attach_form_defaults(event) + defaults = super().get_vc_room_attach_form_defaults(event) defaults['password_visibility'] = 'logged_in' return defaults def can_manage_vc_room(self, user, room): return ( user == principal_from_identifier(room.data['host']) or - super(ZoomPlugin, self).can_manage_vc_room(user, room) + super().can_manage_vc_room(user, room) ) def _merge_users(self, target, source, **kwargs): - super(ZoomPlugin, self)._merge_users(target, source, **kwargs) + super()._merge_users(target, source, **kwargs) for room in VCRoom.query.filter( VCRoom.type == self.service_name, VCRoom.data.contains({'host': source.identifier}) ): @@ -478,8 +476,8 @@ def _render_vc_room_labels(self, event, vc_room, **kwargs): return render_plugin_template('room_labels.html', vc_room=vc_room) def _times_changed(self, sender, obj, **kwargs): - from indico.modules.events.models.events import Event from indico.modules.events.contributions.models.contributions import Contribution + from indico.modules.events.models.events import Event from indico.modules.events.sessions.models.blocks import SessionBlock if not hasattr(obj, 'vc_room_associations'): diff --git a/vc_zoom/indico_vc_zoom/util.py b/vc_zoom/indico_vc_zoom/util.py index 978d64816..7d7d4574e 100644 --- a/vc_zoom/indico_vc_zoom/util.py +++ b/vc_zoom/indico_vc_zoom/util.py @@ -5,8 +5,6 @@ # them and/or modify them under the terms of the MIT License; # see the LICENSE file for more details. -from __future__ import unicode_literals - import random import re import string @@ -38,7 +36,7 @@ class ZoomMeetingType(int, IndicoEnum): recurring_webinar_fixed_time = 9 -class UserLookupMode(unicode, RichEnum): +class UserLookupMode(str, RichEnum): __titles__ = { 'all_emails': _('All emails'), 'email_domains': _('Email domains'), @@ -79,7 +77,7 @@ def iter_user_emails(user): domains = ZoomPlugin.settings.get('email_domains') if not domains: return - email_criterion = db.or_(UserEmail.email.endswith('@{}'.format(domain)) for domain in domains) + email_criterion = db.or_(UserEmail.email.endswith(f'@{domain}') for domain in domains) # get all matching e-mails, primary first query = UserEmail.query.filter( UserEmail.user == user, @@ -92,7 +90,7 @@ def iter_user_emails(user): elif mode == UserLookupMode.authenticators: domain = ZoomPlugin.settings.get('enterprise_domain') for username in _iter_user_identifiers(user): - yield '{}@{}'.format(username, domain) + yield f'{username}@{domain}' @memoize_request diff --git a/vc_zoom/setup.cfg b/vc_zoom/setup.cfg index fcfe660c9..fbc9b4e02 100644 --- a/vc_zoom/setup.cfg +++ b/vc_zoom/setup.cfg @@ -11,13 +11,13 @@ classifiers = Environment :: Plugins Environment :: Web Environment License :: OSI Approved :: MIT License - Programming Language :: Python :: 2.7 + Programming Language :: Python :: 3.9 [options] packages = find: zip_safe = false include_package_data = true -python_requires = ~=2.7 +python_requires = ~=3.9 [options.entry_points] indico.plugins = diff --git a/vc_zoom/setup.py b/vc_zoom/setup.py index a1994c48d..b2f9e9eb0 100644 --- a/vc_zoom/setup.py +++ b/vc_zoom/setup.py @@ -5,7 +5,6 @@ # them and/or modify them under the terms of the MIT License; # see the LICENSE file for more details. -from __future__ import unicode_literals from setuptools import setup @@ -15,9 +14,9 @@ # is in setup.cfg now setup( name='indico-plugin-vc-zoom', - version='2.3b1', + version='3.0-dev', install_requires=[ - 'indico>=2.3.2.dev0', + 'indico>=3.0.dev0', 'PyJWT>=1.7.1,<2' ], )