├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── haikunator ├── __init__.py ├── haikunator.py └── tests.py ├── setup.cfg └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # Distribution / packaging 6 | .Python 7 | env/ 8 | build/ 9 | develop-eggs/ 10 | dist/ 11 | downloads/ 12 | eggs/ 13 | lib/ 14 | lib64/ 15 | parts/ 16 | sdist/ 17 | var/ 18 | *.egg-info/ 19 | .installed.cfg 20 | *.egg 21 | 22 | # PyInstaller 23 | # Usually these files are written by a python script from a template 24 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 25 | *.manifest 26 | *.spec 27 | 28 | # Installer logs 29 | pip-log.txt 30 | pip-delete-this-directory.txt 31 | 32 | # Coverage 33 | .coverage 34 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | python: 4 | - 2.7 5 | - 3.4 6 | - 3.5 7 | - nightly 8 | 9 | install: 10 | - pip install coveralls 11 | - python setup.py install 12 | 13 | script: coverage run --source=haikunator/haikunator.py setup.py test 14 | 15 | after_success: coveralls 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Atrox 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of [project] nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HaikunatorPY 2 | 3 | [![Build Status](https://img.shields.io/travis/Atrox/haikunatorpy.svg?style=flat-square)](https://travis-ci.org/Atrox/haikunatorpy) 4 | [![Latest Version](https://img.shields.io/pypi/v/haikunator.svg?style=flat-square)](https://pypi.python.org/pypi/haikunator) 5 | [![Coverage Status](https://img.shields.io/coveralls/Atrox/haikunatorpy.svg?style=flat-square)](https://coveralls.io/r/Atrox/haikunatorpy) 6 | 7 | 8 | Generate Heroku-like random names to use in your python applications. 9 | 10 | ## Installation 11 | ``` 12 | pip install haikunator 13 | ``` 14 | 15 | ## Usage 16 | 17 | Haikunator is pretty simple. There is nothing to configure and it only has a single method, `haikunate`: 18 | 19 | ```python 20 | from haikunator import Haikunator 21 | 22 | haikunator = Haikunator() 23 | # haikunator = Haikunator(seed='random seed') # optional seed 24 | 25 | # default usage 26 | haikunator.haikunate() # => "wispy-dust-1337" 27 | 28 | # custom length (default=4) 29 | haikunator.haikunate(token_length=6) # => "patient-king-887265" 30 | 31 | # use hex instead of numbers 32 | haikunator.haikunate(token_hex=True) # => "purple-breeze-98e1" 33 | 34 | # use custom chars instead of numbers/hex 35 | haikunator.haikunate(token_chars='HAIKUNATE') # => "summer-atom-IHEA" 36 | 37 | # don't include a token 38 | haikunator.haikunate(token_length=0) # => "cold-wildflower" 39 | 40 | # use a different delimiter 41 | haikunator.haikunate(delimiter='.') # => "restless.sea.7976" 42 | 43 | # no token, space delimiter 44 | haikunator.haikunate(token_length=0, delimiter=' ') # => "delicate haze" 45 | 46 | # no token, empty delimiter 47 | haikunator.haikunate(token_length=0, delimiter='') # => "billowingleaf" 48 | ``` 49 | 50 | ## Options 51 | 52 | The following options are available: 53 | 54 | ```python 55 | from haikunator import Haikunator 56 | 57 | haikunator = Haikunator( 58 | adjectives=['custom', 'adjectives'], 59 | nouns=['custom', 'nouns'], 60 | seed='random seed' 61 | ) 62 | 63 | haikunator.haikunate( 64 | delimiter='-', 65 | token_length=4, 66 | token_hex=False, 67 | token_chars='0123456789' 68 | ) 69 | ``` 70 | *If `token_hex` is true, any tokens specified in `token_chars` are ignored* 71 | 72 | ## Contributing 73 | 74 | Everyone is encouraged to help improve this project. Here are a few ways you can help: 75 | 76 | - [Report bugs](https://github.com/atrox/haikunatorpy/issues) 77 | - Fix bugs and [submit pull requests](https://github.com/atrox/haikunatorpy/pulls) 78 | - Write, clarify, or fix documentation 79 | - Suggest or add new features 80 | 81 | ## Other Languages 82 | 83 | Haikunator is also available in other languages. Check them out: 84 | 85 | - Node: https://github.com/Atrox/haikunatorjs 86 | - PHP: https://github.com/Atrox/haikunatorphp 87 | - .NET: https://github.com/Atrox/haikunator.net 88 | - Java: https://github.com/Atrox/haikunatorjava 89 | - Go: https://github.com/Atrox/haikunatorgo 90 | - Perl: https://github.com/Atrox/haikunatorperl 91 | - Dart: https://github.com/Atrox/haikunatordart 92 | - Ruby: https://github.com/usmanbashir/haikunator -------------------------------------------------------------------------------- /haikunator/__init__.py: -------------------------------------------------------------------------------- 1 | from .haikunator import Haikunator 2 | -------------------------------------------------------------------------------- /haikunator/haikunator.py: -------------------------------------------------------------------------------- 1 | from random import Random 2 | 3 | 4 | class Haikunator: 5 | _adjectives = [ 6 | 'aged', 'ancient', 'autumn', 'billowing', 'bitter', 'black', 'blue', 'bold', 7 | 'broad', 'broken', 'calm', 'cold', 'cool', 'crimson', 'curly', 'damp', 8 | 'dark', 'dawn', 'delicate', 'divine', 'dry', 'empty', 'falling', 'fancy', 9 | 'flat', 'floral', 'fragrant', 'frosty', 'gentle', 'green', 'hidden', 'holy', 10 | 'icy', 'jolly', 'late', 'lingering', 'little', 'lively', 'long', 'lucky', 11 | 'misty', 'morning', 'muddy', 'mute', 'nameless', 'noisy', 'odd', 'old', 12 | 'orange', 'patient', 'plain', 'polished', 'proud', 'purple', 'quiet', 'rapid', 13 | 'raspy', 'red', 'restless', 'rough', 'round', 'royal', 'shiny', 'shrill', 14 | 'shy', 'silent', 'small', 'snowy', 'soft', 'solitary', 'sparkling', 'spring', 15 | 'square', 'steep', 'still', 'summer', 'super', 'sweet', 'throbbing', 'tight', 16 | 'tiny', 'twilight', 'wandering', 'weathered', 'white', 'wild', 'winter', 'wispy', 17 | 'withered', 'yellow', 'young' 18 | ] 19 | 20 | _nouns = [ 21 | 'art', 'band', 'bar', 'base', 'bird', 'block', 'boat', 'bonus', 22 | 'bread', 'breeze', 'brook', 'bush', 'butterfly', 'cake', 'cell', 'cherry', 23 | 'cloud', 'credit', 'darkness', 'dawn', 'dew', 'disk', 'dream', 'dust', 24 | 'feather', 'field', 'fire', 'firefly', 'flower', 'fog', 'forest', 'frog', 25 | 'frost', 'glade', 'glitter', 'grass', 'hall', 'hat', 'haze', 'heart', 26 | 'hill', 'king', 'lab', 'lake', 'leaf', 'limit', 'math', 'meadow', 27 | 'mode', 'moon', 'morning', 'mountain', 'mouse', 'mud', 'night', 'paper', 28 | 'pine', 'poetry', 'pond', 'queen', 'rain', 'recipe', 'resonance', 'rice', 29 | 'river', 'salad', 'scene', 'sea', 'shadow', 'shape', 'silence', 'sky', 30 | 'smoke', 'snow', 'snowflake', 'sound', 'star', 'sun', 'sun', 'sunset', 31 | 'surf', 'term', 'thunder', 'tooth', 'tree', 'truth', 'union', 'unit', 32 | 'violet', 'voice', 'water', 'waterfall', 'wave', 'wildflower', 'wind', 'wood' 33 | ] 34 | 35 | def __init__(self, seed=None, adjectives=None, nouns=None): 36 | """ 37 | Initialize new haikunator 38 | 39 | :param seed: Seed for Random 40 | :param adjectives: Custom Adjectives 41 | :param nouns: Custom Nouns 42 | :type adjectives: list 43 | :type nouns: list 44 | """ 45 | if adjectives is not None: 46 | self._adjectives = adjectives 47 | 48 | if nouns is not None: 49 | self._nouns = nouns 50 | 51 | self.random = Random(seed) 52 | 53 | def haikunate(self, delimiter='-', token_length=4, token_hex=False, token_chars='0123456789'): 54 | """ 55 | Generate heroku-like random names to use in your python applications 56 | 57 | :param delimiter: Delimiter 58 | :param token_length: TokenLength 59 | :param token_hex: TokenHex 60 | :param token_chars: TokenChars 61 | :type delimiter: str 62 | :type token_length: int 63 | :type token_hex: bool 64 | :type token_chars: str 65 | :return: heroku-like random string 66 | :rtype: str 67 | """ 68 | if token_hex: 69 | token_chars = '0123456789abcdef' 70 | 71 | adjective = self._random_element(self._adjectives) 72 | noun = self._random_element(self._nouns) 73 | token = ''.join(self._random_element(token_chars) for _ in range(token_length)) 74 | 75 | sections = [adjective, noun, token] 76 | return delimiter.join(filter(None, sections)) 77 | 78 | def _random_element(self, s): 79 | """ 80 | Get random element from string or list 81 | 82 | :param s: Element 83 | :type s: str or list 84 | :return: str 85 | :rtype: str 86 | """ 87 | if len(s) <= 0: 88 | return '' 89 | 90 | return self.random.choice(s) 91 | -------------------------------------------------------------------------------- /haikunator/tests.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import unittest 3 | 4 | from haikunator import Haikunator 5 | 6 | 7 | class HaikunatorTests(unittest.TestCase): 8 | def setUp(self): 9 | if sys.version_info > (3, 0): 10 | self.assertRegexp = self.assertRegex 11 | else: 12 | self.assertRegexp = self.assertRegexpMatches 13 | 14 | def test_general_functionality(self): 15 | tests = [ 16 | [{}, '[a-z]+-[a-z]+-[0-9]{4}$'], 17 | [{'token_hex': True}, '[a-z]+-[a-z]+-[0-f]{4}$'], 18 | [{'token_length': 9}, '[a-z]+-[a-z]+-[0-9]{9}$'], 19 | [{'token_length': 9, 'token_hex': True}, '[a-z]+-[a-z]+-[0-f]{9}$'], 20 | [{'token_length': 0}, '[a-z]+-[a-z]+$'], 21 | [{'delimiter': '.'}, '[a-z]+.[a-z]+.[0-9]{4}$'], 22 | [{'token_length': 0, 'delimiter': ' '}, '[a-z]+ [a-z]+'], 23 | [{'token_length': 0, 'delimiter': ''}, '[a-z]+$'], 24 | [{'token_chars': 'xyz'}, '[a-z]+-[a-z]+-[x-z]{4}$'], 25 | ] 26 | 27 | haikunator = Haikunator() 28 | for test in tests: 29 | self.assertRegexp(haikunator.haikunate(**test[0]), test[1]) 30 | 31 | def test_wont_return_same(self): 32 | haikunator = Haikunator() 33 | 34 | self.assertNotEqual(haikunator.haikunate(), haikunator.haikunate()) 35 | 36 | def test_return_same_with_seed(self): 37 | seed = 'definitively random seed' 38 | 39 | h1 = Haikunator(seed=seed) 40 | h2 = Haikunator(seed=seed) 41 | 42 | self.assertEqual(h1.haikunate(), h2.haikunate()) 43 | self.assertEqual(h1.haikunate(), h2.haikunate()) 44 | 45 | def test_custom_adjectives_nouns(self): 46 | haikunator = Haikunator( 47 | adjectives=['adjective'], 48 | nouns=['noun'] 49 | ) 50 | 51 | self.assertRegexp(haikunator.haikunate(), 'adjective-noun-\d{4}$') 52 | 53 | def test_empty_adjectives_nouns(self): 54 | haikunator = Haikunator( 55 | adjectives=[], 56 | nouns=[] 57 | ) 58 | 59 | self.assertEqual(haikunator.haikunate(token_chars=''), '') 60 | 61 | 62 | if __name__ == '__main__': 63 | unittest.main() 64 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | universal=1 3 | 4 | [metadata] 5 | description-file = README.md 6 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | from setuptools import setup 4 | 5 | CLASSIFIERS = [ 6 | 'Development Status :: 5 - Production/Stable', 7 | 'Intended Audience :: Developers', 8 | 'License :: OSI Approved :: BSD License', 9 | 'Operating System :: OS Independent', 10 | 'Programming Language :: Python', 11 | 'Programming Language :: Python :: 2', 12 | 'Programming Language :: Python :: 2.7', 13 | 'Programming Language :: Python :: 3', 14 | 'Programming Language :: Python :: 3.4', 15 | 'Programming Language :: Python :: 3.5', 16 | 'Programming Language :: Python :: 3.6', 17 | 'Topic :: Software Development :: Libraries :: Python Modules', 18 | ] 19 | 20 | setup(name='haikunator', 21 | author='Atrox', 22 | author_email='mail@atrox.me', 23 | description='Heroku-like random name generator for python.', 24 | license='BSD', 25 | version='2.1.0', 26 | url='https://github.com/Atrox/haikunatorpy', 27 | packages=['haikunator'], 28 | test_suite='haikunator.tests', 29 | include_package_data=True, 30 | classifiers=CLASSIFIERS, 31 | platforms=['any']) 32 | --------------------------------------------------------------------------------