Update docstrings to pass autodoc parsing

This commit is contained in:
Griatch 2020-10-11 17:15:30 +02:00
parent d449acb57b
commit d4f1733bc7
17 changed files with 663 additions and 558 deletions

View file

@ -375,29 +375,41 @@ DUMMYRUNNER_SETTINGS_MODULE = "evennia.server.profiling.dummyrunner_settings"
# tuples mapping the exact tag (not a regex!) to the ANSI convertion, like
# `(r"%c%r", ansi.ANSI_RED)` (the evennia.utils.ansi module contains all
# ANSI escape sequences). Default is to use `|` and `|[` -prefixes.
# Note that to apply all color changes, a full `evennia reboot` is needed!
COLOR_ANSI_EXTRA_MAP = []
# Extend the available regexes for adding XTERM256 colors in-game. This is given
# as a list of regexes, where each regex must contain three anonymous groups for
# holding integers 0-5 for the red, green and blue components Default is
# is r'\|([0-5])([0-5])([0-5])', which allows e.g. |500 for red.
# Note that to apply all color changes, a full `evennia reboot` is needed!
COLOR_ANSI_EXTRA_MAP = []
# XTERM256 foreground color replacement
# Note that to apply all color changes, a full `evennia reboot` is needed!
COLOR_XTERM256_EXTRA_FG = []
# XTERM256 background color replacement. Default is \|\[([0-5])([0-5])([0-5])'
# Note that to apply all color changes, a full `evennia reboot` is needed!
COLOR_XTERM256_EXTRA_BG = []
# Extend the available regexes for adding XTERM256 grayscale values in-game. Given
# as a list of regexes, where each regex must contain one anonymous group containing
# a single letter a-z to mark the level from white to black. Default is r'\|=([a-z])',
# which allows e.g. |=k for a medium gray.
# XTERM256 grayscale foreground
# Note that to apply all color changes, a full `evennia reboot` is needed!
COLOR_XTERM256_EXTRA_GFG = []
# XTERM256 grayscale background. Default is \|\[=([a-z])'
# Note that to apply all color changes, a full `evennia reboot` is needed!
COLOR_XTERM256_EXTRA_GBG = []
# ANSI does not support bright backgrounds, so Evennia fakes this by mapping it to
# XTERM256 backgrounds where supported. This is a list of tuples that maps the wanted
# ansi tag (not a regex!) to a valid XTERM256 background tag, such as `(r'{[r', r'{[500')`.
# ansi tag (not a regex!) to a valid XTERM256 tag, such as `(r'|o', r'|531')`
# for orange. By default this is only used for bright backgrounds but
# both bright and dark colors can be mapped this way, and is a way to add
# new shortcuts to xterm colors without having to write the RGB value.
# Note that to apply all color changes, a full `evennia reboot` is needed!
COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP = []
# If set True, the above color settings *replace* the default |-style color markdown
# rather than extend it.
# Note that to apply all color changes, a full `evennia reboot` is needed!
COLOR_NO_DEFAULT = False

View file

@ -24,6 +24,8 @@ layer.
This module also contains the Managers for the respective models; inherit from
these to create custom managers.
----
"""
from django.db.models import signals
@ -161,7 +163,10 @@ class TypeclassBase(SharedMemoryModelBase):
class DbHolder(object):
"Holder for allowing property access of attributes"
"""
Holder for allowing property access of attributes.
"""
def __init__(self, obj, name, manager_name="attributes"):
_SA(self, name, _GA(obj, manager_name))
@ -309,10 +314,8 @@ class TypedObject(SharedMemoryModel):
than use the one in the model.
Args:
Passed through to parent.
Keyword Args:
Passed through to parent.
*args: Passed through to parent.
**kwargs: Passed through to parent.
Notes:
The loading mechanism will attempt the following steps:
@ -725,14 +728,19 @@ class TypedObject(SharedMemoryModel):
def __db_get(self):
"""
Attribute handler wrapper. Allows for the syntax
::
obj.db.attrname = value
and
value = obj.db.attrname
and
del obj.db.attrname
and
all_attr = obj.db.all() (unless there is an attribute
named 'all', in which case that will be returned instead).
all_attr = obj.db.all()
(unless there is an attribute named 'all', in which case that will be
returned instead).
"""
try:
return self._db_holder
@ -742,14 +750,14 @@ class TypedObject(SharedMemoryModel):
# @db.setter
def __db_set(self, value):
"Stop accidentally replacing the db object"
"""Stop accidentally replacing the db object"""
string = "Cannot assign directly to db object! "
string += "Use db.attr=value instead."
raise Exception(string)
# @db.deleter
def __db_del(self):
"Stop accidental deletion."
"""Stop accidental deletion."""
raise Exception("Cannot delete the db object!")
db = property(__db_get, __db_set, __db_del)
@ -761,10 +769,23 @@ class TypedObject(SharedMemoryModel):
# @property ndb
def __ndb_get(self):
"""
A non-attr_obj store (ndb: NonDataBase). Everything stored
to this is guaranteed to be cleared when a server is shutdown.
Syntax is same as for the _get_db_holder() method and
property, e.g. obj.ndb.attr = value etc.
A non-attr_obj store (NonDataBase). Everything stored to this is
guaranteed to be cleared when a server is shutdown. Syntax is same as
for the `.db` property, e.g.
::
obj.ndb.attrname = value
and
value = obj.ndb.attrname
and
del obj.ndb.attrname
and
all_attr = obj.ndb.all()
What makes this preferable over just assigning properties directly on
the object is that Evennia can track caching for these properties and
for example avoid wiping objects with set `.ndb` data on cache flushes.
"""
try:
return self._ndb_holder
@ -869,28 +890,33 @@ class TypedObject(SharedMemoryModel):
@classmethod
def web_get_create_url(cls):
"""
Returns the URI path for a View that allows users to create new
instances of this object.
ex. Chargen = '/characters/create/'
For this to work, the developer must have defined a named view somewhere
in urls.py that follows the format 'modelname-action', so in this case
a named view of 'character-create' would be referenced by this method.
ex.
url(r'characters/create/', ChargenView.as_view(), name='character-create')
If no View has been created and defined in urls.py, returns an
HTML anchor.
This method is naive and simply returns a path. Securing access to
the actual view and limiting who can create new objects is the
developer's responsibility.
Returns:
path (str): URI path to object creation page, if defined.
Examples:
::
Chargen = '/characters/create/'
For this to work, the developer must have defined a named view somewhere
in urls.py that follows the format 'modelname-action', so in this case
a named view of 'character-create' would be referenced by this method.
::
url(r'characters/create/', ChargenView.as_view(), name='character-create')
If no View has been created and defined in urls.py, returns an
HTML anchor.
Notes:
This method is naive and simply returns a path. Securing access to
the actual view and limiting who can create new objects is the
developer's responsibility.
"""
try:
return reverse("%s-create" % slugify(cls._meta.verbose_name))
@ -902,26 +928,29 @@ class TypedObject(SharedMemoryModel):
Returns the URI path for a View that allows users to view details for
this object.
ex. Oscar (Character) = '/characters/oscar/1/'
For this to work, the developer must have defined a named view somewhere
in urls.py that follows the format 'modelname-action', so in this case
a named view of 'character-detail' would be referenced by this method.
ex.
url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$',
CharDetailView.as_view(), name='character-detail')
If no View has been created and defined in urls.py, returns an
HTML anchor.
This method is naive and simply returns a path. Securing access to
the actual view and limiting who can view this object is the developer's
responsibility.
Returns:
path (str): URI path to object detail page, if defined.
Examples:
::
Oscar (Character) = '/characters/oscar/1/'
For this to work, the developer must have defined a named view somewhere
in urls.py that follows the format 'modelname-action', so in this case
a named view of 'character-detail' would be referenced by this method.
::
CharDetailView.as_view(), name='character-detail')
If no View has been created and defined in urls.py, returns an
HTML anchor.
Notes:
This method is naive and simply returns a path. Securing access to
the actual view and limiting who can view this object is the
developer's responsibility.
"""
try:
return reverse(
@ -936,26 +965,31 @@ class TypedObject(SharedMemoryModel):
Returns the URI path for a View that allows users to puppet a specific
object.
ex. Oscar (Character) = '/characters/oscar/1/puppet/'
For this to work, the developer must have defined a named view somewhere
in urls.py that follows the format 'modelname-action', so in this case
a named view of 'character-puppet' would be referenced by this method.
ex.
url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/puppet/$',
CharPuppetView.as_view(), name='character-puppet')
If no View has been created and defined in urls.py, returns an
HTML anchor.
This method is naive and simply returns a path. Securing access to
the actual view and limiting who can view this object is the developer's
responsibility.
Returns:
path (str): URI path to object puppet page, if defined.
Examples:
::
Oscar (Character) = '/characters/oscar/1/puppet/'
For this to work, the developer must have defined a named view somewhere
in urls.py that follows the format 'modelname-action', so in this case
a named view of 'character-puppet' would be referenced by this method.
::
url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/puppet/$',
CharPuppetView.as_view(), name='character-puppet')
If no View has been created and defined in urls.py, returns an
HTML anchor.
Notes:
This method is naive and simply returns a path. Securing access to
the actual view and limiting who can view this object is the developer's
responsibility.
"""
try:
return reverse(
@ -970,26 +1004,30 @@ class TypedObject(SharedMemoryModel):
Returns the URI path for a View that allows users to update this
object.
ex. Oscar (Character) = '/characters/oscar/1/change/'
For this to work, the developer must have defined a named view somewhere
in urls.py that follows the format 'modelname-action', so in this case
a named view of 'character-update' would be referenced by this method.
ex.
url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$',
CharUpdateView.as_view(), name='character-update')
If no View has been created and defined in urls.py, returns an
HTML anchor.
This method is naive and simply returns a path. Securing access to
the actual view and limiting who can modify objects is the developer's
responsibility.
Returns:
path (str): URI path to object update page, if defined.
Examples:
::
Oscar (Character) = '/characters/oscar/1/change/'
For this to work, the developer must have defined a named view somewhere
in urls.py that follows the format 'modelname-action', so in this case
a named view of 'character-update' would be referenced by this method.
::
url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$',
CharUpdateView.as_view(), name='character-update')
If no View has been created and defined in urls.py, returns an
HTML anchor.
Notes:
This method is naive and simply returns a path. Securing access to
the actual view and limiting who can modify objects is the developer's
responsibility.
"""
try:
return reverse(
@ -1003,26 +1041,31 @@ class TypedObject(SharedMemoryModel):
"""
Returns the URI path for a View that allows users to delete this object.
ex. Oscar (Character) = '/characters/oscar/1/delete/'
For this to work, the developer must have defined a named view somewhere
in urls.py that follows the format 'modelname-action', so in this case
a named view of 'character-detail' would be referenced by this method.
ex.
url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/delete/$',
CharDeleteView.as_view(), name='character-delete')
If no View has been created and defined in urls.py, returns an
HTML anchor.
This method is naive and simply returns a path. Securing access to
the actual view and limiting who can delete this object is the developer's
responsibility.
Returns:
path (str): URI path to object deletion page, if defined.
Examples:
::
Oscar (Character) = '/characters/oscar/1/delete/'
For this to work, the developer must have defined a named view somewhere
in urls.py that follows the format 'modelname-action', so in this case
a named view of 'character-detail' would be referenced by this method.
::
url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/delete/$',
CharDeleteView.as_view(), name='character-delete')
If no View has been created and defined in urls.py, returns an
HTML anchor.
Notes:
This method is naive and simply returns a path. Securing access to
the actual view and limiting who can delete this object is the developer's
responsibility.
"""
try:
return reverse(

View file

@ -1,16 +1,20 @@
"""
ANSI - Gives colour to text.
Use the codes defined in ANSIPARSER in your text
to apply colour to text according to the ANSI standard.
Use the codes defined in ANSIPARSER in your text to apply colour to text
according to the ANSI standard.
::
Examples:
This is |rRed text|n and this is normal again.
Mostly you should not need to call parse_ansi() explicitly;
it is run by Evennia just before returning data to/from the
user. Depreciated example forms are available by extending
the ansi mapping.
Mostly you should not need to call `parse_ansi()` explicitly; it is run by
Evennia just before returning data to/from the user. Depreciated/decativated
example forms are available in contribs by extending the ansi mapping
This module also contains the `ANSIString` custom string-type, which correctly
wraps/manipulates and tracks lengths of strings containing ANSI-markup.
----
"""
import functools
@ -78,16 +82,14 @@ _COLOR_NO_DEFAULT = settings.COLOR_NO_DEFAULT
class ANSIParser(object):
"""
A class that parses ANSI markup
to ANSI command sequences
A class that parses ANSI markup to ANSI command sequences
We also allow to escape colour codes
by prepending with a \ for xterm256,
an extra | for Merc-style codes
We also allow to escape colour codes by prepending with
an extra `|`, so `||r` will literally print `|r`.
"""
# Mapping using {r {n etc
# Mapping using |r, |n etc
ansi_map = [
# alternative |-format
@ -586,10 +588,9 @@ def _on_raw(func_name):
def _transform(func_name):
"""
Some string functions, like those manipulating capital letters,
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.
Some string functions, like those manipulating capital letters, 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.
"""
@ -982,13 +983,14 @@ class ANSIString(str, metaclass=ANSIMeta):
sep (str): The separator to split the string on.
reverse (boolean): Whether to split the string on the last
occurrence of the separator rather than the first.
Returns:
result (tuple):
prefix (ANSIString): The part of the string before the
separator
sep (ANSIString): The separator itself
postfix (ANSIString): The part of the string after the
separator.
- prefix (ANSIString): The part of the string before the
separator
- sep (ANSIString): The separator itself
- postfix (ANSIString): The part of the string after the
separator.
"""
if hasattr(sep, "_clean_string"):
@ -1287,19 +1289,26 @@ class ANSIString(str, metaclass=ANSIMeta):
Joins together strings in an iterable, using this string between each
one.
NOTE: This should always be used for joining strings when ANSIStrings
are involved. Otherwise color information will be discarded by
python, due to details in the C implementation of strings.
Args:
iterable (list of strings): A list of strings to join together
Returns:
result (ANSIString): A single string with all of the iterable's
contents concatenated, with this string between each. For
example:
ANSIString(', ').join(['up', 'right', 'left', 'down'])
...Would return:
ANSIString('up, right, left, down')
contents concatenated, with this string between each.
Examples:
::
ANSIString(', ').join(['up', 'right', 'left', 'down'])
Would return
::
ANSIString('up, right, left, down')
Notes:
This should always be used for joining strings when ANSIStrings are
involved. Otherwise color information will be discarded by python,
due to details in the C implementation of strings.
"""
result = ANSIString("")

View file

@ -31,7 +31,8 @@ etc. You also need to know Python and Evennia's API. Hence it's
recommended that the batch-code processor is limited only to
superusers or highly trusted staff.
Batch-command processor file syntax
Batch-Command processor file syntax
-----------------------------------
The batch-command processor accepts 'batchcommand files' e.g
`batch.ev`, containing a sequence of valid Evennia commands in a
@ -39,66 +40,61 @@ simple format. The engine runs each command in sequence, as if they
had been run at the game prompt.
Each Evennia command must be delimited by a line comment to mark its
end.
```
#INSERT path.batchcmdfile - this as the first entry on a line will
import and run a batch.ev file in this position, as if it was
written in this file.
```
This way entire game worlds can be created and planned offline; it is
end. This way entire game worlds can be created and planned offline; it is
especially useful in order to create long room descriptions where a
real offline text editor is often much better than any online text
editor or prompt.
There is only one batchcommand-specific entry to use in a batch-command
files (all others are just like in-game commands):
- `#INSERT path.batchcmdfile` - this as the first entry on a line will
import and run a batch.ev file in this position, as if it was
written in this file.
Example of batch.ev file:
----------------------------
::
```
# batch file
# all lines starting with # are comments; they also indicate
# that a command definition is over.
# batch file
# all lines starting with # are comments; they also indicate
# that a command definition is over.
@create box
@create box
# this comment ends the @create command.
# this comment ends the @create command.
@set box/desc = A large box.
@set box/desc = A large box.
Inside are some scattered piles of clothing.
Inside are some scattered piles of clothing.
It seems the bottom of the box is a bit loose.
It seems the bottom of the box is a bit loose.
# Again, this comment indicates the @set command is over. Note how
# the description could be freely added. Excess whitespace on a line
# is ignored. An empty line in the command definition is parsed as a \n
# (so two empty lines becomes a new paragraph).
# Again, this comment indicates the @set command is over. Note how
# the description could be freely added. Excess whitespace on a line
# is ignored. An empty line in the command definition is parsed as a \n
# (so two empty lines becomes a new paragraph).
@teleport #221
@teleport #221
# (Assuming #221 is a warehouse or something.)
# (remember, this comment ends the @teleport command! Don'f forget it)
# (Assuming #221 is a warehouse or something.)
# (remember, this comment ends the @teleport command! Don'f forget it)
# Example of importing another file at this point.
#IMPORT examples.batch
# Example of importing another file at this point.
#INSERT examples.batch
@drop box
@drop box
# Done, the box is in the warehouse! (this last comment is not necessary to
# close the @drop command since it's the end of the file)
```
# Done, the box is in the warehouse! (this last comment is not necessary to
# close the @drop command since it's the end of the file)
-------------------------
An example batch file is `contrib/examples/batch_example.ev`.
==========================================================================
Batch-code processor file syntax
Batch-Code processor file syntax
--------------------------------
The Batch-code processor accepts full python modules (e.g. `batch.py`)
that looks identical to normal Python files. The difference from
@ -113,62 +109,62 @@ the code and re-run sections of it easily during development.
Code blocks are marked by commented tokens alone on a line:
#HEADER - This denotes code that should be pasted at the top of all
other code. Multiple HEADER statements - regardless of where
it exists in the file - is the same as one big block.
Observe that changes to variables made in one block is not
preserved between blocks!
#CODE - This designates a code block that will be executed like a
stand-alone piece of code together with any HEADER(s)
defined. It is mainly used as a way to mark stop points for
the interactive mode of the batchprocessor. If no CODE block
is defined in the module, the entire module (including HEADERS)
is assumed to be a CODE block.
#INSERT path.filename - This imports another batch_code.py file and
runs it in the given position. The inserted file will retain
its own HEADERs which will not be mixed with the headers of
this file.
- `#HEADER` - This denotes code that should be pasted at the top of all
other code. Multiple HEADER statements - regardless of where
it exists in the file - is the same as one big block.
Observe that changes to variables made in one block is not
preserved between blocks!
- `#CODE` - This designates a code block that will be executed like a
stand-alone piece of code together with any HEADER(s)
defined. It is mainly used as a way to mark stop points for
the interactive mode of the batchprocessor. If no CODE block
is defined in the module, the entire module (including HEADERS)
is assumed to be a CODE block.
- `#INSERT path.filename` - This imports another batch_code.py file and
runs it in the given position. The inserted file will retain
its own HEADERs which will not be mixed with the headers of
this file.
Importing works as normal. The following variables are automatically
made available in the script namespace.
- `caller` - The object executing the batchscript
- `DEBUG` - This is a boolean marking if the batchprocessor is running
in debug mode. It can be checked to e.g. delete created objects
when running a CODE block multiple times during testing.
(avoids creating a slew of same-named db objects)
in debug mode. It can be checked to e.g. delete created objects
when running a CODE block multiple times during testing.
(avoids creating a slew of same-named db objects)
Example batch.py file:
::
Example batch.py file
-----------------------------------
#HEADER
```
#HEADER
from django.conf import settings
from evennia.utils import create
from types import basetypes
from django.conf import settings
from evennia.utils import create
from types import basetypes
GOLD = 10
GOLD = 10
#CODE
#CODE
obj = create.create_object(basetypes.Object)
obj2 = create.create_object(basetypes.Object)
obj.location = caller.location
obj.db.gold = GOLD
caller.msg("The object was created!")
obj = create.create_object(basetypes.Object)
obj2 = create.create_object(basetypes.Object)
obj.location = caller.location
obj.db.gold = GOLD
caller.msg("The object was created!")
if DEBUG:
obj.delete()
obj2.delete()
if DEBUG:
obj.delete()
obj2.delete()
#INSERT another_batch_file
#INSERT another_batch_file
#CODE
#CODE
script = create.create_script()
----
script = create.create_script()
```
"""
import re
import codecs
@ -206,7 +202,7 @@ def read_batchfile(pythonpath, file_ending=".py"):
file_ending (str): The file ending of this file (.ev or .py)
Returns:
text (str): The text content of the batch file.
str: The text content of the batch file.
Raises:
IOError: If problems reading file.
@ -255,19 +251,20 @@ class BatchCommandProcessor(object):
"""
This parses the lines of a batchfile according to the following
rules:
1) # at the beginning of a line marks the end of the command before
it. It is also a comment and any number of # can exist on
subsequent lines (but not inside comments).
2) #INSERT at the beginning of a line imports another
batch-cmd file file and pastes it into the batch file as if
it was written there.
3) Commands are placed alone at the beginning of a line and their
arguments are considered to be everything following (on any
number of lines) until the next comment line beginning with #.
4) Newlines are ignored in command definitions
5) A completely empty line in a command line definition is condered
a newline (so two empty lines is a paragraph).
6) Excess spaces and indents inside arguments are stripped.
1. `#` at the beginning of a line marks the end of the command before
it. It is also a comment and any number of # can exist on
subsequent lines (but not inside comments).
2. `#INSERT` at the beginning of a line imports another
batch-cmd file file and pastes it into the batch file as if
it was written there.
3. Commands are placed alone at the beginning of a line and their
arguments are considered to be everything following (on any
number of lines) until the next comment line beginning with #.
4. Newlines are ignored in command definitions
5. A completely empty line in a command line definition is condered
a newline (so two empty lines is a paragraph).
6. Excess spaces and indents inside arguments are stripped.
"""

View file

@ -96,7 +96,7 @@ def create_object(
location itself or during unittests.
attributes (list): Tuples on the form (key, value) or (key, value, category),
(key, value, lockstring) or (key, value, lockstring, default_access).
to set as Attributes on the new object.
to set as Attributes on the new object.
nattributes (list): Non-persistent tuples on the form (key, value). Note that
adding this rarely makes sense since this data will not survive a reload.

View file

@ -604,7 +604,7 @@ def from_pickle(data, db_obj=None):
object was removed (or changed in-place) in the database, None will be
returned.
Args_
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)
@ -612,7 +612,7 @@ def from_pickle(data, db_obj=None):
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.
`_SaverList`, `_SaverDict` and `_SaverSet` counterparts.
Returns:
data (any): Unpickled data.

View file

@ -15,32 +15,34 @@ Features of the editor:
To use the editor, just import EvEditor from this module
and initialize it:
::
from evennia.utils.eveditor import EvEditor
EvEditor(caller, loadfunc=None, savefunc=None, quitfunc=None, key="", persistent=True)
- caller is the user of the editor, the one to see all feedback.
- loadfunc(caller) is called when the editor is first launched; the
return from this function is loaded as the starting buffer in the
editor.
- safefunc(caller, buffer) is called with the current buffer when
saving in the editor. The function should return True/False depending
on if the saving was successful or not.
- quitfunc(caller) is called when the editor exits. If this is given,
no automatic quit messages will be given.
- key is an optional identifier for the editing session, to be
displayed in the editor.
- persistent means the editor state will be saved to the database making it
survive a server reload. Note that using this mode, the load- save-
and quit-funcs must all be possible to pickle - notable unusable
callables are class methods and functions defined inside other
functions. With persistent=False, no such restriction exists.
- code set to True activates features on the EvEditor to enter Python code.
- `caller` is the user of the editor, the one to see all feedback.
- `loadfunc(caller)` is called when the editor is first launched; the
return from this function is loaded as the starting buffer in the
editor.
- `safefunc(caller, buffer)` is called with the current buffer when
saving in the editor. The function should return True/False depending
on if the saving was successful or not.
- `quitfunc(caller)` is called when the editor exits. If this is given,
no automatic quit messages will be given.
- `key` is an optional identifier for the editing session, to be
displayed in the editor.
- `persistent` means the editor state will be saved to the database making it
survive a server reload. Note that using this mode, the load- save-
and quit-funcs must all be possible to pickle - notable unusable
callables are class methods and functions defined inside other
functions. With persistent=False, no such restriction exists.
- `code` set to True activates features on the EvEditor to enter Python code.
In addition, the EvEditor can be used to enter Python source code,
and offers basic handling of indentation.
----
"""
import re
@ -229,14 +231,16 @@ class CmdEditorBase(Command):
"""
Handles pre-parsing
Editor commands are on the form
Usage:
:cmd [li] [w] [txt]
Where all arguments are optional.
li - line number (int), starting from 1. This could also
be a range given as <l>:<l>.
w - word(s) (string), could be encased in quotes.
txt - extra text (string), could be encased in quotes.
- li - line number (int), starting from 1. This could also
be a range given as <l>:<l>.
- w - word(s) (string), could be encased in quotes.
- txt - extra text (string), could be encased in quotes.
"""
editor = self.caller.ndb._eveditor

View file

@ -13,34 +13,32 @@ absolute size of the field and will be filled with an `evtable.EvCell`
object when displaying the form.
Example of input file `testform.py`:
::
```python
FORMCHAR = "x"
TABLECHAR = "c"
FORMCHAR = "x"
TABLECHAR = "c"
FORM = '''
.------------------------------------------------.
| |
| Name: xxxxx1xxxxx Player: xxxxxxx2xxxxxxx |
| xxxxxxxxxxx |
| |
>----------------------------------------------<
| |
| Desc: xxxxxxxxxxx STR: x4x DEX: x5x |
| xxxxx3xxxxx INT: x6x STA: x7x |
| xxxxxxxxxxx LUC: x8x MAG: x9x |
| |
>----------------------------------------------<
| | |
| cccccccc | ccccccccccccccccccccccccccccccccccc |
| cccccccc | ccccccccccccccccccccccccccccccccccc |
| cccAcccc | ccccccccccccccccccccccccccccccccccc |
| cccccccc | ccccccccccccccccccccccccccccccccccc |
| cccccccc | cccccccccccccccccBccccccccccccccccc |
| | |
-------------------------------------------------
'''
```
FORM = '''
.------------------------------------------------.
| |
| Name: xxxxx1xxxxx Player: xxxxxxx2xxxxxxx |
| xxxxxxxxxxx |
| |
>----------------------------------------------<
| |
| Desc: xxxxxxxxxxx STR: x4x DEX: x5x |
| xxxxx3xxxxx INT: x6x STA: x7x |
| xxxxxxxxxxx LUC: x8x MAG: x9x |
| |
>----------------------------------------------<
| | |
| cccccccc | ccccccccccccccccccccccccccccccccccc |
| cccccccc | ccccccccccccccccccccccccccccccccccc |
| cccAcccc | ccccccccccccccccccccccccccccccccccc |
| cccccccc | ccccccccccccccccccccccccccccccccccc |
| cccccccc | cccccccccccccccccBccccccccccccccccc |
| | |
-------------------------------------------------
The first line of the `FORM` string is ignored. The forms and table
markers must mark out complete, unbroken rectangles, each containing
@ -54,8 +52,8 @@ character's width.
Use as follows:
::
```python
from evennia import EvForm, EvTable
# create a new form from the template
@ -87,32 +85,32 @@ Use as follows:
"B": tableB})
print(form)
```
This produces the following result:
::
.------------------------------------------------.
| |
| Name: Tom the Player: Griatch |
| Bouncer |
| |
>----------------------------------------------<
| |
| Desc: A sturdy STR: 12 DEX: 10 |
| fellow INT: 5 STA: 18 |
| LUC: 10 MAG: 3 |
| |
>----------------------------------------------<
| | |
| HP|MV|MP | Skill |Value |Exp |
| ~~+~~+~~ | ~~~~~~~~~~~+~~~~~~~~~~~+~~~~~~~~~~~ |
| **|**|** | Shooting |12 |550/1200 |
| |**|* | Herbalism |14 |990/1400 |
| |* | | Smithing |9 |205/900 |
| | |
------------------------------------------------
```
.------------------------------------------------.
| |
| Name: Tom the Player: Griatch |
| Bouncer |
| |
>----------------------------------------------<
| |
| Desc: A sturdy STR: 12 DEX: 10 |
| fellow INT: 5 STA: 18 |
| LUC: 10 MAG: 3 |
| |
>----------------------------------------------<
| | |
| HP|MV|MP | Skill |Value |Exp |
| ~~+~~+~~ | ~~~~~~~~~~~+~~~~~~~~~~~+~~~~~~~~~~~ |
| **|**|** | Shooting |12 |550/1200 |
| |**|* | Herbalism |14 |990/1400 |
| |* | | Smithing |9 |205/900 |
| | |
------------------------------------------------
```
The marked forms have been replaced with EvCells of text and with
EvTables. The form can be updated by simply re-applying `form.map()`
@ -127,6 +125,8 @@ small for it). If you try to fit a table into an area it cannot fit
into (when including its borders and at least one line of text), the
form will raise an error.
----
"""
import re
@ -186,16 +186,15 @@ class EvForm(object):
def __init__(self, filename=None, cells=None, tables=None, form=None, **kwargs):
"""
Initiate the form
Initiate the form.
Keyword Args:
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 {"FORMCHAR":char,
"TABLECHAR":char,
"FORM":templatestring}
if this is given, filename is not read.
cells (dict): A dictionary mapping of `{id:text}`.
tables (dict): A dictionary mapping of `{id:EvTable}`.
form (dict): A dictionary of
`{"FORMCHAR":char, "TABLECHAR":char, "FORM":templatestring}`.
if this is given, filename is not read.
Notes:
Other kwargs are fed as options to the EvCells and EvTables
(see `evtable.EvCell` and `evtable.EvTable` for more info).

View file

@ -1,12 +1,10 @@
"""
EvMenu
This implements a full menu system for Evennia.
The EvMenu is a full in-game menu system for Evennia.
To start the menu, just import the EvMenu class from this module.
Example usage:
```python
Example usage:
::
from evennia.utils.evmenu import EvMenu
@ -14,11 +12,10 @@ Example usage:
startnode="node1",
cmdset_mergetype="Replace", cmdset_priority=1,
auto_quit=True, cmd_on_exit="look", persistent=True)
```
Where `caller` is the Object to use the menu on - it will get a new
cmdset while using the Menu. The menu_module_path is the python path
to a python module containing function definitions. By adjusting the
cmdset while using the Menu. The `menu_module_path` is the python path
to a python module containing function definitions. By adjusting the
keyword options of the Menu() initialization call you can start the
menu at different places in the menu definition file, adjust if the
menu command should overload the normal commands or not, etc.
@ -32,8 +29,7 @@ no such restrictions exist.
The menu is defined in a module (this can be the same module as the
command definition too) with function definitions:
```python
::
def node1(caller):
# (this is the start node if called like above)
@ -47,14 +43,13 @@ command definition too) with function definitions:
def another_node(caller, input_string, **kwargs):
# code
return text, options
```
Where caller is the object using the menu and input_string is the
Where `caller` is the object using the menu and input_string is the
command entered by the user on the *previous* node (the command
entered to get to this node). The node function code will only be
executed once per node-visit and the system will accept nodes with
both one or two arguments interchangeably. It also accepts nodes
that takes **kwargs.
that takes `**kwargs`.
The menu tree itself is available on the caller as
`caller.ndb._evmenu`. This makes it a convenient place to store
@ -65,43 +60,43 @@ The return values must be given in the above order, but each can be
returned as None as well. If the options are returned as None, the
menu is immediately exited and the default "look" command is called.
text (str, tuple or None): Text shown at this node. If a tuple, the
second element in the tuple is a help text to display at this
node when the user enters the menu help command there.
options (tuple, dict or None): If `None`, this exits the menu.
If a single dict, this is a single-option node. If a tuple,
it should be a tuple of option dictionaries. Option dicts have
the following keys:
- `key` (str or tuple, optional): What to enter to choose this option.
If a tuple, it must be a tuple of strings, where the first string is the
key which will be shown to the user and the others are aliases.
If unset, the options' number will be used. The special key `_default`
marks this option as the default fallback when no other option matches
the user input. There can only be one `_default` option per node. It
will not be displayed in the list.
- `desc` (str, optional): This describes what choosing the option will do.
- `goto` (str, tuple or callable): If string, should be the name of node to go to
when this option is selected. If a callable, it has the signature
`callable(caller[,raw_input][,**kwargs]). If a tuple, the first element
is the callable and the second is a dict with the **kwargs to pass to
the callable. Those kwargs will also be passed into the next node if possible.
Such a callable should return either a str or a (str, dict), where the
string is the name of the next node to go to and the dict is the new,
(possibly modified) kwarg to pass into the next node. If the callable returns
None or the empty string, the current node will be revisited.
- `exec` (str, callable or tuple, optional): This takes the same input as `goto` above
and runs before it. If given a node name, the node will be executed but will not
be considered the next node. If node/callback returns str or (str, dict), these will
replace the `goto` step (`goto` callbacks will not fire), with the string being the
next node name and the optional dict acting as the kwargs-input for the next node.
If an exec callable returns the empty string (only), the current node is re-run.
- `text` (str, tuple or None): Text shown at this node. If a tuple, the
second element in the tuple is a help text to display at this
node when the user enters the menu help command there.
- `options` (tuple, dict or None): If `None`, this exits the menu.
If a single dict, this is a single-option node. If a tuple,
it should be a tuple of option dictionaries. Option dicts have
the following keys:
- `key` (str or tuple, optional): What to enter to choose this option.
If a tuple, it must be a tuple of strings, where the first string is the
key which will be shown to the user and the others are aliases.
If unset, the options' number will be used. The special key `_default`
marks this option as the default fallback when no other option matches
the user input. There can only be one `_default` option per node. It
will not be displayed in the list.
- `desc` (str, optional): This describes what choosing the option will do.
- `goto` (str, tuple or callable): If string, should be the name of node to go to
when this option is selected. If a callable, it has the signature
`callable(caller[,raw_input][,**kwargs])`. If a tuple, the first element
is the callable and the second is a dict with the kwargs to pass to
the callable. Those kwargs will also be passed into the next node if possible.
Such a callable should return either a str or a (str, dict), where the
string is the name of the next node to go to and the dict is the new,
(possibly modified) kwarg to pass into the next node. If the callable returns
None or the empty string, the current node will be revisited.
- `exec` (str, callable or tuple, optional): This takes the same input as `goto` above
and runs before it. If given a node name, the node will be executed but will not
be considered the next node. If node/callback returns str or (str, dict), these will
replace the `goto` step (`goto` callbacks will not fire), with the string being the
next node name and the optional dict acting as the kwargs-input for the next node.
If an exec callable returns `None`, the current node is re-run.
If key is not given, the option will automatically be identified by
its number 1..N.
Example:
```python
::
# in menu_module.py
@ -137,10 +132,9 @@ Example:
text = "This ends the menu since there are no options."
return text, None
```
When starting this menu with `Menu(caller, "path.to.menu_module")`,
the first node will look something like this:
::
This is a node text
______________________________________
@ -257,10 +251,11 @@ strings is only needed if wanting to pass strippable spaces, otherwise the
key:values will be converted to strings/numbers with literal_eval before passed
into the callable.
The `> ` option takes a glob or regex to perform different actions depending on user
The "> " option takes a glob or regex to perform different actions depending on user
input. Make sure to sort these in increasing order of generality since they
will be tested in sequence.
----
"""
@ -1317,24 +1312,32 @@ def list_node(option_generator, select=None, pagesize=10):
option_generator (callable or list): A list of strings indicating the options, or a callable
that is called as option_generator(caller) to produce such a list.
select (callable or str, optional): Node to redirect a selection to. Its `**kwargs` will
contain the `available_choices` list and `selection` will hold one of the elements in
that list. If a callable, it will be called as
select(caller, menuchoice, **kwargs) where menuchoice is the chosen option as a
string and `available_choices` is a kwarg mapping the option keys to the choices
offered by the option_generator. The callable whould return the name of the target node
to goto after this selection (or None to repeat the list-node). Note that if this is not
given, the decorated node must itself provide a way to continue from the node!
contain the `available_choices` list and `selection` will hold one
of the elements in that list. If a callable, it will be called as
`select(caller, menuchoice, **kwargs)` where menuchoice is the
chosen option as a string and `available_choices` is the list of available
options offered by the option_generator. The callable whould return
the name of the target node to goto after this selection (or None to repeat the
list-node). Note that if this is not given, the decorated node
must itself provide a way to continue from the node!
pagesize (int): How many options to show per page.
Example:
@list_node(['foo', 'bar'], select)
def node_index(caller):
text = "describing the list"
return text, []
::
def _selectfunc(caller, menuchoice, **kwargs):
# menuchoice would be either 'foo' or 'bar' here
# kwargs['available_choices'] would be the list ['foo', 'bar']
return "the_next_node_to_go_to"
@list_node(['foo', 'bar'], _selectfunc)
def node_index(caller):
text = "describing the list"
return text, []
Notes:
All normal `goto` or `exec` callables returned from the decorated nodes will, if they accept
**kwargs, get a new kwarg 'available_choices' injected. These are the ordered list of named
`**kwargs`, get a new kwarg `available_choices` injected. This is the ordered list of named
options (descs) visible on the current node page.
"""
@ -1579,13 +1582,13 @@ def get_input(caller, prompt, callback, session=None, *args, **kwargs):
greater than 2. The session is then updated by the
command and is available (for example in callbacks)
through `caller.ndb.getinput._session`.
*args, **kwargs (optional): Extra arguments will be
args, kwargs (optional): Extra arguments will be
passed to the fall back function as a list 'args'
and all keyword arguments as a dictionary 'kwargs'.
To utilise *args and **kwargs, a value for the
To utilise `*args` and `**kwargs`, a value for the
session argument must be provided (None by default)
and the callback function must take *args and
**kwargs as arguments.
and the callback function must take `*args` and
`**kwargs` as arguments.
Raises:
RuntimeError: If the given callback is not callable.

View file

@ -7,6 +7,7 @@ down in the text (the name comes from the traditional 'more' unix
command).
To use, simply pass the text through the EvMore object:
::
from evennia.utils.evmore import EvMore
@ -14,17 +15,20 @@ To use, simply pass the text through the EvMore object:
EvMore(caller, text, always_page=False, session=None, justify_kwargs=None, **kwargs)
One can also use the convenience function msg from this module:
::
from evennia.utils import evmore
text = some_long_text_output()
evmore.msg(caller, text, always_page=False, session=None, justify_kwargs=None, **kwargs)
Where always_page decides if the pager is used also if the text is not
long enough to need to scroll, session is used to determine which session to relay to
and justify_kwargs are kwargs to pass to utils.utils.justify in order to change the formatting
of the text. The remaining **kwargs will be passed on to the
caller.msg() construct every time the page is updated.
Where always_page decides if the pager is used also if the text is not long
enough to need to scroll, session is used to determine which session to relay
to and `justify_kwargs` are kwargs to pass to `utils.utils.justify` in order to
change the formatting of the text. The remaining `**kwargs` will be passed on to
the `caller.msg()` construct every time the page is updated.
----
"""
from django.conf import settings
@ -124,9 +128,10 @@ def queryset_maxsize(qs):
return qs.count()
class EvMore(object):
class EvMore:
"""
The main pager object
The main pager object.
"""
def __init__(
@ -144,23 +149,25 @@ class EvMore(object):
):
"""
Initialization of the inp handler.
Initialization of the Evmore input handler.
Args:
caller (Object or Account): Entity reading the text.
inp (str, EvTable, Paginator or iterator): The text or data to put under paging.
- If a string, paginage normally. If this text contains
one or more `\f` format symbol, automatic pagination and justification
are force-disabled and page-breaks will only happen after each `\f`.
one or more \\\\f (backslash + f) format symbols, automatic
pagination and justification are force-disabled and
page-breaks will only happen after each \\\\f.
- If `EvTable`, the EvTable will be paginated with the same
setting on each page if it is too long. The table
decorations will be considered in the size of the page.
setting on each page if it is too long. The table
decorations will be considered in the size of the page.
- Otherwise `inp` is converted to an iterator, where each step is
expected to be a line in the final display. Each line
will be run through `iter_callable`.
always_page (bool, optional): If `False`, the
pager will only kick in if `inp` is too big
to fit the screen.
expected to be a line in the final display. Each line
will be run through `iter_callable`.
always_page (bool, optional): If `False`, the pager will only kick
in if `inp` is too big to fit the screen.
session (Session, optional): If given, this session will be used
to determine the screen width and will receive all output.
justify (bool, optional): If set, auto-justify long lines. This must be turned
@ -176,30 +183,51 @@ class EvMore(object):
the caller when the more page exits. Note that this will be using whatever
cmdset the user had *before* the evmore pager was activated (so none of
the evmore commands will be available when this is run).
kwargs (any, optional): These will be passed on to the `caller.msg` method.
kwargs (any, any): These will be passed on to the `caller.msg` method.
Examples:
Basic use:
```
super_long_text = " ... "
EvMore(caller, super_long_text)
```
Paginator
```
from django.core.paginator import Paginator
query = ObjectDB.objects.all()
pages = Paginator(query, 10) # 10 objs per page
EvMore(caller, pages)
```
Every page an EvTable
```
from evennia import EvTable
def _to_evtable(page):
table = ... # convert page to a table
return EvTable(*headers, table=table, ...)
EvMore(caller, pages, page_formatter=_to_evtable)
```
::
super_long_text = " ... "
EvMore(caller, super_long_text)
Paginated query data - this is an optimization to avoid fetching
database data until it's actually paged to.
::
from django.core.paginator import Paginator
query = ObjectDB.objects.all()
pages = Paginator(query, 10) # 10 objs per page
EvMore(caller, pages)
Automatic split EvTable over multiple EvMore pages
::
table = EvMore(*header, table=tabledata)
EvMore(caller, table)
Every page a separate EvTable (optimization for very large data sets)
::
from evennia import EvTable, EvMore
class TableEvMore(EvMore):
def init_pages(self, data):
pages = # depends on data type
super().init_pages(pages)
def page_formatter(self, page):
table = EvTable()
for line in page:
cols = # split raw line into columns
table.add_row(*cols)
return str(table)
TableEvMore(caller, pages)
"""
self._caller = caller
@ -386,9 +414,10 @@ class EvMore(object):
def init_f_str(self, text):
"""
The input contains \f markers. We use \f to indicate the user wants to
enforce their line breaks on their own. If so, we do no automatic
line-breaking/justification at all.
The input contains \\\\f (backslash + f) markers. We use \\\\f to indicate
the user wants to enforce their line breaks on their own. If so, we do
no automatic line-breaking/justification at all.
"""
self._data = text.split("\f")
self._npages = len(self._data)
@ -433,14 +462,17 @@ class EvMore(object):
Notes:
If overridden, this method must perform the following actions:
- read and re-store `self._data` (the incoming data set) if needed for pagination to work.
- read and re-store `self._data` (the incoming data set) if needed
for pagination to work.
- set `self._npages` to the total number of pages. Default is 1.
- set `self._paginator` to a callable that will take a page number 1...N and return
the data to display on that page (not any decorations or next/prev buttons). If only
wanting to change the paginator, override `self.paginator` instead.
- set `self._page_formatter` to a callable that will receive the page from `self._paginator`
and format it with one element per line. Default is `str`. Or override `self.page_formatter`
directly instead.
the data to display on that page (not any decorations or next/prev buttons). If only
wanting to change the paginator, override `self.paginator` instead.
- set `self._page_formatter` to a callable that will receive the
page from `self._paginator` and format it with one element per
line. Default is `str`. Or override `self.page_formatter`
directly instead.
By default, helper methods are called that perform these actions
depending on supported inputs.
@ -520,15 +552,17 @@ def msg(
Args:
caller (Object or Account): Entity reading the text.
text (str, EvTable or iterator): The text or data to put under paging.
- If a string, paginage normally. If this text contains
one or more `\f` format symbol, automatic pagination is disabled
and page-breaks will only happen after each `\f`.
one or more \\\\f (backslash + f) format symbol, automatic pagination is disabled
and page-breaks will only happen after each \\\\f.
- If `EvTable`, the EvTable will be paginated with the same
setting on each page if it is too long. The table
decorations will be considered in the size of the page.
setting on each page if it is too long. The table
decorations will be considered in the size of the page.
- Otherwise `text` is converted to an iterator, where each step is
is expected to be a line in the final display, and each line
will be run through repr().
always_page (bool, optional): If `False`, the
pager will only kick in if `text` is too big
to fit the screen.

View file

@ -1,66 +1,61 @@
"""
This is an advanced ASCII table creator. It was inspired by
[prettytable](https://code.google.com/p/prettytable/) but shares no
code.
[prettytable](https://code.google.com/p/prettytable/) but shares no code.
Example usage:
::
```python
from evennia.utils import evtable
from evennia.utils import evtable
table = evtable.EvTable("Heading1", "Heading2",
table = evtable.EvTable("Heading1", "Heading2",
table=[[1,2,3],[4,5,6],[7,8,9]], border="cells")
table.add_column("This is long data", "This is even longer data")
table.add_row("This is a single row")
print table
```
table.add_column("This is long data", "This is even longer data")
table.add_row("This is a single row")
print table
Result:
::
```
+----------------------+----------+---+--------------------------+
| Heading1 | Heading2 | | |
+~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~~+~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~+
| 1 | 4 | 7 | This is long data |
+----------------------+----------+---+--------------------------+
| 2 | 5 | 8 | This is even longer data |
+----------------------+----------+---+--------------------------+
| 3 | 6 | 9 | |
+----------------------+----------+---+--------------------------+
| This is a single row | | | |
+----------------------+----------+---+--------------------------+
```
+----------------------+----------+---+--------------------------+
| Heading1 | Heading2 | | |
+~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~~+~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~+
| 1 | 4 | 7 | This is long data |
+----------------------+----------+---+--------------------------+
| 2 | 5 | 8 | This is even longer data |
+----------------------+----------+---+--------------------------+
| 3 | 6 | 9 | |
+----------------------+----------+---+--------------------------+
| This is a single row | | | |
+----------------------+----------+---+--------------------------+
As seen, the table will automatically expand with empty cells to make
the table symmetric. Tables can be restricted to a given width:
::
```python
table.reformat(width=50, align="l")
```
table.reformat(width=50, align="l")
(We could just have added these keywords to the table creation call)
This yields the following result:
::
```
+-----------+------------+-----------+-----------+
| Heading1 | Heading2 | | |
+~~~~~~~~~~~+~~~~~~~~~~~~+~~~~~~~~~~~+~~~~~~~~~~~+
| 1 | 4 | 7 | This is |
| | | | long data |
+-----------+------------+-----------+-----------+
| | | | This is |
| 2 | 5 | 8 | even |
| | | | longer |
| | | | data |
+-----------+------------+-----------+-----------+
| 3 | 6 | 9 | |
+-----------+------------+-----------+-----------+
| This is a | | | |
| single | | | |
| row | | | |
+-----------+------------+-----------+-----------+
```
+-----------+------------+-----------+-----------+
| Heading1 | Heading2 | | |
+~~~~~~~~~~~+~~~~~~~~~~~~+~~~~~~~~~~~+~~~~~~~~~~~+
| 1 | 4 | 7 | This is |
| | | | long data |
+-----------+------------+-----------+-----------+
| | | | This is |
| 2 | 5 | 8 | even |
| | | | longer |
| | | | data |
+-----------+------------+-----------+-----------+
| 3 | 6 | 9 | |
+-----------+------------+-----------+-----------+
| This is a | | | |
| single | | | |
| row | | | |
+-----------+------------+-----------+-----------+
Table-columns can be individually formatted. Note that if an
individual column is set with a specific width, table auto-balancing
@ -68,29 +63,25 @@ will not affect this column (this may lead to the full table being too
wide, so be careful mixing fixed-width columns with auto- balancing).
Here we change the width and alignment of the column at index 3
(Python starts from 0):
::
```python
table.reformat_column(3, width=30, align="r")
print table
table.reformat_column(3, width=30, align="r")
print table
```
```
+-----------+-------+-----+-----------------------------+---------+
| Heading1 | Headi | | | |
| | ng2 | | | |
+~~~~~~~~~~~+~~~~~~~+~~~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~+
| 1 | 4 | 7 | This is long data | Test1 |
+-----------+-------+-----+-----------------------------+---------+
| 2 | 5 | 8 | This is even longer data | Test3 |
+-----------+-------+-----+-----------------------------+---------+
| 3 | 6 | 9 | | Test4 |
+-----------+-------+-----+-----------------------------+---------+
| This is a | | | | |
| single | | | | |
| row | | | | |
+-----------+-------+-----+-----------------------------+---------+
```
+-----------+-------+-----+-----------------------------+---------+
| Heading1 | Headi | | | |
| | ng2 | | | |
+~~~~~~~~~~~+~~~~~~~+~~~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~+
| 1 | 4 | 7 | This is long data | Test1 |
+-----------+-------+-----+-----------------------------+---------+
| 2 | 5 | 8 | This is even longer data | Test3 |
+-----------+-------+-----+-----------------------------+---------+
| 3 | 6 | 9 | | Test4 |
+-----------+-------+-----+-----------------------------+---------+
| This is a | | | | |
| single | | | | |
| row | | | | |
+-----------+-------+-----+-----------------------------+---------+
When adding new rows/columns their data can have its own alignments
(left/center/right, top/center/bottom).
@ -109,6 +100,8 @@ eventual colour outside the table will not transfer "across" a table,
you need to re-set the color to have it appear on both sides of the
table string.
----
"""
from django.conf import settings

View file

@ -2,20 +2,18 @@
Inline functions (nested form).
This parser accepts nested inlinefunctions on the form
::
```
$funcname(arg, arg, ...)
```
$funcname(arg, arg, ...)
embedded in any text where any arg can be another $funcname{} call.
embedded in any text where any arg can be another `$funcname{}` call.
This functionality is turned off by default - to activate,
`settings.INLINEFUNC_ENABLED` must be set to `True`.
Each token starts with "$funcname(" where there must be no space
between the $funcname and (. It ends with a matched ending parentesis.
")".
Each token starts with `$funcname(` where there must be no space between the
$funcname and "(". It ends with a matched ending parentesis ")".
Inside the inlinefunc definition, one can use `\` to escape. This is
Inside the inlinefunc definition, one can use \\\\ to escape. This is
mainly needed for escaping commas in flowing text (which would
otherwise be interpreted as an argument separator), or to escape `}`
when not intended to close the function block. Enclosing text in
@ -27,11 +25,10 @@ The available inlinefuncs are defined as global-level functions in
modules defined by `settings.INLINEFUNC_MODULES`. They are identified
by their function name (and ignored if this name starts with `_`). They
should be on the following form:
::
```python
def funcname (*args, **kwargs):
def funcname (*args, **kwargs):
# ...
```
Here, the arguments given to `$funcname(arg1,arg2)` will appear as the
`*args` tuple. This will be populated by the arguments given to the
@ -44,19 +41,21 @@ the string is sent to a non-puppetable object. The inlinefunc should
never raise an exception.
There are two reserved function names:
- "nomatch": This is called if the user uses a functionname that is
not registered. The nomatch function will get the name of the
not-found function as its first argument followed by the normal
arguments to the given function. If not defined the default effect is
to print `<UNKNOWN>` to replace the unknown function.
not registered. The nomatch function will get the name of the
not-found function as its first argument followed by the normal
arguments to the given function. If not defined the default effect is
to print `<UNKNOWN>` to replace the unknown function.
- "stackfull": This is called when the maximum nested function stack is reached.
When this happens, the original parsed string is returned and the result of
the `stackfull` inlinefunc is appended to the end. By default this is an
error message.
Error handling:
Syntax errors, notably not completely closing all inlinefunc
blocks, will lead to the entire string remaining unparsed.
Syntax errors, notably not completely closing all inlinefunc blocks, will lead
to the entire string remaining unparsed.
----
"""
@ -92,9 +91,10 @@ def random(*args, **kwargs):
given range.
Example:
`$random()`
`$random(5)`
`$random(5, 10)`
- `$random()`
- `$random(5)`
- `$random(5, 10)`
"""
nargs = len(args)
@ -574,12 +574,12 @@ def initialize_nick_templates(in_template, out_template):
Args:
in_template (str): The template to be used for nick recognition.
out_template (str): The template to be used to replace the string
matched by the in_template.
matched by the `in_template`.
Returns:
regex (regex): Regex to match against strings
template (str): Template with markers {arg1}, {arg2}, etc for
replacement using the standard .format method.
regex, template (regex, str): Regex to match against strings and a
template with markers `{arg1}`, `{arg2}`, etc for replacement using the
standard `.format` method.
Raises:
NickTemplateInvalid: If the in/out template does not have a matching

View file

@ -1,3 +1,9 @@
"""
Option classes store user- or server Options in a generic way
while also providing validation.
"""
import datetime
from evennia import logger
from evennia.utils.ansi import strip_ansi
@ -6,7 +12,7 @@ from evennia.utils.utils import crop
from evennia.utils import validatorfuncs
class BaseOption(object):
class BaseOption:
"""
Abstract Class to deal with encapsulating individual Options. An Option has
a name/key, a description to display in relevant commands and menus, and a
@ -109,7 +115,7 @@ class BaseOption(object):
def save(self, **kwargs):
"""
Stores the current value using .handler.save_handler(self.key, value, **kwargs)
Stores the current value using `.handler.save_handler(self.key, value, **kwargs)`
where kwargs are a combination of those passed into this function and the
ones specified by the OptionHandler.

View file

@ -36,7 +36,6 @@ __all__ = (
"search_message",
"search_channel",
"search_help_entry",
"search_object_tag",
"search_script_tag",
"search_account_tag",
"search_channel_tag",

View file

@ -38,17 +38,19 @@ def unload_module(module):
an object, the module in which that object sits will be unloaded. A string
should directly give the module pathname to unload.
Example:
# (in a test method)
unload_module(foo)
with mock.patch("foo.GLOBALTHING", "mockval"):
import foo
... # test code using foo.GLOBALTHING, now set to 'mockval'
Example:
::
# (in a test method)
unload_module(foo)
with mock.patch("foo.GLOBALTHING", "mockval"):
import foo
... # test code using foo.GLOBALTHING, now set to 'mockval'
This allows for mocking constants global to the module, since
otherwise those would not be mocked (since a module is only
loaded once).
Notes:
This allows for mocking constants global to the module, since
otherwise those would not be mocked (since a module is only
loaded once).
"""
if isinstance(module, str):

View file

@ -1069,7 +1069,7 @@ def run_async(to_execute, *args, **kwargs):
Args:
to_execute (callable): If this is a callable, it will be
executed with *args and non-reserved *kwargs as arguments.
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.
@ -1168,7 +1168,7 @@ def check_evennia_dependencies():
def has_parent(basepath, obj):
"""
Checks if `basepath` is somewhere in `obj`s parent tree.
Checks if `basepath` is somewhere in `obj`'s parent tree.
Args:
basepath (str): Python dotpath to compare against obj path.
@ -1495,8 +1495,8 @@ def init_new_account(account):
def string_similarity(string1, string2):
"""
This implements a "cosine-similarity" algorithm as described for example in
*Proceedings of the 22nd International Conference on Computation
Linguistics* (Coling 2008), pages 593-600, Manchester, August 2008.
*Proceedings of the 22nd International Conference on Computation
Linguistics* (Coling 2008), pages 593-600, Manchester, August 2008.
The measure-vectors used is simply a "bag of words" type histogram
(but for letters).
@ -1605,9 +1605,9 @@ def string_partial_matching(alternatives, inp, ret_index=True):
def format_table(table, extra_space=1):
"""
Note: `evennia.utils.evtable` is more powerful than this, but this
function can be useful when the number of columns and rows are
unknown and must be calculated on the fly.
Note: `evennia.utils.evtable` is more powerful than this, but this function
can be useful when the number of columns and rows are unknown and must be
calculated on the fly.
Args.
table (list): A list of lists to represent columns in the
@ -1626,18 +1626,18 @@ def format_table(table, extra_space=1):
The function formats the columns to be as wide as the widest member
of each column.
Examples:
Example:
::
ftable = format_table([[...], [...], ...])
for ir, row in enumarate(ftable):
if ir == 0:
# make first row white
string += "\\\\n|w" + ""join(row) + "|n"
else:
string += "\\\\n" + "".join(row)
print(string)
```python
ftable = format_table([[...], [...], ...])
for ir, row in enumarate(ftable):
if ir == 0:
# make first row white
string += "\n|w" + ""join(row) + "|n"
else:
string += "\n" + "".join(row)
print string
```
"""
if not table:
return [[]]
@ -2051,26 +2051,28 @@ def get_all_typeclasses(parent=None):
def interactive(func):
"""
Decorator to make a method pausable with yield(seconds)
and able to ask for user-input with response=yield(question).
For the question-asking to work, 'caller' must the name
of an argument or kwarg to the decorated function.
Decorator to make a method pausable with yield(seconds) and able to ask for
user-input with `response=yield(question)`. For the question-asking to
work, 'caller' must the name of an argument or kwarg to the decorated
function.
Note that this turns the method into a generator.
Example:
::
Example usage:
@interactive
def myfunc(caller):
caller.msg("This is a test")
# wait five seconds
yield(5)
# ask user (caller) a question
response = yield("Do you want to continue waiting?")
if response == "yes":
@interactive
def myfunc(caller):
caller.msg("This is a test")
# wait five seconds
yield(5)
else:
# ...
# ask user (caller) a question
response = yield("Do you want to continue waiting?")
if response == "yes":
yield(5)
else:
# ...
Notes:
This turns the method into a generator!
"""
from evennia.utils.evmenu import get_input

View file

@ -39,8 +39,8 @@ def color(entry, option_key="Color", **kwargs):
def datetime(entry, option_key="Datetime", account=None, from_tz=None, **kwargs):
"""
Process a datetime string in standard forms while accounting for the inputer's timezone. Always
returns a result in UTC.
Process a datetime string in standard forms while accounting for the
inputer's timezone. Always returns a result in UTC.
Args:
entry (str): A date string from a user.
@ -48,10 +48,12 @@ def datetime(entry, option_key="Datetime", account=None, from_tz=None, **kwargs)
account (AccountDB): The Account performing this lookup. Unless `from_tz` is provided,
the account's timezone option will be used.
from_tz (pytz.timezone): An instance of a pytz timezone object from the
user. If not provided, tries to use the timezone option of the `account'.
user. If not provided, tries to use the timezone option of the `account`.
If neither one is provided, defaults to UTC.
Returns:
datetime in UTC.
Raises:
ValueError: If encountering a malformed timezone, date string or other format error.