[Python-modules-commits] [python-hashids] 01/03: import python-hashids_1.1.0.orig.tar.gz

Edward Betts edward at moszumanska.debian.org
Wed Apr 13 12:53:28 UTC 2016


This is an automated email from the git hooks/post-receive script.

edward pushed a commit to branch master
in repository python-hashids.

commit 302cc8571a9d0aa41ae45cb87f5709150655c00d
Author: Edward Betts <edward at 4angle.com>
Date:   Wed Apr 13 13:32:45 2016 +0100

    import python-hashids_1.1.0.orig.tar.gz
---
 CHANGELOG            |  20 ++++
 LICENSE              |  22 ++++
 PKG-INFO             | 176 +++++++++++++++++++++++++++++++
 README.rst           | 166 ++++++++++++++++++++++++++++++
 hashids.py           | 285 +++++++++++++++++++++++++++++++++++++++++++++++++++
 setup.py             |  15 +++
 test/test_hashids.py | 176 +++++++++++++++++++++++++++++++
 test/test_legacy.py  | 154 ++++++++++++++++++++++++++++
 8 files changed, 1014 insertions(+)

diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644
index 0000000..cf82ded
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,20 @@
+v1.1.0 / 2015-03-31
+  - add encode_hex() / decode_hex()
+
+v1.0.3 / 2015-02-26
+  - remove dependency to `future`
+
+v1.0.2 / 2015-01-15
+  - compatibility with JS version 1.0.x
+
+v1.0.1 / 2014-06-19
+  - only decode hashids if the re-encoded result equals the input
+
+v1.0.0 / 2014-04-21
+  - compatibility with JS version 0.3.x
+
+v0.8.4 / 2014-02-04
+  - Make setup.py compatible with older python versions
+
+v0.8.3 / 2013-06-02
+  - initial release, compatible with JS version 0.1.x
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..cc45fd4
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2012-2014 Ivan Akimov, David Aurelio
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..d739a51
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,176 @@
+Metadata-Version: 1.0
+Name: hashids
+Version: 1.1.0
+Summary: Python implementation of hashids (http://www.hashids.org).Compatible with python 2.6-3.
+Home-page: https://github.com/davidaurelio/hashids-python
+Author: David Aurelio
+Author-email: dev at david-aurelio.com
+License: MIT License
+Description: ========================
+        hashids for Python 2.6–3
+        ========================
+        
+        A python port of the JavaScript *hashids* implementation. It generates YouTube-like hashes from one or many numbers. Use hashids when you do not want to expose your database ids to the user. Website: http://www.hashids.org/
+        
+        Compatibility
+        =============
+        
+        hashids is tested with python 2.6, 2.7, 3.2, 3.3 and 3.4. PyPy and PyPy 3 work as well.
+        
+        .. image:: https://travis-ci.org/davidaurelio/hashids-python.svg?branch=master
+            :target: https://travis-ci.org/davidaurelio/hashids-python
+        
+        Compatibility with the JavaScript implementation
+        ------------------------------------------------
+        
+        ==================   ==============
+        hashids/JavaScript   hashids/Python
+        ------------------   --------------
+        v0.1.x               v0.8.x
+        v0.3.x and v1.0.x    v1.0.2+
+        ==================   ==============
+        
+        The JavaScript implementation produces different hashes in versions 0.1.x and 0.3.x. For compatibility with the older 0.1.x version install hashids 0.8.4 from pip, otherwise the newest hashids.
+        
+        
+        Installation
+        ============
+        
+        Install the module from PyPI, e. g. with pip:
+        
+        .. code:: bash
+        
+          pip install hashids
+          pip install hashids==0.8.4 # for compatibility with hashids.js 0.1.x
+        
+        Run the tests
+        =============
+        
+        The tests are written with `pytest <http://pytest.org/latest/>`_. The pytest module has to be installed.
+        
+        .. code:: bash
+        
+          python -m pytest
+        
+        Usage
+        =====
+        
+        Import the constructor from the ``hashids`` module:
+        
+        .. code:: python
+        
+          from hashids import Hashids
+          hashids = Hashids()
+        
+        Basic Usage
+        -----------
+        
+        Encode a single integer:
+        
+        .. code:: python
+        
+          hashid = hashids.encode(123) # 'Mj3'
+        
+        Decode a hash:
+        
+        .. code:: python
+        
+          ints = hashids.decode('xoz') # (456,)
+        
+        To encode several integers, pass them all at once:
+        
+        .. code:: python
+        
+          hashid = hashids.encode(123, 456, 789) # 'El3fkRIo3'
+        
+        Decoding is done the same way:
+        
+        .. code:: python
+        
+          ints = hashids.decode('1B8UvJfXm') # (517, 729, 185)
+        
+        Using A Custom Salt
+        -------------------
+        
+        Hashids supports salting hashes by accepting a salt value. If you don’t want others to decode your hashes, provide a unique string to the constructor.
+        
+        .. code:: python
+        
+          hashids = Hashids(salt='this is my salt 1')
+          hashid = hashids.encode(123) # 'nVB'
+        
+        The generated hash changes whenever the salt is changed:
+        
+        .. code:: python
+        
+          hashids = Hashids(salt='this is my salt 2')
+          hashid = hashids.encode(123) # 'ojK'
+        
+        A salt string between 6 and 32 characters provides decent randomization.
+        
+        Controlling Hash Length
+        -----------------------
+        
+        By default, hashes are going to be the shortest possible. One reason you might want to increase the hash length is to obfuscate how large the integer behind the hash is.
+        
+        This is done by passing the minimum hash length to the constructor. Hashes are padded with extra characters to make them seem longer.
+        
+        .. code:: python
+        
+          hashids = Hashids(min_length=16)
+          hashid = hashids.encode(1) # '4q2VolejRejNmGQB'
+        
+        Using A Custom Alphabet
+        -----------------------
+        
+        It’s possible to set a custom alphabet for your hashes. The default alphabet is ``'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'``.
+        
+        To have only lowercase letters in your hashes, pass in the following custom alphabet:
+        
+        .. code:: python
+        
+          hashids = Hashids(alphabet='abcdefghijklmnopqrstuvwxyz')
+          hashid = hashids.encode(123456789) # 'kekmyzyk'
+        
+        A custom alphabet must contain at least 16 characters.
+        
+        Randomness
+        ==========
+        
+        The primary purpose of hashids is to obfuscate ids. It's not meant or tested to be used for security purposes or compression. Having said that, this algorithm does try to make these hashes unguessable and unpredictable:
+        
+        Repeating numbers
+        -----------------
+        
+        There are no repeating patterns that might show that there are 4 identical numbers in the hash:
+        
+        .. code:: python
+        
+          hashids = Hashids("this is my salt")
+          hashids.encode(5, 5, 5, 5) # '1Wc8cwcE'
+        
+        The same is valid for incremented numbers:
+        
+        .. code:: python
+        
+          hashids.encode(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) # 'kRHnurhptKcjIDTWC3sx'
+        
+          hashids.encode(1) # 'NV'
+          hashids.encode(2) # '6m'
+          hashids.encode(3) # 'yD'
+          hashids.encode(4) # '2l'
+          hashids.encode(5) # 'rD'
+        
+        Curses! #$%@
+        ============
+        
+        This code was written with the intent of placing generated hashes in visible places – like the URL.  Which makes it unfortunate if generated hashes accidentally formed a bad word.
+        
+        Therefore, the algorithm tries to avoid generating most common English curse words by never placing the following letters next to each other: **c, C, s, S, f, F, h, H, u, U, i, I, t, T.**
+        
+        License
+        =======
+        
+        MIT license, see the LICENSE file. You can use hashids in open source projects and commercial products.
+        
+Platform: UNKNOWN
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..c408ab3
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,166 @@
+========================
+hashids for Python 2.6–3
+========================
+
+A python port of the JavaScript *hashids* implementation. It generates YouTube-like hashes from one or many numbers. Use hashids when you do not want to expose your database ids to the user. Website: http://www.hashids.org/
+
+Compatibility
+=============
+
+hashids is tested with python 2.6, 2.7, 3.2, 3.3 and 3.4. PyPy and PyPy 3 work as well.
+
+.. image:: https://travis-ci.org/davidaurelio/hashids-python.svg?branch=master
+    :target: https://travis-ci.org/davidaurelio/hashids-python
+
+Compatibility with the JavaScript implementation
+------------------------------------------------
+
+==================   ==============
+hashids/JavaScript   hashids/Python
+------------------   --------------
+v0.1.x               v0.8.x
+v0.3.x and v1.0.x    v1.0.2+
+==================   ==============
+
+The JavaScript implementation produces different hashes in versions 0.1.x and 0.3.x. For compatibility with the older 0.1.x version install hashids 0.8.4 from pip, otherwise the newest hashids.
+
+
+Installation
+============
+
+Install the module from PyPI, e. g. with pip:
+
+.. code:: bash
+
+  pip install hashids
+  pip install hashids==0.8.4 # for compatibility with hashids.js 0.1.x
+
+Run the tests
+=============
+
+The tests are written with `pytest <http://pytest.org/latest/>`_. The pytest module has to be installed.
+
+.. code:: bash
+
+  python -m pytest
+
+Usage
+=====
+
+Import the constructor from the ``hashids`` module:
+
+.. code:: python
+
+  from hashids import Hashids
+  hashids = Hashids()
+
+Basic Usage
+-----------
+
+Encode a single integer:
+
+.. code:: python
+
+  hashid = hashids.encode(123) # 'Mj3'
+
+Decode a hash:
+
+.. code:: python
+
+  ints = hashids.decode('xoz') # (456,)
+
+To encode several integers, pass them all at once:
+
+.. code:: python
+
+  hashid = hashids.encode(123, 456, 789) # 'El3fkRIo3'
+
+Decoding is done the same way:
+
+.. code:: python
+
+  ints = hashids.decode('1B8UvJfXm') # (517, 729, 185)
+
+Using A Custom Salt
+-------------------
+
+Hashids supports salting hashes by accepting a salt value. If you don’t want others to decode your hashes, provide a unique string to the constructor.
+
+.. code:: python
+
+  hashids = Hashids(salt='this is my salt 1')
+  hashid = hashids.encode(123) # 'nVB'
+
+The generated hash changes whenever the salt is changed:
+
+.. code:: python
+
+  hashids = Hashids(salt='this is my salt 2')
+  hashid = hashids.encode(123) # 'ojK'
+
+A salt string between 6 and 32 characters provides decent randomization.
+
+Controlling Hash Length
+-----------------------
+
+By default, hashes are going to be the shortest possible. One reason you might want to increase the hash length is to obfuscate how large the integer behind the hash is.
+
+This is done by passing the minimum hash length to the constructor. Hashes are padded with extra characters to make them seem longer.
+
+.. code:: python
+
+  hashids = Hashids(min_length=16)
+  hashid = hashids.encode(1) # '4q2VolejRejNmGQB'
+
+Using A Custom Alphabet
+-----------------------
+
+It’s possible to set a custom alphabet for your hashes. The default alphabet is ``'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'``.
+
+To have only lowercase letters in your hashes, pass in the following custom alphabet:
+
+.. code:: python
+
+  hashids = Hashids(alphabet='abcdefghijklmnopqrstuvwxyz')
+  hashid = hashids.encode(123456789) # 'kekmyzyk'
+
+A custom alphabet must contain at least 16 characters.
+
+Randomness
+==========
+
+The primary purpose of hashids is to obfuscate ids. It's not meant or tested to be used for security purposes or compression. Having said that, this algorithm does try to make these hashes unguessable and unpredictable:
+
+Repeating numbers
+-----------------
+
+There are no repeating patterns that might show that there are 4 identical numbers in the hash:
+
+.. code:: python
+
+  hashids = Hashids("this is my salt")
+  hashids.encode(5, 5, 5, 5) # '1Wc8cwcE'
+
+The same is valid for incremented numbers:
+
+.. code:: python
+
+  hashids.encode(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) # 'kRHnurhptKcjIDTWC3sx'
+
+  hashids.encode(1) # 'NV'
+  hashids.encode(2) # '6m'
+  hashids.encode(3) # 'yD'
+  hashids.encode(4) # '2l'
+  hashids.encode(5) # 'rD'
+
+Curses! #$%@
+============
+
+This code was written with the intent of placing generated hashes in visible places – like the URL.  Which makes it unfortunate if generated hashes accidentally formed a bad word.
+
+Therefore, the algorithm tries to avoid generating most common English curse words by never placing the following letters next to each other: **c, C, s, S, f, F, h, H, u, U, i, I, t, T.**
+
+License
+=======
+
+MIT license, see the LICENSE file. You can use hashids in open source projects and commercial products.
diff --git a/hashids.py b/hashids.py
new file mode 100644
index 0000000..817ab88
--- /dev/null
+++ b/hashids.py
@@ -0,0 +1,285 @@
+"""Implements the hashids algorithm in python. For more information, visit
+http://www.hashids.org/. Compatible with Python 2.6, 2.7 and 3"""
+
+import warnings
+from functools import wraps
+from math import ceil
+
+__version__ = '1.1.0'
+
+RATIO_SEPARATORS = 3.5
+RATIO_GUARDS = 12
+
+try:
+    StrType = basestring
+except NameError:
+    StrType = str
+
+
+def _is_str(candidate):
+    """Returns whether a value is a string."""
+    return isinstance(candidate, StrType)
+
+
+def _is_uint(number):
+    """Returns whether a value is an unsigned integer."""
+    try:
+        return number == int(number) and number >= 0
+    except ValueError:
+        return False
+
+
+def _split(string, splitters):
+    """Splits a string into parts at multiple characters"""
+    part = ''
+    for character in string:
+        if character in splitters:
+            yield part
+            part = ''
+        else:
+            part += character
+    yield part
+
+
+def _hash(number, alphabet):
+    """Hashes `number` using the given `alphabet` sequence."""
+    hashed = ''
+    len_alphabet = len(alphabet)
+    while True:
+        hashed = alphabet[number % len_alphabet] + hashed
+        number //= len_alphabet
+        if not number:
+            return hashed
+
+
+def _unhash(hashed, alphabet):
+    """Restores a number tuple from hashed using the given `alphabet` index."""
+    number = 0
+    len_hash = len(hashed)
+    len_alphabet = len(alphabet)
+    for i, character in enumerate(hashed):
+        position = alphabet.index(character)
+        number += position * len_alphabet ** (len_hash - i - 1)
+
+    return number
+
+
+def _reorder(string, salt):
+    """Reorders `string` according to `salt`."""
+    len_salt = len(salt)
+
+    if len_salt == 0:
+        return string
+
+    i, index, integer_sum = len(string) - 1, 0, 0
+    while i > 0:
+        index %= len_salt
+        integer = ord(salt[index])
+        integer_sum += integer
+        j = (integer + index + integer_sum) % i
+
+        temp = string[j]
+        trailer = string[j+1:] if j + 1 < len(string) else ''
+        string = string[0:j] + string[i] + trailer
+        string = string[0:i] + temp + string[i+1:]
+
+        i -= 1
+        index += 1
+
+    return string
+
+
+def _index_from_ratio(dividend, divisor):
+    """Returns the ceiled ratio of two numbers as int."""
+    return int(ceil(float(dividend) / divisor))
+
+
+def _ensure_length(encoded, min_length, alphabet, guards, values_hash):
+    """Ensures the minimal hash length"""
+    len_guards = len(guards)
+    guard_index = (values_hash + ord(encoded[0])) % len_guards
+    encoded = guards[guard_index] + encoded
+
+    if len(encoded) < min_length:
+        guard_index = (values_hash + ord(encoded[2])) % len_guards
+        encoded += guards[guard_index]
+
+    split_at = len(alphabet) // 2
+    while len(encoded) < min_length:
+        alphabet = _reorder(alphabet, alphabet)
+        encoded = alphabet[split_at:] + encoded + alphabet[:split_at]
+        excess = len(encoded) - min_length
+        if excess > 0:
+            from_index = excess // 2
+            encoded = encoded[from_index:from_index+min_length]
+
+    return encoded
+
+
+def _encode(values, salt, min_length, alphabet, separators, guards):
+    """Helper function that does the hash building without argument checks."""
+
+    len_alphabet = len(alphabet)
+    len_separators = len(separators)
+    values_hash = sum(x % (i + 100) for i, x in enumerate(values))
+    encoded = lottery = alphabet[values_hash % len(alphabet)]
+
+    last = None
+    for i, value in enumerate(values):
+        alphabet_salt = (lottery + salt + alphabet)[:len_alphabet]
+        alphabet = _reorder(alphabet, alphabet_salt)
+        last = _hash(value, alphabet)
+        encoded += last
+        value %= ord(last[0]) + i
+        encoded += separators[value % len_separators]
+
+    encoded = encoded[:-1]  # cut off last separator
+
+    return (encoded if len(encoded) >= min_length else
+            _ensure_length(encoded, min_length, alphabet, guards, values_hash))
+
+
+def _decode(hashid, salt, alphabet, separators, guards):
+    """Helper method that restores the values encoded in a hashid without
+    argument checks."""
+    parts = tuple(_split(hashid, guards))
+    hashid = parts[1] if 2 <= len(parts) <= 3 else parts[0]
+
+    if not hashid:
+        return
+
+    lottery_char = hashid[0]
+    hashid = hashid[1:]
+
+    hash_parts = _split(hashid, separators)
+    for part in hash_parts:
+        alphabet_salt = (lottery_char + salt + alphabet)[:len(alphabet)]
+        alphabet = _reorder(alphabet, alphabet_salt)
+        yield _unhash(part, alphabet)
+
+
+def _deprecated(func):
+    """A decorator that warns about deprecation when the passed-in function is
+    invoked."""
+    @wraps(func)
+    def with_warning(*args, **kwargs):
+        warnings.warn(
+            ('The %s method is deprecated and will be removed in v2.*.*' %
+             func.__name__),
+            DeprecationWarning
+        )
+        return func(*args, **kwargs)
+    return with_warning
+
+
+class Hashids(object):
+    """Hashes and restores values using the "hashids" algorithm."""
+    ALPHABET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
+
+    def __init__(self, salt='', min_length=0, alphabet=ALPHABET):
+        """
+        Initializes a Hashids object with salt, minimum length, and alphabet.
+
+        :param salt: A string influencing the generated hash ids.
+        :param min_length: The minimum length for generated hashes
+        :param alphabet: The characters to use for the generated hash ids.
+        """
+        self._min_length = max(int(min_length), 0)
+        self._salt = salt
+
+        separators = ''.join(x for x in 'cfhistuCFHISTU' if x in alphabet)
+        alphabet = ''.join(x for i, x in enumerate(alphabet)
+                           if alphabet.index(x) == i and x not in separators)
+
+        len_alphabet, len_separators = len(alphabet), len(separators)
+        if len_alphabet + len_separators < 16:
+            raise ValueError('Alphabet must contain at least 16 '
+                             'unique characters.')
+
+        separators = _reorder(separators, salt)
+
+        min_separators = _index_from_ratio(len_alphabet, RATIO_SEPARATORS)
+        if not separators or len_separators < min_separators:
+            if min_separators == 1:
+                min_separators = 2
+            if min_separators > len_separators:
+                split_at = min_separators - len_separators
+                separators += alphabet[:split_at]
+                alphabet = alphabet[split_at:]
+                len_alphabet = len(alphabet)
+
+        alphabet = _reorder(alphabet, salt)
+        num_guards = _index_from_ratio(len_alphabet, RATIO_GUARDS)
+        if len_alphabet < 3:
+            guards = separators[:num_guards]
+            separators = separators[num_guards:]
+        else:
+            guards = alphabet[:num_guards]
+            alphabet = alphabet[num_guards:]
+
+        self._alphabet = alphabet
+        self._guards = guards
+        self._separators = separators
+
+        # Support old API
+        self.decrypt = _deprecated(self.decode)
+        self.encrypt = _deprecated(self.encode)
+
+    def encode(self, *values):
+        """Builds a hash from the passed `values`.
+
+        :param values The values to transform into a hashid
+
+        >>> hashids = Hashids('arbitrary salt', 16, 'abcdefghijkl0123456')
+        >>> hashids.encode(1, 23, 456)
+        '1d6216i30h53elk3'
+        """
+        if not (values and all(_is_uint(x) for x in values)):
+            return ''
+
+        return _encode(values, self._salt, self._min_length, self._alphabet,
+                       self._separators, self._guards)
+
+    def decode(self, hashid):
+        """Restore a tuple of numbers from the passed `hashid`.
+
+        :param hashid The hashid to decode
+
+        >>> hashids = Hashids('arbitrary salt', 16, 'abcdefghijkl0123456')
+        >>> hashids.decode('1d6216i30h53elk3')
+        (1, 23, 456)
+        """
+        if not hashid or not _is_str(hashid):
+            return ()
+        try:
+            numbers = tuple(_decode(hashid, self._salt, self._alphabet,
+                                    self._separators, self._guards))
+
+            return numbers if hashid == self.encode(*numbers) else ()
+        except ValueError:
+            return ()
+
+    def encode_hex(self, hex_str):
+        """Converts a hexadecimal string (e.g. a MongoDB id) to a hashid.
+
+        :param hex_str The hexadecimal string to encodes
+
+        >>> Hashids.encode_hex('507f1f77bcf86cd799439011')
+        'y42LW46J9luq3Xq9XMly'
+        """
+        numbers = (int('1' + hex_str[i:i+12], 16)
+                   for i in range(0, len(hex_str), 12))
+        try:
+            return self.encode(*numbers)
+        except ValueError:
+            return ''
+
+    def decode_hex(self, hashid):
+        """Restores a hexadecimal string (e.g. a MongoDB id) from a hashid.
+
+        :param hashid The hashid to decode
+
+        >>> Hashids.decode_hex('y42LW46J9luq3Xq9XMly')
+        '507f1f77bcf86cd799439011'
+        """
+        return ''.join(('%x' % x)[1:] for x in self.decode(hashid))
diff --git a/setup.py b/setup.py
new file mode 100755
index 0000000..c47417d
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,15 @@
+#!/usr/bin/env python
+from distutils.core import setup
+from os.path import dirname, join
+from codecs import open
+
+setup(name='hashids',
+      version='1.1.0',
+      description='Python implementation of hashids (http://www.hashids.org).'
+                  'Compatible with python 2.6-3.',
+      long_description=open(join(dirname(__file__), 'README.rst'), encoding='utf-8').read(),
+      author='David Aurelio',
+      author_email='dev at david-aurelio.com',
+      url='https://github.com/davidaurelio/hashids-python',
+      license='MIT License',
+      py_modules=('hashids',))
diff --git a/test/test_hashids.py b/test/test_hashids.py
new file mode 100644
index 0000000..d0e5542
--- /dev/null
+++ b/test/test_hashids.py
@@ -0,0 +1,176 @@
+from hashids import Hashids
+import pytest
+
+class TestConstructor(object):
+    def test_small_alphabet(self):
+        pytest.raises(ValueError, Hashids, alphabet='abcabc')
+
+
+class TestEncoding(object):
+    def test_empty_call(self):
+        assert Hashids().encode() == ''
+
+    def test_default_salt(self):
+        assert Hashids().encode(1, 2, 3) == 'o2fXhV'
+
+    def test_single_number(self):
+        h = Hashids()
+        assert h.encode(12345) == 'j0gW'
+        assert h.encode(1) == 'jR'
+        assert h.encode(22) == 'Lw'
+        assert h.encode(333) == 'Z0E'
+        assert h.encode(9999) == 'w0rR'
+
+    def test_multiple_numbers(self):
+        h = Hashids()
+        assert h.encode(683, 94108, 123, 5) == 'vJvi7On9cXGtD'
+        assert h.encode(1, 2, 3) == 'o2fXhV'
+        assert h.encode(2, 4, 6) == 'xGhmsW'
+        assert h.encode(99, 25) == '3lKfD'
+
+    def test_salt(self):
+        h = Hashids(salt='Arbitrary string')
+        assert h.encode(683, 94108, 123, 5) == 'QWyf8yboH7KT2'
+        assert h.encode(1, 2, 3) == 'neHrCa'
+        assert h.encode(2, 4, 6) == 'LRCgf2'
+        assert h.encode(99, 25) == 'JOMh1'
+
+    def test_alphabet(self):
+        h = Hashids(alphabet='!"#%&\',-/0123456789:;<=>ABCDEFGHIJKLMNOPQRSTUVWXYZ_`abcdefghijklmnopqrstuvwxyz~')
+        assert h.encode(2839, 12, 32, 5) == '_nJUNTVU3'
+        assert h.encode(1, 2, 3) == '7xfYh2'
+        assert h.encode(23832) == 'Z6R>'
+        assert h.encode(99, 25) == 'AYyIB'
+
+    def test_min_length(self):
+        h = Hashids(min_length=25)
+        assert h.encode(7452, 2967, 21401) == 'pO3K69b86jzc6krI416enr2B5'
+        assert h.encode(1, 2, 3) == 'gyOwl4B97bo2fXhVaDR0Znjrq'
+        assert h.encode(6097) == 'Nz7x3VXyMYerRmWeOBQn6LlRG'
+        assert h.encode(99, 25) == 'k91nqP3RBe3lKfDaLJrvy8XjV'
+
+    def test_all_parameters(self):
+        h = Hashids('arbitrary salt', 16, 'abcdefghijklmnopqrstuvwxyz')
+        assert h.encode(7452, 2967, 21401) == 'wygqxeunkatjgkrw'
+        assert h.encode(1, 2, 3) == 'pnovxlaxuriowydb'
+        assert h.encode(60125) == 'jkbgxljrjxmlaonp'
+        assert h.encode(99, 25) == 'erdjpwrgouoxlvbx'
+
+    def test_alphabet_without_standard_separators(self):
+        h = Hashids(alphabet='abdegjklmnopqrvwxyzABDEGJKLMNOPQRVWXYZ1234567890')
+        assert h.encode(7452, 2967, 21401) == 'X50Yg6VPoAO4'
+        assert h.encode(1, 2, 3) == 'GAbDdR'
+        assert h.encode(60125) == '5NMPD'
+        assert h.encode(99, 25) == 'yGya5'
+
+    def test_alphabet_with_two_standard_separators(self):
+        h = Hashids(alphabet='abdegjklmnopqrvwxyzABDEGJKLMNOPQRVWXYZ1234567890uC')
+        assert h.encode(7452, 2967, 21401) == 'GJNNmKYzbPBw'
+        assert h.encode(1, 2, 3) == 'DQCXa4'
+        assert h.encode(60125) == '38V1D'
+        assert h.encode(99, 25) == '373az'
+
+    def test_negative_call(self):
+        assert Hashids().encode(1, -2, 3) == ''
+
+    def test_float_call(self):
+        assert Hashids().encode(1, 2.5, 3) == ''
+
+    def test_encode_hex(self):
+        assert Hashids().encode_hex('507f1f77bcf86cd799439011') == 'y42LW46J9luq3Xq9XMly'
+        assert len(Hashids(min_length=1000).encode_hex('507f1f77bcf86cd799439011')) >= 1000
+        assert Hashids().encode_hex('f000000000000000000000000000000000000000000000000000000000000000000000000000000000000f') == \
+               'WxMLpERDrmh25Lp4L3xEfM6WovWYO3IjkRMKR2ogCMVzn4zQlqt1WK8jKq7OsEpy2qyw1Vi2p'
+
+    def test_illegal_hex(self):
+        assert Hashids().encode_hex('') == ''
+        assert Hashids().encode_hex('1234SGT8') == ''
+
+class TestDecoding(object):
+    def test_empty_string(self):
+        assert Hashids().decode('') == ()
+
+    def test_non_string(self):
+        assert Hashids().decode(object()) == ()
+
+    def test_default_salt(self):
+        assert Hashids().decode('o2fXhV') == (1, 2, 3)
+
+    def test_empty_call(self):
+        assert Hashids().decode('') == ()
+
+    def test_single_number(self):
+        h = Hashids()
+        assert h.decode('j0gW') == (12345,)
+        assert h.decode('jR') == (1,)
+        assert h.decode('Lw') == (22,)
+        assert h.decode('Z0E') == (333,)
+        assert h.decode('w0rR') == (9999,)
+
+    def test_multiple_numbers(self):
+        h = Hashids()
+        assert h.decode('vJvi7On9cXGtD') == (683, 94108, 123, 5)
+        assert h.decode('o2fXhV') == (1, 2, 3)
+        assert h.decode('xGhmsW') == (2, 4, 6)
+        assert h.decode('3lKfD') == (99, 25)
+
+    def test_salt(self):
+        h = Hashids(salt='Arbitrary string')
+        assert h.decode('QWyf8yboH7KT2') == (683, 94108, 123, 5)
+        assert h.decode('neHrCa') == (1, 2, 3)
+        assert h.decode('LRCgf2') == (2, 4, 6)
+        assert h.decode('JOMh1') == (99, 25)
+
+    def test_alphabet(self):
+        h = Hashids(alphabet='!"#%&\',-/0123456789:;<=>ABCDEFGHIJKLMNOPQRSTUVWXYZ_`abcdefghijklmnopqrstuvwxyz~')
+        assert h.decode('_nJUNTVU3') == (2839, 12, 32, 5)
+        assert h.decode('7xfYh2') == (1, 2, 3)
+        assert h.decode('Z6R>') == (23832,)
+        assert h.decode('AYyIB') == (99, 25)
+
+    def test_min_length(self):
+        h = Hashids(min_length=25)
+        assert h.decode('pO3K69b86jzc6krI416enr2B5') == (7452, 2967, 21401)
+        assert h.decode('gyOwl4B97bo2fXhVaDR0Znjrq') == (1, 2, 3)
+        assert h.decode('Nz7x3VXyMYerRmWeOBQn6LlRG') == (6097,)
+        assert h.decode('k91nqP3RBe3lKfDaLJrvy8XjV') == (99, 25)
+
+    def test_all_parameters(self):
+        h = Hashids('arbitrary salt', 16, 'abcdefghijklmnopqrstuvwxyz')
+        assert h.decode('wygqxeunkatjgkrw') == (7452, 2967, 21401)
+        assert h.decode('pnovxlaxuriowydb') == (1, 2, 3)
+        assert h.decode('jkbgxljrjxmlaonp') == (60125,)
+        assert h.decode('erdjpwrgouoxlvbx') == (99, 25)
+
+    def test_invalid_hash(self):
+        assert Hashids(alphabet='abcdefghijklmnop').decode('qrstuvwxyz') == ()
+
+    def test_alphabet_without_standard_separators(self):
+        h = Hashids(alphabet='abdegjklmnopqrvwxyzABDEGJKLMNOPQRVWXYZ1234567890')
+        assert h.decode('X50Yg6VPoAO4') == (7452, 2967, 21401)
+        assert h.decode('GAbDdR') == (1, 2, 3)
+        assert h.decode('5NMPD') == (60125,)
+        assert h.decode('yGya5') == (99, 25)
+
+    def test_alphabet_with_two_standard_separators(self):
+        h = Hashids(alphabet='abdegjklmnopqrvwxyzABDEGJKLMNOPQRVWXYZ1234567890uC')
+        assert h.decode('GJNNmKYzbPBw') == (7452, 2967, 21401)
+        assert h.decode('DQCXa4') == (1, 2, 3)
+        assert h.decode('38V1D') == (60125,)
+        assert h.decode('373az') == (99, 25)
+
+    def test_only_one_valid(self):
+        h = Hashids(min_length=6)
+        assert h.decode(h.encode(1)[:-1] + '0') == ()
+
+    def test_decode_hex(self):
+        hex_str = '507f1f77bcf86cd799439011'
+        assert Hashids().decode_hex('y42LW46J9luq3Xq9XMly') == hex_str
+        h = Hashids(min_length=1000)
+        assert h.decode_hex(h.encode_hex(hex_str)) == hex_str
+        assert Hashids().decode_hex('WxMLpERDrmh25Lp4L3xEfM6WovWYO3IjkRMKR2ogCMVzn4zQlqt1WK8jKq7OsEpy2qyw1Vi2p') == \
+               'f000000000000000000000000000000000000000000000000000000000000000000000000000000000000f'
+
+    def test_illegal_decode_hex(self):
+        assert Hashids().decode_hex('') == ''
+        assert Hashids().decode_hex('WxMLpERDrmh25Lp4L3xEfM6WovWYO3IjkRMKR2ogCMVlqt1WK8jKq7OsEp1Vi2p') == ''
diff --git a/test/test_legacy.py b/test/test_legacy.py
new file mode 100644
index 0000000..532c42c
--- /dev/null
+++ b/test/test_legacy.py
@@ -0,0 +1,154 @@
+from hashids import Hashids
+import pytest
+
+class TestConstructor(object):
+    def test_small_alphabet(self):
+        pytest.raises(ValueError, Hashids, alphabet='abcabc')
+
+
+class TestEncryption(object):
+    def test_empty_call(self):
+        assert Hashids().encrypt() == ''
+
+    def test_default_salt(self):
+        assert Hashids().encrypt(1, 2, 3) == 'o2fXhV'
+
+    def test_single_number(self):
+        h = Hashids()
+        assert h.encrypt(12345) == 'j0gW'
+        assert h.encrypt(1) == 'jR'
+        assert h.encrypt(22) == 'Lw'
+        assert h.encrypt(333) == 'Z0E'
+        assert h.encrypt(9999) == 'w0rR'
+
+    def test_multiple_numbers(self):
+        h = Hashids()
+        assert h.encrypt(683, 94108, 123, 5) == 'vJvi7On9cXGtD'
+        assert h.encrypt(1, 2, 3) == 'o2fXhV'
+        assert h.encrypt(2, 4, 6) == 'xGhmsW'
+        assert h.encrypt(99, 25) == '3lKfD'
+
+    def test_salt(self):
+        h = Hashids(salt='Arbitrary string')
+        assert h.encrypt(683, 94108, 123, 5) == 'QWyf8yboH7KT2'
+        assert h.encrypt(1, 2, 3) == 'neHrCa'
+        assert h.encrypt(2, 4, 6) == 'LRCgf2'
+        assert h.encrypt(99, 25) == 'JOMh1'
+
+    def test_alphabet(self):
+        h = Hashids(alphabet='!"#%&\',-/0123456789:;<=>ABCDEFGHIJKLMNOPQRSTUVWXYZ_`abcdefghijklmnopqrstuvwxyz~')
+        assert h.encrypt(2839, 12, 32, 5) == '_nJUNTVU3'
+        assert h.encrypt(1, 2, 3) == '7xfYh2'
+        assert h.encrypt(23832) == 'Z6R>'
+        assert h.encrypt(99, 25) == 'AYyIB'
+
+    def test_min_length(self):
+        h = Hashids(min_length=25)
+        assert h.encrypt(7452, 2967, 21401) == 'pO3K69b86jzc6krI416enr2B5'
+        assert h.encrypt(1, 2, 3) == 'gyOwl4B97bo2fXhVaDR0Znjrq'
+        assert h.encrypt(6097) == 'Nz7x3VXyMYerRmWeOBQn6LlRG'
+        assert h.encrypt(99, 25) == 'k91nqP3RBe3lKfDaLJrvy8XjV'
+
+    def test_all_parameters(self):
+        h = Hashids('arbitrary salt', 16, 'abcdefghijklmnopqrstuvwxyz')
+        assert h.encrypt(7452, 2967, 21401) == 'wygqxeunkatjgkrw'
+        assert h.encrypt(1, 2, 3) == 'pnovxlaxuriowydb'
+        assert h.encrypt(60125) == 'jkbgxljrjxmlaonp'
+        assert h.encrypt(99, 25) == 'erdjpwrgouoxlvbx'
+
+    def test_alphabet_without_standard_separators(self):
+        h = Hashids(alphabet='abdegjklmnopqrvwxyzABDEGJKLMNOPQRVWXYZ1234567890')
+        assert h.encrypt(7452, 2967, 21401) == 'X50Yg6VPoAO4'
+        assert h.encrypt(1, 2, 3) == 'GAbDdR'
+        assert h.encrypt(60125) == '5NMPD'
+        assert h.encrypt(99, 25) == 'yGya5'
+
+    def test_alphabet_with_two_standard_separators(self):
+        h = Hashids(alphabet='abdegjklmnopqrvwxyzABDEGJKLMNOPQRVWXYZ1234567890uC')
+        assert h.encrypt(7452, 2967, 21401) == 'GJNNmKYzbPBw'
+        assert h.encrypt(1, 2, 3) == 'DQCXa4'
+        assert h.encrypt(60125) == '38V1D'
+        assert h.encrypt(99, 25) == '373az'
+
+    def test_negative_call(self):
+        assert Hashids().encrypt(1, -2, 3) == ''
+
... 79 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-hashids.git



More information about the Python-modules-commits mailing list