Skip to main content

Map integers to fun pseudo-random names following a custom format

Project description

NamedNumber

pip install namednumber

Named number is a simple package which generates unique names which correspond one-to-one with numbers. NamedNumber subclasses int, making it versatile and easy to use. This can be used to generate fun names that are easy to rember for log records, database entries, products, temporary passwords, etc.

Getting started

basic

Create an integer with a seemingly randomly shuffled name associated with it

from namednumber import NamedNumber
x = NamedNumber(50)
print(f"{x=}")  # x=<destructive rhino (50)>
print(str(x))  # destructive rhino

Mapping is one to one and reversible so you can also look up a number by its name

print(int(NamedNumber("destructive rhino"))) # 50

why

  • fun
  • just because
  • generate easy to remember names for files, records, parts, etc.
  • flexible pig is easier to remember than 116994
  • use for auto-generated temporary passwords or two-step verification

math

Do math on it and get results in the same named format (see fancy_number.py for how this works)

print(f"{x+1=}")  # x+1=<crucial impala (51)>
x *= 2
print(f"{x=}")  # x=<huge crocodile (100)>

custom format

Specify your own format using common wordsets and character sets

y = NamedNumber(422, "Bob saw %4% %adjective% %plural_animals% which were all %color%")
print(f"{y=}") # <Bob saw 3 impressive wombats which were all maroon (422)>

custom wordlists

Specify your own custom wordlists

z = NamedNumber(30, "%emotion%_%animal%", emotion=['happy', 'sad', 'angry', 'hungry'])
print(f"{z=}") # z=<happy_rabbit (30)>

saved format

Save name formats and use them to generate numbers

from namednumber import RandomizedNameFmt
fmt = RandomizedNameFmt("%emotion% %animal% %hex#5%", emotion=['happy', 'sad', 'angry', 'hungry'])

print(f"{fmt(0)=}") # fmt(0)=<sad skunk 3113e (0)>
print(f"{fmt[1]=}") # fmt[1]=<happy woodchuck a48ef (1)>
print(f"{fmt[2:10:3]=}") # fmt[2:10:3]=[<hungry kookaburra 3ec9f (2)>, <hungry iguana 841c4 (5)>, <sad shark 11041 (8)>]

moderately interesting

See the individual values of the components

print(dict(x)) # {'huge': 151, 'crocodile': 29}

Command Line

generate a random number

namednumber

convert a number

namednumber 51

or multiple

namednumber 51 52
namednumber :5
namednumber 10:15
namednumber 20:40:7

specify format

namednumber :4 --fmt="%emotion% %pet%" --emotion=["happy","sad","angry","hungry"] --pet=["puppy","kitten","turtle","lizard"]

specify --shuffle (default) or --inc

namednumber :8 --fmt="%emotion% %pet%"  --inc --emotion=["happy","sad","angry","hungry"] --pet=["puppy","kitten","turtle","lizard"]

specify seed

namednumber 50 --seed=321

Shuffling

problem

The default functionality of the NameFmt object is to use the first wordlist as the high bit, second as next highest, etc. and to convert a number to a list of indices for the bases. Therefore, it will by default produce ordered incrementing results.

from namednumber import NameFmt
fmt = NameFmt(fmt="%first% %second%", first=["red", "green", "blue"], second=["car", "bike"])
print(fmt[:]) # [<red car (0)>, <red bike (1)>, <green car (2)>, <green bike (3)>, <blue car (4)>, <blue bike (5)>]

solution

In some cases this is the desired result, but in other cases it is not. Therefore, we need some reversible way of scrambling the numbers, so that we instead get this.

fmt = RandomizedNameFmt(fmt="%first% %second%", first=["red", "green", "blue"], second=["car", "bike"])
print(fmt[:]) # [<blue car (0)>, <green bike (1)>, <red car (2)>, <green car (3)>, <red bike (4)>, <blue bike (5)>]

One easy way to do this is to create a one-to-one mapping is to create a shuffled list of numbers and use the index <-> value mapping. This works well for small wordsets but scales poorly as it requires you to precompute the large shuffled list and then store it in memory or some form of a memory-mapped file.

limitations

RandomizedNameFmt works using np.random.permutation, but it can be very slow to initialize if used with sets of length > (1<<23). Therefore, due to memory and performance concerns, max_size_allowed = 1 << 23. Use RandomizedNameFmt.plot_performance to plot initialization time for varying sized optionsets.

encryption placeholder

We don't yet have a great solution, but we have left a few functions which can be overwritten to use whatever shuffling algorithm you desire.

class MyNameFmt(NameFmt):
    def init_cipher(self):
        # setup here
        pass

    def encrypt(self, i):
        return (7 * i + 23) % self.max_number

    def decrypt(self, i):
        return int((i - 23 % self.max_number)/7)

my_fmt = MyNameFmt()
my_fmt.plot_encryption(50)
print(my_fmt[:5]) # [<all chimpanzee (0)>, <all doe (1)>, <all fish (2)>, <all goat (3)>, <all horse (4)>]

Stylizing

To allow for additional fine-tuning of the string, we have also included placeholders for stylizing and de-stylizing the names.

class sPoNGEboBNameFmt(RandomizedNameFmt):
    def reformat(self, name):
        NAME = name.upper()
        n = int(len(name)/2 + 1)
        upper = self.rng.permutation([0]*n + [1]*n)
        return "".join([NAME[i] if upper[i] else name[i] for i in range(len(name))])
    
    def deformat(self, name):
        return name.lower()

s_fmt = sPoNGEboBNameFmt()
print(s_fmt[:5]) # [<CLean GOat (0)>, <SuBjecTIve BaT (1)>, <inVALuAbLE boNObo (2)>, <TiGht groUnDHOG (3)>, <BroWn yAK (4)>]

Options

wordlists

load your own wordlist from file using the Wordlist class. .json, .yml are supported. for .txt files or other formats it is assumed that there is one word per line.

from options import Wordlist
from name_fmt import RandomizedNameFmt
w = Wordlist("wordlists/128_singular_animals.txt")

r = RandomizedNameFmt("%animal%", animal=w)

pre-existing lists

wordsets

print(list(options.wordsets.keys()))
# ['colors_16', 'singular_animals_128', 'plural_animals_128', 'rgb_24bit', 'singular_nouns_1k', 'plural_nouns_1k',
# 'adjectives_1k']

charsets

print(list(options.charsets.keys()))
# ['binary', 'octadecimal', 'decimal', 'hexadecimal', 'lowercase', 'uppercase', 'punctuation', 'whitespace',
# 'ascii_128', 'ascii_128_unescaped', 'ascii_256', 'ascii_256_unescaped', 'ascii_512', 'ascii_512_unescaped',
# 'ascii_1028', 'ascii_1028_unescaped', 'greek_lowercase', 'greek_uppercase', 'vowels_lowercase',
# 'vowels_uppercase', 'vowels', 'consonants_lowercase', 'consonants_uppercase', 'consonants', 'alphabet',
# 'alphanumeric_lowercase', 'alphanumeric_uppercase', 'alphanumeric', 'greek_alphabet']

wordset aliases

print(list(options.wordset_aliases.keys()))
# ['colors', 'color', 'plural_animal', 'plural_animals', 'animals', 'singular_animal', 'animal', 'plural_nouns',
# 'plural_noun', 'singular_nouns', 'singular_noun', 'noun', 'adjectives', 'adjective']

charset aliases

print(list(options.charset_aliases.keys()))
# ['ascii_lowercase', 'az', 'ascii_uppercase', 'AZ', 'ALPHABET', 'aZ', 'english_alphabet', 'az9', 'AZ9', 'aZ9',
# '09', 'digits', 'digit', '07', 'octdigits', 'octdigit', 'hexdigits', 'hexdigit', 'hex', 'hs', 'bin', 'bs',
# 'printable', 'greek', 'GREEK', 'VOWELS', 'VOWEL', 'CONSONANTS', 'CONSONANT', 'vowel', 'consonant']

example

fmt = NameFmt("%greek#7% %hex#4%")
print([fmt.random_named_number() for _ in range(5)]) # [<λΥΞΓιΕΑ 82 (34166216153218)>, <πκΟΧβΣγ 3c (47605451108924)>, <ΟξημΓψΞ 47 (119835652408647)>, <Ιψεσζωπ 78 (101633973378936)>, <τΞζΕκυΨ 9b (58779657092763)>]

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

namednumber-1.0.0.tar.gz (29.8 kB view details)

Uploaded Source

Built Distribution

namednumber-1.0.0-py3-none-any.whl (29.6 kB view details)

Uploaded Python 3

File details

Details for the file namednumber-1.0.0.tar.gz.

File metadata

  • Download URL: namednumber-1.0.0.tar.gz
  • Upload date:
  • Size: 29.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.10.2

File hashes

Hashes for namednumber-1.0.0.tar.gz
Algorithm Hash digest
SHA256 9fa0150c644742e6beef4665bbc49341426972fd74049ca358292b0b7002faf4
MD5 80dec8908e3e84cd07c2bd4f6d7ed2c0
BLAKE2b-256 e1c08d42584685187f4d7a272018ab1dad3cec426d120dcb9a54f69374276c42

See more details on using hashes here.

File details

Details for the file namednumber-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: namednumber-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 29.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.10.2

File hashes

Hashes for namednumber-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 14ff757a04cf3445da4c42466e1002efd94d7a80bd1bb9add56b528978cbc85a
MD5 712c68b42a844b71d3d6a5d25d418313
BLAKE2b-256 e1bafc73c669ec1c99e6f9fb157c2869262ce17116e188b3e2b07ba0ac8bc936

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page