issue #2243 -- prefer f-strings over %-interpolation

edited docs to prefer f-strings, then str.format(), and remove %-interpolation

additional ad-hoc documentation fixes, as opportunities seen:
- replace Built-In Function (BIF) "min" variable with "mins"
- prefer BIF str(var) over "%s" % var
- reformat some code examples to clarify multiple args passed to functions
- change some single-quote strings to double-quotes for consistency
- fix mismatched parens

misc edits:
- add .vscode/ to gitignore
This commit is contained in:
Dimitri 2021-10-12 12:13:42 -06:00
parent f45051050e
commit 851ca30be5
30 changed files with 207 additions and 193 deletions

View file

@ -91,13 +91,12 @@ Below is a version of the example file found in `evennia/contrib/tutorial_exampl
table = create_object(Object, key="Blue Table", location=limbo) table = create_object(Object, key="Blue Table", location=limbo)
chair = create_object(Object, key="Blue Chair", location=limbo) chair = create_object(Object, key="Blue Chair", location=limbo)
string = "A %s and %s were created." string = f"A {table} and {chair} were created."
if DEBUG: if DEBUG:
table.delete() table.delete()
chair.delete() chair.delete()
string += " Since debug was active, " \ string += " Since debug was active, they were deleted again."
"they were deleted again." caller.msg(string)
caller.msg(string % (table, chair))
``` ```
This uses Evennia's Python API to create three objects in sequence. This uses Evennia's Python API to create three objects in sequence.

View file

@ -65,7 +65,7 @@ Here is a minimalistic command with no custom parsing:
def func(self): def func(self):
# echo the caller's input back to the caller # echo the caller's input back to the caller
self.caller.msg("Echo: {}".format(self.args) self.caller.msg(f"Echo: {self.args}")
``` ```
@ -548,7 +548,7 @@ class CmdTestID(Command):
self.xval = 0 self.xval = 0
self.xval += 1 self.xval += 1
self.caller.msg("Command memory ID: {} (xval={})".format(id(self), self.xval)) self.caller.msg(f"Command memory ID: {id(self)} (xval={self.xval})")
``` ```
@ -651,7 +651,7 @@ thus do so asynchronously, using callbacks.
```python ```python
# in command class func() # in command class func()
def callback(ret, caller): def callback(ret, caller):
caller.msg("Returned is %s" % ret) caller.msg(f"Returned is {ret}")
deferred = self.execute_command("longrunning") deferred = self.execute_command("longrunning")
deferred.addCallback(callback, self.caller) deferred.addCallback(callback, self.caller)
``` ```

View file

@ -58,7 +58,7 @@ class CmdSetTestAttr(Command):
def quit(caller): def quit(caller):
"Since we define it, we must handle messages" "Since we define it, we must handle messages"
caller.msg("Editor exited") caller.msg("Editor exited")
key = "%s/test" % self.caller key = f"{self.caller}/test"
# launch the editor # launch the editor
eveditor.EvEditor(self.caller, eveditor.EvEditor(self.caller,
loadfunc=load, savefunc=save, quitfunc=quit, loadfunc=load, savefunc=save, quitfunc=quit,
@ -100,7 +100,7 @@ class CmdSetTestAttr(Command):
key = "settestattr" key = "settestattr"
def func(self): def func(self):
"Set up the callbacks and launch the editor" "Set up the callbacks and launch the editor"
key = "%s/test" % self.caller key = f"{self.caller}/test"
# launch the editor # launch the editor
eveditor.EvEditor(self.caller, eveditor.EvEditor(self.caller,
loadfunc=load, savefunc=save, quitfunc=quit, loadfunc=load, savefunc=save, quitfunc=quit,

View file

@ -531,10 +531,10 @@ def _set_attribute(caller, raw_string, **kwargs):
def node_background(caller): def node_background(caller):
text = \ text = \
""" f"""
{} experienced a traumatic event {caller.key} experienced a traumatic event
in their childhood. What was it? in their childhood. What was it?
""".format(caller.key} """
options = ({"key": "death", options = ({"key": "death",
"desc": "A violent death in the family", "desc": "A violent death in the family",
@ -580,7 +580,7 @@ def _set_name(caller, raw_string, **kwargs):
# a blank input either means OK or Abort # a blank input either means OK or Abort
if prev_entry: if prev_entry:
caller.key = prev_entry caller.key = prev_entry
caller.msg("Set name to {}.".format(prev_entry)) caller.msg(f"Set name to {prev_entry}.")
return "node_background" return "node_background"
else: else:
caller.msg("Aborted.") caller.msg("Aborted.")
@ -644,7 +644,7 @@ def _set_name(caller, raw_string, **kwargs):
caller.ndb._menutree.charactersheet = {} caller.ndb._menutree.charactersheet = {}
caller.ndb._menutree.charactersheet['name'] = raw_string caller.ndb._menutree.charactersheet['name'] = raw_string
caller.msg("You set your name to {}".format(raw_string) caller.msg(f"You set your name to {raw_string}")
return "background" return "background"
def node_set_name(caller): def node_set_name(caller):
@ -658,7 +658,7 @@ def node_set_name(caller):
def node_view_sheet(caller): def node_view_sheet(caller):
text = "Character sheet:\n {}".format(self.ndb._menutree.charactersheet) text = f"Character sheet:\n {self.ndb._menutree.charactersheet}"
options = ({"key": "Accept", options = ({"key": "Accept",
"goto": "finish_chargen"}, "goto": "finish_chargen"},

View file

@ -190,7 +190,7 @@ The above could for example be used in a lock function like this:
```python ```python
# we have `obj` and `owner_object` from before # we have `obj` and `owner_object` from before
obj.locks.add("edit: id(%i)" % owner_object.id) obj.locks.add(f"edit: id({owner_object.id})")
``` ```
We could check if the "edit" lock is passed with something like this: We could check if the "edit" lock is passed with something like this:

View file

@ -50,9 +50,7 @@ def _monitor_callback(fieldname="", obj=None, **kwargs):
new_value = getattr(obj, fieldname) new_value = getattr(obj, fieldname)
else: # an attribute else: # an attribute
new_value = obj.attributes.get(fieldname) new_value = obj.attributes.get(fieldname)
obj.msg(f"{obj.key}.{fieldname} changed to '{new_value}'.")
obj.msg("%s.%s changed to '%s'." % \
(obj.key, fieldname, new_value))
# (we could add _some_other_monitor_callback here too) # (we could add _some_other_monitor_callback here too)

View file

@ -176,7 +176,7 @@ def red(*args, **kwargs):
""" """
if not args or len(args) > 1: if not args or len(args) > 1:
raise ValueError("Must have one argument, the text to color red!") raise ValueError("Must have one argument, the text to color red!")
return "|r{}|n".format(args[0]) return f"|r{args[0]}|n"
``` ```
> Note that we must make sure to validate input and raise `ValueError` if that fails. Also, it is > Note that we must make sure to validate input and raise `ValueError` if that fails. Also, it is

View file

@ -106,10 +106,10 @@ An example of making an asynchronous call from inside a [Command](../Components/
return final_value return final_value
def at_return_function(r): def at_return_function(r):
self.caller.msg("The final value is %s" % r) self.caller.msg(f"The final value is {r}")
def at_err_function(e): def at_err_function(e):
self.caller.msg("There was an error: %s" % e) self.caller.msg(f"There was an error: {e}")
# do the async call, setting all callbacks # do the async call, setting all callbacks
utils.run_async(long_running_function, at_return=at_return_function, utils.run_async(long_running_function, at_return=at_return_function,

View file

@ -79,7 +79,7 @@ This is how it looks:
if not MYPROC_ENABLED: if not MYPROC_ENABLED:
return return
# output to list this with the other services at startup # output to list this with the other services at startup
print(" myproc: %s" % MY_PORT) print(f" myproc: {MY_PORT}")
# some setup (simple example) # some setup (simple example)
factory = MyOwnFactory() factory = MyOwnFactory()

View file

@ -145,7 +145,7 @@ Here are some examples
```python ```python
msg("Hello!") # using the 'text' outputfunc msg("Hello!") # using the 'text' outputfunc
msg(prompt="HP:%i, SP: %i, MP: %i" % (HP, SP, MP)) msg(prompt=f"HP: {HP}, SP: {SP}, MP: {MP}")
msg(mycommand=((1,2,3,4), {"foo": "bar"}) msg(mycommand=((1,2,3,4), {"foo": "bar"})
``` ```

View file

@ -140,7 +140,7 @@ This is important, in order to know what variables we can use in our callback ou
write a single line to be sure our callback is called when we expect it to: write a single line to be sure our callback is called when we expect it to:
```python ```python
character.msg("You just said {}.".format(message)) character.msg(f"You just said {message}.")
``` ```
You can paste this line in-game, then type the `:wq` command to exit the editor and save your You can paste this line in-game, then type the `:wq` command to exit the editor and save your

View file

@ -73,8 +73,8 @@ class EditCmd(Command):
if obj.typename == "Room": if obj.typename == "Room":
Menu = RoomBuildingMenu Menu = RoomBuildingMenu
else: else:
self.msg("|rThe object {} cannot be obj_name = obj.get_display_name(self.caller)
edited.|n".format(obj.get_display_name(self.caller))) self.msg(f"|rThe object {obj_name} cannot be edited.|n")
return return
menu = Menu(self.caller, obj) menu = Menu(self.caller, obj)
@ -475,8 +475,7 @@ Excessive spaces will be removed from the left for each line automatically. We
information between braces... sometimes using double braces. What might be a bit odd: information between braces... sometimes using double braces. What might be a bit odd:
- `{back}` is a direct format argument we'll use (see the `.format` specifiers). - `{back}` is a direct format argument we'll use (see the `.format` specifiers).
- `{{obj...}} refers to the object being edited. We use two braces, because `.format` will remove - `{{obj...}}` refers to the object being edited. We use two braces, because `.format` will remove them.
them.
In `glance`, we also use `{obj.key}` to indicate we want to show the room's key. In `glance`, we also use `{obj.key}` to indicate we want to show the room's key.
@ -549,7 +548,7 @@ def glance_exits(room):
if room.exits: if room.exits:
glance = "" glance = ""
for exit in room.exits: for exit in room.exits:
glance += "\n |y{exit}|n".format(exit=exit.key) glance += f"\n |y{exit.key}|n"
return glance return glance
@ -648,7 +647,7 @@ def glance_exits(room):
if room.exits: if room.exits:
glance = "" glance = ""
for exit in room.exits: for exit in room.exits:
glance += "\n |y{exit}|n".format(exit=exit.key) glance += f"\n |y{exit.key}|n"
return glance return glance
@ -662,12 +661,13 @@ def text_exits(caller, room):
text += "\n\nExisting exits:" text += "\n\nExisting exits:"
if room.exits: if room.exits:
for exit in room.exits: for exit in room.exits:
text += "\n |y@e {exit}|n".format(exit=exit.key) text += f"\n |y@e {exit.key}|n"
if exit.aliases.all(): if exit.aliases.all():
text += " (|y{aliases}|n)".format(aliases="|n, |y".join( text += " (|y{aliases}|n)".format(aliases="|n, |y".join(
alias for alias in exit.aliases.all())) alias for alias in exit.aliases.all()
))
if exit.destination: if exit.destination:
text += " toward {destination}".format(destination=exit.get_display_name(caller)) text += f" toward {exit.get_display_name(caller)}"
else: else:
text += "\n\n |gNo exit has yet been defined.|n" text += "\n\n |gNo exit has yet been defined.|n"
@ -856,21 +856,19 @@ class RoomBuildingMenu(BuildingMenu):
Current title: |c{{obj.key}}|n Current title: |c{{obj.key}}|n
""".format(back="|n or |y".join(self.keys_go_back))) """.format(back="|n or |y".join(self.keys_go_back)))
self.add_choice_edit("description", "d") self.add_choice_edit("description", "d")
self.add_choice("exits", "e", glance=glance_exits, text=text_exits, self.add_choice("exits", "e", glance=glance_exits, text=text_exits, on_nomatch=nomatch_exits)
on_nomatch=nomatch_exits)
# Exit sub-menu # Exit sub-menu
self.add_choice("exit", "e.*", text=text_single_exit, on_nomatch=nomatch_single_exit) self.add_choice("exit", "e.*", text=text_single_exit, on_nomatch=nomatch_single_exit)
# Menu functions # Menu functions
def glance_exits(room): def glance_exits(room):
"""Show the room exits.""" """Show the room exits."""
if room.exits: if room.exits:
glance = "" glance = ""
for exit in room.exits: for exit in room.exits:
glance += "\n |y{exit}|n".format(exit=exit.key) glance += f"\n |y{exit.key}|n"
return glance return glance
@ -884,12 +882,13 @@ def text_exits(caller, room):
text += "\n\nExisting exits:" text += "\n\nExisting exits:"
if room.exits: if room.exits:
for exit in room.exits: for exit in room.exits:
text += "\n |y@e {exit}|n".format(exit=exit.key) text += f"\n |y@e {exit.key}|n"
if exit.aliases.all(): if exit.aliases.all():
text += " (|y{aliases}|n)".format(aliases="|n, |y".join( text += " (|y{aliases}|n)".format(aliases="|n, |y".join(
alias for alias in exit.aliases.all())) alias for alias in exit.aliases.all()
))
if exit.destination: if exit.destination:
text += " toward {destination}".format(destination=exit.get_display_name(caller)) text += f" toward {exit.get_display_name(caller)}"
else: else:
text += "\n\n |gNo exit has yet been defined.|n" text += "\n\n |gNo exit has yet been defined.|n"
@ -905,7 +904,7 @@ def nomatch_exits(menu, caller, room, string):
return return
# Open a sub-menu, using nested keys # Open a sub-menu, using nested keys
caller.msg("Editing: {}".format(exit.key)) caller.msg(f"Editing: {exit.key}")
menu.move(exit) menu.move(exit)
return False return False
@ -916,13 +915,13 @@ def text_single_exit(menu, caller):
if exit is None: if exit is None:
return "" return ""
return """ return f"""
Exit {exit}: Exit {exit.key}:
Enter the exit key to change it, or |y@|n to go back. Enter the exit key to change it, or |y@|n to go back.
New exit key: New exit key:
""".format(exit=exit.key) """
def nomatch_single_exit(menu, caller, room, string): def nomatch_single_exit(menu, caller, room, string):
"""The user entered something in the exit sub-menu. Replace the exit key.""" """The user entered something in the exit sub-menu. Replace the exit key."""
@ -1012,7 +1011,7 @@ def glance_exits(room):
if room.exits: if room.exits:
glance = "" glance = ""
for exit in room.exits: for exit in room.exits:
glance += "\n |y{exit}|n".format(exit=exit.key) glance += f"\n |y{exit.key}|n"
return glance return glance
@ -1026,12 +1025,13 @@ def text_exits(caller, room):
text += "\n\nExisting exits:" text += "\n\nExisting exits:"
if room.exits: if room.exits:
for exit in room.exits: for exit in room.exits:
text += "\n |y@e {exit}|n".format(exit=exit.key) text += f"\n |y@e {exit.key}|n"
if exit.aliases.all(): if exit.aliases.all():
text += " (|y{aliases}|n)".format(aliases="|n, |y".join( text += " (|y{aliases}|n)".format(aliases="|n, |y".join(
alias for alias in exit.aliases.all())) alias for alias in exit.aliases.all()
))
if exit.destination: if exit.destination:
text += " toward {destination}".format(destination=exit.get_display_name(caller)) text += f" toward {exit.get_display_name(caller)}"
else: else:
text += "\n\n |gNo exit has yet been defined.|n" text += "\n\n |gNo exit has yet been defined.|n"
@ -1047,7 +1047,7 @@ def nomatch_exits(menu, caller, room, string):
return return
# Open a sub-menu, using nested keys # Open a sub-menu, using nested keys
caller.msg("Editing: {}".format(exit.key)) caller.msg(f"Editing: {exit.key}")
menu.open_submenu("commands.building.ExitBuildingMenu", exit, parent_keys=["e"]) menu.open_submenu("commands.building.ExitBuildingMenu", exit, parent_keys=["e"])
return False return False

View file

@ -346,7 +346,7 @@ class Room(DefaultRoom):
def return_appearance(self, looker): def return_appearance(self, looker):
# [...] # [...]
string = "%s\n" % Map(looker).show_map() string = f"{Map(looker).show_map()}\n"
# Add all the normal stuff like room description, # Add all the normal stuff like room description,
# contents, exits etc. # contents, exits etc.
string += "\n" + super().return_appearance(looker) string += "\n" + super().return_appearance(looker)

View file

@ -99,8 +99,9 @@ class CmdShoot(Command):
# we have an argument, search for target # we have an argument, search for target
target = caller.search(self.args.strip()) target = caller.search(self.args.strip())
if target: if target:
message = "BOOM! The mech fires its gun at %s" % target.key location.msg_contents(
location.msg_contents(message) f"BOOM! The mech fires its gun at {target.key}"
)
class CmdLaunch(Command): class CmdLaunch(Command):
# make your own 'launch'-command here as an exercise! # make your own 'launch'-command here as an exercise!

View file

@ -78,19 +78,18 @@ channel send. Edit `mygame/typeclasses/channels.py` (and then `@reload`):
```python ```python
# define our custom color names # define our custom color names
CHANNEL_COLORS = {'public': '|015Public|n', CHANNEL_COLORS = {"public": "|015Public|n",
'newbie': '|550N|n|551e|n|552w|n|553b|n|554i|n|555e|n', "newbie": "|550N|n|551e|n|552w|n|553b|n|554i|n|555e|n",
'staff': '|010S|n|020t|n|030a|n|040f|n|050f|n'} "staff": "|010S|n|020t|n|030a|n|040f|n|050f|n"}
# Add to the Channel class # Add to the Channel class
# ... # ...
def channel_prefix(self, msg, emit=False): def channel_prefix(self, msg, emit=False):
prefix_string = ""
if self.key in COLORS: if self.key in COLORS:
prefix_string = "[%s] " % CHANNEL_COLORS.get(self.key.lower()) p_str = CHANNEL_COLORS.get(self.key.lower())
else: else:
prefix_string = "[%s] " % self.key.capitalize() p_str = self.key.capitalize()
return prefix_string return f"[{p_str}] "
``` ```
Additional hint: To make colors easier to change from one place you could instead put the Additional hint: To make colors easier to change from one place you could instead put the
`CHANNEL_COLORS` dict in your settings file and import it as `from django.conf.settings import `CHANNEL_COLORS` dict in your settings file and import it as `from django.conf.settings import

View file

@ -82,16 +82,16 @@ class CmdEcho(default_cmds.MuxCommand):
""" """
This is called at the initial shout. This is called at the initial shout.
""" """
self.caller.msg("You shout '%s' and wait for an echo ..." % self.args) self.caller.msg(f"You shout '{self.args}' and wait for an echo ...")
# this waits non-blocking for 10 seconds, then calls self.echo # this waits non-blocking for 10 seconds, then calls self.echo
utils.delay(10, self.echo) # call echo after 10 seconds utils.delay(10, self.echo) # call echo after 10 seconds
def echo(self): def echo(self):
"Called after 10 seconds." "Called after 10 seconds."
shout = self.args shout = self.args
string = "You hear an echo: %s ... %s ... %s" self.caller.msg(
string = string % (shout.upper(), shout.capitalize(), shout.lower()) f"You hear an echo: {shout.upper()} ... {shout.capitalize()} ... {shout.lower()}"
self.caller.msg(string) )
``` ```
Import this new echo command into the default command set and reload the server. You will find that Import this new echo command into the default command set and reload the server. You will find that
@ -146,7 +146,7 @@ class CmdEcho(default_cmds.MuxCommand):
def func(self): def func(self):
"This sets off a chain of delayed calls" "This sets off a chain of delayed calls"
self.caller.msg("You shout '%s', waiting for an echo ..." % self.args) self.caller.msg(f"You shout '{self.args}', waiting for an echo ...")
# wait 2 seconds before calling self.echo1 # wait 2 seconds before calling self.echo1
utils.delay(2, self.echo1) utils.delay(2, self.echo1)
@ -154,19 +154,19 @@ class CmdEcho(default_cmds.MuxCommand):
# callback chain, started above # callback chain, started above
def echo1(self): def echo1(self):
"First echo" "First echo"
self.caller.msg("... %s" % self.args.upper()) self.caller.msg(f"... {self.args.upper()}")
# wait 2 seconds for the next one # wait 2 seconds for the next one
utils.delay(2, self.echo2) utils.delay(2, self.echo2)
def echo2(self): def echo2(self):
"Second echo" "Second echo"
self.caller.msg("... %s" % self.args.capitalize()) self.caller.msg(f"... {self.args.capitalize()}")
# wait another 2 seconds # wait another 2 seconds
utils.delay(2, callback=self.echo3) utils.delay(2, callback=self.echo3)
def echo3(self): def echo3(self):
"Last echo" "Last echo"
self.caller.msg("... %s ..." % self.args.lower()) self.caller.msg(f"... {self.args.lower()} ...")
``` ```
The above version will have the echoes arrive one after another, each separated by a two second The above version will have the echoes arrive one after another, each separated by a two second
@ -364,9 +364,9 @@ from evennia import default_cmds, utils
def echo(caller, args): def echo(caller, args):
"Called after 10 seconds." "Called after 10 seconds."
shout = args shout = args
string = "You hear an echo: %s ... %s ... %s" caller.msg(
string = string % (shout.upper(), shout.capitalize(), shout.lower()) f"You hear an echo: {shout.upper()} ... {shout.capitalize()} ... {shout.lower()}"
caller.msg(string) )
class CmdEcho(default_cmds.MuxCommand): class CmdEcho(default_cmds.MuxCommand):
""" """
@ -384,7 +384,7 @@ class CmdEcho(default_cmds.MuxCommand):
""" """
This is called at the initial shout. This is called at the initial shout.
""" """
self.caller.msg("You shout '%s' and wait for an echo ..." % self.args) self.caller.msg(f"You shout '{self.args}' and wait for an echo ...")
# this waits non-blocking for 10 seconds, then calls echo(self.caller, self.args) # this waits non-blocking for 10 seconds, then calls echo(self.caller, self.args)
utils.delay(10, echo, self.caller, self.args, persistent=True) # changes! utils.delay(10, echo, self.caller, self.args, persistent=True) # changes!

View file

@ -59,10 +59,8 @@ Here is a simple example of the prompt sent/updated from a command class:
self.caller.msg("Not a valid target!") self.caller.msg("Not a valid target!")
return return
text = "You diagnose %s as having " \ text = f"You diagnose {target} as having {hp} health, {mp} mana and {sp} stamina."
"%i health, %i mana and %i stamina." \ prompt = f"{hp} HP, {mp} MP, {sp} SP"
% (hp, mp, sp)
prompt = "%i HP, %i MP, %i SP" % (hp, mp, sp)
self.caller.msg(text, prompt=prompt) self.caller.msg(text, prompt=prompt)
``` ```
## A prompt sent with every command ## A prompt sent with every command
@ -86,9 +84,7 @@ class MuxCommand(default_cmds.MuxCommand):
def at_post_cmd(self): def at_post_cmd(self):
"called after self.func()." "called after self.func()."
caller = self.caller caller = self.caller
prompt = "%i HP, %i MP, %i SP" % (caller.db.hp, prompt = f"{caller.db.hp} HP, {caller.db.mp} MP, {caller.db.sp} SP"
caller.db.mp,
caller.db.sp)
caller.msg(prompt=prompt) caller.msg(prompt=prompt)
``` ```

View file

@ -42,7 +42,7 @@ class CmdExitError(default_cmds.MuxCommand):
auto_help = False auto_help = False
def func(self): def func(self):
"returns the error" "returns the error"
self.caller.msg("You cannot move %s." % self.key) self.caller.msg(f"You cannot move {self.key}.")
class CmdExitErrorNorth(CmdExitError): class CmdExitErrorNorth(CmdExitError):
key = "north" key = "north"

View file

@ -127,15 +127,14 @@ class Character(DefaultCharacter):
if selfaccount and selfaccount.db.is_gm: if selfaccount and selfaccount.db.is_gm:
# A GM. Show name as name(GM) # A GM. Show name as name(GM)
name = "%s(GM)" % name name = f"{name}(GM)"
if lookaccount and \ if lookaccount and \
(lookaccount.permissions.get("Developers") or lookaccount.db.is_gm): (lookaccount.permissions.get("Developers") or lookaccount.db.is_gm):
# Developers/GMs see name(#dbref) or name(GM)(#dbref) # Developers/GMs see name(#dbref) or name(GM)(#dbref)
return "%s(#%s)" % (name, self.id) name = f"{name}(#{self.id})"
else:
return name
return name
``` ```
Above, we change how the Character's name is displayed: If the account controlling this Character is Above, we change how the Character's name is displayed: If the account controlling this Character is
@ -192,10 +191,10 @@ class CmdMakeGM(default_cmds.MuxCommand):
accountlist = evennia.search_account(self.args) # returns a list accountlist = evennia.search_account(self.args) # returns a list
if not accountlist: if not accountlist:
caller.msg("Could not find account '%s'" % self.args) caller.msg(f"Could not find account '{self.args}'")
return return
elif len(accountlist) > 1: elif len(accountlist) > 1:
caller.msg("Multiple matches for '%s': %s" % (self.args, accountlist)) caller.msg(f"Multiple matches for '{self.args}': {accountlist}")
return return
else: else:
account = accountlist[0] account = accountlist[0]
@ -203,20 +202,20 @@ class CmdMakeGM(default_cmds.MuxCommand):
if self.cmdstring == "gm": if self.cmdstring == "gm":
# turn someone into a GM # turn someone into a GM
if account.permissions.get("Admins"): if account.permissions.get("Admins"):
caller.msg("Account %s is already a GM." % account) caller.msg(f"Account {account} is already a GM.")
else: else:
account.permissions.add("Admins") account.permissions.add("Admins")
caller.msg("Account %s is now a GM." % account) caller.msg(f"Account {account} is now a GM.")
account.msg("You are now a GM (changed by %s)." % caller) account.msg(f"You are now a GM (changed by {caller}).")
account.character.db.is_gm = True account.character.db.is_gm = True
else: else:
# @ungm was entered - revoke GM status from someone # @ungm was entered - revoke GM status from someone
if not account.permissions.get("Admins"): if not account.permissions.get("Admins"):
caller.msg("Account %s is not a GM." % account) caller.msg(f"Account {account} is not a GM.")
else: else:
account.permissions.remove("Admins") account.permissions.remove("Admins")
caller.msg("Account %s is no longer a GM." % account) caller.msg(f"Account {account} is no longer a GM.")
account.msg("You are no longer a GM (changed by %s)." % caller) account.msg(f"You are no longer a GM (changed by {caller}).")
del account.character.db.is_gm del account.character.db.is_gm
``` ```
@ -511,11 +510,12 @@ ALLOWED_FIELDNAMES = ALLOWED_ATTRS + \
def _validate_fieldname(caller, fieldname): def _validate_fieldname(caller, fieldname):
"Helper function to validate field names." "Helper function to validate field names."
if fieldname not in ALLOWED_FIELDNAMES: if fieldname not in ALLOWED_FIELDNAMES:
err = "Allowed field names: %s" % (", ".join(ALLOWED_FIELDNAMES)) list_of_fieldnames = ", ".join(ALLOWED_FIELDNAMES)
err = f"Allowed field names: {list_of_fieldnames}"
caller.msg(err) caller.msg(err)
return False return False
if fieldname in ALLOWED_ATTRS and not value.isdigit(): if fieldname in ALLOWED_ATTRS and not value.isdigit():
caller.msg("%s must receive a number." % fieldname) caller.msg(f"{fieldname} must receive a number.")
return False return False
return True return True
@ -570,7 +570,7 @@ class CmdSheet(MuxCommand):
else: else:
caller.chardata[fieldname] = value caller.chardata[fieldname] = value
caller.update_charsheet() caller.update_charsheet()
caller.msg("%s was set to %s." % (fieldname, value)) caller.msg(f"{fieldname} was set to {value}.")
``` ```
@ -641,13 +641,13 @@ class CmdGMsheet(MuxCommand):
caller.msg("The character sheet is already locked.") caller.msg("The character sheet is already locked.")
else: else:
character.db.sheet_locked = True character.db.sheet_locked = True
caller.msg("%s can no longer edit their character sheet." % character.key) caller.msg(f"{character.key} can no longer edit their character sheet.")
elif "unlock" in self.switches: elif "unlock" in self.switches:
if not character.db.sheet_locked: if not character.db.sheet_locked:
caller.msg("The character sheet is already unlocked.") caller.msg("The character sheet is already unlocked.")
else: else:
character.db.sheet_locked = False character.db.sheet_locked = False
caller.msg("%s can now edit their character sheet." % character.key) caller.msg(f"{character.key} can now edit their character sheet.")
if fieldname: if fieldname:
if fieldname == "name": if fieldname == "name":
@ -655,7 +655,7 @@ class CmdGMsheet(MuxCommand):
else: else:
character.db.chardata[fieldname] = value character.db.chardata[fieldname] = value
character.update_charsheet() character.update_charsheet()
caller.msg("You set %s's %s to %s." % (character.key, fieldname, value) caller.msg(f"You set {character.key}'s {fieldname} to {value}.")
else: else:
# just display # just display
caller.msg(character.db.charsheet) caller.msg(character.db.charsheet)

View file

@ -252,11 +252,10 @@ class CmdTime(Command):
def func(self): def func(self):
"""Execute the time command.""" """Execute the time command."""
# Get the absolute game time # Get the absolute game time
year, month, day, hour, min, sec = custom_gametime.custom_gametime(absolute=True) year, month, day, hour, mins, secs = custom_gametime.custom_gametime(absolute=True)
string = "We are in year {year}, day {day}, month {month}." time_string = f"We are in year {year}, day {day}, month {month}."
string += "\nIt's {hour:02}:{min:02}:{sec:02}." time_string += f"\nIt's {hour:02}:{mins:02}:{secs:02}."
self.msg(string.format(year=year, month=month, day=day, self.msg(time_string)
hour=hour, min=min, sec=sec))
``` ```
Don't forget to add it in your CharacterCmdSet to see this command: Don't forget to add it in your CharacterCmdSet to see this command:

View file

@ -87,10 +87,12 @@ class CmdInventory(MuxCommand):
table.border = False table.border = False
for item in items: for item in items:
second = item.get_mass() \ second = item.get_mass() \
if 'weight' in self.switches else item.db.desc if "weight" in self.switches else item.db.desc
table.add_row(["%s" % item.get_display_name(self.caller.sessions), table.add_row([
second and second or ""]) str(item.get_display_name(self.caller.sessions)),
string = "|wYou are carrying:\n%s" % table second and second or "",
])
string = f"|wYou are carrying:\n{table}"
self.caller.msg(string) self.caller.msg(string)
``` ```

View file

@ -86,18 +86,17 @@ def menunode_shopfront(caller):
# door! Let's remove that from our for sale list. # door! Let's remove that from our for sale list.
wares = [ware for ware in wares if ware.key.lower() != "door"] wares = [ware for ware in wares if ware.key.lower() != "door"]
text = "*** Welcome to %s! ***\n" % shopname text = f"*** Welcome to {shopname}! ***\n"
if wares: if wares:
text += " Things for sale (choose 1-%i to inspect);" \ text += f" Things for sale (choose 1-{len(wares)} to inspect); quit to exit:"
" quit to exit:" % len(wares)
else: else:
text += " There is nothing for sale; quit to exit." text += " There is nothing for sale; quit to exit."
options = [] options = []
for ware in wares: for ware in wares:
# add an option for every ware in store # add an option for every ware in store
options.append({"desc": "%s (%s gold)" % gold_val = ware.db.gold_value or 1
(ware.key, ware.db.gold_value or 1), options.append({"desc": f"{ware.key} ({gold_val} gold)",
"goto": "menunode_inspect_and_buy"}) "goto": "menunode_inspect_and_buy"})
return text, options return text, options
``` ```
@ -124,26 +123,27 @@ def menunode_inspect_and_buy(caller, raw_string):
ware = wares[iware] ware = wares[iware]
value = ware.db.gold_value or 1 value = ware.db.gold_value or 1
wealth = caller.db.gold or 0 wealth = caller.db.gold or 0
text = "You inspect %s:\n\n%s" % (ware.key, ware.db.desc) text = f"You inspect {ware.key}:\n\n{ware.db.desc}"
def buy_ware_result(caller): def buy_ware_result(caller):
"This will be executed first when choosing to buy." "This will be executed first when choosing to buy."
if wealth >= value: if wealth >= value:
rtext = "You pay %i gold and purchase %s!" % \ rtext = f"You pay {value} gold and purchase {ware.key}!"
(value, ware.key)
caller.db.gold -= value caller.db.gold -= value
ware.move_to(caller, quiet=True) ware.move_to(caller, quiet=True)
else: else:
rtext = "You cannot afford %i gold for %s!" % \ rtext = f"You cannot afford {value} gold for {ware.key}!"
(value, ware.key)
caller.msg(rtext) caller.msg(rtext)
options = ({"desc": "Buy %s for %s gold" % \ gold_val = ware.db.gold_value or 1
(ware.key, ware.db.gold_value or 1), options = ({
"goto": "menunode_shopfront", "desc": f"Buy {ware.key} for {gold_val} gold",
"exec": buy_ware_result}, "goto": "menunode_shopfront",
{"desc": "Look for something else", "exec": buy_ware_result,
"goto": "menunode_shopfront"}) }, {
"desc": "Look for something else",
"goto": "menunode_shopfront",
})
return text, options return text, options
``` ```
@ -267,7 +267,7 @@ class CmdBuildShop(Command):
key=shopname, key=shopname,
location=None) location=None)
storeroom = create_object(DefaultRoom, storeroom = create_object(DefaultRoom,
key="%s-storage" % shopname, key=f"{shopname}-storage",
location=None) location=None)
shop.db.storeroom = storeroom shop.db.storeroom = storeroom
# create a door between the two # create a door between the two
@ -281,15 +281,15 @@ class CmdBuildShop(Command):
location=storeroom, location=storeroom,
destination=shop) destination=shop)
# make a key for accessing the store room # make a key for accessing the store room
storeroom_key_name = "%s-storekey" % shopname storeroom_key_name = f"{shopname}-storekey"
storeroom_key = create_object(DefaultObject, storeroom_key = create_object(DefaultObject,
key=storeroom_key_name, key=storeroom_key_name,
location=shop) location=shop)
# only allow chars with this key to enter the store room # only allow chars with this key to enter the store room
shop_exit.locks.add("traverse:holds(%s)" % storeroom_key_name) shop_exit.locks.add(f"traverse:holds({storeroom_key_name})")
# inform the builder about progress # inform the builder about progress
self.caller.msg("The shop %s was created!" % shop) self.caller.msg(f"The shop {shop} was created!")
``` ```
Our typeclass is simple and so is our `buildshop` command. The command (which is for Builders only) Our typeclass is simple and so is our `buildshop` command. The command (which is for Builders only)

View file

@ -172,7 +172,7 @@ def add_XP(character, amount):
character.db.level += 1 character.db.level += 1
character.db.STR += 1 character.db.STR += 1
character.db.combat += 2 character.db.combat += 2
character.msg("You are now level %i!" % character.db.level) character.msg(f"You are now level {character.db.level}!")
def skill_combat(*args): def skill_combat(*args):
""" """
@ -182,24 +182,24 @@ def skill_combat(*args):
""" """
char1, char2 = args char1, char2 = args
roll1, roll2 = roll_hit(), roll_hit() roll1, roll2 = roll_hit(), roll_hit()
failtext = "You are hit by %s for %i damage!" failtext_template = "You are hit by {attacker} for {dmg} damage!"
wintext = "You hit %s for %i damage!" wintext_template = "You hit {target} for {dmg} damage!"
xp_gain = randint(1, 3) xp_gain = randint(1, 3)
if char1.db.combat >= roll1 > roll2: if char1.db.combat >= roll1 > roll2:
# char 1 hits # char 1 hits
dmg = roll_dmg() + char1.db.STR dmg = roll_dmg() + char1.db.STR
char1.msg(wintext % (char2, dmg)) char1.msg(wintext_template.format(target=char2, dmg=dmg))
add_XP(char1, xp_gain) add_XP(char1, xp_gain)
char2.msg(failtext % (char1, dmg)) char2.msg(failtext_template.format(attacker=char1, dmg=dmg))
char2.db.HP -= dmg char2.db.HP -= dmg
check_defeat(char2) check_defeat(char2)
elif char2.db.combat >= roll2 > roll1: elif char2.db.combat >= roll2 > roll1:
# char 2 hits # char 2 hits
dmg = roll_dmg() + char2.db.STR dmg = roll_dmg() + char2.db.STR
char1.msg(failtext % (char2, dmg)) char1.msg(failtext_template.format(attacker=char2, dmg=dmg))
char1.db.HP -= dmg char1.db.HP -= dmg
check_defeat(char1) check_defeat(char1)
char2.msg(wintext % (char1, dmg)) char2.msg(wintext_template.format(target=char1, dmg=dmg))
add_XP(char2, xp_gain) add_XP(char2, xp_gain)
else: else:
# a draw # a draw
@ -217,7 +217,7 @@ def roll_challenge(character1, character2, skillname):
if skillname in SKILLS: if skillname in SKILLS:
SKILLS[skillname](character1, character2) SKILLS[skillname](character1, character2)
else: else:
raise RunTimeError("Skillname %s not found." % skillname) raise RunTimeError(f"Skillname {skillname} not found.")
``` ```
These few functions implement the entirety of our simple rule system. We have a function to check These few functions implement the entirety of our simple rule system. We have a function to check

View file

@ -113,7 +113,7 @@ class CombatHandler(DefaultScript):
def at_script_creation(self): def at_script_creation(self):
"Called when script is first created" "Called when script is first created"
self.key = "combat_handler_%i" % random.randint(1, 1000) self.key = f"combat_handler_{random.randint(1, 1000)}"
self.desc = "handles combat" self.desc = "handles combat"
self.interval = 60 * 2 # two minute timeout self.interval = 60 * 2 # two minute timeout
self.start_delay = True self.start_delay = True
@ -400,57 +400,58 @@ def resolve_combat(combat_handler, actiondict):
taction, tchar, ttarget = actiondict[target.id][isub] taction, tchar, ttarget = actiondict[target.id][isub]
if action == "hit": if action == "hit":
if taction == "parry" and ttarget == char: if taction == "parry" and ttarget == char:
msg = "%s tries to hit %s, but %s parries the attack!" messages.append(
messages.append(msg % (char, tchar, tchar)) f"{char} tries to hit {tchar}, but {tchar} parries the attack!"
)
elif taction == "defend" and random.random() < 0.5: elif taction == "defend" and random.random() < 0.5:
msg = "%s defends against the attack by %s." messages.append(
messages.append(msg % (tchar, char)) f"{tchar} defends against the attack by {char}."
)
elif taction == "flee": elif taction == "flee":
msg = "%s stops %s from disengaging, with a hit!"
flee[tchar] = -2 flee[tchar] = -2
messages.append(msg % (char, tchar)) messages.append(
f"{char} stops {tchar} from disengaging, with a hit!"
)
else: else:
msg = "%s hits %s, bypassing their %s!" messages.append(
messages.append(msg % (char, tchar, taction)) f"{char} hits {tchar}, bypassing their {taction}!"
)
elif action == "parry": elif action == "parry":
if taction == "hit": if taction == "hit":
msg = "%s parries the attack by %s." messages.append(f"{char} parries the attack by {tchar}.")
messages.append(msg % (char, tchar))
elif taction == "feint": elif taction == "feint":
msg = "%s tries to parry, but %s feints and hits!" messages.append(
messages.append(msg % (char, tchar)) f"{char} tries to parry, but {tchar} feints and hits!"
)
else: else:
msg = "%s parries to no avail." messages.append(f"{char} parries to no avail.")
messages.append(msg % char)
elif action == "feint": elif action == "feint":
if taction == "parry": if taction == "parry":
msg = "%s feints past %s's parry, landing a hit!" messages.append(
messages.append(msg % (char, tchar)) f"{char} feints past {tchar}'s parry, landing a hit!"
)
elif taction == "hit": elif taction == "hit":
msg = "%s feints but is defeated by %s hit!" messages.append(f"{char} feints but is defeated by {tchar}'s hit!")
messages.append(msg % (char, tchar))
else: else:
msg = "%s feints to no avail." messages.append(f"{char} feints to no avail.")
messages.append(msg % char)
elif action == "defend": elif action == "defend":
msg = "%s defends." messages.append(f"{char} defends.")
messages.append(msg % char)
elif action == "flee": elif action == "flee":
if char in flee: if char in flee:
flee[char] += 1 flee[char] += 1
else: else:
flee[char] = 1 flee[char] = 1
msg = "%s tries to disengage (two subsequent turns needed)" messages.append(
messages.append(msg % char) f"{char} tries to disengage (two subsequent turns needed)"
)
# echo results of each subturn # echo results of each subturn
combat_handler.msg_all("\n".join(messages)) combat_handler.msg_all("\n".join(messages))
# at the end of both sub-turns, test if anyone fled # at the end of both sub-turns, test if anyone fled
msg = "%s withdraws from combat."
for (char, fleevalue) in flee.items(): for (char, fleevalue) in flee.items():
if fleevalue == 2: if fleevalue == 2:
combat_handler.msg_all(msg % char) combat_handler.msg_all(f"{char} withdraws from combat.")
combat_handler.remove_character(char) combat_handler.remove_character(char)
``` ```
@ -495,14 +496,14 @@ class CmdAttack(Command):
if target.ndb.combat_handler: if target.ndb.combat_handler:
# target is already in combat - join it # target is already in combat - join it
target.ndb.combat_handler.add_character(self.caller) target.ndb.combat_handler.add_character(self.caller)
target.ndb.combat_handler.msg_all("%s joins combat!" % self.caller) target.ndb.combat_handler.msg_all(f"{self.caller} joins combat!")
else: else:
# create a new combat handler # create a new combat handler
chandler = create_script("combat_handler.CombatHandler") chandler = create_script("combat_handler.CombatHandler")
chandler.add_character(self.caller) chandler.add_character(self.caller)
chandler.add_character(target) chandler.add_character(target)
self.caller.msg("You attack %s! You are in combat." % target) self.caller.msg(f"You attack {target}! You are in combat.")
target.msg("%s attacks you! You are in combat." % self.caller) target.msg(f"{self.caller} attacks you! You are in combat.")
``` ```
The `attack` command will not go into the combat cmdset but rather into the default cmdset. See e.g. The `attack` command will not go into the combat cmdset but rather into the default cmdset. See e.g.

View file

@ -150,7 +150,7 @@ class CmdSetPower(Command):
return return
# at this point the argument is tested as valid. Let's set it. # at this point the argument is tested as valid. Let's set it.
self.caller.db.power = power self.caller.db.power = power
self.caller.msg("Your Power was set to %i." % power) self.caller.msg(f"Your Power was set to {power}.")
``` ```
This is a pretty straightforward command. We do some error checking, then set the power on ourself. This is a pretty straightforward command. We do some error checking, then set the power on ourself.
We use a `help_category` of "mush" for all our commands, just so they are easy to find and separate We use a `help_category` of "mush" for all our commands, just so they are easy to find and separate
@ -295,11 +295,17 @@ class CmdAttack(Command):
caller.db.combat_score = combat_score caller.db.combat_score = combat_score
# announce # announce
message = "%s +attack%s with a combat score of %s!" message_template = "{attacker} +attack{s} with a combat score of {c_score}!"
caller.msg(message % ("You", "", combat_score)) caller.msg(message_template.format(
caller.location.msg_contents(message % attacker="You",
(caller.key, "s", combat_score), s="",
exclude=caller) c_score=combat_score,
))
caller.location.msg_contents(message_template.format(
attacker=caller.key,
s="s",
c_score=combat_score,
), exclude=caller)
``` ```
What we do here is simply to generate a "combat score" using Python's inbuilt `random.randint()` What we do here is simply to generate a "combat score" using Python's inbuilt `random.randint()`
@ -359,7 +365,7 @@ class Character(DefaultCharacter):
looker sees when looking at this object. looker sees when looking at this object.
""" """
text = super().return_appearance(looker) text = super().return_appearance(looker)
cscore = " (combat score: %s)" % self.db.combat_score cscore = f" (combat score: {self.db.combat_score})"
if "\n" in text: if "\n" in text:
# text is multi-line, add score after first line # text is multi-line, add score after first line
first_line, rest = text.split("\n", 1) first_line, rest = text.split("\n", 1)
@ -435,12 +441,17 @@ class CmdCreateNPC(Command):
npc = create_object("characters.Character", npc = create_object("characters.Character",
key=name, key=name,
location=caller.location, location=caller.location,
locks="edit:id(%i) and perm(Builders);call:false()" % caller.id) locks=f"edit:id({caller.id}) and perm(Builders);call:false()")
# announce # announce
message = "%s created the NPC '%s'." message_template = "{creator} created the NPC '{npc}'."
caller.msg(message % ("You", name)) caller.msg(message_template.format(
caller.location.msg_contents(message % (caller.key, name), creator="You",
exclude=caller) npc=name,
))
caller.location.msg_contents(message_template.format(
creator=caller.key,
npt=name,
), exclude=caller)
``` ```
Here we define a `+createnpc` (`+createNPC` works too) that is callable by everyone *not* having the Here we define a `+createnpc` (`+createNPC` works too) that is callable by everyone *not* having the
`nonpcs` "[permission](../../../Components/Locks#Permissions)" (in Evennia, a "permission" can just as well be used to `nonpcs` "[permission](../../../Components/Locks#Permissions)" (in Evennia, a "permission" can just as well be used to
@ -532,10 +543,10 @@ class CmdEditNPC(Command):
return return
if not self.propname: if not self.propname:
# this means we just list the values # this means we just list the values
output = "Properties of %s:" % npc.key output = f"Properties of {npc.key}:"
for propname in allowed_propnames: for propname in allowed_propnames:
propvalue = npc.attributes.get(propname, default="N/A") propvalue = npc.attributes.get(propname, default="N/A")
output += "\n %s = %s" % (propname, propvalue) output += f"\n {propname} = {propvalue}"
caller.msg(output) caller.msg(output)
elif self.propname not in allowed_propnames: elif self.propname not in allowed_propnames:
caller.msg("You may only change %s." % caller.msg("You may only change %s." %
@ -619,7 +630,7 @@ class CmdNPC(Command):
return return
# send the command order # send the command order
npc.execute_cmd(self.cmdname) npc.execute_cmd(self.cmdname)
caller.msg("You told %s to do '%s'." % (npc.key, self.cmdname)) caller.msg(f"You told {npc.key} to do '{self.cmdname}'.")
``` ```
Note that if you give an erroneous command, you will not see any error message, since that error Note that if you give an erroneous command, you will not see any error message, since that error

View file

@ -29,7 +29,7 @@ class Npc(Character):
message = message.split('says, ')[1].strip(' "') message = message.split('says, ')[1].strip(' "')
# we'll make use of this in .msg() below # we'll make use of this in .msg() below
return "%s said: '%s'" % (from_obj, message) return f"{from_obj} said: '{message}'"
``` ```
When someone in the room speaks to this NPC, its `msg` method will be called. We will modify the When someone in the room speaks to this NPC, its `msg` method will be called. We will modify the
@ -60,7 +60,7 @@ class Npc(Character):
# If there is a response # If there is a response
if response != None: if response != None:
# speak ourselves, using the return # speak ourselves, using the return
self.execute_cmd("say %s" % response) self.execute_cmd(f"say {response}")
# this is needed if anyone ever puppets this NPC - without it you would never # this is needed if anyone ever puppets this NPC - without it you would never
# get any feedback from the server (not even the results of look) # get any feedback from the server (not even the results of look)

View file

@ -66,16 +66,16 @@ command
keys = prototypes.keys() keys = prototypes.keys()
nprots = len(prototypes) nprots = len(prototypes)
tweet = "Prototype Count: %s Random Keys: " % nprots tweet = f"Prototype Count: {nprots} Random Keys: "
tweet += " %s" % keys[randint(0,len(keys)-1)] tweet += f" {keys[randint(0,len(keys)-1)]}"
for x in range(0,2): ##tweet 3 for x in range(0,2): ##tweet 3
tweet += ", %s" % keys[randint(0,len(keys)-1)] tweet += f", {keys[randint(0,len(keys)-1)]}"
# post the tweet # post the tweet
try: try:
response = api.PostUpdate(tweet) response = api.PostUpdate(tweet)
except: except:
logger.log_trace("Tweet Error: When attempting to tweet %s" % tweet) logger.log_trace(f"Tweet Error: When attempting to tweet {tweet}")
``` ```
In the `at_script_creation` method, we configure the script to fire immediately (useful for testing) In the `at_script_creation` method, we configure the script to fire immediately (useful for testing)

View file

@ -293,7 +293,7 @@ class TrainObject(DefaultObject):
roomref = self.db.rooms[idx] roomref = self.db.rooms[idx]
room = search_object(roomref)[0] room = search_object(roomref)[0]
self.move_to(room) self.move_to(room)
self.msg_contents("The train is moving forward to %s." % (room.name, )) self.msg_contents(f"The train is moving forward to {room.name}.")
``` ```
We added a lot of code here. Since we changed the `at_object_creation` to add in variables we will We added a lot of code here. Since we changed the `at_object_creation` to add in variables we will

View file

@ -246,8 +246,12 @@ def creating(request):
user.db._playable_characters.append(char) user.db._playable_characters.append(char)
# add the right locks for the character so the account can # add the right locks for the character so the account can
# puppet it # puppet it
char.locks.add("puppet:id(%i) or pid(%i) or perm(Developers) " char.locks.add(" or ".join([
"or pperm(Developers)" % (char.id, user.id)) f"puppet:id({char.id})",
f"pid({user.id})",
"perm(Developers)",
"pperm(Developers)",
]))
char.db.background = background # set the character background char.db.background = background # set the character background
return HttpResponseRedirect('/chargen') return HttpResponseRedirect('/chargen')
else: else:
@ -332,8 +336,12 @@ def creating(request):
user.db._playable_characters.append(char) user.db._playable_characters.append(char)
# add the right locks for the character so the account can # add the right locks for the character so the account can
# puppet it # puppet it
char.locks.add("puppet:id(%i) or pid(%i) or perm(Developers) " char.locks.add(" or ".join([
"or pperm(Developers)" % (char.id, user.id)) f"puppet:id({char.id})",
f"pid({user.id})",
"perm(Developers)",
"pperm(Developers)",
]))
char.db.background = background # set the character background char.db.background = background # set the character background
return HttpResponseRedirect('/chargen') return HttpResponseRedirect('/chargen')
else: else:

View file

@ -76,13 +76,13 @@ class CmdTweet(Command):
tlen = len(tweet) tlen = len(tweet)
if tlen > 280: if tlen > 280:
caller.msg("Your tweet was %i chars long (max 280)." % tlen) caller.msg(f"Your tweet was {tlen} chars long (max 280).")
return return
# post the tweet # post the tweet
TWITTER_API.PostUpdate(tweet) TWITTER_API.PostUpdate(tweet)
caller.msg("You tweeted:\n%s" % tweet) caller.msg(f"You tweeted:\n{tweet}")
``` ```
Be sure to substitute your own actual API/Access keys and secrets in the appropriate places. Be sure to substitute your own actual API/Access keys and secrets in the appropriate places.