You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
65 lines
2.0 KiB
65 lines
2.0 KiB
# -*- coding: utf-8 -*-
|
|
|
|
import re
|
|
import sys
|
|
from decorator import decorator
|
|
from .errors import AccessError
|
|
|
|
# Help class(...es? Nah. Just singular for now.)
|
|
|
|
class NoNoneDict(dict):
|
|
"""A dict that ignores values that are None. Not completely API-compatible
|
|
with dict, but contains all that's needed.
|
|
"""
|
|
def __repr__(self):
|
|
return "NoNoneDict({dict})".format(dict=dict.__repr__(self))
|
|
|
|
def __init__(self, initial={}):
|
|
self.update(initial)
|
|
|
|
def __setitem__(self, key, value):
|
|
if value is not None:
|
|
dict.__setitem__(self, key, value)
|
|
|
|
def update(self, data):
|
|
for key, value in data.items():
|
|
self[key] = value
|
|
|
|
# Decorators / factories
|
|
|
|
@decorator
|
|
def requires_secret_key(func, self, *args, **kwargs):
|
|
"""Raise an error if the method is called without a secret key."""
|
|
if self.secret_key is None:
|
|
raise AccessError("The Service doesn't have a secret "
|
|
"key provided, and therefore lacks write permission.")
|
|
return func(self, *args, **kwargs)
|
|
|
|
def with_api_bound(cls, api):
|
|
new_cls = type(cls.__name__, (cls,), {
|
|
'_api': api,
|
|
'__doc__': (
|
|
"Create a :class:`~pushjet.{name}` bound to the API. "
|
|
"See :class:`pushjet.{name}` for documentation."
|
|
).format(name=cls.__name__)
|
|
})
|
|
return new_cls
|
|
|
|
# Helper functions
|
|
|
|
UUID_RE = re.compile(r'^[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}$')
|
|
PUBLIC_KEY_RE = re.compile(r'^[A-Za-z0-9]{4}-[A-Za-z0-9]{6}-[A-Za-z0-9]{12}-[A-Za-z0-9]{5}-[A-Za-z0-9]{9}$')
|
|
SECRET_KEY_RE = re.compile(r'^[A-Za-z0-9]{32}$')
|
|
|
|
is_valid_uuid = lambda s: UUID_RE.match(s) is not None
|
|
is_valid_public_key = lambda s: PUBLIC_KEY_RE.match(s) is not None
|
|
is_valid_secret_key = lambda s: SECRET_KEY_RE.match(s) is not None
|
|
|
|
def repr_format(s):
|
|
s = s.replace('\n', ' ').replace('\r', '')
|
|
original_length = len(s)
|
|
s = s[:30]
|
|
s += '...' if len(s) != original_length else ''
|
|
s = s.encode(sys.stdout.encoding, errors='replace')
|
|
return s
|