Python 3 style type hinting

This commit is contained in:
Raphael Michel
2014-10-21 10:15:42 +02:00
parent c604d45488
commit da24aa3f6e
9 changed files with 47 additions and 35 deletions

View File

@@ -3,6 +3,8 @@ import hashlib
from django.core.cache import caches from django.core.cache import caches
from tixlbase.models import Event
class EventRelatedCache: class EventRelatedCache:
""" """
@@ -17,12 +19,12 @@ class EventRelatedCache:
instantiate it as many times as you want. 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.cache = caches[cache]
self.event = event self.event = event
self.prefixkey = 'event:%d' % self.event.pk 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. # Race conditions can happen here, but should be very very rare.
# We could only handle this by going _really_ lowlevel using # We could only handle this by going _really_ lowlevel using
# memcached's `add` keyword instead of `set`. # memcached's `add` keyword instead of `set`.
@@ -39,7 +41,7 @@ class EventRelatedCache:
return key return key
@staticmethod @staticmethod
def _strip_prefix(key): def _strip_prefix(key: str) -> str:
return key.split(":", 3)[-1] if 'event:' in key else key return key.split(":", 3)[-1] if 'event:' in key else key
def clear(self): def clear(self):
@@ -49,35 +51,35 @@ class EventRelatedCache:
prefix = int(time.time()) prefix = int(time.time())
self.cache.set(self.prefixkey, prefix) 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) 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)) 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]) values = self.cache.get_many([self._prefix_key(key) for key in keys])
newvalues = {} newvalues = {}
for k, v in values.items(): for k, v in values.items():
newvalues[self._strip_prefix(k)] = v newvalues[self._strip_prefix(k)] = v
return newvalues return newvalues
def set_many(self, values, timeout=3600): def set_many(self, values: "dict[str, str]", timeout=3600):
newvalues = {} newvalues = {}
for k, v in values.items(): for k, v in values.items():
newvalues[self._prefix_key(k)] = v newvalues[self._prefix_key(k)] = v
return self.cache.set_many(newvalues, timeout) 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)) 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]) 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) 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) return self.cache.decr(self._prefix_key(key), by)
def close(self): # NOQA def close(self): # NOQA

View File

@@ -62,7 +62,7 @@ class LocaleMiddleware(BaseLocaleMiddleware):
return response 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 Analyzes the request to find what language the user wants the system to
show. Only languages listed in settings.LANGUAGES are taken into account. show. Only languages listed in settings.LANGUAGES are taken into account.

View File

@@ -119,7 +119,7 @@ class User(AbstractBaseUser, PermissionsMixin):
self.identifier = self.identifier.lower() self.identifier = self.identifier.lower()
super().save(*args, **kwargs) super().save(*args, **kwargs)
def get_short_name(self): def get_short_name(self) -> str:
if self.givenname: if self.givenname:
return self.givenname return self.givenname
elif self.familyname: elif self.familyname:
@@ -127,7 +127,7 @@ class User(AbstractBaseUser, PermissionsMixin):
else: else:
return self.username return self.username
def get_full_name(self): def get_full_name(self) -> str:
if self.givenname and not self.familyname: if self.givenname and not self.familyname:
return self.givenname return self.givenname
elif not self.givenname and self.familyname: elif not self.givenname and self.familyname:
@@ -295,18 +295,18 @@ class Event(models.Model):
self.get_cache().clear() self.get_cache().clear()
return obj return obj
def get_plugins(self): def get_plugins(self) -> "list[str]":
if self.plugins is None: if self.plugins is None:
return [] return []
return self.plugins.split(",") return self.plugins.split(",")
def get_date_from_display(self): def get_date_from_display(self) -> str:
return _date( return _date(
self.date_from, self.date_from,
"DATETIME_FORMAT" if self.show_times else "DATE_FORMAT" "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: if not self.show_date_to:
return "" return ""
return _date( return _date(
@@ -314,7 +314,7 @@ class Event(models.Model):
"DATETIME_FORMAT" if self.show_times else "DATE_FORMAT" "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 from tixlbase.cache import EventRelatedCache
return EventRelatedCache(self) return EventRelatedCache(self)
@@ -579,7 +579,7 @@ class Item(models.Model):
self.active = False self.active = False
return super().save() 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 This method returns a list containing all variations of this
item. The list contains one VariationDict per variation, where item. The list contains one VariationDict per variation, where

View File

@@ -10,7 +10,7 @@ class PluginType(Enum):
RESTRICTION = 1 RESTRICTION = 1
def get_all_plugins(): def get_all_plugins() -> "class":
plugins = [] plugins = []
for app in apps.get_app_configs(): for app in apps.get_app_configs():
if hasattr(app, 'TixlPluginMeta'): if hasattr(app, 'TixlPluginMeta'):

View File

@@ -8,7 +8,7 @@ RUN_LOCAL = ('SAUCE_USERNAME' not in os.environ)
if RUN_LOCAL: if RUN_LOCAL:
# could add Chrome, PhantomJS etc... here # could add Chrome, PhantomJS etc... here
BROWSERS = ['Chrome'] BROWSERS = ['Chrome', 'Firefox']
else: else:
from sauceclient import SauceClient from sauceclient import SauceClient
USERNAME = os.environ.get('SAUCE_USERNAME') USERNAME = os.environ.get('SAUCE_USERNAME')

View File

@@ -6,7 +6,7 @@ class VariationDict(dict):
code calling this method. code calling this method.
""" """
def relevant_items(self): def relevant_items(self) -> "list[(int, PropertyValue)]":
""" """
Iterate over all items with numeric keys. Iterate over all items with numeric keys.
@@ -17,7 +17,7 @@ class VariationDict(dict):
if type(i[0]) is int: if type(i[0]) is int:
yield i yield i
def relevant_values(self): def relevant_values(self) -> "list[PropertyValue]":
""" """
Iterate over all values with numeric keys. Iterate over all values with numeric keys.
@@ -28,7 +28,7 @@ class VariationDict(dict):
if type(i[0]) is int: if type(i[0]) is int:
yield i[1] yield i[1]
def identify(self): def identify(self) -> str:
""" """
Build a simple and unique identifier for this dict. This can be any string Build a simple and unique identifier for this dict. This can be any string
used to compare one VariationDict to others. 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) 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 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 for this variation without any doubt. This can be used to "talk" about a
@@ -62,7 +62,7 @@ class VariationDict(dict):
else: else:
return super().__eq__(other) return super().__eq__(other)
def ordered_values(self): def ordered_values(self) -> "list[ItemVariation]":
""" """
Returns a list of values ordered by their keys 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 Return a one-level deep copy of this object (create a new
VariationDict but make a shallow copy of the dict inside it). VariationDict but make a shallow copy of the dict inside it).

View File

@@ -22,6 +22,16 @@ class LoginFormBrowserTest(BrowserTest):
self.driver.find_element_by_css_selector('button[type="submit"]').click() self.driver.find_element_by_css_selector('button[type="submit"]').click()
self.driver.find_element_by_class_name("navbar-right") 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): class LoginFormTest(TestCase):
""" """

View File

@@ -52,10 +52,10 @@ class EventUpdate(EventPermissionRequiredMixin, UpdateView):
template_name = 'tixlcontrol/event/settings.html' template_name = 'tixlcontrol/event/settings.html'
permission = 'can_change_settings' permission = 'can_change_settings'
def get_object(self, queryset=None): def get_object(self, queryset=None) -> Event:
return self.request.event return self.request.event
def get_success_url(self): def get_success_url(self) -> str:
return reverse('control:event.settings', kwargs={ return reverse('control:event.settings', kwargs={
'organizer': self.get_object().organizer.slug, 'organizer': self.get_object().organizer.slug,
'event': self.get_object().slug, 'event': self.get_object().slug,
@@ -72,7 +72,7 @@ class EventPlugins(EventPermissionRequiredMixin, TemplateView, SingleObjectMixin
def get_object(self, queryset=None): def get_object(self, queryset=None):
return self.request.event 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 from tixlbase.plugins import get_all_plugins
context = super().get_context_data(*args, **kwargs) context = super().get_context_data(*args, **kwargs)
context['plugins'] = [p for p in get_all_plugins() if not p.name.startswith('.')] 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() self.object.save()
return redirect(self.get_success_url()) return redirect(self.get_success_url())
def get_success_url(self): def get_success_url(self) -> str:
return reverse('control:event.settings.plugins', kwargs={ return reverse('control:event.settings.plugins', kwargs={
'organizer': self.get_object().organizer.slug, 'organizer': self.get_object().organizer.slug,
'event': self.get_object().slug, 'event': self.get_object().slug,

View File

@@ -12,7 +12,7 @@ from tixlbase.models import ItemVariation, PropertyValue, Item
class TolerantFormsetModelForm(forms.ModelForm): class TolerantFormsetModelForm(forms.ModelForm):
def has_changed(self): def has_changed(self) -> bool:
""" """
Returns True if data differs from initial. Contrary to the default Returns True if data differs from initial. Contrary to the default
implementation, the ORDER field is being ignored. implementation, the ORDER field is being ignored.
@@ -231,11 +231,11 @@ class VariationsField(forms.ModelMultipleChoiceField):
kwargs['widget'] = VariationsSelectMultiple kwargs['widget'] = VariationsSelectMultiple
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
def set_item(self, item): def set_item(self, item: Item):
self.item = item self.item = item
self._set_choices(self._get_choices()) 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 We can't use a normal QuerySet as there theoretically might be
two types of variations: Some who already have a ItemVariation two types of variations: Some who already have a ItemVariation
@@ -255,7 +255,7 @@ class VariationsField(forms.ModelMultipleChoiceField):
) for v in variations ) 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 At cleaning time, we have to clean up the mess we produced with our
_get_choices implementation. In the case of ItemVariation object ids _get_choices implementation. In the case of ItemVariation object ids