SDK Functions
Every name listed here is exported from moo.sdk and importable in
verb code (from moo.sdk import lookup, create, ...). For methods
defined on the Object model and accessible as obj.<name>(...),
see Objects in the DjangoMOO Database. For Property and Verb field reference, see
Properties on Objects and Verbs on Objects.
Object lifecycle and lookup
- moo.sdk.lookup(x, return_first=True)
Lookup an object within the current site by PK, name, or alias.
PK lookups are site-scoped: an integer PK that belongs to a different universe raises
NoSuchObjectErrorthe same as a missing object would. Internal system code that genuinely needs cross-site access should useObject.global_objectsdirectly rather than going through this function.- Parameters:
x (
Union[int,str]) – lookup valuereturn_first (
bool) – when True (default), return the first match or raise NoSuchObjectError; when False, return a list of all matches (may be empty)
- Returns:
the result of the lookup, or a list when return_first is False
- Return type:
- Raises:
NoSuchObjectError – when a result cannot be found and return_first is True
- moo.sdk.create(name, *a, **kw)
Creates and returns a new object whose parents are parents and whose owner is as described below. Provided parents are valid Objects with derive permission, otherwise
PermissionErroris raised. After the new object is created, its initialize verb, if any, is called with no arguments.The owner of the new object is either the programmer (if owner is not provided), or the provided owner, if the caller has permission to entrust the object.
If the intended owner of the new object has a property named ownership_quota and the value of that property is an integer, then create() treats that value as a quota. If the quota is less than or equal to zero, then the quota is considered to be exhausted and create() raises
QuotaErrorinstead of creating an object. Otherwise, the quota is decremented and stored back into the ownership_quota property as a part of the creation of the new object.- Parameters:
- Returns:
the new object
- Return type:
- Raises:
PermissionError – if the caller is not allowed to derive from the parent
QuotaError – if the caller has a quota and it has been exceeded
- moo.sdk.players()
Return a list of all player avatar Objects.
- Returns:
Objects that are player avatars
- Return type:
list[Object]
- moo.sdk.connected_players(within=None)
Return a list of player avatars whose
last_connected_timeproperty was updated within the given within window (default: 5 minutes).The
last_connected_timevalue is precached into the session-level property cache on every returned Object so subsequentget_propertycalls incur no extra queries.- Parameters:
within (timedelta) – recency window; defaults to
timedelta(minutes=5)- Returns:
Objects whose avatars have connected recently
- Return type:
list[Object]
- moo.sdk.owned_objects(player_obj)
Return a QuerySet of all Objects owned by player_obj, ordered by name.
- Parameters:
player_obj – the owner Object
- Return type:
QuerySet
- moo.sdk.owned_objects_by_pks(pk_list)
Return a QuerySet of Objects with PKs in pk_list, ordered by name.
Used by continuation tasks (e.g.
audit_batch) where the target player is not in scope but the remaining PK list was passed asargs[0].- Parameters:
pk_list – list of integer Object PKs
- Return type:
QuerySet
- moo.sdk.ensure_player_record(obj)
Ensure a
Playerrow exists for obj withuser=None.Used by NPC initialization so the avatar reports
is_player() == Trueto the parser whileis_connected() == Falsecausestell()to silently drop (no connection). Idempotent: returns the existing Player if one already references this avatar.- Parameters:
obj – the avatar Object
- Returns:
the Player row (created or pre-existing)
- Raises:
UserError – if the current caller is not a wizard
- moo.sdk.remove_player_record(obj)
Delete any anonymous (
user=None)Playerrows pointing at obj.Counterpart to
ensure_player_record(); used by the$npc.recycleverb. Rows tied to a realUserare left alone — those belong to a human player and removing them is not this helper’s job.- Parameters:
obj – the avatar Object
- Returns:
number of Player rows deleted
- Raises:
UserError – if the current caller is not a wizard
Tasks and continuations
- moo.sdk.invoke(*args, verb=None, callback=None, delay=0, periodic=False, cron=None, _caller=None, _player=None, **kwargs)
Asynchronously execute a Verb, optionally returning the result to another Verb. This is often a better alternative than using __call__-syntax to invoke a verb directly, since Verbs invoked this way will each have their own timeout.
- Parameters:
verb (Verb) – the Verb to execute
callback (Verb) – an optional callback Verb to receive the result
delay (
int) – seconds to wait before executing, cannot be used with cronperiodic (
bool) – should this task continue to repeat? cannot be used with croncron (
str|None) – a crontab expression to schedule Verb execution_caller – explicit caller override; falls back to
context.caller. Used bytransaction.on_commitcallbacks that fire after theContextManagerhas exited and cleared the contextvars._player – explicit player override; falls back to
context.player. Same reason as_caller.args – positional arguments for the Verb, if any
kwargs – keyword arguments for the Verb, if any
- Returns:
a
PeriodicTaskinstance or None if the task is a one-shot- Return type:
Optional[
PeriodicTask]
- moo.sdk.cancel_scheduled_task(pk)
Delete a
django_celery_beat.PeriodicTaskrow by primary key.Used by daemon lifecycle verbs (
$daemon.disable,$daemon.recycle) to remove the PT created byinvoke()(periodic=True). Idempotent: returnsFalseif no PT with that pk exists.- Parameters:
pk (
int) – thePeriodicTask.pkreturned byinvoke()- Return type:
bool- Returns:
Trueif a row was deleted,Falseif not found- Raises:
UserError – if the current caller is not a wizard
- moo.sdk.get_scheduled_task_info(pk)
Look up runtime stats for a scheduled task created by
invoke().Returns
Noneif noPeriodicTaskexists with the given pk (useful for orphan-pointer detection on daemon Objects).- Parameters:
pk (
int) – thePeriodicTask.pkto inspect- Return type:
dict|None- Returns:
dict with
enabled,last_run_at,total_run_count,interval_seconds(orNone), andtask(the Celery task name) — orNoneif not found.- Raises:
UserError – if the current caller is not a wizard
- moo.sdk.task_time_low(threshold=0.5)
Return
Trueif the current task’s remaining time is at or below threshold seconds.Always returns
Falsewhen there is no task-time limit (e.g. in tests or interactive shells without a configured limit).- Parameters:
threshold – seconds remaining before considering time low (default 0.5)
- Return type:
bool
- moo.sdk.schedule_continuation(remaining_items, verb, msg=None)
Schedule a continuation task carrying the PKs of remaining_items and notify the current player.
Intended for use inside long-running verbs that iterate over many objects. The continuation verb (e.g.
audit_batch,reload_batch) receivesargs[0]as the list of PKs and dispatches onverb_name.Usage:
for i, item in enumerate(items): if task_time_low(): schedule_continuation(items[i:], this.get_verb("audit_batch")) return # ... process item
- Parameters:
remaining_items – iterable of Objects (or any model with
.pk)verb – Verb instance to invoke for the continuation
msg – optional override for the progress message shown to the player
- moo.sdk.set_task_perms(who)
Set the task permissions to those of who for the duration of the with-block. :type who: :param who: the Object whose permissions to assume :type who: Object
- moo.sdk.moo_eval(code_string)
Evaluate arbitrary Python code in the RestrictedPython sandbox.
The code runs with the same environment as verb code, with standard verb variables (this, _, context) automatically available.
- Parameters:
code_string (
str) – Python code to evaluate- Returns:
The result of the evaluation
- moo.sdk.invoked_verb_name(default=None)
Return the verb name as the player typed it (lowercased), or
defaultwhen there is no active parser context.Verbs called via
moo.sdk.invoke(), async callbacks, or test harnesses have no parser; pass the sandbox-injectedverb_nameasdefaultto fall back to the verb’s defined name.- Return type:
str|None
Output and full-screen UIs
- moo.sdk.write(obj, message)
Send an asynchronous message to the user.
- Parameters:
obj (Object) – the Object to write to
message (Any) – any pickle-able object
- moo.sdk.open_editor(obj, initial_content, callback_verb, *args, content_type='text', title=None)
Request the connected SSH client to open a full-screen text editor. When the user saves, the edited text is passed to callback_verb as args[0], followed by any extra positional arguments supplied here. If the user cancels, the callback is not invoked.
- Parameters:
obj – the player Object whose client should open the editor
initial_content (
str) – text to pre-populate the editor buffercallback_verb – Verb to invoke with the edited text as args[0]
args – additional arguments forwarded to the callback verb as args[1:]
content_type (
str) – “python”, “json”, or “text” (default); controls syntax highlighting
- moo.sdk.open_paginator(obj, content, content_type='text')
Request the connected SSH client to open a full-screen read-only paginator. The user can scroll through the content and press Q to quit.
In raw-mode sessions (MUD clients, line-oriented terminals) the SSH server intercepts the paginator event and writes the content directly to the terminal instead of opening the interactive UI.
- Parameters:
obj – the player Object whose client should open the paginator
content (
str) – text to displaycontent_type (
str) – “python”, “json”, or “text” (default); controls syntax highlighting
- moo.sdk.can_open_editor()
True if the current player’s client can display an editor.
Either the player is in
richmode (prompt_toolkit TUI), or their client advertises support for the GMCPEditorpackage viaCore.Supports.Set(the djangomoo Mudlet bridge does this; the server hands the edit off to the client’s preferred local editor over GMCP). Verbs that open the editor should gate on this rather thanget_client_mode() == "raw"so bridge-equipped MUD clients are not forced onto the inlinewith "..."fallback.- Return type:
bool
Session settings and client capabilities
- moo.sdk.get_client_mode()
Return the current player’s shell mode.
Returns
"rich"(prompt_toolkit TUI, the default) or"raw"(line- based I/O for traditional MUD clients that cannot handle cursor control).Verbs use this to short-circuit editor-opening code paths in raw mode and suggest the inline
@edit ... with "..."form instead. Most verbs should callcan_open_editor()instead, which also returnsTruefor raw-mode clients that advertise GMCP Editor support (e.g. the djangomoo Mudlet bridge).- Return type:
str
- moo.sdk.get_wrap_column()
Return the effective wrap column for the current player.
Reads the player’s
wrap_columnproperty. If it is"auto"(or the property is not set), returns theterminal_widthsession setting, falling back to 80 if the terminal width is not known.
- moo.sdk.get_session_setting(key, default=None)
Get a session-specific output setting for the current player.
Session settings are stored per-user and cleared on disconnect. Used by PREFIX, SUFFIX, OUTPUTPREFIX/SUFFIX, and the
a11yverb.Checks the in-process
_session_settingsdict first (authoritative in the SSH server process and in tests), then falls back to the Django cache so Celery workers — which run in a separate process — can also read the value.- Parameters:
key – setting name (‘output_prefix’, ‘output_suffix’, ‘quiet_mode’, ‘color_system’)
default – value to return if setting is not found
- Returns:
setting value or default
- moo.sdk.set_session_setting(key, value)
Set a session-specific output setting for the current player.
Session settings are stored per-user and cleared on disconnect. Used by PREFIX, SUFFIX, OUTPUTPREFIX/SUFFIX, and the
a11yverb.Writes to the Django cache (accessible cross-process from Celery workers) and also publishes a
session_settingevent to the player’s Kombu queue so the SSH server’sprocess_messages()loop can update its own registry.- Parameters:
key – setting name (‘output_prefix’, ‘output_suffix’, ‘quiet_mode’, ‘color_system’)
value – setting value
Out-of-band MUD-client protocols
- moo.sdk.send_gmcp(obj, module, data=None)
Send a GMCP event to
obj’s SSH channel.GMCP (Generic MUD Communication Protocol) is the canonical OOB channel for structured MUD events. Clients that negotiated GMCP receive
IAC SB GMCP <module> <json> IAC SE; clients that did not see it as zero bytes on the wire (the SSH server skips the emit if the capability flag is false).Example:
send_gmcp(player, "Char.Vitals", {"hp": 50, "maxhp": 100}) send_gmcp(player, "Room.Info", {"num": 12, "name": "A dim hall"}) send_gmcp(player, "Core.Ping") # no payload
- Parameters:
obj – the Object (player avatar) to send the GMCP event to
module (
str) – GMCP module/package name, e.g."Char.Vitals"data – JSON-serializable value, or
Nonefor an empty event
- moo.sdk.play_sound(obj, name, volume=100, priority=10)
Play a sound on
obj’s client.Prefers GMCP
Client.Media.Playwhen the client negotiated GMCP; falls back to the inline MSP!!SOUND(...)marker if the client negotiated MSP; no-ops otherwise.DjangoMOO does not bundle any sound assets. Sound pack authors are expected to provide filenames that their client-side pack can resolve.
- Parameters:
obj – the player to play the sound on
name (
str) – filename (client-resolvable), e.g."door.wav"volume (
int) – 0–100priority (
int) – higher numbers preempt lower-priority sounds
- moo.sdk.room_info_payload(room)
Build the IRE-style GMCP
Room.Infopayload forroom.Returns
{"num", "name", "exits"}with values stringified per the Achaea/Aardwolf/Mudlet-generic-mapper convention. Exit keys are normalized to short codes (n,ne,u, …); custom-named exits ("ladder","portal") round-trip unchanged so they still appear on the client.DjangoMOO names cardinal exits
"<direction> from <room>"— e.g."east from grand foyer"— to keep them globally unique. We check the exit’s exact name, then its first word, then its aliases for a direction match before falling back to the raw name.- Parameters:
room – an Object representing a room
- Return type:
dict- Returns:
a dict suitable for
send_gmcp(player, "Room.Info", payload)
Server administration
- moo.sdk.boot_player(obj)
Disconnect the given player from the MOO server.
Publishes a
disconnectevent to the player’s Kombu message queue, which the SSH server’sprocess_messages()loop picks up and exits cleanly.Permission: the caller must be the player being booted, or a wizard.
- Parameters:
obj – the player Object to disconnect
- moo.sdk.server_info()
Return a dict with server version and process statistics.
Keys:
version,python,pid,memory_mb(may beNoneon platforms whereresourceis unavailable).- Return type:
dict
Mail Functions
- moo.sdk.send_message(sender, recipients, subject, body)
Create a message and deliver it to all recipients.
- Parameters:
sender – the sending Object (must be a player)
recipients (
list) – list of recipient Objects (must be players)subject (
str) – message subject linebody (
str) – message body text
- Returns:
plain message value for the created message
- moo.sdk.get_mailbox(player, include_deleted=False)
Return player’s received messages as plain mailbox values, newest first.
- Parameters:
player – the recipient Object
include_deleted (
bool) – if True, include soft-deleted messages
- Return type:
list- Returns:
list of MailboxEntry values
- moo.sdk.get_message(player, n)
Return the nth message (1-based) in the player’s non-deleted mailbox, or None.
- Parameters:
player – the recipient Object
n (
int) – 1-based message index
- Returns:
MailboxEntry or None
- moo.sdk.mark_read(player, n)
Mark message n as read. Returns True if successful, False if n is out of range.
- Return type:
bool
- moo.sdk.delete_message(player, n)
Soft-delete message n. Returns True if successful, False if n is out of range.
- Return type:
bool
- moo.sdk.undelete_message(player, n)
Restore the nth deleted message (1-based among deleted-only list). Returns True if successful, False if n is out of range.
- Return type:
bool
- moo.sdk.count_unread(player)
Return the count of unread, non-deleted messages for the player.
- Return type:
int
- moo.sdk.get_mail_stats(player)
Return a dict with
total,unread, anddeletedmessage counts for the player. All counts are computed in two queries.- Return type:
dict
Accounts and identity
The Player row is the durable account behind an
avatar; these resolve between an avatar and its account.
- moo.sdk.account_for(avatar_obj)
Return the
Playeraccount for an avatar Object, orNone.- Parameters:
avatar_obj – a player avatar Object
- Returns:
the owning Player account, or None if the object is not an avatar
- moo.sdk.avatars_of(account)
Return the list of avatar Objects an account owns.
Today an account carries a single avatar; this returns it as a one-element list (empty if the avatar has been recycled) so callers are already shaped for the later multi-avatar model.
- Parameters:
account – a Player account
- Returns:
list of avatar Objects
- moo.sdk.account_id_for(avatar_obj)
Return the stable account id for an avatar, or
None.The cheap form used on the provenance hot path (E): one indexed lookup, no avatar materialization beyond the id.
- Parameters:
avatar_obj – a player avatar Object
- Returns:
the account pk, or None
- moo.sdk.current_account()
Return the account for the current
context.player, orNone.
Provenance and tagged output
Every published message carries a server-computed provenance triple, recorded
always; sanctioned output forms carry a structural kind tag the client
renders so a user line cannot present as a system line or another actor.
- moo.sdk.notify(obj, message, kind='text')
Send a structurally-tagged message to a player.
The tagged-output counterpart to
moo.sdk.write(): thekindis applied server-side and carried in the envelope so it cannot be spoofed by embedding markup inmessage. Likewrite, this is a privileged primitive (wizard-owned verbs only); the sanctionedsay/emote/ system verbs route through it. Thesystemkind additionally requires a wizard initiator, so an ordinary user’s verb cannot wear it.- Parameters:
obj – the player avatar Object to write to
message – the payload (typically a string)
kind – one of
OUTPUT_KINDS
- Raises:
UserError – on a bad kind, a non-wizard caller, or a non-wizard initiator attempting a privileged kind
- moo.sdk.current_provenance()
Return the always-on provenance triple for the running task.
See
moo.core.current_provenance(). Re-exported here so verb authors import it frommoo.sdklike the rest of the API.
- moo.sdk.capture_provenance_stack()
Return the full caller stack as a list of provenance frames.
The expensive form, for a report or audit only — the hot path uses the single-frame
current_provenance(). Each frame is{"origin", "this", "verb", "owner"}with object pks.- Returns:
list of frame dicts, outermost first
- moo.sdk.resolve_provenance_account(provenance)
Resolve a provenance triple’s
ownerobject to its account id.The report/audit-time step that turns the cheap object-pk record into an account-keyed one (G), so moderation keys to the human, not a discardable avatar.
- Parameters:
provenance – a triple from
current_provenance(), orNone- Returns:
the owning Player account id, or
None
Flood limiting
- moo.sdk.broadcast_allowed(account_id)
Charge one broadcast line to
account_idand report whether it is allowed.Returns
True(and does not charge) when the limit is disabled or no account is known. Otherwise increments the account’s fixed-window counter and returnsFalseonce the budget is exceeded.- Parameters:
account_id – the initiating Player account id
- Return type:
bool- Returns:
True if the line may be sent, False if the account is over budget
- moo.sdk.broadcast_limit()
The effective per-window broadcast line budget (0 disables).
- Return type:
int
- moo.sdk.broadcast_window()
The effective fixed-window length in seconds.
- Return type:
int
Moderation: suspend and ban
Staff-gated sanctions keyed to the durable account; neither can target staff.
- moo.sdk.suspend(account, duration=None, hours=None, reason='')
Suspend an account, blocking login until the deadline elapses.
- Parameters:
account – the Player account to suspend
duration – a
datetime.timedelta, orNonefor open-endedhours – convenience for verb authors (who cannot import
datetimein the sandbox); converted to aduration. Ignored ifdurationis given.reason – optional free-text reason (recorded in the audit log)
- Raises:
PermissionError – if the caller is not staff
UserError – if the target is missing or is a staff account
- moo.sdk.unsuspend(account, reason='')
Lift a suspension, returning the account to active.
- Parameters:
account – the Player account to reinstate
- Raises:
PermissionError – if the caller is not staff
- moo.sdk.ban(account, reason='')
Ban an account and blacklist its durable identity / last site.
The status flag stops this account; the
Blacklistrow stops the same human from re-registering under a fresh account.- Parameters:
account – the Player account to ban
- Raises:
PermissionError – if the caller is not staff
UserError – if the target is missing or is a staff account
- moo.sdk.is_blacklisted(identity, site=None)
True if a durable identity is banned (globally, or on the given site).
- Parameters:
identity – the durable identifier to check
site – optional Site to scope the check to
- Return type:
bool
- moo.sdk.account_login_blocked(account)
Return a reason string if this account may not log in, else
None.The single chokepoint the SSH login path consults — composes the account’s own status (suspended/banned) with the identity blacklist.
- Parameters:
account – the Player account attempting to log in
Onboarding: guests and registration
- moo.sdk.provision_guest(name, site=None, user=None)
Create a non-persistent guest avatar + account.
The avatar is parented to
$guestand given its ownownership_quotaof 0 somoo.sdk.create()refuses (the class default is not enough —createreads the quota withrecurse=False).- Parameters:
name – display name for the guest avatar
site – the Site to provision on (defaults to the active site)
user – an optional Django User to tie the guest to (usually
None)
- Returns:
(account, avatar)
- moo.sdk.remove_guest(account)
Reap a guest account and its avatar (the non-persistence side).
No-op for a non-guest account, so it is safe to call unconditionally on disconnect.
- Parameters:
account – the guest Player account to remove
- Returns:
True if a guest was removed
- moo.sdk.is_guest(account)
True if an account is in the guest tier.
- Return type:
bool
- moo.sdk.register(account, identity)
Bind a durable identity to an account and promote it out of guest.
Runs the pluggable verifier, refuses a banned identity (H), records the identity, and lifts a guest account to active.
- Parameters:
account – the Player account to register
identity – the candidate durable identifier
- Raises:
UserError – on a missing account, a rejected identity, a banned one, or an identity already claimed on this site
- moo.sdk.require_registered(account)
Raise unless an account has bound a durable identity (the build gate).
Build-granting code calls this so build rights require accountability.
- Parameters:
account – the Player account to check
- Raises:
UserError – if the account is unregistered
Audit log
- moo.sdk.record_action(action, target=None, detail='', actor=None, force=False)
Append one consequential action to the audit log.
- Parameters:
action – one of
AuditLog’s action constantstarget – the affected Object (or
None); recorded by pk and a name snapshot so the row survives the target’s deletiondetail – optional free-text / serialized context
actor – the acting Player account; defaults to the current account
force – record even when no human actor is resolvable (used by staff-initiated sanctions that must always be logged)
- Returns:
the created AuditLog row, or
Noneif skipped
- moo.sdk.query_audit(actor=None, action=None, target=None, limit=50)
Return recent audit rows, most recent first (staff-only at the verb layer).
- Parameters:
actor – filter to a Player account
action – filter to one action kind
target – filter to an affected Object (by pk)
limit – maximum rows to return
- Returns:
list of AuditLog rows
Non-destructive recovery
@recycle is now a reversible soft-recycle; @destroy is the permanent
delete. Soft-recycled objects are hidden from the site-scoped manager but keep
their id and inbound references.
- moo.sdk.soft_recycle(obj)
Soft-delete an object: hide it, but keep its id and inbound refs.
Refunds the owner’s quota immediately (so the builder can build again) and moves the object out of the world. Idempotent.
- Parameters:
obj – the Object to recycle
- Returns:
the recycled Object
- moo.sdk.restore(obj, location=None)
Restore a soft-recycled object, re-consuming a quota slot.
- Parameters:
obj – the recycled Object
location – where to place it (defaults to the owner’s location)
- Returns:
the restored Object
- moo.sdk.destroy(obj)
Hard-delete an object permanently (the irreversible path).
- Parameters:
obj – the Object to destroy
- moo.sdk.get_recycled(owner=None)
List soft-recycled objects (optionally for one owner) for recovery.
Uses
global_objectsbecause the site-scoped default manager hides recycled rows by design.- Parameters:
owner – optional owner Object to filter by
- Returns:
list of recycled Objects
- moo.sdk.sweep_recycled(older_than_days=30)
Hard-delete objects left recycled beyond the retention window.
The reaper’s final step. Returns the number purged.
- Parameters:
older_than_days – retention window in days
- Returns:
count of objects hard-deleted
Escape guarantee and connectivity
- moo.sdk.guaranteed_moveto(obj, dest)
Move
objtodest, bypassing the destination’saccept/locks.The un-trappable panic move (used by
home): even a misconfigured or hostile destination cannot refuse it.enterfunc/exitfuncstill run.- Parameters:
obj – the Object to move (typically a player)
dest – the destination Object
- Returns:
the moved Object
- moo.sdk.send_home(player)
Send a player home, guaranteed.
Tries the player’s
home(or$player_startif unset) and forces the move so it cannot be blocked. This is the engine-level escape thehomeverb delegates to.- Parameters:
player – the player Object
- Returns:
the destination the player landed in
- moo.sdk.check_room_connectivity(room)
Report whether a room is a potential trap.
A build-completion guard: flags a room with no way out, and any exit whose destination has no exit leading back (a one-way trip).
- Parameters:
room – the room Object to check
- Returns:
{"has_exit": bool, "one_way_exits": [names], "issues": [str]}
Indexed external keys
- moo.sdk.resolve_by_key(namespace, key)
Resolve an Object by its indexed external key.
O(1) via the unique
(namespace, key)index — the fast path for data-generated worlds that resolve by a stable external id rather than by a fullProperty.valuescan.- Parameters:
namespace – the key namespace (e.g.
"zone_slug")key – the external key value
- Returns:
the mapped Object, or
None
- moo.sdk.get_or_create_by_key(namespace, key, **kwargs)
Idempotently resolve-or-create an Object keyed by an external id.
The common bootstrap pattern made fast and re-runnable: a second run with the same
(namespace, key)returns the existing Object in one indexed query, never a duplicate. On first sight it creates the Object (via the standardcreate(), so quota/ownership/initializeall apply) and records the mapping.- Parameters:
namespace – the key namespace
key – the external key value
name – the Object name to create (defaults to
key)kwargs – forwarded to
create()(parents,owner, …)
- Returns:
(object, created)