From 9fbfc8f8d04427630c13962dda53d8032b6a780b Mon Sep 17 00:00:00 2001 From: Griatch Date: Fri, 10 Jul 2020 22:47:37 +0200 Subject: [PATCH] Almost completed refactoring of source docstrings for new doc system --- docs/pylib/create_toctree.py | 3 + docs/source/_static/nature.css | 4 + docs/source/_templates/layout.html | 3 - docs/source/toc.md | 2 +- evennia/utils/batchprocessors.py | 52 +++++---- evennia/utils/create.py | 33 +++--- evennia/utils/dbserialize.py | 2 +- evennia/utils/eveditor.py | 74 ++++++------- evennia/utils/evform.py | 58 +++++----- evennia/utils/evmenu.py | 164 ++++++++++++++--------------- evennia/utils/evmore.py | 94 +++++++---------- evennia/utils/evtable.py | 121 ++++++++++----------- evennia/utils/inlinefuncs.py | 33 +++--- evennia/utils/optionclasses.py | 6 +- evennia/utils/search.py | 2 +- evennia/utils/test_resources.py | 4 +- evennia/utils/utils.py | 2 +- evennia/utils/validatorfuncs.py | 6 +- 18 files changed, 331 insertions(+), 332 deletions(-) diff --git a/docs/pylib/create_toctree.py b/docs/pylib/create_toctree.py index 280c2d3175..8e76119fac 100644 --- a/docs/pylib/create_toctree.py +++ b/docs/pylib/create_toctree.py @@ -185,6 +185,8 @@ def create_toctree(): with open(_TOC_FILE, "w") as fil: fil.write("# Toc\n") + fil.write("- [API root](api/evennia-api.rst)") + for ref in sorted(toc_map.values()): if ref == "toc": @@ -193,6 +195,7 @@ def create_toctree(): linkname = ref.replace("-", " ") fil.write(f"\n- [{linkname}]({ref})") + # we add a self-reference so the toc itself is also a part of a toctree fil.write("\n\n```toctree::\n :hidden:\n\n toc\n```") diff --git a/docs/source/_static/nature.css b/docs/source/_static/nature.css index e422d24a4f..8e58299be6 100644 --- a/docs/source/_static/nature.css +++ b/docs/source/_static/nature.css @@ -364,6 +364,10 @@ div.code-block-caption { font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; } +.sig-paren { + margin-left: 1px; +} + .property { font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; } diff --git a/docs/source/_templates/layout.html b/docs/source/_templates/layout.html index 05c281227b..192566093e 100644 --- a/docs/source/_templates/layout.html +++ b/docs/source/_templates/layout.html @@ -3,7 +3,4 @@ {% block footer %} - {{ super() }} - The value of next is {{ next }}. - {% endblock %} diff --git a/docs/source/toc.md b/docs/source/toc.md index 5327095961..61a570c571 100644 --- a/docs/source/toc.md +++ b/docs/source/toc.md @@ -1,5 +1,5 @@ # Toc - +- [API root](api/evennia-api.rst) - [Coding/Coding Introduction](Coding/Coding-Introduction) - [Coding/Coding Overview](Coding/Coding-Overview) - [Coding/Continuous Integration](Coding/Continuous-Integration) diff --git a/evennia/utils/batchprocessors.py b/evennia/utils/batchprocessors.py index 63c87e2389..fee83e7091 100644 --- a/evennia/utils/batchprocessors.py +++ b/evennia/utils/batchprocessors.py @@ -250,21 +250,30 @@ class BatchCommandProcessor(object): def parse_file(self, pythonpath): """ - 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 + This parses the lines of a batch-command-file. + + Args: + pythonpath (str): The dot-python path to the file. + + Returns: + list: A list of all parsed commands with arguments, as strings. + + Notes: + Parsing follows the following rules: + + 1. A `#` 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. + 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. """ @@ -313,21 +322,23 @@ class BatchCodeProcessor(object): def parse_file(self, pythonpath): """ - This parses the lines of a batchfile according to the following - rules: + This parses the lines of a batch-code file Args: pythonpath (str): The dot-python path to the file. Returns: - codeblocks (list): A list of all #CODE blocks, each with - prepended #HEADER data. If no #CODE blocks were found, - this will be a list of one element. + list: A list of all `#CODE` blocks, each with + prepended `#HEADER` block data. If no `#CODE` + blocks were found, this will be a list of one element + containing all code in the file (so a normal Python file). Notes: + Parsing is done according to the following rules: + 1. Code before a #CODE/HEADER block are considered part of - the first code/header block or is the ONLY block if no - #CODE/HEADER blocks are defined. + the first code/header block or is the ONLY block if no + `#CODE/HEADER` blocks are defined. 2. Lines starting with #HEADER starts a header block (ends other blocks) 3. Lines starting with #CODE begins a code block (ends other blocks) 4. Lines starting with #INSERT are on form #INSERT filename. Code from @@ -336,6 +347,7 @@ class BatchCodeProcessor(object): 5. Code after the last block is considered part of the last header/code block + """ text = "".join(read_batchfile(pythonpath, file_ending=".py")) diff --git a/evennia/utils/create.py b/evennia/utils/create.py index 2c77f614c5..ca1ca20003 100644 --- a/evennia/utils/create.py +++ b/evennia/utils/create.py @@ -1,25 +1,17 @@ """ -This module gathers all the essential database-creation -functions for the game engine's various object types. +This module gathers all the essential database-creation functions for the game +engine's various object types. -Only objects created 'stand-alone' are in here, e.g. object Attributes -are always created directly through their respective objects. +Only objects created 'stand-alone' are in here. E.g. object Attributes are +always created through their respective objects handlers. -Each creation_* function also has an alias named for the entity being -created, such as create_object() and object(). This is for -consistency with the utils.search module and allows you to do the -shorter "create.object()". +Each `creation_*` function also has an alias named for the entity being created, +such as create_object() and object(). This is for consistency with the +utils.search module and allows you to do the shorter `create.object()`. -The respective object managers hold more methods for manipulating and -searching objects already existing in the database. +The respective object managers hold more methods for manipulating and searching +objects already existing in the database. -Models covered: - Objects - Scripts - Help - Message - Channel - Accounts """ from django.conf import settings from django.db import IntegrityError @@ -81,21 +73,20 @@ def create_object( Keyword args: typeclass (class or str): Class or python path to a typeclass. key (str): Name of the new object. If not set, a name of - #dbref will be set. + `#dbref` will be set. home (Object or str): Obj or #dbref to use as the object's home location. permissions (list): A list of permission strings or tuples (permstring, category). locks (str): one or more lockstrings, separated by semicolons. aliases (list): A list of alternative keys or tuples (aliasstring, category). tags (list): List of tag keys or tuples (tagkey, category) or (tagkey, category, data). - destination (Object or str): Obj or #dbref to use as an Exit's - target. + destination (Object or str): Obj or #dbref to use as an Exit's target. report_to (Object): The object to return error messages to. nohome (bool): This allows the creation of objects without a default home location; only used when creating the default location itself or during unittests. attributes (list): Tuples on the form (key, value) or (key, value, category), - (key, value, lockstring) or (key, value, lockstring, default_access). + (key, value, lockstring) or (key, value, lockstring, default_access). 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. diff --git a/evennia/utils/dbserialize.py b/evennia/utils/dbserialize.py index ddfdb765de..12895ed386 100644 --- a/evennia/utils/dbserialize.py +++ b/evennia/utils/dbserialize.py @@ -591,7 +591,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) diff --git a/evennia/utils/eveditor.py b/evennia/utils/eveditor.py index 3268c553f8..1e6828d62c 100644 --- a/evennia/utils/eveditor.py +++ b/evennia/utils/eveditor.py @@ -1,45 +1,42 @@ """ EvEditor (Evennia Line Editor) -This implements an advanced line editor for editing longer texts -in-game. The editor mimics the command mechanisms of the "VI" editor -(a famous line-by-line editor) as far as reasonable. +This implements an advanced line editor for editing longer texts in-game. The +editor mimics the command mechanisms of the "VI" editor (a famous line-by-line +editor) as far as reasonable. Features of the editor: - - undo/redo. - - edit/replace on any line of the buffer. - - search&replace text anywhere in buffer. - - formatting of buffer, or selection, to certain width + indentations. - - allow to echo the input or not, depending on your client. +- undo/redo. +- edit/replace on any line of the buffer. +- search&replace text anywhere in buffer. +- formatting of buffer, or selection, to certain width + indentations. +- allow to echo the input or not, depending on your client. +- in-built help -To use the editor, just import EvEditor from this module -and initialize it: +To use the editor, just import EvEditor from this module and initialize it: - from evennia.utils.eveditor import EvEditor +```python +from evennia.utils.eveditor import EvEditor - EvEditor(caller, loadfunc=None, savefunc=None, quitfunc=None, key="", persistent=True) +# set up an editor to edit the caller's 'desc' Attribute +def _loadfunc(caller): + return caller.db.desc - - 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. +def _savefunc(caller, buffer): + caller.db.desc = buffer.strip() + return True -In addition, the EvEditor can be used to enter Python source code, -and offers basic handling of indentation. +def _quitfunc(caller): + caller.msg("Custom quit message") + +# start the editor +EvEditor(caller, loadfunc=None, savefunc=None, quitfunc=None, key="", + persistent=True, code=False) +``` + +The editor can also be used to format Python code and be made to +survive a reload. See the `EvEditor` class for more details. """ import re @@ -227,16 +224,19 @@ class CmdEditorBase(Command): def parse(self): """ - Handles pre-parsing + Handles pre-parsing. Editor commands are on the form + + :: - Editor commands are on the form :cmd [li] [w] [txt] Where all arguments are optional. - li - line number (int), starting from 1. This could also - be a range given as :. - 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 :. + - `w` - word(s) (string), could be encased in quotes. + - `txt` - extra text (string), could be encased in quotes. + """ editor = self.caller.ndb._eveditor diff --git a/evennia/utils/evform.py b/evennia/utils/evform.py index 3e520df7c0..1521befa6c 100644 --- a/evennia/utils/evform.py +++ b/evennia/utils/evform.py @@ -91,28 +91,28 @@ Use as follows: 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 +127,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 @@ -190,12 +192,12 @@ class EvForm(object): 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 `{id: text}` + tables (dict): A dictionary mapping `{id: EvTable}`. + form (dict): A dictionary + `{"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). diff --git a/evennia/utils/evmenu.py b/evennia/utils/evmenu.py index d6aa4c86ed..20859136a4 100644 --- a/evennia/utils/evmenu.py +++ b/evennia/utils/evmenu.py @@ -54,7 +54,7 @@ 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._menutree`. This makes it a convenient place to store @@ -65,38 +65,38 @@ 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: -If key is not given, the option will automatically be identified by + - `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. + +If `key` is not given, the option will automatically be identified by its number 1..N. Example: @@ -142,6 +142,8 @@ Example: When starting this menu with `Menu(caller, "path.to.menu_module")`, the first node will look something like this: +:: + This is a node text ______________________________________ @@ -158,9 +160,10 @@ The menu tree is exited either by using the in-menu quit command or by reaching a node without any options. -For a menu demo, import CmdTestMenu from this module and add it to -your default cmdset. Run it with this module, like `testmenu -evennia.utils.evmenu`. +For a menu demo, import `CmdTestMenu` from this module and add it to +your default cmdset. Run it with this module, like `testmenu evennia.utils.evmenu`. + +---- """ @@ -1155,7 +1158,7 @@ def list_node(option_generator, select=None, pagesize=10): 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 + `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 @@ -1163,15 +1166,19 @@ def list_node(option_generator, select=None, pagesize=10): pagesize (int): How many options to show per page. Example: - @list_node(['foo', 'bar'], select) + + ```python + list_node(['foo', 'bar'], select) 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 - options (descs) visible on the current node page. + 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 options (descs) visible + on the current node page. """ @@ -1392,60 +1399,51 @@ class _Prompt(object): def get_input(caller, prompt, callback, session=None, *args, **kwargs): """ - This is a helper function for easily request input from - the caller. + This is a helper function for easily request input from the caller. Args: - caller (Account or Object): The entity being asked - the question. This should usually be an object - controlled by a user. - prompt (str): This text will be shown to the user, - in order to let them know their input is needed. + caller (Account or Object): The entity being asked the question. This + should usually be an object controlled by a user. + prompt (str): This text will be shown to the user, in order to let them + know their input is needed. callback (callable): A function that will be called - when the user enters a reply. It must take three - arguments: the `caller`, the `prompt` text and the - `result` of the input given by the user. If the - callback doesn't return anything or return False, - the input prompt will be cleaned up and exited. If - returning True, the prompt will remain and continue to - accept input. + when the user enters a reply. It must take three arguments: the + `caller`, the `prompt` text and the `result` of the input given by + the user. If the callback doesn't return anything or return False, + the input prompt will be cleaned up and exited. If returning True, + the prompt will remain and continue to accept input. session (Session, optional): This allows to specify the - session to send the prompt to. It's usually only - needed if `caller` is an Account in multisession modes - 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 - 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 - session argument must be provided (None by default) - and the callback function must take *args and - **kwargs as arguments. + session to send the prompt to. It's usually only needed if `caller` + is an Account in multisession modes greater than 2. The session is + then updated by the command and is available (for example in + callbacks) through `caller.ndb.getinput._session`. + *args (any): Extra arguments to pass to `callback`. To utilise `*args` + (and `**kwargs`), a value for the `session` argument must also be + provided. + **kwargs (any): Extra kwargs to pass to `callback`. Raises: RuntimeError: If the given callback is not callable. Notes: - The result value sent to the callback is raw and not - processed in any way. This means that you will get - the ending line return character from most types of - client inputs. So make sure to strip that before - doing a comparison. + The result value sent to the callback is raw and not processed in any + way. This means that you will get the ending line return character from + most types of client inputs. So make sure to strip that before doing a + comparison. - When the prompt is running, a temporary object - `caller.ndb._getinput` is stored; this will be removed - when the prompt finishes. - If you need the specific Session of the caller (which - may not be easy to get if caller is an account in higher - multisession modes), then it is available in the - callback through `caller.ndb._getinput._session`. + When the prompt is running, a temporary object `caller.ndb._getinput` + is stored; this will be removed when the prompt finishes. - Chaining get_input functions will result in the caller - stacking ever more instances of InputCmdSets. Whilst - they will all be cleared on concluding the get_input - chain, EvMenu should be considered for anything beyond - a single question. + If you need the specific Session of the caller (which may not be easy + to get if caller is an account in higher multisession modes), then it + is available in the callback through `caller.ndb._getinput._session`. + This is why the `session` is required as input. + + It's not recommended to 'chain' `get_input` into a sequence of + questions. This will result in the caller stacking ever more instances + of InputCmdSets. While they will all be cleared on concluding the + get_input chain, EvMenu should be considered for anything beyond a + single question. """ if not callable(callback): diff --git a/evennia/utils/evmore.py b/evennia/utils/evmore.py index 9257e67ea8..2342cf374c 100644 --- a/evennia/utils/evmore.py +++ b/evennia/utils/evmore.py @@ -2,29 +2,35 @@ """ EvMore - pager mechanism -This is a pager for displaying long texts and allows stepping up and -down in the text (the name comes from the traditional 'more' unix -command). +This is a pager for displaying long texts and allows stepping up and 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 +```python +from evennia.utils.evmore import EvMore - text = some_long_text_output() - EvMore(caller, text, always_page=False, session=None, justify_kwargs=None, **kwargs) +text = some_long_text_output() +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 to avoid +having to set up the `EvMenu` object manually: +```python 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. +The `always_page` argument 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 @@ -32,7 +38,7 @@ from django.db.models.query import QuerySet from evennia import Command, CmdSet from evennia.commands import cmdhandler from evennia.utils.ansi import ANSIString -from evennia.utils.utils import make_iter, inherits_from, justify +from evennia.utils.utils import make_iter, inherits_from, justify, dedent _CMD_NOMATCH = cmdhandler.CMD_NOMATCH _CMD_NOINPUT = cmdhandler.CMD_NOINPUT @@ -146,20 +152,21 @@ class EvMore(object): ): """ - Initialization of the text handler. + EvMore pager 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 and justification - are force-disabled and page-breaks will only happen after each `\f`. + + - If a string, paginate normally. If this text contains one or more `\\\\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 `text` 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`. + 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 `text` is too big to fit the screen. @@ -187,6 +194,8 @@ class EvMore(object): kwargs (any, optional): These will be passed on to the `caller.msg` method. Examples: + + ```python super_long_text = " ... " EvMore(caller, super_long_text) @@ -199,6 +208,7 @@ class EvMore(object): EvMore(caller, multi_page_table, use_evtable=True, evtable_args=("Header1", "Header2"), evtable_kwargs={"align": "r", "border": "tablecols"}) + ``` """ self._caller = caller @@ -305,9 +315,13 @@ class EvMore(object): def init_f_str(self, text): """ - The input contains \f markers. We use \f to indicate the user wants to + 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. + + Args: + text (str): The string to format with f-markers. + """ self._data = text.split("\f") self._npages = len(self._data) @@ -443,39 +457,6 @@ def msg( ): """ EvMore-supported version of msg, mimicking the normal msg method. - - 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`. - - 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. - - 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. - 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, justify long lines in output. Disable for - fixed-format output, like tables. - justify_kwargs (dict, bool or None, optional): If given, this should - be valid keyword arguments to the utils.justify() function. If False, - no justification will be done. - exit_on_lastpage (bool, optional): Immediately exit pager when reaching the last page. - use_evtable (bool, optional): If True, each page will be rendered as an - EvTable. For this to work, `text` must be an iterable, where each element - is the table (list of list) to render on that page. - evtable_args (tuple, optional): The args to use for EvTable on each page. - evtable_kwargs (dict, optional): The kwargs to use for EvTable on each - page (except `table`, which is supplied by EvMore per-page). - kwargs (any, optional): These will be passed on - to the `caller.msg` method. - """ EvMore( caller, @@ -487,3 +468,6 @@ def msg( exit_on_lastpage=exit_on_lastpage, **kwargs, ) + + +msg.__doc__ += dedent(EvMore.__init__.__doc__) diff --git a/evennia/utils/evtable.py b/evennia/utils/evtable.py index 52d31a05f4..5a0244189b 100644 --- a/evennia/utils/evtable.py +++ b/evennia/utils/evtable.py @@ -1,7 +1,8 @@ """ -This is an advanced ASCII table creator. It was inspired by -[prettytable](https://code.google.com/p/prettytable/) but shares no -code. +This is an advanced ASCII table creator. It was inspired by Prettytable +(https://code.google.com/p/prettytable/) but shares no code and is considerably +more advanced, supporting auto-balancing of incomplete tables and ANSI colors among +other things. Example usage: @@ -17,19 +18,19 @@ Example usage: 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: @@ -42,25 +43,26 @@ the table symmetric. Tables can be restricted to a given width: 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 @@ -75,22 +77,22 @@ 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). @@ -99,15 +101,16 @@ If the height is restricted, cells will be restricted from expanding vertically. This will lead to text contents being cropped. Each cell can only shrink to a minimum width and height of 1. -`EvTable` is intended to be used with [ANSIString](evennia.utils.ansi#ansistring) -for supporting ANSI-coloured string types. +`EvTable` is intended to be used with `ANSIString` for supporting ANSI-coloured +string types. -When a cell is auto-wrapped across multiple lines, ANSI-reset -sequences will be put at the end of each wrapped line. This means that -the colour of a wrapped cell will not "bleed", but it also means that -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. +When a cell is auto-wrapped across multiple lines, ANSI-reset sequences will be +put at the end of each wrapped line. This means that the colour of a wrapped +cell will not "bleed", but it also means that 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. + +---- """ diff --git a/evennia/utils/inlinefuncs.py b/evennia/utils/inlinefuncs.py index 87893e4667..a25ee88ce1 100644 --- a/evennia/utils/inlinefuncs.py +++ b/evennia/utils/inlinefuncs.py @@ -3,21 +3,21 @@ Inline functions (nested form). This parser accepts nested inlinefunctions on the form -``` +```python $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 `"("`. The inlinefunc ends with a matched ending parentesis. +`")"`. 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 `}` +otherwise be interpreted as an argument separator), or to escape `)` when not intended to close the function block. Enclosing text in matched `\"\"\"` (triple quotes) or `'''` (triple single-quotes) will also escape *everything* within without needing to escape individual @@ -44,19 +44,22 @@ 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 `` 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 `` 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 failing to completely closing all inlinefunc +blocks, will lead to the entire string remaining unparsed. Inlineparsing should +never traceback. + +---- """ @@ -518,11 +521,11 @@ def initialize_nick_templates(in_template, out_template): Returns: regex (regex): Regex to match against strings template (str): Template with markers {arg1}, {arg2}, etc for - replacement using the standard .format method. + replacement using the standard .format method. Raises: NickTemplateInvalid: If the in/out template does not have a matching - number of $args. + number of $args. """ # create the regex for in_template diff --git a/evennia/utils/optionclasses.py b/evennia/utils/optionclasses.py index cbc93a2bca..bdca3ffa51 100644 --- a/evennia/utils/optionclasses.py +++ b/evennia/utils/optionclasses.py @@ -109,9 +109,9 @@ class BaseOption(object): def save(self, **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. + 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`. Keyword args: any (any): Not used by default. These are passed in from self.set diff --git a/evennia/utils/search.py b/evennia/utils/search.py index c7231309ac..a8376bdc00 100644 --- a/evennia/utils/search.py +++ b/evennia/utils/search.py @@ -36,7 +36,7 @@ __all__ = ( "search_message", "search_channel", "search_help_entry", - "search_object_tag", + "search_tag", "search_script_tag", "search_account_tag", "search_channel_tag", diff --git a/evennia/utils/test_resources.py b/evennia/utils/test_resources.py index d128302a71..c641bb8919 100644 --- a/evennia/utils/test_resources.py +++ b/evennia/utils/test_resources.py @@ -39,12 +39,14 @@ def unload_module(module): should directly give the module pathname to unload. Example: + + ```python # (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 diff --git a/evennia/utils/utils.py b/evennia/utils/utils.py index 0b84f94f0a..20d5b0db15 100644 --- a/evennia/utils/utils.py +++ b/evennia/utils/utils.py @@ -1197,7 +1197,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. diff --git a/evennia/utils/validatorfuncs.py b/evennia/utils/validatorfuncs.py index 3443c47d5c..dd80e6bfdb 100644 --- a/evennia/utils/validatorfuncs.py +++ b/evennia/utils/validatorfuncs.py @@ -41,8 +41,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. @@ -50,7 +50,7 @@ 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 `account`. If neither one is provided, defaults to UTC. Returns: datetime in UTC.