def redirect(self, url): """Used when you need to redirect to another view, and you only have the final plugin:// url.""" # TODO: Should we be overriding self.request with the new request? new_request = self._parse_request(url=url, handle=self.request.handle) log.debug('Redirecting %s to %s', self.request.path, new_request.path) return self._dispatch(new_request.path)
def redirect(self, url): """Used when you need to redirect to another view, and you only have the final plugin:// url.""" new_request = self._parse_request(url=url, handle=self.request.handle) log.debug('Redirecting %s to %s', self.request.path, new_request.path) self._request = new_request return self._dispatch(new_request.path)
def get_storage(self, name='main', file_format='pickle', ttl=None): """Returns a storage for the given name. The returned storage is a fully functioning python dictionary and is designed to be used that way. It is usually not necessary for the caller to load or save the storage manually. If the storage does not already exist, it will be created. See Also: :class:`kodiswift.TimedStorage` for more details. Args: name (str): The name of the storage to retrieve. file_format (str): Choices are 'pickle', 'csv', and 'json'. Pickle is recommended as it supports python objects. Notes: If a storage already exists for the given name, the file_format parameter is ignored. The format will be determined by the existing storage file. ttl (int): The time to live for storage items specified in minutes or None for no expiration. Since storage items aren't expired until a storage is loaded form disk, it is possible to call get_storage() with a different TTL than when the storage was created. The currently specified TTL is always honored. Returns: kodiswift.storage.TimedStorage: """ if not hasattr(self, '_unsynced_storage'): self._unsynced_storage = {} filename = os.path.join(self.storage_path, name) try: storage = self._unsynced_storage[filename] log.debug('Loaded storage "%s" from memory', name) except KeyError: if ttl: ttl = timedelta(minutes=ttl) try: storage = TimedStorage(filename, ttl, file_format=file_format) storage.load() except UnknownFormat: # Thrown when the storage file is corrupted and can't be read. # Prompt user to delete storage. choices = ['Clear storage', 'Cancel'] ret = xbmcgui.Dialog().select( 'A storage file is corrupted. It' ' is recommended to clear it.', choices) if ret == 0: os.remove(filename) storage = TimedStorage(filename, ttl, file_format=file_format) else: raise Exception('Corrupted storage file at %s' % filename) self._unsynced_storage[filename] = storage log.debug('Loaded storage "%s" from disk', name) return storage
def run(self): """The main entry point for a plugin.""" self._request = self._parse_request() log.debug('Handling incoming request for %s', self.request.path) items = self._dispatch(self.request.path) # Close any open storages which will persist them to disk if hasattr(self, '_unsynced_storage'): for storage in self._unsynced_storage.values(): log.debug('Saving a %s storage to disk at "%s"', storage.file_format, storage.file_path) storage.close() return items
def wrapper(*args, **kwargs): key = (function.__name__, kwd_mark) + args if kwargs: key += (kwd_mark, ) + tuple(sorted(kwargs.items())) try: result = storage[key] log.debug( 'Storage hit for function "%s" with args "%s" ' 'and kwargs "%s"', function.__name__, args, kwargs) except KeyError: log.debug( 'Storage miss for function "%s" with args "%s" ' 'and kwargs "%s"', function.__name__, args, kwargs) result = function(*args, **kwargs) storage[key] = result storage.sync() return result
def wrapper(*args, **kwargs): key = (function.__name__, kwd_mark) + args if kwargs: key += (kwd_mark,) + tuple(sorted(kwargs.items())) try: result = storage[key] log.debug('Storage hit for function "%s" with args "%s" ' 'and kwargs "%s"', function.__name__, args, kwargs) except KeyError: log.debug('Storage miss for function "%s" with args "%s" ' 'and kwargs "%s"', function.__name__, args, kwargs) result = function(*args, **kwargs) storage[key] = result storage.sync() return result
def add_url_rule(self, url_rule, view_func, name, options=None): """This method adds a URL rule for routing purposes. The provided name can be different from the view function name if desired. The provided name is what is used in url_for to build a URL. The route decorator provides the same functionality. """ rule = UrlRule(url_rule, view_func, name, options) if name in self._view_functions.keys(): # TODO: Raise exception for ambiguous views during registration log.warning('Cannot add url rule "%s" with name "%s". There is ' 'already a view with that name', url_rule, name) self._view_functions[name] = None else: log.debug('Adding url rule "%s" named "%s" pointing to function ' '"%s"', url_rule, name, view_func.__name__) self._view_functions[name] = rule self._routes.append(rule)
def add_url_rule(self, url_rule, view_func, name, options=None): """This method adds a URL rule for routing purposes. The provided name can be different from the view function name if desired. The provided name is what is used in url_for to build a URL. The route decorator provides the same functionality. """ rule = UrlRule(url_rule, view_func, name, options) if name in self._view_functions.keys(): # TODO: Raise exception for ambiguous views during registration log.warning( 'Cannot add url rule "%s" with name "%s". There is ' 'already a view with that name', url_rule, name) self._view_functions[name] = None else: log.debug( 'Adding url rule "%s" named "%s" pointing to function ' '"%s"', url_rule, name, view_func.__name__) self._view_functions[name] = rule self._routes.append(rule)