Package: python-blueprint
=========Blueprint=========Magical blueprints for procedural generation of content. Based roughlyon a `series of articles`_ by Sean Howard. `Overview here`_... _series of articles: http://www.squidi.net/mapmaker/index.php.. _Overview here: http://www.squidi.net/mapmaker/musings/m100402.php- `Introduction`_- `Fields and Generators`_- `Tags`_- `Mods`_- `Factories`_- `TODO`_- `HELP`_- `Changelog`_============Introduction============Blueprints are data objects. The essential idea is that you writesubclasses of ``blueprint.Blueprint`` with fields that define thegeneral parameters of their values (e.g. an integer between 0 and10). When you instantiate a blueprint, you get a "mastered" blueprintwith well-defined values for each field. Mastered blueprints maydefine special "generator" instance methods that build final objectsfrom the master.**Think of it as prototypal inheritance for Python!** (Yeah, Iprobably don't know what I'm talking about.)Most of the big moving parts have their documentation, often withexamples, in the docstring. Blueprint is best played with at thecommand line, trying out how things work. For the impatient, anexample::import blueprintclass Item(blueprint.Blueprint):value = 1tags = 'foo bar'class Meta:abstract = Trueclass Weapon(Item):name = 'Some Weapon'tags = 'dangerous equippable'damage = blueprint.RandomInt(1, 5)class Meta:abstract = Trueclass Spear(Weapon):tags = 'primitive piercing'name = 'Worn Spear'damage = blueprint.RandomInt(10, 15)value = blueprint.RandomInt(4, 6)class PointedStick(Weapon):tags = 'primitive piercing'name = 'Pointed Stick'damage = 6value = 2class Club(Weapon):tags = 'primitive crushing'name = 'Big Club'damage = blueprint.RandomInt(10, 15)value = 2class Actor(blueprint.Blueprint):tags = 'active'class CaveMan(Actor):name = 'Cave Man'weapon = blueprint.PickOne(Club, Spear, PointedStick)And then:>>> actor = CaveMan()>>> actor<CaveMan:name -- 'Cave Man'weapon -- <Spear:damage -- 5name -- 'Spear'value -- 6>>>>> actor.weapon.name'Spear'Now, we can take our reified master data object and do something withit--use it as-is, or build another entity using the generated data.=====================Fields and Generators=====================Blueprints are data objects. By default, every member of a blueprintis treated as a field, either static or dynamic. Static fields aresimple data attributes. Dynamic fields are callable objects that takeone positional argument, the blueprint on which they are being called.Dynamic fields make blueprints quite useful. A few basic fields areprovided to get you started, and Blueprints themselves can be used asfields. Fields are designed to be nestable. They can rely upon eachother too--use the ``blueprint.depends_on`` decorator to declare thesedependencies.If you really must have a callable method on your mastered blueprint,use the ``blueprint.generator`` decorator (or mark your callableobject with the ``is_generator`` flag). These are called "generators"("contractors" in squidi's terminology) because they're intended to beused to generate your final entity, whether it be a ``dict`` or a WADfile.====Tags====Blueprints automatically organize themselves using tags (domains insquidi's parlance). A direct descendant of Blueprint has its own tagrepository (``blueprint.taggables.TagRepository``), which all itssubclasses will share. So, in the above example, you can query``Weapon.tag_repo.query(with_tags=('piercing'))`` and receive``set([Spear, PointedStick])``.Blueprints are also automatically tagged by their class name (andtheir ancestor superclass names!), with camel-cased words separatedout. So ``CaveMan`` will automatically get the tags ``set(['cave', 'man','actor'])``.This makes the following possible::class MammothHunter(CaveMan):weapon = blueprint.PickFrom(blueprint.WithTags('pointed weapon'))====Mods====Sometimes, you'll want to dynamically modify a blueprint. To do this,create a subclass of ``Mod``. Mods are just special blueprints::class OfDoom(blueprint.Mod):name = blueprint.FormatTemplate('{meta.source.name} of DOOM')value = lambda _: _.meta.source.value * 5Then, apply it to another blueprint::>>> club = OfDoom(Club)>>> club.name'Big Club of DOOM'Mods always produce mastered blueprints.=========Factories=========Factories put all the pieces together--they're rather a blueprintfactory. Say that you want an item drop that selects from a few commonWeapon blueprints and adds a couple magical Mods to make itcooler. Here's our second mod::class MagicalItemPrefix(blueprint.Mod):prefix = blueprint.PickOne('Gnarled','Inscribed','Magnificent',)name = blueprint.depends_on('prefix')(blueprint.FormatTemplate('{parent.prefix} {meta.source.name}'))Now, here's our Magical Item factory::class MagicalItemFactory(blueprint.Factory):product = blueprint.PickFrom(blueprint.WithTags('weapon'))mods = [MagicalItemPrefix, OfDoom]Now, when we call the factory, we get a random Weapon with magical properties::>>> weapon = MagicalItemFactory()>>> weapon.name'Gnarled Worn Spear of DOOM'Factories always produce mastered blueprints.====TODO====- Better documentation. :\)- Support all operators on ``blueprint.Field``====HELP====If you run into trouble, or find a bug, file an issue in the `trackeron github <https://github.com/eykd/blueprint/issues>`_.On github, bleeding-edge development work is done on the ``develop``branch. ``master`` *should* always be stable.Tests are written using the `behave`_ BDD framework, and may be foundin the ``features/`` folder. To run the test suite, invoke ``behave``from the project root... _behave: http://packages.python.org/behave/===========DEVELOPMENT===========Itching to hack on blueprint? Fork the repository on `on github`_ andsubmit a pull request. If you're not sure what you're doing, follow`these guidelines`_... _on github: http://github.com/eykd/blueprint/.. _these guidelines: https://gun.io/blog/how-to-github-fork-branch-and-pull-request/If you're really high class, your code will be `PEP8`_ compliant, andwill pass the `pep8`_ static checker like so::pep8 --ignore=E221,E701,E202,E203,E225,E251,E5,W291,W293 mymodule.py.. _PEP8: http://www.python.org/dev/peps/pep-0008/.. _pep8: http://pypi.python.org/pypi/pep8/=========CHANGELOG=========- **0.6.1**: Fixed Python 3 compatibility in dice roller.- **0.6**: Experimental Python 3 compatibility, and bug-fixes:- **Feature:** Experimental Python 3 compatibility, thanks to `0ion9`_.- **Major bug fix:** Fixed bug in dice compilation.- **0.5**: A couple new features, some interfaces and many bug-fixes:- **Feature:** Added Property descriptor which acts like a field. May not actually be useful.- **Feature:** Dice rolls now return a results list, which auto-sumswhen doing integer or floating point arithmetic. No more mandatory``sum()`` in your dice expressions.- **Major bug fix:** Fixed bug where Dice fields did not use thecorrect random object, with nondeterministic results.- **Bug fix/Interface change:** Improved (though not yet perfect)field resolution mechanics. Fields that depend on other, deferredfields now have a fighting chance at resolving.- **Bug fix/Interface change:** DiceTable no longer accepts `-` orarbitrary numbers of `.` or `:` as a range separator. Only `..` or`:` work now.- **Interface change:** Operators are now Fields in their own right,with all resulting rights and privileges.- **0.4**: Added a dice roller through ``blueprint.dice.roll``, and acorresponding ``Dice`` and ``DiceTable`` fields. Blueprintsubclasses now have a better ``__repr__`` through themetaclass. **METACLASSES ROCK.**Modified the behavior of field resolution. All fields now use``fields.resolve`` to consistently handle nested callables.- **0.3.4**: Learned how to read. Corrected Sean Howard's name in theintro copy. Three micro-releases in 1 hour!- **0.3.3**: Learned how to use distutils. :P (Fixed a unicode stringin ``setup([packages=[...]])``.)- **0.3.2**: Added the LICENSE file to the source distribution, so pipwon't fail.- **0.3.1**: Radically improved docstrings, with relevantexamples. Added a changelog!- **0.3**: Added Factories. Bugfixes.- **0.2**: Added Mods. Bugfixes.- **0.1**: Initial release... _0ion9: https://github.com/0ion9