Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/.coveragerc b/.coveragerc
- new file mode 100644
- --- /dev/null
- +++ b/.coveragerc
- @@ -0,0 +1,2 @@
- +[run]
- +branch = True
- diff --git a/.hgignore b/.hgignore
- new file mode 100644
- --- /dev/null
- +++ b/.hgignore
- @@ -0,0 +1,96 @@
- +syntax: glob
- +# Byte-compiled / optimized / DLL files
- +__pycache__/
- +*.py[cod]
- +
- +# C extensions
- +*.so
- +
- +# Distribution / packaging
- +.Python
- +env/
- +build/
- +develop-eggs/
- +dist/
- +downloads/
- +eggs/
- +lib/
- +lib64/
- +parts/
- +sdist/
- +var/
- +*.egg-info/
- +.installed.cfg
- +*.egg
- +
- +# PyInstaller
- +# Usually these files are written by a python script from a template
- +# before PyInstaller builds the exe, so as to inject date/other infos into it.
- +*.manifest
- +*.spec
- +
- +# Installer logs
- +pip-log.txt
- +pip-delete-this-directory.txt
- +
- +# Unit test / coverage reports
- +htmlcov/
- +.tox/
- +.coverage
- +.cache
- +nosetests.xml
- +coverage.xml
- +
- +# Translations
- +*.mo
- +*.pot
- +
- +# Django stuff:
- +*.log
- +
- +# Sphinx documentation
- +docs/_build/
- +
- +# PyBuilder
- +target/
- +
- +
- +# cache files for sublime text
- +*.tmlanguage.cache
- +*.tmPreferences.cache
- +*.stTheme.cache
- +
- +# workspace files are user-specific
- +*.sublime-workspace
- +
- +# project files should be checked into the repository, unless a significant
- +# proportion of contributors will probably not be using SublimeText
- +# *.sublime-project
- +
- +# sftp configuration file
- +sftp-config.json
- +
- +
- +.DS_Store
- +.AppleDouble
- +.LSOverride
- +
- +# Icon must end with two \r
- +Icon
- +
- +
- +# Thumbnails
- +._*
- +
- +# Files that might appear on external disk
- +.Spotlight-V100
- +.Trashes
- +
- +# Directories potentially created on remote AFP share
- +.AppleDB
- +.AppleDesktop
- +Network Trash Folder
- +Temporary Items
- +.apdisk
- +
- +
- diff --git a/README.rst b/README.rst
- new file mode 100644
- diff --git a/data.py b/prototype/data.py
- rename from data.py
- rename to prototype/data.py
- diff --git a/nobilis.py b/prototype/nobilis.py
- rename from nobilis.py
- rename to prototype/nobilis.py
- diff --git a/setup.py b/setup.py
- new file mode 100644
- --- /dev/null
- +++ b/setup.py
- @@ -0,0 +1,47 @@
- +"""A setuptools based setup module."""
- +
- +# Always prefer setuptools over distutils
- +from setuptools import setup, find_packages
- +# To use a consistent encoding
- +from codecs import open as c_open
- +from os import path
- +
- +HERE = path.abspath(path.dirname(__file__))
- +
- +# Get the long description from the README file
- +with c_open(path.join(HERE, 'README.rst'), encoding='utf-8') as f:
- + LONG_DESCRIPTION = f.read()
- +
- +setup(
- + name='nobilis',
- +
- + version='0.1.0',
- +
- + description='Nobilis character creator',
- + long_description=LONG_DESCRIPTION,
- +
- + # url='https://github.com/mwchase/class-namespaces',
- +
- + author='Max Woerner Chase',
- + author_email='[email protected]',
- +
- + license='MIT',
- +
- + classifiers=[
- + 'Development Status :: 3 - Alpha',
- +
- + 'License :: OSI Approved :: MIT License',
- +
- + 'Programming Language :: Python :: 3',
- + 'Programming Language :: Python :: 3.6',
- + ],
- +
- + keywords='nobilis',
- +
- + packages=find_packages('src', exclude=['contrib', 'docs', 'tests']),
- + package_dir={'': 'src'},
- +
- + extras_require={
- + 'test': ['coverage', 'pytest'],
- + },
- +)
- diff --git a/src/nobilis/__init__.py b/src/nobilis/__init__.py
- new file mode 100644
- diff --git a/src/nobilis/game_data.py b/src/nobilis/game_data.py
- new file mode 100644
- --- /dev/null
- +++ b/src/nobilis/game_data.py
- @@ -0,0 +1,265 @@
- +import collections
- +
- +
- +KeyType = collections.namedtuple('KeyType', 'strength weakness')
- +
- +POWER_KEY = KeyType('heart', 'shadow')
- +DECEIVER_KEY = KeyType('lie', 'truth')
- +
- +KeyTemplate = collections.namedtuple(
- + 'KeyTemplate',
- + 'type flower key_name names strength_hint weakness_bullets')
- +
- +
- +POWER_TEMPLATES = ()
- +POWER_TEMPLATES += KeyTemplate(
- + POWER_KEY, 'Lotus Flower', 'Key of the Descending Angel',
- + ('My Power', 'My Nature'),
- + "how you enact meaningful change in people's lives",
- + ('glorious', 'set apart')),
- +POWER_TEMPLATES += KeyTemplate(
- + POWER_KEY, 'Vervain', 'Key of Something Powerful',
- + ('My Identity', 'Burdens'), 'who you are when you wield power',
- + ('bound by duty', 'set apart')),
- +POWER_TEMPLATES += KeyTemplate(
- + POWER_KEY, 'Acacia', 'Key of Something that Must Be Hidden',
- + ('A Dangerous Secret', '...That Hurts To Keep'),
- + 'what you do when dealing with the secret',
- + ('painful silence', 'set apart')),
- +POWER_TEMPLATES += KeyTemplate(
- + POWER_KEY, 'Clematis', 'Key of Something, Given Gifts',
- + ('I Have Witnessed It', 'Why I Doubt'),
- + 'who you are when you are witness to grace', ()),
- +POWER_TEMPLATES += KeyTemplate(
- + POWER_KEY, 'Aconite', 'Key of Rage',
- + # Not sure how best to represent this.
- + ("(.*'s )?(Rage|Hatred|Fury)", 'What Lets Me Oppose It'),
- + 'who you are in this drama', ()),
- +POWER_TEMPLATES += KeyTemplate(
- + POWER_KEY, 'Wild Oats', 'Key of Destiny Denied',
- + ('Hunger', 'Why It Feels Empty'),
- + 'who you are when indulging in your vice', ()),
- +POWER_TEMPLATES += KeyTemplate(
- + POWER_KEY, 'Star of Bethlehem', 'Key of Something, Changed Forever',
- + ('What it Made Me', 'How It Changed the World'),
- + "who you are when you're thinking about the mystery",
- + ("I can't let go", "I'm committed")),
- +POWER_TEMPLATES += KeyTemplate(
- + POWER_KEY, 'Gorse', 'Key of Something in Thrall',
- + ('Held in Thrall', 'Entangled with my Enemy'),
- + 'how you are held in thrall, and by what',
- + ("I can't let go", "I'm weak")),
- +POWER_TEMPLATES += KeyTemplate(
- + POWER_KEY, 'Honeysuckle', 'Key of Something, Finally, at Rest',
- + ('My New Life', 'My Old Life'), 'who you are and who you were', ()),
- +POWER_TEMPLATES += KeyTemplate(
- + POWER_KEY, 'Chamomile', 'Key of Something Romantic',
- + ('The Dream', 'The Cost'), 'who you are', ()),
- +POWER_TEMPLATES += KeyTemplate(
- + POWER_KEY, 'Wild Rose', 'Key of Something Different',
- + ('My Nature', 'My Struggles'), 'who you are compared to others',
- + ('self-doubt', 'trying to fit in')),
- +POWER_TEMPLATES += KeyTemplate(
- + POWER_KEY, 'Hollyhock', 'Key of Destiny in the Balance',
- + ('My Destiny', 'My Struggles'), 'what you are doing as you change',
- + ('self-doubt', 'changing hurts')),
- +POWER_TEMPLATES += KeyTemplate(
- + POWER_KEY, 'Mimulus', 'Key of Something Restless',
- + ('My Path', 'Why it Feels Empty'), 'who you are when you wander',
- + ('self-doubt', "the things I've left behind")),
- +POWER_TEMPLATES += KeyTemplate(
- + POWER_KEY, 'Water Lily', 'Key of Something Spiritual',
- + ('My Retreat', 'Burdens'),
- + 'who you are when you separate yourself from the world',
- + ('my duties as a Power',)),
- +POWER_TEMPLATES += KeyTemplate(
- + POWER_KEY, 'Oak', "Key of Something That Hasn't Changed",
- + ('My Identity', 'Crisis'), 'who you are', ()),
- +POWER_TEMPLATES += KeyTemplate(
- + POWER_KEY, 'Alyssym', 'Key of Destiny Fulfilled',
- + ('My Destiny', None), 'who you are, in terms of who you were', ()),
- +
- +DECEIVER_TEMPLATES = ()
- +DECEIVER_TEMPLATES += KeyTemplate(
- + DECEIVER_KEY, 'Lotus Flower', 'Key of the Shepherd', 'I BRING MY FLOCK...',
- + 'what people get out of interacting with you',
- + ('I love them', 'I listen to them')),
- +DECEIVER_TEMPLATES += KeyTemplate(
- + DECEIVER_KEY, 'Vervain', 'Key of the Dragon', 'THE EXCRUCIAN WAR',
- + 'cool stuff that you could do or have done',
- + ('I love them', 'I am their enemy')),
- +DECEIVER_TEMPLATES += KeyTemplate(
- + DECEIVER_KEY, 'Acacia', 'Key of the Crossroads', 'WHY I FALTER',
- + 'your excuse for being kind to mortals and Powers',
- + ('I love them', "I've lost sight of what I'm fighting for")),
- +DECEIVER_TEMPLATES += KeyTemplate(
- + DECEIVER_KEY, 'Clematis', 'Key of the Angel', "I'M REACHING OUT TO YOU",
- + "who you pretend to be when you're reaching out to the Powers",
- + ()),
- +DECEIVER_TEMPLATES += KeyTemplate(
- + DECEIVER_KEY, 'Aconite', 'Key of the Nemesis', 'THE EXCRUCIAN WAR',
- + "who you are when ruining a Power's life", ()),
- +DECEIVER_TEMPLATES += KeyTemplate(
- + DECEIVER_KEY, 'Wild Oats', 'Key of the Dreamer',
- + 'WHO I AM, IN THIS YOUR DREAM',
- + 'the role you take on in this dream', ()),
- +DECEIVER_TEMPLATES += KeyTemplate(
- + DECEIVER_KEY, 'Star of Bethlehem', 'Key of Burdens', 'IT MARKED ME',
- + "what you do to show you're carrying something with you",
- + ("I can't let go", "It's always with me")),
- +DECEIVER_TEMPLATES += KeyTemplate(
- + DECEIVER_KEY, 'Gorse', 'Key of Promises', 'HELD IN THRALL',
- + "the situation you're trapped in", ("I can't let go", "It's killing me")),
- +DECEIVER_TEMPLATES += KeyTemplate(
- + DECEIVER_KEY, 'Periwinkle', 'Key of Legends', 'MY LEGEND',
- + 'an impressive thing you did', ()),
- +DECEIVER_TEMPLATES += KeyTemplate(
- + DECEIVER_KEY, 'Chamomile', 'Key of the Mask',
- + 'WHO I AM, IN THIS YOUR DREAM', 'who you are', ()),
- +DECEIVER_TEMPLATES += KeyTemplate(
- + DECEIVER_KEY, 'Widow-Rose', 'Key of the Alien', 'MY NATURE',
- + 'why you cannot fit in',
- + ("I'm an enemy of the world", 'You cannot keep me away')),
- +DECEIVER_TEMPLATES += KeyTemplate(
- + DECEIVER_KEY, 'Milkmay', 'Key Unformed', 'THAT WHICH STIRS',
- + "what form you're likely to take when play begins",
- + ("I'm an enemy of the world", 'I am truth preceding form')),
- +DECEIVER_TEMPLATES += KeyTemplate(
- + DECEIVER_KEY, 'Phoenix Posy', 'Self-Creating Key, the',
- + 'I HAVE MADE MYSELF...', 'how you fit into the world',
- + ("I'm an enemy of the world", 'from nothing')),
- +DECEIVER_TEMPLATES += KeyTemplate(
- + DECEIVER_KEY, 'Water Lily', 'Key of Something Spiritual', 'MY NATURE',
- + 'how your holiness expresses itself in the world',
- + ('Excrucian Deceiver',)),
- +DECEIVER_TEMPLATES += KeyTemplate(
- + DECEIVER_KEY, 'Bilberry', 'Key of the Fallen', 'WHAT I BELIEVE',
- + "what you've accepted", ()),
- +DECEIVER_TEMPLATES += KeyTemplate(
- + DECEIVER_KEY, 'Hemlock', 'Key of the Lie', 'WHO I AM, IN THIS YOUR DREAM',
- + "the story you're trying to tell (often part of another Key)",
- + ()),
- +
- +
- +GeneralTemplate = collections.namedtuple('GeneralTemplate', 'name indices')
- +
- +
- +FOUNDATION_TEMPLATES = ()
- +FOUNDATION_TEMPLATES += GeneralTemplate(
- + 'Something Cool', (1, 2, 10, 15)),
- +FOUNDATION_TEMPLATES += GeneralTemplate(
- + 'In Love with Something', (4, 7, 9, 16)),
- +FOUNDATION_TEMPLATES += GeneralTemplate(
- + 'Epic, Inhuman, and Powerful', (5, 6, 12, 14)),
- +FOUNDATION_TEMPLATES += GeneralTemplate(
- + 'Just Plain Weird', (3, 8, 11, 13)),
- +
- +ESTATE_SOURCE_TEMPLATES = ()
- +ESTATE_SOURCE_TEMPLATES += GeneralTemplate(
- + 'Light Side of Human Experience', (2, 6, 10, 12)),
- +ESTATE_SOURCE_TEMPLATES += GeneralTemplate(
- + 'Dark Side of Human Experience', (3, 5, 11, 15)),
- +ESTATE_SOURCE_TEMPLATES += GeneralTemplate(
- + 'Beautiful Side of the World', (4, 7, 14, 16)),
- +ESTATE_SOURCE_TEMPLATES += GeneralTemplate(
- + 'Painful Side of the World', (1, 8, 9, 13)),
- +
- +ESTATE_NATURE_TEMPLATES = ()
- +ESTATE_NATURE_TEMPLATES += GeneralTemplate(
- + 'Something You Can Point To', (8, 9, 13, 14, 15)),
- +ESTATE_NATURE_TEMPLATES += GeneralTemplate(
- + 'Something You Live', (3, 5, 6, 4, 11, 12)),
- +ESTATE_NATURE_TEMPLATES += GeneralTemplate(
- + 'Something You Can Describe', (1, 2, 7, 10, 16)),
- +
- +ORIGIN_TEMPLATES = ()
- +ORIGIN_TEMPLATES += GeneralTemplate('Troubled Life', (2, 5, 6, 11)),
- +ORIGIN_TEMPLATES += GeneralTemplate('Humble Life', (8, 9, 14, 15)),
- +ORIGIN_TEMPLATES += GeneralTemplate('Blessed Life', (1, 4, 12, 16)),
- +ORIGIN_TEMPLATES += GeneralTemplate('Extraordinary Life', (3, 7, 10, 13)),
- +
- +TROUBLED_TEMPLATES = ()
- +TROUBLED_TEMPLATES += GeneralTemplate(
- + "You're Still in Trouble!", (3, 5, 8, 13)),
- +TROUBLED_TEMPLATES += GeneralTemplate(
- + 'Some Scars Remain', (7, 11, 12, 14)),
- +TROUBLED_TEMPLATES += GeneralTemplate(
- + "It's All Happening Again!", (6, 10, 15, 16)),
- +TROUBLED_TEMPLATES += GeneralTemplate(
- + 'Trouble Inspired Me', (1, 2, 4, 9)),
- +
- +HUMBLE_TEMPLATES = ()
- +HUMBLE_TEMPLATES += GeneralTemplate(
- + 'Love for the Ordinary...', (6, 7, 15, 16)),
- +HUMBLE_TEMPLATES += GeneralTemplate(
- + 'Alienation...', (3, 5, 11, 14)),
- +HUMBLE_TEMPLATES += GeneralTemplate(
- + 'Transformation...', (4, 8, 12, 13)),
- +HUMBLE_TEMPLATES += GeneralTemplate(
- + 'Freedom!', (1, 2, 9, 10)),
- +
- +BLESSED_TEMPLATES = ()
- +BLESSED_TEMPLATES += GeneralTemplate('Reverence in Purpose', (2, 4, 10, 13)),
- +BLESSED_TEMPLATES += GeneralTemplate('Community', (1, 3, 8, 15)),
- +BLESSED_TEMPLATES += GeneralTemplate('Your Way of Life', (7, 9, 14, 16)),
- +BLESSED_TEMPLATES += GeneralTemplate('Anger', (5, 6, 9, 12)),
- +
- +NORMAL_CONTACT_TEMPLATES = ()
- +NORMAL_CONTACT_TEMPLATES += GeneralTemplate(
- + 'Organization', (1,)),
- +NORMAL_CONTACT_TEMPLATES += GeneralTemplate(
- + 'Followers', (2,)),
- +NORMAL_CONTACT_TEMPLATES += GeneralTemplate(
- + 'Excrucian', (3,)),
- +NORMAL_CONTACT_TEMPLATES += GeneralTemplate(
- + 'Inspirational Friend or Lover', (4,)),
- +NORMAL_CONTACT_TEMPLATES += GeneralTemplate(
- + 'Nemesis', (5,)),
- +NORMAL_CONTACT_TEMPLATES += GeneralTemplate(
- + 'Corrupting Influence', (6,)),
- +NORMAL_CONTACT_TEMPLATES += GeneralTemplate(
- + 'Ghost', (7,)),
- +NORMAL_CONTACT_TEMPLATES += GeneralTemplate(
- + 'Cammora', (8,)),
- +NORMAL_CONTACT_TEMPLATES += GeneralTemplate(
- + 'Legacy', (9,)),
- +NORMAL_CONTACT_TEMPLATES += GeneralTemplate(
- + 'True Love', (10,)),
- +NORMAL_CONTACT_TEMPLATES += GeneralTemplate(
- + 'Alien(s)', (11,)),
- +NORMAL_CONTACT_TEMPLATES += GeneralTemplate(
- + 'Manufactured Army', (12,)),
- +NORMAL_CONTACT_TEMPLATES += GeneralTemplate(
- + 'Faraway or Troubled Love', (13,)),
- +NORMAL_CONTACT_TEMPLATES += GeneralTemplate(
- + 'Ward', (14,)),
- +NORMAL_CONTACT_TEMPLATES += GeneralTemplate(
- + 'Moral Friends and Family', (15,)),
- +NORMAL_CONTACT_TEMPLATES += GeneralTemplate(
- + 'Disciples', (16,)),
- +
- +SPECIAL_CONTACT_TEMPLATES = ()
- +SPECIAL_CONTACT_TEMPLATES += GeneralTemplate('Noble Friend or Enemy', ()),
- +SPECIAL_CONTACT_TEMPLATES += GeneralTemplate('Cleave of the Botanists', ()),
- +SPECIAL_CONTACT_TEMPLATES += GeneralTemplate('Mystery Cult', ()),
- +
- +
- +AFFLIATION_TEMPLATES = ()
- +AFFLIATION_TEMPLATES += GeneralTemplate(
- + '(The Song of) Heaven', (1, 2, 3)),
- +AFFLIATION_TEMPLATES += GeneralTemplate(
- + '(The Song of) Hell', (4, 5, 6)),
- +AFFLIATION_TEMPLATES += GeneralTemplate(
- + '(The Song of) The Light', (7, 8)),
- +AFFLIATION_TEMPLATES += GeneralTemplate(
- + '(The Song of) The Dark', (9, 10)),
- +AFFLIATION_TEMPLATES += GeneralTemplate(
- + '(The Song of) The Wild', (11, 12, 13)),
- +AFFLIATION_TEMPLATES += GeneralTemplate(
- + 'An Independent Song', (14, 15, 16)),
- +
- +
- +BACKGROUND_TEMPLATES = ()
- +BACKGROUND_TEMPLATES += GeneralTemplate('Animal', (6, 8, 14, 15)),
- +BACKGROUND_TEMPLATES += GeneralTemplate('Strange', (4, 11, 12, 16)),
- +BACKGROUND_TEMPLATES += GeneralTemplate('"Sort of" Human', (1, 7, 10, 13)),
- diff --git a/src/nobilis/lifepath.py b/src/nobilis/lifepath.py
- new file mode 100644
- --- /dev/null
- +++ b/src/nobilis/lifepath.py
- @@ -0,0 +1,62 @@
- +import collections
- +
- +from . import visitor
- +
- +
- +nt = collections.namedtuple
- +
- +Business = visitor.make_visitor()
- +
- +
- +def key(item):
- + return type(item), item
- +
- +
- +class Parentable:
- +
- + __slots__ = ()
- +
- +
- +P = Parentable
- +
- +
- +class Choice(P, nt('Choice', 'template')):
- +
- + __slots__ = ()
- +
- +
- +class ChoiceDisplay(P, nt('ChoiceDisplay', 'choice')):
- +
- + __slots__ = ()
- +
- +
- +class ChoiceTaken(P, nt('ChoiceTaken', 'choice')):
- +
- + __slots__ = ()
- +
- +
- +class ChoiceListed(P, nt('ChoiceListed', 'choice')):
- +
- + __slots__ = ()
- +
- +
- +class ChoiceList(P, nt('ChoiceList', 'choices initial_min initial_max')):
- +
- + __slots__ = ()
- +
- +
- +class DisplayList(P, nt('DisplayList', 'factory choices_ sections_')):
- +
- + __slots__ = ()
- +
- +
- +class Section(P, nt('Section', 'display_list name')):
- +
- + __slots__ = ()
- diff --git a/src/nobilis/visitor.py b/src/nobilis/visitor.py
- new file mode 100644
- --- /dev/null
- +++ b/src/nobilis/visitor.py
- @@ -0,0 +1,88 @@
- +"""This module provides an abstract class for visitors."""
- +
- +import functools
- +
- +SENTINEL = object()
- +
- +
- +def visitor_func(self, node, function, old_visitor):
- + def next_visitor(arg=None):
- + return function(self, node, old_visitor)
- + return next_visitor
- +
- +
- +def identity(arg=None):
- + return arg
- +
- +
- +def make_visitor(default=None):
- + """Return a base Visitor class."""
- + class Visitor:
- +
- + __classes = set()
- +
- + def __new__(cls, *args, **kwargs):
- + if cls is Visitor:
- + raise TypeError
- + return super().__new__(cls, *args, **kwargs)
- +
- + def __init_subclass__(cls, **kwargs):
- + super().__init_subclass__(**kwargs)
- + cls.__visitors = {}
- +
- + if default is not None:
- + default_visit = default
- + else:
- + def default_visit(self, node):
- + raise NotImplementedError(
- + f'No implementation for {node} on {self}.')
- +
- + def __get_visitor(self, node_class):
- + my_mro = type(self).mro()
- + visitor_index = my_mro.index(Visitor)
- + my_mro = my_mro[:visitor_index]
- + visitor_mro = []
- + for cls in node_class.mro():
- + for visitor_class in my_mro:
- + try:
- + visitor_dict = visitor_class.__visitors
- + except AttributeError:
- + pass
- + else:
- + visitor = visitor_dict.get(cls, SENTINEL)
- + if visitor is not SENTINEL:
- + visitor_mro.append(visitor)
- + return visitor_mro
- +
- + def visit(self, node):
- + visitors = self.__get_visitor(type(node))
- + if visitors:
- + visitor = identity
- + while visitors:
- + visitor = visitor_func(self, node, visitors.pop(), visitor)
- + return visitor()
- + else:
- + return self.default_visit(node)
- +
- + @classmethod
- + def bind(cls, node_class, function=None):
- + if cls is Visitor:
- + raise NotImplementedError
- + if node_class not in cls.__classes:
- + raise ValueError
- + if function is None:
- + return functools.partial(cls.bind, node_class)
- + cls.__visitors[node_class] = function
- + return cls
- +
- + @classmethod
- + def mark(cls, node_class):
- + cls.__classes.add(node_class)
- + return node_class
- +
- + @classmethod
- + def undefined(cls):
- + if cls is Visitor:
- + raise ValueError
- + return cls.__classes.difference(cls.__visitors)
- + return Visitor
- diff --git a/tests/nobilis/__init__.py b/tests/nobilis/__init__.py
- new file mode 100644
- diff --git a/tests/nobilis/conftest.py b/tests/nobilis/conftest.py
- new file mode 100644
- --- /dev/null
- +++ b/tests/nobilis/conftest.py
- @@ -0,0 +1,19 @@
- +import pytest
- +
- +
- +def visitor():
- + import nobilis.visitor
- + return nobilis.visitor
- +
- +
- +def game_data():
- + import nobilis.game_data
- + return nobilis.game_data
- +
- +
- +def lifepath():
- + import nobilis.lifepath
- + return nobilis.lifepath
- diff --git a/tests/nobilis/test_game_data.py b/tests/nobilis/test_game_data.py
- new file mode 100644
- --- /dev/null
- +++ b/tests/nobilis/test_game_data.py
- @@ -0,0 +1,2 @@
- +def test_import(game_data):
- + assert game_data
- diff --git a/tests/nobilis/test_lifepath.py b/tests/nobilis/test_lifepath.py
- new file mode 100644
- --- /dev/null
- +++ b/tests/nobilis/test_lifepath.py
- @@ -0,0 +1,7 @@
- +def test_import(lifepath):
- + assert lifepath
- +
- +
- +def test_key(lifepath):
- + assert lifepath.key(lifepath.Choice(None)) != lifepath.key(
- + lifepath.ChoiceDisplay(None))
- diff --git a/tests/nobilis/test_visitor.py b/tests/nobilis/test_visitor.py
- new file mode 100644
- --- /dev/null
- +++ b/tests/nobilis/test_visitor.py
- @@ -0,0 +1,149 @@
- +import pytest
- +
- +
- +def test_import(visitor):
- + assert visitor
- +
- +
- +def test_visitor(visitor):
- + assert visitor.make_visitor()
- +
- +
- +def test_mark(visitor):
- + Visitor = visitor.make_visitor()
- +
- + @Visitor.mark
- + class Test:
- + pass
- +
- + class Test2:
- + pass
- +
- + Test3 = Visitor.mark(Test2)
- + assert Test2 is Test3
- +
- +
- +def test_cannot_instantiate_base_class(visitor):
- + Visitor = visitor.make_visitor()
- +
- + with pytest.raises(TypeError):
- + print(Visitor())
- +
- + class Subclass(Visitor):
- + pass
- +
- + assert Subclass()
- +
- +
- +def test_bind(visitor):
- + Visitor = visitor.make_visitor()
- +
- + @Visitor.mark
- + class Test:
- + pass
- +
- + class Subclass(Visitor):
- + pass
- +
- + with pytest.raises(ValueError):
- + print(Visitor.undefined())
- +
- + assert Subclass.undefined() == {Test}
- +
- + with pytest.raises(NotImplementedError):
- + Visitor.bind(Test)
- +
- + with pytest.raises(NotImplementedError):
- + Subclass().visit(Test())
- +
- + @Subclass.bind(Test)
- + def Subclass(self, node, next_visitor):
- + return node
- +
- + assert Subclass.undefined() == set()
- +
- + test = Test()
- + assert Subclass().visit(test) is test
- +
- +
- +def test_provide_default(visitor):
- + @visitor.make_visitor
- + def Visitor(self, node):
- + return node
- +
- + @Visitor.mark
- + class Test:
- + pass
- +
- + class Subclass(Visitor):
- + pass
- +
- + test = Test()
- + assert Subclass().visit(test) is test
- +
- +
- +def test_cannot_add_unmarked(visitor):
- + Visitor = visitor.make_visitor()
- +
- + class Subclass(Visitor):
- + pass
- +
- + with pytest.raises(ValueError):
- + Subclass.bind(object)
- +
- + Visitor.mark(object)
- +
- + assert Subclass.bind(object)
- +
- +
- +def test_multiple_inheritance(visitor):
- + Visitor = visitor.make_visitor()
- +
- + class Klass:
- + pass
- +
- + class Subclass(Klass, Visitor):
- + pass
- +
- + @Visitor.mark
- + class Test:
- + pass
- +
- + with pytest.raises(NotImplementedError):
- + Subclass().visit(Test())
- +
- +
- +def test_next_visitor(visitor):
- + Visitor = visitor.make_visitor()
- +
- + @Visitor.mark
- + class Test1:
- + pass
- +
- + @Visitor.mark
- + class Test2(Test1):
- + pass
- +
- + class Visitor1(Visitor):
- + pass
- +
- + class Visitor2(Visitor1):
- + pass
- +
- + @Visitor2.bind(Test2)
- + def Visitor2(self, node, next_visitor):
- + return 'a' + next_visitor('f')
- +
- + @Visitor1.bind(Test2)
- + def Visitor1(self, node, next_visitor):
- + return 'b' + next_visitor('f')
- +
- + @Visitor2.bind(Test1)
- + def Visitor2(self, node, next_visitor):
- + return 'c' + next_visitor('f')
- +
- + @Visitor1.bind(Test1)
- + def Visitor1(self, node, next_visitor):
- + return 'd' + next_visitor('e')
- +
- + assert Visitor2().visit(Test2()) == 'abcde'
- diff --git a/tests/test_nobilis.py b/tests/test_nobilis.py
- new file mode 100644
- --- /dev/null
- +++ b/tests/test_nobilis.py
- @@ -0,0 +1,3 @@
- +def test_import_nobilis():
- + import nobilis
- + assert nobilis
- diff --git a/tox.ini b/tox.ini
- new file mode 100644
- --- /dev/null
- +++ b/tox.ini
- @@ -0,0 +1,17 @@
- +# Tox (http://tox.testrun.org/) is a tool for running tests
- +# in multiple virtualenvs. This configuration file will run the
- +# test suite on all supported python versions. To use it, "pip install tox"
- +# and then run "tox" from this directory.
- +
- +[tox]
- +envlist = py36
- +
- +[testenv]
- +commands =
- + {envpython} -m divide_and_cover run -m pytest --divide-and-cover
- + {envpython} -m divide_and_cover html -d htmlcov/{envname}
- +deps =
- + pytest-divide-and-cover
- + divide-and-cover
- + pytest
- + coverage
Advertisement
Add Comment
Please, Sign In to add comment