Converted a large part of utils/ folder to google code docstrings as per #709.

This commit is contained in:
Griatch 2015-09-27 19:51:54 +02:00
parent fc4beed9ca
commit eb2bd8d44c
17 changed files with 1107 additions and 406 deletions

View file

@ -472,10 +472,10 @@ def _create_player(session, playername, password, permissions, typeclass=None):
logger.log_trace()
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
# hooks during login later)
utils.init_new_player(new_player)
new_player.db.FIRST_LOGIN = True
# join the new player to the public channel
pchannel = ChannelDB.objects.get_channel(settings.DEFAULT_CHANNELS[0]["key"])

View file

@ -213,10 +213,10 @@ its and @/./+/-/_ only.") # this echoes the restrictions made by django's auth m
logger.log_trace()
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
# hooks during login later)
utils.init_new_player(new_player)
new_player.db.FIRST_LOGIN = True
# join the new player to the public channel
pchanneldef = settings.CHANNEL_PUBLIC

View file

@ -80,6 +80,13 @@ class ANSIParser(object):
"""
Replacer used by `re.sub` to replace ANSI
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(), "")
@ -87,6 +94,13 @@ class ANSIParser(object):
"""
Replacer used by `re.sub` to replace ANSI
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(), "")
@ -97,6 +111,14 @@ class ANSIParser(object):
It checks `self.do_xterm256` to determine if conversion
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:
return ""
@ -177,21 +199,43 @@ class ANSIParser(object):
def strip_raw_codes(self, 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)
def strip_mxp(self, 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)
def parse_ansi(self, string, strip_ansi=False, xterm256=False, mxp=False):
"""
Parses a string, subbing color codes according to
the stored mapping.
Parses a string, subbing color codes according to the stored
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'):
@ -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.
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)
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)
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)
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('{', '{{')
@ -385,8 +459,9 @@ def group(lst, n):
def _spacing_preflight(func):
"""
This wrapper function is used to do some preflight checks on functions used
for padding ANSIStrings.
This wrapper function is used to do some preflight checks on
functions used for padding ANSIStrings.
"""
def wrapped(self, width, fillchar=None):
if fillchar is None:
@ -404,8 +479,9 @@ def _spacing_preflight(func):
def _query_super(func_name):
"""
Have the string class handle this with the cleaned string instead of
ANSIString.
Have the string class handle this with the cleaned string instead
of ANSIString.
"""
def wrapped(self, *args, **kwargs):
return getattr(self.clean(), func_name)(*args, **kwargs)
@ -415,6 +491,7 @@ def _query_super(func_name):
def _on_raw(func_name):
"""
Like query_super, but makes the operation run on the raw string.
"""
def wrapped(self, *args, **kwargs):
args = list(args)
@ -439,6 +516,7 @@ def _transform(func_name):
return a string the same length as the original. This function
allows us to do the same, replacing all the non-coded characters
with the resulting string.
"""
def wrapped(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
base class. We apply them here, as part of the classes construction.
"""
def __init__(cls, *args, **kwargs):
for func_name in [
@ -493,6 +572,7 @@ class ANSIString(unicode):
Please refer to the Metaclass, ANSIMeta, which is used to apply wrappers
for several of the methods that need not be defined directly here.
"""
__metaclass__ = ANSIMeta
@ -506,6 +586,7 @@ class ANSIString(unicode):
Internally, ANSIString can also passes itself precached code/character
indexes and clean strings to avoid doing extra work when combining
ANSIStrings.
"""
string = args[0]
if not isinstance(string, basestring):
@ -554,9 +635,11 @@ class ANSIString(unicode):
def __unicode__(self):
"""
Unfortunately, this is not called during print() statements due to a
bug in the Python interpreter. You can always do unicode() or str()
around the resulting ANSIString and print that.
Unfortunately, this is not called during print() statements
due to a bug in the Python interpreter. You can always do
unicode() or str() around the resulting ANSIString and print
that.
"""
return self._raw_string
@ -564,6 +647,7 @@ class ANSIString(unicode):
"""
Let's make the repr the command that would actually be used to
construct this object, for convenience and reference.
"""
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
tables for which characters in the raw string are related to ANSI
escapes, and which are for the readable text.
"""
self.parser = kwargs.pop('parser', ANSI_PARSER)
super(ANSIString, self).__init__()
@ -603,6 +688,7 @@ class ANSIString(unicode):
"""
Takes a list of integers, and produces a new one incrementing all
by a number.
"""
return [i + offset for i in iterable]
@ -610,6 +696,7 @@ class ANSIString(unicode):
def _adder(cls, first, second):
"""
Joins two ANSIStrings, preserving calculated info.
"""
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
that don't need to be reprocessed, lest we end up with escapes being
interpreted literally.
"""
if not isinstance(other, basestring):
return NotImplemented
@ -639,6 +727,7 @@ class ANSIString(unicode):
def __radd__(self, other):
"""
Likewise, if we're on the other end.
"""
if not isinstance(other, basestring):
return NotImplemented
@ -650,6 +739,7 @@ class ANSIString(unicode):
"""
This function is deprecated, so we just make it call the proper
function.
"""
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
those indexes to figure out what escape characters need to be
replayed.
"""
slice_indexes = self._char_indexes[slc]
# 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
string instead, bypassing ANSIString's intelligent escape skipping,
for reasons explained in the __new__ method's docstring.
"""
if isinstance(item, slice):
# Slices must be handled specially.
@ -727,12 +819,14 @@ class ANSIString(unicode):
def clean(self):
"""
Return a unicode object without the ANSI escapes.
"""
return self._clean_string
def raw(self):
"""
Return a unicode object with the ANSI escapes.
"""
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
colored.
"""
if hasattr(sep, '_clean_string'):
sep = sep.clean()
@ -776,6 +871,7 @@ class ANSIString(unicode):
It's possible that only one of these tables is actually needed, the
other assumed to be what isn't in the first.
"""
code_indexes = []
@ -792,6 +888,7 @@ class ANSIString(unicode):
"""
Get the code characters from the given slice end to the next
character.
"""
try:
index = self._char_indexes[index - 1]
@ -815,6 +912,7 @@ class ANSIString(unicode):
PyPy is distributed under the MIT licence.
http://opensource.org/licenses/MIT
"""
bylen = len(by)
if bylen == 0:
@ -837,6 +935,7 @@ class ANSIString(unicode):
def __mul__(self, other):
"""
Multiplication method. Implemented for performance reasons.
"""
if not isinstance(other, int):
return NotImplemented
@ -863,6 +962,7 @@ class ANSIString(unicode):
PyPy is distributed under the MIT licence.
http://opensource.org/licenses/MIT
"""
res = []
end = len(self)
@ -886,6 +986,7 @@ class ANSIString(unicode):
def join(self, iterable):
"""
Joins together strings in an iterable.
"""
result = ANSIString('')
last_item = None
@ -902,6 +1003,7 @@ class ANSIString(unicode):
"""
Generate a line of characters in a more efficient way than just adding
ANSIStrings.
"""
if not isinstance(char, ANSIString):
line = char * amount
@ -929,6 +1031,7 @@ class ANSIString(unicode):
def center(self, width, fillchar, difference):
"""
Center some text with some spaces padding both sides.
"""
remainder = difference % 2
difference /= 2
@ -940,6 +1043,7 @@ class ANSIString(unicode):
def ljust(self, width, fillchar, difference):
"""
Left justify some text.
"""
return self + self._filler(fillchar, difference)
@ -947,5 +1051,6 @@ class ANSIString(unicode):
def rjust(self, width, fillchar, difference):
"""
Right justify some text.
"""
return self._filler(fillchar, difference) + self

View file

@ -192,13 +192,23 @@ RE_CODE_SPLIT = re.compile(r"(^\#CODE.*?$|^\#HEADER)$", re.MULTILINE)
def read_batchfile(pythonpath, file_ending='.py'):
"""
This reads the contents of a batch-file.
Filename is considered to be a python path to a batch file
relative the directory specified in `settings.py`.
This reads the contents of a batch-file. Filename is considered
to be a python path to a batch file relative the directory
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
@ -293,6 +303,7 @@ def tb_filename(tb):
def tb_iter(tb):
"Traceback iterator."
while tb is not None:
yield tb
tb = tb.tb_next
@ -309,13 +320,22 @@ class BatchCodeProcessor(object):
This parses the lines of a batchfile according to the following
rules:
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.
Args:
pythonpath (str): The dot-python path to the file.
debug (bool, optional): Insert delete-commands for
deleting created objects.
Returns:
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):
"""
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
environdict = {"settings_module": settings}

View file

@ -59,24 +59,35 @@ def create_object(typeclass=None, key=None, location=None,
Create a new in-game object.
keywords:
typeclass - class or python path to a typeclass
key - name of the new object. If not set, a name of #dbref will be set.
home - obj or #dbref to use as the object's home location
permissions - a comma-separated string of permissions
locks - one or more lockstrings, separated by semicolons
aliases - a list of alternative keys
tags - a list of tag keys (using no category)
destination - obj or #dbref to use as an Exit's target
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.
home (Object or str): Obj or #dbref to use as the object's
home location.
permissions (str): A comma-separated string of permissions.
locks (str): one or more lockstrings, separated by semicolons.
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
if not _ObjectDB:
from evennia.objects.models import ObjectDB as _ObjectDB
typeclass = typeclass if typeclass else settings.BASE_OBJECT_TYPECLASS
if isinstance(typeclass, basestring):
@ -120,32 +131,42 @@ object = create_object
# 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,
persistent=None, autostart=True, report_to=None):
"""
Create a new script. All scripts are a combination
of a database object that communicates with the
database, and an typeclass that 'decorates' the
database object into being different types of scripts.
It's behaviour is similar to the game objects except
scripts has a time component and are more limited in
scope.
Create a new script. All scripts are a combination of a database
object that communicates with the database, and an typeclass that
'decorates' the database object into being different types of
scripts. It's behaviour is similar to the game objects except
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
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
if not _ScriptDB:
@ -194,10 +215,20 @@ script = create_script
def create_help_entry(key, entrytext, category="General", locks=None):
"""
Create a static help entry in the help database. Note that Command
help entries are dynamic and directly taken from the __doc__ entries
of the command. The database-stored help entries are intended for more
general help on the game, more extensive info, in-game setting information
and so on.
help entries are dynamic and directly taken from the __doc__
entries of the command. The database-stored help entries are
intended for more general help on the game, more extensive info,
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
if not _HelpEntry:
@ -230,24 +261,28 @@ help_entry = create_help_entry
def create_message(senderobj, message, channels=None,
receivers=None, locks=None, header=None):
"""
Create a new communication message. Msgs are used for all
player-to-player communication, both between individual players
and over channels.
senderobj - the player sending the message. This must be the actual object.
message - text with the message. Eventual headers, titles etc
should all be included in this text string. Formatting
will be retained.
channels - a channel or a list of channels to send to. The channels
may be actual channel objects or their unique key strings.
receivers - a player to send to, or a list of them. May be Player objects
or playernames.
locks - lock definition string
header - mime-type or other optional information for the message
Create a new communication Msg. Msgs represent a unit of
database-persistent communication between entites.
Args:
senderobj (Object or Player): The entity sending the Msg.
message (str): Text with the message. Eventual headers, titles
etc should all be included in this text string. Formatting
will be retained.
channels (Channel, key or list): A channel or a list of channels to
send to. The channels may be actual channel objects or their
unique key strings.
receivers (Object, Player, str or list): A Player/Object to send
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
if not _Msg:
@ -275,16 +310,27 @@ def create_channel(key, aliases=None, desc=None,
locks=None, keep_log=True,
typeclass=None):
"""
Create A communication Channel. A Channel serves as a central
hub for distributing Msgs to groups of people without
specifying the receivers explicitly. Instead players may
'connect' to the channel and follow the flow of messages. By
default the channel allows access to all old messages, but
this can be turned off with the keep_log switch.
Create A communication Channel. A Channel serves as a central hub
for distributing Msgs to groups of people without specifying the
receivers explicitly. Instead players may 'connect' to the channel
and follow the flow of messages. By default the channel allows
access to all old messages, but this can be turned off with the
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
@ -322,23 +368,28 @@ def create_player(key, email, password,
"""
This creates a new player.
key - the player's name. This should be unique.
email - email on valid addr@addr.domain form.
password - password in cleartext
is_superuser - wether or not this player is to be a superuser
locks - lockstring
permission - list of permissions
report_to - an object with a msg() method to report errors to. If
not given, errors will be logged.
Args:
key (str): The player's name. This should be unique.
email (str): Email on valid addr@addr.domain form. This is
technically required but if set to `None`, an email of
`dummy@dummy.com` will be used as a placeholder.
password (str): Password in cleartext.
Will return the Player-typeclass or None/raise Exception if the
Typeclass given failed to load.
Kwargs:
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:
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.
Raises:
ValueError: If `key` already exists in database.
Notes:
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

View file

@ -25,7 +25,6 @@ try:
from cPickle import dumps, loads
except ImportError:
from pickle import dumps, loads
from django.db import transaction
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.contenttypes.models import ContentType
from evennia.server.models import ServerConfig
@ -52,8 +51,14 @@ else:
def _TO_DATESTRING(obj):
"""
this will only be called with valid database objects. Returns datestring
on correct form.
Creates datestring hash.
Args:
obj (Object): Database object.
Returns:
datestring (str): A datestring hash.
"""
try:
return _GA(obj, "db_date_created").strftime(_DATESTRING)
@ -209,8 +214,14 @@ class _SaverSet(_SaverMutable, MutableSet):
def pack_dbobj(item):
"""
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()
obj = item
@ -224,10 +235,18 @@ def pack_dbobj(item):
def unpack_dbobj(item):
"""
Check and convert internal representations back to Django database models.
The fact that item is a packed dbobj should be checked before this call.
This either returns the original input or converts the internal store back
to a database representation (its typeclass is returned if applicable).
Check and convert internal representations back to Django database
models.
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()
try:
@ -244,11 +263,18 @@ def unpack_dbobj(item):
def to_pickle(data):
"""
This prepares data on arbitrary form to be pickled. It handles any nested
structure and returns data on a form that is safe to pickle (including
having converted any database models to their internal representation).
We also convert any Saver*-type objects back to their normal
representations, they are not pickle-safe.
This prepares data on arbitrary form to be pickled. It handles any
nested structure and returns data on a form that is safe to pickle
(including having converted any database models to their internal
representation). We also convert any Saver*-type objects back to
their normal representations, they are not pickle-safe.
Args:
data (any): Data to pickle.
Returns:
data (any): Pickled data.
"""
def process_item(item):
"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
returned.
db_obj - this is the model instance (normally 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.
Args_
data (any): Pickled data to unpickle.
db_obj (Atribute, any): This is the model instance (normally
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
to their _SaverList, _SaverDict and _SaverSet counterparts.
Returns:
data (any): Unpickled data.
"""
def process_item(item):

View file

@ -631,7 +631,9 @@ class EvEditor(object):
def get_buffer(self):
"""
Return the current buffer
Return:
buffer (str): The current buffer.
"""
return self._buffer
@ -639,6 +641,10 @@ class EvEditor(object):
"""
This should be called when the buffer has been changed
somehow. It will handle unsaved flag and undo updating.
Args:
buf (str): The text to update the buffer with.
"""
if is_iter(buf):
buf = "\n".join(buf)
@ -651,6 +657,7 @@ class EvEditor(object):
def quit(self):
"""
Cleanly exit the editor.
"""
try:
self._quitfunc(self._caller)
@ -663,6 +670,7 @@ class EvEditor(object):
"""
Saves the content of the buffer. The 'quitting' argument is a bool
indicating whether or not the editor intends to exit after saving.
"""
if self._unsaved:
try:
@ -680,6 +688,12 @@ class EvEditor(object):
"""
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:
# undo
@ -706,8 +720,15 @@ class EvEditor(object):
"""
This displays the line editor buffer, or selected parts of it.
If `buf` is set and is not the full buffer, `offset` should define
the starting line number, to get the linenum display right.
Args:
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:
buf = self._buffer
@ -733,6 +754,7 @@ class EvEditor(object):
def display_help(self):
"""
Shows the help entry for the editor.
"""
string = self._sep * _DEFAULT_WIDTH + _HELP_TEXT + self._sep * _DEFAULT_WIDTH
self._caller.msg(string)

View file

@ -168,17 +168,17 @@ class EvForm(object):
"""
Initiate the form
keywords:
filename - path to template file
form - dictionary of {"CELLCHAR":char,
"TABLECHAR":char,
"FORM":templatestring}
Kwargs:
filename (str): Path to template file.
cells (dict): A dictionary mapping of {id:text}
tables (dict): A dictionary mapping of {id:EvTable}.
form (dict): A dictionary of {"CELLCHAR":char,
"TABLECHAR":char,
"FORM":templatestring}
if this is given, filename is not read.
cells - a dictionary mapping of {id:text}
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).
Notes:
Other kwargs are fed as options to the EvCells and EvTables
(see `evtable.EvCell` and `evtable.EvTable` for more info).
"""
self.filename = filename
@ -204,8 +204,9 @@ class EvForm(object):
def _parse_rectangles(self, cellchar, tablechar, form, **kwargs):
"""
Parse a form for rectangular formfields identified by
formchar enclosing an identifier.
Parse a form for rectangular formfields identified by formchar
enclosing an identifier.
"""
# update options given at creation with new input - this
@ -337,6 +338,7 @@ class EvForm(object):
def _populate_form(self, raw_form, mapping):
"""
Insert cell contents into form at given locations
"""
form = copy.copy(raw_form)
for key, (iy0, ix0, width, height, cell_or_table) in mapping.items():
@ -352,11 +354,13 @@ class EvForm(object):
"""
Add mapping for form.
cells - a dictionary of {identifier:celltext}
tables - a dictionary of {identifier:table}
Args:
cells (dict): A dictionary of {identifier:celltext}
tables (dict): A dictionary of {identifier:table}
kwargs will be forwarded to tables/cells. See
evtable.EvCell and evtable.EvTable for info.
Notes:
kwargs will be forwarded to tables/cells. See
`evtable.EvCell` and `evtable.EvTable` for info.
"""
# clean kwargs (these cannot be overridden)
@ -373,7 +377,15 @@ class EvForm(object):
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)
kwargs.pop("enforce_size", None)

View file

@ -65,21 +65,52 @@ def _format(seconds, *divisors) :
# Access functions
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)
if format:
return _format(runtime, 31536000, 2628000, 604800, 86400, 3600, 60)
return runtime
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
if format:
return _format(uptime, 31536000, 2628000, 604800, 86400, 3600, 60)
return uptime
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
if format:
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
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:
gametime_to_realtime(days=2) -> number of seconds in real life from
now after which 2 in-game days will have passed.
gametime_to_realtime(days=2) -> number of seconds in real life from
now after which 2 in-game days will have passed.
"""
realtime = (secs + mins * MIN + hrs * HOUR + days * DAY + weeks * WEEK + \
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):
"""
This method calculates how much in-game time a real-world time
interval would correspond to. This is usually a lot less interesting
than the other way around.
interval would correspond to. This is usually a lot less
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:
realtime_to_gametime(days=2) -> number of game-world seconds
corresponding to 2 real days.
"""
gametime = TIMEFACTOR * (secs + mins * 60 + hrs * 3600 + days * 86400 +
weeks * 604800 + months * 2628000 + yrs * 31536000)

View file

@ -13,6 +13,9 @@ class SharedMemoryManager(Manager):
# still use the singleton cache, but the active model isn't required
# to be a SharedMemoryModel.
def get(self, **kwargs):
"""
Data entity lookup.
"""
items = kwargs.keys()
inst = None
if len(items) == 1:

View file

@ -17,7 +17,7 @@ from django.db.models.signals import post_save
from django.db.models.base import Model, ModelBase
from django.db.models.signals import pre_delete, post_syncdb
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
@ -53,6 +53,7 @@ class SharedMemoryModelBase(ModelBase):
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
populated whenever possible (ie when it is possible to infer the pk value).
"""
def new_instance():
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
share the same cache.
"""
# the dbmodel is either the proxy base or ourselves
dbmodel = cls._meta.proxy_for_model if cls._meta.proxy else cls
@ -89,15 +91,17 @@ class SharedMemoryModelBase(ModelBase):
"""
Field shortcut creation:
Takes field names `db_*` and creates property wrappers named without the
`db_` prefix. So db_key -> key
Takes field names `db_*` and creates property wrappers named
without the `db_` prefix. So db_key -> key
This wrapper happens on the class level, so there is no overhead when creating objects.
If a class already has a wrapper of the given name, the automatic creation is skipped.
This wrapper happens on the class level, so there is no
overhead when creating objects. If a class already has a
wrapper of the given name, the automatic creation is skipped.
Notes:
Remember to document this auto-wrapping in the class header, this could seem very
much like magic to the user otherwise.
Remember to document this auto-wrapping in the class
header, this could seem very much like magic to the user
otherwise.
"""
attrs["typename"] = cls.__name__
@ -218,8 +222,10 @@ class SharedMemoryModel(Model):
@classmethod
def _get_cache_key(cls, args, kwargs):
"""
This method is used by the caching subsystem to infer the PK value from the constructor arguments.
It is used to decide if an instance has to be built or is already in the cache.
This method is used by the caching subsystem to infer the PK
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
# Quick hack for my composites work for now.
@ -248,9 +254,11 @@ class SharedMemoryModel(Model):
@classmethod
def get_cached_instance(cls, id):
"""
Method to retrieve a cached instance by pk value. Returns None when not found
(which will always be the case when caching is disabled for this class). Please
note that the lookup will be done even when instance caching is disabled.
Method to retrieve a cached instance by pk value. Returns None
when not found (which will always be the case when caching is
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)
@ -261,9 +269,9 @@ class SharedMemoryModel(Model):
Args:
instance (Class instance): the instance to cache.
new (bool, optional): this is the first time this
instance is cached (i.e. this is not an update
operation like after a db save).
new (bool, optional): this is the first time this instance is
cached (i.e. this is not an update operation like after a
db save).
"""
pk = instance._get_pk_val()
@ -281,6 +289,7 @@ class SharedMemoryModel(Model):
def get_all_cached_instances(cls):
"""
Return the objects so far cached by idmapper for this class.
"""
return cls.__dbclass__.__instance_cache__.values()
@ -288,6 +297,7 @@ class SharedMemoryModel(Model):
def _flush_cached_by_key(cls, key, force=True):
"""
Remove the cached reference.
"""
try:
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`
keyword to remove all objects, safe or not.
"""
if force:
cls.__dbclass__.__instance_cache__ = {}
@ -326,6 +337,7 @@ class SharedMemoryModel(Model):
"""
Flush this instance from the instance cache. Use
`force` to override recache_protection for the object.
"""
pk = self._get_pk_val()
if pk and (force or not self._idmapper_recache_protection):
@ -334,12 +346,14 @@ class SharedMemoryModel(Model):
def set_recache_protection(self, mode=True):
"""
Set if this instance should be allowed to be recached.
"""
self._idmapper_recache_protection = bool(mode)
def delete(self, *args, **kwargs):
"""
Delete the object, clearing cache.
"""
self.flush_from_cache()
self._is_deleted = True
@ -349,12 +363,11 @@ class SharedMemoryModel(Model):
"""
Central database save operation.
Arguments as per Django documentation
Calls:
self.at_<fieldname>_postsave(new)
# this is a wrapper set by oobhandler:
self._oob_at_<fieldname>_postsave()
Notes:
Arguments as per Django documentation.
Calls `self.at_<fieldname>_postsave(new)`
(this is a wrapper set by oobhandler:
self._oob_at_<fieldname>_postsave())
"""
@ -400,6 +413,7 @@ class SharedMemoryModel(Model):
class WeakSharedMemoryModelBase(SharedMemoryModelBase):
"""
Uses a WeakValue dictionary for caching instead of a regular one.
"""
def _prepare(cls):
super(WeakSharedMemoryModelBase, cls)._prepare()
@ -410,6 +424,7 @@ class WeakSharedMemoryModelBase(SharedMemoryModelBase):
class WeakSharedMemoryModel(SharedMemoryModel):
"""
Uses a WeakValue dictionary for caching instead of a regular one
"""
__metaclass__ = WeakSharedMemoryModelBase
class Meta:
@ -424,6 +439,7 @@ def flush_cache(**kwargs):
is `True`.
Uses a signal so we make sure to catch cascades.
"""
def class_hierarchy(clslist):
"""Recursively yield a class hierarchy"""
@ -448,6 +464,7 @@ post_syncdb.connect(flush_cache)
def flush_cached_instance(sender, instance, **kwargs):
"""
Flush the idmapper cache only for a given instance.
"""
# XXX: Is this the best way to make sure we can flush?
if not hasattr(instance, 'flush_cached_instance'):
@ -459,6 +476,7 @@ pre_delete.connect(flush_cached_instance)
def update_cached_instance(sender, instance, **kwargs):
"""
Re-cache the given instance in the idmapper cache.
"""
if not hasattr(instance, 'cache_instance'):
return
@ -481,6 +499,7 @@ def conditional_flush(max_rmem, force=False):
cache is flushed.
force (bool, optional): forces a flush, regardless of timeout.
Defaults to `False`.
"""
global LAST_FLUSH
@ -546,6 +565,7 @@ def cache_size(mb=True):
Returns:
total_num, {objclass:total_num, ...}
"""
numtotal = [0] # use mutable to keep reference through recursion
classdict = {}

View file

@ -1,8 +1,8 @@
"""
Inlinefunc
This is a simple inline text language for use to custom-format text
in Evennia. It is applied BEFORE ANSI/MUX parsing is applied.
This is a simple inline text language for use to custom-format text in
Evennia. It is applied BEFORE ANSI/MUX parsing is applied.
To activate Inlinefunc, settings.INLINEFUNC_ENABLED must be set.
@ -52,7 +52,10 @@ _DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
# inline functions
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
align = 'c'
fillchar = ' '
@ -67,8 +70,12 @@ def pad(text, *args, **kwargs):
break
return utils.pad(text, width=width, align=align, fillchar=fillchar)
def crop(text, *args, **kwargs):
"Crop to width. crop(text, width=78, suffix='[...]')"
"""
Crop to width. crop(text, width=78, suffix='[...]')
"""
width = _DEFAULT_WIDTH
suffix = "[...]"
for iarg, arg in enumerate(args):
@ -80,8 +87,12 @@ def crop(text, *args, **kwargs):
break
return utils.crop(text, width=width, suffix=suffix)
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
indent = 0
for iarg, arg in enumerate(args):
@ -91,16 +102,24 @@ def wrap(text, *args, **kwargs):
indent = int(arg) if arg.isdigit() else indent
return utils.wrap(text, width=width, indent=indent)
def time(text, *args, **kwargs):
"Inserts current time"
"""
Inserts current time.
"""
import time
strformat = "%h %d, %H:%M"
if args and args[0]:
strformat = str(args[0])
return time.strftime(strformat)
def you(text, *args, **kwargs):
"Inserts your name"
"""
Inserts your name.
"""
name = "You"
sess = kwargs.get("session")
if sess and sess.puppet:
@ -139,23 +158,40 @@ def _execute_inline_function(funcname, text, session):
Get the enclosed text between {funcname(...) and {/funcname
and execute the inline function to replace the whole block
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
"inside out" on a nested function tree, so each call only works
on a "flat" tag.
Args:
funcname (str): Inlinefunction identifier.
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):
"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(",")]
intext = match.group(2)
kwargs = {"session":session}
return _INLINE_FUNCS[funcname][0](intext, *args, **kwargs)
return _INLINE_FUNCS[funcname][1].sub(subfunc, text)
def _execute_inline_single_function(funcname, text, session):
"""
Get the arguments of a single function call (no matching end tag)
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):
"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][2].sub(subfunc, text)
def parse_inlinefunc(text, strip=False, session=None):
"""
Parse inline function-replacement.
strip - remove all supported inlinefuncs from text
session - session calling for the parsing
Args:
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:
@ -204,6 +248,7 @@ def parse_inlinefunc(text, strip=False, session=None):
return "".join(outstack)
def _test():
# 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."

View file

@ -24,9 +24,13 @@ _TIMEZONE = None
def log_trace(errmsg=None):
"""
Log a traceback to the log. This should be called
from within an exception. errmsg is optional and
adds an extra line with added info.
Log a traceback to the log. This should be called from within an
exception.
Args:
errmsg (str, optional): Adds an extra line with added info
at the end of the traceback in the log.
"""
tracestring = format_exc()
try:
@ -49,7 +53,9 @@ def log_err(errmsg):
"""
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:
errmsg = str(errmsg)
@ -65,7 +71,9 @@ def log_warn(warnmsg):
"""
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:
warnmsg = str(warnmsg)
@ -94,7 +102,10 @@ log_infomsg = log_info
def log_dep(depmsg):
"""
Prints a deprecation message
Prints a deprecation message.
Args:
depmsg (str): The deprecation message to log.
"""
try:
depmsg = str(depmsg)
@ -111,9 +122,13 @@ LOG_FILE_HANDLES = {} # holds open log handles
def log_file(msg, filename="game.log"):
"""
Arbitrary file logger using threads. Filename defaults to
'game.log'. All logs will appear in the logs directory and log
entries will start on new lines following datetime info.
Arbitrary file logger using threads.
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
@ -131,6 +146,7 @@ def log_file(msg, filename="game.log"):
# manually or log file won't be written to until the
# write buffer is full.
filehandle.flush()
def errback(failure):
"Catching errors to normal log"
log_trace()

View file

@ -92,7 +92,10 @@ _handle_dbref = lambda inp: dbid_to_obj(inp, ObjectDB)
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)
if id(prototype) in visited:
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):
"""
Recursively traverse a prototype dictionary,
including multiple inheritance. Use _validate_prototype
before this, we don't check for infinite recursion here.
Recursively traverse a prototype dictionary, including multiple
inheritance. Use _validate_prototype before this, we don't check
for infinite recursion here.
"""
if "prototype" in dic:
# 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
so make sure the spawned Typeclass works before using this!
Input:
objsparams - each argument should be a tuple of arguments for the respective
creation/add handlers in the following order:
(create, permissions, locks, aliases, nattributes, attributes)
Args:
objsparams (any): Aach argument should be a tuple of arguments
for the respective creation/add handlers in the following
order: (create, permissions, locks, aliases, nattributes,
attributes)
Returns:
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
prototype dictionary.
keyword args:
prototype_modules - a python-path to a
prototype module, or a list of such paths. These will be used
to build the global protparents dictionary accessible by the
input prototypes. If not given, it will instead look for modules
Kwargs:
prototype_modules (str or list): A python-path to a prototype
module, or a list of such paths. These will be used to build
the global protparents dictionary accessible by the input
prototypes. If not given, it will instead look for modules
defined by settings.PROTOTYPE_MODULES.
prototype_parents - a dictionary holding a custom prototype-parent dictionary. Will
overload same-named prototypes from prototype_modules.
return_prototypes - only return a list of the prototype-parents
(no object creation happens)
prototype_parents (dict): A dictionary holding a custom
prototype-parent dictionary. Will overload same-named
prototypes from prototype_modules.
return_prototypes (bool): Only return a list of the
prototype-parents (no object creation happens)
"""
protparents = {}

View file

@ -82,8 +82,16 @@ class TextToHTMLparser(object):
def re_color(self, text):
"""
Replace ansi colors with html color class names.
Let the client choose how it will display colors, if it wishes to. """
Replace ansi colors with html color class names. Let the
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:
text = regex.sub(r'''<span class="%s">\1</span>''' % colorname, text)
for bgname, regex in self.re_bgs:
@ -91,19 +99,56 @@ class TextToHTMLparser(object):
return self.re_normal.sub("", 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)
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)
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', '')
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)'
n = 1
while n > 0:
@ -111,11 +156,29 @@ class TextToHTMLparser(object):
return 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>')
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$\"\']+))"
# -> added target to output prevent the web browser from attempting to
# change pages (and losing our webclient session).
@ -123,14 +186,31 @@ class TextToHTMLparser(object):
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>"
repl = self.re_link.sub(html, text)
return repl
def do_sub(self, m):
"Helper method to be passed to re.sub."
def do_sub(self, match):
"""
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()
if c['htmlchars']:
return cgi.escape(c['htmlchars'])
@ -145,8 +225,15 @@ class TextToHTMLparser(object):
def parse(self, text, strip_ansi=False):
"""
Main access function, converts a text containing
ANSI codes into html statements.
Main access function, converts a text containing ANSI codes
into html statements.
Args:
text (str): Text to process.
strip_ansi (bool, optional):
Returns:
text (str): Parsed text.
"""
# parse everything to ansi first
text = parse_ansi(text, strip_ansi=strip_ansi, xterm256=False, mxp=True)

View file

@ -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.
"""
# TODO: eliminate magic numbers.
if isinstance(buf, str):
return make_hybi07_frame(buf, opcode=0x2)
@ -349,7 +349,7 @@ class WebSocketProtocol(ProtocolWrapper):
def setBinaryMode(self, mode):
"""
If True, send str as binary and unicode as text.
Defaults to false for backwards compatibility.
"""
self.do_binary_frames = bool(mode)

View file

@ -40,22 +40,34 @@ _DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
def is_iter(iterable):
"""
Checks if an object behaves iterably. However,
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
Checks if an object behaves iterably.
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):
"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
@ -63,10 +75,15 @@ def wrap(text, width=_DEFAULT_WIDTH, indent=0):
"""
Safely wrap text to a certain number of characters.
text: (str) The text to wrap.
width: (int) The number of characters to wrap to.
indent: (int) How much to indent new lines (the first line
will not be indented)
Args:
text (str): The text to wrap.
width (int, optional): The number of characters to wrap to.
indent (int): How much to indent new lines (the first line
will not be indented)
Returns:
text (str): Properly wrapped text.
"""
if not text:
return ""
@ -76,10 +93,21 @@ def wrap(text, width=_DEFAULT_WIDTH, indent=0):
# alias - fill
fill = wrap
def pad(text, width=_DEFAULT_WIDTH, align="c", fillchar=" "):
"""
Pads to a given width, align is one of c,l,r
and fillchar defaults to the space character.
Pads to a given width.
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'
fillchar = fillchar[0] if fillchar else " "
@ -90,12 +118,24 @@ def pad(text, width=_DEFAULT_WIDTH, align="c", fillchar=" "):
else:
return text.center(width, fillchar)
def crop(text, width=_DEFAULT_WIDTH, suffix="[...]"):
"""
Crop text to a certain width, adding `suffix` to show that the line
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, crop without the suffix.
Crop text to a certain width, throwing away text from too-long
lines.
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)
@ -110,11 +150,19 @@ def crop(text, width=_DEFAULT_WIDTH, suffix="[...]"):
def dedent(text):
"""
Safely clean all whitespace at the left
of a paragraph. This is useful for preserving
triple-quoted string indentation while still
shifting it all to be next to the left edge of
the display.
Safely clean all whitespace at the left of a paragraph.
Args:
text (str): The text to dedent.
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:
return ""
@ -123,19 +171,31 @@ def dedent(text):
def list_to_string(inlist, endsep="and", addquote=False):
"""
This pretty-formats a list as string output, adding
an optional alternative separator to the second to last entry.
If `addquote` is `True`, the outgoing strings will be surrounded by quotes.
This pretty-formats a list as string output, adding an optional
alternative separator to the second to last entry. If `addquote`
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:
```
no endsep:
[1,2,3] -> '1, 2, 3'
with endsep=='and':
[1,2,3] -> '1, 2 and 3'
with addquote and endsep
[1,2,3] -> '"1", "2" and "3"'
```
```python
# no endsep:
[1,2,3] -> '1, 2, 3'
# with endsep=='and':
[1,2,3] -> '1, 2 and 3'
# with addquote and endsep
[1,2,3] -> '"1", "2" and "3"'
```
"""
if not endsep:
endsep = ","
@ -155,10 +215,17 @@ def list_to_string(inlist, endsep="and", addquote=False):
def wildcard_to_regexp(instring):
"""
Converts a player-supplied string that may have wildcards in it to regular
expressions. This is useful for name matching.
Converts a player-supplied string that may have wildcards in it to
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 = ""
@ -182,10 +249,13 @@ def time_format(seconds, style=0):
"""
Function to return a 'prettified' version of a value in seconds.
Style 0: 1d 08:30
Style 1: 1d
Style 2: 1 day, 8 hours, 30 minutes
Style 3: 1 day, 8 hours, 30 minutes, 10 seconds
Args:
seconds (int): Number if seconds to format.
style (int): One of the following styles:
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:
seconds = 0
@ -208,8 +278,8 @@ def time_format(seconds, style=0):
retval = '%id %02i:%02i' % (days, hours, minutes,)
else:
retval = '%02i:%02i' % (hours, minutes,)
return retval
elif style is 1:
"""
Simple, abbreviated form that only shows the highest time amount.
@ -275,8 +345,15 @@ def time_format(seconds, style=0):
def datetime_format(dtobj):
"""
Takes a datetime object instance (e.g. from Django's `DateTimeField`)
and returns a string describing how long ago that date was.
Pretty-prints the time since a given time.
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):
"""
Check to see if the host OS matches the query.
Common osnames are
posix
nt
Args:
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 True
return False
return os.name == osname
def get_evennia_version():
"""
Helper method for getting the current evennia version.
Returns:
version (str): The version string.
"""
import evennia
return evennia.__version__
@ -345,11 +432,17 @@ def pypath_to_realpath(python_path, file_ending='.py'):
def dbref(dbref, reqhash=True):
"""
Converts/checks if input is a valid dbref. If `reqhash` is set,
only input strings on the form '#N', where N is an integer is
accepted. Otherwise strings '#N', 'N' and integers N are all
accepted.
Output is the integer part.
Converts/checks if input is a valid dbref.
Args:
dbref (int or str): A datbase ref on the form N or #N.
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:
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):
"""
Convert a #dbid to a valid object of `objclass`. `objclass`
should be a valid object class to filter against (`objclass.filter` ...)
If not `raise_errors` is set, this will swallow errors of non-existing
objects.
Convert a #dbid to a valid object.
Args:
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)
if not dbid:
@ -389,13 +494,28 @@ def dbid_to_obj(inp, objclass, raise_errors=True):
raise
return inp
def to_unicode(obj, encoding='utf-8', force_string=False):
"""
This decodes a suitable object to the unicode format. Note that
one needs to encode it back to utf-8 before writing to disk or
printing. Note that non-string objects are let through without
conversion - this is important for e.g. Attributes. Use
`force_string` to enforce conversion of objects to string.
This decodes a suitable object to the unicode format.
Args:
obj (any): Object to decode to unicode.
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):
@ -427,10 +547,20 @@ def to_unicode(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,
for printing, writing to disk etc. Note that 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.
for printing, writing to disk etc.
Args:
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):
@ -460,8 +590,16 @@ def validate_email_address(emailaddress):
"""
Checks if an email address is syntactically correct.
(This snippet was adapted from
http://commandline.org.uk/python/email-syntax-check.)
Args:
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
@ -498,11 +636,23 @@ def validate_email_address(emailaddress):
def inherits_from(obj, parent):
"""
Takes an object and tries to determine if it inherits at any distance
from parent. 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).
Takes an object and tries to determine if it inherits at *any*
distance from parent.
Args:
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):
@ -524,9 +674,13 @@ def inherits_from(obj, parent):
def server_services():
"""
Lists all services active on the Server. Observe that
since services are launched in memory, this function will
only return any results if called from inside the game.
Lists all services active on the Server. Observe that since
services are launched in memory, this function will only return
any results if called from inside the game.
Returns:
services (dict): A dict of available services.
"""
from evennia.server.sessionhandler import SESSIONS
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
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:
engine = settings.DATABASES["default"]["ENGINE"]
@ -555,17 +715,21 @@ def uses_database(name="sqlite3"):
def delay(delay=2, callback=None, retval=None):
"""
Delay the return of a value.
Inputs:
delay (int) - the delay in seconds
callback (func() or func(retval)) - if given, will be called without
arguments or with `retval` after delay seconds.
retval (any) - this will be returned by this function after a delay,
or as input to callback.
Args:
delay (int): The delay in seconds
callback (callable, optional): Will be called without arguments
or with `retval` after delay seconds.
retval (any, optional): Whis will be returned by this function
after a delay, or as input to callback.
Returns:
deferred that will fire with callback after `delay` seconds. Note that
if `delay()` is used in the commandhandler callback chain, the callback
chain can be defined directly in the command body and don't need to be
specified here.
deferred (deferred): Will fire fire with callback after
`delay` seconds. Note that if `delay()` is used in the
commandhandler callback chain, the callback chain can be
defined directly in the command body and don't need to be
specified here.
"""
callb = callback or defer.Deferred().callback
if retval is not None:
@ -579,14 +743,18 @@ _OBJECTMODELS = None
def clean_object_caches(obj):
"""
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
if not _TYPECLASSMODELS:
from evennia.typeclasses import models as _TYPECLASSMODELS
#if not _OBJECTMODELS:
# from evennia.objects import models as _OBJECTMODELS
#print "recaching:", obj
if not obj:
return
# contents cache
@ -612,45 +780,39 @@ def run_async(to_execute, *args, **kwargs):
"""
Runs a function or executes a code snippet asynchronously.
Inputs:
to_execute (callable) - if this is a callable, it will
be executed with *args and non-reserved *kwargs as
arguments.
The callable will be executed using ProcPool, or in
a thread if ProcPool is not available.
Args:
to_execute (callable): If this is a callable, it will be
executed with *args and non-reserved *kwargs as arguments.
The callable will be executed using ProcPool, or in a thread
if ProcPool is not available.
reserved kwargs:
'at_return' -should point to a callable with one argument.
It will be called with the return value from
to_execute.
'at_return_kwargs' - this dictionary which be used as keyword
arguments to the at_return callback.
'at_err' - this will be called with a Failure instance if
there is an error in to_execute.
'at_err_kwargs' - this dictionary will be used as keyword
arguments to the at_err errback.
Kwargs:
at_return (callable): Should point to a callable with one
argument. It will be called with the return value from
to_execute.
at_return_kwargs (dict): This dictionary will be used as
keyword arguments to the at_return callback.
at_err (callable): This will be called with a Failure instance
if there is an error in to_execute.
at_err_kwargs (dict): This dictionary will be used as keyword
arguments to the at_err errback.
*args - these args will be used
as arguments for that function. If to_execute is a string
*args are not used.
*kwargs - these kwargs will be used
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.
Notes:
All other `*args` and `**kwargs` will be passed on to
`to_execute`. Run_async will relay executed code to a thread
or procpool.
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
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").
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.
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():
"""
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
@ -711,6 +876,14 @@ def check_evennia_dependencies():
def has_parent(basepath, obj):
"""
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:
return any(cls for cls in obj.__class__.mro()
@ -726,15 +899,15 @@ def mod_import(module):
A generic Python module loader.
Args:
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`)
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:
an imported module. If the input argument was already a model,
this is returned as-is, otherwise the path is parsed and imported.
Error:
returns `None`. The error is also logged.
module (module or None): An imported module. If the input argument was
already a module, this is returned as-is, otherwise the path is
parsed and imported. Returns `None` and logs error if import failed.
"""
def log_trace(errmsg=None):
@ -800,8 +973,21 @@ def mod_import(module):
def all_from_module(module):
"""
Return all global-level variables from a module as a dict.
Ignores modules and variable names starting with an underscore.
Return all global-level variables from a module.
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)
if not mod:
@ -812,23 +998,24 @@ def all_from_module(module):
def variable_from_module(module, variable=None, default=None):
"""
Retrieve a variable or list of variables from a module. The variable(s)
must be defined globally in the module. If no variable 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.
Retrieve a variable or list of variables from a module. The
variable(s) must be defined globally in the module. If no variable
is given (or a list entry is `None`), all global variables are
extracted from the module.
Args:
module (string or module)- python path, absolute path or a module.
variable (string or iterable) - single variable name or iterable of
variable names to extract.
default (string) - default value to use if a variable fails
to be extracted. Ignored if `variable` is not given.
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:
a single value or a list of values depending on the type of
`variable` argument. Errors in lists are replaced by the
`default` argument.
variables (value or list): A single value or a list of values
depending on if `variable` is given or not. Errors in lists
are replaced by the `default` argument.
"""
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
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)
if val:
@ -868,23 +1067,38 @@ def string_from_module(module, variable=None, default=None):
return result if result else default
return default
def random_string_from_module(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))
def fuzzy_import_from_module(path, variable, default=None, defaultpaths=None):
"""
Import a variable based on a fuzzy path. First the literal
`path` will be tried, then all given `defaultpaths` will be
prepended to see a match is found.
path - full or partial python path.
variable - name of variable to import from module.
defaultpaths - an iterable of python paths to attempt
in order if importing directly from
`path` doesn't work.
Args:
path (str): Full or partial python path.
variable (str): Name of variable to import from module.
default (string, optional): Default value to use if a variable fails to
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)
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 default
def class_from_module(path, defaultpaths=None):
"""
Return a class from a module, given the module's path. This is
primarily used to convert db_typeclass_path:s to classes.
if a list of `defaultpaths` is given, try subsequent runs by
prepending those paths to the given `path`.
Args:
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
if defaultpaths:
@ -949,14 +1173,10 @@ object_from_module = class_from_module
def init_new_player(player):
"""
Helper method to call all hooks, set flags etc on a newly created
player (and potentially their character, if it exists already).
Deprecated.
"""
# the FIRST_LOGIN flags are necessary for the system to call
# the relevant first-login hooks.
#if player.character:
# player.character.db.FIRST_LOGIN = True
player.db.FIRST_LOGIN = True
from evennia.utils import logger
logger.log_depmsg("evennia.utils.utils.init_new_player is DEPRECATED and should not be used.")
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
(but for letters).
The function returns a value 0...1 rating how similar the two strings
are. The strings can contain multiple words.
Args:
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))
vec1 = [string1.count(v) for v in vocabulary]