Continuing to make more methods _private to simplify API.

This commit is contained in:
Griatch 2012-03-31 16:09:48 +02:00
parent c8df141e89
commit d44dd92b5f
6 changed files with 277 additions and 268 deletions

View file

@ -16,10 +16,9 @@ together to create interesting in-game effects.
import copy
from src.utils.utils import inherits_from, is_iter
__all__ = ("CmdSet",)
RECURSIVE_PROTECTION = False
class CmdSetMeta(type):
class _CmdSetMeta(type):
"""
This metaclass makes some minor on-the-fly convenience fixes to
the cmdset class.
@ -37,55 +36,7 @@ class CmdSetMeta(type):
if not type(mcs.key_mergetypes) == dict:
mcs.key_mergetypes = {}
super(CmdSetMeta, mcs).__init__(*args, **kwargs)
# Some priority-sensitive merge operations for cmdsets
def union(cmdset_a, cmdset_b, duplicates=False):
"C = A U B. CmdSet A is assumed to have higher priority"
cmdset_c = cmdset_a.copy_this()
# we make copies, not refs by use of [:]
cmdset_c.commands = cmdset_a.commands[:]
if duplicates and cmdset_a.priority == cmdset_b.priority:
cmdset_c.commands.extend(cmdset_b.commands)
else:
cmdset_c.commands.extend([cmd for cmd in cmdset_b if not cmd in cmdset_a])
return cmdset_c
def intersect(cmdset_a, cmdset_b, duplicates=False):
"C = A (intersect) B. A is assumed higher priority"
cmdset_c = cmdset_a.copy_this()
if duplicates and cmdset_a.priority == cmdset_b.priority:
for cmd in [cmd for cmd in cmdset_a if cmd in cmdset_b]:
cmdset_c.add(cmd)
cmdset_c.add(cmdset_b.get(cmd))
else:
cmdset_c.commands = [cmd for cmd in cmdset_a if cmd in cmdset_b]
return cmdset_c
def replace(cmdset_a, cmdset_b, cmdset_c):
"C = A + B where the result is A."
cmdset_c = cmdset_a.copy_this()
cmdset_c.commands = cmdset_a.commands[:]
return cmdset_c
def remove(cmdset_a, cmdset_b, cmdset_c):
"C = A + B, where B is filtered by A"
cmdset_c = cmdset_a.copy_this()
cmdset_c.commands = [cmd for cmd in cmdset_b if not cmd in cmdset_a]
return cmdset_c
def instantiate(cmd):
"""
checks so that object is an instantiated command
and not, say a cmdclass. If it is, instantiate it.
Other types, like strings, are passed through.
"""
try:
return cmd()
except TypeError:
return cmd
super(_CmdSetMeta, mcs).__init__(*args, **kwargs)
class CmdSet(object):
"""
@ -166,7 +117,7 @@ class CmdSet(object):
"""
__metaclass__ = CmdSetMeta
__metaclass__ = _CmdSetMeta
key = "Unnamed CmdSet"
mergetype = "Union"
@ -177,6 +128,9 @@ class CmdSet(object):
no_objs = False
no_channels = False
permanent = False
# pre-store properties to duplicate straight off
to_duplicate = ("key", "cmdsetobj", "no_exits", "no_objs", "no_channels", "permanent",
"mergetype", "priority", "duplicates")
def __init__(self, cmdsetobj=None, key=None):
"""
@ -194,127 +148,63 @@ class CmdSet(object):
# initialize system
self.at_cmdset_creation()
def at_cmdset_creation(self):
"""
Hook method - this should be overloaded in the inheriting
class, and should take care of populating the cmdset
by use of self.add().
"""
pass
# Priority-sensitive merge operations for cmdsets
def add(self, cmd):
"""
Add a command, a list of commands or a cmdset to this cmdset.
Note that if cmd already exists in set,
it will replace the old one (no priority checking etc
at this point; this is often used to overload
default commands).
If cmd is another cmdset class or -instance, the commands
of that command set is added to this one, as if they were part
of the original cmdset definition. No merging or priority checks
are made, rather later added commands will simply replace
existing ones to make a unique set.
"""
if inherits_from(cmd, "src.commands.cmdset.CmdSet"):
# cmd is a command set so merge all commands in that set
# to this one. We raise a visible error if we created
# an infinite loop (adding cmdset to itself somehow)
try:
cmd = instantiate(cmd)
except RuntimeError, e:
string = "Adding cmdset %s to %s lead to an infinite loop. When adding a cmdset to another, "
string += "make sure they are not themself cyclically added to the new cmdset somewhere in the chain."
raise RuntimeError(string % (cmd, self.__class__))
cmds = cmd.commands
elif is_iter(cmd):
cmds = [instantiate(c) for c in cmd]
def _union(self, cmdset_a, cmdset_b, duplicates=False):
"C = A U B. CmdSet A is assumed to have higher priority"
cmdset_c = cmdset_a._duplicate()
# we make copies, not refs by use of [:]
cmdset_c.commands = cmdset_a.commands[:]
if duplicates and cmdset_a.priority == cmdset_b.priority:
cmdset_c.commands.extend(cmdset_b.commands)
else:
cmds = [instantiate(cmd)]
for cmd in cmds:
# add all commands
if not hasattr(cmd, 'obj'):
cmd.obj = self.cmdsetobj
try:
ic = self.commands.index(cmd)
self.commands[ic] = cmd # replace
except ValueError:
self.commands.append(cmd)
# extra run to make sure to avoid doublets
self.commands = list(set(self.commands))
#print "In cmdset.add(cmd):", self.key, cmd
cmdset_c.commands.extend([cmd for cmd in cmdset_b if not cmd in cmdset_a])
return cmdset_c
def remove(self, cmd):
"""
Remove a command instance from the cmdset.
cmd can be either a cmd instance or a key string.
"""
cmd = instantiate(cmd)
self.commands = [oldcmd for oldcmd in self.commands if oldcmd != cmd]
def _intersect(self, cmdset_a, cmdset_b, duplicates=False):
"C = A (intersect) B. A is assumed higher priority"
cmdset_c = cmdset_a._duplicate()
if duplicates and cmdset_a.priority == cmdset_b.priority:
for cmd in [cmd for cmd in cmdset_a if cmd in cmdset_b]:
cmdset_c.add(cmd)
cmdset_c.add(cmdset_b.get(cmd))
else:
cmdset_c.commands = [cmd for cmd in cmdset_a if cmd in cmdset_b]
return cmdset_c
def get(self, cmd):
"""
Return the command in this cmdset that matches the
given command. cmd may be either a command instance or
a key string.
"""
cmd = instantiate(cmd)
for thiscmd in self.commands:
if thiscmd == cmd:
return thiscmd
def _replace(self, cmdset_a, cmdset_b, cmdset_c):
"C = A + B where the result is A."
cmdset_c = cmdset_a._duplicate()
cmdset_c.commands = cmdset_a.commands[:]
return cmdset_c
def count(self):
"Return number of commands in set"
return len(self.commands)
def _remove(self, cmdset_a, cmdset_b, cmdset_c):
"C = A + B, where B is filtered by A"
cmdset_c = cmdset_a._duplicate()
cmdset_c.commands = [cmd for cmd in cmdset_b if not cmd in cmdset_a]
return cmdset_c
def get_system_cmds(self):
def _instantiate(self, cmd):
"""
Return system commands in the cmdset, defined as
commands starting with double underscore __.
These are excempt from merge operations.
checks so that object is an instantiated command
and not, say a cmdclass. If it is, instantiate it.
Other types, like strings, are passed through.
"""
return [cmd for cmd in self.commands if cmd.key.startswith('__')]
try:
return cmd()
except TypeError:
return cmd
def copy_this(self):
def _duplicate(self):
"""
Returns a new cmdset with the same settings as this one
(no commands are copied over)
(no actual commands are copied over)
"""
cmdset = CmdSet()
cmdset.key = self.key
cmdset.cmdsetobj = self.cmdsetobj
cmdset.no_exits = self.no_exits
cmdset.no_objs = self.no_objs
cmdset.no_channels = self.no_channels
cmdset.mergetype = self.mergetype
cmdset.priority = self.priority
cmdset.duplicates = self.duplicates
cmdset.__dict__.update(dict((key, val) for key, val in self.__dict__.items() if key in self.to_duplicate))
cmdset.key_mergetypes = self.key_mergetypes.copy() #copy.deepcopy(self.key_mergetypes)
return cmdset
def make_unique(self, caller):
"""
This is an unsafe command meant to clean out a cmdset of
doublet commands after it has been created. It is useful
for commands inheriting cmdsets from the cmdhandler where
obj-based cmdsets always are added double. Doublets will
be weeded out with preference to commands defined on caller,
otherwise just by first-come-first-served.
"""
unique = {}
for cmd in self.commands:
if cmd.key in unique:
ocmd = unique[cmd.key]
if (hasattr(cmd, 'obj') and cmd.obj == caller) and not \
(hasattr(ocmd, 'obj') and ocmd.obj == caller):
unique[cmd.key] = cmd
else:
unique[cmd.key] = cmd
self.commands = unique.values()
def __str__(self):
"""
Show all commands in cmdset when printing it.
@ -360,24 +250,24 @@ class CmdSet(object):
# A higher or equal priority than B
mergetype = self.key_mergetypes.get(cmdset_b.key, self.mergetype)
if mergetype == "Intersect":
cmdset_c = intersect(self, cmdset_b, cmdset_b.duplicates)
cmdset_c = self._intersect(self, cmdset_b, cmdset_b.duplicates)
elif mergetype == "Replace":
cmdset_c = replace(self, cmdset_b, cmdset_b.duplicates)
cmdset_c = self._replace(self, cmdset_b, cmdset_b.duplicates)
elif mergetype == "Remove":
cmdset_c = remove(self, cmdset_b, cmdset_b.duplicates)
cmdset_c = self._remove(self, cmdset_b, cmdset_b.duplicates)
else: # Union
cmdset_c = union(self, cmdset_b, cmdset_b.duplicates)
cmdset_c = self._union(self, cmdset_b, cmdset_b.duplicates)
else:
# B higher priority than A
mergetype = cmdset_b.key_mergetypes.get(self.key, cmdset_b.mergetype)
if mergetype == "Intersect":
cmdset_c = intersect(cmdset_b, self, self.duplicates)
cmdset_c = self._intersect(cmdset_b, self, self.duplicates)
elif mergetype == "Replace":
cmdset_c = replace(cmdset_b, self, self.duplicates)
cmdset_c = self._replace(cmdset_b, self, self.duplicates)
elif mergetype == "Remove":
cmdset_c = remove(self, cmdset_b, self.duplicates)
cmdset_c = self._remove(self, cmdset_b, self.duplicates)
else: # Union
cmdset_c = union(cmdset_b, self, self.duplicates)
cmdset_c = self._union(cmdset_b, self, self.duplicates)
# we store actual_mergetype since key_mergetypes
# might be different from the main mergetype.
@ -388,3 +278,107 @@ class CmdSet(object):
cmdset_c.add(sys_commands)
return cmdset_c
def add(self, cmd):
"""
Add a command, a list of commands or a cmdset to this cmdset.
Note that if cmd already exists in set,
it will replace the old one (no priority checking etc
at this point; this is often used to overload
default commands).
If cmd is another cmdset class or -instance, the commands
of that command set is added to this one, as if they were part
of the original cmdset definition. No merging or priority checks
are made, rather later added commands will simply replace
existing ones to make a unique set.
"""
if inherits_from(cmd, "src.commands.cmdset.CmdSet"):
# cmd is a command set so merge all commands in that set
# to this one. We raise a visible error if we created
# an infinite loop (adding cmdset to itself somehow)
try:
cmd = self._instantiate(cmd)
except RuntimeError, e:
string = "Adding cmdset %s to %s lead to an infinite loop. When adding a cmdset to another, "
string += "make sure they are not themself cyclically added to the new cmdset somewhere in the chain."
raise RuntimeError(string % (cmd, self.__class__))
cmds = cmd.commands
elif is_iter(cmd):
cmds = [self._instantiate(c) for c in cmd]
else:
cmds = [self._instantiate(cmd)]
for cmd in cmds:
# add all commands
if not hasattr(cmd, 'obj'):
cmd.obj = self.cmdsetobj
try:
ic = self.commands.index(cmd)
self.commands[ic] = cmd # replace
except ValueError:
self.commands.append(cmd)
# extra run to make sure to avoid doublets
self.commands = list(set(self.commands))
#print "In cmdset.add(cmd):", self.key, cmd
def remove(self, cmd):
"""
Remove a command instance from the cmdset.
cmd can be either a cmd instance or a key string.
"""
cmd = self._instantiate(cmd)
self.commands = [oldcmd for oldcmd in self.commands if oldcmd != cmd]
def get(self, cmd):
"""
Return the command in this cmdset that matches the
given command. cmd may be either a command instance or
a key string.
"""
cmd = self._instantiate(cmd)
for thiscmd in self.commands:
if thiscmd == cmd:
return thiscmd
def count(self):
"Return number of commands in set"
return len(self.commands)
def get_system_cmds(self):
"""
Return system commands in the cmdset, defined as
commands starting with double underscore __.
These are excempt from merge operations.
"""
return [cmd for cmd in self.commands if cmd.key.startswith('__')]
def make_unique(self, caller):
"""
This is an unsafe command meant to clean out a cmdset of
doublet commands after it has been created. It is useful
for commands inheriting cmdsets from the cmdhandler where
obj-based cmdsets always are added double. Doublets will
be weeded out with preference to commands defined on caller,
otherwise just by first-come-first-served.
"""
unique = {}
for cmd in self.commands:
if cmd.key in unique:
ocmd = unique[cmd.key]
if (hasattr(cmd, 'obj') and cmd.obj == caller) and not \
(hasattr(ocmd, 'obj') and ocmd.obj == caller):
unique[cmd.key] = cmd
else:
unique[cmd.key] = cmd
self.commands = unique.values()
def at_cmdset_creation(self):
"""
Hook method - this should be overloaded in the inheriting
class, and should take care of populating the cmdset
by use of self.add().
"""
pass