mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
Moved all command definitions of Typeclassed entities up one level, to Object, Player and Script respectively. The actual code is still on the models (ObjectDB, PlayerDB and ScriptDB), but one should not be able to use the methods without having to dig into the code as far. Also added extensive, up-to-date headers to the inheriting base objects in game/gamesrc.
This commit is contained in:
parent
8ada50fcb7
commit
7a2cdd3842
8 changed files with 676 additions and 170 deletions
|
|
@ -42,56 +42,90 @@ class Object(BaseObject):
|
|||
__setattr__ since these are used heavily by the typeclass system
|
||||
of Evennia and messing with them might well break things for you.
|
||||
|
||||
Hooks (these are class methods, so their arguments should also start with self):
|
||||
|
||||
at_object_creation() - only called once, when object is first created.
|
||||
Almost all object customizations go here.
|
||||
at_first_login() - only called once, the very first time user logs in.
|
||||
at_pre_login() - called every time the user connects, after they have
|
||||
identified, just before the system actually logs them in.
|
||||
at_post_login() - called at the end of login, just before setting the
|
||||
player loose in the world.
|
||||
at_disconnect() - called just before the use is disconnected (this is also
|
||||
called if the system determines the player lost their link)
|
||||
at_object_delete() - called just before the database object is permanently
|
||||
deleted from the database with obj.delete(). Note that cleaning out contents
|
||||
and deleting connected exits is not needed, this is handled
|
||||
automatically when doing obj.delete(). If this method returns
|
||||
False, deletion is aborted.
|
||||
* Base properties defined/available on all Objects
|
||||
|
||||
at_before_move(destination) - called by obj.move_to() just before moving object to the destination.
|
||||
If this method returns False, move is cancelled.
|
||||
announce_move_from(destination) - called while still standing in the old location,
|
||||
if obj.move_to() has argument quiet=False.
|
||||
announce_move_to(source_location) - called after move, while standing in the new location
|
||||
if obj.move_to() has argument quiet=False.
|
||||
at_after_move(source_location) - always called after a move has been performed.
|
||||
key (string) - name of object
|
||||
name (string)- same as key
|
||||
aliases (list of strings) - aliases to the object. Will be saved to database as AliasDB entries but returned as strings.
|
||||
dbref (int, read-only) - unique #id-number. Also "id" can be used.
|
||||
dbobj (Object, read-only) - link to database model. dbobj.typeclass points back to this class
|
||||
typeclass (Object, read-only) - this links back to this class as an identified only. Use self.swap_typeclass() to switch.
|
||||
date_created (string) - time stamp of object creation
|
||||
permissions (list of strings) - list of permission strings
|
||||
|
||||
player (Player) - controlling player (will also return offline player)
|
||||
location (Object) - current location. Is None if this is a room
|
||||
home (Object) - safety start-location
|
||||
sessions (list of Sessions, read-only) - returns all sessions connected to this object
|
||||
has_player (bool, read-only)- will only return *connected* players
|
||||
contents (list of Objects, read-only) - returns all objects inside this object (including exits)
|
||||
exits (list of Objects, read-only) - returns all exits from this object, if any
|
||||
destination (Object) - only set if this object is an exit.
|
||||
is_superuser (bool, read-only) - True/False if this user is a superuser
|
||||
|
||||
* Handlers available
|
||||
|
||||
locks - lock-handler: use locks.add() to add new lock strings
|
||||
db - attribute-handler: store/retrieve database attributes on this self.db.myattr=val, val=self.db.myattr
|
||||
ndb - non-persistent attribute handler: same as db but does not create a database entry when storing data
|
||||
scripts - script-handler. Add new scripts to object with scripts.add()
|
||||
cmdset - cmdset-handler. Use cmdset.add() to add new cmdsets to object
|
||||
nicks - nick-handler. New nicks with nicks.add().
|
||||
|
||||
at_object_leave(obj, target_location) - called when this object loose an object (e.g.
|
||||
someone leaving the room, an object is given away etc)
|
||||
at_object_receive(obj, source_location) - called when this object receives another object
|
||||
(e.g. a room being entered, an object moved into inventory)
|
||||
* Helper methods (see src.objects.objects.py for full headers)
|
||||
|
||||
|
||||
|
||||
|
||||
return_appearance(looker) - by default, this is used by the 'look' command to
|
||||
request this object to describe itself. Looker
|
||||
is the object requesting to get the information.
|
||||
at_desc(looker=None) - by default called whenever the appearance is requested.
|
||||
|
||||
at_msg_receive(self, msg, from_obj=None, data=None) - called whenever someone sends a message to this object.
|
||||
message aborted if hook returns False.
|
||||
at_msg_send(self, msg, to_obj=None, data=None) - called when this objects sends a message. This can only be
|
||||
called if from_obj is specified in the call to msg().
|
||||
at_object_delete() - calleed when this object is to be deleted. If returns False, deletion is aborted.
|
||||
search(ostring, global_search=False, attribute_name=None, use_nicks=False, location=None, ignore_errors=False, player=False)
|
||||
execute_cmd(raw_string)
|
||||
msg(message, from_obj=None, data=None)
|
||||
msg_contents(message, exclude=None, from_obj=None, data=None)
|
||||
move_to(destination, quiet=False, emit_to_obj=None, use_destination=True)
|
||||
copy(new_key=None)
|
||||
delete()
|
||||
is_typeclass(typeclass, exact=False)
|
||||
swap_typeclass(new_typeclass, clean_attributes=False, no_default=True)
|
||||
access(accessing_obj, access_type='read', default=False)
|
||||
check_permstring(permstring)
|
||||
|
||||
at_get(getter) - called after object has been picked up. Does not stop pickup.
|
||||
at_drop(dropper) - called when this object has been dropped.
|
||||
at_say(speaker, message) - by default, called if an object inside this object speaks
|
||||
* Hooks (these are class methods, so their arguments should also start with self):
|
||||
|
||||
basetype_setup() - only called once, used for behind-the-scenes setup. Normally not modified.
|
||||
basetype_posthook_setup() - customization in basetype, after the object has been created; Normally not modified.
|
||||
|
||||
at_object_creation() - only called once, when object is first created. Object customizations go here.
|
||||
at_object_delete() - called just before deleting an object. If returning False, deletion is aborted. Note that all objects
|
||||
inside a deleted object are automatically moved to their <home>, they don't need to be removed here.
|
||||
|
||||
at_init() - called whenever typeclass is cached from memory, at least once every server restart/reload
|
||||
at_cmdset_get() - this is called just before the command handler requests a cmdset from this object
|
||||
at_first_login() - (player-controlled objects only) called once, the very first time user logs in.
|
||||
at_pre_login() - (player-controlled objects only) called every time the user connects, after they have identified, before other setup
|
||||
at_post_login() - (player-controlled objects only) called at the end of login, just before setting the player loose in the world.
|
||||
at_disconnect() - (player-controlled objects only) called just before the user disconnects (or goes linkless)
|
||||
at_server_reload() - called before server is reloaded
|
||||
at_server_shutdown() - called just before server is fully shut down
|
||||
|
||||
at_before_move(destination) - called just before moving object to the destination. If returns False, move is cancelled.
|
||||
announce_move_from(destination) - called in old location, just before move, if obj.move_to() has quiet=False
|
||||
announce_move_to(source_location) - called in new location, just after move, if obj.move_to() has quiet=False
|
||||
at_after_move(source_location) - always called after a move has been successfully performed.
|
||||
at_object_leave(obj, target_location) - called when an object leaves this object in any fashion
|
||||
at_object_receive(obj, source_location) - called when this object receives another object
|
||||
|
||||
at_before_traverse(traversing_object) - (exit-objects only) called just before an object traverses this object
|
||||
at_after_traverse(traversing_object, source_location) - (exit-objects only) called just after a traversal has happened.
|
||||
at_failed_traverse(traversing_object) - (exit-objects only) called if traversal fails and property err_traverse is not defined.
|
||||
|
||||
at_msg_receive(self, msg, from_obj=None, data=None) - called when a message (via self.msg()) is sent to this obj.
|
||||
If returns false, aborts send.
|
||||
at_msg_send(self, msg, to_obj=None, data=None) - called when this objects sends a message to someone via self.msg().
|
||||
|
||||
return_appearance(looker) - describes this object. Used by "look" command by default
|
||||
at_desc(looker=None) - called by 'look' whenever the appearance is requested.
|
||||
at_get(getter) - called after object has been picked up. Does not stop pickup.
|
||||
at_drop(dropper) - called when this object has been dropped.
|
||||
at_say(speaker, message) - by default, called if an object inside this object speaks
|
||||
|
||||
at_server_reload() - called when server is reloading
|
||||
at_server_shutdown() - called when server is resetting/shutting down
|
||||
"""
|
||||
pass
|
||||
|
||||
|
|
|
|||
|
|
@ -22,27 +22,43 @@ class Script(BaseScript):
|
|||
All scripts should inherit from this class and implement
|
||||
some or all of its hook functions and variables.
|
||||
|
||||
Important variables controlling the script object:
|
||||
self.key - the name of all scripts inheriting from this class
|
||||
(defaults to <unnamed>), used in lists and searches.
|
||||
self.desc - a description of the script, used in lists
|
||||
self.interval (seconds) - How often the event is triggered and calls self.at_repeat()
|
||||
(see below) Defaults to 0 - that is, never calls at_repeat().
|
||||
self.start_delay (True/False). If True, will wait self.interval seconds
|
||||
befor calling self.at_repeat() for the first time. Defaults to False.
|
||||
self.repeats - The number of times at_repeat() should be called before automatically
|
||||
stopping the script. Default is 0, which means infinitely many repeats.
|
||||
self.persistent (True/False). If True, the script will survive a server restart
|
||||
(defaults to False).
|
||||
* available properties
|
||||
|
||||
self.obj (game Object)- this ties this script to a particular object. It is
|
||||
usually not needed to set this parameter explicitly; it's set in the
|
||||
create methods.
|
||||
key (string) - name of object
|
||||
name (string)- same as key
|
||||
aliases (list of strings) - aliases to the object. Will be saved to database as AliasDB entries but returned as strings.
|
||||
dbref (int, read-only) - unique #id-number. Also "id" can be used.
|
||||
dbobj (Object, read-only) - link to database model. dbobj.typeclass points back to this class
|
||||
typeclass (Object, read-only) - this links back to this class as an identified only. Use self.swap_typeclass() to switch.
|
||||
date_created (string) - time stamp of object creation
|
||||
permissions (list of strings) - list of permission strings
|
||||
|
||||
desc (string) - optional description of script, shown in listings
|
||||
obj (Object) - optional object that this script is connected to and acts on (set automatically by obj.scripts.add())
|
||||
interval (int) - how often script should run, in seconds. <0 turns off ticker
|
||||
start_delay (bool) - if the script should start repeating right away or wait self.interval seconds
|
||||
repeats (int) - how many times the script should repeat before stopping. 0 means infinite repeats
|
||||
persistent (bool) - if script should survive a server shutdown or not
|
||||
is_active (bool) - if script is currently running
|
||||
|
||||
Hook methods (should also include self as the first argument):
|
||||
at_script_creation() - called only once, when an object of this class
|
||||
is first created.
|
||||
* Handlers
|
||||
|
||||
locks - lock-handler: use locks.add() to add new lock strings
|
||||
db - attribute-handler: store/retrieve database attributes on this self.db.myattr=val, val=self.db.myattr
|
||||
ndb - non-persistent attribute handler: same as db but does not create a database entry when storing data
|
||||
|
||||
* Helper methods
|
||||
|
||||
start() - start script (this usually happens automatically at creation and obj.script.add() etc)
|
||||
stop() - stop script, and delete it
|
||||
pause() - put the script on hold, until unpause() is called. If script is persistent, the pause state will survive a shutdown.
|
||||
unpause() - restart a previously paused script. The script will continue as if it was never paused.
|
||||
time_until_next_repeat() - if a timed script (interval>0), returns time until next tick
|
||||
|
||||
* Hook methods (should also include self as the first argument):
|
||||
|
||||
at_script_creation() - called only once, when an object of this
|
||||
class is first created.
|
||||
is_valid() - is called to check if the script is valid to be running
|
||||
at the current time. If is_valid() returns False, the running
|
||||
script is stopped and removed from the game. You can use this
|
||||
|
|
@ -59,5 +75,9 @@ class Script(BaseScript):
|
|||
self.interval==0, this method will never be called.
|
||||
at_stop() - Called as the script object is stopped and is about to be removed from
|
||||
the game, e.g. because is_valid() returned False.
|
||||
at_server_reload() - Called when server reloads. Can be used to save temporary
|
||||
variables you want should survive a reload.
|
||||
at_server_shutdown() - called at a full server shutdown.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -491,6 +491,10 @@ class ObjectDB(TypedObject):
|
|||
This will also find players that don't
|
||||
currently have a character.
|
||||
|
||||
Returns - a unique Object/Player match or None. All error
|
||||
messages are handled by system-commands and the parser-handlers
|
||||
specified in settings.
|
||||
|
||||
Use *<string> to search for objects controlled by a specific
|
||||
player. Note that the object controlled by the player will be
|
||||
returned, not the player object itself. This also means that
|
||||
|
|
@ -538,13 +542,20 @@ class ObjectDB(TypedObject):
|
|||
def execute_cmd(self, raw_string):
|
||||
"""
|
||||
Do something as this object. This command transparently
|
||||
lets its typeclass execute the command.
|
||||
raw_string - raw command input coming from the command line.
|
||||
lets its typeclass execute the command. Evennia also calls
|
||||
this method whenever the player sends a command on the command line.
|
||||
|
||||
The return from this method is None for all default commands
|
||||
(it's the return value of cmd.func()) and is not used in any
|
||||
way by the engine. It might be useful for admins wanting to
|
||||
implement some sort of 'nested' command structure though,
|
||||
Argument:
|
||||
raw_string (string) - raw command input
|
||||
|
||||
Returns Deferred - this is an asynchronous Twisted object that will
|
||||
not fire until the command has actually finished executing. To overload
|
||||
this one needs to attach callback functions to it, with addCallback(function).
|
||||
This function will be called with an eventual return value from the command
|
||||
execution.
|
||||
|
||||
This return is not used at all by Evennia by default, but might be useful
|
||||
for coders intending to implement some sort of nested command structure.
|
||||
"""
|
||||
# nick replacement - we require full-word matching.
|
||||
|
||||
|
|
@ -599,15 +610,27 @@ class ObjectDB(TypedObject):
|
|||
self.msg_contents(message, exclude=exclude, from_obj=from_obj, data=data)
|
||||
|
||||
def move_to(self, destination, quiet=False,
|
||||
emit_to_obj=None):
|
||||
emit_to_obj=None, use_destination=True):
|
||||
"""
|
||||
Moves this object to a new location.
|
||||
|
||||
Moves this object to a new location. Note that if <destination> is an
|
||||
exit object (i.e. it has "destination"!=None), the move_to will
|
||||
happen to this destination and -not- into the exit object itself, unless
|
||||
use_destination=False. Note that no lock checks are done by this function,
|
||||
such things are assumed to have been handled before calling move_to.
|
||||
|
||||
destination: (Object) Reference to the object to move to. This
|
||||
can also be an exit object, in which case the destination
|
||||
property is used as destination.
|
||||
quiet: (bool) If true, don't emit left/arrived messages.
|
||||
emit_to_obj: (Object) object to receive error messages
|
||||
use_destination (bool): Default is for objects to use the "destination" property
|
||||
of destinations as the target to move to. Turning off this
|
||||
keyword allows objects to move "inside" exit objects.
|
||||
|
||||
Returns True/False depending on if there were problems with the move. This method
|
||||
may also return various error messages to the emit_to_obj.
|
||||
"""
|
||||
def logerr(string=""):
|
||||
trc = traceback.format_exc()
|
||||
|
|
@ -765,10 +788,12 @@ class ObjectDB(TypedObject):
|
|||
|
||||
def copy(self, new_key=None):
|
||||
"""
|
||||
Makes an identical copy of this object and returns
|
||||
it. The copy will be named <key>_copy by default. If you
|
||||
want to customize the copy by changing some settings, use
|
||||
the manager method copy_object directly.
|
||||
Makes an identical copy of this object. If you want to customize the copy by
|
||||
changing some settings, use ObjectDB.object.copy_object() directly.
|
||||
|
||||
new_key (string) - new key/name of copied object. If new_key is not specified, the copy will be named
|
||||
<old_key>_copy by default.
|
||||
Returns: Object (copy of this one)
|
||||
"""
|
||||
if not new_key:
|
||||
new_key = "%s_copy" % self.key
|
||||
|
|
|
|||
|
|
@ -29,6 +29,254 @@ class Object(TypeClass):
|
|||
objects in the game.
|
||||
"""
|
||||
|
||||
## available properties
|
||||
|
||||
# key (string) - name of object
|
||||
# name (string)- same as key
|
||||
# aliases (list of strings) - aliases to the object. Will be saved to database as AliasDB entries but returned as strings.
|
||||
# dbref (int, read-only) - unique #id-number. Also "id" can be used.
|
||||
# dbobj (Object, read-only) - link to database model. dbobj.typeclass points back to this class
|
||||
# typeclass (Object, read-only) - this links back to this class as an identified only. Use self.swap_typeclass() to switch.
|
||||
# date_created (string) - time stamp of object creation
|
||||
# permissions (list of strings) - list of permission strings
|
||||
|
||||
# player (Player) - controlling player (will also return offline player)
|
||||
# location (Object) - current location. Is None if this is a room
|
||||
# home (Object) - safety start-location
|
||||
# sessions (list of Sessions, read-only) - returns all sessions connected to this object
|
||||
# has_player (bool, read-only)- will only return *connected* players
|
||||
# contents (list of Objects, read-only) - returns all objects inside this object (including exits)
|
||||
# exits (list of Objects, read-only) - returns all exits from this object, if any
|
||||
# destination (Object) - only set if this object is an exit.
|
||||
# is_superuser (bool, read-only) - True/False if this user is a superuser
|
||||
|
||||
# Handlers
|
||||
# locks - lock-handler: use locks.add() to add new lock strings
|
||||
# db - attribute-handler: store/retrieve database attributes on this self.db.myattr=val, val=self.db.myattr
|
||||
# ndb - non-persistent attribute handler: same as db but does not create a database entry when storing data
|
||||
# scripts - script-handler. Add new scripts to object with scripts.add()
|
||||
# cmdset - cmdset-handler. Use cmdset.add() to add new cmdsets to object
|
||||
# nicks - nick-handler. New nicks with nicks.add().
|
||||
|
||||
## methods inherited from the database object (overload them here)
|
||||
|
||||
def search(self, ostring,
|
||||
global_search=False,
|
||||
attribute_name=None,
|
||||
use_nicks=False,
|
||||
location=None,
|
||||
ignore_errors=False,
|
||||
player=False):
|
||||
"""
|
||||
Perform a standard object search in the database, handling
|
||||
multiple results and lack thereof gracefully.
|
||||
|
||||
ostring: (str) The string to match object names against.
|
||||
Obs - To find a player, append * to the
|
||||
start of ostring.
|
||||
global_search(bool): Search all objects, not just the current
|
||||
location/inventory
|
||||
attribute_name (string) Which attribute to match
|
||||
(if None, uses default 'name')
|
||||
use_nicks (bool) : Use nickname replace (off by default)
|
||||
location (Object): If None, use caller's current location
|
||||
ignore_errors (bool): Don't display any error messages even
|
||||
if there are none/multiple matches -
|
||||
just return the result as a list.
|
||||
player (Objectt): Don't search for an Object but a Player.
|
||||
This will also find players that don't
|
||||
currently have a character.
|
||||
|
||||
Returns - a unique Object/Player match or None. All error
|
||||
messages are handled by system-commands and the parser-handlers
|
||||
specified in settings.
|
||||
|
||||
Use *<string> to search for objects controlled by a specific
|
||||
player. Note that the object controlled by the player will be
|
||||
returned, not the player object itself. This also means that
|
||||
this will not find Players without a character. Use the keyword
|
||||
player=True to find player objects.
|
||||
|
||||
Note - for multiple matches, the engine accepts a number
|
||||
linked to the key in order to separate the matches from
|
||||
each other without showing the dbref explicitly. Default
|
||||
syntax for this is 'N-searchword'. So for example, if there
|
||||
are three objects in the room all named 'ball', you could
|
||||
address the individual ball as '1-ball', '2-ball', '3-ball'
|
||||
etc.
|
||||
"""
|
||||
return self.dbobj.search(ostring,
|
||||
global_search=global_search,
|
||||
attribute_name=attribute_name,
|
||||
use_nicks=use_nicks,
|
||||
location=location,
|
||||
ignore_errors=ignore_errors,
|
||||
player=player)
|
||||
|
||||
def execute_cmd(self, raw_string):
|
||||
"""
|
||||
Do something as this object. This command transparently
|
||||
lets its typeclass execute the command. Evennia also calls
|
||||
this method whenever the player sends a command on the command line.
|
||||
|
||||
Argument:
|
||||
raw_string (string) - raw command input
|
||||
|
||||
Returns Deferred - this is an asynchronous Twisted object that will
|
||||
not fire until the command has actually finished executing. To overload
|
||||
this one needs to attach callback functions to it, with addCallback(function).
|
||||
This function will be called with an eventual return value from the command
|
||||
execution.
|
||||
|
||||
This return is not used at all by Evennia by default, but might be useful
|
||||
for coders intending to implement some sort of nested command structure.
|
||||
"""
|
||||
return self.dbobj.execute_cmd(raw_string)
|
||||
|
||||
def msg(self, message, from_obj=None, data=None):
|
||||
"""
|
||||
Emits something to any sessions attached to the object.
|
||||
|
||||
message (str): The message to send
|
||||
from_obj (obj): object that is sending.
|
||||
data (object): an optional data object that may or may not
|
||||
be used by the protocol.
|
||||
"""
|
||||
self.dbobj.msg(message, from_obj=from_obj, data=data)
|
||||
|
||||
def msg_contents(self, message, exclude=None, from_obj=None, data=None):
|
||||
"""
|
||||
Emits something to all objects inside an object.
|
||||
|
||||
exclude is a list of objects not to send to. See self.msg() for more info.
|
||||
"""
|
||||
self.dbobj.msg_contents(message, exclude=exclude, from_obj=from_obj, data=data)
|
||||
|
||||
def move_to(self, destination, quiet=False,
|
||||
emit_to_obj=None, use_destination=True):
|
||||
"""
|
||||
Moves this object to a new location. Note that if <destination> is an
|
||||
exit object (i.e. it has "destination"!=None), the move_to will
|
||||
happen to this destination and -not- into the exit object itself, unless
|
||||
use_destination=False. Note that no lock checks are done by this function,
|
||||
such things are assumed to have been handled before calling move_to.
|
||||
|
||||
destination: (Object) Reference to the object to move to. This
|
||||
can also be an exit object, in which case the destination
|
||||
property is used as destination.
|
||||
quiet: (bool) If true, don't emit left/arrived messages.
|
||||
emit_to_obj: (Object) object to receive error messages
|
||||
use_destination (bool): Default is for objects to use the "destination" property
|
||||
of destinations as the target to move to. Turning off this
|
||||
keyword allows objects to move "inside" exit objects.
|
||||
Returns True/False depending on if there were problems with the move. This method
|
||||
may also return various error messages to the emit_to_obj.
|
||||
|
||||
"""
|
||||
return self.dbobj.move_to(destination, quiet=quiet,
|
||||
emit_to_obj=emit_to_obj, use_destination=use_destination)
|
||||
|
||||
def copy(self, new_key=None):
|
||||
"""
|
||||
Makes an identical copy of this object. If you want to customize the copy by
|
||||
changing some settings, use ObjectDB.object.copy_object() directly.
|
||||
|
||||
new_key (string) - new key/name of copied object. If new_key is not specified, the copy will be named
|
||||
<old_key>_copy by default.
|
||||
Returns: Object (copy of this one)
|
||||
"""
|
||||
return self.dbobj.copy(new_key=new_key)
|
||||
|
||||
def delete(self):
|
||||
"""
|
||||
Deletes this object.
|
||||
Before deletion, this method makes sure to move all contained
|
||||
objects to their respective home locations, as well as clean
|
||||
up all exits to/from the object.
|
||||
|
||||
Returns: boolean True if deletion succeded, False if there
|
||||
were errors during deletion or deletion otherwise
|
||||
failed.
|
||||
"""
|
||||
return self.dbobj.delete()
|
||||
|
||||
|
||||
# methods inherited from the typeclass system
|
||||
|
||||
def is_typeclass(self, typeclass, exact=False):
|
||||
"""
|
||||
Returns true if this object has this type
|
||||
OR has a typeclass which is an subclass of
|
||||
the given typeclass.
|
||||
|
||||
typeclass - can be a class object or the
|
||||
python path to such an object to match against.
|
||||
|
||||
exact - returns true only if the object's
|
||||
type is exactly this typeclass, ignoring
|
||||
parents.
|
||||
|
||||
Returns: Boolean
|
||||
"""
|
||||
return self.dbobj.is_typeclass(typeclass, exact=exact)
|
||||
|
||||
def swap_typeclass(self, new_typeclass, clean_attributes=False, no_default=True):
|
||||
"""
|
||||
This performs an in-situ swap of the typeclass. This means
|
||||
that in-game, this object will suddenly be something else.
|
||||
Player will not be affected. To 'move' a player to a different
|
||||
object entirely (while retaining this object's type), use
|
||||
self.player.swap_object().
|
||||
|
||||
Note that this might be an error prone operation if the
|
||||
old/new typeclass was heavily customized - your code
|
||||
might expect one and not the other, so be careful to
|
||||
bug test your code if using this feature! Often its easiest
|
||||
to create a new object and just swap the player over to
|
||||
that one instead.
|
||||
|
||||
Arguments:
|
||||
new_typeclass (path/classobj) - type to switch to
|
||||
clean_attributes (bool/list) - will delete all attributes
|
||||
stored on this object (but not any
|
||||
of the database fields such as name or
|
||||
location). You can't get attributes back,
|
||||
but this is often the safest bet to make
|
||||
sure nothing in the new typeclass clashes
|
||||
with the old one. If you supply a list,
|
||||
only those named attributes will be cleared.
|
||||
no_default - if this is active, the swapper will not allow for
|
||||
swapping to a default typeclass in case the given
|
||||
one fails for some reason. Instead the old one
|
||||
will be preserved.
|
||||
Returns:
|
||||
boolean True/False depending on if the swap worked or not.
|
||||
|
||||
|
||||
"""
|
||||
self.dbobj.swap_typeclass(new_typeclass, clean_attributes=clean_attributes, no_default=no_default)
|
||||
|
||||
def access(self, accessing_obj, access_type='read', default=False):
|
||||
"""
|
||||
Determines if another object has permission to access this object in whatever way.
|
||||
|
||||
accessing_obj (Object)- object trying to access this one
|
||||
access_type (string) - type of access sought
|
||||
default (bool) - what to return if no lock of access_type was found
|
||||
"""
|
||||
return self.dbobj.access(accessing_obj, access_type=access_type, default=default)
|
||||
|
||||
def check_permstring(self, permstring):
|
||||
"""
|
||||
This explicitly checks the given string against this object's
|
||||
'permissions' property without involving any locks.
|
||||
|
||||
permstring (string) - permission string that need to match a permission on the object.
|
||||
(example: 'Builders')
|
||||
"""
|
||||
return self.dbobj.check_permstring(permstring)
|
||||
|
||||
|
||||
def __eq__(self, other):
|
||||
"""
|
||||
Checks for equality against an id string or another object or user.
|
||||
|
|
@ -46,8 +294,10 @@ class Object(TypeClass):
|
|||
pass
|
||||
return result
|
||||
|
||||
# hooks called by the game engine
|
||||
|
||||
## hooks called by the game engine
|
||||
|
||||
|
||||
def basetype_setup(self):
|
||||
"""
|
||||
This sets up the default properties of an Object,
|
||||
|
|
@ -72,23 +322,6 @@ class Object(TypeClass):
|
|||
self.locks.add("call:true()") # allow to call commands on this object
|
||||
self.locks.add("puppet:id(%s) or perm(Immortals) or pperm(Immortals)" % dbref) # restricts puppeting of this object
|
||||
|
||||
def at_object_creation(self):
|
||||
"""
|
||||
Called once, when this object is first
|
||||
created.
|
||||
"""
|
||||
pass
|
||||
|
||||
def at_init(self):
|
||||
"""
|
||||
This is always called whenever this object is initiated --
|
||||
that is, whenever it its typeclass is cached from memory. This
|
||||
happens on-demand first time the object is used or activated
|
||||
in some way after being created but also after each server
|
||||
restart or reload.
|
||||
"""
|
||||
pass
|
||||
|
||||
def basetype_posthook_setup(self):
|
||||
"""
|
||||
Called once, after basetype_setup and at_object_creation. This should generally not be overloaded unless
|
||||
|
|
@ -98,20 +331,30 @@ class Object(TypeClass):
|
|||
"""
|
||||
pass
|
||||
|
||||
def at_server_reload(self):
|
||||
"""
|
||||
This hook is called whenever the server is shutting down for restart/reboot.
|
||||
If you want to, for example, save non-persistent properties across a restart,
|
||||
this is the place to do it.
|
||||
def at_object_creation(self):
|
||||
"""
|
||||
Called once, when this object is first created.
|
||||
"""
|
||||
pass
|
||||
|
||||
def at_server_shutdown(self):
|
||||
|
||||
def at_object_delete(self):
|
||||
"""
|
||||
This hook is called whenever the server is shutting down fully (i.e. not for
|
||||
a restart).
|
||||
Called just before the database object is
|
||||
permanently delete()d from the database. If
|
||||
this method returns False, deletion is aborted.
|
||||
"""
|
||||
pass
|
||||
return True
|
||||
|
||||
def at_init(self):
|
||||
"""
|
||||
This is always called whenever this object is initiated --
|
||||
that is, whenever it its typeclass is cached from memory. This
|
||||
happens on-demand first time the object is used or activated
|
||||
in some way after being created but also after each server
|
||||
restart or reload.
|
||||
"""
|
||||
pass
|
||||
|
||||
def at_cmdset_get(self):
|
||||
"""
|
||||
|
|
@ -149,6 +392,22 @@ class Object(TypeClass):
|
|||
"""
|
||||
pass
|
||||
|
||||
def at_server_reload(self):
|
||||
"""
|
||||
This hook is called whenever the server is shutting down for restart/reboot.
|
||||
If you want to, for example, save non-persistent properties across a restart,
|
||||
this is the place to do it.
|
||||
"""
|
||||
pass
|
||||
|
||||
def at_server_shutdown(self):
|
||||
"""
|
||||
This hook is called whenever the server is shutting down fully (i.e. not for
|
||||
a restart).
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
# hooks called when moving the object
|
||||
|
||||
def at_before_move(self, destination):
|
||||
|
|
@ -260,6 +519,39 @@ class Object(TypeClass):
|
|||
"""
|
||||
pass
|
||||
|
||||
def at_msg_receive(self, msg, from_obj=None, data=None):
|
||||
"""
|
||||
This hook is called whenever someone
|
||||
sends a message to this object.
|
||||
|
||||
Note that from_obj may be None if the sender did
|
||||
not include itself as an argument to the obj.msg()
|
||||
call - so you have to check for this. .
|
||||
|
||||
Consider this a pre-processing method before
|
||||
msg is passed on to the user sesssion. If this
|
||||
method returns False, the msg will not be
|
||||
passed on.
|
||||
|
||||
msg = the message received
|
||||
from_obj = the one sending the message
|
||||
"""
|
||||
return True
|
||||
|
||||
def at_msg_send(self, msg, to_obj=None, data=None):
|
||||
"""
|
||||
This is a hook that is called when /this/ object
|
||||
sends a message to another object with obj.msg()
|
||||
while also specifying that it is the one sending.
|
||||
|
||||
Note that this method is executed on the object
|
||||
passed along with the msg() function (i.e. using
|
||||
obj.msg(msg, caller) will then launch caller.at_msg())
|
||||
and if no object was passed, it will never be called.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
# hooks called by the default cmdset.
|
||||
|
||||
def return_appearance(self, pobject):
|
||||
|
|
@ -296,38 +588,6 @@ class Object(TypeClass):
|
|||
string += ", ".join(things)
|
||||
return string
|
||||
|
||||
def at_msg_receive(self, msg, from_obj=None, data=None):
|
||||
"""
|
||||
This hook is called whenever someone
|
||||
sends a message to this object.
|
||||
|
||||
Note that from_obj may be None if the sender did
|
||||
not include itself as an argument to the obj.msg()
|
||||
call - so you have to check for this. .
|
||||
|
||||
Consider this a pre-processing method before
|
||||
msg is passed on to the user sesssion. If this
|
||||
method returns False, the msg will not be
|
||||
passed on.
|
||||
|
||||
msg = the message received
|
||||
from_obj = the one sending the message
|
||||
"""
|
||||
return True
|
||||
|
||||
def at_msg_send(self, msg, to_obj=None, data=None):
|
||||
"""
|
||||
This is a hook that is called when /this/ object
|
||||
sends a message to another object with obj.msg()
|
||||
while also specifying that it is the one sending.
|
||||
|
||||
Note that this method is executed on the object
|
||||
passed along with the msg() function (i.e. using
|
||||
obj.msg(msg, caller) will then launch caller.at_msg())
|
||||
and if no object was passed, it will never be called.
|
||||
"""
|
||||
pass
|
||||
|
||||
def at_desc(self, looker=None):
|
||||
"""
|
||||
This is called whenever someone looks
|
||||
|
|
@ -335,14 +595,6 @@ class Object(TypeClass):
|
|||
object.
|
||||
"""
|
||||
pass
|
||||
|
||||
def at_object_delete(self):
|
||||
"""
|
||||
Called just before the database object is
|
||||
permanently delete()d from the database. If
|
||||
this method returns False, deletion is aborted.
|
||||
"""
|
||||
return True
|
||||
|
||||
def at_get(self, getter):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -120,7 +120,6 @@ class PlayerDB(TypedObject):
|
|||
|
||||
The TypedObject supplies the following (inherited) properties:
|
||||
key - main name
|
||||
name - alias for key
|
||||
typeclass_path - the path to the decorating typeclass
|
||||
typeclass - auto-linked typeclass
|
||||
date_created - time stamp of object creation
|
||||
|
|
@ -363,7 +362,7 @@ class PlayerDB(TypedObject):
|
|||
if nick.db_nick in raw_list:
|
||||
raw_string = raw_string.replace(nick.db_nick, nick.db_real, 1)
|
||||
break
|
||||
cmdhandler.cmdhandler(self.typeclass, raw_string)
|
||||
return cmdhandler.cmdhandler(self.typeclass, raw_string)
|
||||
|
||||
def search(self, ostring, global_search=False, attribute_name=None, use_nicks=False,
|
||||
location=None, ignore_errors=False, player=False):
|
||||
|
|
|
|||
|
|
@ -18,6 +18,161 @@ class Player(TypeClass):
|
|||
"""
|
||||
Base typeclass for all Players.
|
||||
"""
|
||||
|
||||
## available properties
|
||||
|
||||
# key (string) - name of player
|
||||
# name (string)- wrapper for user.username
|
||||
# aliases (list of strings) - aliases to the object. Will be saved to database as AliasDB entries but returned as strings.
|
||||
# dbref (int, read-only) - unique #id-number. Also "id" can be used.
|
||||
# dbobj (Player, read-only) - link to database model. dbobj.typeclass points back to this class
|
||||
# typeclass (Player, read-only) - this links back to this class as an identified only. Use self.swap_typeclass() to switch.
|
||||
# date_created (string) - time stamp of object creation
|
||||
# permissions (list of strings) - list of permission strings
|
||||
|
||||
# user (User, read-only) - django User authorization object
|
||||
# obj (Object) - game object controlled by player. 'character' can also be used.
|
||||
# sessions (list of Sessions) - sessions connected to this player
|
||||
# is_superuser (bool, read-only) - if the connected user is a superuser
|
||||
|
||||
## Handlers
|
||||
|
||||
# locks - lock-handler: use locks.add() to add new lock strings
|
||||
# db - attribute-handler: store/retrieve database attributes on this self.db.myattr=val, val=self.db.myattr
|
||||
# ndb - non-persistent attribute handler: same as db but does not create a database entry when storing data
|
||||
# scripts - script-handler. Add new scripts to object with scripts.add()
|
||||
# cmdset - cmdset-handler. Use cmdset.add() to add new cmdsets to object
|
||||
# nicks - nick-handler. New nicks with nicks.add().
|
||||
|
||||
|
||||
## methods inherited from database model
|
||||
|
||||
def msg(self, outgoing_string, from_obj=None, data=None):
|
||||
"""
|
||||
Evennia -> User
|
||||
This is the main route for sending data back to the user from the server.
|
||||
|
||||
outgoing_string (string) - text data to send
|
||||
from_obj (Object/Player) - source object of message to send
|
||||
data (?) - arbitrary data object containing eventual protocol-specific options
|
||||
|
||||
"""
|
||||
self.dbobj.msg(outgoing_string, from_obj=from_obj, data=data)
|
||||
|
||||
def swap_character(self, new_character, delete_old_character=False):
|
||||
"""
|
||||
Swaps the character controlled by this Player, if possible.
|
||||
|
||||
new_character (Object) - character/object to swap to
|
||||
delete_old_character (bool) - delete the old character when swapping
|
||||
|
||||
Returns: True/False depending on if swap suceeded or not.
|
||||
"""
|
||||
return self.dbobj.swap_character(new_character, delete_old_character=delete_old_character)
|
||||
|
||||
def execute_cmd(self, raw_string):
|
||||
"""
|
||||
Do something as this object. This command transparently
|
||||
lets its typeclass execute the command. Evennia also calls
|
||||
this method whenever the player sends a command on the command line.
|
||||
|
||||
Argument:
|
||||
raw_string (string) - raw command input
|
||||
|
||||
Returns Deferred - this is an asynchronous Twisted object that will
|
||||
not fire until the command has actually finished executing. To overload
|
||||
this one needs to attach callback functions to it, with addCallback(function).
|
||||
This function will be called with an eventual return value from the command
|
||||
execution.
|
||||
|
||||
This return is not used at all by Evennia by default, but might be useful
|
||||
for coders intending to implement some sort of nested command structure.
|
||||
"""
|
||||
self.dbobj.execute_cmd(raw_string)
|
||||
|
||||
def search(self, ostring, global_search=False, attribute_name=None, use_nicks=False,
|
||||
location=None, ignore_errors=False, player=False):
|
||||
"""
|
||||
This method mimicks object.search if self.character is set. Otherwise only
|
||||
other Players can be searched with this method.
|
||||
"""
|
||||
self.dbobj.search(ostring, global_search=global_search, attribute_name=attribute_name, use_nicks=use_nicks,
|
||||
location=location, ignore_errors=ignore_errors, player=player)
|
||||
|
||||
def is_typeclass(self, typeclass, exact=False):
|
||||
"""
|
||||
Returns true if this object has this type
|
||||
OR has a typeclass which is an subclass of
|
||||
the given typeclass.
|
||||
|
||||
typeclass - can be a class object or the
|
||||
python path to such an object to match against.
|
||||
|
||||
exact - returns true only if the object's
|
||||
type is exactly this typeclass, ignoring
|
||||
parents.
|
||||
|
||||
Returns: Boolean
|
||||
"""
|
||||
return self.dbobj.is_typeclass(typeclass, exact=exact)
|
||||
|
||||
def swap_typeclass(self, new_typeclass, clean_attributes=False, no_default=True):
|
||||
"""
|
||||
This performs an in-situ swap of the typeclass. This means
|
||||
that in-game, this object will suddenly be something else.
|
||||
Player will not be affected. To 'move' a player to a different
|
||||
object entirely (while retaining this object's type), use
|
||||
self.player.swap_object().
|
||||
|
||||
Note that this might be an error prone operation if the
|
||||
old/new typeclass was heavily customized - your code
|
||||
might expect one and not the other, so be careful to
|
||||
bug test your code if using this feature! Often its easiest
|
||||
to create a new object and just swap the player over to
|
||||
that one instead.
|
||||
|
||||
Arguments:
|
||||
new_typeclass (path/classobj) - type to switch to
|
||||
clean_attributes (bool/list) - will delete all attributes
|
||||
stored on this object (but not any
|
||||
of the database fields such as name or
|
||||
location). You can't get attributes back,
|
||||
but this is often the safest bet to make
|
||||
sure nothing in the new typeclass clashes
|
||||
with the old one. If you supply a list,
|
||||
only those named attributes will be cleared.
|
||||
no_default - if this is active, the swapper will not allow for
|
||||
swapping to a default typeclass in case the given
|
||||
one fails for some reason. Instead the old one
|
||||
will be preserved.
|
||||
Returns:
|
||||
boolean True/False depending on if the swap worked or not.
|
||||
|
||||
|
||||
"""
|
||||
self.dbobj.swap_typeclass(new_typeclass, clean_attributes=clean_attributes, no_default=no_default)
|
||||
|
||||
def access(self, accessing_obj, access_type='read', default=False):
|
||||
"""
|
||||
Determines if another object has permission to access this object in whatever way.
|
||||
|
||||
accessing_obj (Object)- object trying to access this one
|
||||
access_type (string) - type of access sought
|
||||
default (bool) - what to return if no lock of access_type was found
|
||||
"""
|
||||
return self.dbobj.access(accessing_obj, access_type=access_type, default=default)
|
||||
|
||||
def check_permstring(self, permstring):
|
||||
"""
|
||||
This explicitly checks the given string against this object's
|
||||
'permissions' property without involving any locks.
|
||||
|
||||
permstring (string) - permission string that need to match a permission on the object.
|
||||
(example: 'Builders')
|
||||
"""
|
||||
return self.dbobj.check_permstring(permstring)
|
||||
|
||||
## player hooks
|
||||
|
||||
def basetype_setup(self):
|
||||
"""
|
||||
|
|
@ -63,14 +218,11 @@ class Player(TypeClass):
|
|||
"""
|
||||
pass
|
||||
|
||||
# Note that the hooks below also exist
|
||||
# in the character object's typeclass. You
|
||||
# can often ignore these and rely on the
|
||||
# character ones instead, unless you
|
||||
# are implementing a multi-character game
|
||||
# and have some things that should be done
|
||||
# regardless of which character is currently
|
||||
# connected to this player.
|
||||
# Note that the hooks below also exist in the character object's
|
||||
# typeclass. You can often ignore these and rely on the character
|
||||
# ones instead, unless you are implementing a multi-character game
|
||||
# and have some things that should be done regardless of which
|
||||
# character is currently connected to this player.
|
||||
|
||||
def at_cmdset_get(self):
|
||||
"""
|
||||
|
|
@ -87,12 +239,14 @@ class Player(TypeClass):
|
|||
time the user logs in.
|
||||
"""
|
||||
pass
|
||||
|
||||
def at_pre_login(self):
|
||||
"""
|
||||
Called every time the user logs in,
|
||||
before they are actually logged in.
|
||||
"""
|
||||
pass
|
||||
|
||||
def at_post_login(self):
|
||||
"""
|
||||
Called at the end of the login
|
||||
|
|
@ -100,6 +254,7 @@ class Player(TypeClass):
|
|||
them loose.
|
||||
"""
|
||||
pass
|
||||
|
||||
def at_disconnect(self, reason=None):
|
||||
"""
|
||||
Called just before user
|
||||
|
|
|
|||
|
|
@ -101,6 +101,8 @@ class ScriptClass(TypeClass):
|
|||
except Exception:
|
||||
logger.log_trace()
|
||||
|
||||
|
||||
# Public methods
|
||||
|
||||
def time_until_next_repeat(self):
|
||||
"""
|
||||
|
|
@ -251,6 +253,32 @@ class Script(ScriptClass):
|
|||
the hooks called by the script machinery.
|
||||
"""
|
||||
|
||||
## available properties
|
||||
|
||||
# key (string) - name of object
|
||||
# name (string)- same as key
|
||||
# aliases (list of strings) - aliases to the object. Will be saved to database as AliasDB entries but returned as strings.
|
||||
# dbref (int, read-only) - unique #id-number. Also "id" can be used.
|
||||
# dbobj (Object, read-only) - link to database model. dbobj.typeclass points back to this class
|
||||
# typeclass (Object, read-only) - this links back to this class as an identified only. Use self.swap_typeclass() to switch.
|
||||
# date_created (string) - time stamp of object creation
|
||||
# permissions (list of strings) - list of permission strings
|
||||
|
||||
# desc (string) - optional description of script, shown in listings
|
||||
# obj (Object) - optional object that this script is connected to and acts on (set automatically by obj.scripts.add())
|
||||
# interval (int) - how often script should run, in seconds. <0 turns off ticker
|
||||
# start_delay (bool) - if the script should start repeating right away or wait self.interval seconds
|
||||
# repeats (int) - how many times the script should repeat before stopping. 0 means infinite repeats
|
||||
# persistent (bool) - if script should survive a server shutdown or not
|
||||
# is_active (bool) - if script is currently running
|
||||
|
||||
## Handlers
|
||||
|
||||
# locks - lock-handler: use locks.add() to add new lock strings
|
||||
# db - attribute-handler: store/retrieve database attributes on this self.db.myattr=val, val=self.db.myattr
|
||||
# ndb - non-persistent attribute handler: same as db but does not create a database entry when storing data
|
||||
|
||||
|
||||
def at_script_creation(self):
|
||||
"""
|
||||
Only called once, by the create function.
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ that are protected, so as to not overwrite property names
|
|||
used by the typesystem or django itself.
|
||||
"""
|
||||
|
||||
from src.utils import logger
|
||||
from src.utils.logger import log_trace, log_errmsg
|
||||
from django.conf import settings
|
||||
|
||||
# these are called so many times it's worth to avoid lookup calls
|
||||
|
|
@ -92,14 +92,8 @@ class TypeClass(object):
|
|||
property on the class, it will NOT be
|
||||
accessible through getattr.
|
||||
"""
|
||||
try:
|
||||
dbobj = GA(self, 'dbobj')
|
||||
except AttributeError:
|
||||
dbobj = None
|
||||
logger.log_trace("This is probably due to an unsafe reload.")
|
||||
raise
|
||||
if propname == 'dbobj':
|
||||
return dbobj
|
||||
return GA(self, 'dbobj')
|
||||
if propname.startswith('__') and propname.endswith('__'):
|
||||
# python specials are parsed as-is (otherwise things like
|
||||
# isinstance() fail to identify the typeclass)
|
||||
|
|
@ -108,20 +102,19 @@ class TypeClass(object):
|
|||
try:
|
||||
return GA(self, propname)
|
||||
except AttributeError:
|
||||
try:
|
||||
dbobj = GA(self, 'dbobj')
|
||||
except AttributeError:
|
||||
log_trace("Typeclass CRITICAL ERROR! dbobj not found for Typeclass %s!" % self)
|
||||
raise
|
||||
try:
|
||||
return GA(dbobj, propname)
|
||||
except AttributeError:
|
||||
try:
|
||||
if propname == 'ndb':
|
||||
# get non-persistent data (getattr raises AttributeError)
|
||||
return getattr(GA(dbobj, 'ndb'), propname)
|
||||
else:
|
||||
return GA(dbobj,"get_attribute_raise")(propname)
|
||||
return GA(dbobj,"get_attribute_raise")(propname)
|
||||
except AttributeError:
|
||||
string = "Object: '%s' not found on %s(%s), nor on its typeclass %s."
|
||||
raise AttributeError(string % (propname, dbobj,
|
||||
dbobj.dbref,
|
||||
dbobj.typeclass_path,))
|
||||
raise AttributeError(string % (propname, dbobj, dbobj.dbref, dbobj.typeclass_path))
|
||||
|
||||
def __setattr__(self, propname, value):
|
||||
"""
|
||||
|
|
@ -135,14 +128,14 @@ class TypeClass(object):
|
|||
if propname in PROTECTED:
|
||||
string = "%s: '%s' is a protected attribute name."
|
||||
string += " (protected: [%s])" % (", ".join(PROTECTED))
|
||||
logger.log_errmsg(string % (self.name, propname))
|
||||
log_errmsg(string % (self.name, propname))
|
||||
return
|
||||
|
||||
try:
|
||||
dbobj = GA(self, 'dbobj')
|
||||
except AttributeError:
|
||||
dbobj = None
|
||||
logger.log_trace("This is probably due to an unsafe reload.")
|
||||
log_trace("This is probably due to an unsafe reload.")
|
||||
|
||||
if dbobj:
|
||||
try:
|
||||
|
|
@ -175,7 +168,7 @@ class TypeClass(object):
|
|||
if propname in PROTECTED:
|
||||
string = "%s: '%s' is a protected attribute name."
|
||||
string += " (protected: [%s])" % (", ".join(PROTECTED))
|
||||
logger.log_errmsg(string % (self.name, propname))
|
||||
log_errmsg(string % (self.name, propname))
|
||||
return
|
||||
|
||||
try:
|
||||
|
|
@ -185,7 +178,7 @@ class TypeClass(object):
|
|||
try:
|
||||
dbobj = GA(self, 'dbobj')
|
||||
except AttributeError:
|
||||
logger.log_trace("This is probably due to an unsafe reload.")
|
||||
log_trace("This is probably due to an unsafe reload.")
|
||||
return # ignore delete
|
||||
try:
|
||||
dbobj.del_attribute_raise(propname)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue