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 # 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 # `(r"%c%r", ansi.ANSI_RED)` (the evennia.utils.ansi module contains all
# ANSI escape sequences). Default is to use `|` and `|[` -prefixes. # 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 = [] COLOR_ANSI_EXTRA_MAP = []
# Extend the available regexes for adding XTERM256 colors in-game. This is given # 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 # 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 # 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. # 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 # XTERM256 foreground color replacement
# Note that to apply all color changes, a full `evennia reboot` is needed!
COLOR_XTERM256_EXTRA_FG = [] COLOR_XTERM256_EXTRA_FG = []
# XTERM256 background color replacement. Default is \|\[([0-5])([0-5])([0-5])' # 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 = [] COLOR_XTERM256_EXTRA_BG = []
# Extend the available regexes for adding XTERM256 grayscale values in-game. Given # 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 # 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])', # 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. # which allows e.g. |=k for a medium gray.
# XTERM256 grayscale foreground # XTERM256 grayscale foreground
# Note that to apply all color changes, a full `evennia reboot` is needed!
COLOR_XTERM256_EXTRA_GFG = [] COLOR_XTERM256_EXTRA_GFG = []
# XTERM256 grayscale background. Default is \|\[=([a-z])' # XTERM256 grayscale background. Default is \|\[=([a-z])'
# Note that to apply all color changes, a full `evennia reboot` is needed!
COLOR_XTERM256_EXTRA_GBG = [] COLOR_XTERM256_EXTRA_GBG = []
# ANSI does not support bright backgrounds, so Evennia fakes this by mapping it to # 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 # 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 = [] COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP = []
# If set True, the above color settings *replace* the default |-style color markdown # If set True, the above color settings *replace* the default |-style color markdown
# rather than extend it. # rather than extend it.
# Note that to apply all color changes, a full `evennia reboot` is needed!
COLOR_NO_DEFAULT = False COLOR_NO_DEFAULT = False

View file

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

View file

@ -1,16 +1,20 @@
""" """
ANSI - Gives colour to text. ANSI - Gives colour to text.
Use the codes defined in ANSIPARSER in your text Use the codes defined in ANSIPARSER in your text to apply colour to text
to apply colour to text according to the ANSI standard. according to the ANSI standard.
::
Examples:
This is |rRed text|n and this is normal again. This is |rRed text|n and this is normal again.
Mostly you should not need to call parse_ansi() explicitly; Mostly you should not need to call `parse_ansi()` explicitly; it is run by
it is run by Evennia just before returning data to/from the Evennia just before returning data to/from the user. Depreciated/decativated
user. Depreciated example forms are available by extending example forms are available in contribs by extending the ansi mapping
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 import functools
@ -78,16 +82,14 @@ _COLOR_NO_DEFAULT = settings.COLOR_NO_DEFAULT
class ANSIParser(object): class ANSIParser(object):
""" """
A class that parses ANSI markup A class that parses ANSI markup to ANSI command sequences
to ANSI command sequences
We also allow to escape colour codes We also allow to escape colour codes by prepending with
by prepending with a \ for xterm256, an extra `|`, so `||r` will literally print `|r`.
an extra | for Merc-style codes
""" """
# Mapping using {r {n etc # Mapping using |r, |n etc
ansi_map = [ ansi_map = [
# alternative |-format # alternative |-format
@ -586,10 +588,9 @@ def _on_raw(func_name):
def _transform(func_name): def _transform(func_name):
""" """
Some string functions, like those manipulating capital letters, Some string functions, like those manipulating capital letters, return a
return a string the same length as the original. This function string the same length as the original. This function allows us to do the
allows us to do the same, replacing all the non-coded characters same, replacing all the non-coded characters with the resulting string.
with the resulting string.
""" """
@ -982,12 +983,13 @@ class ANSIString(str, metaclass=ANSIMeta):
sep (str): The separator to split the string on. sep (str): The separator to split the string on.
reverse (boolean): Whether to split the string on the last reverse (boolean): Whether to split the string on the last
occurrence of the separator rather than the first. occurrence of the separator rather than the first.
Returns: Returns:
result (tuple): result (tuple):
prefix (ANSIString): The part of the string before the - prefix (ANSIString): The part of the string before the
separator separator
sep (ANSIString): The separator itself - sep (ANSIString): The separator itself
postfix (ANSIString): The part of the string after the - postfix (ANSIString): The part of the string after the
separator. separator.
""" """
@ -1287,20 +1289,27 @@ class ANSIString(str, metaclass=ANSIMeta):
Joins together strings in an iterable, using this string between each Joins together strings in an iterable, using this string between each
one. 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: Args:
iterable (list of strings): A list of strings to join together iterable (list of strings): A list of strings to join together
Returns: Returns:
result (ANSIString): A single string with all of the iterable's result (ANSIString): A single string with all of the iterable's
contents concatenated, with this string between each. For contents concatenated, with this string between each.
example:
Examples:
::
ANSIString(', ').join(['up', 'right', 'left', 'down']) ANSIString(', ').join(['up', 'right', 'left', 'down'])
...Would return:
Would return
::
ANSIString('up, right, left, down') 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("") result = ANSIString("")
last_item = None last_item = None

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

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 object was removed (or changed in-place) in the database, None will be
returned. returned.
Args_ Args:
data (any): Pickled data to unpickle. data (any): Pickled data to unpickle.
db_obj (Atribute, any): This is the model instance (normally db_obj (Atribute, any): This is the model instance (normally
an Attribute) that _Saver*-type iterables (_SaverList etc) 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 that saves assigned data to the database. Skip if not
serializing onto a given object. If db_obj is given, this serializing onto a given object. If db_obj is given, this
function will convert lists, dicts and sets to their function will convert lists, dicts and sets to their
_SaverList, _SaverDict and _SaverSet counterparts. `_SaverList`, `_SaverDict` and `_SaverSet` counterparts.
Returns: Returns:
data (any): Unpickled data. data (any): Unpickled data.

View file

@ -15,32 +15,34 @@ Features of the editor:
To use the editor, just import EvEditor from this module To use the editor, just import EvEditor from this module
and initialize it: and initialize it:
::
from evennia.utils.eveditor import EvEditor from evennia.utils.eveditor import EvEditor
EvEditor(caller, loadfunc=None, savefunc=None, quitfunc=None, key="", persistent=True) EvEditor(caller, loadfunc=None, savefunc=None, quitfunc=None, key="", persistent=True)
- caller is the user of the editor, the one to see all feedback. - `caller` is the user of the editor, the one to see all feedback.
- loadfunc(caller) is called when the editor is first launched; the - `loadfunc(caller)` is called when the editor is first launched; the
return from this function is loaded as the starting buffer in the return from this function is loaded as the starting buffer in the
editor. editor.
- safefunc(caller, buffer) is called with the current buffer when - `safefunc(caller, buffer)` is called with the current buffer when
saving in the editor. The function should return True/False depending saving in the editor. The function should return True/False depending
on if the saving was successful or not. on if the saving was successful or not.
- quitfunc(caller) is called when the editor exits. If this is given, - `quitfunc(caller)` is called when the editor exits. If this is given,
no automatic quit messages will be given. no automatic quit messages will be given.
- key is an optional identifier for the editing session, to be - `key` is an optional identifier for the editing session, to be
displayed in the editor. displayed in the editor.
- persistent means the editor state will be saved to the database making it - `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- survive a server reload. Note that using this mode, the load- save-
and quit-funcs must all be possible to pickle - notable unusable and quit-funcs must all be possible to pickle - notable unusable
callables are class methods and functions defined inside other callables are class methods and functions defined inside other
functions. With persistent=False, no such restriction exists. functions. With persistent=False, no such restriction exists.
- code set to True activates features on the EvEditor to enter Python code. - `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, In addition, the EvEditor can be used to enter Python source code,
and offers basic handling of indentation. and offers basic handling of indentation.
----
""" """
import re import re
@ -229,14 +231,16 @@ class CmdEditorBase(Command):
""" """
Handles pre-parsing Handles pre-parsing
Editor commands are on the form Usage:
:cmd [li] [w] [txt] :cmd [li] [w] [txt]
Where all arguments are optional. Where all arguments are optional.
li - line number (int), starting from 1. This could also
- li - line number (int), starting from 1. This could also
be a range given as <l>:<l>. be a range given as <l>:<l>.
w - word(s) (string), could be encased in quotes. - w - word(s) (string), could be encased in quotes.
txt - extra text (string), could be encased in quotes. - txt - extra text (string), could be encased in quotes.
""" """
editor = self.caller.ndb._eveditor 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. object when displaying the form.
Example of input file `testform.py`: Example of input file `testform.py`:
::
```python FORMCHAR = "x"
FORMCHAR = "x" TABLECHAR = "c"
TABLECHAR = "c"
FORM = ''' FORM = '''
.------------------------------------------------. .------------------------------------------------.
| | | |
| Name: xxxxx1xxxxx Player: xxxxxxx2xxxxxxx | | Name: xxxxx1xxxxx Player: xxxxxxx2xxxxxxx |
| xxxxxxxxxxx | | xxxxxxxxxxx |
| | | |
>----------------------------------------------< >----------------------------------------------<
| | | |
| Desc: xxxxxxxxxxx STR: x4x DEX: x5x | | Desc: xxxxxxxxxxx STR: x4x DEX: x5x |
| xxxxx3xxxxx INT: x6x STA: x7x | | xxxxx3xxxxx INT: x6x STA: x7x |
| xxxxxxxxxxx LUC: x8x MAG: x9x | | xxxxxxxxxxx LUC: x8x MAG: x9x |
| | | |
>----------------------------------------------< >----------------------------------------------<
| | | | | |
| cccccccc | ccccccccccccccccccccccccccccccccccc | | cccccccc | ccccccccccccccccccccccccccccccccccc |
| cccccccc | ccccccccccccccccccccccccccccccccccc | | cccccccc | ccccccccccccccccccccccccccccccccccc |
| cccAcccc | ccccccccccccccccccccccccccccccccccc | | cccAcccc | ccccccccccccccccccccccccccccccccccc |
| cccccccc | ccccccccccccccccccccccccccccccccccc | | cccccccc | ccccccccccccccccccccccccccccccccccc |
| cccccccc | cccccccccccccccccBccccccccccccccccc | | cccccccc | cccccccccccccccccBccccccccccccccccc |
| | | | | |
------------------------------------------------- -------------------------------------------------
'''
```
The first line of the `FORM` string is ignored. The forms and table The first line of the `FORM` string is ignored. The forms and table
markers must mark out complete, unbroken rectangles, each containing markers must mark out complete, unbroken rectangles, each containing
@ -54,8 +52,8 @@ character's width.
Use as follows: Use as follows:
::
```python
from evennia import EvForm, EvTable from evennia import EvForm, EvTable
# create a new form from the template # create a new form from the template
@ -87,32 +85,32 @@ Use as follows:
"B": tableB}) "B": tableB})
print(form) print(form)
```
This produces the following result: This produces the following result:
::
``` .------------------------------------------------.
.------------------------------------------------. | |
| | | Name: Tom the Player: Griatch |
| Name: Tom the Player: Griatch | | Bouncer |
| Bouncer | | |
| |
>----------------------------------------------< >----------------------------------------------<
| | | |
| Desc: A sturdy STR: 12 DEX: 10 | | Desc: A sturdy STR: 12 DEX: 10 |
| fellow INT: 5 STA: 18 | | fellow INT: 5 STA: 18 |
| LUC: 10 MAG: 3 | | LUC: 10 MAG: 3 |
| | | |
>----------------------------------------------< >----------------------------------------------<
| | | | | |
| HP|MV|MP | Skill |Value |Exp | | HP|MV|MP | Skill |Value |Exp |
| ~~+~~+~~ | ~~~~~~~~~~~+~~~~~~~~~~~+~~~~~~~~~~~ | | ~~+~~+~~ | ~~~~~~~~~~~+~~~~~~~~~~~+~~~~~~~~~~~ |
| **|**|** | Shooting |12 |550/1200 | | **|**|** | Shooting |12 |550/1200 |
| |**|* | Herbalism |14 |990/1400 | | |**|* | Herbalism |14 |990/1400 |
| |* | | Smithing |9 |205/900 | | |* | | Smithing |9 |205/900 |
| | | | | |
------------------------------------------------ ------------------------------------------------
```
The marked forms have been replaced with EvCells of text and with The marked forms have been replaced with EvCells of text and with
EvTables. The form can be updated by simply re-applying `form.map()` 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 into (when including its borders and at least one line of text), the
form will raise an error. form will raise an error.
----
""" """
import re import re
@ -186,15 +186,14 @@ class EvForm(object):
def __init__(self, filename=None, cells=None, tables=None, form=None, **kwargs): def __init__(self, filename=None, cells=None, tables=None, form=None, **kwargs):
""" """
Initiate the form Initiate the form.
Keyword Args: Keyword Args:
filename (str): Path to template file. filename (str): Path to template file.
cells (dict): A dictionary mapping of {id:text} cells (dict): A dictionary mapping of `{id:text}`.
tables (dict): A dictionary mapping of {id:EvTable}. tables (dict): A dictionary mapping of `{id:EvTable}`.
form (dict): A dictionary of {"FORMCHAR":char, form (dict): A dictionary of
"TABLECHAR":char, `{"FORMCHAR":char, "TABLECHAR":char, "FORM":templatestring}`.
"FORM":templatestring}
if this is given, filename is not read. if this is given, filename is not read.
Notes: Notes:
Other kwargs are fed as options to the EvCells and EvTables Other kwargs are fed as options to the EvCells and EvTables

View file

@ -1,12 +1,10 @@
""" """
EvMenu The EvMenu is a full in-game menu system for Evennia.
This implements a full menu system for Evennia.
To start the menu, just import the EvMenu class from this module. To start the menu, just import the EvMenu class from this module.
Example usage:
```python Example usage:
::
from evennia.utils.evmenu import EvMenu from evennia.utils.evmenu import EvMenu
@ -14,10 +12,9 @@ Example usage:
startnode="node1", startnode="node1",
cmdset_mergetype="Replace", cmdset_priority=1, cmdset_mergetype="Replace", cmdset_priority=1,
auto_quit=True, cmd_on_exit="look", persistent=True) auto_quit=True, cmd_on_exit="look", persistent=True)
```
Where `caller` is the Object to use the menu on - it will get a new 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 cmdset while using the Menu. The `menu_module_path` is the python path
to a python module containing function definitions. By adjusting the to a python module containing function definitions. By adjusting the
keyword options of the Menu() initialization call you can start 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 at different places in the menu definition file, adjust if the
@ -32,8 +29,7 @@ no such restrictions exist.
The menu is defined in a module (this can be the same module as the The menu is defined in a module (this can be the same module as the
command definition too) with function definitions: command definition too) with function definitions:
::
```python
def node1(caller): def node1(caller):
# (this is the start node if called like above) # (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): def another_node(caller, input_string, **kwargs):
# code # code
return text, options 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 command entered by the user on the *previous* node (the command
entered to get to this node). The node function code will only be 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 executed once per node-visit and the system will accept nodes with
both one or two arguments interchangeably. It also accepts nodes 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 The menu tree itself is available on the caller as
`caller.ndb._evmenu`. This makes it a convenient place to store `caller.ndb._evmenu`. This makes it a convenient place to store
@ -65,13 +60,14 @@ 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 returned as None as well. If the options are returned as None, the
menu is immediately exited and the default "look" command is called. 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 - `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 second element in the tuple is a help text to display at this
node when the user enters the menu help command there. node when the user enters the menu help command there.
options (tuple, dict or None): If `None`, this exits the menu. - `options` (tuple, dict or None): If `None`, this exits the menu.
If a single dict, this is a single-option node. If a tuple, If a single dict, this is a single-option node. If a tuple,
it should be a tuple of option dictionaries. Option dicts have it should be a tuple of option dictionaries. Option dicts have
the following keys: the following keys:
- `key` (str or tuple, optional): What to enter to choose this option. - `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 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. key which will be shown to the user and the others are aliases.
@ -82,8 +78,8 @@ menu is immediately exited and the default "look" command is called.
- `desc` (str, optional): This describes what choosing the option will do. - `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 - `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 when this option is selected. If a callable, it has the signature
`callable(caller[,raw_input][,**kwargs]). If a tuple, the first element `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 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. 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 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, string is the name of the next node to go to and the dict is the new,
@ -94,14 +90,13 @@ menu is immediately exited and the default "look" command is called.
be considered the next node. If node/callback returns str or (str, dict), these will 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 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. 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. If an exec callable returns `None`, the current node is re-run.
If key is not given, the option will automatically be identified by If key is not given, the option will automatically be identified by
its number 1..N. its number 1..N.
Example: Example:
::
```python
# in menu_module.py # in menu_module.py
@ -137,10 +132,9 @@ Example:
text = "This ends the menu since there are no options." text = "This ends the menu since there are no options."
return text, None return text, None
```
When starting this menu with `Menu(caller, "path.to.menu_module")`, When starting this menu with `Menu(caller, "path.to.menu_module")`,
the first node will look something like this: the first node will look something like this:
::
This is a node text 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 key:values will be converted to strings/numbers with literal_eval before passed
into the callable. 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 input. Make sure to sort these in increasing order of generality since they
will be tested in sequence. 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 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. 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 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 contain the `available_choices` list and `selection` will hold one
that list. If a callable, it will be called as 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 `select(caller, menuchoice, **kwargs)` where menuchoice is the
string and `available_choices` is a kwarg mapping the option keys to the choices chosen option as a string and `available_choices` is the list of available
offered by the option_generator. The callable whould return the name of the target node options offered by the option_generator. The callable whould return
to goto after this selection (or None to repeat the list-node). Note that if this is not the name of the target node to goto after this selection (or None to repeat the
given, the decorated node must itself provide a way to continue from the node! 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. pagesize (int): How many options to show per page.
Example: Example:
@list_node(['foo', 'bar'], select) ::
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): def node_index(caller):
text = "describing the list" text = "describing the list"
return text, [] return text, []
Notes: Notes:
All normal `goto` or `exec` callables returned from the decorated nodes will, if they accept 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. 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 greater than 2. The session is then updated by the
command and is available (for example in callbacks) command and is available (for example in callbacks)
through `caller.ndb.getinput._session`. 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' passed to the fall back function as a list 'args'
and all keyword arguments as a dictionary 'kwargs'. 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) session argument must be provided (None by default)
and the callback function must take *args and and the callback function must take `*args` and
**kwargs as arguments. `**kwargs` as arguments.
Raises: Raises:
RuntimeError: If the given callback is not callable. 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). command).
To use, simply pass the text through the EvMore object: To use, simply pass the text through the EvMore object:
::
from evennia.utils.evmore import EvMore 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) EvMore(caller, text, always_page=False, session=None, justify_kwargs=None, **kwargs)
One can also use the convenience function msg from this module: One can also use the convenience function msg from this module:
::
from evennia.utils import evmore from evennia.utils import evmore
text = some_long_text_output() text = some_long_text_output()
evmore.msg(caller, text, always_page=False, session=None, justify_kwargs=None, **kwargs) 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 Where always_page decides if the pager is used also if the text is not long
long enough to need to scroll, session is used to determine which session to relay to enough to need to scroll, session is used to determine which session to relay
and justify_kwargs are kwargs to pass to utils.utils.justify in order to change the formatting to and `justify_kwargs` are kwargs to pass to `utils.utils.justify` in order to
of the text. The remaining **kwargs will be passed on to the change the formatting of the text. The remaining `**kwargs` will be passed on to
caller.msg() construct every time the page is updated. the `caller.msg()` construct every time the page is updated.
----
""" """
from django.conf import settings from django.conf import settings
@ -124,9 +128,10 @@ def queryset_maxsize(qs):
return qs.count() return qs.count()
class EvMore(object): class EvMore:
""" """
The main pager object The main pager object.
""" """
def __init__( def __init__(
@ -144,23 +149,25 @@ class EvMore(object):
): ):
""" """
Initialization of the inp handler. Initialization of the Evmore input handler.
Args: Args:
caller (Object or Account): Entity reading the text. caller (Object or Account): Entity reading the text.
inp (str, EvTable, Paginator or iterator): The text or data to put under paging. inp (str, EvTable, Paginator or iterator): The text or data to put under paging.
- If a string, paginage normally. If this text contains - If a string, paginage normally. If this text contains
one or more `\f` format symbol, automatic pagination and justification one or more \\\\f (backslash + f) format symbols, automatic
are force-disabled and page-breaks will only happen after each `\f`. 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 - If `EvTable`, the EvTable will be paginated with the same
setting on each page if it is too long. The table setting on each page if it is too long. The table
decorations will be considered in the size of the page. decorations will be considered in the size of the page.
- Otherwise `inp` is converted to an iterator, where each step is - Otherwise `inp` is converted to an iterator, where each step is
expected to be a line in the final display. Each line expected to be a line in the final display. Each line
will be run through `iter_callable`. will be run through `iter_callable`.
always_page (bool, optional): If `False`, the
pager will only kick in if `inp` is too big always_page (bool, optional): If `False`, the pager will only kick
to fit the screen. in if `inp` is too big to fit the screen.
session (Session, optional): If given, this session will be used session (Session, optional): If given, this session will be used
to determine the screen width and will receive all output. to determine the screen width and will receive all output.
justify (bool, optional): If set, auto-justify long lines. This must be turned 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 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 cmdset the user had *before* the evmore pager was activated (so none of
the evmore commands will be available when this is run). 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: Examples:
Basic use: Basic use:
``` ::
super_long_text = " ... " super_long_text = " ... "
EvMore(caller, super_long_text) EvMore(caller, super_long_text)
```
Paginator Paginated query data - this is an optimization to avoid fetching
``` database data until it's actually paged to.
::
from django.core.paginator import Paginator from django.core.paginator import Paginator
query = ObjectDB.objects.all() query = ObjectDB.objects.all()
pages = Paginator(query, 10) # 10 objs per page pages = Paginator(query, 10) # 10 objs per page
EvMore(caller, pages) EvMore(caller, pages)
```
Every page an EvTable Automatic split EvTable over multiple EvMore pages
``` ::
from evennia import EvTable
def _to_evtable(page): table = EvMore(*header, table=tabledata)
table = ... # convert page to a table EvMore(caller, table)
return EvTable(*headers, table=table, ...)
EvMore(caller, pages, page_formatter=_to_evtable) 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 self._caller = caller
@ -386,9 +414,10 @@ class EvMore(object):
def init_f_str(self, text): def init_f_str(self, text):
""" """
The input contains \f markers. We use \f to indicate the user wants to The input contains \\\\f (backslash + f) markers. We use \\\\f to indicate
enforce their line breaks on their own. If so, we do no automatic the user wants to enforce their line breaks on their own. If so, we do
line-breaking/justification at all. no automatic line-breaking/justification at all.
""" """
self._data = text.split("\f") self._data = text.split("\f")
self._npages = len(self._data) self._npages = len(self._data)
@ -433,13 +462,16 @@ class EvMore(object):
Notes: Notes:
If overridden, this method must perform the following actions: 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._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 - 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 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. wanting to change the paginator, override `self.paginator` instead.
- set `self._page_formatter` to a callable that will receive the page from `self._paginator` - set `self._page_formatter` to a callable that will receive the
and format it with one element per line. Default is `str`. Or override `self.page_formatter` page from `self._paginator` and format it with one element per
line. Default is `str`. Or override `self.page_formatter`
directly instead. directly instead.
By default, helper methods are called that perform these actions By default, helper methods are called that perform these actions
@ -520,15 +552,17 @@ def msg(
Args: Args:
caller (Object or Account): Entity reading the text. caller (Object or Account): Entity reading the text.
text (str, EvTable or iterator): The text or data to put under paging. text (str, EvTable or iterator): The text or data to put under paging.
- If a string, paginage normally. If this text contains - If a string, paginage normally. If this text contains
one or more `\f` format symbol, automatic pagination is disabled one or more \\\\f (backslash + f) format symbol, automatic pagination is disabled
and page-breaks will only happen after each `\f`. and page-breaks will only happen after each \\\\f.
- If `EvTable`, the EvTable will be paginated with the same - If `EvTable`, the EvTable will be paginated with the same
setting on each page if it is too long. The table setting on each page if it is too long. The table
decorations will be considered in the size of the page. decorations will be considered in the size of the page.
- Otherwise `text` is converted to an iterator, where each step is - Otherwise `text` is converted to an iterator, where each step is
is expected to be a line in the final display, and each line is expected to be a line in the final display, and each line
will be run through repr(). will be run through repr().
always_page (bool, optional): If `False`, the always_page (bool, optional): If `False`, the
pager will only kick in if `text` is too big pager will only kick in if `text` is too big
to fit the screen. to fit the screen.

View file

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

View file

@ -2,20 +2,18 @@
Inline functions (nested form). Inline functions (nested form).
This parser accepts nested inlinefunctions on the 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, This functionality is turned off by default - to activate,
`settings.INLINEFUNC_ENABLED` must be set to `True`. `settings.INLINEFUNC_ENABLED` must be set to `True`.
Each token starts with "$funcname(" where there must be no space Each token starts with `$funcname(` where there must be no space between the
between the $funcname and (. It ends with a matched ending parentesis. $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 mainly needed for escaping commas in flowing text (which would
otherwise be interpreted as an argument separator), or to escape `}` otherwise be interpreted as an argument separator), or to escape `}`
when not intended to close the function block. Enclosing text in 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 modules defined by `settings.INLINEFUNC_MODULES`. They are identified
by their function name (and ignored if this name starts with `_`). They by their function name (and ignored if this name starts with `_`). They
should be on the following form: 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 Here, the arguments given to `$funcname(arg1,arg2)` will appear as the
`*args` tuple. This will be populated by the arguments given to the `*args` tuple. This will be populated by the arguments given to the
@ -44,6 +41,7 @@ the string is sent to a non-puppetable object. The inlinefunc should
never raise an exception. never raise an exception.
There are two reserved function names: There are two reserved function names:
- "nomatch": This is called if the user uses a functionname that is - "nomatch": This is called if the user uses a functionname that is
not registered. The nomatch function will get the name of the not registered. The nomatch function will get the name of the
not-found function as its first argument followed by the normal not-found function as its first argument followed by the normal
@ -54,9 +52,10 @@ There are two reserved function names:
the `stackfull` inlinefunc is appended to the end. By default this is an the `stackfull` inlinefunc is appended to the end. By default this is an
error message. error message.
Error handling: Syntax errors, notably not completely closing all inlinefunc blocks, will lead
Syntax errors, notably not completely closing all inlinefunc to the entire string remaining unparsed.
blocks, will lead to the entire string remaining unparsed.
----
""" """
@ -92,9 +91,10 @@ def random(*args, **kwargs):
given range. given range.
Example: Example:
`$random()`
`$random(5)` - `$random()`
`$random(5, 10)` - `$random(5)`
- `$random(5, 10)`
""" """
nargs = len(args) nargs = len(args)
@ -574,12 +574,12 @@ def initialize_nick_templates(in_template, out_template):
Args: Args:
in_template (str): The template to be used for nick recognition. in_template (str): The template to be used for nick recognition.
out_template (str): The template to be used to replace the string out_template (str): The template to be used to replace the string
matched by the in_template. matched by the `in_template`.
Returns: Returns:
regex (regex): Regex to match against strings regex, template (regex, str): Regex to match against strings and a
template (str): Template with markers {arg1}, {arg2}, etc for template with markers `{arg1}`, `{arg2}`, etc for replacement using the
replacement using the standard .format method. standard `.format` method.
Raises: Raises:
NickTemplateInvalid: If the in/out template does not have a matching 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 import datetime
from evennia import logger from evennia import logger
from evennia.utils.ansi import strip_ansi from evennia.utils.ansi import strip_ansi
@ -6,7 +12,7 @@ from evennia.utils.utils import crop
from evennia.utils import validatorfuncs from evennia.utils import validatorfuncs
class BaseOption(object): class BaseOption:
""" """
Abstract Class to deal with encapsulating individual Options. An Option has 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 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): 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 where kwargs are a combination of those passed into this function and the
ones specified by the OptionHandler. ones specified by the OptionHandler.

View file

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

View file

@ -39,13 +39,15 @@ def unload_module(module):
should directly give the module pathname to unload. should directly give the module pathname to unload.
Example: Example:
::
# (in a test method) # (in a test method)
unload_module(foo) unload_module(foo)
with mock.patch("foo.GLOBALTHING", "mockval"): with mock.patch("foo.GLOBALTHING", "mockval"):
import foo import foo
... # test code using foo.GLOBALTHING, now set to 'mockval' ... # test code using foo.GLOBALTHING, now set to 'mockval'
Notes:
This allows for mocking constants global to the module, since This allows for mocking constants global to the module, since
otherwise those would not be mocked (since a module is only otherwise those would not be mocked (since a module is only
loaded once). loaded once).

View file

@ -1069,7 +1069,7 @@ def run_async(to_execute, *args, **kwargs):
Args: Args:
to_execute (callable): If this is a callable, it will be 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 The callable will be executed using ProcPool, or in a thread
if ProcPool is not available. if ProcPool is not available.
@ -1168,7 +1168,7 @@ def check_evennia_dependencies():
def has_parent(basepath, obj): def has_parent(basepath, obj):
""" """
Checks if `basepath` is somewhere in `obj`s parent tree. Checks if `basepath` is somewhere in `obj`'s parent tree.
Args: Args:
basepath (str): Python dotpath to compare against obj path. basepath (str): Python dotpath to compare against obj path.
@ -1605,9 +1605,9 @@ def string_partial_matching(alternatives, inp, ret_index=True):
def format_table(table, extra_space=1): def format_table(table, extra_space=1):
""" """
Note: `evennia.utils.evtable` is more powerful than this, but this Note: `evennia.utils.evtable` is more powerful than this, but this function
function can be useful when the number of columns and rows are can be useful when the number of columns and rows are unknown and must be
unknown and must be calculated on the fly. calculated on the fly.
Args. Args.
table (list): A list of lists to represent columns in the 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 The function formats the columns to be as wide as the widest member
of each column. of each column.
Examples: Example:
::
```python
ftable = format_table([[...], [...], ...]) ftable = format_table([[...], [...], ...])
for ir, row in enumarate(ftable): for ir, row in enumarate(ftable):
if ir == 0: if ir == 0:
# make first row white # make first row white
string += "\n|w" + ""join(row) + "|n" string += "\\\\n|w" + ""join(row) + "|n"
else: else:
string += "\n" + "".join(row) string += "\\\\n" + "".join(row)
print string print(string)
```
""" """
if not table: if not table:
return [[]] return [[]]
@ -2051,14 +2051,13 @@ def get_all_typeclasses(parent=None):
def interactive(func): def interactive(func):
""" """
Decorator to make a method pausable with yield(seconds) Decorator to make a method pausable with yield(seconds) and able to ask for
and able to ask for user-input with response=yield(question). user-input with `response=yield(question)`. For the question-asking to
For the question-asking to work, 'caller' must the name work, 'caller' must the name of an argument or kwarg to the decorated
of an argument or kwarg to the decorated function. function.
Note that this turns the method into a generator. Example:
::
Example usage:
@interactive @interactive
def myfunc(caller): def myfunc(caller):
@ -2072,6 +2071,9 @@ def interactive(func):
else: else:
# ... # ...
Notes:
This turns the method into a generator!
""" """
from evennia.utils.evmenu import get_input 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): 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 Process a datetime string in standard forms while accounting for the
returns a result in UTC. inputer's timezone. Always returns a result in UTC.
Args: Args:
entry (str): A date string from a user. 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, account (AccountDB): The Account performing this lookup. Unless `from_tz` is provided,
the account's timezone option will be used. the account's timezone option will be used.
from_tz (pytz.timezone): An instance of a pytz timezone object from the 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. If neither one is provided, defaults to UTC.
Returns: Returns:
datetime in UTC. datetime in UTC.
Raises: Raises:
ValueError: If encountering a malformed timezone, date string or other format error. ValueError: If encountering a malformed timezone, date string or other format error.