Updated scripts/ directory source to use Google style docstrings as per #709.

This commit is contained in:
Griatch 2015-05-29 21:08:04 +02:00
parent 13042e6d1a
commit d23a8a94db
4 changed files with 263 additions and 130 deletions

View file

@ -38,9 +38,16 @@ class ScriptDBManager(TypedObjectManager):
@returns_typeclass_list
def get_all_scripts_on_obj(self, obj, key=None):
"""
Returns as result all the Scripts related to a particular object.
key can be given as a dbref or name string. If given, only scripts
matching the key on the object will be returned.
Find all Scripts related to a particular object.
Args:
obj (Object): Object whose Scripts we are looking for.
key (str, optional): Script identifier - can be given as a
dbref or name string. If given, only scripts matching the
key on the object will be returned.
Returns:
matches (list): Matching scripts.
"""
if not obj:
return []
@ -64,8 +71,15 @@ class ScriptDBManager(TypedObjectManager):
@returns_typeclass_list
def get_all_scripts(self, key=None):
"""
Return all scripts, alternative only
scripts with a certain key/dbref
Get all scripts in the database.
Args:
key (str, optional): Restrict result to only those
with matching key or dbref.
Returns:
scripts (list): All scripts found, or those matching `key`.
"""
if key:
script = []
@ -79,10 +93,16 @@ class ScriptDBManager(TypedObjectManager):
def delete_script(self, dbref):
"""
This stops and deletes a specific script directly
from the script database. This might be
needed for global scripts not tied to
a specific game object.
This stops and deletes a specific script directly from the
script database.
Args:
dbref (int): Database unique id.
Notes:
This might be needed for global scripts not tied to a
specific game object
"""
scripts = self.get_id(dbref)
for script in make_iter(scripts):
@ -91,8 +111,12 @@ class ScriptDBManager(TypedObjectManager):
def remove_non_persistent(self, obj=None):
"""
This cleans up the script database of all non-persistent
scripts, or only those on obj. It is called every time the server
restarts.
scripts. It is called every time the server restarts.
Args:
obj (Object, optional): Only remove non-persistent scripts
assigned to this object.
"""
if obj:
to_stop = self.filter(db_obj=obj, db_persistent=False, db_is_active=True)
@ -114,26 +138,32 @@ class ScriptDBManager(TypedObjectManager):
all objects run scripts that are still valid in the context
they are in. This is called by the game engine at regular
intervals but can also be initiated by player scripts.
If key and/or obj is given, only update the related
script/object.
Only one of the arguments are supposed to be supplied
at a time, since they are exclusive to each other.
scripts = a list of scripts objects obtained somewhere.
obj = validate only scripts defined on a special object.
key = validate only scripts with a particular key
dbref = validate only the single script with this particular id.
Args:
scripts (list, optional): A list of script objects to
validate.
obj (Object, optional): Validate only scripts defined on
this object.
key (str): Validate only scripts with this key.
dbref (int): Validate only the single script with this
particular id.
init_mode (str, optional): This is used during server
upstart and can have three values:
- `False` (no init mode). Called during run.
- `"reset"` - server reboot. Kill non-persistent scripts
- `"reload"` - server reload. Keep non-persistent scripts.
Returns:
nr_started, nr_stopped (tuple): Statistics on how many objects
where started and stopped.
init_mode - This is used during server upstart and can have
three values:
False (no init mode). Called during run.
"reset" - server reboot. Kill non-persistent scripts
"reload" - server reload. Keep non-persistent scripts.
Notes:
This method also makes sure start any scripts it validates
which should be harmless, since already-active scripts have
the property 'is_running' set and will be skipped.
This method also makes sure start any scripts it validates,
this should be harmless, since already-active scripts
have the property 'is_running' set and will be skipped.
"""
# we store a variable that tracks if we are calling a
@ -194,10 +224,13 @@ class ScriptDBManager(TypedObjectManager):
"""
Search for a particular script.
ostring - search criterion - a script ID or key
obj - limit search to scripts defined on this object
only_timed - limit search only to scripts that run
on a timer.
Args:
ostring (str): Search criterion - a script dbef or key.
obj (Object, optional): Limit search to scripts defined on
this object
only_timed (bool): Limit search only to scripts that run
on a timer.
"""
ostring = ostring.strip()
@ -218,7 +251,18 @@ class ScriptDBManager(TypedObjectManager):
def copy_script(self, original_script, new_key=None, new_obj=None, new_locks=None):
"""
Make an identical copy of the original_script
Make an identical copy of the original_script.
Args:
original_script (Script): The Script to copy.
new_key (str, optional): Rename the copy.
new_obj (Object, optional): Place copy on different Object.
new_locks (str, optional): Give copy different locks from
the original.
Returns:
script_copy (Script): A new Script instance, copied from
the original.
"""
typeclass = original_script.typeclass_path
new_key = new_key if new_key is not None else original_script.key

View file

@ -3,8 +3,8 @@ Scripts are entities that perform some sort of action, either only
once or repeatedly. They can be directly linked to a particular
Evennia Object or be stand-alonw (in the latter case it is considered
a 'global' script). Scripts can indicate both actions related to the
game world as well as pure behind-the-scenes events and
effects. Everything that has a time component in the game (i.e. is not
game world as well as pure behind-the-scenes events and effects.
Everything that has a time component in the game (i.e. is not
hard-coded at startup or directly created/controlled by players) is
handled by Scripts.
@ -14,14 +14,14 @@ Scripts can also implement at_start and at_end hooks for preparing and
cleaning whatever effect they have had on the game object.
Common examples of uses of Scripts:
- load the default cmdset to the player object's cmdhandler
- Load the default cmdset to the player object's cmdhandler
when logging in.
- switch to a different state, such as entering a text editor,
- Switch to a different state, such as entering a text editor,
start combat or enter a dark room.
- Weather patterns in-game
- merge a new cmdset with the default one for changing which
- Merge a new cmdset with the default one for changing which
commands are available at a particular time
- give the player/object a time-limited bonus/effect
- Give the player/object a time-limited bonus/effect
"""
from django.conf import settings
@ -118,9 +118,10 @@ class ScriptDB(TypedObject):
# obj property
def __get_obj(self):
"""
property wrapper that homogenizes access to either
the db_player or db_obj field, using the same obj
property name
Property wrapper that homogenizes access to either the
db_player or db_obj field, using the same object property
name.
"""
obj = _GA(self, "db_player")
if not obj:
@ -131,6 +132,7 @@ class ScriptDB(TypedObject):
"""
Set player or obj to their right database field. If
a dbref is given, assume ObjectDB.
"""
try:
value = _GA(value, "dbobj")
@ -157,25 +159,3 @@ class ScriptDB(TypedObject):
_GA(self, "save")(update_fields=[fname])
obj = property(__get_obj, __set_obj)
object = property(__get_obj, __set_obj)
# def at_typeclass_error(self):
# """
# If this is called, it means the typeclass has a critical
# error and cannot even be loaded. We don't allow a script
# to be created under those circumstances. Already created,
# permanent scripts are set to already be active so they
# won't get activated now (next reboot the bug might be fixed)
# """
# # By setting is_active=True, we trick the script not to run "again".
# self.is_active = True
# return super(ScriptDB, self).at_typeclass_error()
#
# delete_iter = 0
# def delete(self):
# "Delete script"
# if self.delete_iter > 0:
# return
# self.delete_iter += 1
# _GA(self, "attributes").clear()
# super(ScriptDB, self).delete()

View file

@ -1,8 +1,9 @@
"""
The script handler makes sure to check through all stored scripts
to make sure they are still relevant.
A scripthandler is automatically added to all game objects. You
access it through the property `scripts` on the game object.
The script handler makes sure to check through all stored scripts to
make sure they are still relevant. A scripthandler is automatically
added to all game objects. You access it through the property
`scripts` on the game object.
"""
from evennia.scripts.models import ScriptDB
@ -14,20 +15,24 @@ from django.utils.translation import ugettext as _
class ScriptHandler(object):
"""
Implements the handler. This sits on each game object.
"""
def __init__(self, obj):
"""
Set up internal state.
obj - a reference to the object this handler is attached to.
We retrieve all scripts attached to this object and check
if they are all persistent. If they are not, they are just
cruft left over from a server shutdown.
Args:
obj (Object): A reference to the object this handler is
attached to.
"""
self.obj = obj
def __str__(self):
"List the scripts tied to this object"
"""
List the scripts tied to this object.
"""
scripts = ScriptDB.objects.get_all_scripts_on_obj(self.obj)
string = ""
for script in scripts:
@ -51,12 +56,14 @@ class ScriptHandler(object):
"""
Add a script to this object.
scriptclass - either a class object
inheriting from Script, an instantiated script object
or a python path to such a class object.
key - optional identifier for the script (often set in script
definition)
autostart - start the script upon adding it
Args:
scriptclass (Scriptclass, Script or str): Either a class
object inheriting from DefaultScript, an instantiated
script object or a python path to such a class object.
key (str, optional): Identifier for the script (often set
in script definition and listings)
autostart (bool, optional): Start the script upon adding it.
"""
if self.obj.__dbclass__.__name__ == "PlayerDB":
# we add to a Player, not an Object
@ -71,56 +78,74 @@ class ScriptHandler(object):
return False
return True
def start(self, scriptid):
def start(self, key):
"""
Find an already added script and force-start it
Find scripts and force-start them
Args:
key (str): The script's key or dbref.
Returns:
nr_started (int): The number of started scripts found.
"""
scripts = ScriptDB.objects.get_all_scripts_on_obj(self.obj, key=scriptid)
scripts = ScriptDB.objects.get_all_scripts_on_obj(self.obj, key=key)
num = 0
for script in scripts:
num += script.start()
return num
def get(self, scriptid):
def get(self, key):
"""
Return one or all scripts on this object matching `scriptid`. Will return
a list.
"""
return ScriptDB.objects.get_all_scripts_on_obj(self.obj, key=scriptid)
Search scripts on this object.
def delete(self, scriptid=None):
Args:
key (str): Search criterion, the script's key or dbref.
Returns:
scripts (list): The found scripts matching `key`.
"""
return ScriptDB.objects.get_all_scripts_on_obj(self.obj, key=key)
def delete(self, key=None):
"""
Forcibly delete a script from this object.
scriptid can be a script key or the path to a script (in the
latter case all scripts with this path will be deleted!)
If no scriptid is set, delete all scripts on the object.
Args:
key (str, optional): A script key or the path to a script (in the
latter case all scripts with this path will be deleted!)
If no key is given, delete *all* scripts on the object!
"""
delscripts = ScriptDB.objects.get_all_scripts_on_obj(self.obj, key=scriptid)
delscripts = ScriptDB.objects.get_all_scripts_on_obj(self.obj, key=key)
if not delscripts:
delscripts = [script for script in ScriptDB.objects.get_all_scripts_on_obj(self.obj) if script.path == scriptid]
delscripts = [script for script in ScriptDB.objects.get_all_scripts_on_obj(self.obj) if script.path == key]
num = 0
for script in delscripts:
num += script.stop()
return num
# alias to delete
stop = delete
def stop(self, scriptid=None):
def all(self):
"""
Alias for delete. scriptid can be a script key or a script path string.
"""
return self.delete(scriptid)
Get all scripts stored in this handler.
def all(self, scriptid=None):
"""
Get all scripts stored in the handler, alternatively all matching a key.
"""
return ScriptDB.objects.get_all_scripts_on_obj(self.obj, key=scriptid)
return ScriptDB.objects.get_all_scripts_on_obj(self.obj)
def validate(self, init_mode=False):
"""
Runs a validation on this object's scripts only.
This should be called regularly to crank the wheels.
Runs a validation on this object's scripts only. This should
be called regularly to crank the wheels.
Args:
init_mode (str, optional): - This is used during server
upstart and can have three values:
- `False` (no init mode). Called during run.
- `"reset"` - server reboot. Kill non-persistent scripts
- `"reload"` - server reload. Keep non-persistent scripts.
"""
ScriptDB.objects.validate(obj=self.obj, init_mode=init_mode)

View file

@ -88,8 +88,12 @@ class Ticker(object):
If overloading, this callback is expected to handle all
subscriptions when it is triggered. It should not return
anything and should not traceback on poorly designed hooks.
The callback should ideally work under @inlineCallbacks so it can yield
appropriately.
The callback should ideally work under @inlineCallbacks so it
can yield appropriately.
The _hook_key, which is passed down through the handler via
kwargs is used here to identify which hook method to call.
"""
for store_key, (obj, args, kwargs) in self.subscriptions.items():
hook_key = yield kwargs.pop("_hook_key", "at_tick")
@ -111,6 +115,10 @@ class Ticker(object):
def __init__(self, interval):
"""
Set up the ticker
Args:
interval (int): The stepping interval.
"""
self.interval = interval
self.subscriptions = {}
@ -119,8 +127,12 @@ class Ticker(object):
def validate(self, start_delay=None):
"""
Start/stop the task depending on how many
subscribers we have using it.
Start/stop the task depending on how many subscribers we have
using it.
Args:
start_delay (int): Time to way before starting.
"""
subs = self.subscriptions
if None in subs.values():
@ -135,9 +147,19 @@ class Ticker(object):
def add(self, store_key, obj, *args, **kwargs):
"""
Sign up a subscriber to this ticker. If kwargs contains
a keyword _start_delay, this will be used to delay the start
of the trigger instead of interval.
Sign up a subscriber to this ticker.
Args:
store_key (str): Unique storage hash for this ticker subscription.
obj (Object): Object subscribing to this ticker.
args (any, optional): Arguments to call the hook method with.
Kwargs:
_start_delay (int): If set, this will be
used to delay the start of the trigger instead of
`interval`.
_hooK_key (str): This carries the name of the hook method
to call. It is passed on as-is from this method.
"""
start_delay = kwargs.pop("_start_delay", None)
self.subscriptions[store_key] = (obj, args, kwargs)
@ -146,13 +168,18 @@ class Ticker(object):
def remove(self, store_key):
"""
Unsubscribe object from this ticker
Args:
store_key (str): Unique store key.
"""
self.subscriptions.pop(store_key, False)
self.validate()
def stop(self):
"""
Kill the Task, regardless of subscriptions
Kill the Task, regardless of subscriptions.
"""
self.subscriptions = {}
self.validate()
@ -160,18 +187,37 @@ class Ticker(object):
class TickerPool(object):
"""
This maintains a pool of Twisted LoopingCall tasks
for calling subscribed objects at given times.
This maintains a pool of
`evennia.scripts.scripts.ExtendedLoopingCall` tasks for calling
subscribed objects at given times.
"""
ticker_class = Ticker
def __init__(self):
"Initialize the pool"
"""
Initialize the pool.
"""
self.tickers = {}
def add(self, store_key, obj, interval, *args, **kwargs):
"""
Add new ticker subscriber
Add new ticker subscriber.
Args:
store_key (str): Unique storage hash.
obj (Object): Object subscribing.
interval (int): How often to call the ticker.
args (any, optional): Arguments to send to the hook method.
Kwargs:
_start_delay (int): If set, this will be
used to delay the start of the trigger instead of
`interval`. It is passed on as-is from this method.
_hooK_key (str): This carries the name of the hook method
to call. It is passed on as-is from this method.
"""
if not interval:
log_err(_ERROR_ADD_INTERVAL.format(store_key=store_key, obj=obj,
@ -184,7 +230,16 @@ class TickerPool(object):
def remove(self, store_key, interval):
"""
Remove subscription from pool
Remove subscription from pool.
Args:
store_key (str): Unique storage hash.
interval (int): Ticker interval.
Notes:
A given subscription is uniquely identified both
via its `store_key` and its `interval`.
"""
if interval in self.tickers:
self.tickers[interval].remove(store_key)
@ -193,7 +248,11 @@ class TickerPool(object):
"""
Stop all scripts in pool. This is done at server reload since
restoring the pool will automatically re-populate the pool.
If interval is given, only stop tickers with that interval.
Args:
interval (int, optional): Only stop tickers with this
interval.
"""
if interval and interval in self.tickers:
self.tickers[interval].stop()
@ -207,12 +266,17 @@ class TickerHandler(object):
The Tickerhandler maintains a pool of tasks for subscribing
objects to various tick rates. The pool maintains creation
instructions and and re-applies them at a server restart.
"""
ticker_pool_class = TickerPool
def __init__(self, save_name="ticker_storage"):
"""
Initialize handler
save_name (str, optional): The name of the ServerConfig
instance to store the handler state persistently.
"""
self.ticker_storage = {}
self.save_name = save_name
@ -220,10 +284,16 @@ class TickerHandler(object):
def _store_key(self, obj, interval, idstring=""):
"""
Tries to create a store_key for the object.
Returns a tuple (isdb, store_key) where isdb
is a boolean True if obj was a database object,
False otherwise.
Tries to create a store_key for the object. Returns a tuple
(isdb, store_key) where isdb is a boolean True if obj was a
database object, False otherwise.
Args:
obj (Object): Subscribing object.
interval (int): Ticker interval
idstring (str, optional): Additional separator between
different subscription types.
"""
if hasattr(obj, "db_key"):
# create a store_key using the database representation
@ -243,9 +313,10 @@ class TickerHandler(object):
def save(self):
"""
Save ticker_storage as a serialized string into a temporary
ServerConf field. Whereas saving is done on the fly, if called by
server when it shuts down, the current timer of each ticker will be
saved so it can start over from that point.
ServerConf field. Whereas saving is done on the fly, if called
by server when it shuts down, the current timer of each ticker
will be saved so it can start over from that point.
"""
if self.ticker_storage:
start_delays = dict((interval, ticker.task.next_call_time())
@ -349,10 +420,15 @@ class TickerHandler(object):
def clear(self, interval=None):
"""
Stop/remove all tickers from handler, or the ones
with a given interval. This is the only supported
way to kill tickers for non-db objects. If interval
is given, only stop tickers with this interval.
Stop/remove all tickers from handler.
Args:
interval (int): Only stop tickers with this interval.
Notes:
This is the only supported way to kill tickers related to
non-db objects.
"""
self.ticker_pool.stop(interval)
if interval:
@ -365,9 +441,17 @@ class TickerHandler(object):
def all(self, interval=None):
"""
Get the subsciptions for a given interval. If interval
is not given, return a dictionary with lists for every
interval in the tickerhandler.
Get all subscriptions.
Args:
interval (int): Limit match to tickers with this interval.
Returns:
tickers (list): If `interval` was given, this is a list of
tickers using that interval.
tickerpool_layout (dict): If `interval` was *not* given,
this is a dict {interval1: [ticker1, ticker2, ...], ...}
"""
if interval is None:
# return dict of all, ordered by interval