Make PEP8 cleanup of line spaces and character distances as well as indents

This commit is contained in:
Griatch 2017-08-19 23:16:36 +02:00
parent 7ff783fea1
commit b278337172
189 changed files with 2039 additions and 1583 deletions

View file

@ -142,7 +142,7 @@ class ANSIParser(object):
(r'|[C', ANSI_BACK_CYAN),
(r'|[W', ANSI_BACK_WHITE), # light grey background
(r'|[X', ANSI_BACK_BLACK) # pure black background
]
]
ansi_xterm256_bright_bg_map = [
# "bright" ANSI backgrounds using xterm256 since ANSI
@ -186,7 +186,7 @@ class ANSIParser(object):
# prepare regex matching
brightbg_sub = re.compile(r"|".join([r"(?<!\|)%s" % re.escape(tup[0])
for tup in ansi_xterm256_bright_bg_map]), re.DOTALL)
for tup in ansi_xterm256_bright_bg_map]), re.DOTALL)
xterm256_fg_sub = re.compile(r"|".join(xterm256_fg), re.DOTALL)
xterm256_bg_sub = re.compile(r"|".join(xterm256_bg), re.DOTALL)
xterm256_gfg_sub = re.compile(r"|".join(xterm256_gfg), re.DOTALL)
@ -207,6 +207,7 @@ class ANSIParser(object):
# escapes - these double-chars will be replaced with a single
# instance of each
ansi_escapes = re.compile(r"(%s)" % "|".join(ANSI_ESCAPES), re.DOTALL)
def sub_ansi(self, ansimatch):
"""
Replacer used by `re.sub` to replace ANSI
@ -285,7 +286,7 @@ class ANSIParser(object):
colval = 134 + ord(letter)
# ansi fallback logic expects r,g,b values in [0..5] range
gray = (ord(letter)-97)/5.0
gray = (ord(letter) - 97) / 5.0
red, green, blue = gray, gray, gray
if use_xterm256:
@ -532,6 +533,7 @@ def _spacing_preflight(func):
functions used for padding ANSIStrings.
"""
def wrapped(self, width, fillchar=None):
if fillchar is None:
fillchar = " "
@ -552,6 +554,7 @@ def _query_super(func_name):
of ANSIString.
"""
def wrapped(self, *args, **kwargs):
return getattr(self.clean(), func_name)(*args, **kwargs)
return wrapped
@ -562,6 +565,7 @@ 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)
try:
@ -588,6 +592,7 @@ def _transform(func_name):
with the resulting string.
"""
def wrapped(self, *args, **kwargs):
replacement_string = _query_super(func_name)(self, *args, **kwargs)
to_string = []
@ -1107,7 +1112,7 @@ class ANSIString(with_metaclass(ANSIMeta, unicode)):
if next < 0:
break
# Get character codes after the index as well.
res.append(self[next+bylen:end])
res.append(self[next + bylen:end])
end = next
maxsplit -= 1 # NB. if it's already < 0, it stays < 0
@ -1151,7 +1156,7 @@ class ANSIString(with_metaclass(ANSIMeta, unicode)):
ic += 1
ir1 += 1
rstripped = ""
ic, ir2 = nlen-1, len(raw)-1
ic, ir2 = nlen - 1, len(raw) - 1
while nrstripped:
if nlen - ic > nrstripped:
break
@ -1161,7 +1166,7 @@ class ANSIString(with_metaclass(ANSIMeta, unicode)):
ic -= 1
ir2 -= 1
rstripped = rstripped[::-1]
return ANSIString(lstripped + raw[ir1:ir2+1] + rstripped)
return ANSIString(lstripped + raw[ir1:ir2 + 1] + rstripped)
def lstrip(self, chars=None):
"""
@ -1214,7 +1219,7 @@ class ANSIString(with_metaclass(ANSIMeta, unicode)):
nlen = len(clean)
nrstripped = nlen - len(clean.rstrip(chars))
rstripped = ""
ic, ir2 = nlen-1, len(raw)-1
ic, ir2 = nlen - 1, len(raw) - 1
while nrstripped:
if nlen - ic > nrstripped:
break
@ -1224,7 +1229,7 @@ class ANSIString(with_metaclass(ANSIMeta, unicode)):
ic -= 1
ir2 -= 1
rstripped = rstripped[::-1]
return ANSIString(raw[:ir2+1] + rstripped)
return ANSIString(raw[:ir2 + 1] + rstripped)
def join(self, iterable):
"""

View file

@ -248,6 +248,7 @@ class BatchCommandProcessor(object):
This class implements a batch-command processor.
"""
def parse_file(self, pythonpath):
"""
This parses the lines of a batchfile according to the following
@ -413,5 +414,6 @@ class BatchCodeProcessor(object):
return err
return None
BATCHCMD = BatchCommandProcessor()
BATCHCODE = BatchCodeProcessor()

View file

@ -122,6 +122,7 @@ def create_object(typeclass=None, key=None, location=None, home=None,
new_object.save()
return new_object
# alias for create_object
object = create_object
@ -179,14 +180,22 @@ def create_script(typeclass=None, key=None, obj=None, account=None, locks=None,
# validate input
kwarg = {}
if key: kwarg["db_key"] = key
if account: kwarg["db_account"] = dbid_to_obj(account, _ScriptDB)
if obj: kwarg["db_obj"] = dbid_to_obj(obj, _ScriptDB)
if interval: kwarg["db_interval"] = interval
if start_delay: kwarg["db_start_delay"] = start_delay
if repeats: kwarg["db_repeats"] = repeats
if persistent: kwarg["db_persistent"] = persistent
if desc: kwarg["db_desc"] = desc
if key:
kwarg["db_key"] = key
if account:
kwarg["db_account"] = dbid_to_obj(account, _ScriptDB)
if obj:
kwarg["db_obj"] = dbid_to_obj(obj, _ScriptDB)
if interval:
kwarg["db_interval"] = interval
if start_delay:
kwarg["db_start_delay"] = start_delay
if repeats:
kwarg["db_repeats"] = repeats
if persistent:
kwarg["db_persistent"] = persistent
if desc:
kwarg["db_desc"] = desc
# create new instance
new_script = typeclass(**kwarg)
@ -201,6 +210,7 @@ def create_script(typeclass=None, key=None, obj=None, account=None, locks=None,
new_script.save()
return new_script
# alias
script = create_script
@ -250,6 +260,8 @@ def create_help_entry(key, entrytext, category="General", locks=None, aliases=No
except Exception:
logger.log_trace()
return None
# alias
help_entry = create_help_entry
@ -301,6 +313,8 @@ def create_message(senderobj, message, channels=None, receivers=None, locks=None
new_message.locks.add(locks)
new_message.save()
return new_message
message = create_message
@ -348,6 +362,7 @@ def create_channel(key, aliases=None, desc=None,
new_channel.save()
return new_channel
channel = create_channel
@ -357,11 +372,10 @@ channel = create_channel
def create_account(key, email, password,
typeclass=None,
is_superuser=False,
locks=None, permissions=None,
report_to=None):
typeclass=None,
is_superuser=False,
locks=None, permissions=None,
report_to=None):
"""
This creates a new account.
@ -416,8 +430,8 @@ def create_account(key, email, password,
now = timezone.now()
email = typeclass.objects.normalize_email(email)
new_account = typeclass(username=key, email=email,
is_staff=is_superuser, is_superuser=is_superuser,
last_login=now, date_joined=now)
is_staff=is_superuser, is_superuser=is_superuser,
last_login=now, date_joined=now)
new_account.set_password(password)
new_account._createdict = dict(locks=locks, permissions=permissions, report_to=report_to)
# saving will trigger the signal that calls the
@ -426,5 +440,6 @@ def create_account(key, email, password,
new_account.save()
return new_account
# alias
account = create_account

View file

@ -56,13 +56,22 @@ def _get_mysql_db_version():
# initialization and helpers
_GA = object.__getattribute__
_SA = object.__setattr__
_FROM_MODEL_MAP = None
_TO_MODEL_MAP = None
_SESSION_HANDLER = None
_IS_PACKED_DBOBJ = lambda o: type(o) == tuple and len(o) == 4 and o[0] == '__packed_dbobj__'
_IS_PACKED_SESSION = lambda o: type(o) == tuple and len(o) == 3 and o[0] == '__packed_session__'
def _IS_PACKED_DBOBJ(o):
return isinstance(o, tuple) and len(o) == 4 and o[0] == '__packed_dbobj__'
def _IS_PACKED_SESSION(o):
return isinstance(o, tuple) and len(o) == 3 and o[0] == '__packed_session__'
if uses_database("mysql") and _get_mysql_db_version() < '5.6.4':
# mysql <5.6.4 don't support millisecond precision
_DATESTRING = "%Y:%m:%d-%H:%M:%S:000000"
@ -112,6 +121,7 @@ def _init_globals():
def _save(method):
"""method decorator that saves data to Attribute"""
def save_wrapper(self, *args, **kwargs):
self.__doc__ = method.__doc__
ret = method(self, *args, **kwargs)
@ -127,6 +137,7 @@ class _SaverMutable(object):
obj.db.mylist[1][2] = "test" (allocation to a nested list)
will not save the updated value to the database.
"""
def __init__(self, *args, **kwargs):
"""store all properties for tracking the tree"""
self._parent = kwargs.pop("_parent", None)
@ -196,6 +207,7 @@ class _SaverList(_SaverMutable, MutableSequence):
"""
A list that saves itself to an Attribute when updated.
"""
def __init__(self, *args, **kwargs):
super(_SaverList, self).__init__(*args, **kwargs)
self._data = list()
@ -223,6 +235,7 @@ class _SaverDict(_SaverMutable, MutableMapping):
"""
A dict that stores changes to an Attribute when updated
"""
def __init__(self, *args, **kwargs):
super(_SaverDict, self).__init__(*args, **kwargs)
self._data = dict()
@ -235,6 +248,7 @@ class _SaverSet(_SaverMutable, MutableSet):
"""
A set that saves to an Attribute when updated
"""
def __init__(self, *args, **kwargs):
super(_SaverSet, self).__init__(*args, **kwargs)
self._data = set()
@ -255,6 +269,7 @@ class _SaverOrderedDict(_SaverMutable, MutableMapping):
"""
An ordereddict that can be saved and operated on.
"""
def __init__(self, *args, **kwargs):
super(_SaverOrderedDict, self).__init__(*args, **kwargs)
self._data = OrderedDict()
@ -267,6 +282,7 @@ class _SaverDeque(_SaverMutable):
"""
A deque that can be saved and operated on.
"""
def __init__(self, *args, **kwargs):
super(_SaverDeque, self).__init__(*args, **kwargs)
self._data = deque()

View file

@ -378,7 +378,7 @@ class CmdLineInput(CmdEditorBase):
indent = "off"
self.caller.msg("|b%02i|||n (|g%s|n) %s" % (
cline, indent, raw(line)))
cline, indent, raw(line)))
else:
self.caller.msg("|b%02i|||n %s" % (cline, raw(self.args)))
@ -643,7 +643,7 @@ class CmdEditorGroup(CmdEditorBase):
indent = editor._indent
if indent >= 0:
caller.msg("Decreased indentation: new indentation is {}.".format(
indent))
indent))
else:
caller.msg("|rManual indentation is OFF.|n Use := to turn it on.")
else:
@ -655,7 +655,7 @@ class CmdEditorGroup(CmdEditorBase):
indent = editor._indent
if indent >= 0:
caller.msg("Increased indentation: new indentation is {}.".format(
indent))
indent))
else:
caller.msg("|rManual indentation is OFF.|n Use := to turn it on.")
else:
@ -780,7 +780,7 @@ class EvEditor(object):
caller.attributes.add("_eveditor_buffer_temp", (self._buffer, self._undo_buffer))
caller.attributes.add("_eveditor_unsaved", False)
caller.attributes.add("_eveditor_indent", 0)
except Exception, err:
except Exception as err:
caller.msg(_ERROR_PERSISTENT_SAVING.format(error=err))
logger.log_trace(_TRACE_PERSISTENT_SAVING)
persistent = False
@ -929,7 +929,7 @@ class EvEditor(object):
nchars = len(buf)
sep = self._sep
header = "|n" + sep * 10 + "Line Editor [%s]" % self._key + sep * (_DEFAULT_WIDTH-20-len(self._key))
header = "|n" + sep * 10 + "Line Editor [%s]" % self._key + sep * (_DEFAULT_WIDTH - 20 - len(self._key))
footer = "|n" + sep * 10 +\
"[l:%02i w:%03i c:%04i]" % (nlines, nwords, nchars) + sep * 12 + "(:h for help)" + sep * 28
if linenums:
@ -956,10 +956,10 @@ class EvEditor(object):
"""
keywords = {
"elif ": ["if "],
"else:": ["if ", "try"],
"except": ["try:"],
"finally:": ["try:"],
"elif ": ["if "],
"else:": ["if ", "try"],
"except": ["try:"],
"finally:": ["try:"],
}
opening_tags = ("if ", "try:", "for ", "while ")

View file

@ -166,6 +166,7 @@ def _to_ansi(obj, regexable=False):
else:
return ANSIString(to_unicode(obj), regexable=regexable)
class EvForm(object):
"""
This object is instantiated with a text file and parses
@ -174,6 +175,7 @@ class EvForm(object):
EvCell or Tables.
"""
def __init__(self, filename=None, cells=None, tables=None, form=None, **kwargs):
"""
Initiate the form
@ -194,7 +196,7 @@ class EvForm(object):
self.filename = filename
self.input_form_dict = form
self.cells_mapping = dict((to_str(key, force_string=True), value) for key, value in cells.items()) if cells else {}
self.cells_mapping = dict((to_str(key, force_string=True), value) for key, value in cells.items()) if cells else {}
self.tables_mapping = dict((to_str(key, force_string=True), value) for key, value in tables.items()) if tables else {}
self.cellchar = "x"
@ -232,7 +234,7 @@ class EvForm(object):
table_coords = {}
# Locate the identifier tags and the horizontal end coords for all forms
re_cellchar = re.compile(r"%s+([^%s%s]+)%s+" % (cellchar, INVALID_FORMCHARS, cellchar, cellchar))
re_cellchar = re.compile(r"%s+([^%s%s]+)%s+" % (cellchar, INVALID_FORMCHARS, cellchar, cellchar))
re_tablechar = re.compile(r"%s+([^%s%s|+])%s+" % (tablechar, INVALID_FORMCHARS, tablechar, tablechar))
for iy, line in enumerate(_to_ansi(form, regexable=True)):
# find cells
@ -262,16 +264,16 @@ class EvForm(object):
# scan up to find top of rectangle
dy_up = 0
if iy > 0:
for i in range(1,iy):
if all(form[iy-i][ix] == cellchar for ix in range(leftix, rightix)):
for i in range(1, iy):
if all(form[iy - i][ix] == cellchar for ix in range(leftix, rightix)):
dy_up += 1
else:
break
# find bottom edge of rectangle
dy_down = 0
if iy < nform-1:
for i in range(1,nform-iy-1):
if all(form[iy+i][ix] == cellchar for ix in range(leftix, rightix)):
if iy < nform - 1:
for i in range(1, nform - iy - 1):
if all(form[iy + i][ix] == cellchar for ix in range(leftix, rightix)):
dy_down += 1
else:
break
@ -284,13 +286,13 @@ class EvForm(object):
# we have all the coordinates we need. Create EvCell.
data = self.cells_mapping.get(key, "")
#if key == "1":
# if key == "1":
options = { "pad_left":0, "pad_right":0, "pad_top":0, "pad_bottom":0, "align":"l", "valign":"t", "enforce_size":True}
options = {"pad_left": 0, "pad_right": 0, "pad_top": 0, "pad_bottom": 0, "align": "l", "valign": "t", "enforce_size": True}
options.update(custom_options)
#if key=="4":
# if key=="4":
mapping[key] = (iyup, leftix, width, height, EvCell(data, width=width, height=height,**options))
mapping[key] = (iyup, leftix, width, height, EvCell(data, width=width, height=height, **options))
# get rectangles and assign Tables
for key, (iy, leftix, rightix) in table_coords.items():
@ -298,16 +300,16 @@ class EvForm(object):
# scan up to find top of rectangle
dy_up = 0
if iy > 0:
for i in range(1,iy):
if all(form[iy-i][ix] == tablechar for ix in range(leftix, rightix)):
for i in range(1, iy):
if all(form[iy - i][ix] == tablechar for ix in range(leftix, rightix)):
dy_up += 1
else:
break
# find bottom edge of rectangle
dy_down = 0
if iy < nform-1:
for i in range(1,nform-iy-1):
if all(form[iy+i][ix] == tablechar for ix in range(leftix, rightix)):
if iy < nform - 1:
for i in range(1, nform - iy - 1):
if all(form[iy + i][ix] == tablechar for ix in range(leftix, rightix)):
dy_down += 1
else:
break
@ -321,8 +323,8 @@ class EvForm(object):
# we have all the coordinates we need. Create Table.
table = self.tables_mapping.get(key, None)
options = { "pad_left":0, "pad_right":0, "pad_top":0, "pad_bottom":0,
"align":"l", "valign":"t", "enforce_size":True}
options = {"pad_left": 0, "pad_right": 0, "pad_top": 0, "pad_bottom": 0,
"align": "l", "valign": "t", "enforce_size": True}
options.update(custom_options)
if table:
@ -343,9 +345,9 @@ class EvForm(object):
# rect is a list of <height> lines, each <width> wide
rect = cell_or_table.get()
for il, rectline in enumerate(rect):
formline = form[iy0+il]
formline = form[iy0 + il]
# insert new content, replacing old
form[iy0+il] = formline[:ix0] + rectline + formline[ix0+width:]
form[iy0 + il] = formline[:ix0] + rectline + formline[ix0 + width:]
return form
def map(self, cells=None, tables=None, **kwargs):
@ -366,7 +368,7 @@ class EvForm(object):
kwargs.pop("width", None)
kwargs.pop("height", None)
new_cells = dict((to_str(key, force_string=True), value) for key, value in cells.items()) if cells else {}
new_cells = dict((to_str(key, force_string=True), value) for key, value in cells.items()) if cells else {}
new_tables = dict((to_str(key, force_string=True), value) for key, value in tables.items()) if tables else {}
self.cells_mapping.update(new_cells)
@ -424,6 +426,7 @@ class EvForm(object):
"prints the form"
return unicode(ANSIString("\n").join([line for line in self.form]))
def _test():
"test evform. This is used by the unittest system."
form = EvForm("evennia.utils.evform_test")
@ -434,18 +437,18 @@ def _test():
3: "A sturdy fellow",
4: 12,
5: 10,
6: 5,
6: 5,
7: 18,
8: 10,
9: 3})
9: 3})
# create the EvTables
tableA = EvTable("HP","MV","MP",
table=[["**"], ["*****"], ["***"]],
border="incols")
tableA = EvTable("HP", "MV", "MP",
table=[["**"], ["*****"], ["***"]],
border="incols")
tableB = EvTable("Skill", "Value", "Exp",
table=[["Shooting", "Herbalism", "Smithing"],
[12,14,9],["550/1200", "990/1400", "205/900"]],
border="incols")
table=[["Shooting", "Herbalism", "Smithing"],
[12, 14, 9], ["550/1200", "990/1400", "205/900"]],
border="incols")
# add the tables to the proper ids in the form
form.map(tables={"A": tableA,
"B": tableB})

View file

@ -28,5 +28,3 @@ FORM = """
| | |
-----------`-------------------------------------
"""

View file

@ -258,7 +258,7 @@ class CmdEvMenuNode(Command):
if not menu:
# can't restore from a session
err = "Menu object not found as %s.ndb._menutree!" % orig_caller
orig_caller.msg(err) # don't give the session as a kwarg here, direct to original
orig_caller.msg(err) # don't give the session as a kwarg here, direct to original
raise EvMenuError(err)
# we must do this after the caller with the menui has been correctly identified since it
# can be either Account, Object or Session (in the latter case this info will be superfluous).
@ -299,6 +299,7 @@ class EvMenu(object):
a menufile.py instruction.
"""
def __init__(self, caller, menudata, startnode="start",
cmdset_mergetype="Replace", cmdset_priority=1,
auto_quit=True, auto_look=True, auto_help=True,
@ -419,8 +420,8 @@ class EvMenu(object):
# assign kwargs as initialization vars on ourselves.
if set(("_startnode", "_menutree", "_session", "_persistent",
"cmd_on_exit", "default", "nodetext", "helptext",
"options", "cmdset_mergetype", "auto_quit")).intersection(set(kwargs.keys())):
"cmd_on_exit", "default", "nodetext", "helptext",
"options", "cmdset_mergetype", "auto_quit")).intersection(set(kwargs.keys())):
raise RuntimeError("One or more of the EvMenu `**kwargs` is reserved by EvMenu for internal use.")
for key, val in kwargs.iteritems():
setattr(self, key, val)
@ -686,7 +687,7 @@ class EvMenu(object):
goto, execute = dic.get("goto", None), dic.get("exec", None)
self.default = (goto, execute)
else:
keys = list(make_iter(dic.get("key", str(inum+1).strip())))
keys = list(make_iter(dic.get("key", str(inum + 1).strip())))
desc = dic.get("desc", dic.get("text", _ERR_NO_OPTION_DESC).strip())
goto, execute = dic.get("goto", None), dic.get("exec", None)
if keys:
@ -810,14 +811,14 @@ class EvMenu(object):
# add a default white color to key
table.append(" |lc%s|lt|w%s|n|le: %s" % (raw_key, raw_key, desc))
ncols = (_MAX_TEXT_WIDTH // table_width_max) + 1 # number of ncols
ncols = (_MAX_TEXT_WIDTH // table_width_max) + 1 # number of ncols
# get the amount of rows needed (start with 4 rows)
nrows = 4
while nrows * ncols < nlist:
nrows += 1
ncols = nlist // nrows # number of full columns
nlastcol = nlist % nrows # number of elements in last column
ncols = nlist // nrows # number of full columns
nlastcol = nlist % nrows # number of elements in last column
# get the final column count
ncols = ncols + 1 if nlastcol > 0 else ncols
@ -826,7 +827,7 @@ class EvMenu(object):
table.extend([" " for i in range(nrows - nlastcol)])
# build the actual table grid
table = [table[icol * nrows : (icol * nrows) + nrows] for icol in range(0, ncols)]
table = [table[icol * nrows: (icol * nrows) + nrows] for icol in range(0, ncols)]
# adjust the width of each column
for icol in range(len(table)):
@ -857,7 +858,6 @@ class EvMenu(object):
return separator1 + "|n" + nodetext + "|n" + separator2 + "|n" + optionstext
# -------------------------------------------------------------------------------------------------
#
# Simple input shortcuts

View file

@ -44,7 +44,7 @@ _SCREEN_HEIGHT = settings.CLIENT_DEFAULT_HEIGHT
# text
_DISPLAY = \
"""{text}
"""{text}
(|wmore|n [{pageno}/{pagemax}] retur|wn|n|||wb|nack|||wt|nop|||we|nnd|||wq|nuit)"""
@ -82,6 +82,7 @@ class CmdMore(Command):
# return or n, next
more.page_next()
class CmdMoreLook(Command):
"""
Override look to display window and prevent OOCLook from firing
@ -89,6 +90,7 @@ class CmdMoreLook(Command):
key = "look"
aliases = ["l"]
auto_help = False
def func(self):
"""
Implement the command
@ -118,8 +120,9 @@ class EvMore(object):
"""
The main pager object
"""
def __init__(self, caller, text, always_page=False, session=None,
justify_kwargs=None, exit_on_lastpage=False, **kwargs):
justify_kwargs=None, exit_on_lastpage=False, **kwargs):
"""
Initialization of the text handler.
@ -159,8 +162,8 @@ class EvMore(object):
self._session = session
# set up individual pages for different sessions
height = max(4, session.protocol_flags.get("SCREENHEIGHT", {0:_SCREEN_HEIGHT})[0] - 4)
width = session.protocol_flags.get("SCREENWIDTH", {0:_SCREEN_WIDTH})[0]
height = max(4, session.protocol_flags.get("SCREENHEIGHT", {0: _SCREEN_HEIGHT})[0] - 4)
width = session.protocol_flags.get("SCREENWIDTH", {0: _SCREEN_WIDTH})[0]
if justify_kwargs is False:
# no justification. Simple division by line
@ -183,7 +186,7 @@ class EvMore(object):
# always limit number of chars to 10 000 per page
height = min(10000 // max(1, width), height)
self._pages = ["\n".join(lines[i:i+height]) for i in range(0, len(lines), height)]
self._pages = ["\n".join(lines[i:i + height]) for i in range(0, len(lines), height)]
self._npages = len(self._pages)
self._npos = 0
@ -246,7 +249,6 @@ class EvMore(object):
if self.exit_on_lastpage and self._pos == self._pos >= self._npages - 1:
self.page_quit()
def page_back(self):
"""
Scroll the text back up, at the most to the top.
@ -283,5 +285,4 @@ def msg(caller, text="", always_page=False, session=None, justify_kwargs=None, *
"""
EvMore(caller, text, always_page=always_page, session=session,
justify_kwargs=justify_kwargs, **kwargs)
justify_kwargs=justify_kwargs, **kwargs)

View file

@ -322,6 +322,7 @@ class EvCell(object):
and resize as needed.
"""
def __init__(self, data, **kwargs):
"""
Args:
@ -472,7 +473,7 @@ class EvCell(object):
"""
if m_len(text) > width:
crop_string = self.crop_string
return text[:width-m_len(crop_string)] + crop_string
return text[:width - m_len(crop_string)] + crop_string
return text
def _reformat(self):
@ -661,7 +662,7 @@ class EvCell(object):
left = self.border_left_char * self.border_left + ANSIString('|n')
right = ANSIString('|n') + self.border_right_char * self.border_right
cwidth = self.width + self.pad_left + self.pad_right + max(0, self.border_left-1) + max(0, self.border_right-1)
cwidth = self.width + self.pad_left + self.pad_right + max(0, self.border_left - 1) + max(0, self.border_right - 1)
vfill = self.corner_top_left_char if left else ""
vfill += cwidth * self.border_top_char
@ -849,7 +850,7 @@ class EvCell(object):
return unicode(ANSIString("\n").join(self.formatted))
## EvColumn class
# EvColumn class
class EvColumn(object):
"""
@ -861,7 +862,8 @@ class EvColumn(object):
incorporated into an EvTable (like EvCells)
"""
def __init__(self, *args, **kwargs):
def __init__(self, *args, **kwargs):
"""
Args:
Text for each row in the column
@ -918,7 +920,7 @@ class EvColumn(object):
self.column.extend([EvCell(data, **self.options) for data in args])
else:
# insert cells before given index
ypos = min(len(self.column)-1, max(0, int(ypos)))
ypos = min(len(self.column) - 1, max(0, int(ypos)))
new_cells = [EvCell(data, **self.options) for data in args]
self.column = self.column[:ypos] + new_cells + self.column[ypos:]
# self._balance(**kwargs)
@ -1223,7 +1225,7 @@ class EvTable(object):
"""
Add borders to table. This is called from self._balance.
"""
nx, ny = self.ncols-1, self.nrows-1
nx, ny = self.ncols - 1, self.nrows - 1
options = self.options
for ix, col in enumerate(self.worktable):
for iy, cell in enumerate(col):
@ -1254,7 +1256,7 @@ class EvTable(object):
self.worktable[icol].reformat(**options)
if nrow < nrowmax:
# add more rows to too-short columns
empty_rows = ["" for _ in range(nrowmax-nrow)]
empty_rows = ["" for _ in range(nrowmax - nrow)]
self.worktable[icol].add_rows(*empty_rows)
self.ncols = ncols
self.nrows = nrowmax
@ -1441,7 +1443,7 @@ class EvTable(object):
self.table.append(column)
else:
# insert column
xpos = min(wtable-1, max(0, int(xpos)))
xpos = min(wtable - 1, max(0, int(xpos)))
self.table.insert(xpos, column)
self.ncols += 1
# self._balance()
@ -1491,7 +1493,7 @@ class EvTable(object):
col.add_rows(row[icol], **options)
else:
# insert row elsewhere
ypos = min(htable-1, max(0, int(ypos)))
ypos = min(htable - 1, max(0, int(ypos)))
for icol, col in enumerate(self.table):
col.add_rows(row[icol], ypos=ypos, **options)
self.nrows += 1
@ -1575,9 +1577,9 @@ def _test():
print(unicode(table))
return table
def _test2():
table = EvTable("|yHeading1|n", "|B|[GHeading2|n", "Heading3")
for i in range(100):
table.add_row("This is col 0, row %i" % i, "|gThis is col 1, row |w%i|n|g.|n" % i, "This is col 2, row %i" % i)
return table

View file

@ -86,7 +86,7 @@ def server_epoch():
global _SERVER_EPOCH
if not _SERVER_EPOCH:
_SERVER_EPOCH = ServerConfig.objects.conf("server_epoch", default=None) \
or time.time() - runtime()
or time.time() - runtime()
return _SERVER_EPOCH
@ -224,12 +224,12 @@ def schedule(callback, repeat=False, sec=None, min=None,
repeats=-1 if repeat else 1)
script.db.callback = callback
script.db.gametime = {
"sec": sec,
"min": min,
"hour": hour,
"day": day,
"month": month,
"year": year,
"sec": sec,
"min": min,
"hour": hour,
"day": day,
"month": month,
"year": year,
}
return script

View file

@ -3,6 +3,7 @@ IDmapper extension to the default manager.
"""
from django.db.models.manager import Manager
class SharedMemoryManager(Manager):
# CL: this ensures our manager is used when accessing instances via
# ForeignKey etc. (see docs)

View file

@ -10,7 +10,10 @@ from __future__ import absolute_import, division
from builtins import object
from future.utils import listitems, listvalues, with_metaclass
import os, threading, gc, time
import os
import threading
import gc
import time
from weakref import WeakValueDictionary
from twisted.internet.reactor import callFromThread
from django.core.exceptions import ObjectDoesNotExist, FieldError
@ -22,7 +25,7 @@ from evennia.utils.utils import dbref, get_evennia_pids, to_str
from .manager import SharedMemoryManager
AUTO_FLUSH_MIN_INTERVAL = 60.0 * 5 # at least 5 mins between cache flushes
AUTO_FLUSH_MIN_INTERVAL = 60.0 * 5 # at least 5 mins between cache flushes
_GA = object.__getattribute__
_SA = object.__setattr__
@ -39,9 +42,10 @@ PROC_MODIFIED_OBJS = WeakValueDictionary()
# subprocess or not)
_SELF_PID = os.getpid()
_SERVER_PID, _PORTAL_PID = get_evennia_pids()
_IS_SUBPROCESS = (_SERVER_PID and _PORTAL_PID) and not _SELF_PID in (_SERVER_PID, _PORTAL_PID)
_IS_SUBPROCESS = (_SERVER_PID and _PORTAL_PID) and _SELF_PID not in (_SERVER_PID, _PORTAL_PID)
_IS_MAIN_THREAD = threading.currentThread().getName() == "MainThread"
class SharedMemoryModelBase(ModelBase):
# CL: upstream had a __new__ method that skipped ModelBase's __new__ if
# SharedMemoryModelBase was not in the model class's ancestors. It's not
@ -69,7 +73,6 @@ class SharedMemoryModelBase(ModelBase):
cls.cache_instance(cached_instance, new=True)
return cached_instance
def _prepare(cls):
"""
Prepare the cache, making sure that proxies of the same db base
@ -102,7 +105,7 @@ class SharedMemoryModelBase(ModelBase):
"""
attrs["typename"] = cls.__name__
attrs["path"] = "%s.%s" % (attrs["__module__"], name)
attrs["path"] = "%s.%s" % (attrs["__module__"], name)
attrs["_is_deleted"] = False
# set up the typeclass handling only if a variable _is_typeclass is set on the class
@ -113,14 +116,17 @@ class SharedMemoryModelBase(ModelBase):
if _GA(cls, "_is_deleted"):
raise ObjectDoesNotExist("Cannot access %s: Hosting object was already deleted." % fname)
return _GA(cls, fieldname)
def _get_foreign(cls, fname):
"Wrapper for returning foreignkey fields"
if _GA(cls, "_is_deleted"):
raise ObjectDoesNotExist("Cannot access %s: Hosting object was already deleted." % fname)
return _GA(cls, fieldname)
def _set_nonedit(cls, fname, value):
"Wrapper for blocking editing of field"
raise FieldError("Field %s cannot be edited." % fname)
def _set(cls, fname, value):
"Wrapper for setting database field"
if _GA(cls, "_is_deleted"):
@ -130,6 +136,7 @@ class SharedMemoryModelBase(ModelBase):
# primary key assigned already (won't be set when first creating object)
update_fields = [fname] if _GA(cls, "_get_pk_val")(_GA(cls, "_meta")) is not None else None
_GA(cls, "save")(update_fields=update_fields)
def _set_foreign(cls, fname, value):
"Setter only used on foreign key relations, allows setting with #dbref"
if _GA(cls, "_is_deleted"):
@ -153,9 +160,11 @@ class SharedMemoryModelBase(ModelBase):
# primary key assigned already (won't be set when first creating object)
update_fields = [fname] if _GA(cls, "_get_pk_val")(_GA(cls, "_meta")) is not None else None
_GA(cls, "save")(update_fields=update_fields)
def _del_nonedit(cls, fname):
"wrapper for not allowing deletion"
raise FieldError("Field %s cannot be edited." % fname)
def _del(cls, fname):
"Wrapper for clearing database field - sets it to None"
_SA(cls, fname, None)
@ -163,29 +172,31 @@ class SharedMemoryModelBase(ModelBase):
_GA(cls, "save")(update_fields=update_fields)
# wrapper factories
fget = lambda cls: _get(cls, fieldname)
def fget(cls): return _get(cls, fieldname)
if not editable:
fset = lambda cls, val: _set_nonedit(cls, fieldname, val)
def fset(cls, val): return _set_nonedit(cls, fieldname, val)
elif foreignkey:
fget = lambda cls: _get_foreign(cls, fieldname)
fset = lambda cls, val: _set_foreign(cls, fieldname, val)
def fget(cls): return _get_foreign(cls, fieldname)
def fset(cls, val): return _set_foreign(cls, fieldname, val)
else:
fset = lambda cls, val: _set(cls, fieldname, val)
fdel = lambda cls: _del(cls, fieldname) if editable else _del_nonedit(cls,fieldname)
def fset(cls, val): return _set(cls, fieldname, val)
def fdel(cls): return _del(cls, fieldname) if editable else _del_nonedit(cls, fieldname)
# set docstrings for auto-doc
fget.__doc__ = "A wrapper for getting database field `%s`." % fieldname
fset.__doc__ = "A wrapper for setting (and saving) database field `%s`." % fieldname
fdel.__doc__ = "A wrapper for deleting database field `%s`." % fieldname
# assigning
attrs[wrappername] = property(fget, fset, fdel)
#type(cls).__setattr__(cls, wrappername, property(fget, fset, fdel))#, doc))
# type(cls).__setattr__(cls, wrappername, property(fget, fset, fdel))#, doc))
# exclude some models that should not auto-create wrapper fields
if cls.__name__ in ("ServerConfig", "TypeNick"):
return
# dynamically create the wrapper properties for all fields not already handled (manytomanyfields are always handlers)
for fieldname, field in ((fname, field) for fname, field in listitems(attrs)
if fname.startswith("db_") and type(field).__name__ != "ManyToManyField"):
if fname.startswith("db_") and type(field).__name__ != "ManyToManyField"):
foreignkey = type(field).__name__ == "ForeignKey"
wrappername = "dbid" if fieldname == "id" else fieldname.replace("db_", "", 1)
if wrappername not in attrs:
@ -394,7 +405,7 @@ class SharedMemoryModel(with_metaclass(SharedMemoryModelBase, Model)):
for fieldname in kwargs.get("update_fields"))
else:
# meta.fields are already field objects; get them all
new =True
new = True
update_fields = self._meta.fields
for field in update_fields:
fieldname = field.name
@ -454,7 +465,9 @@ def flush_cache(**kwargs):
cls.flush_instance_cache()
# run the python garbage collector
return gc.collect()
#request_finished.connect(flush_cache)
# request_finished.connect(flush_cache)
post_migrate.connect(flush_cache)
@ -467,6 +480,8 @@ def flush_cached_instance(sender, instance, **kwargs):
if not hasattr(instance, 'flush_cached_instance'):
return
sender.flush_cached_instance(instance, force=True)
pre_delete.connect(flush_cached_instance)
@ -478,10 +493,14 @@ def update_cached_instance(sender, instance, **kwargs):
if not hasattr(instance, 'cache_instance'):
return
sender.cache_instance(instance)
post_save.connect(update_cached_instance)
LAST_FLUSH = None
def conditional_flush(max_rmem, force=False):
"""
Flush the cache if the estimated memory usage exceeds `max_rmem`.
@ -530,8 +549,8 @@ def conditional_flush(max_rmem, force=False):
if ((now - LAST_FLUSH) < AUTO_FLUSH_MIN_INTERVAL) and not force:
# too soon after last flush.
logger.log_warn("Warning: Idmapper flush called more than "\
"once in %s min interval. Check memory usage." % (AUTO_FLUSH_MIN_INTERVAL/60.0))
logger.log_warn("Warning: Idmapper flush called more than "
"once in %s min interval. Check memory usage." % (AUTO_FLUSH_MIN_INTERVAL / 60.0))
return
if os.name == "nt":
@ -549,6 +568,7 @@ def conditional_flush(max_rmem, force=False):
flush_cache()
LAST_FLUSH = now
def cache_size(mb=True):
"""
Calculate statistics about the cache.
@ -564,8 +584,9 @@ def cache_size(mb=True):
total_num, {objclass:total_num, ...}
"""
numtotal = [0] # use mutable to keep reference through recursion
numtotal = [0] # use mutable to keep reference through recursion
classdict = {}
def get_recurse(submodels):
for submodel in submodels:
subclasses = submodel.__subclasses__()

View file

@ -6,22 +6,27 @@ from django.test import TestCase
from .models import SharedMemoryModel
from django.db import models
class Category(SharedMemoryModel):
name = models.CharField(max_length=32)
class RegularCategory(models.Model):
name = models.CharField(max_length=32)
class Article(SharedMemoryModel):
name = models.CharField(max_length=32)
category = models.ForeignKey(Category)
category2 = models.ForeignKey(RegularCategory)
class RegularArticle(models.Model):
name = models.CharField(max_length=32)
category = models.ForeignKey(Category)
category2 = models.ForeignKey(RegularCategory)
class SharedMemorysTest(TestCase):
# TODO: test for cross model relation (singleton to regular)
@ -58,7 +63,7 @@ class SharedMemorysTest(TestCase):
#article_list = Article.objects.all().select_related('category')
#last_article = article_list[0]
#for article in article_list[1:]:
# for article in article_list[1:]:
# self.assertEquals(article.category2 is last_article.category2, False)
# last_article = article
@ -70,5 +75,3 @@ class SharedMemorysTest(TestCase):
pk = article.pk
article.delete()
self.assertEquals(pk not in Article.__instance_cache__, True)

View file

@ -161,7 +161,7 @@ def clr(*args, **kwargs):
# found. This will be overloaded by any nomatch function defined in
# the imported modules.
_INLINE_FUNCS = {"nomatch": lambda *args, **kwargs: "<UKNOWN>",
"stackfull": lambda *args, **kwargs: "\n (not parsed: inlinefunc stack size exceeded.)"}
"stackfull": lambda *args, **kwargs: "\n (not parsed: inlinefunc stack size exceeded.)"}
# load custom inline func modules.
@ -172,7 +172,7 @@ for module in utils.make_iter(settings.INLINEFUNC_MODULES):
if module == "server.conf.inlinefuncs":
# a temporary warning since the default module changed name
raise ImportError("Error: %s\nPossible reason: mygame/server/conf/inlinefunc.py should "
"be renamed to mygame/server/conf/inlinefuncs.py (note the S at the end)." % err)
"be renamed to mygame/server/conf/inlinefuncs.py (note the S at the end)." % err)
else:
raise
@ -189,7 +189,7 @@ except AttributeError:
# regex definitions
_RE_STARTTOKEN = re.compile(r"(?<!\\)\$(\w+)\(") # unescaped $funcname{ (start of function call)
_RE_STARTTOKEN = re.compile(r"(?<!\\)\$(\w+)\(") # unescaped $funcname{ (start of function call)
_RE_TOKEN = re.compile(r"""
(?<!\\)\'\'\'(?P<singlequote>.*?)(?<!\\)\'\'\'| # unescaped single-triples (escapes all inside them)
@ -199,12 +199,13 @@ _RE_TOKEN = re.compile(r"""
(?P<start>(?<!\\)\$\w+\()| # unescaped $funcname( (start of function call)
(?P<escaped>\\'|\\"|\\\)|\\$\w+\()| # escaped tokens should re-appear in text
(?P<rest>[\w\s.-\/#!%\^&\*;:=\-_`~\|\(}{\[\]]+|\"{1}|\'{1}) # everything else should also be included""",
re.UNICODE + re.IGNORECASE + re.VERBOSE + re.DOTALL)
re.UNICODE + re.IGNORECASE + re.VERBOSE + re.DOTALL)
# Cache for function lookups.
_PARSING_CACHE = utils.LimitedSizeOrderedDict(size_limit=1000)
class ParseStack(list):
"""
Custom stack that always concatenates strings together when the
@ -221,6 +222,7 @@ class ParseStack(list):
string + string]
"""
def __init__(self, *args, **kwargs):
super(ParseStack, self).__init__(*args, **kwargs)
# always start stack with the empty string
@ -247,6 +249,7 @@ class ParseStack(list):
class InlinefuncError(RuntimeError):
pass
def parse_inlinefunc(string, strip=False, **kwargs):
"""
Parse the incoming string.
@ -347,7 +350,7 @@ def parse_inlinefunc(string, strip=False, **kwargs):
args.append("")
else:
# all other args should merge into one string
args[-1] += _run_stack(arg, depth=depth+1)
args[-1] += _run_stack(arg, depth=depth + 1)
# execute the inlinefunc at this point or strip it.
kwargs["inlinefunc_stack_depth"] = depth
retval = "" if strip else func(*args, **kwargs)
@ -360,6 +363,7 @@ def parse_inlinefunc(string, strip=False, **kwargs):
# Nick templating
#
"""
This supports the use of replacement templates in nicks:
@ -451,5 +455,3 @@ def parse_nick_template(string, template_regex, outtemplate):
if match:
return outtemplate.format(**match.groupdict())
return string

View file

@ -83,6 +83,8 @@ def log_trace(errmsg=None):
log.msg('[EE] %s' % line)
except Exception:
log.msg('[EE] %s' % errmsg)
log_tracemsg = log_trace
@ -100,6 +102,8 @@ def log_err(errmsg):
errmsg = str(e)
for line in errmsg.splitlines():
log.msg('[EE] %s' % line)
# log.err('ERROR: %s' % (errmsg,))
log_errmsg = log_err
@ -118,6 +122,8 @@ def log_warn(warnmsg):
warnmsg = str(e)
for line in warnmsg.splitlines():
log.msg('[WW] %s' % line)
# log.msg('WARNING: %s' % (warnmsg,))
log_warnmsg = log_warn
@ -134,6 +140,8 @@ def log_info(infomsg):
infomsg = str(e)
for line in infomsg.splitlines():
log.msg('[..] %s' % line)
log_infomsg = log_info
@ -150,6 +158,8 @@ def log_dep(depmsg):
depmsg = str(e)
for line in depmsg.splitlines():
log.msg('[DP] %s' % line)
log_depmsg = log_dep
@ -207,6 +217,7 @@ class EvenniaLogFile(logfile.LogFile):
"""
return self._file.readlines(*args, **kwargs)
_LOG_FILE_HANDLES = {} # holds open log handles
@ -307,7 +318,7 @@ def tail_log_file(filename, offset, nlines, callback=None):
lines_found = filehandle.readlines()
block_count -= 1
# return the right number of lines
lines_found = lines_found[-nlines-offset:-offset if offset else None]
lines_found = lines_found[-nlines - offset:-offset if offset else None]
if callback:
callback(lines_found)
return None

View file

@ -34,7 +34,7 @@ from ast import literal_eval
from copy import deepcopy
from base64 import b64encode, b64decode
from zlib import compress, decompress
#import six # this is actually a pypy component, not in default syslib
# import six # this is actually a pypy component, not in default syslib
import django
from django.core.exceptions import ValidationError
from django.db import models
@ -54,12 +54,13 @@ except ImportError:
# python 3.x does not have cPickle module
try:
from cPickle import loads, dumps # cpython 2.x
from cPickle import loads, dumps # cpython 2.x
except ImportError:
from pickle import loads, dumps # cpython 3.x, other interpreters
from pickle import loads, dumps # cpython 3.x, other interpreters
DEFAULT_PROTOCOL = 2
class PickledObject(str):
"""
A subclass of string so it can be told whether a string is a pickled
@ -105,12 +106,12 @@ def dbsafe_encode(value, compress_object=False, pickle_protocol=DEFAULT_PROTOCOL
value = dumps(deepcopy(value), protocol=pickle_protocol)
if compress_object:
value = compress(value)
value = b64encode(value).decode() # decode bytes to str
value = b64encode(value).decode() # decode bytes to str
return PickledObject(value)
def dbsafe_decode(value, compress_object=False):
value = value.encode() # encode str to bytes
value = value.encode() # encode str to bytes
value = b64decode(value)
if compress_object:
value = decompress(value)
@ -198,7 +199,7 @@ class PickledObjectField(models.Field):
# If the field doesn't have a default, then we punt to models.Field.
return super(PickledObjectField, self).get_default()
#def to_python(self, value):
# def to_python(self, value):
def from_db_value(self, value, *args):
"""
B64decode and unpickle the object, optionally decompressing it.

View file

@ -78,6 +78,7 @@ _re = re.compile("\033\[[0-9;]*m")
def _ansi(method):
"""decorator for converting ansi in input"""
def wrapper(self, *args, **kwargs):
def convert(inp):
if isinstance(inp, basestring):
@ -110,7 +111,6 @@ class PrettyTable(object):
@_ansi
def __init__(self, field_names=None, **kwargs):
"""Return a new PrettyTable instance
Arguments:
@ -223,15 +223,15 @@ class PrettyTable(object):
# Uneven padding
# Put more space on right if text is of odd length...
if _str_block_width(text) % 2:
return (excess//2)*" " + text + (excess//2 + 1)*" "
return (excess // 2) * " " + text + (excess // 2 + 1) * " "
# and more space on left if text is of even length
else:
return (excess//2 + 1)*" " + text + (excess//2)*" "
return (excess // 2 + 1) * " " + text + (excess // 2) * " "
# Why distribute extra space this way? To match the behaviour of
# the inbuilt str.center() method.
else:
# Equal padding on either side
return (excess//2)*" " + text + (excess//2)*" "
return (excess // 2) * " " + text + (excess // 2) * " "
def __getattr__(self, name):
@ -252,7 +252,7 @@ class PrettyTable(object):
new = PrettyTable()
new.field_names = self.field_names
for attr in self._options:
setattr(new, "_"+attr, getattr(self, "_"+attr))
setattr(new, "_" + attr, getattr(self, "_" + attr))
setattr(new, "_align", getattr(self, "_align"))
if isinstance(index, slice):
for row in self._rows[index]:
@ -823,7 +823,7 @@ class PrettyTable(object):
self._validate_option(option, kwargs[option])
options[option] = kwargs[option]
else:
options[option] = getattr(self, "_"+option)
options[option] = getattr(self, "_" + option)
return options
##############################
@ -893,7 +893,6 @@ class PrettyTable(object):
@_ansi
def add_row(self, row):
"""Add a row to the table
Arguments:
@ -905,24 +904,22 @@ class PrettyTable(object):
raise Exception("Row has incorrect number of values, (actual) %d!=%d (expected)"
% (len(row), len(self._field_names)))
if not self._field_names:
self.field_names = [("Field %d" % (n+1)) for n in range(0, len(row))]
self.field_names = [("Field %d" % (n + 1)) for n in range(0, len(row))]
self._rows.append(list(row))
def del_row(self, row_index):
"""Delete a row to the table
Arguments:
row_index - The index of the row you want to delete. Indexing starts at 0."""
if row_index > len(self._rows)-1:
if row_index > len(self._rows) - 1:
raise Exception("Can't delete row at index %d, table only has %d rows!" % (row_index, len(self._rows)))
del self._rows[row_index]
@_ansi
def add_column(self, fieldname, column, align="l", valign="t"):
"""Add a column to the table.
Arguments:
@ -940,20 +937,18 @@ class PrettyTable(object):
self._align[fieldname] = align
self._valign[fieldname] = valign
for i in range(0, len(column)):
if len(self._rows) < i+1:
if len(self._rows) < i + 1:
self._rows.append([])
self._rows[i].append(column[i])
else:
raise Exception("Column length %d does not match number of rows %d!" % (len(column), len(self._rows)))
def clear_rows(self):
"""Delete all rows from the table but keep the current field names"""
self._rows = []
def clear(self):
"""Delete all rows and field names from the table, maintaining nothing but styling options"""
self._rows = []
@ -1017,7 +1012,7 @@ class PrettyTable(object):
if options["sortby"]:
sortindex = self._field_names.index(options["sortby"])
# Decorate
rows = [[row[sortindex]]+row for row in rows]
rows = [[row[sortindex]] + row for row in rows]
# Sort
rows.sort(reverse=options["reversesort"], key=options["sort_key"])
# Undecorate
@ -1035,7 +1030,6 @@ class PrettyTable(object):
##############################
def get_string(self, **kwargs):
"""Return string representation of table in current state.
Arguments:
@ -1106,12 +1100,12 @@ class PrettyTable(object):
bits = [options["horizontal_char"]]
# For tables with no data or fieldnames
if not self._field_names:
bits.append(options["junction_char"])
return "".join(bits)
bits.append(options["junction_char"])
return "".join(bits)
for field, width in zip(self._field_names, self._widths):
if options["fields"] and field not in options["fields"]:
continue
bits.append((width+lpad+rpad)*options["horizontal_char"])
bits.append((width + lpad + rpad) * options["horizontal_char"])
if options['vrules'] == ALL:
bits.append(options["junction_char"])
else:
@ -1232,8 +1226,8 @@ class PrettyTable(object):
bits[y].append(options["vertical_char"])
if options["border"] and options["hrules"] == ALL:
bits[row_height-1].append("\n")
bits[row_height-1].append(self._hrule)
bits[row_height - 1].append("\n")
bits[row_height - 1].append(self._hrule)
for y in range(0, row_height):
bits[y] = "".join(bits[y])
@ -1245,7 +1239,6 @@ class PrettyTable(object):
##############################
def get_html_string(self, **kwargs):
"""Return string representation of HTML formatted version of table in current state.
Arguments:
@ -1515,7 +1508,7 @@ class TableHandler(HTMLParser):
iterates over the row and make each field unique
"""
for i in range(0, len(fields)):
for j in range(i+1, len(fields)):
for j in range(i + 1, len(fields)):
if fields[i] == fields[j]:
fields[j] += "'"
@ -1566,5 +1559,6 @@ def main():
x.add_row(["Perth", 5386, 1554769, 869.4])
print(x)
if __name__ == "__main__":
main()

View file

@ -212,6 +212,7 @@ def search_script_attribute(key=None, category=None, value=None, strvalue=None):
def search_channel_attribute(key=None, category=None, value=None, strvalue=None):
return Channel.objects.get_by_attribute(key=key, category=category, value=value, strvalue=strvalue)
# search for attribute objects
search_attribute_object = ObjectDB.objects.get_attribute
@ -243,6 +244,8 @@ def search_object_by_tag(key=None, category=None):
"""
return ObjectDB.objects.get_by_tag(key=key, category=category)
search_tag = search_object_by_tag # this is the most common case
@ -302,5 +305,6 @@ def search_channel_tag(key=None, category=None):
"""
return Channel.objects.get_by_tag(key=key, category=category)
# search for tag objects (not the objects they are attached to
search_tag_object = ObjectDB.objects.get_tag

View file

@ -307,35 +307,35 @@ if __name__ == "__main__":
# testing
protparents = {
"NOBODY": {},
# "INFINITE" : {
# "prototype":"INFINITE"
# },
"GOBLIN": {
"key": "goblin grunt",
"health": lambda: randint(20, 30),
"resists": ["cold", "poison"],
"attacks": ["fists"],
"weaknesses": ["fire", "light"]
},
"GOBLIN_WIZARD": {
"prototype": "GOBLIN",
"key": "goblin wizard",
"spells": ["fire ball", "lighting bolt"]
},
"GOBLIN_ARCHER": {
"prototype": "GOBLIN",
"key": "goblin archer",
"attacks": ["short bow"]
},
"ARCHWIZARD": {
"attacks": ["archwizard staff"],
},
"GOBLIN_ARCHWIZARD": {
"key": "goblin archwizard",
"prototype": ("GOBLIN_WIZARD", "ARCHWIZARD")
}
"NOBODY": {},
# "INFINITE" : {
# "prototype":"INFINITE"
# },
"GOBLIN": {
"key": "goblin grunt",
"health": lambda: randint(20, 30),
"resists": ["cold", "poison"],
"attacks": ["fists"],
"weaknesses": ["fire", "light"]
},
"GOBLIN_WIZARD": {
"prototype": "GOBLIN",
"key": "goblin wizard",
"spells": ["fire ball", "lighting bolt"]
},
"GOBLIN_ARCHER": {
"prototype": "GOBLIN",
"key": "goblin archer",
"attacks": ["short bow"]
},
"ARCHWIZARD": {
"attacks": ["archwizard staff"],
},
"GOBLIN_ARCHWIZARD": {
"key": "goblin archwizard",
"prototype": ("GOBLIN_WIZARD", "ARCHWIZARD")
}
}
# test
print([o.key for o in spawn(protparents["GOBLIN"],
protparents["GOBLIN_ARCHWIZARD"],

View file

@ -53,8 +53,8 @@ class EvenniaTest(TestCase):
dummysession = ServerSession()
dummysession.init_session("telnet", ("localhost", "testmode"), SESSIONS)
dummysession.sessid = 1
SESSIONS.portal_connect(dummysession.get_sync_data()) # note that this creates a new Session!
session = SESSIONS.session_from_sessid(1) # the real session
SESSIONS.portal_connect(dummysession.get_sync_data()) # note that this creates a new Session!
session = SESSIONS.session_from_sessid(1) # the real session
SESSIONS.login(session, self.account, testmode=True)
self.session = session

View file

@ -12,6 +12,7 @@ from evennia import utils
from django.conf import settings
class ANSIStringTestCase(TestCase):
def checker(self, ansi, raw, clean):
"""
@ -209,6 +210,7 @@ class TestListToString(TestCase):
with addquote and endsep
[1,2,3] -> '"1", "2" and "3"'
"""
def test_list_to_string(self):
self.assertEqual('1, 2, 3', utils.list_to_string([1, 2, 3], endsep=""))
self.assertEqual('"1", "2", "3"', utils.list_to_string([1, 2, 3], endsep="", addquote=True))
@ -221,6 +223,7 @@ class TestMLen(TestCase):
Verifies that m_len behaves like len in all situations except those
where MXP may be involved.
"""
def test_non_mxp_string(self):
self.assertEqual(utils.m_len('Test_string'), 11)
@ -325,15 +328,19 @@ class TestTextToHTMLparser(TestCase):
'</span><a href="http://example.com/" target="_blank">'
'http://example.com/</a><span class="red">')
from evennia.utils import evmenu
from mock import Mock
class TestEvMenu(TestCase):
"Run the EvMenu test."
def setUp(self):
self.caller = Mock()
self.caller.msg = Mock()
self.menu = evmenu.EvMenu(self.caller, "evennia.utils.evmenu", startnode="test_start_node",
persistent=True, cmdset_mergetype="Replace", testval="val", testval2="val2")
persistent=True, cmdset_mergetype="Replace", testval="val", testval2="val2")
def test_kwargsave(self):
self.assertTrue(hasattr(self.menu, "testval"))
@ -345,6 +352,7 @@ from evennia.utils import inlinefuncs
class TestInlineFuncs(TestCase):
"""Test the nested inlinefunc module"""
def test_nofunc(self):
self.assertEqual(inlinefuncs.parse_inlinefunc(
"as$382ewrw w we w werw,|44943}"),
@ -375,6 +383,7 @@ class TestInlineFuncs(TestCase):
'this should be $pad("""escaped,""" and """instead,""" cropped $crop(with a long,5) text., 80)'),
"this should be escaped, and instead, cropped with text. ")
from evennia.utils import evform
@ -424,7 +433,8 @@ class TestEvForm(TestCase):
def test_ansi_escape(self):
# note that in a msg() call, the result would be the correct |-----,
# in a print, ansi only gets called once, so ||----- is the result
self.assertEqual(unicode(evform.EvForm(form={"FORM":"\n||-----"})), "||-----")
self.assertEqual(unicode(evform.EvForm(form={"FORM": "\n||-----"})), "||-----")
class TestTimeformat(TestCase):
"""
@ -472,11 +482,11 @@ class TestTimeformat(TestCase):
self.assertEqual(utils.time_format(3725, 2), "1 hour, 2 minutes")
self.assertEqual(utils.time_format(86350, 2), "23 hours, 59 minutes")
self.assertEqual(utils.time_format(86800, 2),
"1 day, 0 hours, 6 minutes")
"1 day, 0 hours, 6 minutes")
self.assertEqual(utils.time_format(130800, 2),
"1 day, 12 hours, 20 minutes")
"1 day, 12 hours, 20 minutes")
self.assertEqual(utils.time_format(530800, 2),
"6 days, 3 hours, 26 minutes")
"6 days, 3 hours, 26 minutes")
def test_style_3(self):
"""Test the style 3 of time_format."""
@ -486,17 +496,17 @@ class TestTimeformat(TestCase):
self.assertEqual(utils.time_format(300, 3), "5 minutes 0 seconds")
self.assertEqual(utils.time_format(660, 3), "11 minutes 0 seconds")
self.assertEqual(utils.time_format(3600, 3),
"1 hour, 0 minutes")
"1 hour, 0 minutes")
self.assertEqual(utils.time_format(3725, 3),
"1 hour, 2 minutes 5 seconds")
"1 hour, 2 minutes 5 seconds")
self.assertEqual(utils.time_format(86350, 3),
"23 hours, 59 minutes 10 seconds")
"23 hours, 59 minutes 10 seconds")
self.assertEqual(utils.time_format(86800, 3),
"1 day, 0 hours, 6 minutes 40 seconds")
"1 day, 0 hours, 6 minutes 40 seconds")
self.assertEqual(utils.time_format(130800, 3),
"1 day, 12 hours, 20 minutes 0 seconds")
"1 day, 12 hours, 20 minutes 0 seconds")
self.assertEqual(utils.time_format(530800, 3),
"6 days, 3 hours, 26 minutes 40 seconds")
"6 days, 3 hours, 26 minutes 40 seconds")
def test_style_4(self):
"""Test the style 4 of time_format."""

View file

@ -30,48 +30,48 @@ class TextToHTMLparser(object):
tabstop = 4
# mapping html color name <-> ansi code.
hilite = ANSI_HILITE
unhilite = ANSI_UNHILITE # this will be stripped - there is no css equivalent.
normal = ANSI_NORMAL # "
unhilite = ANSI_UNHILITE # this will be stripped - there is no css equivalent.
normal = ANSI_NORMAL # "
underline = ANSI_UNDERLINE
blink = ANSI_BLINK
inverse = ANSI_INVERSE # this will produce an outline; no obvious css equivalent?
colorcodes = [
('color-000', unhilite + ANSI_BLACK), # pure black
('color-001', unhilite + ANSI_RED),
('color-002', unhilite + ANSI_GREEN),
('color-003', unhilite + ANSI_YELLOW),
('color-004', unhilite + ANSI_BLUE),
('color-005', unhilite + ANSI_MAGENTA),
('color-006', unhilite + ANSI_CYAN),
('color-007', unhilite + ANSI_WHITE), # light grey
('color-008', hilite + ANSI_BLACK), # dark grey
('color-009', hilite + ANSI_RED),
('color-010', hilite + ANSI_GREEN),
('color-011', hilite + ANSI_YELLOW),
('color-012', hilite + ANSI_BLUE),
('color-013', hilite + ANSI_MAGENTA),
('color-014', hilite + ANSI_CYAN),
('color-015', hilite + ANSI_WHITE) # pure white
] + [("color-%03i" % (i+16), XTERM256_FG % ("%i" % (i+16))) for i in xrange(240)]
('color-000', unhilite + ANSI_BLACK), # pure black
('color-001', unhilite + ANSI_RED),
('color-002', unhilite + ANSI_GREEN),
('color-003', unhilite + ANSI_YELLOW),
('color-004', unhilite + ANSI_BLUE),
('color-005', unhilite + ANSI_MAGENTA),
('color-006', unhilite + ANSI_CYAN),
('color-007', unhilite + ANSI_WHITE), # light grey
('color-008', hilite + ANSI_BLACK), # dark grey
('color-009', hilite + ANSI_RED),
('color-010', hilite + ANSI_GREEN),
('color-011', hilite + ANSI_YELLOW),
('color-012', hilite + ANSI_BLUE),
('color-013', hilite + ANSI_MAGENTA),
('color-014', hilite + ANSI_CYAN),
('color-015', hilite + ANSI_WHITE) # pure white
] + [("color-%03i" % (i + 16), XTERM256_FG % ("%i" % (i + 16))) for i in xrange(240)]
colorback = [
('bgcolor-000', ANSI_BACK_BLACK), # pure black
('bgcolor-001', ANSI_BACK_RED),
('bgcolor-002', ANSI_BACK_GREEN),
('bgcolor-003', ANSI_BACK_YELLOW),
('bgcolor-004', ANSI_BACK_BLUE),
('bgcolor-005', ANSI_BACK_MAGENTA),
('bgcolor-006', ANSI_BACK_CYAN),
('bgcolor-007', ANSI_BACK_WHITE), # light grey
('bgcolor-008', hilite + ANSI_BACK_BLACK), # dark grey
('bgcolor-009', hilite + ANSI_BACK_RED),
('bgcolor-010', hilite + ANSI_BACK_GREEN),
('bgcolor-011', hilite + ANSI_BACK_YELLOW),
('bgcolor-012', hilite + ANSI_BACK_BLUE),
('bgcolor-013', hilite + ANSI_BACK_MAGENTA),
('bgcolor-014', hilite + ANSI_BACK_CYAN),
('bgcolor-015', hilite + ANSI_BACK_WHITE), # pure white
] + [("bgcolor-%03i" % (i+16), XTERM256_BG % ("%i" % (i+16))) for i in range(240)]
('bgcolor-000', ANSI_BACK_BLACK), # pure black
('bgcolor-001', ANSI_BACK_RED),
('bgcolor-002', ANSI_BACK_GREEN),
('bgcolor-003', ANSI_BACK_YELLOW),
('bgcolor-004', ANSI_BACK_BLUE),
('bgcolor-005', ANSI_BACK_MAGENTA),
('bgcolor-006', ANSI_BACK_CYAN),
('bgcolor-007', ANSI_BACK_WHITE), # light grey
('bgcolor-008', hilite + ANSI_BACK_BLACK), # dark grey
('bgcolor-009', hilite + ANSI_BACK_RED),
('bgcolor-010', hilite + ANSI_BACK_GREEN),
('bgcolor-011', hilite + ANSI_BACK_YELLOW),
('bgcolor-012', hilite + ANSI_BACK_BLUE),
('bgcolor-013', hilite + ANSI_BACK_MAGENTA),
('bgcolor-014', hilite + ANSI_BACK_CYAN),
('bgcolor-015', hilite + ANSI_BACK_WHITE), # pure white
] + [("bgcolor-%03i" % (i + 16), XTERM256_BG % ("%i" % (i + 16))) for i in range(240)]
# make sure to escape [
#colorcodes = [(c, code.replace("[", r"\[")) for c, code in colorcodes]
@ -80,8 +80,8 @@ class TextToHTMLparser(object):
bg_colormap = dict((code, clr) for clr, code in colorback)
# create stop markers
fgstop = "(?:\033\[1m|\033\[22m)*\033\[3[0-8].*?m|\033\[0m|$"
bgstop = "(?:\033\[1m|\033\[22m)*\033\[4[0-8].*?m|\033\[0m|$"
fgstop = "(?:\033\[1m|\033\[22m)*\033\[3[0-8].*?m|\033\[0m|$"
bgstop = "(?:\033\[1m|\033\[22m)*\033\[4[0-8].*?m|\033\[0m|$"
# extract color markers, tagging the start marker and the text marked
re_fgs = re.compile("((?:\033\[1m|\033\[22m)*\033\[3[0-8].*?m)(.*?)(?=" + fgstop + ")")
@ -93,9 +93,9 @@ class TextToHTMLparser(object):
re_uline = re.compile("(?:%s)(.*?)(?=%s|%s)" % (underline.replace("[", r"\["), fgstop, bgstop))
re_blink = re.compile("(?:%s)(.*?)(?=%s|%s)" % (blink.replace("[", r"\["), fgstop, bgstop))
re_inverse = re.compile("(?:%s)(.*?)(?=%s|%s)" % (inverse.replace("[", r"\["), fgstop, bgstop))
re_string = re.compile(r'(?P<htmlchars>[<&>])|(?P<space> [ \t]+)|(?P<spacestart>^ )|(?P<lineend>\r\n|\r|\n)', re.S|re.M|re.I)
re_string = re.compile(r'(?P<htmlchars>[<&>])|(?P<space> [ \t]+)|(?P<spacestart>^ )|(?P<lineend>\r\n|\r|\n)', re.S | re.M | re.I)
re_url = re.compile(r'((?:ftp|www|https?)\W+(?:(?!\.(?:\s|$)|&\w+;)[^"\',;$*^\\(){}<>\[\]\s])+)(\.(?:\s|$)|&\w+;|)')
re_mxplink = re.compile(r'\|lc(.*?)\|lt(.*?)\|le', re.DOTALL)
re_mxplink = re.compile(r'\|lc(.*?)\|lt(.*?)\|le', re.DOTALL)
def _sub_fg(self, colormatch):
code, text = colormatch.groups()
@ -135,7 +135,7 @@ class TextToHTMLparser(object):
"""
text = self.re_hilite.sub(r'<strong>\1</strong>', text)
return self.re_unhilite.sub(r'\1', text) # strip unhilite - there is no equivalent in css.
return self.re_unhilite.sub(r'\1', text) # strip unhilite - there is no equivalent in css.
def re_underline(self, text):
"""
@ -245,9 +245,9 @@ class TextToHTMLparser(object):
"""
cmd, text = [grp.replace('\"', "\\&quot;") for grp in match.groups()]
val = r'''<a id="mxplink" href="#" ''' \
'''onclick="Evennia.msg(&quot;text&quot;,[&quot;{cmd}&quot;],{{}});''' \
'''return false;">{text}</a>'''.format(cmd=cmd, text=text)
val = r'''<a id="mxplink" href="#" ''' \
'''onclick="Evennia.msg(&quot;text&quot;,[&quot;{cmd}&quot;],{{}});''' \
'''return false;">{text}</a>'''.format(cmd=cmd, text=text)
return val
def sub_text(self, match):
@ -306,6 +306,7 @@ class TextToHTMLparser(object):
return result
HTML_PARSER = TextToHTMLparser()

View file

@ -36,6 +36,7 @@ from twisted.protocols.policies import ProtocolWrapper, WrappingFactory
from twisted.python import log
from twisted.web.http import datetimeToString
class WSException(Exception):
"""
Something stupid happened here.
@ -54,6 +55,7 @@ class WSException(Exception):
# RFC6455 - RFC 6455. The official WebSocket protocol standard. The protocol
# number is 13, but otherwise it is identical to HyBi-07.
HYBI00, HYBI07, HYBI10, RFC6455 = list(range(4))
# States of the state machine. Because there are no reliable byte counts for
@ -87,6 +89,7 @@ decoders = {
# Fake HTTP stuff, and a couple convenience methods for examining fake HTTP
# headers.
def http_headers(s):
"""
Create a dictionary of data from raw HTTP headers.
@ -104,13 +107,15 @@ def http_headers(s):
return d
def is_websocket(headers):
"""
Determine whether a given set of headers is asking for WebSockets.
"""
return ("upgrade" in headers.get("Connection", "").lower()
and headers.get("Upgrade").lower() == "websocket")
return ("upgrade" in headers.get("Connection", "").lower() and
headers.get("Upgrade").lower() == "websocket")
def is_hybi00(headers):
"""
@ -124,6 +129,7 @@ def is_hybi00(headers):
# Authentication for WS.
def complete_hybi00(headers, challenge):
"""
Generate the response for a HyBi-00 challenge.
@ -139,6 +145,7 @@ def complete_hybi00(headers, challenge):
return md5(nonce).digest()
def make_accept(key):
"""
Create an "accept" response for a given key.
@ -154,6 +161,7 @@ def make_accept(key):
# Separated out to make unit testing a lot easier.
# Frames are bonghits in newer WS versions, so helpers are appreciated.
def make_hybi00_frame(buf):
"""
Make a HyBi-00 frame from some data.
@ -164,6 +172,7 @@ def make_hybi00_frame(buf):
return "\x00%s\xff" % buf
def parse_hybi00_frames(buf):
"""
Parse HyBi-00 frames, returning unwrapped frames and any unmatched data.
@ -192,6 +201,7 @@ def parse_hybi00_frames(buf):
buf = buf[tail:]
return frames, buf
def mask(buf, key):
"""
Mask or unmask a buffer of bytes with a masking key.
@ -206,6 +216,7 @@ def mask(buf, key):
buf[i] = chr(ord(char) ^ key[i % 4])
return "".join(buf)
def make_hybi07_frame(buf, opcode=0x1):
"""
Make a HyBi-07 frame.
@ -226,6 +237,7 @@ def make_hybi07_frame(buf, opcode=0x1):
frame = "%s%s%s" % (header, length, buf)
return frame
def make_hybi07_frame_dwim(buf):
"""
Make a HyBi-07 frame with binary or text data according to the type of buf.
@ -239,6 +251,7 @@ def make_hybi07_frame_dwim(buf):
else:
raise TypeError("In binary support mode, frame data must be either str or unicode")
def parse_hybi07_frames(buf):
"""
Parse HyBi-07 frames in a highly compliant manner.
@ -259,7 +272,7 @@ def parse_hybi07_frames(buf):
# At least one of the reserved flags is set. Pork chop sandwiches!
raise WSException("Reserved flag in HyBi-07 frame (%d)" % header)
#frames.append(("", CLOSE))
#return frames, buf
# return frames, buf
# Get the opcode, and translate it to a local enum which we actually
# care about.
@ -329,6 +342,7 @@ def parse_hybi07_frames(buf):
return frames, buf[start:]
class WebSocketProtocol(ProtocolWrapper):
"""
Protocol which wraps another protocol to provide a WebSockets transport
@ -538,7 +552,7 @@ class WebSocketProtocol(ProtocolWrapper):
log.msg("Can't support protocol version %s!" % version)
return False
self.validationMade() # custom Evennia addition
self.validationMade() # custom Evennia addition
return True
def dataReceived(self, data):
@ -639,6 +653,7 @@ class WebSocketProtocol(ProtocolWrapper):
self.loseConnection()
class WebSocketFactory(WrappingFactory):
"""
Factory which wraps another factory to provide WebSockets transports for

View file

@ -44,6 +44,7 @@ _DA = object.__delattr__
_DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
def is_iter(iterable):
"""
Checks if an object behaves iterably.
@ -96,6 +97,8 @@ def wrap(text, width=_DEFAULT_WIDTH, indent=0):
text = to_unicode(text)
indent = " " * indent
return to_str(textwrap.fill(text, width, initial_indent=indent, subsequent_indent=indent))
# alias - fill
fill = wrap
@ -437,27 +440,27 @@ def time_format(seconds, style=0):
"""
Only return the highest unit.
"""
if days >= 730: # Several years
if days >= 730: # Several years
return "{} years".format(days // 365)
elif days >= 365: # One year
elif days >= 365: # One year
return "a year"
elif days >= 62: # Several months
elif days >= 62: # Several months
return "{} months".format(days // 31)
elif days >= 31: # One month
elif days >= 31: # One month
return "a month"
elif days >= 2: # Several days
elif days >= 2: # Several days
return "{} days".format(days)
elif days > 0:
return "a day"
elif hours >= 2: # Several hours
elif hours >= 2: # Several hours
return "{} hours".format(hours)
elif hours > 0: # One hour
elif hours > 0: # One hour
return "an hour"
elif minutes >= 2: # Several minutes
elif minutes >= 2: # Several minutes
return "{} minutes".format(minutes)
elif minutes > 0: # One minute
elif minutes > 0: # One minute
return "a minute"
elif seconds >= 2: # Several seconds
elif seconds >= 2: # Several seconds
return "{} seconds".format(seconds)
elif seconds == 1:
return "a second"
@ -593,9 +596,9 @@ def dbref(inp, reqhash=True):
"""
if reqhash:
num = (int(inp.lstrip('#')) if (isinstance(inp, basestring) and
inp.startswith("#") and
inp.lstrip('#').isdigit())
else None)
inp.startswith("#") and
inp.lstrip('#').isdigit())
else None)
return num if num > 0 else None
elif isinstance(inp, basestring):
inp = inp.lstrip('#')
@ -641,6 +644,7 @@ def dbref_to_obj(inp, objclass, raise_errors=True):
raise
return inp
# legacy alias
dbid_to_obj = dbref_to_obj
@ -788,7 +792,7 @@ def to_str(obj, encoding='utf-8', force_string=False):
# if we get to this point we have not found any way to convert this string. Try to parse it manually,
try:
return latinify(obj, '?')
except Exception, err:
except Exception as err:
raise Exception("%s, Error: Unicode could not encode unicode string '%s'(%s) to a bytestring. " % (err, obj, encoding))
return obj
@ -921,6 +925,7 @@ def uses_database(name="sqlite3"):
_TASK_HANDLER = None
def delay(timedelay, callback, *args, **kwargs):
"""
Delay the return of a value.
@ -989,7 +994,7 @@ def clean_object_caches(obj):
# on-object property cache
[_DA(obj, cname) for cname in viewkeys(obj.__dict__)
if cname.startswith("_cached_db_")]
if cname.startswith("_cached_db_")]
try:
hashid = _GA(obj, "hashid")
_TYPECLASSMODELS._ATTRIBUTE_CACHE[hashid] = {}
@ -1001,6 +1006,8 @@ def clean_object_caches(obj):
_PPOOL = None
_PCMD = None
_PROC_ERR = "A process has ended with a probable error condition: process ended by signal 9."
def run_async(to_execute, *args, **kwargs):
"""
Runs a function or executes a code snippet asynchronously.
@ -1094,7 +1101,7 @@ def check_evennia_dependencies():
errstring = errstring.strip()
if errstring:
mlen = max(len(line) for line in errstring.split("\n"))
logger.log_err("%s\n%s\n%s" % ("-"*mlen, errstring, '-'*mlen))
logger.log_err("%s\n%s\n%s" % ("-" * mlen, errstring, '-' * mlen))
return not_error
@ -1333,7 +1340,7 @@ def fuzzy_import_from_module(path, variable, default=None, defaultpaths=None):
try:
mod = import_module(modpath)
except ImportError as ex:
if not str(ex).startswith ("No module named %s" % modpath):
if not str(ex).startswith("No module named %s" % modpath):
# this means the module was found but it
# triggers an ImportError on import.
raise ex
@ -1396,6 +1403,8 @@ def class_from_module(path, defaultpaths=None):
err += "."
raise ImportError(err)
return cls
# alias
object_from_module = class_from_module
@ -1430,7 +1439,7 @@ def string_similarity(string1, string2):
vec2 = [string2.count(v) for v in vocabulary]
try:
return float(sum(vec1[i] * vec2[i] for i in range(len(vocabulary)))) / \
(math.sqrt(sum(v1**2 for v1 in vec1)) * math.sqrt(sum(v2**2 for v2 in vec2)))
(math.sqrt(sum(v1**2 for v1 in vec1)) * math.sqrt(sum(v2**2 for v2 in vec2)))
except ZeroDivisionError:
# can happen if empty-string cmdnames appear for some reason.
# This is a no-match.
@ -1456,9 +1465,9 @@ def string_suggestions(string, vocabulary, cutoff=0.6, maxnum=3):
"""
return [tup[1] for tup in sorted([(string_similarity(string, sugg), sugg)
for sugg in vocabulary],
key=lambda tup: tup[0], reverse=True)
if tup[0] >= cutoff][:maxnum]
for sugg in vocabulary],
key=lambda tup: tup[0], reverse=True)
if tup[0] >= cutoff][:maxnum]
def string_partial_matching(alternatives, inp, ret_index=True):
@ -1589,6 +1598,7 @@ def get_evennia_pids():
return int(server_pid), int(portal_pid)
return None, None
from gc import get_referents
from sys import getsizeof
@ -1622,12 +1632,13 @@ def deepsize(obj, max_depth=4):
idr = id(ref)
if idr not in dct:
dct[idr] = (ref, getsizeof(ref, default=0))
_recurse(ref, dct, depth+1)
_recurse(ref, dct, depth + 1)
sizedict = {}
_recurse(obj, sizedict, 0)
size = getsizeof(obj) + sum([p[1] for p in sizedict.values()])
return size
# lazy load handler
_missing = object()
@ -1651,6 +1662,7 @@ class lazy_property(object):
property "attributes" on the object.
"""
def __init__(self, func, name=None, doc=None):
"""Store all properties for now"""
self.__name__ = name or func.__name__
@ -1668,6 +1680,7 @@ class lazy_property(object):
obj.__dict__[self.__name__] = value
return value
_STRIP_ANSI = None
_RE_CONTROL_CHAR = re.compile('[%s]' % re.escape(''.join([unichr(c) for c in range(0, 32)]))) # + range(127,160)])))
@ -1707,7 +1720,7 @@ def calledby(callerdepth=1):
stack = inspect.stack()
# we must step one extra level back in stack since we don't want
# to include the call of this function itself.
callerdepth = min(max(2, callerdepth + 1), len(stack)-1)
callerdepth = min(max(2, callerdepth + 1), len(stack) - 1)
frame = inspect.stack()[callerdepth]
path = os.path.sep.join(frame[1].rsplit(os.path.sep, 2)[-2:])
return "[called by '%s': %s:%s %s]" % (frame[3], path, frame[2], frame[4])
@ -1774,15 +1787,15 @@ def at_search_result(matches, caller, query="", quiet=False, **kwargs):
matches = None
elif len(matches) > 1:
error = kwargs.get("multimatch_string") or \
_("More than one match for '%s' (please narrow target):\n" % query)
_("More than one match for '%s' (please narrow target):\n" % query)
for num, result in enumerate(matches):
# we need to consider Commands, where .aliases is a list
aliases = result.aliases.all() if hasattr(result.aliases, "all") else result.aliases
error += _MULTIMATCH_TEMPLATE.format(
number=num + 1,
name=result.get_display_name(caller) if hasattr(result, "get_display_name") else query,
aliases=" [%s]" % ";".join(aliases) if aliases else "",
info=result.get_extra_info(caller))
number=num + 1,
name=result.get_display_name(caller) if hasattr(result, "get_display_name") else query,
aliases=" [%s]" % ";".join(aliases) if aliases else "",
info=result.get_extra_info(caller))
matches = None
else:
# exactly one match
@ -1800,6 +1813,7 @@ class LimitedSizeOrderedDict(OrderedDict):
grow out of bounds.
"""
def __init__(self, *args, **kwargs):
"""
Limited-size ordered dict.
@ -1814,7 +1828,7 @@ class LimitedSizeOrderedDict(OrderedDict):
"""
super(LimitedSizeOrderedDict, self).__init__()
self.size_limit = kwargs.get("size_limit", None)
self.filo = not kwargs.get("fifo", True) # FIFO inverse of FILO
self.filo = not kwargs.get("fifo", True) # FIFO inverse of FILO
self._check_size()
def _check_size(self):
@ -1850,7 +1864,3 @@ def get_game_dir_path():
else:
os.chdir(os.pardir)
raise RuntimeError("server/conf/settings.py not found: Must start from inside game dir.")