mirror of
https://github.com/evennia/evennia.git
synced 2026-03-22 15:56:30 +01:00
Converted a large part of utils/ folder to google code docstrings as per #709.
This commit is contained in:
parent
fc4beed9ca
commit
eb2bd8d44c
17 changed files with 1107 additions and 406 deletions
|
|
@ -472,10 +472,10 @@ def _create_player(session, playername, password, permissions, typeclass=None):
|
||||||
logger.log_trace()
|
logger.log_trace()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# This needs to be called so the engine knows this player is
|
# This needs to be set so the engine knows this player is
|
||||||
# logging in for the first time. (so it knows to call the right
|
# logging in for the first time. (so it knows to call the right
|
||||||
# hooks during login later)
|
# hooks during login later)
|
||||||
utils.init_new_player(new_player)
|
new_player.db.FIRST_LOGIN = True
|
||||||
|
|
||||||
# join the new player to the public channel
|
# join the new player to the public channel
|
||||||
pchannel = ChannelDB.objects.get_channel(settings.DEFAULT_CHANNELS[0]["key"])
|
pchannel = ChannelDB.objects.get_channel(settings.DEFAULT_CHANNELS[0]["key"])
|
||||||
|
|
|
||||||
|
|
@ -213,10 +213,10 @@ its and @/./+/-/_ only.") # this echoes the restrictions made by django's auth m
|
||||||
logger.log_trace()
|
logger.log_trace()
|
||||||
return
|
return
|
||||||
|
|
||||||
# This needs to be called so the engine knows this player is
|
# This needs to be set so the engine knows this player is
|
||||||
# logging in for the first time. (so it knows to call the right
|
# logging in for the first time. (so it knows to call the right
|
||||||
# hooks during login later)
|
# hooks during login later)
|
||||||
utils.init_new_player(new_player)
|
new_player.db.FIRST_LOGIN = True
|
||||||
|
|
||||||
# join the new player to the public channel
|
# join the new player to the public channel
|
||||||
pchanneldef = settings.CHANNEL_PUBLIC
|
pchanneldef = settings.CHANNEL_PUBLIC
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,13 @@ class ANSIParser(object):
|
||||||
"""
|
"""
|
||||||
Replacer used by `re.sub` to replace ANSI
|
Replacer used by `re.sub` to replace ANSI
|
||||||
markers with correct ANSI sequences
|
markers with correct ANSI sequences
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ansimatch (re.matchobject): The match.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
processed (str): The processed match string.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.ansi_map.get(ansimatch.group(), "")
|
return self.ansi_map.get(ansimatch.group(), "")
|
||||||
|
|
||||||
|
|
@ -87,6 +94,13 @@ class ANSIParser(object):
|
||||||
"""
|
"""
|
||||||
Replacer used by `re.sub` to replace ANSI
|
Replacer used by `re.sub` to replace ANSI
|
||||||
bright background markers with Xterm256 replacement
|
bright background markers with Xterm256 replacement
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ansimatch (re.matchobject): The match.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
processed (str): The processed match string.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.ansi_bright_bgs.get(ansimatch.group(), "")
|
return self.ansi_bright_bgs.get(ansimatch.group(), "")
|
||||||
|
|
||||||
|
|
@ -97,6 +111,14 @@ class ANSIParser(object):
|
||||||
|
|
||||||
It checks `self.do_xterm256` to determine if conversion
|
It checks `self.do_xterm256` to determine if conversion
|
||||||
to standard ANSI should be done or not.
|
to standard ANSI should be done or not.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
rgbmatch (re.matchobject): The match.
|
||||||
|
convert (bool, optional): Convert 256-colors to 16.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
processed (str): The processed match string.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not rgbmatch:
|
if not rgbmatch:
|
||||||
return ""
|
return ""
|
||||||
|
|
@ -177,21 +199,43 @@ class ANSIParser(object):
|
||||||
def strip_raw_codes(self, string):
|
def strip_raw_codes(self, string):
|
||||||
"""
|
"""
|
||||||
Strips raw ANSI codes from a string.
|
Strips raw ANSI codes from a string.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
string (str): The string to strip.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
string (str): The processed string.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.ansi_regex.sub("", string)
|
return self.ansi_regex.sub("", string)
|
||||||
|
|
||||||
def strip_mxp(self, string):
|
def strip_mxp(self, string):
|
||||||
"""
|
"""
|
||||||
Strips all MXP codes from a string.
|
Strips all MXP codes from a string.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
string (str): The string to strip.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
string (str): The processed string.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.mxp_sub.sub(r'\2', string)
|
return self.mxp_sub.sub(r'\2', string)
|
||||||
|
|
||||||
def parse_ansi(self, string, strip_ansi=False, xterm256=False, mxp=False):
|
def parse_ansi(self, string, strip_ansi=False, xterm256=False, mxp=False):
|
||||||
"""
|
"""
|
||||||
Parses a string, subbing color codes according to
|
Parses a string, subbing color codes according to the stored
|
||||||
the stored mapping.
|
mapping.
|
||||||
|
|
||||||
strip_ansi flag instead removes all ANSI markup.
|
Args:
|
||||||
|
string (str): The string to parse.
|
||||||
|
strip_ansi (boolean, optional): Strip all found ansi markup.
|
||||||
|
xterm256 (boolean, optional): If actually using xterm256 or if
|
||||||
|
these values should be converted to 16-color ANSI.
|
||||||
|
mxp (boolean, optional): Parse MXP commands in string.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
string (str): The parsed string.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if hasattr(string, '_raw_string'):
|
if hasattr(string, '_raw_string'):
|
||||||
|
|
@ -351,27 +395,57 @@ def parse_ansi(string, strip_ansi=False, parser=ANSI_PARSER, xterm256=False, mxp
|
||||||
"""
|
"""
|
||||||
Parses a string, subbing color codes as needed.
|
Parses a string, subbing color codes as needed.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
string (str): The string to parse.
|
||||||
|
strip_ansi (bool, optional): Strip all ANSI sequences.
|
||||||
|
parser (ansi.AnsiParser, optional): A parser instance to use.
|
||||||
|
xterm256 (bool, optional): Support xterm256 or not.
|
||||||
|
mxp (bool, optional): Support MXP markup or not.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
string (str): The parsed string.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return parser.parse_ansi(string, strip_ansi=strip_ansi, xterm256=xterm256, mxp=mxp)
|
return parser.parse_ansi(string, strip_ansi=strip_ansi, xterm256=xterm256, mxp=mxp)
|
||||||
|
|
||||||
|
|
||||||
def strip_ansi(string, parser=ANSI_PARSER):
|
def strip_ansi(string, parser=ANSI_PARSER):
|
||||||
"""
|
"""
|
||||||
Strip all ansi from the string.
|
Strip all ansi from the string. This handles the Evennia-specific
|
||||||
|
markup.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
parser (ansi.AnsiParser, optional): The parser to use.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
string (str): The stripped string.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return parser.parse_ansi(string, strip_ansi=True)
|
return parser.parse_ansi(string, strip_ansi=True)
|
||||||
|
|
||||||
def strip_raw_ansi(string, parser=ANSI_PARSER):
|
def strip_raw_ansi(string, parser=ANSI_PARSER):
|
||||||
"""
|
"""
|
||||||
Remove raw ansi codes from string
|
Remove raw ansi codes from string. This assumes pure
|
||||||
|
ANSI-bytecodes in the string.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
string (str): The string to parse.
|
||||||
|
parser (bool, optional): The parser to use.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
string (str): the stripped string.
|
||||||
"""
|
"""
|
||||||
return parser.strip_raw_codes(string)
|
return parser.strip_raw_codes(string)
|
||||||
|
|
||||||
|
|
||||||
def raw(string):
|
def raw(string):
|
||||||
"""
|
"""
|
||||||
Escapes a string into a form which won't be colorized by the ansi parser.
|
Escapes a string into a form which won't be colorized by the ansi
|
||||||
|
parser.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
string (str): The raw, escaped string.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return string.replace('{', '{{')
|
return string.replace('{', '{{')
|
||||||
|
|
||||||
|
|
@ -385,8 +459,9 @@ def group(lst, n):
|
||||||
|
|
||||||
def _spacing_preflight(func):
|
def _spacing_preflight(func):
|
||||||
"""
|
"""
|
||||||
This wrapper function is used to do some preflight checks on functions used
|
This wrapper function is used to do some preflight checks on
|
||||||
for padding ANSIStrings.
|
functions used for padding ANSIStrings.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def wrapped(self, width, fillchar=None):
|
def wrapped(self, width, fillchar=None):
|
||||||
if fillchar is None:
|
if fillchar is None:
|
||||||
|
|
@ -404,8 +479,9 @@ def _spacing_preflight(func):
|
||||||
|
|
||||||
def _query_super(func_name):
|
def _query_super(func_name):
|
||||||
"""
|
"""
|
||||||
Have the string class handle this with the cleaned string instead of
|
Have the string class handle this with the cleaned string instead
|
||||||
ANSIString.
|
of ANSIString.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def wrapped(self, *args, **kwargs):
|
def wrapped(self, *args, **kwargs):
|
||||||
return getattr(self.clean(), func_name)(*args, **kwargs)
|
return getattr(self.clean(), func_name)(*args, **kwargs)
|
||||||
|
|
@ -415,6 +491,7 @@ def _query_super(func_name):
|
||||||
def _on_raw(func_name):
|
def _on_raw(func_name):
|
||||||
"""
|
"""
|
||||||
Like query_super, but makes the operation run on the raw string.
|
Like query_super, but makes the operation run on the raw string.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def wrapped(self, *args, **kwargs):
|
def wrapped(self, *args, **kwargs):
|
||||||
args = list(args)
|
args = list(args)
|
||||||
|
|
@ -439,6 +516,7 @@ def _transform(func_name):
|
||||||
return a string the same length as the original. This function
|
return a string the same length as the original. This function
|
||||||
allows us to do the same, replacing all the non-coded characters
|
allows us to do the same, replacing all the non-coded characters
|
||||||
with the resulting string.
|
with the resulting string.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def wrapped(self, *args, **kwargs):
|
def wrapped(self, *args, **kwargs):
|
||||||
replacement_string = _query_super(func_name)(self, *args, **kwargs)
|
replacement_string = _query_super(func_name)(self, *args, **kwargs)
|
||||||
|
|
@ -461,6 +539,7 @@ class ANSIMeta(type):
|
||||||
"""
|
"""
|
||||||
Many functions on ANSIString are just light wrappers around the unicode
|
Many functions on ANSIString are just light wrappers around the unicode
|
||||||
base class. We apply them here, as part of the classes construction.
|
base class. We apply them here, as part of the classes construction.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def __init__(cls, *args, **kwargs):
|
def __init__(cls, *args, **kwargs):
|
||||||
for func_name in [
|
for func_name in [
|
||||||
|
|
@ -493,6 +572,7 @@ class ANSIString(unicode):
|
||||||
|
|
||||||
Please refer to the Metaclass, ANSIMeta, which is used to apply wrappers
|
Please refer to the Metaclass, ANSIMeta, which is used to apply wrappers
|
||||||
for several of the methods that need not be defined directly here.
|
for several of the methods that need not be defined directly here.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
__metaclass__ = ANSIMeta
|
__metaclass__ = ANSIMeta
|
||||||
|
|
||||||
|
|
@ -506,6 +586,7 @@ class ANSIString(unicode):
|
||||||
Internally, ANSIString can also passes itself precached code/character
|
Internally, ANSIString can also passes itself precached code/character
|
||||||
indexes and clean strings to avoid doing extra work when combining
|
indexes and clean strings to avoid doing extra work when combining
|
||||||
ANSIStrings.
|
ANSIStrings.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
string = args[0]
|
string = args[0]
|
||||||
if not isinstance(string, basestring):
|
if not isinstance(string, basestring):
|
||||||
|
|
@ -554,9 +635,11 @@ class ANSIString(unicode):
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
"""
|
"""
|
||||||
Unfortunately, this is not called during print() statements due to a
|
Unfortunately, this is not called during print() statements
|
||||||
bug in the Python interpreter. You can always do unicode() or str()
|
due to a bug in the Python interpreter. You can always do
|
||||||
around the resulting ANSIString and print that.
|
unicode() or str() around the resulting ANSIString and print
|
||||||
|
that.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self._raw_string
|
return self._raw_string
|
||||||
|
|
||||||
|
|
@ -564,6 +647,7 @@ class ANSIString(unicode):
|
||||||
"""
|
"""
|
||||||
Let's make the repr the command that would actually be used to
|
Let's make the repr the command that would actually be used to
|
||||||
construct this object, for convenience and reference.
|
construct this object, for convenience and reference.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return "ANSIString(%s, decoded=True)" % repr(self._raw_string)
|
return "ANSIString(%s, decoded=True)" % repr(self._raw_string)
|
||||||
|
|
||||||
|
|
@ -592,6 +676,7 @@ class ANSIString(unicode):
|
||||||
Finally, _code_indexes and _char_indexes are defined. These are lookup
|
Finally, _code_indexes and _char_indexes are defined. These are lookup
|
||||||
tables for which characters in the raw string are related to ANSI
|
tables for which characters in the raw string are related to ANSI
|
||||||
escapes, and which are for the readable text.
|
escapes, and which are for the readable text.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.parser = kwargs.pop('parser', ANSI_PARSER)
|
self.parser = kwargs.pop('parser', ANSI_PARSER)
|
||||||
super(ANSIString, self).__init__()
|
super(ANSIString, self).__init__()
|
||||||
|
|
@ -603,6 +688,7 @@ class ANSIString(unicode):
|
||||||
"""
|
"""
|
||||||
Takes a list of integers, and produces a new one incrementing all
|
Takes a list of integers, and produces a new one incrementing all
|
||||||
by a number.
|
by a number.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return [i + offset for i in iterable]
|
return [i + offset for i in iterable]
|
||||||
|
|
||||||
|
|
@ -610,6 +696,7 @@ class ANSIString(unicode):
|
||||||
def _adder(cls, first, second):
|
def _adder(cls, first, second):
|
||||||
"""
|
"""
|
||||||
Joins two ANSIStrings, preserving calculated info.
|
Joins two ANSIStrings, preserving calculated info.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
raw_string = first._raw_string + second._raw_string
|
raw_string = first._raw_string + second._raw_string
|
||||||
|
|
@ -629,6 +716,7 @@ class ANSIString(unicode):
|
||||||
We have to be careful when adding two strings not to reprocess things
|
We have to be careful when adding two strings not to reprocess things
|
||||||
that don't need to be reprocessed, lest we end up with escapes being
|
that don't need to be reprocessed, lest we end up with escapes being
|
||||||
interpreted literally.
|
interpreted literally.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not isinstance(other, basestring):
|
if not isinstance(other, basestring):
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
|
|
@ -639,6 +727,7 @@ class ANSIString(unicode):
|
||||||
def __radd__(self, other):
|
def __radd__(self, other):
|
||||||
"""
|
"""
|
||||||
Likewise, if we're on the other end.
|
Likewise, if we're on the other end.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not isinstance(other, basestring):
|
if not isinstance(other, basestring):
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
|
|
@ -650,6 +739,7 @@ class ANSIString(unicode):
|
||||||
"""
|
"""
|
||||||
This function is deprecated, so we just make it call the proper
|
This function is deprecated, so we just make it call the proper
|
||||||
function.
|
function.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.__getitem__(slice(i, j))
|
return self.__getitem__(slice(i, j))
|
||||||
|
|
||||||
|
|
@ -667,6 +757,7 @@ class ANSIString(unicode):
|
||||||
indexes that need slicing in the raw string. We can check between
|
indexes that need slicing in the raw string. We can check between
|
||||||
those indexes to figure out what escape characters need to be
|
those indexes to figure out what escape characters need to be
|
||||||
replayed.
|
replayed.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
slice_indexes = self._char_indexes[slc]
|
slice_indexes = self._char_indexes[slc]
|
||||||
# If it's the end of the string, we need to append final color codes.
|
# If it's the end of the string, we need to append final color codes.
|
||||||
|
|
@ -700,6 +791,7 @@ class ANSIString(unicode):
|
||||||
this is a regexable ANSIString, it will get the data from the raw
|
this is a regexable ANSIString, it will get the data from the raw
|
||||||
string instead, bypassing ANSIString's intelligent escape skipping,
|
string instead, bypassing ANSIString's intelligent escape skipping,
|
||||||
for reasons explained in the __new__ method's docstring.
|
for reasons explained in the __new__ method's docstring.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
# Slices must be handled specially.
|
# Slices must be handled specially.
|
||||||
|
|
@ -727,12 +819,14 @@ class ANSIString(unicode):
|
||||||
def clean(self):
|
def clean(self):
|
||||||
"""
|
"""
|
||||||
Return a unicode object without the ANSI escapes.
|
Return a unicode object without the ANSI escapes.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self._clean_string
|
return self._clean_string
|
||||||
|
|
||||||
def raw(self):
|
def raw(self):
|
||||||
"""
|
"""
|
||||||
Return a unicode object with the ANSI escapes.
|
Return a unicode object with the ANSI escapes.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self._raw_string
|
return self._raw_string
|
||||||
|
|
||||||
|
|
@ -746,6 +840,7 @@ class ANSIString(unicode):
|
||||||
|
|
||||||
We use the same techniques we used in split() to make sure each are
|
We use the same techniques we used in split() to make sure each are
|
||||||
colored.
|
colored.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if hasattr(sep, '_clean_string'):
|
if hasattr(sep, '_clean_string'):
|
||||||
sep = sep.clean()
|
sep = sep.clean()
|
||||||
|
|
@ -776,6 +871,7 @@ class ANSIString(unicode):
|
||||||
|
|
||||||
It's possible that only one of these tables is actually needed, the
|
It's possible that only one of these tables is actually needed, the
|
||||||
other assumed to be what isn't in the first.
|
other assumed to be what isn't in the first.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
code_indexes = []
|
code_indexes = []
|
||||||
|
|
@ -792,6 +888,7 @@ class ANSIString(unicode):
|
||||||
"""
|
"""
|
||||||
Get the code characters from the given slice end to the next
|
Get the code characters from the given slice end to the next
|
||||||
character.
|
character.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
index = self._char_indexes[index - 1]
|
index = self._char_indexes[index - 1]
|
||||||
|
|
@ -815,6 +912,7 @@ class ANSIString(unicode):
|
||||||
|
|
||||||
PyPy is distributed under the MIT licence.
|
PyPy is distributed under the MIT licence.
|
||||||
http://opensource.org/licenses/MIT
|
http://opensource.org/licenses/MIT
|
||||||
|
|
||||||
"""
|
"""
|
||||||
bylen = len(by)
|
bylen = len(by)
|
||||||
if bylen == 0:
|
if bylen == 0:
|
||||||
|
|
@ -837,6 +935,7 @@ class ANSIString(unicode):
|
||||||
def __mul__(self, other):
|
def __mul__(self, other):
|
||||||
"""
|
"""
|
||||||
Multiplication method. Implemented for performance reasons.
|
Multiplication method. Implemented for performance reasons.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not isinstance(other, int):
|
if not isinstance(other, int):
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
|
|
@ -863,6 +962,7 @@ class ANSIString(unicode):
|
||||||
|
|
||||||
PyPy is distributed under the MIT licence.
|
PyPy is distributed under the MIT licence.
|
||||||
http://opensource.org/licenses/MIT
|
http://opensource.org/licenses/MIT
|
||||||
|
|
||||||
"""
|
"""
|
||||||
res = []
|
res = []
|
||||||
end = len(self)
|
end = len(self)
|
||||||
|
|
@ -886,6 +986,7 @@ class ANSIString(unicode):
|
||||||
def join(self, iterable):
|
def join(self, iterable):
|
||||||
"""
|
"""
|
||||||
Joins together strings in an iterable.
|
Joins together strings in an iterable.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
result = ANSIString('')
|
result = ANSIString('')
|
||||||
last_item = None
|
last_item = None
|
||||||
|
|
@ -902,6 +1003,7 @@ class ANSIString(unicode):
|
||||||
"""
|
"""
|
||||||
Generate a line of characters in a more efficient way than just adding
|
Generate a line of characters in a more efficient way than just adding
|
||||||
ANSIStrings.
|
ANSIStrings.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not isinstance(char, ANSIString):
|
if not isinstance(char, ANSIString):
|
||||||
line = char * amount
|
line = char * amount
|
||||||
|
|
@ -929,6 +1031,7 @@ class ANSIString(unicode):
|
||||||
def center(self, width, fillchar, difference):
|
def center(self, width, fillchar, difference):
|
||||||
"""
|
"""
|
||||||
Center some text with some spaces padding both sides.
|
Center some text with some spaces padding both sides.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
remainder = difference % 2
|
remainder = difference % 2
|
||||||
difference /= 2
|
difference /= 2
|
||||||
|
|
@ -940,6 +1043,7 @@ class ANSIString(unicode):
|
||||||
def ljust(self, width, fillchar, difference):
|
def ljust(self, width, fillchar, difference):
|
||||||
"""
|
"""
|
||||||
Left justify some text.
|
Left justify some text.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self + self._filler(fillchar, difference)
|
return self + self._filler(fillchar, difference)
|
||||||
|
|
||||||
|
|
@ -947,5 +1051,6 @@ class ANSIString(unicode):
|
||||||
def rjust(self, width, fillchar, difference):
|
def rjust(self, width, fillchar, difference):
|
||||||
"""
|
"""
|
||||||
Right justify some text.
|
Right justify some text.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self._filler(fillchar, difference) + self
|
return self._filler(fillchar, difference) + self
|
||||||
|
|
|
||||||
|
|
@ -192,13 +192,23 @@ RE_CODE_SPLIT = re.compile(r"(^\#CODE.*?$|^\#HEADER)$", re.MULTILINE)
|
||||||
|
|
||||||
def read_batchfile(pythonpath, file_ending='.py'):
|
def read_batchfile(pythonpath, file_ending='.py'):
|
||||||
"""
|
"""
|
||||||
This reads the contents of a batch-file.
|
This reads the contents of a batch-file. Filename is considered
|
||||||
Filename is considered to be a python path to a batch file
|
to be a python path to a batch file relative the directory
|
||||||
relative the directory specified in `settings.py`.
|
specified in `settings.py`.
|
||||||
|
|
||||||
|
file_ending specify which batchfile ending should be assumed (.ev
|
||||||
|
or .py). The ending should not be included in the python path.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
pythonpath (str): A dot-python path to a file.
|
||||||
|
file_ending (str): The file ending of this file (.ev or .py)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
text (str): The text content of the batch file.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
IOError: If problems reading file.
|
||||||
|
|
||||||
file_ending specify which batchfile ending should be
|
|
||||||
assumed (.ev or .py). The ending should not be included
|
|
||||||
in the python path.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# open the file
|
# open the file
|
||||||
|
|
@ -293,6 +303,7 @@ def tb_filename(tb):
|
||||||
|
|
||||||
|
|
||||||
def tb_iter(tb):
|
def tb_iter(tb):
|
||||||
|
"Traceback iterator."
|
||||||
while tb is not None:
|
while tb is not None:
|
||||||
yield tb
|
yield tb
|
||||||
tb = tb.tb_next
|
tb = tb.tb_next
|
||||||
|
|
@ -309,13 +320,22 @@ class BatchCodeProcessor(object):
|
||||||
This parses the lines of a batchfile according to the following
|
This parses the lines of a batchfile according to the following
|
||||||
rules:
|
rules:
|
||||||
|
|
||||||
1) Lines starting with #HEADER starts a header block (ends other blocks)
|
Args:
|
||||||
2) Lines starting with #CODE begins a code block (ends other blocks)
|
pythonpath (str): The dot-python path to the file.
|
||||||
3) #CODE headers may be of the following form:
|
debug (bool, optional): Insert delete-commands for
|
||||||
#CODE (info) objname, objname2, ...
|
deleting created objects.
|
||||||
4) Lines starting with #INSERT are on form #INSERT filename.
|
|
||||||
5) All lines outside blocks are stripped.
|
Returns:
|
||||||
6) All excess whitespace beginning/ending a block is stripped.
|
codeblocks (list): A list of all #CODE blocks.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
1. Lines starting with #HEADER starts a header block (ends other blocks)
|
||||||
|
2. Lines starting with #CODE begins a code block (ends other blocks)
|
||||||
|
3. #CODE headers may be of the following form:
|
||||||
|
#CODE (info) objname, objname2, ...
|
||||||
|
4. Lines starting with #INSERT are on form #INSERT filename.
|
||||||
|
5. All lines outside blocks are stripped.
|
||||||
|
6. All excess whitespace beginning/ending a block is stripped.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -373,9 +393,17 @@ class BatchCodeProcessor(object):
|
||||||
|
|
||||||
def code_exec(self, code, extra_environ=None, debug=False):
|
def code_exec(self, code, extra_environ=None, debug=False):
|
||||||
"""
|
"""
|
||||||
Execute a single code block, including imports and appending global vars
|
Execute a single code block, including imports and appending
|
||||||
|
global vars.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
code (str): Code to run.
|
||||||
|
extra_environ (dict): Environment variables to run with code.
|
||||||
|
debug (bool, optional): Insert delete statements for objects.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
err (str or None): An error code or None (ok).
|
||||||
|
|
||||||
extra_environ - dict with environment variables
|
|
||||||
"""
|
"""
|
||||||
# define the execution environment
|
# define the execution environment
|
||||||
environdict = {"settings_module": settings}
|
environdict = {"settings_module": settings}
|
||||||
|
|
|
||||||
|
|
@ -59,24 +59,35 @@ def create_object(typeclass=None, key=None, location=None,
|
||||||
|
|
||||||
Create a new in-game object.
|
Create a new in-game object.
|
||||||
|
|
||||||
keywords:
|
Kwargs:
|
||||||
typeclass - class or python path to a typeclass
|
typeclass (class or str): Class or python path to a typeclass.
|
||||||
key - name of the new object. If not set, a name of #dbref will be set.
|
key (str): Name of the new object. If not set, a name of
|
||||||
home - obj or #dbref to use as the object's home location
|
#dbref will be set.
|
||||||
permissions - a comma-separated string of permissions
|
home (Object or str): Obj or #dbref to use as the object's
|
||||||
locks - one or more lockstrings, separated by semicolons
|
home location.
|
||||||
aliases - a list of alternative keys
|
permissions (str): A comma-separated string of permissions.
|
||||||
tags - a list of tag keys (using no category)
|
locks (str): one or more lockstrings, separated by semicolons.
|
||||||
destination - obj or #dbref to use as an Exit's target
|
aliases (list): A list of alternative keys.
|
||||||
|
tags (list): List of tag keys (using no category).
|
||||||
|
destination (Object or str): Obj or #dbref to use as an Exit's
|
||||||
|
target.
|
||||||
|
report_to (Object): The object to return error messages to.
|
||||||
|
nohome (bool): This allows the creation of objects without a
|
||||||
|
default home location; only used when creating the default
|
||||||
|
location itself or during unittests.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
object (Object): A newly created object of the given typeclass.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ObjectDB.DoesNotExist: If trying to create an Object with
|
||||||
|
`location` or `home` that can't be found.
|
||||||
|
|
||||||
nohome - this allows the creation of objects without a default home location;
|
|
||||||
only used when creating the default location itself or during unittests
|
|
||||||
"""
|
"""
|
||||||
global _ObjectDB
|
global _ObjectDB
|
||||||
if not _ObjectDB:
|
if not _ObjectDB:
|
||||||
from evennia.objects.models import ObjectDB as _ObjectDB
|
from evennia.objects.models import ObjectDB as _ObjectDB
|
||||||
|
|
||||||
|
|
||||||
typeclass = typeclass if typeclass else settings.BASE_OBJECT_TYPECLASS
|
typeclass = typeclass if typeclass else settings.BASE_OBJECT_TYPECLASS
|
||||||
|
|
||||||
if isinstance(typeclass, basestring):
|
if isinstance(typeclass, basestring):
|
||||||
|
|
@ -120,32 +131,42 @@ object = create_object
|
||||||
# Script creation
|
# Script creation
|
||||||
#
|
#
|
||||||
|
|
||||||
def create_script(typeclass, key=None, obj=None, player=None, locks=None,
|
def create_script(typeclass=None, key=None, obj=None, player=None, locks=None,
|
||||||
interval=None, start_delay=None, repeats=None,
|
interval=None, start_delay=None, repeats=None,
|
||||||
persistent=None, autostart=True, report_to=None):
|
persistent=None, autostart=True, report_to=None):
|
||||||
"""
|
"""
|
||||||
Create a new script. All scripts are a combination
|
Create a new script. All scripts are a combination of a database
|
||||||
of a database object that communicates with the
|
object that communicates with the database, and an typeclass that
|
||||||
database, and an typeclass that 'decorates' the
|
'decorates' the database object into being different types of
|
||||||
database object into being different types of scripts.
|
scripts. It's behaviour is similar to the game objects except
|
||||||
It's behaviour is similar to the game objects except
|
scripts has a time component and are more limited in scope.
|
||||||
scripts has a time component and are more limited in
|
|
||||||
scope.
|
Kwargs:
|
||||||
|
typeclass (class or str): Class or python path to a typeclass.
|
||||||
|
key (str): Name of the new object. If not set, a name of
|
||||||
|
#dbref will be set.
|
||||||
|
obj (Object): The entity on which this Script sits. If this
|
||||||
|
is `None`, we are creating a "global" script.
|
||||||
|
player (Player): The player on which this Script sits. It is
|
||||||
|
exclusiv to `obj`.
|
||||||
|
locks (str): one or more lockstrings, separated by semicolons.
|
||||||
|
interval (int): The triggering interval for this Script, in
|
||||||
|
seconds. If unset, the Script will not have a timing
|
||||||
|
component.
|
||||||
|
start_delay (bool): If `True`, will wait `interval` seconds
|
||||||
|
before triggering the first time.
|
||||||
|
repeats (int): The number of times to trigger before stopping.
|
||||||
|
If unset, will repeat indefinitely.
|
||||||
|
persistent (bool): If this Script survives a server shutdown
|
||||||
|
or not (all Scripts will survive a reload).
|
||||||
|
autostart (bool): If this Script will start immediately when
|
||||||
|
created or if the `start` method must be called explicitly.
|
||||||
|
report_to (Object): The object to return error messages to.
|
||||||
|
|
||||||
Argument 'typeclass' can be either an actual
|
|
||||||
typeclass object or a python path to such an object.
|
|
||||||
Only set key here if you want a unique name for this
|
|
||||||
particular script (set it in config to give
|
|
||||||
same key to all scripts of the same type). Set obj
|
|
||||||
to tie this script to a particular object.
|
|
||||||
|
|
||||||
See evennia.scripts.manager for methods to manipulate existing
|
See evennia.scripts.manager for methods to manipulate existing
|
||||||
scripts in the database.
|
scripts in the database.
|
||||||
|
|
||||||
report_to is an obtional object to receive error messages.
|
|
||||||
If report_to is not set, an Exception with the
|
|
||||||
error will be raised. If set, this method will
|
|
||||||
return None upon errors.
|
|
||||||
"""
|
"""
|
||||||
global _ScriptDB
|
global _ScriptDB
|
||||||
if not _ScriptDB:
|
if not _ScriptDB:
|
||||||
|
|
@ -194,10 +215,20 @@ script = create_script
|
||||||
def create_help_entry(key, entrytext, category="General", locks=None):
|
def create_help_entry(key, entrytext, category="General", locks=None):
|
||||||
"""
|
"""
|
||||||
Create a static help entry in the help database. Note that Command
|
Create a static help entry in the help database. Note that Command
|
||||||
help entries are dynamic and directly taken from the __doc__ entries
|
help entries are dynamic and directly taken from the __doc__
|
||||||
of the command. The database-stored help entries are intended for more
|
entries of the command. The database-stored help entries are
|
||||||
general help on the game, more extensive info, in-game setting information
|
intended for more general help on the game, more extensive info,
|
||||||
and so on.
|
in-game setting information and so on.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
key (str): The name of the help entry.
|
||||||
|
entrytext (str): The body of te help entry
|
||||||
|
category (str, optional): The help category of the entry.
|
||||||
|
locks (str, optional): A lockstring to restrict access.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
help (HelpEntry): A newly created help entry.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
global _HelpEntry
|
global _HelpEntry
|
||||||
if not _HelpEntry:
|
if not _HelpEntry:
|
||||||
|
|
@ -230,24 +261,28 @@ help_entry = create_help_entry
|
||||||
def create_message(senderobj, message, channels=None,
|
def create_message(senderobj, message, channels=None,
|
||||||
receivers=None, locks=None, header=None):
|
receivers=None, locks=None, header=None):
|
||||||
"""
|
"""
|
||||||
Create a new communication message. Msgs are used for all
|
Create a new communication Msg. Msgs represent a unit of
|
||||||
player-to-player communication, both between individual players
|
database-persistent communication between entites.
|
||||||
and over channels.
|
|
||||||
senderobj - the player sending the message. This must be the actual object.
|
Args:
|
||||||
message - text with the message. Eventual headers, titles etc
|
senderobj (Object or Player): The entity sending the Msg.
|
||||||
should all be included in this text string. Formatting
|
message (str): Text with the message. Eventual headers, titles
|
||||||
will be retained.
|
etc should all be included in this text string. Formatting
|
||||||
channels - a channel or a list of channels to send to. The channels
|
will be retained.
|
||||||
may be actual channel objects or their unique key strings.
|
channels (Channel, key or list): A channel or a list of channels to
|
||||||
receivers - a player to send to, or a list of them. May be Player objects
|
send to. The channels may be actual channel objects or their
|
||||||
or playernames.
|
unique key strings.
|
||||||
locks - lock definition string
|
receivers (Object, Player, str or list): A Player/Object to send
|
||||||
header - mime-type or other optional information for the message
|
to, or a list of them. May be Player objects or playernames.
|
||||||
|
locks (str): Lock definition string.
|
||||||
|
header (str): Mime-type or other optional information for the message
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
The Comm system is created very open-ended, so it's fully possible
|
||||||
|
to let a message both go to several channels and to several
|
||||||
|
receivers at the same time, it's up to the command definitions to
|
||||||
|
limit this as desired.
|
||||||
|
|
||||||
The Comm system is created very open-ended, so it's fully possible
|
|
||||||
to let a message both go to several channels and to several receivers
|
|
||||||
at the same time, it's up to the command definitions to limit this as
|
|
||||||
desired.
|
|
||||||
"""
|
"""
|
||||||
global _Msg
|
global _Msg
|
||||||
if not _Msg:
|
if not _Msg:
|
||||||
|
|
@ -275,16 +310,27 @@ def create_channel(key, aliases=None, desc=None,
|
||||||
locks=None, keep_log=True,
|
locks=None, keep_log=True,
|
||||||
typeclass=None):
|
typeclass=None):
|
||||||
"""
|
"""
|
||||||
Create A communication Channel. A Channel serves as a central
|
Create A communication Channel. A Channel serves as a central hub
|
||||||
hub for distributing Msgs to groups of people without
|
for distributing Msgs to groups of people without specifying the
|
||||||
specifying the receivers explicitly. Instead players may
|
receivers explicitly. Instead players may 'connect' to the channel
|
||||||
'connect' to the channel and follow the flow of messages. By
|
and follow the flow of messages. By default the channel allows
|
||||||
default the channel allows access to all old messages, but
|
access to all old messages, but this can be turned off with the
|
||||||
this can be turned off with the keep_log switch.
|
keep_log switch.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
key (str): This must be unique.
|
||||||
|
|
||||||
|
Kwargs:
|
||||||
|
aliases (list): List of alternative (likely shorter) keynames.
|
||||||
|
desc (str): A description of the channel, for use in listings.
|
||||||
|
locks (str): Lockstring.
|
||||||
|
keep_log (bool): Log channel throughput.
|
||||||
|
typeclass (str or class): The typeclass of the Channel (not
|
||||||
|
often used).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
channel (Channel): A newly created channel.
|
||||||
|
|
||||||
key - this must be unique.
|
|
||||||
aliases - list of alternative (likely shorter) keynames.
|
|
||||||
locks - lock string definitions
|
|
||||||
"""
|
"""
|
||||||
typeclass = typeclass if typeclass else settings.BASE_CHANNEL_TYPECLASS
|
typeclass = typeclass if typeclass else settings.BASE_CHANNEL_TYPECLASS
|
||||||
|
|
||||||
|
|
@ -322,23 +368,28 @@ def create_player(key, email, password,
|
||||||
"""
|
"""
|
||||||
This creates a new player.
|
This creates a new player.
|
||||||
|
|
||||||
key - the player's name. This should be unique.
|
Args:
|
||||||
email - email on valid addr@addr.domain form.
|
key (str): The player's name. This should be unique.
|
||||||
password - password in cleartext
|
email (str): Email on valid addr@addr.domain form. This is
|
||||||
is_superuser - wether or not this player is to be a superuser
|
technically required but if set to `None`, an email of
|
||||||
locks - lockstring
|
`dummy@dummy.com` will be used as a placeholder.
|
||||||
permission - list of permissions
|
password (str): Password in cleartext.
|
||||||
report_to - an object with a msg() method to report errors to. If
|
|
||||||
not given, errors will be logged.
|
|
||||||
|
|
||||||
Will return the Player-typeclass or None/raise Exception if the
|
Kwargs:
|
||||||
Typeclass given failed to load.
|
is_superuser (bool): Wether or not this player is to be a superuser
|
||||||
|
locks (str): Lockstring.
|
||||||
|
permission (list): List of permission strings.
|
||||||
|
report_to (Object): An object with a msg() method to report
|
||||||
|
errors to. If not given, errors will be logged.
|
||||||
|
|
||||||
Concerning is_superuser:
|
Raises:
|
||||||
Usually only the server admin should need to be superuser, all
|
ValueError: If `key` already exists in database.
|
||||||
other access levels can be handled with more fine-grained
|
|
||||||
permissions or groups. A superuser bypasses all lock checking
|
Notes:
|
||||||
operations and is thus not suitable for play-testing the game.
|
Usually only the server admin should need to be superuser, all
|
||||||
|
other access levels can be handled with more fine-grained
|
||||||
|
permissions or groups. A superuser bypasses all lock checking
|
||||||
|
operations and is thus not suitable for play-testing the game.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
global _PlayerDB
|
global _PlayerDB
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ try:
|
||||||
from cPickle import dumps, loads
|
from cPickle import dumps, loads
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from pickle import dumps, loads
|
from pickle import dumps, loads
|
||||||
from django.db import transaction
|
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from evennia.server.models import ServerConfig
|
from evennia.server.models import ServerConfig
|
||||||
|
|
@ -52,8 +51,14 @@ else:
|
||||||
|
|
||||||
def _TO_DATESTRING(obj):
|
def _TO_DATESTRING(obj):
|
||||||
"""
|
"""
|
||||||
this will only be called with valid database objects. Returns datestring
|
Creates datestring hash.
|
||||||
on correct form.
|
|
||||||
|
Args:
|
||||||
|
obj (Object): Database object.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
datestring (str): A datestring hash.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return _GA(obj, "db_date_created").strftime(_DATESTRING)
|
return _GA(obj, "db_date_created").strftime(_DATESTRING)
|
||||||
|
|
@ -209,8 +214,14 @@ class _SaverSet(_SaverMutable, MutableSet):
|
||||||
def pack_dbobj(item):
|
def pack_dbobj(item):
|
||||||
"""
|
"""
|
||||||
Check and convert django database objects to an internal representation.
|
Check and convert django database objects to an internal representation.
|
||||||
This either returns the original input item or a tuple
|
|
||||||
("__packed_dbobj__", key, creation_time, id)
|
Args:
|
||||||
|
item (any): A database entity to pack
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
packed (any or tuple): Either returns the original input item
|
||||||
|
or the packing tuple `("__packed_dbobj__", key, creation_time, id)`.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
_init_globals()
|
_init_globals()
|
||||||
obj = item
|
obj = item
|
||||||
|
|
@ -224,10 +235,18 @@ def pack_dbobj(item):
|
||||||
|
|
||||||
def unpack_dbobj(item):
|
def unpack_dbobj(item):
|
||||||
"""
|
"""
|
||||||
Check and convert internal representations back to Django database models.
|
Check and convert internal representations back to Django database
|
||||||
The fact that item is a packed dbobj should be checked before this call.
|
models.
|
||||||
This either returns the original input or converts the internal store back
|
|
||||||
to a database representation (its typeclass is returned if applicable).
|
Args:
|
||||||
|
item (packed_dbobj): The fact that item is a packed dbobj
|
||||||
|
should be checked before this call.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
unpacked (any): Either the original input or converts the
|
||||||
|
internal store back to a database representation (its
|
||||||
|
typeclass is returned if applicable).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
_init_globals()
|
_init_globals()
|
||||||
try:
|
try:
|
||||||
|
|
@ -244,11 +263,18 @@ def unpack_dbobj(item):
|
||||||
|
|
||||||
def to_pickle(data):
|
def to_pickle(data):
|
||||||
"""
|
"""
|
||||||
This prepares data on arbitrary form to be pickled. It handles any nested
|
This prepares data on arbitrary form to be pickled. It handles any
|
||||||
structure and returns data on a form that is safe to pickle (including
|
nested structure and returns data on a form that is safe to pickle
|
||||||
having converted any database models to their internal representation).
|
(including having converted any database models to their internal
|
||||||
We also convert any Saver*-type objects back to their normal
|
representation). We also convert any Saver*-type objects back to
|
||||||
representations, they are not pickle-safe.
|
their normal representations, they are not pickle-safe.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data (any): Data to pickle.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
data (any): Pickled data.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def process_item(item):
|
def process_item(item):
|
||||||
"Recursive processor and identification of data"
|
"Recursive processor and identification of data"
|
||||||
|
|
@ -281,13 +307,18 @@ def from_pickle(data, db_obj=None):
|
||||||
object was removed (or changed in-place) in the database, None will be
|
object was removed (or changed in-place) in the database, None will be
|
||||||
returned.
|
returned.
|
||||||
|
|
||||||
db_obj - this is the model instance (normally an Attribute) that
|
Args_
|
||||||
_Saver*-type iterables (_SaverList etc) will save to when they
|
data (any): Pickled data to unpickle.
|
||||||
update. It must have a 'value' property that saves assigned data
|
db_obj (Atribute, any): This is the model instance (normally
|
||||||
to the database. Skip if not serializing onto a given object.
|
an Attribute) that _Saver*-type iterables (_SaverList etc)
|
||||||
|
will save to when they update. It must have a 'value' property
|
||||||
|
that saves assigned data to the database. Skip if not
|
||||||
|
serializing onto a given object. If db_obj is given, this
|
||||||
|
function will convert lists, dicts and sets to their
|
||||||
|
_SaverList, _SaverDict and _SaverSet counterparts.
|
||||||
|
|
||||||
If db_obj is given, this function will convert lists, dicts and sets
|
Returns:
|
||||||
to their _SaverList, _SaverDict and _SaverSet counterparts.
|
data (any): Unpickled data.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def process_item(item):
|
def process_item(item):
|
||||||
|
|
|
||||||
|
|
@ -631,7 +631,9 @@ class EvEditor(object):
|
||||||
|
|
||||||
def get_buffer(self):
|
def get_buffer(self):
|
||||||
"""
|
"""
|
||||||
Return the current buffer
|
Return:
|
||||||
|
buffer (str): The current buffer.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self._buffer
|
return self._buffer
|
||||||
|
|
||||||
|
|
@ -639,6 +641,10 @@ class EvEditor(object):
|
||||||
"""
|
"""
|
||||||
This should be called when the buffer has been changed
|
This should be called when the buffer has been changed
|
||||||
somehow. It will handle unsaved flag and undo updating.
|
somehow. It will handle unsaved flag and undo updating.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
buf (str): The text to update the buffer with.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if is_iter(buf):
|
if is_iter(buf):
|
||||||
buf = "\n".join(buf)
|
buf = "\n".join(buf)
|
||||||
|
|
@ -651,6 +657,7 @@ class EvEditor(object):
|
||||||
def quit(self):
|
def quit(self):
|
||||||
"""
|
"""
|
||||||
Cleanly exit the editor.
|
Cleanly exit the editor.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
self._quitfunc(self._caller)
|
self._quitfunc(self._caller)
|
||||||
|
|
@ -663,6 +670,7 @@ class EvEditor(object):
|
||||||
"""
|
"""
|
||||||
Saves the content of the buffer. The 'quitting' argument is a bool
|
Saves the content of the buffer. The 'quitting' argument is a bool
|
||||||
indicating whether or not the editor intends to exit after saving.
|
indicating whether or not the editor intends to exit after saving.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if self._unsaved:
|
if self._unsaved:
|
||||||
try:
|
try:
|
||||||
|
|
@ -680,6 +688,12 @@ class EvEditor(object):
|
||||||
"""
|
"""
|
||||||
This updates the undo position.
|
This updates the undo position.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
step (int, optional): The amount of steps
|
||||||
|
to progress the undo position to. This
|
||||||
|
may be a negative value for undo and
|
||||||
|
a positive value for redo.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if step and step < 0:
|
if step and step < 0:
|
||||||
# undo
|
# undo
|
||||||
|
|
@ -706,8 +720,15 @@ class EvEditor(object):
|
||||||
"""
|
"""
|
||||||
This displays the line editor buffer, or selected parts of it.
|
This displays the line editor buffer, or selected parts of it.
|
||||||
|
|
||||||
If `buf` is set and is not the full buffer, `offset` should define
|
Args:
|
||||||
the starting line number, to get the linenum display right.
|
buf (str, optional): The buffer or part of buffer to display.
|
||||||
|
offset (int, optional): If `buf` is set and is not the full buffer,
|
||||||
|
`offset` should define the actual starting line number, to
|
||||||
|
get the linenum display right.
|
||||||
|
linenums (bool, optional): Show line numbers in buffer.
|
||||||
|
raw (bool, optional): Tell protocol to not parse
|
||||||
|
formatting information.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if buf == None:
|
if buf == None:
|
||||||
buf = self._buffer
|
buf = self._buffer
|
||||||
|
|
@ -733,6 +754,7 @@ class EvEditor(object):
|
||||||
def display_help(self):
|
def display_help(self):
|
||||||
"""
|
"""
|
||||||
Shows the help entry for the editor.
|
Shows the help entry for the editor.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
string = self._sep * _DEFAULT_WIDTH + _HELP_TEXT + self._sep * _DEFAULT_WIDTH
|
string = self._sep * _DEFAULT_WIDTH + _HELP_TEXT + self._sep * _DEFAULT_WIDTH
|
||||||
self._caller.msg(string)
|
self._caller.msg(string)
|
||||||
|
|
|
||||||
|
|
@ -168,17 +168,17 @@ class EvForm(object):
|
||||||
"""
|
"""
|
||||||
Initiate the form
|
Initiate the form
|
||||||
|
|
||||||
keywords:
|
Kwargs:
|
||||||
filename - path to template file
|
filename (str): Path to template file.
|
||||||
form - dictionary of {"CELLCHAR":char,
|
cells (dict): A dictionary mapping of {id:text}
|
||||||
"TABLECHAR":char,
|
tables (dict): A dictionary mapping of {id:EvTable}.
|
||||||
"FORM":templatestring}
|
form (dict): A dictionary of {"CELLCHAR":char,
|
||||||
|
"TABLECHAR":char,
|
||||||
|
"FORM":templatestring}
|
||||||
if this is given, filename is not read.
|
if this is given, filename is not read.
|
||||||
cells - a dictionary mapping of {id:text}
|
Notes:
|
||||||
tables - dictionary mapping of {id:EvTable}
|
Other kwargs are fed as options to the EvCells and EvTables
|
||||||
|
(see `evtable.EvCell` and `evtable.EvTable` for more info).
|
||||||
other kwargs are fed as options to the EvCells and EvTables
|
|
||||||
(see `evtable.EvCell` and `evtable.EvTable` for more info).
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
|
|
@ -204,8 +204,9 @@ class EvForm(object):
|
||||||
|
|
||||||
def _parse_rectangles(self, cellchar, tablechar, form, **kwargs):
|
def _parse_rectangles(self, cellchar, tablechar, form, **kwargs):
|
||||||
"""
|
"""
|
||||||
Parse a form for rectangular formfields identified by
|
Parse a form for rectangular formfields identified by formchar
|
||||||
formchar enclosing an identifier.
|
enclosing an identifier.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# update options given at creation with new input - this
|
# update options given at creation with new input - this
|
||||||
|
|
@ -337,6 +338,7 @@ class EvForm(object):
|
||||||
def _populate_form(self, raw_form, mapping):
|
def _populate_form(self, raw_form, mapping):
|
||||||
"""
|
"""
|
||||||
Insert cell contents into form at given locations
|
Insert cell contents into form at given locations
|
||||||
|
|
||||||
"""
|
"""
|
||||||
form = copy.copy(raw_form)
|
form = copy.copy(raw_form)
|
||||||
for key, (iy0, ix0, width, height, cell_or_table) in mapping.items():
|
for key, (iy0, ix0, width, height, cell_or_table) in mapping.items():
|
||||||
|
|
@ -352,11 +354,13 @@ class EvForm(object):
|
||||||
"""
|
"""
|
||||||
Add mapping for form.
|
Add mapping for form.
|
||||||
|
|
||||||
cells - a dictionary of {identifier:celltext}
|
Args:
|
||||||
tables - a dictionary of {identifier:table}
|
cells (dict): A dictionary of {identifier:celltext}
|
||||||
|
tables (dict): A dictionary of {identifier:table}
|
||||||
|
|
||||||
kwargs will be forwarded to tables/cells. See
|
Notes:
|
||||||
evtable.EvCell and evtable.EvTable for info.
|
kwargs will be forwarded to tables/cells. See
|
||||||
|
`evtable.EvCell` and `evtable.EvTable` for info.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# clean kwargs (these cannot be overridden)
|
# clean kwargs (these cannot be overridden)
|
||||||
|
|
@ -373,7 +377,15 @@ class EvForm(object):
|
||||||
|
|
||||||
def reload(self, filename=None, form=None, **kwargs):
|
def reload(self, filename=None, form=None, **kwargs):
|
||||||
"""
|
"""
|
||||||
Creates the form from a stored file name
|
Creates the form from a stored file name.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
filename (str): The file to read from.
|
||||||
|
form (dict): A mapping for the form.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
Kwargs are passed through to Cel creation.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# clean kwargs (these cannot be overridden)
|
# clean kwargs (these cannot be overridden)
|
||||||
kwargs.pop("enforce_size", None)
|
kwargs.pop("enforce_size", None)
|
||||||
|
|
|
||||||
|
|
@ -65,21 +65,52 @@ def _format(seconds, *divisors) :
|
||||||
# Access functions
|
# Access functions
|
||||||
|
|
||||||
def runtime(format=False):
|
def runtime(format=False):
|
||||||
"Get the total runtime of the server since first start (minus downtimes)"
|
"""
|
||||||
|
Get the total runtime of the server since first start (minus
|
||||||
|
downtimes)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
format (bool, optional): Format into a time representation.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
time (float or tuple): The runtime or the same time split up
|
||||||
|
into time units.
|
||||||
|
|
||||||
|
"""
|
||||||
runtime = SERVER_RUNTIME + (time() - SERVER_RUNTIME_LAST_UPDATED)
|
runtime = SERVER_RUNTIME + (time() - SERVER_RUNTIME_LAST_UPDATED)
|
||||||
if format:
|
if format:
|
||||||
return _format(runtime, 31536000, 2628000, 604800, 86400, 3600, 60)
|
return _format(runtime, 31536000, 2628000, 604800, 86400, 3600, 60)
|
||||||
return runtime
|
return runtime
|
||||||
|
|
||||||
def uptime(format=False):
|
def uptime(format=False):
|
||||||
"Get the current uptime of the server since last reload"
|
"""
|
||||||
|
Get the current uptime of the server since last reload
|
||||||
|
|
||||||
|
Args:
|
||||||
|
format (bool, optional): Format into time representation.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
time (float or tuple): The uptime or the same time split up
|
||||||
|
into time units.
|
||||||
|
|
||||||
|
"""
|
||||||
uptime = time() - SERVER_START_TIME
|
uptime = time() - SERVER_START_TIME
|
||||||
if format:
|
if format:
|
||||||
return _format(uptime, 31536000, 2628000, 604800, 86400, 3600, 60)
|
return _format(uptime, 31536000, 2628000, 604800, 86400, 3600, 60)
|
||||||
return uptime
|
return uptime
|
||||||
|
|
||||||
def gametime(format=False):
|
def gametime(format=False):
|
||||||
"Get the total gametime of the server since first start (minus downtimes)"
|
"""
|
||||||
|
Get the total gametime of the server since first start (minus downtimes)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
format (bool, optional): Format into time representation.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
time (float or tuple): The gametime or the same time split up
|
||||||
|
into time units.
|
||||||
|
|
||||||
|
"""
|
||||||
gametime = runtime() * TIMEFACTOR
|
gametime = runtime() * TIMEFACTOR
|
||||||
if format:
|
if format:
|
||||||
return _format(gametime, YEAR, MONTH, WEEK, DAY, HOUR, MIN)
|
return _format(gametime, YEAR, MONTH, WEEK, DAY, HOUR, MIN)
|
||||||
|
|
@ -94,9 +125,18 @@ def gametime_to_realtime(secs=0, mins=0, hrs=0, days=0,
|
||||||
in-game, you will be able to find the number of real-world seconds this
|
in-game, you will be able to find the number of real-world seconds this
|
||||||
corresponds to (hint: Interval events deal with real life seconds).
|
corresponds to (hint: Interval events deal with real life seconds).
|
||||||
|
|
||||||
|
Kwargs:
|
||||||
|
times (int): The various components of the time.
|
||||||
|
format (bool): Formatting the output.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
time (float or tuple): The realtime difference or the same
|
||||||
|
time split up into time units.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
gametime_to_realtime(days=2) -> number of seconds in real life from
|
gametime_to_realtime(days=2) -> number of seconds in real life from
|
||||||
now after which 2 in-game days will have passed.
|
now after which 2 in-game days will have passed.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
realtime = (secs + mins * MIN + hrs * HOUR + days * DAY + weeks * WEEK + \
|
realtime = (secs + mins * MIN + hrs * HOUR + days * DAY + weeks * WEEK + \
|
||||||
months * MONTH + yrs * YEAR) / TIMEFACTOR
|
months * MONTH + yrs * YEAR) / TIMEFACTOR
|
||||||
|
|
@ -109,12 +149,21 @@ def realtime_to_gametime(secs=0, mins=0, hrs=0, days=0,
|
||||||
weeks=0, months=0, yrs=0, format=False):
|
weeks=0, months=0, yrs=0, format=False):
|
||||||
"""
|
"""
|
||||||
This method calculates how much in-game time a real-world time
|
This method calculates how much in-game time a real-world time
|
||||||
interval would correspond to. This is usually a lot less interesting
|
interval would correspond to. This is usually a lot less
|
||||||
than the other way around.
|
interesting than the other way around.
|
||||||
|
|
||||||
|
Kwargs:
|
||||||
|
times (int): The various components of the time.
|
||||||
|
format (bool): Formatting the output.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
time (float or tuple): The gametime difference or the same
|
||||||
|
time split up into time units.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
realtime_to_gametime(days=2) -> number of game-world seconds
|
realtime_to_gametime(days=2) -> number of game-world seconds
|
||||||
corresponding to 2 real days.
|
corresponding to 2 real days.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
gametime = TIMEFACTOR * (secs + mins * 60 + hrs * 3600 + days * 86400 +
|
gametime = TIMEFACTOR * (secs + mins * 60 + hrs * 3600 + days * 86400 +
|
||||||
weeks * 604800 + months * 2628000 + yrs * 31536000)
|
weeks * 604800 + months * 2628000 + yrs * 31536000)
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,9 @@ class SharedMemoryManager(Manager):
|
||||||
# still use the singleton cache, but the active model isn't required
|
# still use the singleton cache, but the active model isn't required
|
||||||
# to be a SharedMemoryModel.
|
# to be a SharedMemoryModel.
|
||||||
def get(self, **kwargs):
|
def get(self, **kwargs):
|
||||||
|
"""
|
||||||
|
Data entity lookup.
|
||||||
|
"""
|
||||||
items = kwargs.keys()
|
items = kwargs.keys()
|
||||||
inst = None
|
inst = None
|
||||||
if len(items) == 1:
|
if len(items) == 1:
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ from django.db.models.signals import post_save
|
||||||
from django.db.models.base import Model, ModelBase
|
from django.db.models.base import Model, ModelBase
|
||||||
from django.db.models.signals import pre_delete, post_syncdb
|
from django.db.models.signals import pre_delete, post_syncdb
|
||||||
from evennia.utils import logger
|
from evennia.utils import logger
|
||||||
from evennia.utils.utils import dbref, get_evennia_pids, to_str,calledby
|
from evennia.utils.utils import dbref, get_evennia_pids, to_str
|
||||||
|
|
||||||
from manager import SharedMemoryManager
|
from manager import SharedMemoryManager
|
||||||
|
|
||||||
|
|
@ -53,6 +53,7 @@ class SharedMemoryModelBase(ModelBase):
|
||||||
or try to retrieve one from the class-wide cache by inferring the pk value from
|
or try to retrieve one from the class-wide cache by inferring the pk value from
|
||||||
`args` and `kwargs`. If instance caching is enabled for this class, the cache is
|
`args` and `kwargs`. If instance caching is enabled for this class, the cache is
|
||||||
populated whenever possible (ie when it is possible to infer the pk value).
|
populated whenever possible (ie when it is possible to infer the pk value).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def new_instance():
|
def new_instance():
|
||||||
return super(SharedMemoryModelBase, cls).__call__(*args, **kwargs)
|
return super(SharedMemoryModelBase, cls).__call__(*args, **kwargs)
|
||||||
|
|
@ -75,6 +76,7 @@ class SharedMemoryModelBase(ModelBase):
|
||||||
"""
|
"""
|
||||||
Prepare the cache, making sure that proxies of the same db base
|
Prepare the cache, making sure that proxies of the same db base
|
||||||
share the same cache.
|
share the same cache.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# the dbmodel is either the proxy base or ourselves
|
# the dbmodel is either the proxy base or ourselves
|
||||||
dbmodel = cls._meta.proxy_for_model if cls._meta.proxy else cls
|
dbmodel = cls._meta.proxy_for_model if cls._meta.proxy else cls
|
||||||
|
|
@ -89,15 +91,17 @@ class SharedMemoryModelBase(ModelBase):
|
||||||
"""
|
"""
|
||||||
Field shortcut creation:
|
Field shortcut creation:
|
||||||
|
|
||||||
Takes field names `db_*` and creates property wrappers named without the
|
Takes field names `db_*` and creates property wrappers named
|
||||||
`db_` prefix. So db_key -> key
|
without the `db_` prefix. So db_key -> key
|
||||||
|
|
||||||
This wrapper happens on the class level, so there is no overhead when creating objects.
|
This wrapper happens on the class level, so there is no
|
||||||
If a class already has a wrapper of the given name, the automatic creation is skipped.
|
overhead when creating objects. If a class already has a
|
||||||
|
wrapper of the given name, the automatic creation is skipped.
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
Remember to document this auto-wrapping in the class header, this could seem very
|
Remember to document this auto-wrapping in the class
|
||||||
much like magic to the user otherwise.
|
header, this could seem very much like magic to the user
|
||||||
|
otherwise.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
attrs["typename"] = cls.__name__
|
attrs["typename"] = cls.__name__
|
||||||
|
|
@ -218,8 +222,10 @@ class SharedMemoryModel(Model):
|
||||||
@classmethod
|
@classmethod
|
||||||
def _get_cache_key(cls, args, kwargs):
|
def _get_cache_key(cls, args, kwargs):
|
||||||
"""
|
"""
|
||||||
This method is used by the caching subsystem to infer the PK value from the constructor arguments.
|
This method is used by the caching subsystem to infer the PK
|
||||||
It is used to decide if an instance has to be built or is already in the cache.
|
value from the constructor arguments. It is used to decide if
|
||||||
|
an instance has to be built or is already in the cache.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
result = None
|
result = None
|
||||||
# Quick hack for my composites work for now.
|
# Quick hack for my composites work for now.
|
||||||
|
|
@ -248,9 +254,11 @@ class SharedMemoryModel(Model):
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_cached_instance(cls, id):
|
def get_cached_instance(cls, id):
|
||||||
"""
|
"""
|
||||||
Method to retrieve a cached instance by pk value. Returns None when not found
|
Method to retrieve a cached instance by pk value. Returns None
|
||||||
(which will always be the case when caching is disabled for this class). Please
|
when not found (which will always be the case when caching is
|
||||||
note that the lookup will be done even when instance caching is disabled.
|
disabled for this class). Please note that the lookup will be
|
||||||
|
done even when instance caching is disabled.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return cls.__dbclass__.__instance_cache__.get(id)
|
return cls.__dbclass__.__instance_cache__.get(id)
|
||||||
|
|
||||||
|
|
@ -261,9 +269,9 @@ class SharedMemoryModel(Model):
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
instance (Class instance): the instance to cache.
|
instance (Class instance): the instance to cache.
|
||||||
new (bool, optional): this is the first time this
|
new (bool, optional): this is the first time this instance is
|
||||||
instance is cached (i.e. this is not an update
|
cached (i.e. this is not an update operation like after a
|
||||||
operation like after a db save).
|
db save).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
pk = instance._get_pk_val()
|
pk = instance._get_pk_val()
|
||||||
|
|
@ -281,6 +289,7 @@ class SharedMemoryModel(Model):
|
||||||
def get_all_cached_instances(cls):
|
def get_all_cached_instances(cls):
|
||||||
"""
|
"""
|
||||||
Return the objects so far cached by idmapper for this class.
|
Return the objects so far cached by idmapper for this class.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return cls.__dbclass__.__instance_cache__.values()
|
return cls.__dbclass__.__instance_cache__.values()
|
||||||
|
|
||||||
|
|
@ -288,6 +297,7 @@ class SharedMemoryModel(Model):
|
||||||
def _flush_cached_by_key(cls, key, force=True):
|
def _flush_cached_by_key(cls, key, force=True):
|
||||||
"""
|
"""
|
||||||
Remove the cached reference.
|
Remove the cached reference.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
if force or not cls._idmapper_recache_protection:
|
if force or not cls._idmapper_recache_protection:
|
||||||
|
|
@ -312,6 +322,7 @@ class SharedMemoryModel(Model):
|
||||||
"""
|
"""
|
||||||
This will clean safe objects from the cache. Use `force`
|
This will clean safe objects from the cache. Use `force`
|
||||||
keyword to remove all objects, safe or not.
|
keyword to remove all objects, safe or not.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if force:
|
if force:
|
||||||
cls.__dbclass__.__instance_cache__ = {}
|
cls.__dbclass__.__instance_cache__ = {}
|
||||||
|
|
@ -326,6 +337,7 @@ class SharedMemoryModel(Model):
|
||||||
"""
|
"""
|
||||||
Flush this instance from the instance cache. Use
|
Flush this instance from the instance cache. Use
|
||||||
`force` to override recache_protection for the object.
|
`force` to override recache_protection for the object.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
pk = self._get_pk_val()
|
pk = self._get_pk_val()
|
||||||
if pk and (force or not self._idmapper_recache_protection):
|
if pk and (force or not self._idmapper_recache_protection):
|
||||||
|
|
@ -334,12 +346,14 @@ class SharedMemoryModel(Model):
|
||||||
def set_recache_protection(self, mode=True):
|
def set_recache_protection(self, mode=True):
|
||||||
"""
|
"""
|
||||||
Set if this instance should be allowed to be recached.
|
Set if this instance should be allowed to be recached.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._idmapper_recache_protection = bool(mode)
|
self._idmapper_recache_protection = bool(mode)
|
||||||
|
|
||||||
def delete(self, *args, **kwargs):
|
def delete(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Delete the object, clearing cache.
|
Delete the object, clearing cache.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.flush_from_cache()
|
self.flush_from_cache()
|
||||||
self._is_deleted = True
|
self._is_deleted = True
|
||||||
|
|
@ -349,12 +363,11 @@ class SharedMemoryModel(Model):
|
||||||
"""
|
"""
|
||||||
Central database save operation.
|
Central database save operation.
|
||||||
|
|
||||||
Arguments as per Django documentation
|
Notes:
|
||||||
|
Arguments as per Django documentation.
|
||||||
Calls:
|
Calls `self.at_<fieldname>_postsave(new)`
|
||||||
self.at_<fieldname>_postsave(new)
|
(this is a wrapper set by oobhandler:
|
||||||
# this is a wrapper set by oobhandler:
|
self._oob_at_<fieldname>_postsave())
|
||||||
self._oob_at_<fieldname>_postsave()
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -400,6 +413,7 @@ class SharedMemoryModel(Model):
|
||||||
class WeakSharedMemoryModelBase(SharedMemoryModelBase):
|
class WeakSharedMemoryModelBase(SharedMemoryModelBase):
|
||||||
"""
|
"""
|
||||||
Uses a WeakValue dictionary for caching instead of a regular one.
|
Uses a WeakValue dictionary for caching instead of a regular one.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def _prepare(cls):
|
def _prepare(cls):
|
||||||
super(WeakSharedMemoryModelBase, cls)._prepare()
|
super(WeakSharedMemoryModelBase, cls)._prepare()
|
||||||
|
|
@ -410,6 +424,7 @@ class WeakSharedMemoryModelBase(SharedMemoryModelBase):
|
||||||
class WeakSharedMemoryModel(SharedMemoryModel):
|
class WeakSharedMemoryModel(SharedMemoryModel):
|
||||||
"""
|
"""
|
||||||
Uses a WeakValue dictionary for caching instead of a regular one
|
Uses a WeakValue dictionary for caching instead of a regular one
|
||||||
|
|
||||||
"""
|
"""
|
||||||
__metaclass__ = WeakSharedMemoryModelBase
|
__metaclass__ = WeakSharedMemoryModelBase
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
@ -424,6 +439,7 @@ def flush_cache(**kwargs):
|
||||||
is `True`.
|
is `True`.
|
||||||
|
|
||||||
Uses a signal so we make sure to catch cascades.
|
Uses a signal so we make sure to catch cascades.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def class_hierarchy(clslist):
|
def class_hierarchy(clslist):
|
||||||
"""Recursively yield a class hierarchy"""
|
"""Recursively yield a class hierarchy"""
|
||||||
|
|
@ -448,6 +464,7 @@ post_syncdb.connect(flush_cache)
|
||||||
def flush_cached_instance(sender, instance, **kwargs):
|
def flush_cached_instance(sender, instance, **kwargs):
|
||||||
"""
|
"""
|
||||||
Flush the idmapper cache only for a given instance.
|
Flush the idmapper cache only for a given instance.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# XXX: Is this the best way to make sure we can flush?
|
# XXX: Is this the best way to make sure we can flush?
|
||||||
if not hasattr(instance, 'flush_cached_instance'):
|
if not hasattr(instance, 'flush_cached_instance'):
|
||||||
|
|
@ -459,6 +476,7 @@ pre_delete.connect(flush_cached_instance)
|
||||||
def update_cached_instance(sender, instance, **kwargs):
|
def update_cached_instance(sender, instance, **kwargs):
|
||||||
"""
|
"""
|
||||||
Re-cache the given instance in the idmapper cache.
|
Re-cache the given instance in the idmapper cache.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not hasattr(instance, 'cache_instance'):
|
if not hasattr(instance, 'cache_instance'):
|
||||||
return
|
return
|
||||||
|
|
@ -481,6 +499,7 @@ def conditional_flush(max_rmem, force=False):
|
||||||
cache is flushed.
|
cache is flushed.
|
||||||
force (bool, optional): forces a flush, regardless of timeout.
|
force (bool, optional): forces a flush, regardless of timeout.
|
||||||
Defaults to `False`.
|
Defaults to `False`.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
global LAST_FLUSH
|
global LAST_FLUSH
|
||||||
|
|
||||||
|
|
@ -546,6 +565,7 @@ def cache_size(mb=True):
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
total_num, {objclass:total_num, ...}
|
total_num, {objclass:total_num, ...}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
numtotal = [0] # use mutable to keep reference through recursion
|
numtotal = [0] # use mutable to keep reference through recursion
|
||||||
classdict = {}
|
classdict = {}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
"""
|
"""
|
||||||
Inlinefunc
|
Inlinefunc
|
||||||
|
|
||||||
This is a simple inline text language for use to custom-format text
|
This is a simple inline text language for use to custom-format text in
|
||||||
in Evennia. It is applied BEFORE ANSI/MUX parsing is applied.
|
Evennia. It is applied BEFORE ANSI/MUX parsing is applied.
|
||||||
|
|
||||||
To activate Inlinefunc, settings.INLINEFUNC_ENABLED must be set.
|
To activate Inlinefunc, settings.INLINEFUNC_ENABLED must be set.
|
||||||
|
|
||||||
|
|
@ -52,7 +52,10 @@ _DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
|
||||||
# inline functions
|
# inline functions
|
||||||
|
|
||||||
def pad(text, *args, **kwargs):
|
def pad(text, *args, **kwargs):
|
||||||
"Pad to width. pad(text, width=78, align='c', fillchar=' ')"
|
"""
|
||||||
|
Pad to width. pad(text, width=78, align='c', fillchar=' ')
|
||||||
|
|
||||||
|
"""
|
||||||
width = _DEFAULT_WIDTH
|
width = _DEFAULT_WIDTH
|
||||||
align = 'c'
|
align = 'c'
|
||||||
fillchar = ' '
|
fillchar = ' '
|
||||||
|
|
@ -67,8 +70,12 @@ def pad(text, *args, **kwargs):
|
||||||
break
|
break
|
||||||
return utils.pad(text, width=width, align=align, fillchar=fillchar)
|
return utils.pad(text, width=width, align=align, fillchar=fillchar)
|
||||||
|
|
||||||
|
|
||||||
def crop(text, *args, **kwargs):
|
def crop(text, *args, **kwargs):
|
||||||
"Crop to width. crop(text, width=78, suffix='[...]')"
|
"""
|
||||||
|
Crop to width. crop(text, width=78, suffix='[...]')
|
||||||
|
|
||||||
|
"""
|
||||||
width = _DEFAULT_WIDTH
|
width = _DEFAULT_WIDTH
|
||||||
suffix = "[...]"
|
suffix = "[...]"
|
||||||
for iarg, arg in enumerate(args):
|
for iarg, arg in enumerate(args):
|
||||||
|
|
@ -80,8 +87,12 @@ def crop(text, *args, **kwargs):
|
||||||
break
|
break
|
||||||
return utils.crop(text, width=width, suffix=suffix)
|
return utils.crop(text, width=width, suffix=suffix)
|
||||||
|
|
||||||
|
|
||||||
def wrap(text, *args, **kwargs):
|
def wrap(text, *args, **kwargs):
|
||||||
"Wrap/Fill text to width. fill(text, width=78, indent=0)"
|
"""
|
||||||
|
Wrap/Fill text to width. fill(text, width=78, indent=0)
|
||||||
|
|
||||||
|
"""
|
||||||
width = _DEFAULT_WIDTH
|
width = _DEFAULT_WIDTH
|
||||||
indent = 0
|
indent = 0
|
||||||
for iarg, arg in enumerate(args):
|
for iarg, arg in enumerate(args):
|
||||||
|
|
@ -91,16 +102,24 @@ def wrap(text, *args, **kwargs):
|
||||||
indent = int(arg) if arg.isdigit() else indent
|
indent = int(arg) if arg.isdigit() else indent
|
||||||
return utils.wrap(text, width=width, indent=indent)
|
return utils.wrap(text, width=width, indent=indent)
|
||||||
|
|
||||||
|
|
||||||
def time(text, *args, **kwargs):
|
def time(text, *args, **kwargs):
|
||||||
"Inserts current time"
|
"""
|
||||||
|
Inserts current time.
|
||||||
|
|
||||||
|
"""
|
||||||
import time
|
import time
|
||||||
strformat = "%h %d, %H:%M"
|
strformat = "%h %d, %H:%M"
|
||||||
if args and args[0]:
|
if args and args[0]:
|
||||||
strformat = str(args[0])
|
strformat = str(args[0])
|
||||||
return time.strftime(strformat)
|
return time.strftime(strformat)
|
||||||
|
|
||||||
|
|
||||||
def you(text, *args, **kwargs):
|
def you(text, *args, **kwargs):
|
||||||
"Inserts your name"
|
"""
|
||||||
|
Inserts your name.
|
||||||
|
|
||||||
|
"""
|
||||||
name = "You"
|
name = "You"
|
||||||
sess = kwargs.get("session")
|
sess = kwargs.get("session")
|
||||||
if sess and sess.puppet:
|
if sess and sess.puppet:
|
||||||
|
|
@ -139,23 +158,40 @@ def _execute_inline_function(funcname, text, session):
|
||||||
Get the enclosed text between {funcname(...) and {/funcname
|
Get the enclosed text between {funcname(...) and {/funcname
|
||||||
and execute the inline function to replace the whole block
|
and execute the inline function to replace the whole block
|
||||||
with the result.
|
with the result.
|
||||||
Note that this lookup is "dumb" - we just grab the first end
|
|
||||||
tag we find. So to work correctly this function must be called
|
Args:
|
||||||
"inside out" on a nested function tree, so each call only works
|
funcname (str): Inlinefunction identifier.
|
||||||
on a "flat" tag.
|
text (str): Text to process.
|
||||||
|
session (Session): Session object.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
This lookup is "dumb" - we just grab the first end tag we find. So
|
||||||
|
to work correctly this function must be called "inside out" on a
|
||||||
|
nested function tree, so each call only works on a "flat" tag.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def subfunc(match):
|
def subfunc(match):
|
||||||
"replace the entire block with the result of the function call"
|
"""
|
||||||
|
replace the entire block with the result of the function call
|
||||||
|
|
||||||
|
"""
|
||||||
args = [part.strip() for part in match.group(1).split(",")]
|
args = [part.strip() for part in match.group(1).split(",")]
|
||||||
intext = match.group(2)
|
intext = match.group(2)
|
||||||
kwargs = {"session":session}
|
kwargs = {"session":session}
|
||||||
return _INLINE_FUNCS[funcname][0](intext, *args, **kwargs)
|
return _INLINE_FUNCS[funcname][0](intext, *args, **kwargs)
|
||||||
return _INLINE_FUNCS[funcname][1].sub(subfunc, text)
|
return _INLINE_FUNCS[funcname][1].sub(subfunc, text)
|
||||||
|
|
||||||
|
|
||||||
def _execute_inline_single_function(funcname, text, session):
|
def _execute_inline_single_function(funcname, text, session):
|
||||||
"""
|
"""
|
||||||
Get the arguments of a single function call (no matching end tag)
|
Get the arguments of a single function call (no matching end tag)
|
||||||
and execute it with an empty text input.
|
and execute it with an empty text input.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
funcname (str): Function identifier.
|
||||||
|
text (str): String to process.
|
||||||
|
session (Session): Session id.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def subfunc(match):
|
def subfunc(match):
|
||||||
"replace the single call with the result of the function call"
|
"replace the single call with the result of the function call"
|
||||||
|
|
@ -164,12 +200,20 @@ def _execute_inline_single_function(funcname, text, session):
|
||||||
return _INLINE_FUNCS[funcname][0]("", *args, **kwargs)
|
return _INLINE_FUNCS[funcname][0]("", *args, **kwargs)
|
||||||
return _INLINE_FUNCS[funcname][2].sub(subfunc, text)
|
return _INLINE_FUNCS[funcname][2].sub(subfunc, text)
|
||||||
|
|
||||||
|
|
||||||
def parse_inlinefunc(text, strip=False, session=None):
|
def parse_inlinefunc(text, strip=False, session=None):
|
||||||
"""
|
"""
|
||||||
Parse inline function-replacement.
|
Parse inline function-replacement.
|
||||||
|
|
||||||
strip - remove all supported inlinefuncs from text
|
Args:
|
||||||
session - session calling for the parsing
|
text (str): Text to parse.
|
||||||
|
strip (bool, optional): Remove all supported inlinefuncs from text.
|
||||||
|
session (bool): Session calling for the parsing.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
text (str): Parsed text with processed results of
|
||||||
|
inlinefuncs.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if strip:
|
if strip:
|
||||||
|
|
@ -204,6 +248,7 @@ def parse_inlinefunc(text, strip=False, session=None):
|
||||||
|
|
||||||
return "".join(outstack)
|
return "".join(outstack)
|
||||||
|
|
||||||
|
|
||||||
def _test():
|
def _test():
|
||||||
# this should all be handled
|
# this should all be handled
|
||||||
s = "This is a text with a{pad(78,c,-)text {pad(5)of{/pad {pad(30)nice{/pad size{/pad inside {pad(4,l)it{/pad."
|
s = "This is a text with a{pad(78,c,-)text {pad(5)of{/pad {pad(30)nice{/pad size{/pad inside {pad(4,l)it{/pad."
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,13 @@ _TIMEZONE = None
|
||||||
|
|
||||||
def log_trace(errmsg=None):
|
def log_trace(errmsg=None):
|
||||||
"""
|
"""
|
||||||
Log a traceback to the log. This should be called
|
Log a traceback to the log. This should be called from within an
|
||||||
from within an exception. errmsg is optional and
|
exception.
|
||||||
adds an extra line with added info.
|
|
||||||
|
Args:
|
||||||
|
errmsg (str, optional): Adds an extra line with added info
|
||||||
|
at the end of the traceback in the log.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
tracestring = format_exc()
|
tracestring = format_exc()
|
||||||
try:
|
try:
|
||||||
|
|
@ -49,7 +53,9 @@ def log_err(errmsg):
|
||||||
"""
|
"""
|
||||||
Prints/logs an error message to the server log.
|
Prints/logs an error message to the server log.
|
||||||
|
|
||||||
errormsg: (string) The message to be logged.
|
Args:
|
||||||
|
errormsg (str): The message to be logged.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
errmsg = str(errmsg)
|
errmsg = str(errmsg)
|
||||||
|
|
@ -65,7 +71,9 @@ def log_warn(warnmsg):
|
||||||
"""
|
"""
|
||||||
Prints/logs any warnings that aren't critical but should be noted.
|
Prints/logs any warnings that aren't critical but should be noted.
|
||||||
|
|
||||||
warnmsg: (string) The message to be logged.
|
Args:
|
||||||
|
warnmsg (str): The message to be logged.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
warnmsg = str(warnmsg)
|
warnmsg = str(warnmsg)
|
||||||
|
|
@ -94,7 +102,10 @@ log_infomsg = log_info
|
||||||
|
|
||||||
def log_dep(depmsg):
|
def log_dep(depmsg):
|
||||||
"""
|
"""
|
||||||
Prints a deprecation message
|
Prints a deprecation message.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
depmsg (str): The deprecation message to log.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
depmsg = str(depmsg)
|
depmsg = str(depmsg)
|
||||||
|
|
@ -111,9 +122,13 @@ LOG_FILE_HANDLES = {} # holds open log handles
|
||||||
|
|
||||||
def log_file(msg, filename="game.log"):
|
def log_file(msg, filename="game.log"):
|
||||||
"""
|
"""
|
||||||
Arbitrary file logger using threads. Filename defaults to
|
Arbitrary file logger using threads.
|
||||||
'game.log'. All logs will appear in the logs directory and log
|
|
||||||
entries will start on new lines following datetime info.
|
Args:
|
||||||
|
filename (str, optional): Defaults to 'game.log'. All logs
|
||||||
|
will appear in the logs directory and log entries will start
|
||||||
|
on new lines following datetime info.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
global LOG_FILE_HANDLES, _LOGDIR, _TIMEZONE
|
global LOG_FILE_HANDLES, _LOGDIR, _TIMEZONE
|
||||||
|
|
||||||
|
|
@ -131,6 +146,7 @@ def log_file(msg, filename="game.log"):
|
||||||
# manually or log file won't be written to until the
|
# manually or log file won't be written to until the
|
||||||
# write buffer is full.
|
# write buffer is full.
|
||||||
filehandle.flush()
|
filehandle.flush()
|
||||||
|
|
||||||
def errback(failure):
|
def errback(failure):
|
||||||
"Catching errors to normal log"
|
"Catching errors to normal log"
|
||||||
log_trace()
|
log_trace()
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,10 @@ _handle_dbref = lambda inp: dbid_to_obj(inp, ObjectDB)
|
||||||
|
|
||||||
|
|
||||||
def _validate_prototype(key, prototype, protparents, visited):
|
def _validate_prototype(key, prototype, protparents, visited):
|
||||||
"Run validation on a prototype, checking for inifinite regress"
|
"""
|
||||||
|
Run validation on a prototype, checking for inifinite regress.
|
||||||
|
|
||||||
|
"""
|
||||||
assert isinstance(prototype, dict)
|
assert isinstance(prototype, dict)
|
||||||
if id(prototype) in visited:
|
if id(prototype) in visited:
|
||||||
raise RuntimeError("%s has infinite nesting of prototypes." % key or prototype)
|
raise RuntimeError("%s has infinite nesting of prototypes." % key or prototype)
|
||||||
|
|
@ -110,9 +113,10 @@ def _validate_prototype(key, prototype, protparents, visited):
|
||||||
|
|
||||||
def _get_prototype(dic, prot, protparents):
|
def _get_prototype(dic, prot, protparents):
|
||||||
"""
|
"""
|
||||||
Recursively traverse a prototype dictionary,
|
Recursively traverse a prototype dictionary, including multiple
|
||||||
including multiple inheritance. Use _validate_prototype
|
inheritance. Use _validate_prototype before this, we don't check
|
||||||
before this, we don't check for infinite recursion here.
|
for infinite recursion here.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if "prototype" in dic:
|
if "prototype" in dic:
|
||||||
# move backwards through the inheritance
|
# move backwards through the inheritance
|
||||||
|
|
@ -130,10 +134,11 @@ def _batch_create_object(*objparams):
|
||||||
optimized for speed. It does NOT check and convert various input
|
optimized for speed. It does NOT check and convert various input
|
||||||
so make sure the spawned Typeclass works before using this!
|
so make sure the spawned Typeclass works before using this!
|
||||||
|
|
||||||
Input:
|
Args:
|
||||||
objsparams - each argument should be a tuple of arguments for the respective
|
objsparams (any): Aach argument should be a tuple of arguments
|
||||||
creation/add handlers in the following order:
|
for the respective creation/add handlers in the following
|
||||||
(create, permissions, locks, aliases, nattributes, attributes)
|
order: (create, permissions, locks, aliases, nattributes,
|
||||||
|
attributes)
|
||||||
Returns:
|
Returns:
|
||||||
objects (list): A list of created objects
|
objects (list): A list of created objects
|
||||||
|
|
||||||
|
|
@ -168,16 +173,17 @@ def spawn(*prototypes, **kwargs):
|
||||||
Spawn a number of prototyped objects. Each argument should be a
|
Spawn a number of prototyped objects. Each argument should be a
|
||||||
prototype dictionary.
|
prototype dictionary.
|
||||||
|
|
||||||
keyword args:
|
Kwargs:
|
||||||
prototype_modules - a python-path to a
|
prototype_modules (str or list): A python-path to a prototype
|
||||||
prototype module, or a list of such paths. These will be used
|
module, or a list of such paths. These will be used to build
|
||||||
to build the global protparents dictionary accessible by the
|
the global protparents dictionary accessible by the input
|
||||||
input prototypes. If not given, it will instead look for modules
|
prototypes. If not given, it will instead look for modules
|
||||||
defined by settings.PROTOTYPE_MODULES.
|
defined by settings.PROTOTYPE_MODULES.
|
||||||
prototype_parents - a dictionary holding a custom prototype-parent dictionary. Will
|
prototype_parents (dict): A dictionary holding a custom
|
||||||
overload same-named prototypes from prototype_modules.
|
prototype-parent dictionary. Will overload same-named
|
||||||
return_prototypes - only return a list of the prototype-parents
|
prototypes from prototype_modules.
|
||||||
(no object creation happens)
|
return_prototypes (bool): Only return a list of the
|
||||||
|
prototype-parents (no object creation happens)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
protparents = {}
|
protparents = {}
|
||||||
|
|
|
||||||
|
|
@ -82,8 +82,16 @@ class TextToHTMLparser(object):
|
||||||
|
|
||||||
def re_color(self, text):
|
def re_color(self, text):
|
||||||
"""
|
"""
|
||||||
Replace ansi colors with html color class names.
|
Replace ansi colors with html color class names. Let the
|
||||||
Let the client choose how it will display colors, if it wishes to. """
|
client choose how it will display colors, if it wishes to.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text (str): the string with color to replace.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
text (str): Re-colored text.
|
||||||
|
|
||||||
|
"""
|
||||||
for colorname, regex in self.re_fgs:
|
for colorname, regex in self.re_fgs:
|
||||||
text = regex.sub(r'''<span class="%s">\1</span>''' % colorname, text)
|
text = regex.sub(r'''<span class="%s">\1</span>''' % colorname, text)
|
||||||
for bgname, regex in self.re_bgs:
|
for bgname, regex in self.re_bgs:
|
||||||
|
|
@ -91,19 +99,56 @@ class TextToHTMLparser(object):
|
||||||
return self.re_normal.sub("", text)
|
return self.re_normal.sub("", text)
|
||||||
|
|
||||||
def re_bold(self, text):
|
def re_bold(self, text):
|
||||||
"Clean out superfluous hilights rather than set <strong>to make it match the look of telnet."
|
"""
|
||||||
|
Clean out superfluous hilights rather than set <strong>to make
|
||||||
|
it match the look of telnet.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text (str): Text to process.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
text (str): Processed text.
|
||||||
|
|
||||||
|
"""
|
||||||
return self.re_hilite.sub(r'<strong>\1</strong>', text)
|
return self.re_hilite.sub(r'<strong>\1</strong>', text)
|
||||||
|
|
||||||
def re_underline(self, text):
|
def re_underline(self, text):
|
||||||
"Replace ansi underline with html underline class name."
|
"""
|
||||||
|
Replace ansi underline with html underline class name.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text (str): Text to process.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
text (str): Processed text.
|
||||||
|
|
||||||
|
"""
|
||||||
return self.re_uline.sub(r'<span class="underline">\1</span>', text)
|
return self.re_uline.sub(r'<span class="underline">\1</span>', text)
|
||||||
|
|
||||||
def remove_bells(self, text):
|
def remove_bells(self, text):
|
||||||
"Remove ansi specials"
|
"""
|
||||||
|
Remove ansi specials
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text (str): Text to process.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
text (str): Processed text.
|
||||||
|
|
||||||
|
"""
|
||||||
return text.replace('\07', '')
|
return text.replace('\07', '')
|
||||||
|
|
||||||
def remove_backspaces(self, text):
|
def remove_backspaces(self, text):
|
||||||
"Removes special escape sequences"
|
"""
|
||||||
|
Removes special escape sequences
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text (str): Text to process.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
text (str): Processed text.
|
||||||
|
|
||||||
|
"""
|
||||||
backspace_or_eol = r'(.\010)|(\033\[K)'
|
backspace_or_eol = r'(.\010)|(\033\[K)'
|
||||||
n = 1
|
n = 1
|
||||||
while n > 0:
|
while n > 0:
|
||||||
|
|
@ -111,11 +156,29 @@ class TextToHTMLparser(object):
|
||||||
return text
|
return text
|
||||||
|
|
||||||
def convert_linebreaks(self, text):
|
def convert_linebreaks(self, text):
|
||||||
"Extra method for cleaning linebreaks"
|
"""
|
||||||
|
Extra method for cleaning linebreaks
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text (str): Text to process.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
text (str): Processed text.
|
||||||
|
|
||||||
|
"""
|
||||||
return text.replace(r'\n', r'<br>')
|
return text.replace(r'\n', r'<br>')
|
||||||
|
|
||||||
def convert_urls(self, text):
|
def convert_urls(self, text):
|
||||||
"Replace urls (http://...) by valid HTML"
|
"""
|
||||||
|
Replace urls (http://...) by valid HTML.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text (str): Text to process.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
text (str): Processed text.
|
||||||
|
|
||||||
|
"""
|
||||||
regexp = r"((ftp|www|http)(\W+\S+[^).,:;?\]\}(\<span\>) \r\n$\"\']+))"
|
regexp = r"((ftp|www|http)(\W+\S+[^).,:;?\]\}(\<span\>) \r\n$\"\']+))"
|
||||||
# -> added target to output prevent the web browser from attempting to
|
# -> added target to output prevent the web browser from attempting to
|
||||||
# change pages (and losing our webclient session).
|
# change pages (and losing our webclient session).
|
||||||
|
|
@ -123,14 +186,31 @@ class TextToHTMLparser(object):
|
||||||
|
|
||||||
def convert_links(self, text):
|
def convert_links(self, text):
|
||||||
"""
|
"""
|
||||||
Replaces links with HTML code
|
Replaces links with HTML code.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text (str): Text to process.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
text (str): Processed text.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
html = "<a href='#' onclick='websocket.send(\"CMD\\1\"); return false;'>\\2</a>"
|
html = "<a href='#' onclick='websocket.send(\"CMD\\1\"); return false;'>\\2</a>"
|
||||||
repl = self.re_link.sub(html, text)
|
repl = self.re_link.sub(html, text)
|
||||||
return repl
|
return repl
|
||||||
|
|
||||||
def do_sub(self, m):
|
def do_sub(self, match):
|
||||||
"Helper method to be passed to re.sub."
|
"""
|
||||||
|
Helper method to be passed to re.sub,
|
||||||
|
for handling all substitutions.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
match (re.Matchobject): Match for substitution.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
text (str): Processed text.
|
||||||
|
|
||||||
|
"""
|
||||||
c = m.groupdict()
|
c = m.groupdict()
|
||||||
if c['htmlchars']:
|
if c['htmlchars']:
|
||||||
return cgi.escape(c['htmlchars'])
|
return cgi.escape(c['htmlchars'])
|
||||||
|
|
@ -145,8 +225,15 @@ class TextToHTMLparser(object):
|
||||||
|
|
||||||
def parse(self, text, strip_ansi=False):
|
def parse(self, text, strip_ansi=False):
|
||||||
"""
|
"""
|
||||||
Main access function, converts a text containing
|
Main access function, converts a text containing ANSI codes
|
||||||
ANSI codes into html statements.
|
into html statements.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text (str): Text to process.
|
||||||
|
strip_ansi (bool, optional):
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
text (str): Parsed text.
|
||||||
"""
|
"""
|
||||||
# parse everything to ansi first
|
# parse everything to ansi first
|
||||||
text = parse_ansi(text, strip_ansi=strip_ansi, xterm256=False, mxp=True)
|
text = parse_ansi(text, strip_ansi=strip_ansi, xterm256=False, mxp=True)
|
||||||
|
|
|
||||||
|
|
@ -228,7 +228,7 @@ def make_hybi07_frame_dwim(buf):
|
||||||
"""
|
"""
|
||||||
Make a HyBi-07 frame with binary or text data according to the type of buf.
|
Make a HyBi-07 frame with binary or text data according to the type of buf.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# TODO: eliminate magic numbers.
|
# TODO: eliminate magic numbers.
|
||||||
if isinstance(buf, str):
|
if isinstance(buf, str):
|
||||||
return make_hybi07_frame(buf, opcode=0x2)
|
return make_hybi07_frame(buf, opcode=0x2)
|
||||||
|
|
@ -349,7 +349,7 @@ class WebSocketProtocol(ProtocolWrapper):
|
||||||
def setBinaryMode(self, mode):
|
def setBinaryMode(self, mode):
|
||||||
"""
|
"""
|
||||||
If True, send str as binary and unicode as text.
|
If True, send str as binary and unicode as text.
|
||||||
|
|
||||||
Defaults to false for backwards compatibility.
|
Defaults to false for backwards compatibility.
|
||||||
"""
|
"""
|
||||||
self.do_binary_frames = bool(mode)
|
self.do_binary_frames = bool(mode)
|
||||||
|
|
|
||||||
|
|
@ -40,22 +40,34 @@ _DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
|
||||||
|
|
||||||
def is_iter(iterable):
|
def is_iter(iterable):
|
||||||
"""
|
"""
|
||||||
Checks if an object behaves iterably. However,
|
Checks if an object behaves iterably.
|
||||||
strings are not accepted as iterable (although
|
|
||||||
they are actually iterable), since string iterations
|
|
||||||
are usually not what we want to do with a string.
|
|
||||||
"""
|
|
||||||
# use a try..except here to avoid a property
|
|
||||||
# lookup when using this from a typeclassed entity
|
|
||||||
try:
|
|
||||||
_GA(iterable, '__iter__')
|
|
||||||
return True
|
|
||||||
except AttributeError:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
Args:
|
||||||
|
iterable (any): Entity to check for iterability.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
is_iterable (bool): If `iterable` is iterable or not.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
Strings are *not* accepted as iterable (although they are
|
||||||
|
actually iterable), since string iterations are usually not
|
||||||
|
what we want to do with a string.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return hasattr(iterable, '__iter__')
|
||||||
|
|
||||||
def make_iter(obj):
|
def make_iter(obj):
|
||||||
"Makes sure that the object is always iterable."
|
"""
|
||||||
|
Makes sure that the object is always iterable.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (any): Object to make iterable.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
iterable (list or iterable): The same object
|
||||||
|
passed-through or made iterable.
|
||||||
|
|
||||||
|
"""
|
||||||
return not hasattr(obj, '__iter__') and [obj] or obj
|
return not hasattr(obj, '__iter__') and [obj] or obj
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -63,10 +75,15 @@ def wrap(text, width=_DEFAULT_WIDTH, indent=0):
|
||||||
"""
|
"""
|
||||||
Safely wrap text to a certain number of characters.
|
Safely wrap text to a certain number of characters.
|
||||||
|
|
||||||
text: (str) The text to wrap.
|
Args:
|
||||||
width: (int) The number of characters to wrap to.
|
text (str): The text to wrap.
|
||||||
indent: (int) How much to indent new lines (the first line
|
width (int, optional): The number of characters to wrap to.
|
||||||
will not be indented)
|
indent (int): How much to indent new lines (the first line
|
||||||
|
will not be indented)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
text (str): Properly wrapped text.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not text:
|
if not text:
|
||||||
return ""
|
return ""
|
||||||
|
|
@ -76,10 +93,21 @@ def wrap(text, width=_DEFAULT_WIDTH, indent=0):
|
||||||
# alias - fill
|
# alias - fill
|
||||||
fill = wrap
|
fill = wrap
|
||||||
|
|
||||||
|
|
||||||
def pad(text, width=_DEFAULT_WIDTH, align="c", fillchar=" "):
|
def pad(text, width=_DEFAULT_WIDTH, align="c", fillchar=" "):
|
||||||
"""
|
"""
|
||||||
Pads to a given width, align is one of c,l,r
|
Pads to a given width.
|
||||||
and fillchar defaults to the space character.
|
|
||||||
|
Args:
|
||||||
|
text (str): Text to pad.
|
||||||
|
width (int, optional): The width to pad to, in characters.
|
||||||
|
align (str, optional): This is one of 'c', 'l' or 'r' (center,
|
||||||
|
left or right).
|
||||||
|
fillchar (str, optional): The character to fill with.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
text (str): The padded text.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
align = align if align in ('c', 'l', 'r') else 'c'
|
align = align if align in ('c', 'l', 'r') else 'c'
|
||||||
fillchar = fillchar[0] if fillchar else " "
|
fillchar = fillchar[0] if fillchar else " "
|
||||||
|
|
@ -90,12 +118,24 @@ def pad(text, width=_DEFAULT_WIDTH, align="c", fillchar=" "):
|
||||||
else:
|
else:
|
||||||
return text.center(width, fillchar)
|
return text.center(width, fillchar)
|
||||||
|
|
||||||
|
|
||||||
def crop(text, width=_DEFAULT_WIDTH, suffix="[...]"):
|
def crop(text, width=_DEFAULT_WIDTH, suffix="[...]"):
|
||||||
"""
|
"""
|
||||||
Crop text to a certain width, adding `suffix` to show that the line
|
Crop text to a certain width, throwing away text from too-long
|
||||||
continues. Cropping will be done so that the suffix will also fit
|
lines.
|
||||||
within the given width. If width is too small to fit both crop
|
|
||||||
and suffix, crop without the suffix.
|
Args:
|
||||||
|
text (str): Text to crop.
|
||||||
|
width (int, optional): Width of line to crop, in characters.
|
||||||
|
suffix (str, optional): This is appended to the end of cropped
|
||||||
|
lines to show that the line actually continues. Cropping
|
||||||
|
will be done so that the suffix will also fit within the
|
||||||
|
given width. If width is too small to fit both crop and
|
||||||
|
suffix, the suffix will be dropped.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
text (str): The cropped text.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
utext = to_unicode(text)
|
utext = to_unicode(text)
|
||||||
|
|
@ -110,11 +150,19 @@ def crop(text, width=_DEFAULT_WIDTH, suffix="[...]"):
|
||||||
|
|
||||||
def dedent(text):
|
def dedent(text):
|
||||||
"""
|
"""
|
||||||
Safely clean all whitespace at the left
|
Safely clean all whitespace at the left of a paragraph.
|
||||||
of a paragraph. This is useful for preserving
|
|
||||||
triple-quoted string indentation while still
|
Args:
|
||||||
shifting it all to be next to the left edge of
|
text (str): The text to dedent.
|
||||||
the display.
|
|
||||||
|
Returns:
|
||||||
|
text (str): Dedented string.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
This is useful for preserving triple-quoted string indentation
|
||||||
|
while still shifting it all to be next to the left edge of the
|
||||||
|
display.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not text:
|
if not text:
|
||||||
return ""
|
return ""
|
||||||
|
|
@ -123,19 +171,31 @@ def dedent(text):
|
||||||
|
|
||||||
def list_to_string(inlist, endsep="and", addquote=False):
|
def list_to_string(inlist, endsep="and", addquote=False):
|
||||||
"""
|
"""
|
||||||
This pretty-formats a list as string output, adding
|
This pretty-formats a list as string output, adding an optional
|
||||||
an optional alternative separator to the second to last entry.
|
alternative separator to the second to last entry. If `addquote`
|
||||||
If `addquote` is `True`, the outgoing strings will be surrounded by quotes.
|
is `True`, the outgoing strings will be surrounded by quotes.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
inlist (list): The list to print.
|
||||||
|
endsep (str, optional): If set, the last item separator will
|
||||||
|
be replaced with this value.
|
||||||
|
addquote (bool, optional): This will surround all outgoing
|
||||||
|
values with double quotes.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
liststr (str): The list represented as a string.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
```
|
|
||||||
no endsep:
|
```python
|
||||||
[1,2,3] -> '1, 2, 3'
|
# no endsep:
|
||||||
with endsep=='and':
|
[1,2,3] -> '1, 2, 3'
|
||||||
[1,2,3] -> '1, 2 and 3'
|
# with endsep=='and':
|
||||||
with addquote and endsep
|
[1,2,3] -> '1, 2 and 3'
|
||||||
[1,2,3] -> '"1", "2" and "3"'
|
# with addquote and endsep
|
||||||
```
|
[1,2,3] -> '"1", "2" and "3"'
|
||||||
|
```
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not endsep:
|
if not endsep:
|
||||||
endsep = ","
|
endsep = ","
|
||||||
|
|
@ -155,10 +215,17 @@ def list_to_string(inlist, endsep="and", addquote=False):
|
||||||
|
|
||||||
def wildcard_to_regexp(instring):
|
def wildcard_to_regexp(instring):
|
||||||
"""
|
"""
|
||||||
Converts a player-supplied string that may have wildcards in it to regular
|
Converts a player-supplied string that may have wildcards in it to
|
||||||
expressions. This is useful for name matching.
|
regular expressions. This is useful for name matching.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
instring (string): A string that may potentially contain
|
||||||
|
wildcards (`*` or `?`).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
regex (str): A string where wildcards were replaced with
|
||||||
|
regular expressions.
|
||||||
|
|
||||||
instring: (string) A string that may potentially contain wildcards (`*` or `?`).
|
|
||||||
"""
|
"""
|
||||||
regexp_string = ""
|
regexp_string = ""
|
||||||
|
|
||||||
|
|
@ -182,10 +249,13 @@ def time_format(seconds, style=0):
|
||||||
"""
|
"""
|
||||||
Function to return a 'prettified' version of a value in seconds.
|
Function to return a 'prettified' version of a value in seconds.
|
||||||
|
|
||||||
Style 0: 1d 08:30
|
Args:
|
||||||
Style 1: 1d
|
seconds (int): Number if seconds to format.
|
||||||
Style 2: 1 day, 8 hours, 30 minutes
|
style (int): One of the following styles:
|
||||||
Style 3: 1 day, 8 hours, 30 minutes, 10 seconds
|
0. "1d 08:30"
|
||||||
|
1. "1d"
|
||||||
|
2. "1 day, 8 hours, 30 minutes"
|
||||||
|
3. "1 day, 8 hours, 30 minutes, 10 seconds"
|
||||||
"""
|
"""
|
||||||
if seconds < 0:
|
if seconds < 0:
|
||||||
seconds = 0
|
seconds = 0
|
||||||
|
|
@ -208,8 +278,8 @@ def time_format(seconds, style=0):
|
||||||
retval = '%id %02i:%02i' % (days, hours, minutes,)
|
retval = '%id %02i:%02i' % (days, hours, minutes,)
|
||||||
else:
|
else:
|
||||||
retval = '%02i:%02i' % (hours, minutes,)
|
retval = '%02i:%02i' % (hours, minutes,)
|
||||||
|
|
||||||
return retval
|
return retval
|
||||||
|
|
||||||
elif style is 1:
|
elif style is 1:
|
||||||
"""
|
"""
|
||||||
Simple, abbreviated form that only shows the highest time amount.
|
Simple, abbreviated form that only shows the highest time amount.
|
||||||
|
|
@ -275,8 +345,15 @@ def time_format(seconds, style=0):
|
||||||
|
|
||||||
def datetime_format(dtobj):
|
def datetime_format(dtobj):
|
||||||
"""
|
"""
|
||||||
Takes a datetime object instance (e.g. from Django's `DateTimeField`)
|
Pretty-prints the time since a given time.
|
||||||
and returns a string describing how long ago that date was.
|
|
||||||
|
Args:
|
||||||
|
dtobj (datetime): An datetime object, e.g. from Django's
|
||||||
|
`DateTimeField`.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
deltatime (str): A string describing how long ago `dtobj`
|
||||||
|
took place.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -302,16 +379,26 @@ def datetime_format(dtobj):
|
||||||
def host_os_is(osname):
|
def host_os_is(osname):
|
||||||
"""
|
"""
|
||||||
Check to see if the host OS matches the query.
|
Check to see if the host OS matches the query.
|
||||||
Common osnames are
|
|
||||||
posix
|
Args:
|
||||||
nt
|
osname (str): Common names are "posix" (linux/unix/mac) and
|
||||||
|
"nt" (windows).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
is_os (bool): If the os matches or not.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if os.name == osname:
|
return os.name == osname
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def get_evennia_version():
|
def get_evennia_version():
|
||||||
|
"""
|
||||||
|
Helper method for getting the current evennia version.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
version (str): The version string.
|
||||||
|
|
||||||
|
"""
|
||||||
import evennia
|
import evennia
|
||||||
return evennia.__version__
|
return evennia.__version__
|
||||||
|
|
||||||
|
|
@ -345,11 +432,17 @@ def pypath_to_realpath(python_path, file_ending='.py'):
|
||||||
|
|
||||||
def dbref(dbref, reqhash=True):
|
def dbref(dbref, reqhash=True):
|
||||||
"""
|
"""
|
||||||
Converts/checks if input is a valid dbref. If `reqhash` is set,
|
Converts/checks if input is a valid dbref.
|
||||||
only input strings on the form '#N', where N is an integer is
|
|
||||||
accepted. Otherwise strings '#N', 'N' and integers N are all
|
Args:
|
||||||
accepted.
|
dbref (int or str): A datbase ref on the form N or #N.
|
||||||
Output is the integer part.
|
reqhash (bool, optional): Require the #N form to accept
|
||||||
|
input as a valid dbref.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dbref (int or None): The integer part of the dbref or `None`
|
||||||
|
if input was not a valid dbref.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if reqhash:
|
if reqhash:
|
||||||
num = (int(dbref.lstrip('#')) if (isinstance(dbref, basestring) and
|
num = (int(dbref.lstrip('#')) if (isinstance(dbref, basestring) and
|
||||||
|
|
@ -366,10 +459,22 @@ def dbref(dbref, reqhash=True):
|
||||||
|
|
||||||
def dbid_to_obj(inp, objclass, raise_errors=True):
|
def dbid_to_obj(inp, objclass, raise_errors=True):
|
||||||
"""
|
"""
|
||||||
Convert a #dbid to a valid object of `objclass`. `objclass`
|
Convert a #dbid to a valid object.
|
||||||
should be a valid object class to filter against (`objclass.filter` ...)
|
|
||||||
If not `raise_errors` is set, this will swallow errors of non-existing
|
Args:
|
||||||
objects.
|
inp (str or int): A valid dbref.
|
||||||
|
objclass (class): A valid django model to filter against.
|
||||||
|
raise_errors (bool, optional): Whether to raise errors
|
||||||
|
or return `None` on errors.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
obj (Object or None): An entity loaded from the dbref.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
Exception: If `raise_errors` is `True` and
|
||||||
|
`objclass.objects.get(id=dbref)` did not return a valid
|
||||||
|
object.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
dbid = dbref(inp)
|
dbid = dbref(inp)
|
||||||
if not dbid:
|
if not dbid:
|
||||||
|
|
@ -389,13 +494,28 @@ def dbid_to_obj(inp, objclass, raise_errors=True):
|
||||||
raise
|
raise
|
||||||
return inp
|
return inp
|
||||||
|
|
||||||
|
|
||||||
def to_unicode(obj, encoding='utf-8', force_string=False):
|
def to_unicode(obj, encoding='utf-8', force_string=False):
|
||||||
"""
|
"""
|
||||||
This decodes a suitable object to the unicode format. Note that
|
This decodes a suitable object to the unicode format.
|
||||||
one needs to encode it back to utf-8 before writing to disk or
|
|
||||||
printing. Note that non-string objects are let through without
|
Args:
|
||||||
conversion - this is important for e.g. Attributes. Use
|
obj (any): Object to decode to unicode.
|
||||||
`force_string` to enforce conversion of objects to string.
|
encoding (str, optional): The encoding type to use for the
|
||||||
|
dedoding.
|
||||||
|
force_string (bool, optional): Always convert to string, no
|
||||||
|
matter what type `obj` is initially.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
result (unicode or any): Will return a unicode object if input
|
||||||
|
was a string. If input was not a string, the original will be
|
||||||
|
returned unchanged unless `force_string` is also set.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
One needs to encode the obj back to utf-8 before writing to disk
|
||||||
|
or printing. That non-string objects are let through without
|
||||||
|
conversion is important for e.g. Attributes.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if force_string and not isinstance(obj, basestring):
|
if force_string and not isinstance(obj, basestring):
|
||||||
|
|
@ -427,10 +547,20 @@ def to_unicode(obj, encoding='utf-8', force_string=False):
|
||||||
def to_str(obj, encoding='utf-8', force_string=False):
|
def to_str(obj, encoding='utf-8', force_string=False):
|
||||||
"""
|
"""
|
||||||
This encodes a unicode string back to byte-representation,
|
This encodes a unicode string back to byte-representation,
|
||||||
for printing, writing to disk etc. Note that non-string
|
for printing, writing to disk etc.
|
||||||
objects are let through without modification - this is
|
|
||||||
required e.g. for Attributes. Use `force_string` to force
|
Args:
|
||||||
conversion of objects to strings.
|
obj (any): Object to encode to bytecode.
|
||||||
|
encoding (str, optional): The encoding type to use for the
|
||||||
|
encoding.
|
||||||
|
force_string (bool, optional): Always convert to string, no
|
||||||
|
matter what type `obj` is initially.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
Non-string objects are let through without modification - this
|
||||||
|
is required e.g. for Attributes. Use `force_string` to force
|
||||||
|
conversion of objects to strings.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if force_string and not isinstance(obj, basestring):
|
if force_string and not isinstance(obj, basestring):
|
||||||
|
|
@ -460,8 +590,16 @@ def validate_email_address(emailaddress):
|
||||||
"""
|
"""
|
||||||
Checks if an email address is syntactically correct.
|
Checks if an email address is syntactically correct.
|
||||||
|
|
||||||
(This snippet was adapted from
|
Args:
|
||||||
http://commandline.org.uk/python/email-syntax-check.)
|
emailaddress (str): Email address to validate.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
is_valid (bool): If this is a valid email or not.
|
||||||
|
|
||||||
|
Notes.
|
||||||
|
(This snippet was adapted from
|
||||||
|
http://commandline.org.uk/python/email-syntax-check.)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
emailaddress = r"%s" % emailaddress
|
emailaddress = r"%s" % emailaddress
|
||||||
|
|
@ -498,11 +636,23 @@ def validate_email_address(emailaddress):
|
||||||
|
|
||||||
def inherits_from(obj, parent):
|
def inherits_from(obj, parent):
|
||||||
"""
|
"""
|
||||||
Takes an object and tries to determine if it inherits at any distance
|
Takes an object and tries to determine if it inherits at *any*
|
||||||
from parent. What differs this function from e.g. `isinstance()`
|
distance from parent.
|
||||||
is that `obj` may be both an instance and a class, and parent
|
|
||||||
may be an instance, a class, or the python path to a class (counting
|
Args:
|
||||||
from the evennia root directory).
|
obj (any): Object to analyze. This may be either an instance
|
||||||
|
or a class.
|
||||||
|
parent (any): Can be either instance, class or python path to class.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
inherits_from (bool): If `parent` is a parent to `obj` or not.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
What differs this function from e.g. `isinstance()` is that `obj`
|
||||||
|
may be both an instance and a class, and parent may be an
|
||||||
|
instance, a class, or the python path to a class (counting from
|
||||||
|
the evennia root directory).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if callable(obj):
|
if callable(obj):
|
||||||
|
|
@ -524,9 +674,13 @@ def inherits_from(obj, parent):
|
||||||
|
|
||||||
def server_services():
|
def server_services():
|
||||||
"""
|
"""
|
||||||
Lists all services active on the Server. Observe that
|
Lists all services active on the Server. Observe that since
|
||||||
since services are launched in memory, this function will
|
services are launched in memory, this function will only return
|
||||||
only return any results if called from inside the game.
|
any results if called from inside the game.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
services (dict): A dict of available services.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from evennia.server.sessionhandler import SESSIONS
|
from evennia.server.sessionhandler import SESSIONS
|
||||||
if hasattr(SESSIONS, "server") and hasattr(SESSIONS.server, "services"):
|
if hasattr(SESSIONS, "server") and hasattr(SESSIONS.server, "services"):
|
||||||
|
|
@ -543,7 +697,13 @@ def uses_database(name="sqlite3"):
|
||||||
Checks if the game is currently using a given database. This is a
|
Checks if the game is currently using a given database. This is a
|
||||||
shortcut to having to use the full backend name.
|
shortcut to having to use the full backend name.
|
||||||
|
|
||||||
name - one of 'sqlite3', 'mysql', 'postgresql_psycopg2' or 'oracle'
|
Args:
|
||||||
|
name (str): One of 'sqlite3', 'mysql', 'postgresql_psycopg2'
|
||||||
|
or 'oracle'.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
uses (bool): If the given database is used or not.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
engine = settings.DATABASES["default"]["ENGINE"]
|
engine = settings.DATABASES["default"]["ENGINE"]
|
||||||
|
|
@ -555,17 +715,21 @@ def uses_database(name="sqlite3"):
|
||||||
def delay(delay=2, callback=None, retval=None):
|
def delay(delay=2, callback=None, retval=None):
|
||||||
"""
|
"""
|
||||||
Delay the return of a value.
|
Delay the return of a value.
|
||||||
Inputs:
|
|
||||||
delay (int) - the delay in seconds
|
Args:
|
||||||
callback (func() or func(retval)) - if given, will be called without
|
delay (int): The delay in seconds
|
||||||
arguments or with `retval` after delay seconds.
|
callback (callable, optional): Will be called without arguments
|
||||||
retval (any) - this will be returned by this function after a delay,
|
or with `retval` after delay seconds.
|
||||||
or as input to callback.
|
retval (any, optional): Whis will be returned by this function
|
||||||
|
after a delay, or as input to callback.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
deferred that will fire with callback after `delay` seconds. Note that
|
deferred (deferred): Will fire fire with callback after
|
||||||
if `delay()` is used in the commandhandler callback chain, the callback
|
`delay` seconds. Note that if `delay()` is used in the
|
||||||
chain can be defined directly in the command body and don't need to be
|
commandhandler callback chain, the callback chain can be
|
||||||
specified here.
|
defined directly in the command body and don't need to be
|
||||||
|
specified here.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
callb = callback or defer.Deferred().callback
|
callb = callback or defer.Deferred().callback
|
||||||
if retval is not None:
|
if retval is not None:
|
||||||
|
|
@ -579,14 +743,18 @@ _OBJECTMODELS = None
|
||||||
def clean_object_caches(obj):
|
def clean_object_caches(obj):
|
||||||
"""
|
"""
|
||||||
Clean all object caches on the given object.
|
Clean all object caches on the given object.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (Object instace): An object whose caches to clean.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
This is only the contents cache these days.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
global _TYPECLASSMODELS, _OBJECTMODELS
|
global _TYPECLASSMODELS, _OBJECTMODELS
|
||||||
if not _TYPECLASSMODELS:
|
if not _TYPECLASSMODELS:
|
||||||
from evennia.typeclasses import models as _TYPECLASSMODELS
|
from evennia.typeclasses import models as _TYPECLASSMODELS
|
||||||
#if not _OBJECTMODELS:
|
|
||||||
# from evennia.objects import models as _OBJECTMODELS
|
|
||||||
|
|
||||||
#print "recaching:", obj
|
|
||||||
if not obj:
|
if not obj:
|
||||||
return
|
return
|
||||||
# contents cache
|
# contents cache
|
||||||
|
|
@ -612,45 +780,39 @@ def run_async(to_execute, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Runs a function or executes a code snippet asynchronously.
|
Runs a function or executes a code snippet asynchronously.
|
||||||
|
|
||||||
Inputs:
|
Args:
|
||||||
to_execute (callable) - if this is a callable, it will
|
to_execute (callable): If this is a callable, it will be
|
||||||
be executed with *args and non-reserved *kwargs as
|
executed with *args and non-reserved *kwargs as arguments.
|
||||||
arguments.
|
The callable will be executed using ProcPool, or in a thread
|
||||||
The callable will be executed using ProcPool, or in
|
if ProcPool is not available.
|
||||||
a thread if ProcPool is not available.
|
|
||||||
|
|
||||||
reserved kwargs:
|
Kwargs:
|
||||||
'at_return' -should point to a callable with one argument.
|
at_return (callable): Should point to a callable with one
|
||||||
It will be called with the return value from
|
argument. It will be called with the return value from
|
||||||
to_execute.
|
to_execute.
|
||||||
'at_return_kwargs' - this dictionary which be used as keyword
|
at_return_kwargs (dict): This dictionary will be used as
|
||||||
arguments to the at_return callback.
|
keyword arguments to the at_return callback.
|
||||||
'at_err' - this will be called with a Failure instance if
|
at_err (callable): This will be called with a Failure instance
|
||||||
there is an error in to_execute.
|
if there is an error in to_execute.
|
||||||
'at_err_kwargs' - this dictionary will be used as keyword
|
at_err_kwargs (dict): This dictionary will be used as keyword
|
||||||
arguments to the at_err errback.
|
arguments to the at_err errback.
|
||||||
|
|
||||||
*args - these args will be used
|
Notes:
|
||||||
as arguments for that function. If to_execute is a string
|
All other `*args` and `**kwargs` will be passed on to
|
||||||
*args are not used.
|
`to_execute`. Run_async will relay executed code to a thread
|
||||||
*kwargs - these kwargs will be used
|
or procpool.
|
||||||
as keyword arguments in that function. If a string, they
|
|
||||||
instead are used to define the executable environment
|
|
||||||
that should be available to execute the code in to_execute.
|
|
||||||
|
|
||||||
run_async will relay executed code to a thread or procpool.
|
Use this function with restrain and only for features/commands
|
||||||
|
that you know has no influence on the cause-and-effect order of your
|
||||||
|
game (commands given after the async function might be executed before
|
||||||
|
it has finished). Accessing the same property from different threads
|
||||||
|
can lead to unpredicted behaviour if you are not careful (this is called a
|
||||||
|
"race condition").
|
||||||
|
|
||||||
Use this function with restrain and only for features/commands
|
Also note that some databases, notably sqlite3, don't support access from
|
||||||
that you know has no influence on the cause-and-effect order of your
|
multiple threads simultaneously, so if you do heavy database access from
|
||||||
game (commands given after the async function might be executed before
|
your `to_execute` under sqlite3 you will probably run very slow or even get
|
||||||
it has finished). Accessing the same property from different threads
|
tracebacks.
|
||||||
can lead to unpredicted behaviour if you are not careful (this is called a
|
|
||||||
"race condition").
|
|
||||||
|
|
||||||
Also note that some databases, notably sqlite3, don't support access from
|
|
||||||
multiple threads simultaneously, so if you do heavy database access from
|
|
||||||
your `to_execute` under sqlite3 you will probably run very slow or even get
|
|
||||||
tracebacks.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -676,9 +838,12 @@ def run_async(to_execute, *args, **kwargs):
|
||||||
def check_evennia_dependencies():
|
def check_evennia_dependencies():
|
||||||
"""
|
"""
|
||||||
Checks the versions of Evennia's dependencies including making
|
Checks the versions of Evennia's dependencies including making
|
||||||
some checks for runtime libraries
|
some checks for runtime libraries.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
result (bool): `False` if a show-stopping version mismatch is
|
||||||
|
found.
|
||||||
|
|
||||||
Returns False if a show-stopping version mismatch is found.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# check main dependencies
|
# check main dependencies
|
||||||
|
|
@ -711,6 +876,14 @@ def check_evennia_dependencies():
|
||||||
def has_parent(basepath, obj):
|
def has_parent(basepath, obj):
|
||||||
"""
|
"""
|
||||||
Checks if `basepath` is somewhere in `obj`s parent tree.
|
Checks if `basepath` is somewhere in `obj`s parent tree.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
basepath (str): Python dotpath to compare against obj path.
|
||||||
|
obj (any): Object whose path is to be checked.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
has_parent (bool): If the check was successful or not.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return any(cls for cls in obj.__class__.mro()
|
return any(cls for cls in obj.__class__.mro()
|
||||||
|
|
@ -726,15 +899,15 @@ def mod_import(module):
|
||||||
A generic Python module loader.
|
A generic Python module loader.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
module - this can be either a Python path (dot-notation like
|
module (str, module): This can be either a Python path
|
||||||
`evennia.objects.models`), an absolute path
|
(dot-notation like `evennia.objects.models`), an absolute path
|
||||||
(e.g. `/home/eve/evennia/evennia/objects.models.py`)
|
(e.g. `/home/eve/evennia/evennia/objects.models.py`) or an
|
||||||
or an already imported module object (e.g. `models`)
|
already imported module object (e.g. `models`)
|
||||||
Returns:
|
Returns:
|
||||||
an imported module. If the input argument was already a model,
|
module (module or None): An imported module. If the input argument was
|
||||||
this is returned as-is, otherwise the path is parsed and imported.
|
already a module, this is returned as-is, otherwise the path is
|
||||||
Error:
|
parsed and imported. Returns `None` and logs error if import failed.
|
||||||
returns `None`. The error is also logged.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def log_trace(errmsg=None):
|
def log_trace(errmsg=None):
|
||||||
|
|
@ -800,8 +973,21 @@ def mod_import(module):
|
||||||
|
|
||||||
def all_from_module(module):
|
def all_from_module(module):
|
||||||
"""
|
"""
|
||||||
Return all global-level variables from a module as a dict.
|
Return all global-level variables from a module.
|
||||||
Ignores modules and variable names starting with an underscore.
|
|
||||||
|
Args:
|
||||||
|
module (str, module): This can be either a Python path
|
||||||
|
(dot-notation like `evennia.objects.models`), an absolute path
|
||||||
|
(e.g. `/home/eve/evennia/evennia/objects.models.py`) or an
|
||||||
|
already imported module object (e.g. `models`)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
variables (dict): A dict of {variablename: variable} for all
|
||||||
|
variables in the given module.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
Ignores modules and variable names starting with an underscore.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
mod = mod_import(module)
|
mod = mod_import(module)
|
||||||
if not mod:
|
if not mod:
|
||||||
|
|
@ -812,23 +998,24 @@ def all_from_module(module):
|
||||||
|
|
||||||
def variable_from_module(module, variable=None, default=None):
|
def variable_from_module(module, variable=None, default=None):
|
||||||
"""
|
"""
|
||||||
Retrieve a variable or list of variables from a module. The variable(s)
|
Retrieve a variable or list of variables from a module. The
|
||||||
must be defined globally in the module. If no variable is given (or a
|
variable(s) must be defined globally in the module. If no variable
|
||||||
list entry is `None`), all global variables are extracted from the module.
|
is given (or a list entry is `None`), all global variables are
|
||||||
|
extracted from the module.
|
||||||
If `module` cannot be imported or a given `variable` not found, `default`
|
|
||||||
is returned.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
module (string or module)- python path, absolute path or a module.
|
module (string or module): Python path, absolute path or a module.
|
||||||
variable (string or iterable) - single variable name or iterable of
|
variable (string or iterable, optional): Single variable name or iterable
|
||||||
variable names to extract.
|
of variable names to extract. If not given, all variables in
|
||||||
default (string) - default value to use if a variable fails
|
the module will be returned.
|
||||||
to be extracted. Ignored if `variable` is not given.
|
default (string, optional): Default value to use if a variable fails to
|
||||||
|
be extracted. Ignored if `variable` is not given.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
a single value or a list of values depending on the type of
|
variables (value or list): A single value or a list of values
|
||||||
`variable` argument. Errors in lists are replaced by the
|
depending on if `variable` is given or not. Errors in lists
|
||||||
`default` argument.
|
are replaced by the `default` argument.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not module:
|
if not module:
|
||||||
|
|
@ -856,8 +1043,20 @@ def string_from_module(module, variable=None, default=None):
|
||||||
"""
|
"""
|
||||||
This is a wrapper for `variable_from_module` that requires return
|
This is a wrapper for `variable_from_module` that requires return
|
||||||
value to be a string to pass. It's primarily used by login screen.
|
value to be a string to pass. It's primarily used by login screen.
|
||||||
if `variable` is not set, returns a list of all string variables in
|
|
||||||
`module`.
|
Args:
|
||||||
|
module (string or module): Python path, absolute path or a module.
|
||||||
|
variable (string or iterable, optional): Single variable name or iterable
|
||||||
|
of variable names to extract. If not given, all variables in
|
||||||
|
the module will be returned.
|
||||||
|
default (string, optional): Default value to use if a variable fails to
|
||||||
|
be extracted. Ignored if `variable` is not given.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
variables (value or list): A single (string) value or a list of values
|
||||||
|
depending on if `variable` is given or not. Errors in lists (such
|
||||||
|
as the value not being a string) are replaced by the `default` argument.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
val = variable_from_module(module, variable=variable, default=default)
|
val = variable_from_module(module, variable=variable, default=default)
|
||||||
if val:
|
if val:
|
||||||
|
|
@ -868,23 +1067,38 @@ def string_from_module(module, variable=None, default=None):
|
||||||
return result if result else default
|
return result if result else default
|
||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
def random_string_from_module(module):
|
def random_string_from_module(module):
|
||||||
"""
|
"""
|
||||||
Returns a random global string from a module.
|
Returns a random global string from a module.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
module (string or module): Python path, absolute path or a module.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
random (string): A random stribg variable from `module`.
|
||||||
"""
|
"""
|
||||||
return random.choice(string_from_module(module))
|
return random.choice(string_from_module(module))
|
||||||
|
|
||||||
|
|
||||||
def fuzzy_import_from_module(path, variable, default=None, defaultpaths=None):
|
def fuzzy_import_from_module(path, variable, default=None, defaultpaths=None):
|
||||||
"""
|
"""
|
||||||
Import a variable based on a fuzzy path. First the literal
|
Import a variable based on a fuzzy path. First the literal
|
||||||
`path` will be tried, then all given `defaultpaths` will be
|
`path` will be tried, then all given `defaultpaths` will be
|
||||||
prepended to see a match is found.
|
prepended to see a match is found.
|
||||||
|
|
||||||
path - full or partial python path.
|
Args:
|
||||||
variable - name of variable to import from module.
|
path (str): Full or partial python path.
|
||||||
defaultpaths - an iterable of python paths to attempt
|
variable (str): Name of variable to import from module.
|
||||||
in order if importing directly from
|
default (string, optional): Default value to use if a variable fails to
|
||||||
`path` doesn't work.
|
be extracted. Ignored if `variable` is not given.
|
||||||
|
defaultpaths (iterable, options): Python paths to attempt in order if
|
||||||
|
importing directly from `path` doesn't work.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
value (any): The variable imported from the module, or `default`, if
|
||||||
|
not found.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
paths = [path] + make_iter(defaultpaths)
|
paths = [path] + make_iter(defaultpaths)
|
||||||
for modpath in paths:
|
for modpath in paths:
|
||||||
|
|
@ -898,13 +1112,23 @@ def fuzzy_import_from_module(path, variable, default=None, defaultpaths=None):
|
||||||
return getattr(mod, variable, default)
|
return getattr(mod, variable, default)
|
||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
def class_from_module(path, defaultpaths=None):
|
def class_from_module(path, defaultpaths=None):
|
||||||
"""
|
"""
|
||||||
Return a class from a module, given the module's path. This is
|
Return a class from a module, given the module's path. This is
|
||||||
primarily used to convert db_typeclass_path:s to classes.
|
primarily used to convert db_typeclass_path:s to classes.
|
||||||
|
|
||||||
if a list of `defaultpaths` is given, try subsequent runs by
|
Args:
|
||||||
prepending those paths to the given `path`.
|
path (str): Full Python dot-path to module.
|
||||||
|
defaultpaths (iterable, optional): If a direc import from `path` fails,
|
||||||
|
try subsequent imports by prepending those paths to `path`.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
class (Class): An uninstatiated class recovered from path.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ImportError: If all loading failed.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
cls = None
|
cls = None
|
||||||
if defaultpaths:
|
if defaultpaths:
|
||||||
|
|
@ -949,14 +1173,10 @@ object_from_module = class_from_module
|
||||||
|
|
||||||
def init_new_player(player):
|
def init_new_player(player):
|
||||||
"""
|
"""
|
||||||
Helper method to call all hooks, set flags etc on a newly created
|
Deprecated.
|
||||||
player (and potentially their character, if it exists already).
|
|
||||||
"""
|
"""
|
||||||
# the FIRST_LOGIN flags are necessary for the system to call
|
from evennia.utils import logger
|
||||||
# the relevant first-login hooks.
|
logger.log_depmsg("evennia.utils.utils.init_new_player is DEPRECATED and should not be used.")
|
||||||
#if player.character:
|
|
||||||
# player.character.db.FIRST_LOGIN = True
|
|
||||||
player.db.FIRST_LOGIN = True
|
|
||||||
|
|
||||||
|
|
||||||
def string_similarity(string1, string2):
|
def string_similarity(string1, string2):
|
||||||
|
|
@ -967,8 +1187,14 @@ def string_similarity(string1, string2):
|
||||||
The measure-vectors used is simply a "bag of words" type histogram
|
The measure-vectors used is simply a "bag of words" type histogram
|
||||||
(but for letters).
|
(but for letters).
|
||||||
|
|
||||||
The function returns a value 0...1 rating how similar the two strings
|
Args:
|
||||||
are. The strings can contain multiple words.
|
string1 (str): String to compare (may contain any number of words).
|
||||||
|
string2 (str): Second string to compare (any number of words).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
similarity (float): A value 0...1 rating how similar the two
|
||||||
|
strings are.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
vocabulary = set(list(string1 + string2))
|
vocabulary = set(list(string1 + string2))
|
||||||
vec1 = [string1.count(v) for v in vocabulary]
|
vec1 = [string1.count(v) for v in vocabulary]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue