API

This part of the documentation covers the developer interfaces of Shorten.

Store Objects

The base classes used to create and operate stores. Methods that should be implemented by a custom class are indicated.

class shorten.BaseStore(key_gen=None, formatter=None, token_gen=None)

Stores allow insertion, deletion and lookup of data through an interface similar to a Python dict, the primary difference being that store keys are generated automatically by a key generator (or keygen). tokens are used to delete values from the store and are supplied by a token generator.

Because they are closely associated, keys and tokens are returned in a Pair. A pair is a named tuple containing a key and token (in that order) as well key and token attributes.

s = Store()
key, token = pair = s.insert('aardvark')

# 'aardvark'
s[pair.key]

# True
pair.key == pair[0] == key

# True
pair.token == pair[1] == token

# Removes 'aardvark'
del s[pair.token]

Unlike a Python dict, a BaseStore allows insertion but no modification of its values. Some stores may provide __len__() and __iter__() methods if the underlying storage mechanism makes it feasible.

Subclassing

Subclasses should implement insert(), revoke(), get_value(), has_key(), has_token(), get_token() and get_value()

Parameters:
  • key_gen – a Keygen that generates unique keys.
  • formatter – a Formatter used to transform keys and tokens for storage in a backend.
  • token_gen – an object with a create_token() method that returns unique revokation tokens.
get(key, default=None)

Get the value for key or default if the key does not exist.

get_token(key)

Returns the token for key.

get_value(key)

Gets the value for key or raise a KeyError if it doesn’t exist. get() and store[key] will call this method.

has_key(key)

Returns True if the key exists in this store, False otherwise.

has_token(token)

Returns True if the token exists in this store, False otherwise.

insert(val)

Insert a val and return a Pair, which is a tuple. It contains a key and token (in that order) as well key and token attributes.

pair = store.insert('aardvark')
key, token = pair

# True
pair.key == pair[0] == key

# True
pair.token == pair[1] == token

If the generated key exists or the cannot be stored, a KeyInsertError is raised (or a TokenInsertError for tokens).

try:
   store.insert('bonobo')
except (KeyInsertError, TokenInsertError):
   print('Cannot insert')
next_formatted_pair()

Returns a FormattedPair containing attributes key, token, formatted_key and formatted_token. Calling this method will always consume a key and token.

revoke(token)

Revokes the token. A RevokeError is raised if the token is not found or the underlying storage cannot complete the revokation.

try:
   store.revoke(token)
   print('Revoked!')
except RevokeError:
   print('Could not revoke')
class shorten.BaseKeyGenerator(alphabet=None, min_length=None, start=None)

A class which yields a unique string on every iteration (a key). If the key generator is deterministic, then two generators should yield the same keys given the same parameters.

alphabet can be any iterable, as long as each item is not contained within any other item. For instance, ('00', '0', '1') would be an ambiguous alphabet, since 00 could be interpreted as two numbers.

Each yielded key is expected to be encoded with encode()

class KeyGenerator(BaseKeyGenerator):
   def __iter__(self):
      ...
      yield self.encode(num)

Keys of a minimum length or starting at a certain unencoded value can be generated by specifying min_length or start.

hexabet = '0123456789abcef'
keygen = KeyGenerator(start=255, alphabet=hexabet)

# ['ff', '100', '101']
[key for key in islice(k, 0, 3)]

Subclassing

Subclasses should implement __iter__.

Parameters:
  • alphabet – an iterable.
  • start – the number to start iteration at.
  • min_length – the length of the string to start iteration at. Leading zero-characters are not counted in the length. Only one of start or min_length should be given.
shorten.make_store(name, min_length=4, **kwargs)

Creates a store with a reasonable keygen.

Deprecated since version 2.0.0: Instantiate stores directly e.g. shorten.MemoryStore(min_length=4)

Memory Stores

class shorten.MemoryStore(**kwargs)

Stores keys, tokens and data in memory.

If key_gen is None, a MemoryKeygen will be created with the following paramters:

alphabet an iterable of characters in an alphabet.
min_length the minimum key length to begin generating keys at.
start the number to start the keygen’s counter at.
Parameters:key_gen (a MemoryKeygen or None) – a key generator. If None, a new key generator is created (see above).
get(key, default=None)

Get the value for key or default if the key does not exist.

next_formatted_pair()

Returns a FormattedPair containing attributes key, token, formatted_key and formatted_token. Calling this method will always consume a key and token.

class shorten.MemoryKeygen(alphabet=None, min_length=None, start=None)

Creates keys in-memory. Keys are always generated in increasing order.

Redis Stores

class shorten.RedisStore(**kwargs)

Stores keys, tokens and data in Redis.

If key_gen is None, a RedisKeygen <shorten.RedisKeygen will be created with the following paramters:

alphabet an iterable of characters in an alphabet.
min_length the minimum key length to begin generating keys at.
start the number to start the keygen’s counter at.
counter_key the Redis key in which to store the keygen’s counter value.
redis_client an open Redis connection.
Parameters:
  • counter_key – the Redis key in which to store the keygen’s counter value.
  • key_gen (a RedisKeyGen or None) – a key generator. If None, a new key generator is created (see above).
  • redis_client – an open Redis connection.
insert(val, pipe=None)

Inserts a value and returns a Pair.

Key Safety

Keys and tokens are always inserted with a Pipeline, so irrevocable keys will never occur.

If pipe is given, KeyInsertError and TokenInsertError will not be thrown if duplicate keys and tokens exist. Instead, the nth-from-last results must be checked:

pipe = redis.pipeline()
key, token = short.insert('value', pipe)
results = pipe.execute()

if not results[-2]:
   raise KeyInsertError(key)

if not results[-1]:
   raise TokenInsertError(token)
Attr val:a value to insert.
Attr pipe:a Redis pipeline. If None, the pair will be returned immediately. Otherwise they must be extracted from the pipeline results (see above).
revoke(token, pipe=None)

Revokes the key associated with the given revokation token.

If the token does not exist, a KeyError is thrown. Otherwise None is returned.

If pipe is given, then a RevokeError will not be thrown if the key does not exist. The n-th from last result should be checked like so:

pipe = redis.Pipeline()
store.revoke(token, pipe=pipe)

results = pipe.execute()
if not results[-1]:
   raise RevokeError(token)
Parameters:pipe – a Redis pipeline. If None, the token will be revoked immediately. Otherwise they must be extracted from the pipeline results (see above).
class shorten.RedisKeygen(redis_client=None, counter_key=None, **kwargs)

Creates keys in Redis. Keys are always generated in increasing order.

Parameters:
  • redis – an open Redis connection.
  • counter_key – the Redis key in which to store the keygen’s counter value.

Memcache Stores

class shorten.MemcacheStore(**kwargs)

Stores keys, tokens and data in Memcache.

If key_gen is None, a MemcacheKeygen
will be created with the following paramters:
alphabet an iterable of characters in an alphabet.
min_length the minimum key length to begin generating keys at.
start the number to start the keygen’s counter at.
counter_key the Memcache key in which to store the keygen’s counter value.
memcache_client a Memcache client.
Parameters:
  • counter_key – the Memcache key in which to store the keygen’s counter value.
  • key_gen (a MemcacheKeyGen or None) – a key generator. If None, a new key generator is created (see above).
  • redis_client – a Memcache client.
insert(val)

Inserts a value and returns a Pair.

If the generated key exists or memcache cannot store it, a KeyInsertError is raised (or a TokenInsertError if a token exists or cannot be stored).

class shorten.MemcacheKeygen(memcache_client=None, counter_key=None, **kwargs)

Creates keys in-memory. Keys are always generated in increasing order.

Token Generators

class shorten.TokenGenerator

A token generator which returns the key passed to it.

class shorten.UUIDTokenGenerator

A token generator which returns a UUID4 (random) token. See https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_.28random.29

Formatter Objects

class shorten.Formatter

A formatter is used to format the internal representation of a key or token. This is useful for Redis and SQL databases, which often need to prefix keys and columns in order to avoid clashes.

Subclassing

Subclasses should implement format_key(key) and format_token(token).

format_key(key)

Formats a key.

format_token(token)

Formats a token.

class shorten.NamespacedFormatter(namespace)

Prefixes keys and tokens with namespace string.

Parameters:namespace – a string to prefix to keys and tokens.

Encoding and Decoding

shorten.key.bx_encode(n, alphabet)

Encodes an integer n in base len(alphabet) with digits in alphabet.

# 'ba'
bx_encode(3, 'abc')
Parameters:
  • n – a positive integer.
  • alphabet – a 0-based iterable.
shorten.key.bx_decode(string, alphabet, mapping=None)

Transforms a string in alphabet to an integer.

If mapping is provided, each key must map to its positional value without duplicates.

mapping = {'a': 0, 'b': 1, 'c': 2}

# 3
bx_decode('ba', 'abc', mapping)
Parameters:
  • string – a string consisting of key from alphabet.
  • alphabet – a 0-based iterable.
  • mapping – a Mapping. If None, the inverse of alphabet is used, with values mapped to indices.

Table Of Contents

Related Topics

This Page

Fork me on GitHub