Format code with black. Add makefile to run fmt/tests
This commit is contained in:
parent
d00bce9288
commit
c2c7fa311a
299 changed files with 19037 additions and 11611 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -49,6 +49,7 @@ _RE_DBREF = re.compile(r"\#[0-9]+")
|
|||
|
||||
# default protfuncs
|
||||
|
||||
|
||||
def random(*args, **kwargs):
|
||||
"""
|
||||
Usage: $random()
|
||||
|
|
@ -77,7 +78,7 @@ def left_justify(*args, **kwargs):
|
|||
|
||||
"""
|
||||
if args:
|
||||
return base_justify(args[0], align='l')
|
||||
return base_justify(args[0], align="l")
|
||||
return ""
|
||||
|
||||
|
||||
|
|
@ -88,7 +89,7 @@ def right_justify(*args, **kwargs):
|
|||
|
||||
"""
|
||||
if args:
|
||||
return base_justify(args[0], align='r')
|
||||
return base_justify(args[0], align="r")
|
||||
return ""
|
||||
|
||||
|
||||
|
|
@ -100,7 +101,7 @@ def center_justify(*args, **kwargs):
|
|||
|
||||
"""
|
||||
if args:
|
||||
return base_justify(args[0], align='c')
|
||||
return base_justify(args[0], align="c")
|
||||
return ""
|
||||
|
||||
|
||||
|
|
@ -122,7 +123,7 @@ def full_justify(*args, **kwargs):
|
|||
|
||||
"""
|
||||
if args:
|
||||
return base_justify(args[0], align='f')
|
||||
return base_justify(args[0], align="f")
|
||||
return ""
|
||||
|
||||
|
||||
|
|
@ -134,7 +135,7 @@ def protkey(*args, **kwargs):
|
|||
|
||||
"""
|
||||
if args:
|
||||
prototype = kwargs['prototype']
|
||||
prototype = kwargs["prototype"]
|
||||
return prototype[args[0].strip()]
|
||||
|
||||
|
||||
|
|
@ -287,7 +288,7 @@ def _obj_search(*args, **kwargs):
|
|||
retlist = []
|
||||
if account:
|
||||
for target in targets:
|
||||
if target.access(account, target, 'control'):
|
||||
if target.access(account, target, "control"):
|
||||
retlist.append(target)
|
||||
else:
|
||||
retlist = targets
|
||||
|
|
@ -297,15 +298,19 @@ def _obj_search(*args, **kwargs):
|
|||
if not targets:
|
||||
raise ValueError("$obj: Query '{}' gave no matches.".format(query))
|
||||
if len(targets) > 1:
|
||||
raise ValueError("$obj: Query '{query}' gave {nmatches} matches. Limit your "
|
||||
"query or use $objlist instead.".format(
|
||||
query=query, nmatches=len(targets)))
|
||||
raise ValueError(
|
||||
"$obj: Query '{query}' gave {nmatches} matches. Limit your "
|
||||
"query or use $objlist instead.".format(query=query, nmatches=len(targets))
|
||||
)
|
||||
target = targets[0]
|
||||
if account:
|
||||
if not target.access(account, target, 'control'):
|
||||
raise ValueError("$obj: Obj {target}(#{dbref} cannot be added - "
|
||||
"Account {account} does not have 'control' access.".format(
|
||||
target=target.key, dbref=target.id, account=account))
|
||||
if not target.access(account, target, "control"):
|
||||
raise ValueError(
|
||||
"$obj: Obj {target}(#{dbref} cannot be added - "
|
||||
"Account {account} does not have 'control' access.".format(
|
||||
target=target.key, dbref=target.id, account=account
|
||||
)
|
||||
)
|
||||
return target
|
||||
|
||||
|
||||
|
|
@ -336,6 +341,6 @@ def dbref(*args, **kwargs):
|
|||
Validate that a #dbref input is valid.
|
||||
"""
|
||||
if not args or len(args) < 1 or _RE_DBREF.match(args[0]) is None:
|
||||
raise ValueError('$dbref requires a valid #dbref argument.')
|
||||
raise ValueError("$dbref requires a valid #dbref argument.")
|
||||
|
||||
return obj(args[0])
|
||||
|
|
|
|||
|
|
@ -13,8 +13,17 @@ from evennia.scripts.scripts import DefaultScript
|
|||
from evennia.objects.models import ObjectDB
|
||||
from evennia.utils.create import create_script
|
||||
from evennia.utils.utils import (
|
||||
all_from_module, make_iter, is_iter, dbid_to_obj, callables_from_module,
|
||||
get_all_typeclasses, to_str, dbref, justify, class_from_module)
|
||||
all_from_module,
|
||||
make_iter,
|
||||
is_iter,
|
||||
dbid_to_obj,
|
||||
callables_from_module,
|
||||
get_all_typeclasses,
|
||||
to_str,
|
||||
dbref,
|
||||
justify,
|
||||
class_from_module,
|
||||
)
|
||||
from evennia.locks.lockhandler import validate_lockstring, check_lockstring
|
||||
from evennia.utils import logger
|
||||
from evennia.utils import inlinefuncs, dbserialize
|
||||
|
|
@ -24,10 +33,25 @@ from evennia.utils.evtable import EvTable
|
|||
_MODULE_PROTOTYPE_MODULES = {}
|
||||
_MODULE_PROTOTYPES = {}
|
||||
_PROTOTYPE_META_NAMES = (
|
||||
"prototype_key", "prototype_desc", "prototype_tags", "prototype_locks", "prototype_parent")
|
||||
"prototype_key",
|
||||
"prototype_desc",
|
||||
"prototype_tags",
|
||||
"prototype_locks",
|
||||
"prototype_parent",
|
||||
)
|
||||
_PROTOTYPE_RESERVED_KEYS = _PROTOTYPE_META_NAMES + (
|
||||
"key", "aliases", "typeclass", "location", "home", "destination",
|
||||
"permissions", "locks", "exec", "tags", "attrs")
|
||||
"key",
|
||||
"aliases",
|
||||
"typeclass",
|
||||
"location",
|
||||
"home",
|
||||
"destination",
|
||||
"permissions",
|
||||
"locks",
|
||||
"exec",
|
||||
"tags",
|
||||
"attrs",
|
||||
)
|
||||
_PROTOTYPE_TAG_CATEGORY = "from_prototype"
|
||||
_PROTOTYPE_TAG_META_CATEGORY = "db_prototype"
|
||||
PROT_FUNCS = {}
|
||||
|
|
@ -41,6 +65,7 @@ class ValidationError(RuntimeError):
|
|||
"""
|
||||
Raised on prototype validation errors
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
|
@ -61,14 +86,14 @@ def homogenize_prototype(prototype, custom_keys=None):
|
|||
"""
|
||||
reserved = _PROTOTYPE_RESERVED_KEYS + (custom_keys or ())
|
||||
|
||||
attrs = list(prototype.get('attrs', [])) # break reference
|
||||
tags = make_iter(prototype.get('tags', []))
|
||||
attrs = list(prototype.get("attrs", [])) # break reference
|
||||
tags = make_iter(prototype.get("tags", []))
|
||||
homogenized_tags = []
|
||||
|
||||
homogenized = {}
|
||||
for key, val in prototype.items():
|
||||
if key in reserved:
|
||||
if key == 'tags':
|
||||
if key == "tags":
|
||||
for tag in tags:
|
||||
if not is_iter(tag):
|
||||
homogenized_tags.append((tag, None, None))
|
||||
|
|
@ -78,18 +103,19 @@ def homogenize_prototype(prototype, custom_keys=None):
|
|||
homogenized[key] = val
|
||||
else:
|
||||
# unassigned keys -> attrs
|
||||
attrs.append((key, val, None, ''))
|
||||
attrs.append((key, val, None, ""))
|
||||
if attrs:
|
||||
homogenized['attrs'] = attrs
|
||||
homogenized["attrs"] = attrs
|
||||
if homogenized_tags:
|
||||
homogenized['tags'] = homogenized_tags
|
||||
homogenized["tags"] = homogenized_tags
|
||||
|
||||
# add required missing parts that had defaults before
|
||||
|
||||
if "prototype_key" not in prototype:
|
||||
# assign a random hash as key
|
||||
homogenized["prototype_key"] = "prototype-{}".format(
|
||||
hashlib.md5(bytes(str(time.time()), 'utf-8')).hexdigest()[:7])
|
||||
hashlib.md5(bytes(str(time.time()), "utf-8")).hexdigest()[:7]
|
||||
)
|
||||
|
||||
if "typeclass" not in prototype and "prototype_parent" not in prototype:
|
||||
homogenized["typeclass"] = settings.BASE_OBJECT_TYPECLASS
|
||||
|
|
@ -106,19 +132,25 @@ for mod in settings.PROTOTYPE_MODULES:
|
|||
for variable_name, prot in all_from_module(mod).items():
|
||||
if isinstance(prot, dict):
|
||||
if "prototype_key" not in prot:
|
||||
prot['prototype_key'] = variable_name.lower()
|
||||
prots.append((prot['prototype_key'], homogenize_prototype(prot)))
|
||||
prot["prototype_key"] = variable_name.lower()
|
||||
prots.append((prot["prototype_key"], homogenize_prototype(prot)))
|
||||
# assign module path to each prototype_key for easy reference
|
||||
_MODULE_PROTOTYPE_MODULES.update({prototype_key.lower(): mod for prototype_key, _ in prots})
|
||||
# make sure the prototype contains all meta info
|
||||
for prototype_key, prot in prots:
|
||||
actual_prot_key = prot.get('prototype_key', prototype_key).lower()
|
||||
prot.update({
|
||||
"prototype_key": actual_prot_key,
|
||||
"prototype_desc": prot['prototype_desc'] if 'prototype_desc' in prot else mod,
|
||||
"prototype_locks": (prot['prototype_locks']
|
||||
if 'prototype_locks' in prot else "use:all();edit:false()"),
|
||||
"prototype_tags": list(set(make_iter(prot.get('prototype_tags', [])) + ["module"]))})
|
||||
actual_prot_key = prot.get("prototype_key", prototype_key).lower()
|
||||
prot.update(
|
||||
{
|
||||
"prototype_key": actual_prot_key,
|
||||
"prototype_desc": prot["prototype_desc"] if "prototype_desc" in prot else mod,
|
||||
"prototype_locks": (
|
||||
prot["prototype_locks"]
|
||||
if "prototype_locks" in prot
|
||||
else "use:all();edit:false()"
|
||||
),
|
||||
"prototype_tags": list(set(make_iter(prot.get("prototype_tags", [])) + ["module"])),
|
||||
}
|
||||
)
|
||||
_MODULE_PROTOTYPES[actual_prot_key] = prot
|
||||
|
||||
|
||||
|
|
@ -129,19 +161,20 @@ class DbPrototype(DefaultScript):
|
|||
"""
|
||||
This stores a single prototype, in an Attribute `prototype`.
|
||||
"""
|
||||
|
||||
def at_script_creation(self):
|
||||
self.key = "empty prototype" # prototype_key
|
||||
self.desc = "A prototype" # prototype_desc (.tags are used for prototype_tags)
|
||||
self.db.prototype = {} # actual prototype
|
||||
self.desc = "A prototype" # prototype_desc (.tags are used for prototype_tags)
|
||||
self.db.prototype = {} # actual prototype
|
||||
|
||||
@property
|
||||
def prototype(self):
|
||||
"Make sure to decouple from db!"
|
||||
return dbserialize.deserialize(self.attributes.get('prototype', {}))
|
||||
return dbserialize.deserialize(self.attributes.get("prototype", {}))
|
||||
|
||||
@prototype.setter
|
||||
def prototype(self, prototype):
|
||||
self.attributes.add('prototype', prototype)
|
||||
self.attributes.add("prototype", prototype)
|
||||
|
||||
|
||||
# Prototype manager functions
|
||||
|
|
@ -174,7 +207,7 @@ def save_prototype(prototype):
|
|||
if is_iter(inp):
|
||||
# already a tuple/list, use as-is
|
||||
return inp
|
||||
return (inp, ) + args
|
||||
return (inp,) + args
|
||||
|
||||
prototype_key = in_prototype.get("prototype_key")
|
||||
if not prototype_key:
|
||||
|
|
@ -185,25 +218,31 @@ def save_prototype(prototype):
|
|||
# we can't edit a prototype defined in a module
|
||||
if prototype_key in _MODULE_PROTOTYPES:
|
||||
mod = _MODULE_PROTOTYPE_MODULES.get(prototype_key, "N/A")
|
||||
raise PermissionError("{} is a read-only prototype "
|
||||
"(defined as code in {}).".format(prototype_key, mod))
|
||||
raise PermissionError(
|
||||
"{} is a read-only prototype " "(defined as code in {}).".format(prototype_key, mod)
|
||||
)
|
||||
|
||||
# make sure meta properties are included with defaults
|
||||
stored_prototype = DbPrototype.objects.filter(db_key=prototype_key)
|
||||
prototype = stored_prototype[0].prototype if stored_prototype else {}
|
||||
|
||||
in_prototype['prototype_desc'] = in_prototype.get("prototype_desc", prototype.get("prototype_desc", ""))
|
||||
in_prototype["prototype_desc"] = in_prototype.get(
|
||||
"prototype_desc", prototype.get("prototype_desc", "")
|
||||
)
|
||||
prototype_locks = in_prototype.get(
|
||||
"prototype_locks", prototype.get('prototype_locks', "spawn:all();edit:perm(Admin)"))
|
||||
"prototype_locks", prototype.get("prototype_locks", "spawn:all();edit:perm(Admin)")
|
||||
)
|
||||
is_valid, err = validate_lockstring(prototype_locks)
|
||||
if not is_valid:
|
||||
raise ValidationError("Lock error: {}".format(err))
|
||||
in_prototype['prototype_locks'] = prototype_locks
|
||||
in_prototype["prototype_locks"] = prototype_locks
|
||||
|
||||
prototype_tags = [
|
||||
_to_batchtuple(tag, _PROTOTYPE_TAG_META_CATEGORY)
|
||||
for tag in make_iter(in_prototype.get("prototype_tags",
|
||||
prototype.get('prototype_tags', [])))]
|
||||
for tag in make_iter(
|
||||
in_prototype.get("prototype_tags", prototype.get("prototype_tags", []))
|
||||
)
|
||||
]
|
||||
in_prototype["prototype_tags"] = prototype_tags
|
||||
|
||||
prototype.update(in_prototype)
|
||||
|
|
@ -211,21 +250,27 @@ def save_prototype(prototype):
|
|||
if stored_prototype:
|
||||
# edit existing prototype
|
||||
stored_prototype = stored_prototype[0]
|
||||
stored_prototype.desc = prototype['prototype_desc']
|
||||
stored_prototype.desc = prototype["prototype_desc"]
|
||||
if prototype_tags:
|
||||
stored_prototype.tags.clear(category=_PROTOTYPE_TAG_CATEGORY)
|
||||
stored_prototype.tags.batch_add(*prototype['prototype_tags'])
|
||||
stored_prototype.locks.add(prototype['prototype_locks'])
|
||||
stored_prototype.attributes.add('prototype', prototype)
|
||||
stored_prototype.tags.batch_add(*prototype["prototype_tags"])
|
||||
stored_prototype.locks.add(prototype["prototype_locks"])
|
||||
stored_prototype.attributes.add("prototype", prototype)
|
||||
else:
|
||||
# create a new prototype
|
||||
stored_prototype = create_script(
|
||||
DbPrototype, key=prototype_key, desc=prototype['prototype_desc'], persistent=True,
|
||||
locks=prototype_locks, tags=prototype['prototype_tags'],
|
||||
attributes=[("prototype", prototype)])
|
||||
DbPrototype,
|
||||
key=prototype_key,
|
||||
desc=prototype["prototype_desc"],
|
||||
persistent=True,
|
||||
locks=prototype_locks,
|
||||
tags=prototype["prototype_tags"],
|
||||
attributes=[("prototype", prototype)],
|
||||
)
|
||||
return stored_prototype.prototype
|
||||
|
||||
create_prototype = save_prototype # alias
|
||||
|
||||
create_prototype = save_prototype # alias
|
||||
|
||||
|
||||
def delete_prototype(prototype_key, caller=None):
|
||||
|
|
@ -244,8 +289,9 @@ def delete_prototype(prototype_key, caller=None):
|
|||
"""
|
||||
if prototype_key in _MODULE_PROTOTYPES:
|
||||
mod = _MODULE_PROTOTYPE_MODULES.get(prototype_key.lower(), "N/A")
|
||||
raise PermissionError("{} is a read-only prototype "
|
||||
"(defined as code in {}).".format(prototype_key, mod))
|
||||
raise PermissionError(
|
||||
"{} is a read-only prototype " "(defined as code in {}).".format(prototype_key, mod)
|
||||
)
|
||||
|
||||
stored_prototype = DbPrototype.objects.filter(db_key__iexact=prototype_key)
|
||||
|
||||
|
|
@ -254,9 +300,11 @@ def delete_prototype(prototype_key, caller=None):
|
|||
|
||||
stored_prototype = stored_prototype[0]
|
||||
if caller:
|
||||
if not stored_prototype.access(caller, 'edit'):
|
||||
raise PermissionError("{} needs explicit 'edit' permissions to "
|
||||
"delete prototype {}.".format(caller, prototype_key))
|
||||
if not stored_prototype.access(caller, "edit"):
|
||||
raise PermissionError(
|
||||
"{} needs explicit 'edit' permissions to "
|
||||
"delete prototype {}.".format(caller, prototype_key)
|
||||
)
|
||||
stored_prototype.delete()
|
||||
return True
|
||||
|
||||
|
|
@ -294,9 +342,11 @@ def search_prototype(key=None, tags=None, require_single=False):
|
|||
if tags:
|
||||
# use tags to limit selection
|
||||
tagset = set(tags)
|
||||
mod_matches = {prototype_key: prototype
|
||||
for prototype_key, prototype in _MODULE_PROTOTYPES.items()
|
||||
if tagset.intersection(prototype.get("prototype_tags", []))}
|
||||
mod_matches = {
|
||||
prototype_key: prototype
|
||||
for prototype_key, prototype in _MODULE_PROTOTYPES.items()
|
||||
if tagset.intersection(prototype.get("prototype_tags", []))
|
||||
}
|
||||
else:
|
||||
mod_matches = _MODULE_PROTOTYPES
|
||||
|
||||
|
|
@ -306,8 +356,11 @@ def search_prototype(key=None, tags=None, require_single=False):
|
|||
module_prototypes = [mod_matches[key]]
|
||||
else:
|
||||
# fuzzy matching
|
||||
module_prototypes = [prototype for prototype_key, prototype in mod_matches.items()
|
||||
if key in prototype_key]
|
||||
module_prototypes = [
|
||||
prototype
|
||||
for prototype_key, prototype in mod_matches.items()
|
||||
if key in prototype_key
|
||||
]
|
||||
else:
|
||||
module_prototypes = [match for match in mod_matches.values()]
|
||||
|
||||
|
|
@ -322,8 +375,9 @@ def search_prototype(key=None, tags=None, require_single=False):
|
|||
db_matches = DbPrototype.objects.all().order_by("id")
|
||||
if key:
|
||||
# exact or partial match on key
|
||||
db_matches = (db_matches.filter(db_key=key) or
|
||||
db_matches.filter(db_key__icontains=key)).order_by("id")
|
||||
db_matches = (
|
||||
db_matches.filter(db_key=key) or db_matches.filter(db_key__icontains=key)
|
||||
).order_by("id")
|
||||
# return prototype
|
||||
db_prototypes = [dbprot.prototype for dbprot in db_matches]
|
||||
|
||||
|
|
@ -332,8 +386,9 @@ def search_prototype(key=None, tags=None, require_single=False):
|
|||
if nmatches > 1 and key:
|
||||
key = key.lower()
|
||||
# avoid duplicates if an exact match exist between the two types
|
||||
filter_matches = [mta for mta in matches
|
||||
if mta.get('prototype_key') and mta['prototype_key'] == key]
|
||||
filter_matches = [
|
||||
mta for mta in matches if mta.get("prototype_key") and mta["prototype_key"] == key
|
||||
]
|
||||
if filter_matches and len(filter_matches) < nmatches:
|
||||
matches = filter_matches
|
||||
|
||||
|
|
@ -381,20 +436,22 @@ def list_prototypes(caller, key=None, tags=None, show_non_use=False, show_non_ed
|
|||
|
||||
# get use-permissions of readonly attributes (edit is always False)
|
||||
display_tuples = []
|
||||
for prototype in sorted(prototypes, key=lambda d: d.get('prototype_key', '')):
|
||||
for prototype in sorted(prototypes, key=lambda d: d.get("prototype_key", "")):
|
||||
lock_use = caller.locks.check_lockstring(
|
||||
caller, prototype.get('prototype_locks', ''), access_type='spawn', default=True)
|
||||
caller, prototype.get("prototype_locks", ""), access_type="spawn", default=True
|
||||
)
|
||||
if not show_non_use and not lock_use:
|
||||
continue
|
||||
if prototype.get('prototype_key', '') in _MODULE_PROTOTYPES:
|
||||
if prototype.get("prototype_key", "") in _MODULE_PROTOTYPES:
|
||||
lock_edit = False
|
||||
else:
|
||||
lock_edit = caller.locks.check_lockstring(
|
||||
caller, prototype.get('prototype_locks', ''), access_type='edit', default=True)
|
||||
caller, prototype.get("prototype_locks", ""), access_type="edit", default=True
|
||||
)
|
||||
if not show_non_edit and not lock_edit:
|
||||
continue
|
||||
ptags = []
|
||||
for ptag in prototype.get('prototype_tags', []):
|
||||
for ptag in prototype.get("prototype_tags", []):
|
||||
if is_iter(ptag):
|
||||
if len(ptag) > 1:
|
||||
ptags.append("{} (category: {}".format(ptag[0], ptag[1]))
|
||||
|
|
@ -404,10 +461,13 @@ def list_prototypes(caller, key=None, tags=None, show_non_use=False, show_non_ed
|
|||
ptags.append(str(ptag))
|
||||
|
||||
display_tuples.append(
|
||||
(prototype.get('prototype_key', '<unset>'),
|
||||
prototype.get('prototype_desc', '<unset>'),
|
||||
"{}/{}".format('Y' if lock_use else 'N', 'Y' if lock_edit else 'N'),
|
||||
",".join(ptags)))
|
||||
(
|
||||
prototype.get("prototype_key", "<unset>"),
|
||||
prototype.get("prototype_desc", "<unset>"),
|
||||
"{}/{}".format("Y" if lock_use else "N", "Y" if lock_edit else "N"),
|
||||
",".join(ptags),
|
||||
)
|
||||
)
|
||||
|
||||
if not display_tuples:
|
||||
return ""
|
||||
|
|
@ -419,13 +479,14 @@ def list_prototypes(caller, key=None, tags=None, show_non_use=False, show_non_ed
|
|||
table = EvTable("Key", "Desc", "Spawn/Edit", "Tags", table=table, crop=True, width=width)
|
||||
table.reformat_column(0, width=22)
|
||||
table.reformat_column(1, width=29)
|
||||
table.reformat_column(2, width=11, align='c')
|
||||
table.reformat_column(2, width=11, align="c")
|
||||
table.reformat_column(3, width=16)
|
||||
return table
|
||||
|
||||
|
||||
def validate_prototype(prototype, protkey=None, protparents=None,
|
||||
is_prototype_base=True, strict=True, _flags=None):
|
||||
def validate_prototype(
|
||||
prototype, protkey=None, protparents=None, is_prototype_base=True, strict=True, _flags=None
|
||||
):
|
||||
"""
|
||||
Run validation on a prototype, checking for inifinite regress.
|
||||
|
||||
|
|
@ -453,83 +514,97 @@ def validate_prototype(prototype, protkey=None, protparents=None,
|
|||
_flags = {"visited": [], "depth": 0, "typeclass": False, "errors": [], "warnings": []}
|
||||
|
||||
if not protparents:
|
||||
protparents = {prototype.get('prototype_key', "").lower(): prototype
|
||||
for prototype in search_prototype()}
|
||||
protparents = {
|
||||
prototype.get("prototype_key", "").lower(): prototype
|
||||
for prototype in search_prototype()
|
||||
}
|
||||
|
||||
protkey = protkey and protkey.lower() or prototype.get('prototype_key', None)
|
||||
protkey = protkey and protkey.lower() or prototype.get("prototype_key", None)
|
||||
|
||||
if strict and not bool(protkey):
|
||||
_flags['errors'].append("Prototype lacks a `prototype_key`.")
|
||||
_flags["errors"].append("Prototype lacks a `prototype_key`.")
|
||||
protkey = "[UNSET]"
|
||||
|
||||
typeclass = prototype.get('typeclass')
|
||||
prototype_parent = prototype.get('prototype_parent', [])
|
||||
typeclass = prototype.get("typeclass")
|
||||
prototype_parent = prototype.get("prototype_parent", [])
|
||||
|
||||
if strict and not (typeclass or prototype_parent):
|
||||
if is_prototype_base:
|
||||
_flags['errors'].append("Prototype {} requires `typeclass` "
|
||||
"or 'prototype_parent'.".format(protkey))
|
||||
_flags["errors"].append(
|
||||
"Prototype {} requires `typeclass` " "or 'prototype_parent'.".format(protkey)
|
||||
)
|
||||
else:
|
||||
_flags['warnings'].append("Prototype {} can only be used as a mixin since it lacks "
|
||||
"a typeclass or a prototype_parent.".format(protkey))
|
||||
_flags["warnings"].append(
|
||||
"Prototype {} can only be used as a mixin since it lacks "
|
||||
"a typeclass or a prototype_parent.".format(protkey)
|
||||
)
|
||||
|
||||
if strict and typeclass:
|
||||
try:
|
||||
class_from_module(typeclass)
|
||||
except ImportError as err:
|
||||
_flags['errors'].append(
|
||||
_flags["errors"].append(
|
||||
"{}: Prototype {} is based on typeclass {}, which could not be imported!".format(
|
||||
err, protkey, typeclass))
|
||||
err, protkey, typeclass
|
||||
)
|
||||
)
|
||||
|
||||
# recursively traverese prototype_parent chain
|
||||
|
||||
for protstring in make_iter(prototype_parent):
|
||||
protstring = protstring.lower()
|
||||
if protkey is not None and protstring == protkey:
|
||||
_flags['errors'].append("Prototype {} tries to parent itself.".format(protkey))
|
||||
_flags["errors"].append("Prototype {} tries to parent itself.".format(protkey))
|
||||
protparent = protparents.get(protstring)
|
||||
if not protparent:
|
||||
_flags['errors'].append("Prototype {}'s prototype_parent '{}' was not found.".format(
|
||||
(protkey, protstring)))
|
||||
if id(prototype) in _flags['visited']:
|
||||
_flags['errors'].append(
|
||||
"{} has infinite nesting of prototypes.".format(protkey or prototype))
|
||||
_flags["errors"].append(
|
||||
"Prototype {}'s prototype_parent '{}' was not found.".format((protkey, protstring))
|
||||
)
|
||||
if id(prototype) in _flags["visited"]:
|
||||
_flags["errors"].append(
|
||||
"{} has infinite nesting of prototypes.".format(protkey or prototype)
|
||||
)
|
||||
|
||||
if _flags['errors']:
|
||||
raise RuntimeError("Error: " + "\nError: ".join(_flags['errors']))
|
||||
_flags['visited'].append(id(prototype))
|
||||
_flags['depth'] += 1
|
||||
validate_prototype(protparent, protstring, protparents,
|
||||
is_prototype_base=is_prototype_base, _flags=_flags)
|
||||
_flags['visited'].pop()
|
||||
_flags['depth'] -= 1
|
||||
if _flags["errors"]:
|
||||
raise RuntimeError("Error: " + "\nError: ".join(_flags["errors"]))
|
||||
_flags["visited"].append(id(prototype))
|
||||
_flags["depth"] += 1
|
||||
validate_prototype(
|
||||
protparent, protstring, protparents, is_prototype_base=is_prototype_base, _flags=_flags
|
||||
)
|
||||
_flags["visited"].pop()
|
||||
_flags["depth"] -= 1
|
||||
|
||||
if typeclass and not _flags['typeclass']:
|
||||
_flags['typeclass'] = typeclass
|
||||
if typeclass and not _flags["typeclass"]:
|
||||
_flags["typeclass"] = typeclass
|
||||
|
||||
# if we get back to the current level without a typeclass it's an error.
|
||||
if strict and is_prototype_base and _flags['depth'] <= 0 and not _flags['typeclass']:
|
||||
_flags['errors'].append("Prototype {} has no `typeclass` defined anywhere in its parent\n "
|
||||
"chain. Add `typeclass`, or a `prototype_parent` pointing to a "
|
||||
"prototype with a typeclass.".format(protkey))
|
||||
if strict and is_prototype_base and _flags["depth"] <= 0 and not _flags["typeclass"]:
|
||||
_flags["errors"].append(
|
||||
"Prototype {} has no `typeclass` defined anywhere in its parent\n "
|
||||
"chain. Add `typeclass`, or a `prototype_parent` pointing to a "
|
||||
"prototype with a typeclass.".format(protkey)
|
||||
)
|
||||
|
||||
if _flags['depth'] <= 0:
|
||||
if _flags['errors']:
|
||||
raise RuntimeError("Error: " + "\nError: ".join(_flags['errors']))
|
||||
if _flags['warnings']:
|
||||
raise RuntimeWarning("Warning: " + "\nWarning: ".join(_flags['warnings']))
|
||||
if _flags["depth"] <= 0:
|
||||
if _flags["errors"]:
|
||||
raise RuntimeError("Error: " + "\nError: ".join(_flags["errors"]))
|
||||
if _flags["warnings"]:
|
||||
raise RuntimeWarning("Warning: " + "\nWarning: ".join(_flags["warnings"]))
|
||||
|
||||
# make sure prototype_locks are set to defaults
|
||||
prototype_locks = [lstring.split(":", 1)
|
||||
for lstring in prototype.get("prototype_locks", "").split(';')
|
||||
if ":" in lstring]
|
||||
prototype_locks = [
|
||||
lstring.split(":", 1)
|
||||
for lstring in prototype.get("prototype_locks", "").split(";")
|
||||
if ":" in lstring
|
||||
]
|
||||
locktypes = [tup[0].strip() for tup in prototype_locks]
|
||||
if "spawn" not in locktypes:
|
||||
prototype_locks.append(("spawn", "all()"))
|
||||
if "edit" not in locktypes:
|
||||
prototype_locks.append(("edit", "all()"))
|
||||
prototype_locks = ";".join(":".join(tup) for tup in prototype_locks)
|
||||
prototype['prototype_locks'] = prototype_locks
|
||||
prototype["prototype_locks"] = prototype_locks
|
||||
|
||||
|
||||
# Protfunc parsing (in-prototype functions)
|
||||
|
|
@ -582,8 +657,8 @@ def protfunc_parser(value, available_functions=None, testing=False, stacktrace=F
|
|||
available_functions = PROT_FUNCS if available_functions is None else available_functions
|
||||
|
||||
result = inlinefuncs.parse_inlinefunc(
|
||||
value, available_funcs=available_functions,
|
||||
stacktrace=stacktrace, testing=testing, **kwargs)
|
||||
value, available_funcs=available_functions, stacktrace=stacktrace, testing=testing, **kwargs
|
||||
)
|
||||
|
||||
err = None
|
||||
try:
|
||||
|
|
@ -599,6 +674,7 @@ def protfunc_parser(value, available_functions=None, testing=False, stacktrace=F
|
|||
|
||||
# Various prototype utilities
|
||||
|
||||
|
||||
def format_available_protfuncs():
|
||||
"""
|
||||
Get all protfuncs in a pretty-formatted form.
|
||||
|
|
@ -608,8 +684,11 @@ def format_available_protfuncs():
|
|||
"""
|
||||
out = []
|
||||
for protfunc_name, protfunc in PROT_FUNCS.items():
|
||||
out.append("- |c${name}|n - |W{docs}".format(
|
||||
name=protfunc_name, docs=protfunc.__doc__.strip().replace("\n", "")))
|
||||
out.append(
|
||||
"- |c${name}|n - |W{docs}".format(
|
||||
name=protfunc_name, docs=protfunc.__doc__.strip().replace("\n", "")
|
||||
)
|
||||
)
|
||||
return justify("\n".join(out), indent=8)
|
||||
|
||||
|
||||
|
|
@ -628,61 +707,70 @@ def prototype_to_str(prototype):
|
|||
|c-desc|n: {prototype_desc}
|
||||
|cprototype-parent:|n {prototype_parent}
|
||||
\n""".format(
|
||||
prototype_key=prototype.get('prototype_key', '|r[UNSET](required)|n'),
|
||||
prototype_tags=prototype.get('prototype_tags', '|wNone|n'),
|
||||
prototype_locks=prototype.get('prototype_locks', '|wNone|n'),
|
||||
prototype_desc=prototype.get('prototype_desc', '|wNone|n'),
|
||||
prototype_parent=prototype.get('prototype_parent', '|wNone|n'))
|
||||
prototype_key=prototype.get("prototype_key", "|r[UNSET](required)|n"),
|
||||
prototype_tags=prototype.get("prototype_tags", "|wNone|n"),
|
||||
prototype_locks=prototype.get("prototype_locks", "|wNone|n"),
|
||||
prototype_desc=prototype.get("prototype_desc", "|wNone|n"),
|
||||
prototype_parent=prototype.get("prototype_parent", "|wNone|n"),
|
||||
)
|
||||
|
||||
key = prototype.get('key', '')
|
||||
key = prototype.get("key", "")
|
||||
if key:
|
||||
key = "|ckey:|n {key}".format(key=key)
|
||||
aliases = prototype.get("aliases", '')
|
||||
aliases = prototype.get("aliases", "")
|
||||
if aliases:
|
||||
aliases = "|caliases:|n {aliases}".format(
|
||||
aliases=", ".join(aliases))
|
||||
attrs = prototype.get("attrs", '')
|
||||
aliases = "|caliases:|n {aliases}".format(aliases=", ".join(aliases))
|
||||
attrs = prototype.get("attrs", "")
|
||||
if attrs:
|
||||
out = []
|
||||
for (attrkey, value, category, locks) in attrs:
|
||||
locks = ", ".join(lock for lock in locks if lock)
|
||||
category = "|ccategory:|n {}".format(category) if category else ''
|
||||
category = "|ccategory:|n {}".format(category) if category else ""
|
||||
cat_locks = ""
|
||||
if category or locks:
|
||||
cat_locks = " (|ccategory:|n {category}, ".format(
|
||||
category=category if category else "|wNone|n")
|
||||
category=category if category else "|wNone|n"
|
||||
)
|
||||
out.append(
|
||||
"{attrkey}{cat_locks} |c=|n {value}".format(
|
||||
attrkey=attrkey,
|
||||
cat_locks=cat_locks,
|
||||
locks=locks if locks else "|wNone|n",
|
||||
value=value))
|
||||
attrkey=attrkey,
|
||||
cat_locks=cat_locks,
|
||||
locks=locks if locks else "|wNone|n",
|
||||
value=value,
|
||||
)
|
||||
)
|
||||
attrs = "|cattrs:|n\n {attrs}".format(attrs="\n ".join(out))
|
||||
tags = prototype.get('tags', '')
|
||||
tags = prototype.get("tags", "")
|
||||
if tags:
|
||||
out = []
|
||||
for (tagkey, category, data) in tags:
|
||||
out.append("{tagkey} (category: {category}{dat})".format(
|
||||
tagkey=tagkey, category=category, dat=", data: {}".format(data) if data else ""))
|
||||
out.append(
|
||||
"{tagkey} (category: {category}{dat})".format(
|
||||
tagkey=tagkey, category=category, dat=", data: {}".format(data) if data else ""
|
||||
)
|
||||
)
|
||||
tags = "|ctags:|n\n {tags}".format(tags=", ".join(out))
|
||||
locks = prototype.get('locks', '')
|
||||
locks = prototype.get("locks", "")
|
||||
if locks:
|
||||
locks = "|clocks:|n\n {locks}".format(locks=locks)
|
||||
permissions = prototype.get("permissions", '')
|
||||
permissions = prototype.get("permissions", "")
|
||||
if permissions:
|
||||
permissions = "|cpermissions:|n {perms}".format(perms=", ".join(permissions))
|
||||
location = prototype.get("location", '')
|
||||
location = prototype.get("location", "")
|
||||
if location:
|
||||
location = "|clocation:|n {location}".format(location=location)
|
||||
home = prototype.get("home", '')
|
||||
home = prototype.get("home", "")
|
||||
if home:
|
||||
home = "|chome:|n {home}".format(home=home)
|
||||
destination = prototype.get("destination", '')
|
||||
destination = prototype.get("destination", "")
|
||||
if destination:
|
||||
destination = "|cdestination:|n {destination}".format(destination=destination)
|
||||
|
||||
body = "\n".join(part for part in (key, aliases, attrs, tags, locks, permissions,
|
||||
location, home, destination) if part)
|
||||
body = "\n".join(
|
||||
part
|
||||
for part in (key, aliases, attrs, tags, locks, permissions, location, home, destination)
|
||||
if part
|
||||
)
|
||||
|
||||
return header.lstrip() + body.strip()
|
||||
|
||||
|
|
@ -700,11 +788,12 @@ def check_permission(prototype_key, action, default=True):
|
|||
passes (bool): If permission for action is granted or not.
|
||||
|
||||
"""
|
||||
if action == 'edit':
|
||||
if action == "edit":
|
||||
if prototype_key in _MODULE_PROTOTYPES:
|
||||
mod = _MODULE_PROTOTYPE_MODULES.get(prototype_key, "N/A")
|
||||
logger.log_err("{} is a read-only prototype "
|
||||
"(defined as code in {}).".format(prototype_key, mod))
|
||||
logger.log_err(
|
||||
"{} is a read-only prototype " "(defined as code in {}).".format(prototype_key, mod)
|
||||
)
|
||||
return False
|
||||
|
||||
prototype = search_prototype(key=prototype_key)
|
||||
|
|
@ -715,8 +804,7 @@ def check_permission(prototype_key, action, default=True):
|
|||
lockstring = prototype.get("prototype_locks")
|
||||
|
||||
if lockstring:
|
||||
return check_lockstring(None, lockstring,
|
||||
default=default, access_type=action)
|
||||
return check_lockstring(None, lockstring, default=default, access_type=action)
|
||||
return default
|
||||
|
||||
|
||||
|
|
@ -753,8 +841,9 @@ def value_to_obj_or_any(value):
|
|||
stype = type(value)
|
||||
if is_iter(value):
|
||||
if stype == dict:
|
||||
return {value_to_obj_or_any(key):
|
||||
value_to_obj_or_any(val) for key, val in value.items()}
|
||||
return {
|
||||
value_to_obj_or_any(key): value_to_obj_or_any(val) for key, val in value.items()
|
||||
}
|
||||
else:
|
||||
return stype([value_to_obj_or_any(val) for val in value])
|
||||
obj = dbid_to_obj(value, ObjectDB)
|
||||
|
|
|
|||
|
|
@ -141,18 +141,33 @@ from evennia.objects.models import ObjectDB
|
|||
from evennia.utils.utils import make_iter, is_iter
|
||||
from evennia.prototypes import prototypes as protlib
|
||||
from evennia.prototypes.prototypes import (
|
||||
value_to_obj, value_to_obj_or_any, init_spawn_value, _PROTOTYPE_TAG_CATEGORY)
|
||||
value_to_obj,
|
||||
value_to_obj_or_any,
|
||||
init_spawn_value,
|
||||
_PROTOTYPE_TAG_CATEGORY,
|
||||
)
|
||||
|
||||
|
||||
_CREATE_OBJECT_KWARGS = ("key", "location", "home", "destination")
|
||||
_PROTOTYPE_META_NAMES = ("prototype_key", "prototype_desc", "prototype_tags", "prototype_locks")
|
||||
_PROTOTYPE_ROOT_NAMES = ('typeclass', 'key', 'aliases', 'attrs', 'tags', 'locks', 'permissions',
|
||||
'location', 'home', 'destination')
|
||||
_PROTOTYPE_ROOT_NAMES = (
|
||||
"typeclass",
|
||||
"key",
|
||||
"aliases",
|
||||
"attrs",
|
||||
"tags",
|
||||
"locks",
|
||||
"permissions",
|
||||
"location",
|
||||
"home",
|
||||
"destination",
|
||||
)
|
||||
_NON_CREATE_KWARGS = _CREATE_OBJECT_KWARGS + _PROTOTYPE_META_NAMES
|
||||
|
||||
|
||||
# Helper
|
||||
|
||||
|
||||
def _get_prototype(inprot, protparents, uninherited=None, _workprot=None):
|
||||
"""
|
||||
Recursively traverse a prototype dictionary, including multiple
|
||||
|
|
@ -170,6 +185,7 @@ def _get_prototype(inprot, protparents, uninherited=None, _workprot=None):
|
|||
`prototype_parent` key is removed).
|
||||
|
||||
"""
|
||||
|
||||
def _inherit_tags(old_tags, new_tags):
|
||||
old = {(tup[0], tup[1]): tup for tup in old_tags}
|
||||
new = {(tup[0], tup[1]): tup for tup in new_tags}
|
||||
|
|
@ -187,22 +203,21 @@ def _get_prototype(inprot, protparents, uninherited=None, _workprot=None):
|
|||
# move backwards through the inheritance
|
||||
for prototype in make_iter(inprot["prototype_parent"]):
|
||||
# Build the prot dictionary in reverse order, overloading
|
||||
new_prot = _get_prototype(protparents.get(prototype.lower(), {}),
|
||||
protparents, _workprot=_workprot)
|
||||
new_prot = _get_prototype(
|
||||
protparents.get(prototype.lower(), {}), protparents, _workprot=_workprot
|
||||
)
|
||||
|
||||
# attrs, tags have internal structure that should be inherited separately
|
||||
new_prot['attrs'] = _inherit_attrs(
|
||||
_workprot.get("attrs", {}), new_prot.get("attrs", {}))
|
||||
new_prot['tags'] = _inherit_tags(
|
||||
_workprot.get("tags", {}), new_prot.get("tags", {}))
|
||||
new_prot["attrs"] = _inherit_attrs(
|
||||
_workprot.get("attrs", {}), new_prot.get("attrs", {})
|
||||
)
|
||||
new_prot["tags"] = _inherit_tags(_workprot.get("tags", {}), new_prot.get("tags", {}))
|
||||
|
||||
_workprot.update(new_prot)
|
||||
# the inprot represents a higher level (a child prot), which should override parents
|
||||
|
||||
inprot['attrs'] = _inherit_attrs(
|
||||
_workprot.get("attrs", {}), inprot.get("attrs", {}))
|
||||
inprot['tags'] = _inherit_tags(
|
||||
_workprot.get("tags", {}), inprot.get("tags", {}))
|
||||
inprot["attrs"] = _inherit_attrs(_workprot.get("attrs", {}), inprot.get("attrs", {}))
|
||||
inprot["tags"] = _inherit_tags(_workprot.get("tags", {}), inprot.get("tags", {}))
|
||||
_workprot.update(inprot)
|
||||
if uninherited:
|
||||
# put back the parts that should not be inherited
|
||||
|
|
@ -227,16 +242,19 @@ def flatten_prototype(prototype, validate=False):
|
|||
|
||||
if prototype:
|
||||
prototype = protlib.homogenize_prototype(prototype)
|
||||
protparents = {prot['prototype_key'].lower(): prot for prot in protlib.search_prototype()}
|
||||
protlib.validate_prototype(prototype, None, protparents,
|
||||
is_prototype_base=validate, strict=validate)
|
||||
return _get_prototype(prototype, protparents,
|
||||
uninherited={"prototype_key": prototype.get("prototype_key")})
|
||||
protparents = {prot["prototype_key"].lower(): prot for prot in protlib.search_prototype()}
|
||||
protlib.validate_prototype(
|
||||
prototype, None, protparents, is_prototype_base=validate, strict=validate
|
||||
)
|
||||
return _get_prototype(
|
||||
prototype, protparents, uninherited={"prototype_key": prototype.get("prototype_key")}
|
||||
)
|
||||
return {}
|
||||
|
||||
|
||||
# obj-related prototype functions
|
||||
|
||||
|
||||
def prototype_from_object(obj):
|
||||
"""
|
||||
Guess a minimal prototype from an existing object.
|
||||
|
|
@ -257,43 +275,49 @@ def prototype_from_object(obj):
|
|||
if not prot or len(prot) > 1:
|
||||
# no unambiguous prototype found - build new prototype
|
||||
prot = {}
|
||||
prot['prototype_key'] = "From-Object-{}-{}".format(
|
||||
obj.key, hashlib.md5(bytes(str(time.time()), 'utf-8')).hexdigest()[:7])
|
||||
prot['prototype_desc'] = "Built from {}".format(str(obj))
|
||||
prot['prototype_locks'] = "spawn:all();edit:all()"
|
||||
prot['prototype_tags'] = []
|
||||
prot["prototype_key"] = "From-Object-{}-{}".format(
|
||||
obj.key, hashlib.md5(bytes(str(time.time()), "utf-8")).hexdigest()[:7]
|
||||
)
|
||||
prot["prototype_desc"] = "Built from {}".format(str(obj))
|
||||
prot["prototype_locks"] = "spawn:all();edit:all()"
|
||||
prot["prototype_tags"] = []
|
||||
else:
|
||||
prot = prot[0]
|
||||
|
||||
prot['key'] = obj.db_key or hashlib.md5(bytes(str(time.time()), 'utf-8')).hexdigest()[:6]
|
||||
prot['typeclass'] = obj.db_typeclass_path
|
||||
prot["key"] = obj.db_key or hashlib.md5(bytes(str(time.time()), "utf-8")).hexdigest()[:6]
|
||||
prot["typeclass"] = obj.db_typeclass_path
|
||||
|
||||
location = obj.db_location
|
||||
if location:
|
||||
prot['location'] = location.dbref
|
||||
prot["location"] = location.dbref
|
||||
home = obj.db_home
|
||||
if home:
|
||||
prot['home'] = home.dbref
|
||||
prot["home"] = home.dbref
|
||||
destination = obj.db_destination
|
||||
if destination:
|
||||
prot['destination'] = destination.dbref
|
||||
prot["destination"] = destination.dbref
|
||||
locks = obj.locks.all()
|
||||
if locks:
|
||||
prot['locks'] = ";".join(locks)
|
||||
prot["locks"] = ";".join(locks)
|
||||
perms = obj.permissions.get(return_list=True)
|
||||
if perms:
|
||||
prot['permissions'] = make_iter(perms)
|
||||
prot["permissions"] = make_iter(perms)
|
||||
aliases = obj.aliases.get(return_list=True)
|
||||
if aliases:
|
||||
prot['aliases'] = aliases
|
||||
tags = sorted([(tag.db_key, tag.db_category, tag.db_data)
|
||||
for tag in obj.tags.all(return_objs=True)])
|
||||
prot["aliases"] = aliases
|
||||
tags = sorted(
|
||||
[(tag.db_key, tag.db_category, tag.db_data) for tag in obj.tags.all(return_objs=True)]
|
||||
)
|
||||
if tags:
|
||||
prot['tags'] = tags
|
||||
attrs = sorted([(attr.key, attr.value, attr.category, ';'.join(attr.locks.all()))
|
||||
for attr in obj.attributes.all()])
|
||||
prot["tags"] = tags
|
||||
attrs = sorted(
|
||||
[
|
||||
(attr.key, attr.value, attr.category, ";".join(attr.locks.all()))
|
||||
for attr in obj.attributes.all()
|
||||
]
|
||||
)
|
||||
if attrs:
|
||||
prot['attrs'] = attrs
|
||||
prot["attrs"] = attrs
|
||||
|
||||
return prot
|
||||
|
||||
|
|
@ -320,6 +344,7 @@ def prototype_diff(prototype1, prototype2, maxdepth=2):
|
|||
instruction can be one of "REMOVE", "ADD", "UPDATE" or "KEEP".
|
||||
|
||||
"""
|
||||
|
||||
def _recursive_diff(old, new, depth=0):
|
||||
|
||||
old_type = type(old)
|
||||
|
|
@ -330,8 +355,9 @@ def prototype_diff(prototype1, prototype2, maxdepth=2):
|
|||
if depth < maxdepth and old_type == dict:
|
||||
return {key: (part, None, "REMOVE") for key, part in old.items()}
|
||||
elif depth < maxdepth and is_iter(old):
|
||||
return {part[0] if is_iter(part) else part:
|
||||
(part, None, "REMOVE") for part in old}
|
||||
return {
|
||||
part[0] if is_iter(part) else part: (part, None, "REMOVE") for part in old
|
||||
}
|
||||
return (old, new, "REMOVE")
|
||||
elif not old and new:
|
||||
if depth < maxdepth and new_type == dict:
|
||||
|
|
@ -344,14 +370,18 @@ def prototype_diff(prototype1, prototype2, maxdepth=2):
|
|||
return (old, new, "UPDATE")
|
||||
elif depth < maxdepth and new_type == dict:
|
||||
all_keys = set(list(old.keys()) + list(new.keys()))
|
||||
return {key: _recursive_diff(old.get(key), new.get(key), depth=depth + 1)
|
||||
for key in all_keys}
|
||||
return {
|
||||
key: _recursive_diff(old.get(key), new.get(key), depth=depth + 1)
|
||||
for key in all_keys
|
||||
}
|
||||
elif depth < maxdepth and is_iter(new):
|
||||
old_map = {part[0] if is_iter(part) else part: part for part in old}
|
||||
new_map = {part[0] if is_iter(part) else part: part for part in new}
|
||||
all_keys = set(list(old_map.keys()) + list(new_map.keys()))
|
||||
return {key: _recursive_diff(old_map.get(key), new_map.get(key), depth=depth + 1)
|
||||
for key in all_keys}
|
||||
return {
|
||||
key: _recursive_diff(old_map.get(key), new_map.get(key), depth=depth + 1)
|
||||
for key in all_keys
|
||||
}
|
||||
elif old != new:
|
||||
return (old, new, "UPDATE")
|
||||
else:
|
||||
|
|
@ -390,7 +420,7 @@ def flatten_diff(diff):
|
|||
- Mix REMOVE, KEEP, UPDATE, ADD -> REPLACE
|
||||
"""
|
||||
|
||||
valid_instructions = ('KEEP', 'REMOVE', 'ADD', 'UPDATE')
|
||||
valid_instructions = ("KEEP", "REMOVE", "ADD", "UPDATE")
|
||||
|
||||
def _get_all_nested_diff_instructions(diffpart):
|
||||
"Started for each root key, returns all instructions nested under it"
|
||||
|
|
@ -403,8 +433,10 @@ def flatten_diff(diff):
|
|||
for val in diffpart.values():
|
||||
out.extend(_get_all_nested_diff_instructions(val))
|
||||
else:
|
||||
raise RuntimeError("Diff contains non-dicts that are not on the "
|
||||
"form (old, new, inst): {}".format(diffpart))
|
||||
raise RuntimeError(
|
||||
"Diff contains non-dicts that are not on the "
|
||||
"form (old, new, inst): {}".format(diffpart)
|
||||
)
|
||||
return out
|
||||
|
||||
flat_diff = {}
|
||||
|
|
@ -480,7 +512,7 @@ def batch_update_objects_with_prototype(prototype, diff=None, objects=None):
|
|||
else:
|
||||
new_prototype = prototype
|
||||
|
||||
prototype_key = new_prototype['prototype_key']
|
||||
prototype_key = new_prototype["prototype_key"]
|
||||
|
||||
if not objects:
|
||||
objects = ObjectDB.objects.get_by_tag(prototype_key, category=_PROTOTYPE_TAG_CATEGORY)
|
||||
|
|
@ -504,7 +536,7 @@ def batch_update_objects_with_prototype(prototype, diff=None, objects=None):
|
|||
obj.tags.add(prototype_key, category=_PROTOTYPE_TAG_CATEGORY)
|
||||
|
||||
for key, directive in diff.items():
|
||||
if directive in ('UPDATE', 'REPLACE'):
|
||||
if directive in ("UPDATE", "REPLACE"):
|
||||
|
||||
if key in _PROTOTYPE_META_NAMES:
|
||||
# prototype meta keys are not stored on-object
|
||||
|
|
@ -513,72 +545,80 @@ def batch_update_objects_with_prototype(prototype, diff=None, objects=None):
|
|||
val = new_prototype[key]
|
||||
do_save = True
|
||||
|
||||
if key == 'key':
|
||||
if key == "key":
|
||||
obj.db_key = init_spawn_value(val, str)
|
||||
elif key == 'typeclass':
|
||||
elif key == "typeclass":
|
||||
obj.db_typeclass_path = init_spawn_value(val, str)
|
||||
elif key == 'location':
|
||||
elif key == "location":
|
||||
obj.db_location = init_spawn_value(val, value_to_obj)
|
||||
elif key == 'home':
|
||||
elif key == "home":
|
||||
obj.db_home = init_spawn_value(val, value_to_obj)
|
||||
elif key == 'destination':
|
||||
elif key == "destination":
|
||||
obj.db_destination = init_spawn_value(val, value_to_obj)
|
||||
elif key == 'locks':
|
||||
if directive == 'REPLACE':
|
||||
elif key == "locks":
|
||||
if directive == "REPLACE":
|
||||
obj.locks.clear()
|
||||
obj.locks.add(init_spawn_value(val, str))
|
||||
elif key == 'permissions':
|
||||
if directive == 'REPLACE':
|
||||
elif key == "permissions":
|
||||
if directive == "REPLACE":
|
||||
obj.permissions.clear()
|
||||
obj.permissions.batch_add(*(init_spawn_value(perm, str) for perm in val))
|
||||
elif key == 'aliases':
|
||||
if directive == 'REPLACE':
|
||||
elif key == "aliases":
|
||||
if directive == "REPLACE":
|
||||
obj.aliases.clear()
|
||||
obj.aliases.batch_add(*(init_spawn_value(alias, str) for alias in val))
|
||||
elif key == 'tags':
|
||||
if directive == 'REPLACE':
|
||||
elif key == "tags":
|
||||
if directive == "REPLACE":
|
||||
obj.tags.clear()
|
||||
obj.tags.batch_add(*(
|
||||
(init_spawn_value(ttag, str), tcategory, tdata)
|
||||
for ttag, tcategory, tdata in val))
|
||||
elif key == 'attrs':
|
||||
if directive == 'REPLACE':
|
||||
obj.tags.batch_add(
|
||||
*(
|
||||
(init_spawn_value(ttag, str), tcategory, tdata)
|
||||
for ttag, tcategory, tdata in val
|
||||
)
|
||||
)
|
||||
elif key == "attrs":
|
||||
if directive == "REPLACE":
|
||||
obj.attributes.clear()
|
||||
obj.attributes.batch_add(*(
|
||||
(init_spawn_value(akey, str),
|
||||
init_spawn_value(aval, value_to_obj),
|
||||
acategory,
|
||||
alocks)
|
||||
for akey, aval, acategory, alocks in val))
|
||||
elif key == 'exec':
|
||||
obj.attributes.batch_add(
|
||||
*(
|
||||
(
|
||||
init_spawn_value(akey, str),
|
||||
init_spawn_value(aval, value_to_obj),
|
||||
acategory,
|
||||
alocks,
|
||||
)
|
||||
for akey, aval, acategory, alocks in val
|
||||
)
|
||||
)
|
||||
elif key == "exec":
|
||||
# we don't auto-rerun exec statements, it would be huge security risk!
|
||||
pass
|
||||
else:
|
||||
obj.attributes.add(key, init_spawn_value(val, value_to_obj))
|
||||
elif directive == 'REMOVE':
|
||||
elif directive == "REMOVE":
|
||||
do_save = True
|
||||
if key == 'key':
|
||||
obj.db_key = ''
|
||||
elif key == 'typeclass':
|
||||
if key == "key":
|
||||
obj.db_key = ""
|
||||
elif key == "typeclass":
|
||||
# fall back to default
|
||||
obj.db_typeclass_path = settings.BASE_OBJECT_TYPECLASS
|
||||
elif key == 'location':
|
||||
elif key == "location":
|
||||
obj.db_location = None
|
||||
elif key == 'home':
|
||||
elif key == "home":
|
||||
obj.db_home = None
|
||||
elif key == 'destination':
|
||||
elif key == "destination":
|
||||
obj.db_destination = None
|
||||
elif key == 'locks':
|
||||
elif key == "locks":
|
||||
obj.locks.clear()
|
||||
elif key == 'permissions':
|
||||
elif key == "permissions":
|
||||
obj.permissions.clear()
|
||||
elif key == 'aliases':
|
||||
elif key == "aliases":
|
||||
obj.aliases.clear()
|
||||
elif key == 'tags':
|
||||
elif key == "tags":
|
||||
obj.tags.clear()
|
||||
elif key == 'attrs':
|
||||
elif key == "attrs":
|
||||
obj.attributes.clear()
|
||||
elif key == 'exec':
|
||||
elif key == "exec":
|
||||
# we don't auto-rerun exec statements, it would be huge security risk!
|
||||
pass
|
||||
else:
|
||||
|
|
@ -639,12 +679,14 @@ def batch_create_object(*objparams):
|
|||
obj = ObjectDB(**objparam[0])
|
||||
|
||||
# setup
|
||||
obj._createdict = {"permissions": make_iter(objparam[1]),
|
||||
"locks": objparam[2],
|
||||
"aliases": make_iter(objparam[3]),
|
||||
"nattributes": objparam[4],
|
||||
"attributes": objparam[5],
|
||||
"tags": make_iter(objparam[6])}
|
||||
obj._createdict = {
|
||||
"permissions": make_iter(objparam[1]),
|
||||
"locks": objparam[2],
|
||||
"aliases": make_iter(objparam[3]),
|
||||
"nattributes": objparam[4],
|
||||
"attributes": objparam[5],
|
||||
"tags": make_iter(objparam[6]),
|
||||
}
|
||||
# this triggers all hooks
|
||||
obj.save()
|
||||
# run eventual extra code
|
||||
|
|
@ -657,6 +699,7 @@ def batch_create_object(*objparams):
|
|||
|
||||
# Spawner mechanism
|
||||
|
||||
|
||||
def spawn(*prototypes, **kwargs):
|
||||
"""
|
||||
Spawn a number of prototyped objects.
|
||||
|
|
@ -688,12 +731,13 @@ def spawn(*prototypes, **kwargs):
|
|||
|
||||
"""
|
||||
# search string (=prototype_key) from input
|
||||
prototypes = [protlib.search_prototype(prot, require_single=True)[0]
|
||||
if isinstance(prot, str) else prot
|
||||
for prot in prototypes]
|
||||
prototypes = [
|
||||
protlib.search_prototype(prot, require_single=True)[0] if isinstance(prot, str) else prot
|
||||
for prot in prototypes
|
||||
]
|
||||
|
||||
# get available protparents
|
||||
protparents = {prot['prototype_key'].lower(): prot for prot in protlib.search_prototype()}
|
||||
protparents = {prot["prototype_key"].lower(): prot for prot in protlib.search_prototype()}
|
||||
|
||||
if not kwargs.get("only_validate"):
|
||||
# homogenization to be more lenient about prototype format when entering the prototype manually
|
||||
|
|
@ -704,7 +748,7 @@ def spawn(*prototypes, **kwargs):
|
|||
# prototype imports. We need to insert prototype_key in this case
|
||||
for key, protparent in kwargs.get("prototype_parents", {}).items():
|
||||
key = str(key).lower()
|
||||
protparent['prototype_key'] = str(protparent.get("prototype_key", key)).lower()
|
||||
protparent["prototype_key"] = str(protparent.get("prototype_key", key)).lower()
|
||||
protparents[key] = protparent
|
||||
|
||||
if "return_parents" in kwargs:
|
||||
|
|
@ -715,8 +759,9 @@ def spawn(*prototypes, **kwargs):
|
|||
for prototype in prototypes:
|
||||
|
||||
protlib.validate_prototype(prototype, None, protparents, is_prototype_base=True)
|
||||
prot = _get_prototype(prototype, protparents,
|
||||
uninherited={"prototype_key": prototype.get("prototype_key")})
|
||||
prot = _get_prototype(
|
||||
prototype, protparents, uninherited={"prototype_key": prototype.get("prototype_key")}
|
||||
)
|
||||
if not prot:
|
||||
continue
|
||||
|
||||
|
|
@ -725,8 +770,10 @@ def spawn(*prototypes, **kwargs):
|
|||
create_kwargs = {}
|
||||
# we must always add a key, so if not given we use a shortened md5 hash. There is a (small)
|
||||
# chance this is not unique but it should usually not be a problem.
|
||||
val = prot.pop("key", "Spawned-{}".format(
|
||||
hashlib.md5(bytes(str(time.time()), 'utf-8')).hexdigest()[:6]))
|
||||
val = prot.pop(
|
||||
"key",
|
||||
"Spawned-{}".format(hashlib.md5(bytes(str(time.time()), "utf-8")).hexdigest()[:6]),
|
||||
)
|
||||
create_kwargs["db_key"] = init_spawn_value(val, str)
|
||||
|
||||
val = prot.pop("location", None)
|
||||
|
|
@ -754,7 +801,7 @@ def spawn(*prototypes, **kwargs):
|
|||
for (tag, category, data) in val:
|
||||
tags.append((init_spawn_value(tag, str), category, data))
|
||||
|
||||
prototype_key = prototype.get('prototype_key', None)
|
||||
prototype_key = prototype.get("prototype_key", None)
|
||||
if prototype_key:
|
||||
# we make sure to add a tag identifying which prototype created this object
|
||||
tags.append((prototype_key, _PROTOTYPE_TAG_CATEGORY))
|
||||
|
|
@ -763,8 +810,11 @@ def spawn(*prototypes, **kwargs):
|
|||
execs = init_spawn_value(val, make_iter)
|
||||
|
||||
# extract ndb assignments
|
||||
nattributes = dict((key.split("_", 1)[1], init_spawn_value(val, value_to_obj))
|
||||
for key, val in prot.items() if key.startswith("ndb_"))
|
||||
nattributes = dict(
|
||||
(key.split("_", 1)[1], init_spawn_value(val, value_to_obj))
|
||||
for key, val in prot.items()
|
||||
if key.startswith("ndb_")
|
||||
)
|
||||
|
||||
# the rest are attribute tuples (attrname, value, category, locks)
|
||||
val = make_iter(prot.pop("attrs", []))
|
||||
|
|
@ -773,21 +823,33 @@ def spawn(*prototypes, **kwargs):
|
|||
attributes.append((attrname, init_spawn_value(value), category, locks))
|
||||
|
||||
simple_attributes = []
|
||||
for key, value in ((key, value) for key, value in prot.items()
|
||||
if not (key.startswith("ndb_"))):
|
||||
for key, value in (
|
||||
(key, value) for key, value in prot.items() if not (key.startswith("ndb_"))
|
||||
):
|
||||
# we don't support categories, nor locks for simple attributes
|
||||
if key in _PROTOTYPE_META_NAMES:
|
||||
continue
|
||||
else:
|
||||
simple_attributes.append(
|
||||
(key, init_spawn_value(value, value_to_obj_or_any), None, None))
|
||||
(key, init_spawn_value(value, value_to_obj_or_any), None, None)
|
||||
)
|
||||
|
||||
attributes = attributes + simple_attributes
|
||||
attributes = [tup for tup in attributes if not tup[0] in _NON_CREATE_KWARGS]
|
||||
|
||||
# pack for call into _batch_create_object
|
||||
objsparams.append((create_kwargs, permission_string, lock_string,
|
||||
alias_string, nattributes, attributes, tags, execs))
|
||||
objsparams.append(
|
||||
(
|
||||
create_kwargs,
|
||||
permission_string,
|
||||
lock_string,
|
||||
alias_string,
|
||||
nattributes,
|
||||
attributes,
|
||||
tags,
|
||||
execs,
|
||||
)
|
||||
)
|
||||
|
||||
if kwargs.get("only_validate"):
|
||||
return objsparams
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue