7cecdfeccb
Various py2 to py3 fixes: 1. func.im_self to func.__self__ 2. func.func_name to func.__name__ 3. basestring to six.string_types 4. unicode to six.u 5. use bytes where appropriate instead of str 6. convert bytes to string for use with re 7. update usage of dict.keys() 8. update regex match for dealing with unicode characters, as '\w' matches unicode word characters in python 3 such as 的. References: [1] http://www.diveintopython3.net/porting-code-to-python-3-with-2to3.html#methodattrs [2] https://docs.python.org/3/whatsnew/3.0.html#operators-and-special-methods [3][4][5][6] https://docs.python.org/3.0/whatsnew/3.0.html#text-vs-data-instead-of-unicode-vs-8-bit [7] https://docs.python.org/3.0/whatsnew/3.0.html#views-and-iterators-instead-of-lists [8] https://docs.python.org/3/library/re.html#regular-expression-syntax Partially-Implements: blueprint magnum-python3 Change-Id: I6a7e13feeecd66910f2046956b1edc4d871208f6
60 lines
1.9 KiB
Python
60 lines
1.9 KiB
Python
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
"""Utilities for creating short ID strings based on a random UUID.
|
|
|
|
The IDs each comprise 12 (lower-case) alphanumeric characters.
|
|
"""
|
|
|
|
import base64
|
|
import uuid
|
|
|
|
import six
|
|
|
|
from magnum.i18n import _
|
|
|
|
|
|
def _to_byte_string(value, num_bits):
|
|
"""Convert an integer to a big-endian string of bytes with padding.
|
|
|
|
Padding is added at the end (i.e. after the least-significant bit) if
|
|
required.
|
|
"""
|
|
shifts = six.moves.xrange(num_bits - 8, -8, -8)
|
|
byte_at = lambda off: (value >> off if off >= 0 else value << -off) & 0xff
|
|
return ''.join(chr(byte_at(offset)) for offset in shifts)
|
|
|
|
|
|
def get_id(source_uuid):
|
|
"""Derive a short (12 character) id from a random UUID.
|
|
|
|
The supplied UUID must be a version 4 UUID object.
|
|
"""
|
|
if isinstance(source_uuid, six.string_types):
|
|
source_uuid = uuid.UUID(source_uuid)
|
|
if source_uuid.version != 4:
|
|
raise ValueError(_('Invalid UUID version (%d)') % source_uuid.version)
|
|
|
|
# The "time" field of a v4 UUID contains 60 random bits
|
|
# (see RFC4122, Section 4.4)
|
|
random_bytes = _to_byte_string(source_uuid.time, 60)
|
|
# The first 12 bytes (= 60 bits) of base32-encoded output is our data
|
|
encoded = base64.b32encode(six.b(random_bytes))[:12]
|
|
|
|
return encoded.lower()
|
|
|
|
|
|
def generate_id():
|
|
"""Generate a short (12 character), random id."""
|
|
return get_id(uuid.uuid4())
|