From da24aa3f6e9195c9c1c71f7b5b4a3852261cef1b Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Tue, 21 Oct 2014 10:15:42 +0200 Subject: [PATCH] Python 3 style type hinting --- src/tixlbase/cache.py | 24 +++++++++++++----------- src/tixlbase/middleware.py | 2 +- src/tixlbase/models.py | 14 +++++++------- src/tixlbase/plugins.py | 2 +- src/tixlbase/tests/__init__.py | 2 +- src/tixlbase/types.py | 12 ++++++------ src/tixlcontrol/tests/test_auth.py | 10 ++++++++++ src/tixlcontrol/views/event.py | 8 ++++---- src/tixlcontrol/views/forms.py | 8 ++++---- 9 files changed, 47 insertions(+), 35 deletions(-) diff --git a/src/tixlbase/cache.py b/src/tixlbase/cache.py index 7a30a9525..89ce3dc6b 100644 --- a/src/tixlbase/cache.py +++ b/src/tixlbase/cache.py @@ -3,6 +3,8 @@ import hashlib from django.core.cache import caches +from tixlbase.models import Event + class EventRelatedCache: """ @@ -17,12 +19,12 @@ class EventRelatedCache: instantiate it as many times as you want. """ - def __init__(self, event, cache='default'): + def __init__(self, event: Event, cache: str='default'): self.cache = caches[cache] self.event = event self.prefixkey = 'event:%d' % self.event.pk - def _prefix_key(self, original_key): + def _prefix_key(self, original_key: str) -> str: # Race conditions can happen here, but should be very very rare. # We could only handle this by going _really_ lowlevel using # memcached's `add` keyword instead of `set`. @@ -39,7 +41,7 @@ class EventRelatedCache: return key @staticmethod - def _strip_prefix(key): + def _strip_prefix(key: str) -> str: return key.split(":", 3)[-1] if 'event:' in key else key def clear(self): @@ -49,35 +51,35 @@ class EventRelatedCache: prefix = int(time.time()) self.cache.set(self.prefixkey, prefix) - def set(self, key, value, timeout=3600): + def set(self, key: str, value: str, timeout: int=3600): return self.cache.set(self._prefix_key(key), value, timeout) - def get(self, key): + def get(self, key: str) -> str: return self.cache.get(self._prefix_key(key)) - def get_many(self, keys): + def get_many(self, keys: "list[str]") -> "dict[str, str]": values = self.cache.get_many([self._prefix_key(key) for key in keys]) newvalues = {} for k, v in values.items(): newvalues[self._strip_prefix(k)] = v return newvalues - def set_many(self, values, timeout=3600): + def set_many(self, values: "dict[str, str]", timeout=3600): newvalues = {} for k, v in values.items(): newvalues[self._prefix_key(k)] = v return self.cache.set_many(newvalues, timeout) - def delete(self, key): # NOQA + def delete(self, key: str): # NOQA return self.cache.delete(self._prefix_key(key)) - def delete_many(self, keys): # NOQA + def delete_many(self, keys: "list[str]"): # NOQA return self.cache.delete_many([self._prefix_key(key) for key in keys]) - def incr(self, key, by=1): # NOQA + def incr(self, key: str, by: int=1): # NOQA return self.cache.incr(self._prefix_key(key), by) - def decr(self, key, by=1): # NOQA + def decr(self, key: str, by: int=1): # NOQA return self.cache.decr(self._prefix_key(key), by) def close(self): # NOQA diff --git a/src/tixlbase/middleware.py b/src/tixlbase/middleware.py index b0f0cefe7..c60c2ff3e 100644 --- a/src/tixlbase/middleware.py +++ b/src/tixlbase/middleware.py @@ -62,7 +62,7 @@ class LocaleMiddleware(BaseLocaleMiddleware): return response -def get_language_from_request(request): +def get_language_from_request(request) -> str: """ Analyzes the request to find what language the user wants the system to show. Only languages listed in settings.LANGUAGES are taken into account. diff --git a/src/tixlbase/models.py b/src/tixlbase/models.py index 627f29c29..bf722867d 100644 --- a/src/tixlbase/models.py +++ b/src/tixlbase/models.py @@ -119,7 +119,7 @@ class User(AbstractBaseUser, PermissionsMixin): self.identifier = self.identifier.lower() super().save(*args, **kwargs) - def get_short_name(self): + def get_short_name(self) -> str: if self.givenname: return self.givenname elif self.familyname: @@ -127,7 +127,7 @@ class User(AbstractBaseUser, PermissionsMixin): else: return self.username - def get_full_name(self): + def get_full_name(self) -> str: if self.givenname and not self.familyname: return self.givenname elif not self.givenname and self.familyname: @@ -295,18 +295,18 @@ class Event(models.Model): self.get_cache().clear() return obj - def get_plugins(self): + def get_plugins(self) -> "list[str]": if self.plugins is None: return [] return self.plugins.split(",") - def get_date_from_display(self): + def get_date_from_display(self) -> str: return _date( self.date_from, "DATETIME_FORMAT" if self.show_times else "DATE_FORMAT" ) - def get_date_to_display(self): + def get_date_to_display(self) -> str: if not self.show_date_to: return "" return _date( @@ -314,7 +314,7 @@ class Event(models.Model): "DATETIME_FORMAT" if self.show_times else "DATE_FORMAT" ) - def get_cache(self): + def get_cache(self) -> "tixlbase.cache.EventRelatedCache": from tixlbase.cache import EventRelatedCache return EventRelatedCache(self) @@ -579,7 +579,7 @@ class Item(models.Model): self.active = False return super().save() - def get_all_variations(self, use_cache=False): + def get_all_variations(self, use_cache: bool=False) -> "list[VariationDict]": """ This method returns a list containing all variations of this item. The list contains one VariationDict per variation, where diff --git a/src/tixlbase/plugins.py b/src/tixlbase/plugins.py index 23a0ce33d..ffe7856fd 100644 --- a/src/tixlbase/plugins.py +++ b/src/tixlbase/plugins.py @@ -10,7 +10,7 @@ class PluginType(Enum): RESTRICTION = 1 -def get_all_plugins(): +def get_all_plugins() -> "class": plugins = [] for app in apps.get_app_configs(): if hasattr(app, 'TixlPluginMeta'): diff --git a/src/tixlbase/tests/__init__.py b/src/tixlbase/tests/__init__.py index f693c517d..9821ebac7 100644 --- a/src/tixlbase/tests/__init__.py +++ b/src/tixlbase/tests/__init__.py @@ -8,7 +8,7 @@ RUN_LOCAL = ('SAUCE_USERNAME' not in os.environ) if RUN_LOCAL: # could add Chrome, PhantomJS etc... here - BROWSERS = ['Chrome'] + BROWSERS = ['Chrome', 'Firefox'] else: from sauceclient import SauceClient USERNAME = os.environ.get('SAUCE_USERNAME') diff --git a/src/tixlbase/types.py b/src/tixlbase/types.py index 62cc361ff..e2e4df23a 100644 --- a/src/tixlbase/types.py +++ b/src/tixlbase/types.py @@ -6,7 +6,7 @@ class VariationDict(dict): code calling this method. """ - def relevant_items(self): + def relevant_items(self) -> "list[(int, PropertyValue)]": """ Iterate over all items with numeric keys. @@ -17,7 +17,7 @@ class VariationDict(dict): if type(i[0]) is int: yield i - def relevant_values(self): + def relevant_values(self) -> "list[PropertyValue]": """ Iterate over all values with numeric keys. @@ -28,7 +28,7 @@ class VariationDict(dict): if type(i[0]) is int: yield i[1] - def identify(self): + def identify(self) -> str: """ Build a simple and unique identifier for this dict. This can be any string used to compare one VariationDict to others. @@ -42,7 +42,7 @@ class VariationDict(dict): str(v[1].pk) for v in sorted(self.relevant_items(), key=order_key) )) - def key(self): + def key(self) -> str: """ Build an identifier for this dict which exactly specifies the combination for this variation without any doubt. This can be used to "talk" about a @@ -62,7 +62,7 @@ class VariationDict(dict): else: return super().__eq__(other) - def ordered_values(self): + def ordered_values(self) -> "list[ItemVariation]": """ Returns a list of values ordered by their keys """ @@ -74,7 +74,7 @@ class VariationDict(dict): ) ] - def copy(self): + def copy(self) -> "VariationDict": """ Return a one-level deep copy of this object (create a new VariationDict but make a shallow copy of the dict inside it). diff --git a/src/tixlcontrol/tests/test_auth.py b/src/tixlcontrol/tests/test_auth.py index d7c5ae219..4df288e05 100644 --- a/src/tixlcontrol/tests/test_auth.py +++ b/src/tixlcontrol/tests/test_auth.py @@ -22,6 +22,16 @@ class LoginFormBrowserTest(BrowserTest): self.driver.find_element_by_css_selector('button[type="submit"]').click() self.driver.find_element_by_class_name("navbar-right") + def test_login_fail(self): + self.driver.implicitly_wait(10) + self.driver.get('%s%s' % (self.live_server_url, '/control/login')) + username_input = self.driver.find_element_by_name("email") + username_input.send_keys('dummy@dummy.dummy') + password_input = self.driver.find_element_by_name("password") + password_input.send_keys('wrong') + self.driver.find_element_by_css_selector('button[type="submit"]').click() + self.driver.find_element_by_class_name("alert-danger") + class LoginFormTest(TestCase): """ diff --git a/src/tixlcontrol/views/event.py b/src/tixlcontrol/views/event.py index c3617ff76..03b2b8b02 100644 --- a/src/tixlcontrol/views/event.py +++ b/src/tixlcontrol/views/event.py @@ -52,10 +52,10 @@ class EventUpdate(EventPermissionRequiredMixin, UpdateView): template_name = 'tixlcontrol/event/settings.html' permission = 'can_change_settings' - def get_object(self, queryset=None): + def get_object(self, queryset=None) -> Event: return self.request.event - def get_success_url(self): + def get_success_url(self) -> str: return reverse('control:event.settings', kwargs={ 'organizer': self.get_object().organizer.slug, 'event': self.get_object().slug, @@ -72,7 +72,7 @@ class EventPlugins(EventPermissionRequiredMixin, TemplateView, SingleObjectMixin def get_object(self, queryset=None): return self.request.event - def get_context_data(self, *args, **kwargs): + def get_context_data(self, *args, **kwargs) -> dict: from tixlbase.plugins import get_all_plugins context = super().get_context_data(*args, **kwargs) context['plugins'] = [p for p in get_all_plugins() if not p.name.startswith('.')] @@ -98,7 +98,7 @@ class EventPlugins(EventPermissionRequiredMixin, TemplateView, SingleObjectMixin self.object.save() return redirect(self.get_success_url()) - def get_success_url(self): + def get_success_url(self) -> str: return reverse('control:event.settings.plugins', kwargs={ 'organizer': self.get_object().organizer.slug, 'event': self.get_object().slug, diff --git a/src/tixlcontrol/views/forms.py b/src/tixlcontrol/views/forms.py index d86fc670d..08f085ae6 100644 --- a/src/tixlcontrol/views/forms.py +++ b/src/tixlcontrol/views/forms.py @@ -12,7 +12,7 @@ from tixlbase.models import ItemVariation, PropertyValue, Item class TolerantFormsetModelForm(forms.ModelForm): - def has_changed(self): + def has_changed(self) -> bool: """ Returns True if data differs from initial. Contrary to the default implementation, the ORDER field is being ignored. @@ -231,11 +231,11 @@ class VariationsField(forms.ModelMultipleChoiceField): kwargs['widget'] = VariationsSelectMultiple super().__init__(*args, **kwargs) - def set_item(self, item): + def set_item(self, item: Item): self.item = item self._set_choices(self._get_choices()) - def _get_choices(self): + def _get_choices(self) -> "list[(str, VariationDict)]": """ We can't use a normal QuerySet as there theoretically might be two types of variations: Some who already have a ItemVariation @@ -255,7 +255,7 @@ class VariationsField(forms.ModelMultipleChoiceField): ) for v in variations ) - def clean(self, value): + def clean(self, value: "list[int]"): """ At cleaning time, we have to clean up the mess we produced with our _get_choices implementation. In the case of ItemVariation object ids