diff --git a/.hgignore b/.hgignore index aea031bdb8..54fbbb073e 100644 --- a/.hgignore +++ b/.hgignore @@ -5,5 +5,18 @@ syntax: glob *.pyc *.swp +*.old +*.prof +*.orig +*.key *~ -*# +\#*\# +game/logs/* +game/*.restart +game/*.pid +game/*.db3 +docs/sphinx/build/* +docs/sphinx/wiki2rest/wiki2html/* +docs/sphinx/wiki2rest/rest/* +docs/sphinx/wiki2rest/html/* +docs/sphinx/wiki2html/* diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000000..47b6a74ffa --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,288 @@ +# -*- coding: utf-8 -*- +# +# evennia documentation build configuration file, created by +# sphinx-quickstart on Fri Mar 30 00:25:21 2012. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath('.')))) +from django.core.management import setup_environ +from game import settings +setup_environ(settings) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'evennia' +copyright = u'2012, Author' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '' +# The full version, including alpha/beta/rc tags. +release = '' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'evenniadoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'evennia.tex', u'evennia Documentation', + u'Author', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'evennia', u'evennia Documentation', + [u'Author'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'evennia', u'evennia Documentation', + u'Author', 'evennia', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + + +# -- Options for Epub output --------------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = u'evennia' +epub_author = u'Author' +epub_publisher = u'Author' +epub_copyright = u'2012, Author' + +# The language of the text. It defaults to the language option +# or en if the language is not set. +#epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +#epub_scheme = '' + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +#epub_identifier = '' + +# A unique identification for the text. +#epub_uid = '' + +# A tuple containing the cover image and cover page html template filenames. +#epub_cover = () + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_pre_files = [] + +# HTML files shat should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_post_files = [] + +# A list of files that should not be packed into the epub file. +#epub_exclude_files = [] + +# The depth of the table of contents in toc.ncx. +#epub_tocdepth = 3 + +# Allow duplicate toc entries. +#epub_tocdup = True diff --git a/src/objects/migrations/0010_converting_attributes.py b/src/objects/migrations/0010_converting_attributes.py new file mode 100644 index 0000000000..6612fe7136 --- /dev/null +++ b/src/objects/migrations/0010_converting_attributes.py @@ -0,0 +1,347 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import DataMigration +from django.db import models + +try: + import cPickle as pickle +except ImportError: + import pickle +from src.utils.utils import to_str, to_unicode +from src.typeclasses.models import PackedDBobject + +from django.contrib.contenttypes.models import ContentType +CTYPEGET = ContentType.objects.get +GA = object.__getattribute__ +SA = object.__setattr__ +DA = object.__delattr__ + +class PackedDict(dict): + """ + Attribute helper class. + A variant of dict that stores itself to the database when + updating one of its keys. This is called and handled by + Attribute.validate_data(). + """ + def __init__(self, db_obj, *args, **kwargs): + """ + Sets up the packing dict. The db_store variable + is set by Attribute.validate_data() when returned in + order to allow custom updates to the dict. + + db_obj - the Attribute object storing this dict. + + """ + self.db_obj = db_obj + super(PackedDict, self).__init__(*args, **kwargs) + def __str__(self): + return "{%s}" % ", ".join("%s:%s" % (key, str(val)) for key, val in self.items()) + def __setitem__(self, *args, **kwargs): + "assign item to this dict" + super(PackedDict, self).__setitem__(*args, **kwargs) + self.db_obj.value = self + def clear(self, *args, **kwargs): + "Custom clear" + super(PackedDict, self).clear(*args, **kwargs) + self.db_obj.value = self + def pop(self, *args, **kwargs): + "Custom pop" + super(PackedDict, self).pop(*args, **kwargs) + self.db_obj.value = self + def popitem(self, *args, **kwargs): + "Custom popitem" + super(PackedDict, self).popitem(*args, **kwargs) + self.db_obj.value = self + def update(self, *args, **kwargs): + "Custom update" + super(PackedDict, self).update(*args, **kwargs) + self.db_obj.value = self + +class PackedList(list): + """ + Attribute helper class. + A variant of list that stores itself to the database when + updating one of its keys. This is called and handled by + Attribute.validate_data(). + """ + def __init__(self, db_obj, *args, **kwargs): + """ + Sets up the packing list. + db_obj - the Attribute object storing this dict. + """ + self.db_obj = db_obj + super(PackedList, self).__init__(*args, **kwargs) + def __str__(self): + return "[%s]" % ", ".join(str(val) for val in self) + def __setitem__(self, *args, **kwargs): + "Custom setitem that stores changed list to database." + super(PackedList, self).__setitem__(*args, **kwargs) + self.db_obj.value = self + def append(self, *args, **kwargs): + "Custom append" + super(PackedList, self).append(*args, **kwargs) + self.db_obj.value = self + def extend(self, *args, **kwargs): + "Custom extend" + super(PackedList, self).extend(*args, **kwargs) + self.db_obj.value = self + def insert(self, *args, **kwargs): + "Custom insert" + super(PackedList, self).insert(*args, **kwargs) + self.db_obj.value = self + def remove(self, *args, **kwargs): + "Custom remove" + super(PackedList, self).remove(*args, **kwargs) + self.db_obj.value = self + def pop(self, *args, **kwargs): + "Custom pop" + super(PackedList, self).pop(*args, **kwargs) + self.db_obj.value = self + def reverse(self, *args, **kwargs): + "Custom reverse" + super(PackedList, self).reverse(*args, **kwargs) + self.db_obj.value = self + def sort(self, *args, **kwargs): + "Custom sort" + super(PackedList, self).sort(*args, **kwargs) + self.db_obj.value = self + + +def to_attr(data): + """ + Convert data to proper attr data format before saving + + We have to make sure to not store database objects raw, since + this will crash the system. Instead we must store their IDs + and make sure to convert back when the attribute is read back + later. + + Due to this it's criticial that we check all iterables + recursively, converting all found database objects to a form + the database can handle. We handle lists, tuples and dicts + (and any nested combination of them) this way, all other + iterables are stored and returned as lists. + + data storage format: + (simple|dbobj|iter, ) + where + simple - a single non-db object, like a string or number + dbobj - a single dbobj + iter - any iterable object - will be looped over recursively + to convert dbobj->id. + + """ + + def iter_db2id(item): + """ + recursively looping through stored iterables, replacing objects with ids. + (Python only builds nested functions once, so there is no overhead for nesting) + """ + dtype = type(item) + if dtype in (basestring, int, float): # check the most common types first, for speed + return item + elif hasattr(item, "id") and hasattr(item, "db_model_name") and hasattr(item, "db_key"): + db_model_name = item.db_model_name + if db_model_name == "typeclass": + db_model_name = GA(item.dbobj, "db_model_name") + return PackedDBobject(item.id, db_model_name, item.db_key) + elif dtype == tuple: + return tuple(iter_db2id(val) for val in item) + elif dtype in (dict, PackedDict): + return dict((key, iter_db2id(val)) for key, val in item.items()) + elif hasattr(item, '__iter__'): + return list(iter_db2id(val) for val in item) + else: + return item + + dtype = type(data) + + if dtype in (basestring, int, float): + return ("simple",data) + elif hasattr(data, "id") and hasattr(data, "db_model_name") and hasattr(data, 'db_key'): + # all django models (objectdb,scriptdb,playerdb,channel,msg,typeclass) + # have the protected property db_model_name hardcoded on themselves for speed. + db_model_name = data.db_model_name + if db_model_name == "typeclass": + # typeclass cannot help us, we want the actual child object model name + db_model_name = GA(data.dbobj, "db_model_name") + return ("dbobj", PackedDBobject(data.id, db_model_name, data.db_key)) + elif hasattr(data, "__iter__"): + return ("iter", iter_db2id(data)) + else: + return ("simple", data) + +def from_attr(attr, datatuple): + """ + Retrieve data from a previously stored attribute. This + is always a dict with keys type and data. + + datatuple comes from the database storage and has + the following format: + (simple|dbobj|iter, ) + where + simple - a single non-db object, like a string. is returned as-is. + dbobj - a single dbobj-id. This id is retrieved back from the database. + iter - an iterable. This is traversed iteratively, converting all found + dbobj-ids back to objects. Also, all lists and dictionaries are + returned as their PackedList/PackedDict counterparts in order to + allow in-place assignment such as obj.db.mylist[3] = val. Mylist + is then a PackedList that saves the data on the fly. + """ + # nested functions + def id2db(data): + """ + Convert db-stored dbref back to object + """ + mclass = CTYPEGET(model=data.db_model).model_class() + try: + return mclass.objects.dbref_search(data.id) + + except AttributeError: + try: + return mclass.objects.get(id=data.id) + except mclass.DoesNotExist: # could happen if object was deleted in the interim. + return None + + def iter_id2db(item): + """ + Recursively looping through stored iterables, replacing ids with actual objects. + We return PackedDict and PackedLists instead of normal lists; this is needed in order for + the user to do dynamic saving of nested in-place, such as obj.db.attrlist[2]=3. What is + stored in the database are however always normal python primitives. + """ + dtype = type(item) + if dtype in (basestring, int, float): # check the most common types first, for speed + return item + elif dtype == PackedDBobject: + return id2db(item) + elif dtype == tuple: + return tuple([iter_id2db(val) for val in item]) + elif dtype in (dict, PackedDict): + return dict(zip([key for key in item.keys()], + [iter_id2db(val) for val in item.values()])) + elif hasattr(item, '__iter__'): + return list(iter_id2db(val) for val in item) + else: + return item + + typ, data = datatuple + + if typ == 'simple': + # single non-db objects + return data + elif typ == 'dbobj': + # a single stored dbobj + return id2db(data) + elif typ == 'iter': + # all types of iterables + return iter_id2db(data) + +class Migration(DataMigration): + + def forwards(self, orm): + "Write your forwards methods here." + + for attr in orm.ObjAttribute.objects.all(): + # repack attr into new format, and reimport + try: + val = pickle.loads(to_str(attr.db_value)) + attr.db_value = to_unicode(pickle.dumps(to_str(to_attr(from_attr(attr, val))))) + attr.save() + except TypeError, RuntimeError: + pass + + def backwards(self, orm): + "Write your backwards methods here." + raise RuntimeError + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'objects.alias': { + 'Meta': {'object_name': 'Alias'}, + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'objects.objattribute': { + 'Meta': {'object_name': 'ObjAttribute'}, + 'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}), + 'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']"}), + 'db_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'objects.objectdb': { + 'Meta': {'object_name': 'ObjectDB'}, + 'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'db_destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destinations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}), + 'db_home': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'homes_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}), + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_location': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}), + 'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}), + 'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']", 'null': 'True', 'blank': 'True'}), + 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'objects.objectnick': { + 'Meta': {'unique_together': "(('db_nick', 'db_type', 'db_obj'),)", 'object_name': 'ObjectNick'}, + 'db_nick': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']"}), + 'db_real': ('django.db.models.fields.TextField', [], {}), + 'db_type': ('django.db.models.fields.CharField', [], {'default': "'inputline'", 'max_length': '16', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'players.playerdb': { + 'Meta': {'object_name': 'PlayerDB'}, + 'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + 'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}), + 'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']", 'null': 'True', 'blank': 'True'}), + 'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'}) + } + } + + complete_apps = ['objects'] diff --git a/src/players/migrations/0009_converting_attributes.py b/src/players/migrations/0009_converting_attributes.py new file mode 100644 index 0000000000..d7b3651c4d --- /dev/null +++ b/src/players/migrations/0009_converting_attributes.py @@ -0,0 +1,343 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import DataMigration +from django.db import models + +try: + import cPickle as pickle +except ImportError: + import pickle +from src.utils.utils import to_str, to_unicode +from src.typeclasses.models import PackedDBobject +from src.players.models import PlayerAttribute + +from django.contrib.contenttypes.models import ContentType +CTYPEGET = ContentType.objects.get +GA = object.__getattribute__ +SA = object.__setattr__ +DA = object.__delattr__ + +class PackedDict(dict): + """ + Attribute helper class. + A variant of dict that stores itself to the database when + updating one of its keys. This is called and handled by + Attribute.validate_data(). + """ + def __init__(self, db_obj, *args, **kwargs): + """ + Sets up the packing dict. The db_store variable + is set by Attribute.validate_data() when returned in + order to allow custom updates to the dict. + + db_obj - the Attribute object storing this dict. + + """ + self.db_obj = db_obj + super(PackedDict, self).__init__(*args, **kwargs) + def __str__(self): + return "{%s}" % ", ".join("%s:%s" % (key, str(val)) for key, val in self.items()) + def __setitem__(self, *args, **kwargs): + "assign item to this dict" + super(PackedDict, self).__setitem__(*args, **kwargs) + self.db_obj.value = self + def clear(self, *args, **kwargs): + "Custom clear" + super(PackedDict, self).clear(*args, **kwargs) + self.db_obj.value = self + def pop(self, *args, **kwargs): + "Custom pop" + super(PackedDict, self).pop(*args, **kwargs) + self.db_obj.value = self + def popitem(self, *args, **kwargs): + "Custom popitem" + super(PackedDict, self).popitem(*args, **kwargs) + self.db_obj.value = self + def update(self, *args, **kwargs): + "Custom update" + super(PackedDict, self).update(*args, **kwargs) + self.db_obj.value = self + +class PackedList(list): + """ + Attribute helper class. + A variant of list that stores itself to the database when + updating one of its keys. This is called and handled by + Attribute.validate_data(). + """ + def __init__(self, db_obj, *args, **kwargs): + """ + Sets up the packing list. + db_obj - the Attribute object storing this dict. + """ + self.db_obj = db_obj + super(PackedList, self).__init__(*args, **kwargs) + def __str__(self): + return "[%s]" % ", ".join(str(val) for val in self) + def __setitem__(self, *args, **kwargs): + "Custom setitem that stores changed list to database." + super(PackedList, self).__setitem__(*args, **kwargs) + self.db_obj.value = self + def append(self, *args, **kwargs): + "Custom append" + super(PackedList, self).append(*args, **kwargs) + self.db_obj.value = self + def extend(self, *args, **kwargs): + "Custom extend" + super(PackedList, self).extend(*args, **kwargs) + self.db_obj.value = self + def insert(self, *args, **kwargs): + "Custom insert" + super(PackedList, self).insert(*args, **kwargs) + self.db_obj.value = self + def remove(self, *args, **kwargs): + "Custom remove" + super(PackedList, self).remove(*args, **kwargs) + self.db_obj.value = self + def pop(self, *args, **kwargs): + "Custom pop" + super(PackedList, self).pop(*args, **kwargs) + self.db_obj.value = self + def reverse(self, *args, **kwargs): + "Custom reverse" + super(PackedList, self).reverse(*args, **kwargs) + self.db_obj.value = self + def sort(self, *args, **kwargs): + "Custom sort" + super(PackedList, self).sort(*args, **kwargs) + self.db_obj.value = self + + +def to_attr(data): + """ + Convert data to proper attr data format before saving + + We have to make sure to not store database objects raw, since + this will crash the system. Instead we must store their IDs + and make sure to convert back when the attribute is read back + later. + + Due to this it's criticial that we check all iterables + recursively, converting all found database objects to a form + the database can handle. We handle lists, tuples and dicts + (and any nested combination of them) this way, all other + iterables are stored and returned as lists. + + data storage format: + (simple|dbobj|iter, ) + where + simple - a single non-db object, like a string or number + dbobj - a single dbobj + iter - any iterable object - will be looped over recursively + to convert dbobj->id. + + """ + + def iter_db2id(item): + """ + recursively looping through stored iterables, replacing objects with ids. + (Python only builds nested functions once, so there is no overhead for nesting) + """ + dtype = type(item) + if dtype in (basestring, int, float): # check the most common types first, for speed + return item + elif hasattr(item, "id") and hasattr(item, "db_model_name") and hasattr(item, "db_key"): + db_model_name = item.db_model_name + if db_model_name == "typeclass": + db_model_name = GA(item.dbobj, "db_model_name") + return PackedDBobject(item.id, db_model_name, item.db_key) + elif dtype == tuple: + return tuple(iter_db2id(val) for val in item) + elif dtype in (dict, PackedDict): + return dict((key, iter_db2id(val)) for key, val in item.items()) + elif hasattr(item, '__iter__'): + return list(iter_db2id(val) for val in item) + else: + return item + + dtype = type(data) + + if dtype in (basestring, int, float): + return ("simple",data) + elif hasattr(data, "id") and hasattr(data, "db_model_name") and hasattr(data, 'db_key'): + # all django models (objectdb,scriptdb,playerdb,channel,msg,typeclass) + # have the protected property db_model_name hardcoded on themselves for speed. + db_model_name = data.db_model_name + if db_model_name == "typeclass": + # typeclass cannot help us, we want the actual child object model name + db_model_name = GA(data.dbobj, "db_model_name") + return ("dbobj", PackedDBobject(data.id, db_model_name, data.db_key)) + elif hasattr(data, "__iter__"): + return ("iter", iter_db2id(data)) + else: + return ("simple", data) + +def from_attr(attr, datatuple): + """ + Retrieve data from a previously stored attribute. This + is always a dict with keys type and data. + + datatuple comes from the database storage and has + the following format: + (simple|dbobj|iter, ) + where + simple - a single non-db object, like a string. is returned as-is. + dbobj - a single dbobj-id. This id is retrieved back from the database. + iter - an iterable. This is traversed iteratively, converting all found + dbobj-ids back to objects. Also, all lists and dictionaries are + returned as their PackedList/PackedDict counterparts in order to + allow in-place assignment such as obj.db.mylist[3] = val. Mylist + is then a PackedList that saves the data on the fly. + """ + # nested functions + def id2db(data): + """ + Convert db-stored dbref back to object + """ + mclass = CTYPEGET(model=data.db_model).model_class() + try: + return mclass.objects.dbref_search(data.id) + + except AttributeError: + try: + return mclass.objects.get(id=data.id) + except mclass.DoesNotExist: # could happen if object was deleted in the interim. + return None + + def iter_id2db(item): + """ + Recursively looping through stored iterables, replacing ids with actual objects. + We return PackedDict and PackedLists instead of normal lists; this is needed in order for + the user to do dynamic saving of nested in-place, such as obj.db.attrlist[2]=3. What is + stored in the database are however always normal python primitives. + """ + dtype = type(item) + if dtype in (basestring, int, float): # check the most common types first, for speed + return item + elif dtype == PackedDBobject: + return id2db(item) + elif dtype == tuple: + return tuple([iter_id2db(val) for val in item]) + elif dtype in (dict, PackedDict): + return dict(zip([key for key in item.keys()], + [iter_id2db(val) for val in item.values()])) + elif hasattr(item, '__iter__'): + return list(iter_id2db(val) for val in item) + else: + return item + + typ, data = datatuple + + if typ == 'simple': + # single non-db objects + return data + elif typ == 'dbobj': + # a single stored dbobj + return id2db(data) + elif typ == 'iter': + # all types of iterables + return iter_id2db(data) + + +class Migration(DataMigration): + + def forwards(self, orm): + "Write your forwards methods here." + for attr in orm.PlayerAttribute.objects.all(): + try: + # repack attr into new format, and reimport + val = pickle.loads(to_str(attr.db_value)) + attr.db_value = to_unicode(pickle.dumps(to_str(to_attr(from_attr(attr, val))))) + attr.save() + except TypeError, RuntimeError: + pass + + + def backwards(self, orm): + "Write your backwards methods here." + raise RuntimeError + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'objects.objectdb': { + 'Meta': {'object_name': 'ObjectDB'}, + 'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'db_destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destinations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}), + 'db_home': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'homes_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}), + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_location': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}), + 'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}), + 'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']", 'null': 'True', 'blank': 'True'}), + 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'players.playerattribute': { + 'Meta': {'object_name': 'PlayerAttribute'}, + 'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}), + 'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']"}), + 'db_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'players.playerdb': { + 'Meta': {'object_name': 'PlayerDB'}, + 'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + 'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}), + 'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']", 'null': 'True', 'blank': 'True'}), + 'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'}) + }, + 'players.playernick': { + 'Meta': {'unique_together': "(('db_nick', 'db_type', 'db_obj'),)", 'object_name': 'PlayerNick'}, + 'db_nick': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']"}), + 'db_real': ('django.db.models.fields.TextField', [], {}), + 'db_type': ('django.db.models.fields.CharField', [], {'default': "'inputline'", 'max_length': '16', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + } + } + + complete_apps = ['players'] diff --git a/src/scripts/migrations/0006_converting_attributes.py b/src/scripts/migrations/0006_converting_attributes.py new file mode 100644 index 0000000000..b1e56d5b94 --- /dev/null +++ b/src/scripts/migrations/0006_converting_attributes.py @@ -0,0 +1,348 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import DataMigration +from django.db import models + +try: + import cPickle as pickle +except ImportError: + import pickle +from src.utils.utils import to_str, to_unicode +from src.typeclasses.models import PackedDBobject + +from django.contrib.contenttypes.models import ContentType +CTYPEGET = ContentType.objects.get +GA = object.__getattribute__ +SA = object.__setattr__ +DA = object.__delattr__ + +class PackedDict(dict): + """ + Attribute helper class. + A variant of dict that stores itself to the database when + updating one of its keys. This is called and handled by + Attribute.validate_data(). + """ + def __init__(self, db_obj, *args, **kwargs): + """ + Sets up the packing dict. The db_store variable + is set by Attribute.validate_data() when returned in + order to allow custom updates to the dict. + + db_obj - the Attribute object storing this dict. + + """ + self.db_obj = db_obj + super(PackedDict, self).__init__(*args, **kwargs) + def __str__(self): + return "{%s}" % ", ".join("%s:%s" % (key, str(val)) for key, val in self.items()) + def __setitem__(self, *args, **kwargs): + "assign item to this dict" + super(PackedDict, self).__setitem__(*args, **kwargs) + self.db_obj.value = self + def clear(self, *args, **kwargs): + "Custom clear" + super(PackedDict, self).clear(*args, **kwargs) + self.db_obj.value = self + def pop(self, *args, **kwargs): + "Custom pop" + super(PackedDict, self).pop(*args, **kwargs) + self.db_obj.value = self + def popitem(self, *args, **kwargs): + "Custom popitem" + super(PackedDict, self).popitem(*args, **kwargs) + self.db_obj.value = self + def update(self, *args, **kwargs): + "Custom update" + super(PackedDict, self).update(*args, **kwargs) + self.db_obj.value = self + +class PackedList(list): + """ + Attribute helper class. + A variant of list that stores itself to the database when + updating one of its keys. This is called and handled by + Attribute.validate_data(). + """ + def __init__(self, db_obj, *args, **kwargs): + """ + Sets up the packing list. + db_obj - the Attribute object storing this dict. + """ + self.db_obj = db_obj + super(PackedList, self).__init__(*args, **kwargs) + def __str__(self): + return "[%s]" % ", ".join(str(val) for val in self) + def __setitem__(self, *args, **kwargs): + "Custom setitem that stores changed list to database." + super(PackedList, self).__setitem__(*args, **kwargs) + self.db_obj.value = self + def append(self, *args, **kwargs): + "Custom append" + super(PackedList, self).append(*args, **kwargs) + self.db_obj.value = self + def extend(self, *args, **kwargs): + "Custom extend" + super(PackedList, self).extend(*args, **kwargs) + self.db_obj.value = self + def insert(self, *args, **kwargs): + "Custom insert" + super(PackedList, self).insert(*args, **kwargs) + self.db_obj.value = self + def remove(self, *args, **kwargs): + "Custom remove" + super(PackedList, self).remove(*args, **kwargs) + self.db_obj.value = self + def pop(self, *args, **kwargs): + "Custom pop" + super(PackedList, self).pop(*args, **kwargs) + self.db_obj.value = self + def reverse(self, *args, **kwargs): + "Custom reverse" + super(PackedList, self).reverse(*args, **kwargs) + self.db_obj.value = self + def sort(self, *args, **kwargs): + "Custom sort" + super(PackedList, self).sort(*args, **kwargs) + self.db_obj.value = self + + +def to_attr(data): + """ + Convert data to proper attr data format before saving + + We have to make sure to not store database objects raw, since + this will crash the system. Instead we must store their IDs + and make sure to convert back when the attribute is read back + later. + + Due to this it's criticial that we check all iterables + recursively, converting all found database objects to a form + the database can handle. We handle lists, tuples and dicts + (and any nested combination of them) this way, all other + iterables are stored and returned as lists. + + data storage format: + (simple|dbobj|iter, ) + where + simple - a single non-db object, like a string or number + dbobj - a single dbobj + iter - any iterable object - will be looped over recursively + to convert dbobj->id. + + """ + + def iter_db2id(item): + """ + recursively looping through stored iterables, replacing objects with ids. + (Python only builds nested functions once, so there is no overhead for nesting) + """ + dtype = type(item) + if dtype in (basestring, int, float): # check the most common types first, for speed + return item + elif hasattr(item, "id") and hasattr(item, "db_model_name") and hasattr(item, "db_key"): + db_model_name = item.db_model_name + if db_model_name == "typeclass": + db_model_name = GA(item.dbobj, "db_model_name") + return PackedDBobject(item.id, db_model_name, item.db_key) + elif dtype == tuple: + return tuple(iter_db2id(val) for val in item) + elif dtype in (dict, PackedDict): + return dict((key, iter_db2id(val)) for key, val in item.items()) + elif hasattr(item, '__iter__'): + return list(iter_db2id(val) for val in item) + else: + return item + + dtype = type(data) + + if dtype in (basestring, int, float): + return ("simple",data) + elif hasattr(data, "id") and hasattr(data, "db_model_name") and hasattr(data, 'db_key'): + # all django models (objectdb,scriptdb,playerdb,channel,msg,typeclass) + # have the protected property db_model_name hardcoded on themselves for speed. + db_model_name = data.db_model_name + if db_model_name == "typeclass": + # typeclass cannot help us, we want the actual child object model name + db_model_name = GA(data.dbobj, "db_model_name") + return ("dbobj", PackedDBobject(data.id, db_model_name, data.db_key)) + elif hasattr(data, "__iter__"): + return ("iter", iter_db2id(data)) + else: + return ("simple", data) + +def from_attr(attr, datatuple): + """ + Retrieve data from a previously stored attribute. This + is always a dict with keys type and data. + + datatuple comes from the database storage and has + the following format: + (simple|dbobj|iter, ) + where + simple - a single non-db object, like a string. is returned as-is. + dbobj - a single dbobj-id. This id is retrieved back from the database. + iter - an iterable. This is traversed iteratively, converting all found + dbobj-ids back to objects. Also, all lists and dictionaries are + returned as their PackedList/PackedDict counterparts in order to + allow in-place assignment such as obj.db.mylist[3] = val. Mylist + is then a PackedList that saves the data on the fly. + """ + # nested functions + def id2db(data): + """ + Convert db-stored dbref back to object + """ + mclass = CTYPEGET(model=data.db_model).model_class() + try: + return mclass.objects.dbref_search(data.id) + + except AttributeError: + try: + return mclass.objects.get(id=data.id) + except mclass.DoesNotExist: # could happen if object was deleted in the interim. + return None + + def iter_id2db(item): + """ + Recursively looping through stored iterables, replacing ids with actual objects. + We return PackedDict and PackedLists instead of normal lists; this is needed in order for + the user to do dynamic saving of nested in-place, such as obj.db.attrlist[2]=3. What is + stored in the database are however always normal python primitives. + """ + dtype = type(item) + if dtype in (basestring, int, float): # check the most common types first, for speed + return item + elif dtype == PackedDBobject: + return id2db(item) + elif dtype == tuple: + return tuple([iter_id2db(val) for val in item]) + elif dtype in (dict, PackedDict): + return attr, dict(zip([key for key in item.keys()], + [iter_id2db(val) for val in item.values()])) + elif hasattr(item, '__iter__'): + return list(iter_id2db(val) for val in item) + else: + return item + + typ, data = datatuple + + if typ == 'simple': + # single non-db objects + return data + elif typ == 'dbobj': + # a single stored dbobj + return id2db(data) + elif typ == 'iter': + # all types of iterables + return iter_id2db(data) + +class Migration(DataMigration): + + def forwards(self, orm): + "Write your forwards methods here." + for attr in orm.ScriptAttribute.objects.all(): + try: + # repack attr into new format, and reimport + val = pickle.loads(to_str(attr.db_value)) + attr.db_value = to_unicode(pickle.dumps(to_str(to_attr(from_attr(attr, val))))) + attr.save() + except TypeError, RuntimeError: + pass + + def backwards(self, orm): + "Write your backwards methods here." + raise RuntimeError + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'objects.objectdb': { + 'Meta': {'object_name': 'ObjectDB'}, + 'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'db_destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destinations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}), + 'db_home': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'homes_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}), + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_location': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}), + 'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}), + 'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']", 'null': 'True', 'blank': 'True'}), + 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'players.playerdb': { + 'Meta': {'object_name': 'PlayerDB'}, + 'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + 'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}), + 'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']", 'null': 'True', 'blank': 'True'}), + 'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'}) + }, + 'scripts.scriptattribute': { + 'Meta': {'object_name': 'ScriptAttribute'}, + 'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}), + 'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['scripts.ScriptDB']"}), + 'db_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'scripts.scriptdb': { + 'Meta': {'object_name': 'ScriptDB'}, + 'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'db_desc': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'db_interval': ('django.db.models.fields.IntegerField', [], {'default': '-1'}), + 'db_is_active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}), + 'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']", 'null': 'True', 'blank': 'True'}), + 'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'db_persistent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'db_repeats': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'db_start_delay': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + } + } + + complete_apps = ['scripts']