Run black on sources; add black config
This commit is contained in:
parent
b5d148b00a
commit
b24d4f0e1e
41 changed files with 400 additions and 344 deletions
|
|
@ -108,13 +108,7 @@ def _case_sensitive_replace(string, old, new):
|
||||||
result.append(new_word[ind + 1 :].lower())
|
result.append(new_word[ind + 1 :].lower())
|
||||||
out.append("".join(result))
|
out.append("".join(result))
|
||||||
# if we have more new words than old ones, just add them verbatim
|
# if we have more new words than old ones, just add them verbatim
|
||||||
out.extend(
|
out.extend([new_word for ind, new_word in enumerate(new_words) if ind >= len(old_words)])
|
||||||
[
|
|
||||||
new_word
|
|
||||||
for ind, new_word in enumerate(new_words)
|
|
||||||
if ind >= len(old_words)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
return " ".join(out)
|
return " ".join(out)
|
||||||
|
|
||||||
regex = re.compile(re.escape(old), re.I)
|
regex = re.compile(re.escape(old), re.I)
|
||||||
|
|
@ -154,9 +148,7 @@ def rename_in_tree(path, in_list, out_list, excl_list, fileend_list, is_interact
|
||||||
print("%s skipped (excluded)." % full_path)
|
print("%s skipped (excluded)." % full_path)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not fileend_list or any(
|
if not fileend_list or any(file.endswith(ending) for ending in fileend_list):
|
||||||
file.endswith(ending) for ending in fileend_list
|
|
||||||
):
|
|
||||||
rename_in_file(full_path, in_list, out_list, is_interactive)
|
rename_in_file(full_path, in_list, out_list, is_interactive)
|
||||||
|
|
||||||
# rename file - always ask
|
# rename file - always ask
|
||||||
|
|
@ -164,9 +156,7 @@ def rename_in_tree(path, in_list, out_list, excl_list, fileend_list, is_interact
|
||||||
for src, dst in repl_mapping:
|
for src, dst in repl_mapping:
|
||||||
new_file = _case_sensitive_replace(new_file, src, dst)
|
new_file = _case_sensitive_replace(new_file, src, dst)
|
||||||
if new_file != file:
|
if new_file != file:
|
||||||
inp = input(
|
inp = input(_green("Rename %s\n -> %s\n Y/[N]? > " % (file, new_file)))
|
||||||
_green("Rename %s\n -> %s\n Y/[N]? > " % (file, new_file))
|
|
||||||
)
|
|
||||||
if inp.upper() == "Y":
|
if inp.upper() == "Y":
|
||||||
new_full_path = os.path.join(root, new_file)
|
new_full_path = os.path.join(root, new_file)
|
||||||
try:
|
try:
|
||||||
|
|
@ -182,9 +172,7 @@ def rename_in_tree(path, in_list, out_list, excl_list, fileend_list, is_interact
|
||||||
for src, dst in repl_mapping:
|
for src, dst in repl_mapping:
|
||||||
new_root = _case_sensitive_replace(new_root, src, dst)
|
new_root = _case_sensitive_replace(new_root, src, dst)
|
||||||
if new_root != root:
|
if new_root != root:
|
||||||
inp = input(
|
inp = input(_green("Dir Rename %s\n -> %s\n Y/[N]? > " % (root, new_root)))
|
||||||
_green("Dir Rename %s\n -> %s\n Y/[N]? > " % (root, new_root))
|
|
||||||
)
|
|
||||||
if inp.upper() == "Y":
|
if inp.upper() == "Y":
|
||||||
try:
|
try:
|
||||||
os.rename(root, new_root)
|
os.rename(root, new_root)
|
||||||
|
|
@ -252,9 +240,7 @@ def rename_in_file(path, in_list, out_list, is_interactive):
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
|
||||||
for iline, renamed_line in sorted(
|
for iline, renamed_line in sorted(list(renamed.items()), key=lambda tup: tup[0]):
|
||||||
list(renamed.items()), key=lambda tup: tup[0]
|
|
||||||
):
|
|
||||||
print("%3i orig: %s" % (iline + 1, org_lines[iline]))
|
print("%3i orig: %s" % (iline + 1, org_lines[iline]))
|
||||||
print(" new : %s" % (_yellow(renamed_line)))
|
print(" new : %s" % (_yellow(renamed_line)))
|
||||||
print(_green("%s (%i lines changed)" % (path, len(renamed))))
|
print(_green("%s (%i lines changed)" % (path, len(renamed))))
|
||||||
|
|
@ -297,11 +283,7 @@ def rename_in_file(path, in_list, out_list, is_interactive):
|
||||||
input(_HELP_TEXT.format(sources=in_list, targets=out_list))
|
input(_HELP_TEXT.format(sources=in_list, targets=out_list))
|
||||||
elif ret.startswith("i"):
|
elif ret.startswith("i"):
|
||||||
# ignore one or more lines
|
# ignore one or more lines
|
||||||
ignores = [
|
ignores = [int(ind) - 1 for ind in ret[1:].split(",") if ind.strip().isdigit()]
|
||||||
int(ind) - 1
|
|
||||||
for ind in ret[1:].split(",")
|
|
||||||
if ind.strip().isdigit()
|
|
||||||
]
|
|
||||||
if not ignores:
|
if not ignores:
|
||||||
input("Ignore example: i 2,7,34,133\n (return to continue)")
|
input("Ignore example: i 2,7,34,133\n (return to continue)")
|
||||||
continue
|
continue
|
||||||
|
|
@ -313,9 +295,7 @@ def rename_in_file(path, in_list, out_list, is_interactive):
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(description="Rename text in a source tree, or a single file")
|
||||||
description="Rename text in a source tree, or a single file"
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-i",
|
"-i",
|
||||||
|
|
@ -326,27 +306,19 @@ if __name__ == "__main__":
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-o", "--output", action="append", help="Word to rename a matching src-word to"
|
"-o", "--output", action="append", help="Word to rename a matching src-word to"
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument("-x", "--exc", action="append", help="File path patterns to exclude")
|
||||||
"-x", "--exc", action="append", help="File path patterns to exclude"
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-a", "--auto", action="store_true", help="Automatic mode, don't ask to rename"
|
"-a", "--auto", action="store_true", help="Automatic mode, don't ask to rename"
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument("-r", "--recursive", action="store_true", help="Recurse subdirs")
|
||||||
"-r", "--recursive", action="store_true", help="Recurse subdirs"
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-f",
|
"-f",
|
||||||
"--fileending",
|
"--fileending",
|
||||||
action="append",
|
action="append",
|
||||||
help="Change which file endings to allow (default .py and .html)",
|
help="Change which file endings to allow (default .py and .html)",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument("--nocolor", action="store_true", help="Turn off in-program color")
|
||||||
"--nocolor", action="store_true", help="Turn off in-program color"
|
parser.add_argument("--fake", action="store_true", help="Simulate run but don't actually save")
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--fake", action="store_true", help="Simulate run but don't actually save"
|
|
||||||
)
|
|
||||||
parser.add_argument("path", help="File or directory in which to rename text")
|
parser.add_argument("path", help="File or directory in which to rename text")
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
@ -362,9 +334,7 @@ if __name__ == "__main__":
|
||||||
print("At least one source- and destination word must be given.")
|
print("At least one source- and destination word must be given.")
|
||||||
sys.exit()
|
sys.exit()
|
||||||
if len(in_list) != len(out_list):
|
if len(in_list) != len(out_list):
|
||||||
print(
|
print("Number of sources must be identical to the number of destination arguments.")
|
||||||
"Number of sources must be identical to the number of destination arguments."
|
|
||||||
)
|
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
exc_list = exc_list or []
|
exc_list = exc_list or []
|
||||||
|
|
@ -376,8 +346,6 @@ if __name__ == "__main__":
|
||||||
FAKE_MODE = args.fake
|
FAKE_MODE = args.fake
|
||||||
|
|
||||||
if is_recursive:
|
if is_recursive:
|
||||||
rename_in_tree(
|
rename_in_tree(args.path, in_list, out_list, exc_list, fileend_list, is_interactive)
|
||||||
args.path, in_list, out_list, exc_list, fileend_list, is_interactive
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
rename_in_file(args.path, in_list, out_list, is_interactive)
|
rename_in_file(args.path, in_list, out_list, is_interactive)
|
||||||
|
|
|
||||||
|
|
@ -15,18 +15,25 @@ _IGNORE_FILES = []
|
||||||
_SOURCEDIR_NAME = "source"
|
_SOURCEDIR_NAME = "source"
|
||||||
_SOURCE_DIR = pathjoin(dirname(dirname(abspath(__file__))), _SOURCEDIR_NAME)
|
_SOURCE_DIR = pathjoin(dirname(dirname(abspath(__file__))), _SOURCEDIR_NAME)
|
||||||
_TOC_FILE = pathjoin(_SOURCE_DIR, "toc.md")
|
_TOC_FILE = pathjoin(_SOURCE_DIR, "toc.md")
|
||||||
_NO_REMAP_STARTSWITH = ["http://", "https://", "github:", "api:",
|
_NO_REMAP_STARTSWITH = [
|
||||||
"feature-request", "report-bug", "issue", "bug-report"]
|
"http://",
|
||||||
|
"https://",
|
||||||
|
"github:",
|
||||||
|
"api:",
|
||||||
|
"feature-request",
|
||||||
|
"report-bug",
|
||||||
|
"issue",
|
||||||
|
"bug-report",
|
||||||
|
]
|
||||||
|
|
||||||
TXT_REMAPS = {
|
TXT_REMAPS = {}
|
||||||
}
|
URL_REMAPS = {}
|
||||||
URL_REMAPS = {
|
|
||||||
}
|
|
||||||
|
|
||||||
_USED_REFS = {}
|
_USED_REFS = {}
|
||||||
|
|
||||||
_CURRFILE = None
|
_CURRFILE = None
|
||||||
|
|
||||||
|
|
||||||
def auto_link_remapper():
|
def auto_link_remapper():
|
||||||
"""
|
"""
|
||||||
- Auto-Remaps links to fit with the actual document file structure. Requires
|
- Auto-Remaps links to fit with the actual document file structure. Requires
|
||||||
|
|
@ -44,7 +51,7 @@ def auto_link_remapper():
|
||||||
# we allow a max of 4 levels of nesting in the source dir
|
# we allow a max of 4 levels of nesting in the source dir
|
||||||
ind = pathparts[-5:].index(_SOURCEDIR_NAME)
|
ind = pathparts[-5:].index(_SOURCEDIR_NAME)
|
||||||
# get the part after source/
|
# get the part after source/
|
||||||
pathparts = pathparts[-5 + 1 + ind:]
|
pathparts = pathparts[-5 + 1 + ind :]
|
||||||
url = "/".join(pathparts)
|
url = "/".join(pathparts)
|
||||||
# get the reference, without .md
|
# get the reference, without .md
|
||||||
url = url.rsplit(".", 1)[0]
|
url = url.rsplit(".", 1)[0]
|
||||||
|
|
@ -71,7 +78,8 @@ def auto_link_remapper():
|
||||||
raise DocumentError(
|
raise DocumentError(
|
||||||
f" Tried to add {src_url}.md, but a file {duplicate_src_url}.md already exists.\n"
|
f" Tried to add {src_url}.md, but a file {duplicate_src_url}.md already exists.\n"
|
||||||
" Evennia's auto-link-corrector does not accept doc-files with the same \n"
|
" Evennia's auto-link-corrector does not accept doc-files with the same \n"
|
||||||
" name, even in different folders. Rename one.\n")
|
" name, even in different folders. Rename one.\n"
|
||||||
|
)
|
||||||
toc_map[fname] = src_url
|
toc_map[fname] = src_url
|
||||||
|
|
||||||
# find relative links to all other files
|
# find relative links to all other files
|
||||||
|
|
@ -86,17 +94,20 @@ def auto_link_remapper():
|
||||||
url = "./" + url
|
url = "./" + url
|
||||||
docref_map[sourcepath][targetname] = url.rsplit(".", 1)[0]
|
docref_map[sourcepath][targetname] = url.rsplit(".", 1)[0]
|
||||||
|
|
||||||
|
|
||||||
# normal reference-links [txt](urls)
|
# normal reference-links [txt](urls)
|
||||||
ref_regex = re.compile(r"\[(?P<txt>[\w -\[\]\`]+?)\]\((?P<url>.+?)\)", re.I + re.S + re.U + re.M)
|
ref_regex = re.compile(
|
||||||
|
r"\[(?P<txt>[\w -\[\]\`]+?)\]\((?P<url>.+?)\)", re.I + re.S + re.U + re.M
|
||||||
|
)
|
||||||
# in document references
|
# in document references
|
||||||
ref_doc_regex = re.compile(r"\[(?P<txt>[\w -\`]+?)\]:\s+?(?P<url>.+?)(?=$|\n)", re.I + re.S + re.U + re.M)
|
ref_doc_regex = re.compile(
|
||||||
|
r"\[(?P<txt>[\w -\`]+?)\]:\s+?(?P<url>.+?)(?=$|\n)", re.I + re.S + re.U + re.M
|
||||||
|
)
|
||||||
|
|
||||||
def _sub(match):
|
def _sub(match):
|
||||||
# inline reference links
|
# inline reference links
|
||||||
global _USED_REFS
|
global _USED_REFS
|
||||||
grpdict = match.groupdict()
|
grpdict = match.groupdict()
|
||||||
txt, url = grpdict['txt'], grpdict['url']
|
txt, url = grpdict["txt"], grpdict["url"]
|
||||||
|
|
||||||
txt = TXT_REMAPS.get(txt, txt)
|
txt = TXT_REMAPS.get(txt, txt)
|
||||||
url = URL_REMAPS.get(url, url)
|
url = URL_REMAPS.get(url, url)
|
||||||
|
|
@ -117,7 +128,7 @@ def auto_link_remapper():
|
||||||
|
|
||||||
if _CURRFILE in docref_map and fname in docref_map[_CURRFILE]:
|
if _CURRFILE in docref_map and fname in docref_map[_CURRFILE]:
|
||||||
cfilename = _CURRFILE.rsplit("/", 1)[-1]
|
cfilename = _CURRFILE.rsplit("/", 1)[-1]
|
||||||
urlout = docref_map[_CURRFILE][fname] + ('#' + anchor[0] if anchor else '')
|
urlout = docref_map[_CURRFILE][fname] + ("#" + anchor[0] if anchor else "")
|
||||||
if urlout != url:
|
if urlout != url:
|
||||||
print(f" {cfilename}: [{txt}]({url}) -> [{txt}]({urlout})")
|
print(f" {cfilename}: [{txt}]({url}) -> [{txt}]({urlout})")
|
||||||
else:
|
else:
|
||||||
|
|
@ -129,7 +140,7 @@ def auto_link_remapper():
|
||||||
# reference links set at the bottom of the page
|
# reference links set at the bottom of the page
|
||||||
global _USED_REFS
|
global _USED_REFS
|
||||||
grpdict = match.groupdict()
|
grpdict = match.groupdict()
|
||||||
txt, url = grpdict['txt'], grpdict['url']
|
txt, url = grpdict["txt"], grpdict["url"]
|
||||||
|
|
||||||
txt = TXT_REMAPS.get(txt, txt)
|
txt = TXT_REMAPS.get(txt, txt)
|
||||||
url = URL_REMAPS.get(url, url)
|
url = URL_REMAPS.get(url, url)
|
||||||
|
|
@ -150,7 +161,7 @@ def auto_link_remapper():
|
||||||
|
|
||||||
if _CURRFILE in docref_map and fname in docref_map[_CURRFILE]:
|
if _CURRFILE in docref_map and fname in docref_map[_CURRFILE]:
|
||||||
cfilename = _CURRFILE.rsplit("/", 1)[-1]
|
cfilename = _CURRFILE.rsplit("/", 1)[-1]
|
||||||
urlout = docref_map[_CURRFILE][fname] + ('#' + anchor[0] if anchor else '')
|
urlout = docref_map[_CURRFILE][fname] + ("#" + anchor[0] if anchor else "")
|
||||||
if urlout != url:
|
if urlout != url:
|
||||||
print(f" {cfilename}: [{txt}]: {url} -> [{txt}]: {urlout}")
|
print(f" {cfilename}: [{txt}]: {url} -> [{txt}]: {urlout}")
|
||||||
else:
|
else:
|
||||||
|
|
@ -165,12 +176,12 @@ def auto_link_remapper():
|
||||||
# from pudb import debugger;debugger.Debugger().set_trace()
|
# from pudb import debugger;debugger.Debugger().set_trace()
|
||||||
_CURRFILE = path.as_posix()
|
_CURRFILE = path.as_posix()
|
||||||
|
|
||||||
with open(path, 'r') as fil:
|
with open(path, "r") as fil:
|
||||||
intxt = fil.read()
|
intxt = fil.read()
|
||||||
outtxt = ref_regex.sub(_sub, intxt)
|
outtxt = ref_regex.sub(_sub, intxt)
|
||||||
outtxt = ref_doc_regex.sub(_sub_doc, outtxt)
|
outtxt = ref_doc_regex.sub(_sub_doc, outtxt)
|
||||||
if intxt != outtxt:
|
if intxt != outtxt:
|
||||||
with open(path, 'w') as fil:
|
with open(path, "w") as fil:
|
||||||
fil.write(outtxt)
|
fil.write(outtxt)
|
||||||
count += 1
|
count += 1
|
||||||
print(f" -- Auto-relinked links in {path.name}")
|
print(f" -- Auto-relinked links in {path.name}")
|
||||||
|
|
@ -207,5 +218,6 @@ def auto_link_remapper():
|
||||||
|
|
||||||
print(" -- Auto-Remapper finished.")
|
print(" -- Auto-Remapper finished.")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
auto_link_remapper()
|
auto_link_remapper()
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ def create_search_index(sourcedir, outfile):
|
||||||
print(f"Building Search index from {len(filepaths)} files ... ", end="")
|
print(f"Building Search index from {len(filepaths)} files ... ", end="")
|
||||||
|
|
||||||
for filepath in filepaths:
|
for filepath in filepaths:
|
||||||
with open(filepath, 'r') as fil:
|
with open(filepath, "r") as fil:
|
||||||
filename = filepath.rsplit(sep, 1)[1].split(".", 1)[0]
|
filename = filepath.rsplit(sep, 1)[1].split(".", 1)[0]
|
||||||
url = f"{URL_BASE}{sep}{filename}.html".strip()
|
url = f"{URL_BASE}{sep}{filename}.html".strip()
|
||||||
title = filename.replace("-", " ").strip()
|
title = filename.replace("-", " ").strip()
|
||||||
|
|
@ -61,16 +61,7 @@ def create_search_index(sourcedir, outfile):
|
||||||
idx = lunr(
|
idx = lunr(
|
||||||
ref="url",
|
ref="url",
|
||||||
documents=outlist,
|
documents=outlist,
|
||||||
fields=[
|
fields=[{"field_name": "title", "boost": 10}, {"field_name": "text", "boost": 1}],
|
||||||
{
|
|
||||||
"field_name": "title",
|
|
||||||
"boost": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"field_name": "text",
|
|
||||||
"boost": 1
|
|
||||||
}
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
with open(outfile, "w") as fil:
|
with open(outfile, "w") as fil:
|
||||||
|
|
@ -83,10 +74,18 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
parser = ArgumentParser(description="Build a static search index.")
|
parser = ArgumentParser(description="Build a static search index.")
|
||||||
|
|
||||||
parser.add_argument("-i", dest="sourcedir", default=DEFAULT_SOURCE_DIR,
|
parser.add_argument(
|
||||||
help="Absolute path to the documentation source dir")
|
"-i",
|
||||||
parser.add_argument("-o", dest="outfile", default=DEFAULT_OUTFILE,
|
dest="sourcedir",
|
||||||
help="Absolute path to the index file to output.")
|
default=DEFAULT_SOURCE_DIR,
|
||||||
|
help="Absolute path to the documentation source dir",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-o",
|
||||||
|
dest="outfile",
|
||||||
|
default=DEFAULT_OUTFILE,
|
||||||
|
help="Absolute path to the index file to output.",
|
||||||
|
)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ We also need to build the toc-tree and should do so automatically for now.
|
||||||
|
|
||||||
import glob
|
import glob
|
||||||
import re
|
import re
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
_RE_MD_LINK = re.compile(r"\[(?P<txt>[\w -\[\]]+?)\]\((?P<url>.+?)\)", re.I + re.S + re.U)
|
_RE_MD_LINK = re.compile(r"\[(?P<txt>[\w -\[\]]+?)\]\((?P<url>.+?)\)", re.I + re.S + re.U)
|
||||||
_RE_REF_LINK = re.compile(r"\[[\w -\[\]]*?\]\(.+?\)", re.I + re.S + re.U)
|
_RE_REF_LINK = re.compile(r"\[[\w -\[\]]*?\]\(.+?\)", re.I + re.S + re.U)
|
||||||
|
|
@ -43,8 +43,11 @@ _INDEX_PREFIX = f"""
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_WIKI_DIR = "../../../evennia.wiki/"
|
_WIKI_DIR = "../../../evennia.wiki/"
|
||||||
_INFILES = [path for path in sorted(glob.glob(_WIKI_DIR + "/*.md"))
|
_INFILES = [
|
||||||
if path.rsplit('/', 1)[-1] not in _IGNORE_FILES]
|
path
|
||||||
|
for path in sorted(glob.glob(_WIKI_DIR + "/*.md"))
|
||||||
|
if path.rsplit("/", 1)[-1] not in _IGNORE_FILES
|
||||||
|
]
|
||||||
_FILENAMES = [path.rsplit("/", 1)[-1] for path in _INFILES]
|
_FILENAMES = [path.rsplit("/", 1)[-1] for path in _INFILES]
|
||||||
_FILENAMES = [path.split(".", 1)[0] for path in _FILENAMES]
|
_FILENAMES = [path.split(".", 1)[0] for path in _FILENAMES]
|
||||||
_FILENAMESLOW = [path.lower() for path in _FILENAMES]
|
_FILENAMESLOW = [path.lower() for path in _FILENAMES]
|
||||||
|
|
@ -95,8 +98,17 @@ _ABSOLUTE_LINK_SKIP = (
|
||||||
# specific references tokens that should be ignored. Should be given
|
# specific references tokens that should be ignored. Should be given
|
||||||
# without any #anchor.
|
# without any #anchor.
|
||||||
_REF_SKIP = (
|
_REF_SKIP = (
|
||||||
"[5](Win)", "[6](Win)", "[7](Win)", "[10](Win)", "[11](Mac)", "[13](Win)",
|
"[5](Win)",
|
||||||
"[14](IOS)", "[15](IOS)", "[16](Andr)", "[17](Andr)", "[18](Unix)",
|
"[6](Win)",
|
||||||
|
"[7](Win)",
|
||||||
|
"[10](Win)",
|
||||||
|
"[11](Mac)",
|
||||||
|
"[13](Win)",
|
||||||
|
"[14](IOS)",
|
||||||
|
"[15](IOS)",
|
||||||
|
"[16](Andr)",
|
||||||
|
"[17](Andr)",
|
||||||
|
"[18](Unix)",
|
||||||
"[21](Chrome)",
|
"[21](Chrome)",
|
||||||
# these should be checked
|
# these should be checked
|
||||||
"[EvTable](EvTable)",
|
"[EvTable](EvTable)",
|
||||||
|
|
@ -126,20 +138,19 @@ def _sub_remap(match):
|
||||||
def _sub_link(match):
|
def _sub_link(match):
|
||||||
|
|
||||||
mdict = match.groupdict()
|
mdict = match.groupdict()
|
||||||
txt, url_orig = mdict['txt'], mdict['url']
|
txt, url_orig = mdict["txt"], mdict["url"]
|
||||||
url = url_orig
|
url = url_orig
|
||||||
# if not txt:
|
# if not txt:
|
||||||
# # the 'comment' is not supported by Mkdocs
|
# # the 'comment' is not supported by Mkdocs
|
||||||
# return ""
|
# return ""
|
||||||
print(f" [{txt}]({url})")
|
print(f" [{txt}]({url})")
|
||||||
|
|
||||||
|
|
||||||
url = _CUSTOM_LINK_REMAP.get(url, url)
|
url = _CUSTOM_LINK_REMAP.get(url, url)
|
||||||
|
|
||||||
url, *anchor = url.rsplit("#", 1)
|
url, *anchor = url.rsplit("#", 1)
|
||||||
|
|
||||||
if url in _ABSOLUTE_LINK_SKIP:
|
if url in _ABSOLUTE_LINK_SKIP:
|
||||||
url += (("#" + anchor[0]) if anchor else "")
|
url += ("#" + anchor[0]) if anchor else ""
|
||||||
return f"[{txt}]({url})"
|
return f"[{txt}]({url})"
|
||||||
|
|
||||||
if url.startswith("evennia"):
|
if url.startswith("evennia"):
|
||||||
|
|
@ -166,11 +177,10 @@ def _sub_link(match):
|
||||||
# this happens on same-file #labels in wiki
|
# this happens on same-file #labels in wiki
|
||||||
url = _CURRENT_TITLE
|
url = _CURRENT_TITLE
|
||||||
|
|
||||||
if (url not in _FILENAMES and
|
if url not in _FILENAMES and not url.startswith("http") and not url.startswith(_CODE_PREFIX):
|
||||||
not url.startswith("http") and not url.startswith(_CODE_PREFIX)):
|
|
||||||
|
|
||||||
url_cap = url.capitalize()
|
url_cap = url.capitalize()
|
||||||
url_plur = url[:-3] + 's' + ".md"
|
url_plur = url[:-3] + "s" + ".md"
|
||||||
url_cap_plur = url_plur.capitalize()
|
url_cap_plur = url_plur.capitalize()
|
||||||
|
|
||||||
link = f"[{txt}]({url})"
|
link = f"[{txt}]({url})"
|
||||||
|
|
@ -201,6 +211,7 @@ def _sub_link(match):
|
||||||
|
|
||||||
return f"[{txt}]({url})"
|
return f"[{txt}]({url})"
|
||||||
|
|
||||||
|
|
||||||
def create_toctree(files):
|
def create_toctree(files):
|
||||||
|
|
||||||
with open("../source/toc.md", "w") as fil:
|
with open("../source/toc.md", "w") as fil:
|
||||||
|
|
@ -216,13 +227,14 @@ def create_toctree(files):
|
||||||
|
|
||||||
fil.write(f"\n* [{linkname}]({ref}.md)")
|
fil.write(f"\n* [{linkname}]({ref}.md)")
|
||||||
|
|
||||||
|
|
||||||
def convert_links(files, outdir):
|
def convert_links(files, outdir):
|
||||||
global _CURRENT_TITLE
|
global _CURRENT_TITLE
|
||||||
|
|
||||||
for inpath in files:
|
for inpath in files:
|
||||||
|
|
||||||
is_index = False
|
is_index = False
|
||||||
outfile = inpath.rsplit('/', 1)[-1]
|
outfile = inpath.rsplit("/", 1)[-1]
|
||||||
if outfile == "Home.md":
|
if outfile == "Home.md":
|
||||||
outfile = "index.md"
|
outfile = "index.md"
|
||||||
is_index = True
|
is_index = True
|
||||||
|
|
@ -235,26 +247,33 @@ def convert_links(files, outdir):
|
||||||
text = fil.read()
|
text = fil.read()
|
||||||
|
|
||||||
if is_index:
|
if is_index:
|
||||||
text = _INDEX_PREFIX + text
|
text = _INDEX_PREFIX + text
|
||||||
lines = text.split("\n")
|
lines = text.split("\n")
|
||||||
lines = (lines[:-11]
|
lines = (
|
||||||
+ [" - The [TOC](toc) lists all regular documentation pages.\n\n"]
|
lines[:-11]
|
||||||
+ lines[-11:])
|
+ [" - The [TOC](toc) lists all regular documentation pages.\n\n"]
|
||||||
|
+ lines[-11:]
|
||||||
|
)
|
||||||
text = "\n".join(lines)
|
text = "\n".join(lines)
|
||||||
|
|
||||||
_CURRENT_TITLE = title.replace(" ", "-")
|
_CURRENT_TITLE = title.replace(" ", "-")
|
||||||
text = _RE_CLEAN.sub("", text)
|
text = _RE_CLEAN.sub("", text)
|
||||||
text = _RE_REF_LINK.sub(_sub_remap, text)
|
text = _RE_REF_LINK.sub(_sub_remap, text)
|
||||||
text = _RE_MD_LINK.sub(_sub_link, text)
|
text = _RE_MD_LINK.sub(_sub_link, text)
|
||||||
text = text.split('\n')[1:] if text.split('\n')[0].strip().startswith('[]') else text.split('\n')
|
text = (
|
||||||
|
text.split("\n")[1:]
|
||||||
|
if text.split("\n")[0].strip().startswith("[]")
|
||||||
|
else text.split("\n")
|
||||||
|
)
|
||||||
text = "\n".join(text)
|
text = "\n".join(text)
|
||||||
|
|
||||||
if not is_index:
|
if not is_index:
|
||||||
text = f"# {title}\n\n{text}"
|
text = f"# {title}\n\n{text}"
|
||||||
|
|
||||||
with open(outfile, 'w') as fil:
|
with open(outfile, "w") as fil:
|
||||||
fil.write(text)
|
fil.write(text)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
create_toctree(_INFILES)
|
create_toctree(_INFILES)
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ def url_resolver(url):
|
||||||
if url.endswith(choose_issue):
|
if url.endswith(choose_issue):
|
||||||
return _github_issue_choose
|
return _github_issue_choose
|
||||||
elif githubstart in url:
|
elif githubstart in url:
|
||||||
urlpath = url[url.index(githubstart) + len(githubstart):]
|
urlpath = url[url.index(githubstart) + len(githubstart) :]
|
||||||
if not (urlpath.startswith("develop/") or urlpath.startswith("master")):
|
if not (urlpath.startswith("develop/") or urlpath.startswith("master")):
|
||||||
urlpath = "master/" + urlpath
|
urlpath = "master/" + urlpath
|
||||||
return _github_code_root + urlpath
|
return _github_code_root + urlpath
|
||||||
|
|
@ -137,14 +137,14 @@ def url_resolver(url):
|
||||||
ind = url.index(apistart)
|
ind = url.index(apistart)
|
||||||
depth = url[:ind].count("/") + 1
|
depth = url[:ind].count("/") + 1
|
||||||
path = "../".join("" for _ in range(depth))
|
path = "../".join("" for _ in range(depth))
|
||||||
urlpath = path + "api/" + url[ind + len(apistart):] + ".html"
|
urlpath = path + "api/" + url[ind + len(apistart) :] + ".html"
|
||||||
return urlpath
|
return urlpath
|
||||||
elif sourcestart in url:
|
elif sourcestart in url:
|
||||||
ind = url.index(sourcestart)
|
ind = url.index(sourcestart)
|
||||||
depth = url[:ind].count("/") + 1
|
depth = url[:ind].count("/") + 1
|
||||||
path = "../".join("" for _ in range(depth))
|
path = "../".join("" for _ in range(depth))
|
||||||
|
|
||||||
modpath, *inmodule = url[ind + len(sourcestart):].rsplit("#", 1)
|
modpath, *inmodule = url[ind + len(sourcestart) :].rsplit("#", 1)
|
||||||
modpath = "/".join(modpath.split("."))
|
modpath = "/".join(modpath.split("."))
|
||||||
inmodule = "#" + inmodule[0] if inmodule else ""
|
inmodule = "#" + inmodule[0] if inmodule else ""
|
||||||
modpath = modpath + ".html" + inmodule
|
modpath = modpath + ".html" + inmodule
|
||||||
|
|
@ -252,13 +252,12 @@ def autodoc_post_process_docstring(app, what, name, obj, options, lines):
|
||||||
|
|
||||||
def _sub_codeblock(match):
|
def _sub_codeblock(match):
|
||||||
code = match.group(1)
|
code = match.group(1)
|
||||||
return "::\n\n {}".format(
|
return "::\n\n {}".format("\n ".join(lne for lne in code.split("\n")))
|
||||||
"\n ".join(lne for lne in code.split("\n")))
|
|
||||||
|
|
||||||
underline_map = {
|
underline_map = {
|
||||||
1: "-",
|
1: "-",
|
||||||
2: "=",
|
2: "=",
|
||||||
3: '^',
|
3: "^",
|
||||||
4: '"',
|
4: '"',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -271,11 +270,14 @@ def autodoc_post_process_docstring(app, what, name, obj, options, lines):
|
||||||
return f"{title}\n" + (underline_map[lvl] * len(title))
|
return f"{title}\n" + (underline_map[lvl] * len(title))
|
||||||
|
|
||||||
doc = "\n".join(lines)
|
doc = "\n".join(lines)
|
||||||
doc = re.sub(r"```python\s*\n+(.*?)```", _sub_codeblock, doc,
|
doc = re.sub(
|
||||||
flags=re.MULTILINE + re.DOTALL)
|
r"```python\s*\n+(.*?)```", _sub_codeblock, doc, flags=re.MULTILINE + re.DOTALL
|
||||||
|
)
|
||||||
doc = re.sub(r"```", "", doc, flags=re.MULTILINE)
|
doc = re.sub(r"```", "", doc, flags=re.MULTILINE)
|
||||||
doc = re.sub(r"`{1}", "**", doc, flags=re.MULTILINE)
|
doc = re.sub(r"`{1}", "**", doc, flags=re.MULTILINE)
|
||||||
doc = re.sub(r"^(?P<hashes>#{1,2})\s*?(?P<title>.*?)$", _sub_header, doc, flags=re.MULTILINE)
|
doc = re.sub(
|
||||||
|
r"^(?P<hashes>#{1,2})\s*?(?P<title>.*?)$", _sub_header, doc, flags=re.MULTILINE
|
||||||
|
)
|
||||||
|
|
||||||
newlines = doc.split("\n")
|
newlines = doc.split("\n")
|
||||||
# we must modify lines in-place
|
# we must modify lines in-place
|
||||||
|
|
|
||||||
|
|
@ -508,8 +508,10 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
||||||
if banned:
|
if banned:
|
||||||
# this is a banned IP or name!
|
# this is a banned IP or name!
|
||||||
errors.append(
|
errors.append(
|
||||||
_("|rYou have been banned and cannot continue from here."
|
_(
|
||||||
"\nIf you feel this ban is in error, please email an admin.|x")
|
"|rYou have been banned and cannot continue from here."
|
||||||
|
"\nIf you feel this ban is in error, please email an admin.|x"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
logger.log_sec(f"Authentication Denied (Banned): {username} (IP: {ip}).")
|
logger.log_sec(f"Authentication Denied (Banned): {username} (IP: {ip}).")
|
||||||
LOGIN_THROTTLE.update(ip, "Too many sightings of banned artifact.")
|
LOGIN_THROTTLE.update(ip, "Too many sightings of banned artifact.")
|
||||||
|
|
@ -673,7 +675,9 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
||||||
|
|
||||||
# Load the appropriate Character class
|
# Load the appropriate Character class
|
||||||
character_typeclass = kwargs.pop("typeclass", None)
|
character_typeclass = kwargs.pop("typeclass", None)
|
||||||
character_typeclass = character_typeclass if character_typeclass else settings.BASE_CHARACTER_TYPECLASS
|
character_typeclass = (
|
||||||
|
character_typeclass if character_typeclass else settings.BASE_CHARACTER_TYPECLASS
|
||||||
|
)
|
||||||
Character = class_from_module(character_typeclass)
|
Character = class_from_module(character_typeclass)
|
||||||
|
|
||||||
# Create the character
|
# Create the character
|
||||||
|
|
@ -683,7 +687,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
||||||
ip=character_ip,
|
ip=character_ip,
|
||||||
typeclass=character_typeclass,
|
typeclass=character_typeclass,
|
||||||
permissions=character_permissions,
|
permissions=character_permissions,
|
||||||
**kwargs
|
**kwargs,
|
||||||
)
|
)
|
||||||
if character:
|
if character:
|
||||||
# Update playable character list
|
# Update playable character list
|
||||||
|
|
@ -761,9 +765,9 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
||||||
banned = cls.is_banned(username=username, ip=ip)
|
banned = cls.is_banned(username=username, ip=ip)
|
||||||
if banned:
|
if banned:
|
||||||
# this is a banned IP or name!
|
# this is a banned IP or name!
|
||||||
string = (
|
string = _(
|
||||||
_("|rYou have been banned and cannot continue from here."
|
"|rYou have been banned and cannot continue from here."
|
||||||
"\nIf you feel this ban is in error, please email an admin.|x")
|
"\nIf you feel this ban is in error, please email an admin.|x"
|
||||||
)
|
)
|
||||||
errors.append(string)
|
errors.append(string)
|
||||||
return None, errors
|
return None, errors
|
||||||
|
|
@ -778,7 +782,9 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
errors.append(
|
errors.append(
|
||||||
_("There was an error creating the Account. If this problem persists, contact an admin.")
|
_(
|
||||||
|
"There was an error creating the Account. If this problem persists, contact an admin."
|
||||||
|
)
|
||||||
)
|
)
|
||||||
logger.log_trace()
|
logger.log_trace()
|
||||||
return None, errors
|
return None, errors
|
||||||
|
|
@ -802,7 +808,9 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
||||||
if account and settings.MULTISESSION_MODE < 2:
|
if account and settings.MULTISESSION_MODE < 2:
|
||||||
# Auto-create a character to go with this account
|
# Auto-create a character to go with this account
|
||||||
|
|
||||||
character, errs = account.create_character(typeclass=kwargs.get("character_typeclass"))
|
character, errs = account.create_character(
|
||||||
|
typeclass=kwargs.get("character_typeclass")
|
||||||
|
)
|
||||||
if errs:
|
if errs:
|
||||||
errors.extend(errs)
|
errors.extend(errs)
|
||||||
|
|
||||||
|
|
@ -990,9 +998,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
||||||
searchdata, categories=("account",), include_account=False
|
searchdata, categories=("account",), include_account=False
|
||||||
)
|
)
|
||||||
if search_object:
|
if search_object:
|
||||||
matches = ObjectDB.objects.object_search(
|
matches = ObjectDB.objects.object_search(searchdata, typeclass=typeclass)
|
||||||
searchdata, typeclass=typeclass
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
matches = AccountDB.objects.account_search(searchdata, typeclass=typeclass)
|
matches = AccountDB.objects.account_search(searchdata, typeclass=typeclass)
|
||||||
|
|
||||||
|
|
@ -1340,7 +1346,9 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
reason = f" ({reason if reason else ''})"
|
reason = f" ({reason if reason else ''})"
|
||||||
self._send_to_connect_channel(_("|R{key} disconnected{reason}|n").format(key=self.key, reason=reason))
|
self._send_to_connect_channel(
|
||||||
|
_("|R{key} disconnected{reason}|n").format(key=self.key, reason=reason)
|
||||||
|
)
|
||||||
|
|
||||||
def at_post_disconnect(self, **kwargs):
|
def at_post_disconnect(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
@ -1489,7 +1497,9 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
||||||
if is_su or len(characters) < charmax:
|
if is_su or len(characters) < charmax:
|
||||||
if not characters:
|
if not characters:
|
||||||
result.append(
|
result.append(
|
||||||
_("\n\n You don't have any characters yet. See |whelp @charcreate|n for creating one.")
|
_(
|
||||||
|
"\n\n You don't have any characters yet. See |whelp @charcreate|n for creating one."
|
||||||
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
result.append("\n |w@charcreate <name> [=description]|n - create new character")
|
result.append("\n |w@charcreate <name> [=description]|n - create new character")
|
||||||
|
|
|
||||||
|
|
@ -274,27 +274,28 @@ class AccountDBAdmin(BaseUserAdmin):
|
||||||
)
|
)
|
||||||
|
|
||||||
@sensitive_post_parameters_m
|
@sensitive_post_parameters_m
|
||||||
def user_change_password(self, request, id, form_url=''):
|
def user_change_password(self, request, id, form_url=""):
|
||||||
user = self.get_object(request, unquote(id))
|
user = self.get_object(request, unquote(id))
|
||||||
if not self.has_change_permission(request, user):
|
if not self.has_change_permission(request, user):
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
if user is None:
|
if user is None:
|
||||||
raise Http404('%(name)s object with primary key %(key)r does not exist.') % {
|
raise Http404("%(name)s object with primary key %(key)r does not exist.") % {
|
||||||
'name': self.model._meta.verbose_name,
|
"name": self.model._meta.verbose_name,
|
||||||
'key': escape(id),
|
"key": escape(id),
|
||||||
}
|
}
|
||||||
if request.method == 'POST':
|
if request.method == "POST":
|
||||||
form = self.change_password_form(user, request.POST)
|
form = self.change_password_form(user, request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
form.save()
|
form.save()
|
||||||
change_message = self.construct_change_message(request, form, None)
|
change_message = self.construct_change_message(request, form, None)
|
||||||
self.log_change(request, user, change_message)
|
self.log_change(request, user, change_message)
|
||||||
msg = 'Password changed successfully.'
|
msg = "Password changed successfully."
|
||||||
messages.success(request, msg)
|
messages.success(request, msg)
|
||||||
update_session_auth_hash(request, form.user)
|
update_session_auth_hash(request, form.user)
|
||||||
return HttpResponseRedirect(
|
return HttpResponseRedirect(
|
||||||
reverse(
|
reverse(
|
||||||
'%s:%s_%s_change' % (
|
"%s:%s_%s_change"
|
||||||
|
% (
|
||||||
self.admin_site.name,
|
self.admin_site.name,
|
||||||
user._meta.app_label,
|
user._meta.app_label,
|
||||||
# the model_name is something we need to hardcode
|
# the model_name is something we need to hardcode
|
||||||
|
|
@ -307,25 +308,24 @@ class AccountDBAdmin(BaseUserAdmin):
|
||||||
else:
|
else:
|
||||||
form = self.change_password_form(user)
|
form = self.change_password_form(user)
|
||||||
|
|
||||||
fieldsets = [(None, {'fields': list(form.base_fields)})]
|
fieldsets = [(None, {"fields": list(form.base_fields)})]
|
||||||
adminForm = admin.helpers.AdminForm(form, fieldsets, {})
|
adminForm = admin.helpers.AdminForm(form, fieldsets, {})
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'title': 'Change password: %s' % escape(user.get_username()),
|
"title": "Change password: %s" % escape(user.get_username()),
|
||||||
'adminForm': adminForm,
|
"adminForm": adminForm,
|
||||||
'form_url': form_url,
|
"form_url": form_url,
|
||||||
'form': form,
|
"form": form,
|
||||||
'is_popup': (IS_POPUP_VAR in request.POST or
|
"is_popup": (IS_POPUP_VAR in request.POST or IS_POPUP_VAR in request.GET),
|
||||||
IS_POPUP_VAR in request.GET),
|
"add": True,
|
||||||
'add': True,
|
"change": False,
|
||||||
'change': False,
|
"has_delete_permission": False,
|
||||||
'has_delete_permission': False,
|
"has_change_permission": True,
|
||||||
'has_change_permission': True,
|
"has_absolute_url": False,
|
||||||
'has_absolute_url': False,
|
"opts": self.model._meta,
|
||||||
'opts': self.model._meta,
|
"original": user,
|
||||||
'original': user,
|
"save_as": False,
|
||||||
'save_as': False,
|
"show_save": True,
|
||||||
'show_save': True,
|
|
||||||
**self.admin_site.each_context(request),
|
**self.admin_site.each_context(request),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -333,8 +333,7 @@ class AccountDBAdmin(BaseUserAdmin):
|
||||||
|
|
||||||
return TemplateResponse(
|
return TemplateResponse(
|
||||||
request,
|
request,
|
||||||
self.change_user_password_template or
|
self.change_user_password_template or "admin/auth/user/change_password.html",
|
||||||
'admin/auth/user/change_password.html',
|
|
||||||
context,
|
context,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -329,7 +329,9 @@ class IRCBot(Bot):
|
||||||
chstr = f"{self.db.irc_channel} ({self.db.irc_network}:{self.db.irc_port})"
|
chstr = f"{self.db.irc_channel} ({self.db.irc_network}:{self.db.irc_port})"
|
||||||
nicklist = ", ".join(sorted(kwargs["nicklist"], key=lambda n: n.lower()))
|
nicklist = ", ".join(sorted(kwargs["nicklist"], key=lambda n: n.lower()))
|
||||||
for obj in self._nicklist_callers:
|
for obj in self._nicklist_callers:
|
||||||
obj.msg(_("Nicks at {chstr}:\n {nicklist}").format(chstr=chstr, nicklist=nicklist))
|
obj.msg(
|
||||||
|
_("Nicks at {chstr}:\n {nicklist}").format(chstr=chstr, nicklist=nicklist)
|
||||||
|
)
|
||||||
self._nicklist_callers = []
|
self._nicklist_callers = []
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -338,7 +340,11 @@ class IRCBot(Bot):
|
||||||
if hasattr(self, "_ping_callers") and self._ping_callers:
|
if hasattr(self, "_ping_callers") and self._ping_callers:
|
||||||
chstr = f"{self.db.irc_channel} ({self.db.irc_network}:{self.db.irc_port})"
|
chstr = f"{self.db.irc_channel} ({self.db.irc_network}:{self.db.irc_port})"
|
||||||
for obj in self._ping_callers:
|
for obj in self._ping_callers:
|
||||||
obj.msg(_("IRC ping return from {chstr} took {time}s.").format(chstr=chstr, time=kwargs['timing']))
|
obj.msg(
|
||||||
|
_("IRC ping return from {chstr} took {time}s.").format(
|
||||||
|
chstr=chstr, time=kwargs["timing"]
|
||||||
|
)
|
||||||
|
)
|
||||||
self._ping_callers = []
|
self._ping_callers = []
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -109,8 +109,8 @@ class AccountDB(TypedObject, AbstractUser):
|
||||||
__applabel__ = "accounts"
|
__applabel__ = "accounts"
|
||||||
__settingsclasspath__ = settings.BASE_SCRIPT_TYPECLASS
|
__settingsclasspath__ = settings.BASE_SCRIPT_TYPECLASS
|
||||||
|
|
||||||
# class Meta:
|
# class Meta:
|
||||||
# verbose_name = "Account"
|
# verbose_name = "Account"
|
||||||
|
|
||||||
# cmdset_storage property
|
# cmdset_storage property
|
||||||
# This seems very sensitive to caching, so leaving it be for now /Griatch
|
# This seems very sensitive to caching, so leaving it be for now /Griatch
|
||||||
|
|
|
||||||
|
|
@ -743,7 +743,9 @@ def cmdhandler(
|
||||||
sysarg = raw_string
|
sysarg = raw_string
|
||||||
else:
|
else:
|
||||||
# fallback to default error text
|
# fallback to default error text
|
||||||
sysarg = _("Command '{command}' is not available.").format(command=raw_string)
|
sysarg = _("Command '{command}' is not available.").format(
|
||||||
|
command=raw_string
|
||||||
|
)
|
||||||
suggestions = string_suggestions(
|
suggestions = string_suggestions(
|
||||||
raw_string,
|
raw_string,
|
||||||
cmdset.get_all_cmd_keys_and_aliases(caller),
|
cmdset.get_all_cmd_keys_and_aliases(caller),
|
||||||
|
|
@ -751,7 +753,9 @@ def cmdhandler(
|
||||||
maxnum=3,
|
maxnum=3,
|
||||||
)
|
)
|
||||||
if suggestions:
|
if suggestions:
|
||||||
sysarg += _(" Maybe you meant {command}?").format(command=utils.list_to_string(suggestions, _("or"), addquote=True))
|
sysarg += _(" Maybe you meant {command}?").format(
|
||||||
|
command=utils.list_to_string(suggestions, _("or"), addquote=True)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
sysarg += _(' Type "help" for help.')
|
sysarg += _(' Type "help" for help.')
|
||||||
raise ExecSystemCommand(syscmd, sysarg)
|
raise ExecSystemCommand(syscmd, sysarg)
|
||||||
|
|
|
||||||
|
|
@ -184,7 +184,9 @@ def import_cmdset(path, cmdsetobj, emit_to_obj=None, no_logging=False):
|
||||||
raise exc.with_traceback(tb)
|
raise exc.with_traceback(tb)
|
||||||
else:
|
else:
|
||||||
# try next suggested path
|
# try next suggested path
|
||||||
errstring += _("\n(Unsuccessfully tried '{path}').").format(path=python_path)
|
errstring += _("\n(Unsuccessfully tried '{path}').").format(
|
||||||
|
path=python_path
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
cmdsetclass = getattr(module, classname)
|
cmdsetclass = getattr(module, classname)
|
||||||
|
|
@ -194,7 +196,9 @@ def import_cmdset(path, cmdsetobj, emit_to_obj=None, no_logging=False):
|
||||||
dum, dum, tb = sys.exc_info()
|
dum, dum, tb = sys.exc_info()
|
||||||
raise exc.with_traceback(tb)
|
raise exc.with_traceback(tb)
|
||||||
else:
|
else:
|
||||||
errstring += _("\n(Unsuccessfully tried '{path}').").format(path=python_path)
|
errstring += _("\n(Unsuccessfully tried '{path}').").format(
|
||||||
|
path=python_path
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
_CACHED_CMDSETS[python_path] = cmdsetclass
|
_CACHED_CMDSETS[python_path] = cmdsetclass
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -314,8 +314,12 @@ class CmdIC(COMMAND_DEFAULT_CLASS):
|
||||||
if account.db._playable_characters:
|
if account.db._playable_characters:
|
||||||
# look at the playable_characters list first
|
# look at the playable_characters list first
|
||||||
character_candidates.extend(
|
character_candidates.extend(
|
||||||
account.search(self.args, candidates=account.db._playable_characters,
|
account.search(
|
||||||
search_object=True, quiet=True)
|
self.args,
|
||||||
|
candidates=account.db._playable_characters,
|
||||||
|
search_object=True,
|
||||||
|
quiet=True,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if account.locks.check_lockstring(account, "perm(Builder)"):
|
if account.locks.check_lockstring(account, "perm(Builder)"):
|
||||||
|
|
@ -337,8 +341,12 @@ class CmdIC(COMMAND_DEFAULT_CLASS):
|
||||||
# fall back to global search only if Builder+ has no
|
# fall back to global search only if Builder+ has no
|
||||||
# playable_characers in list and is not standing in a room
|
# playable_characers in list and is not standing in a room
|
||||||
# with a matching char.
|
# with a matching char.
|
||||||
character_candidates.extend([
|
character_candidates.extend(
|
||||||
char for char in search.object_search(self.args) if char.access(account, "puppet")]
|
[
|
||||||
|
char
|
||||||
|
for char in search.object_search(self.args)
|
||||||
|
if char.access(account, "puppet")
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
# handle possible candidates
|
# handle possible candidates
|
||||||
|
|
|
||||||
|
|
@ -1459,7 +1459,12 @@ class CmdOpen(ObjManipCommand):
|
||||||
if not typeclass:
|
if not typeclass:
|
||||||
typeclass = settings.BASE_EXIT_TYPECLASS
|
typeclass = settings.BASE_EXIT_TYPECLASS
|
||||||
exit_obj = create.create_object(
|
exit_obj = create.create_object(
|
||||||
typeclass, key=exit_name, location=location, aliases=exit_aliases, locks=lockstring, report_to=caller
|
typeclass,
|
||||||
|
key=exit_name,
|
||||||
|
location=location,
|
||||||
|
aliases=exit_aliases,
|
||||||
|
locks=lockstring,
|
||||||
|
report_to=caller,
|
||||||
)
|
)
|
||||||
if exit_obj:
|
if exit_obj:
|
||||||
# storing a destination is what makes it an exit!
|
# storing a destination is what makes it an exit!
|
||||||
|
|
@ -2375,7 +2380,7 @@ class CmdExamine(ObjManipCommand):
|
||||||
value (any): Attribute value.
|
value (any): Attribute value.
|
||||||
Returns:
|
Returns:
|
||||||
"""
|
"""
|
||||||
if attr is None:
|
if attr is None:
|
||||||
return "No such attribute was found."
|
return "No such attribute was found."
|
||||||
value = utils.to_str(value)
|
value = utils.to_str(value)
|
||||||
if crop:
|
if crop:
|
||||||
|
|
@ -2413,13 +2418,14 @@ class CmdExamine(ObjManipCommand):
|
||||||
output = {}
|
output = {}
|
||||||
if db_attr and db_attr[0]:
|
if db_attr and db_attr[0]:
|
||||||
output["Persistent attribute(s)"] = "\n " + "\n ".join(
|
output["Persistent attribute(s)"] = "\n " + "\n ".join(
|
||||||
sorted(self.list_attribute(crop, attr, category, value)
|
sorted(
|
||||||
for attr, value, category in db_attr)
|
self.list_attribute(crop, attr, category, value)
|
||||||
|
for attr, value, category in db_attr
|
||||||
|
)
|
||||||
)
|
)
|
||||||
if ndb_attr and ndb_attr[0]:
|
if ndb_attr and ndb_attr[0]:
|
||||||
output["Non-Persistent attribute(s)"] = " \n" + " \n".join(
|
output["Non-Persistent attribute(s)"] = " \n" + " \n".join(
|
||||||
sorted(self.list_attribute(crop, attr, None, value)
|
sorted(self.list_attribute(crop, attr, None, value) for attr, value in ndb_attr)
|
||||||
for attr, value in ndb_attr)
|
|
||||||
)
|
)
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
@ -2449,7 +2455,7 @@ class CmdExamine(ObjManipCommand):
|
||||||
output["Typeclass"] = f"{obj.typename} ({obj.typeclass_path})"
|
output["Typeclass"] = f"{obj.typename} ({obj.typeclass_path})"
|
||||||
# sessions
|
# sessions
|
||||||
if hasattr(obj, "sessions") and obj.sessions.all():
|
if hasattr(obj, "sessions") and obj.sessions.all():
|
||||||
output["Session id(s)"] = ", ".join(f"#{sess.sessid}" for sess in obj.sessions.all())
|
output["Session id(s)"] = ", ".join(f"#{sess.sessid}" for sess in obj.sessions.all())
|
||||||
# email, if any
|
# email, if any
|
||||||
if hasattr(obj, "email") and obj.email:
|
if hasattr(obj, "email") and obj.email:
|
||||||
output["Email"] = f"{dclr}{obj.email}|n"
|
output["Email"] = f"{dclr}{obj.email}|n"
|
||||||
|
|
@ -2499,20 +2505,19 @@ class CmdExamine(ObjManipCommand):
|
||||||
locks = str(obj.locks)
|
locks = str(obj.locks)
|
||||||
if locks:
|
if locks:
|
||||||
locks_string = "\n" + utils.fill(
|
locks_string = "\n" + utils.fill(
|
||||||
"; ".join([lock for lock in locks.split(";")]), indent=2)
|
"; ".join([lock for lock in locks.split(";")]), indent=2
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
locks_string = " Default"
|
locks_string = " Default"
|
||||||
output["Locks"] = locks_string
|
output["Locks"] = locks_string
|
||||||
# cmdsets
|
# cmdsets
|
||||||
if not (len(obj.cmdset.all()) == 1 and obj.cmdset.current.key == "_EMPTY_CMDSET"):
|
if not (len(obj.cmdset.all()) == 1 and obj.cmdset.current.key == "_EMPTY_CMDSET"):
|
||||||
# all() returns a 'stack', so make a copy to sort.
|
# all() returns a 'stack', so make a copy to sort.
|
||||||
stored_cmdsets = sorted(obj.cmdset.all(), key=lambda x: x.priority,
|
stored_cmdsets = sorted(obj.cmdset.all(), key=lambda x: x.priority, reverse=True)
|
||||||
reverse=True)
|
output["Stored Cmdset(s)"] = "\n " + "\n ".join(
|
||||||
output["Stored Cmdset(s)"] = (
|
f"{cmdset.path} [{cmdset.key}] ({cmdset.mergetype}, prio {cmdset.priority})"
|
||||||
"\n " + "\n ".join(
|
for cmdset in stored_cmdsets
|
||||||
f"{cmdset.path} [{cmdset.key}] ({cmdset.mergetype}, prio {cmdset.priority})"
|
if cmdset.key != "_EMPTY_CMDSET"
|
||||||
for cmdset in stored_cmdsets if cmdset.key != "_EMPTY_CMDSET"
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# this gets all components of the currently merged set
|
# this gets all components of the currently merged set
|
||||||
|
|
@ -2546,11 +2551,9 @@ class CmdExamine(ObjManipCommand):
|
||||||
pass
|
pass
|
||||||
all_cmdsets = [cmdset for cmdset in dict(all_cmdsets).values()]
|
all_cmdsets = [cmdset for cmdset in dict(all_cmdsets).values()]
|
||||||
all_cmdsets.sort(key=lambda x: x.priority, reverse=True)
|
all_cmdsets.sort(key=lambda x: x.priority, reverse=True)
|
||||||
output["Merged Cmdset(s)"] = (
|
output["Merged Cmdset(s)"] = "\n " + "\n ".join(
|
||||||
"\n " + "\n ".join(
|
f"{cmdset.path} [{cmdset.key}] ({cmdset.mergetype} prio {cmdset.priority})"
|
||||||
f"{cmdset.path} [{cmdset.key}] ({cmdset.mergetype} prio {cmdset.priority})"
|
for cmdset in all_cmdsets
|
||||||
for cmdset in all_cmdsets
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
# list the commands available to this object
|
# list the commands available to this object
|
||||||
avail_cmdset = sorted([cmd.key for cmd in avail_cmdset if cmd.access(obj, "cmd")])
|
avail_cmdset = sorted([cmd.key for cmd in avail_cmdset if cmd.access(obj, "cmd")])
|
||||||
|
|
@ -2565,9 +2568,7 @@ class CmdExamine(ObjManipCommand):
|
||||||
# Tags
|
# Tags
|
||||||
tags = obj.tags.all(return_key_and_category=True)
|
tags = obj.tags.all(return_key_and_category=True)
|
||||||
tags_string = "\n" + utils.fill(
|
tags_string = "\n" + utils.fill(
|
||||||
", ".join(
|
", ".join(sorted(f"{tag}[{category}]" for tag, category in tags)), indent=2,
|
||||||
sorted(f"{tag}[{category}]" for tag, category in tags )),
|
|
||||||
indent=2,
|
|
||||||
)
|
)
|
||||||
if tags:
|
if tags:
|
||||||
output["Tags[category]"] = tags_string
|
output["Tags[category]"] = tags_string
|
||||||
|
|
@ -2584,9 +2585,13 @@ class CmdExamine(ObjManipCommand):
|
||||||
else:
|
else:
|
||||||
things.append(content)
|
things.append(content)
|
||||||
if exits:
|
if exits:
|
||||||
output["Exits (has .destination)"] = ", ".join(f"{exit.name}({exit.dbref})" for exit in exits)
|
output["Exits (has .destination)"] = ", ".join(
|
||||||
|
f"{exit.name}({exit.dbref})" for exit in exits
|
||||||
|
)
|
||||||
if pobjs:
|
if pobjs:
|
||||||
output["Characters"] = ", ".join(f"{dclr}{pobj.name}|n({pobj.dbref})" for pobj in pobjs)
|
output["Characters"] = ", ".join(
|
||||||
|
f"{dclr}{pobj.name}|n({pobj.dbref})" for pobj in pobjs
|
||||||
|
)
|
||||||
if things:
|
if things:
|
||||||
output["Contents"] = ", ".join(
|
output["Contents"] = ", ".join(
|
||||||
f"{cont.name}({cont.dbref})"
|
f"{cont.name}({cont.dbref})"
|
||||||
|
|
@ -2601,7 +2606,6 @@ class CmdExamine(ObjManipCommand):
|
||||||
mainstr = "\n".join(f"{hclr}{header}|n: {block}" for (header, block) in output.items())
|
mainstr = "\n".join(f"{hclr}{header}|n: {block}" for (header, block) in output.items())
|
||||||
return f"{sep}\n{mainstr}\n{sep}"
|
return f"{sep}\n{mainstr}\n{sep}"
|
||||||
|
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
"""Process command"""
|
"""Process command"""
|
||||||
caller = self.caller
|
caller = self.caller
|
||||||
|
|
@ -2671,7 +2675,10 @@ class CmdExamine(ObjManipCommand):
|
||||||
# we are only interested in specific attributes
|
# we are only interested in specific attributes
|
||||||
ret = "\n".join(
|
ret = "\n".join(
|
||||||
f"{self.header_color}{header}|n:{value}"
|
f"{self.header_color}{header}|n:{value}"
|
||||||
for header, value in self.format_attributes(obj, attrname, crop=False).items())
|
for header, value in self.format_attributes(
|
||||||
|
obj, attrname, crop=False
|
||||||
|
).items()
|
||||||
|
)
|
||||||
self.caller.msg(ret)
|
self.caller.msg(ret)
|
||||||
else:
|
else:
|
||||||
session = None
|
session = None
|
||||||
|
|
|
||||||
|
|
@ -431,7 +431,9 @@ class CmdGet(COMMAND_DEFAULT_CLASS):
|
||||||
caller.msg("This can't be picked up.")
|
caller.msg("This can't be picked up.")
|
||||||
else:
|
else:
|
||||||
caller.msg("You pick up %s." % obj.name)
|
caller.msg("You pick up %s." % obj.name)
|
||||||
caller.location.msg_contents("%s picks up %s." % (caller.name, obj.name), exclude=caller)
|
caller.location.msg_contents(
|
||||||
|
"%s picks up %s." % (caller.name, obj.name), exclude=caller
|
||||||
|
)
|
||||||
# calling at_get hook method
|
# calling at_get hook method
|
||||||
obj.at_get(caller)
|
obj.at_get(caller)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -446,7 +446,9 @@ def format_script_list(scripts):
|
||||||
|
|
||||||
table.add_row(
|
table.add_row(
|
||||||
script.id,
|
script.id,
|
||||||
f"{script.obj.key}({script.obj.dbref})" if (hasattr(script, "obj") and script.obj) else "<Global>",
|
f"{script.obj.key}({script.obj.dbref})"
|
||||||
|
if (hasattr(script, "obj") and script.obj)
|
||||||
|
else "<Global>",
|
||||||
script.key,
|
script.key,
|
||||||
script.interval if script.interval > 0 else "--",
|
script.interval if script.interval > 0 else "--",
|
||||||
nextrep,
|
nextrep,
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,7 @@ class CommandTest(EvenniaTest):
|
||||||
prt = ""
|
prt = ""
|
||||||
for ic, char in enumerate(msg):
|
for ic, char in enumerate(msg):
|
||||||
import re
|
import re
|
||||||
|
|
||||||
prt += char
|
prt += char
|
||||||
|
|
||||||
sep1 = "\n" + "=" * 30 + "Wanted message" + "=" * 34 + "\n"
|
sep1 = "\n" + "=" * 30 + "Wanted message" + "=" * 34 + "\n"
|
||||||
|
|
@ -369,11 +370,13 @@ class TestAccount(CommandTest):
|
||||||
def test_ic__nonaccess(self):
|
def test_ic__nonaccess(self):
|
||||||
self.account.unpuppet_object(self.session)
|
self.account.unpuppet_object(self.session)
|
||||||
self.call(
|
self.call(
|
||||||
account.CmdIC(), "Nonexistent", "That is not a valid character choice.",
|
account.CmdIC(),
|
||||||
caller=self.account, receiver=self.account
|
"Nonexistent",
|
||||||
|
"That is not a valid character choice.",
|
||||||
|
caller=self.account,
|
||||||
|
receiver=self.account,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_password(self):
|
def test_password(self):
|
||||||
self.call(
|
self.call(
|
||||||
account.CmdPassword(),
|
account.CmdPassword(),
|
||||||
|
|
@ -485,7 +488,11 @@ class TestBuilding(CommandTest):
|
||||||
|
|
||||||
# escape inlinefuncs
|
# escape inlinefuncs
|
||||||
self.char1.db.test2 = "this is a $random() value."
|
self.char1.db.test2 = "this is a $random() value."
|
||||||
self.call(building.CmdExamine(), "self/test2", "Persistent attribute(s):\n test2 = this is a \$random() value.")
|
self.call(
|
||||||
|
building.CmdExamine(),
|
||||||
|
"self/test2",
|
||||||
|
"Persistent attribute(s):\n test2 = this is a \$random() value.",
|
||||||
|
)
|
||||||
|
|
||||||
self.room1.scripts.add(self.script.__class__)
|
self.room1.scripts.add(self.script.__class__)
|
||||||
self.call(building.CmdExamine(), "")
|
self.call(building.CmdExamine(), "")
|
||||||
|
|
|
||||||
|
|
@ -611,7 +611,6 @@ class CmdUsePuzzleParts(MuxCommand):
|
||||||
passed in.
|
passed in.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
key = "use"
|
key = "use"
|
||||||
aliases = "combine"
|
aliases = "combine"
|
||||||
locks = "cmd:pperm(use) or pperm(Player)"
|
locks = "cmd:pperm(use) or pperm(Player)"
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,9 @@ class HelpEntryManager(TypedObjectManager):
|
||||||
for topic in topics:
|
for topic in topics:
|
||||||
topic.help_category = default_category
|
topic.help_category = default_category
|
||||||
topic.save()
|
topic.save()
|
||||||
string = _("Help database moved to category {default_category}").format(default_category=default_category)
|
string = _("Help database moved to category {default_category}").format(
|
||||||
|
default_category=default_category
|
||||||
|
)
|
||||||
logger.log_info(string)
|
logger.log_info(string)
|
||||||
|
|
||||||
def search_help(self, ostring, help_category=None):
|
def search_help(self, ostring, help_category=None):
|
||||||
|
|
|
||||||
|
|
@ -236,7 +236,13 @@ class LockHandler(object):
|
||||||
elist.append(_("Lock: lock-function '%s' is not available.") % funcstring)
|
elist.append(_("Lock: lock-function '%s' is not available.") % funcstring)
|
||||||
continue
|
continue
|
||||||
args = list(arg.strip() for arg in rest.split(",") if arg and "=" not in arg)
|
args = list(arg.strip() for arg in rest.split(",") if arg and "=" not in arg)
|
||||||
kwargs = dict([(part.strip() for part in arg.split("=", 1)) for arg in rest.split(",") if arg and "=" in arg])
|
kwargs = dict(
|
||||||
|
[
|
||||||
|
(part.strip() for part in arg.split("=", 1))
|
||||||
|
for arg in rest.split(",")
|
||||||
|
if arg and "=" in arg
|
||||||
|
]
|
||||||
|
)
|
||||||
lock_funcs.append((func, args, kwargs))
|
lock_funcs.append((func, args, kwargs))
|
||||||
evalstring = evalstring.replace(funcstring, "%s")
|
evalstring = evalstring.replace(funcstring, "%s")
|
||||||
if len(lock_funcs) < nfuncs:
|
if len(lock_funcs) < nfuncs:
|
||||||
|
|
@ -246,7 +252,11 @@ class LockHandler(object):
|
||||||
evalstring = " ".join(_RE_OK.findall(evalstring))
|
evalstring = " ".join(_RE_OK.findall(evalstring))
|
||||||
eval(evalstring % tuple(True for func in funclist), {}, {})
|
eval(evalstring % tuple(True for func in funclist), {}, {})
|
||||||
except Exception:
|
except Exception:
|
||||||
elist.append(_("Lock: definition '{lock_string}' has syntax errors.").format(lock_string=raw_lockstring))
|
elist.append(
|
||||||
|
_("Lock: definition '{lock_string}' has syntax errors.").format(
|
||||||
|
lock_string=raw_lockstring
|
||||||
|
)
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
if access_type in locks:
|
if access_type in locks:
|
||||||
duplicates += 1
|
duplicates += 1
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ from evennia.objects.models import ObjectDB
|
||||||
from django.contrib.admin.utils import flatten_fieldsets
|
from django.contrib.admin.utils import flatten_fieldsets
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
|
|
||||||
class ObjectAttributeInline(AttributeInline):
|
class ObjectAttributeInline(AttributeInline):
|
||||||
"""
|
"""
|
||||||
Defines inline descriptions of Attributes (experimental)
|
Defines inline descriptions of Attributes (experimental)
|
||||||
|
|
@ -61,7 +62,7 @@ class ObjectCreateForm(forms.ModelForm):
|
||||||
required=False,
|
required=False,
|
||||||
widget=forms.TextInput(attrs={"size": "78"}),
|
widget=forms.TextInput(attrs={"size": "78"}),
|
||||||
help_text="Most non-character objects don't need a cmdset"
|
help_text="Most non-character objects don't need a cmdset"
|
||||||
" and can leave this field blank."
|
" and can leave this field blank.",
|
||||||
)
|
)
|
||||||
raw_id_fields = ("db_destination", "db_location", "db_home")
|
raw_id_fields = ("db_destination", "db_location", "db_home")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -175,15 +175,12 @@ class ObjectDBManager(TypedObjectManager):
|
||||||
)
|
)
|
||||||
type_restriction = typeclasses and Q(db_typeclass_path__in=make_iter(typeclasses)) or Q()
|
type_restriction = typeclasses and Q(db_typeclass_path__in=make_iter(typeclasses)) or Q()
|
||||||
|
|
||||||
results = (
|
results = self.filter(
|
||||||
self
|
cand_restriction
|
||||||
.filter(
|
& type_restriction
|
||||||
cand_restriction
|
& Q(db_attributes__db_key=attribute_name)
|
||||||
& type_restriction
|
& Q(db_attributes__db_value=attribute_value)
|
||||||
& Q(db_attributes__db_key=attribute_name)
|
).order_by("id")
|
||||||
& Q(db_attributes__db_value=attribute_value))
|
|
||||||
.order_by("id")
|
|
||||||
)
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def get_objs_with_db_property(self, property_name, candidates=None):
|
def get_objs_with_db_property(self, property_name, candidates=None):
|
||||||
|
|
|
||||||
|
|
@ -2028,8 +2028,10 @@ class DefaultCharacter(DefaultObject):
|
||||||
|
|
||||||
# lockstring of newly created rooms, for easy overloading.
|
# lockstring of newly created rooms, for easy overloading.
|
||||||
# Will be formatted with the appropriate attributes.
|
# Will be formatted with the appropriate attributes.
|
||||||
lockstring = ("puppet:id({character_id}) or pid({account_id}) or perm(Developer) or pperm(Developer);"
|
lockstring = (
|
||||||
"delete:id({account_id}) or perm(Admin)")
|
"puppet:id({character_id}) or pid({account_id}) or perm(Developer) or pperm(Developer);"
|
||||||
|
"delete:id({account_id}) or perm(Admin)"
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, key, account=None, **kwargs):
|
def create(cls, key, account=None, **kwargs):
|
||||||
|
|
|
||||||
|
|
@ -467,7 +467,11 @@ def getKeyPair(pubkeyfile, privkeyfile):
|
||||||
from cryptography.hazmat.backends import default_backend
|
from cryptography.hazmat.backends import default_backend
|
||||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||||
|
|
||||||
rsa_key = Key(rsa.generate_private_key(public_exponent=65537, key_size=_KEY_LENGTH, backend=default_backend()))
|
rsa_key = Key(
|
||||||
|
rsa.generate_private_key(
|
||||||
|
public_exponent=65537, key_size=_KEY_LENGTH, backend=default_backend()
|
||||||
|
)
|
||||||
|
)
|
||||||
public_key_string = rsa_key.public().toString(type="OPENSSH").decode()
|
public_key_string = rsa_key.public().toString(type="OPENSSH").decode()
|
||||||
private_key_string = rsa_key.toString(type="OPENSSH").decode()
|
private_key_string = rsa_key.toString(type="OPENSSH").decode()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from django.utils.unittest import TestCase
|
from django.utils.unittest import TestCase
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
|
@ -290,7 +289,7 @@ class TestWebSocket(EvenniaTest):
|
||||||
self.proto.sessionhandler = PORTAL_SESSIONS
|
self.proto.sessionhandler = PORTAL_SESSIONS
|
||||||
self.proto.sessionhandler.portal = Mock()
|
self.proto.sessionhandler.portal = Mock()
|
||||||
self.proto.transport = proto_helpers.StringTransport()
|
self.proto.transport = proto_helpers.StringTransport()
|
||||||
#self.proto.transport = proto_helpers.FakeDatagramTransport()
|
# self.proto.transport = proto_helpers.FakeDatagramTransport()
|
||||||
self.proto.transport.client = ["localhost"]
|
self.proto.transport.client = ["localhost"]
|
||||||
self.proto.transport.setTcpKeepAlive = Mock()
|
self.proto.transport.setTcpKeepAlive = Mock()
|
||||||
self.proto.state = MagicMock()
|
self.proto.state = MagicMock()
|
||||||
|
|
@ -318,4 +317,4 @@ class TestWebSocket(EvenniaTest):
|
||||||
self.proto.sendLine = MagicMock()
|
self.proto.sendLine = MagicMock()
|
||||||
msg = json.dumps(["logged_in", (), {}])
|
msg = json.dumps(["logged_in", (), {}])
|
||||||
self.proto.sessionhandler.data_out(self.proto, text=[["Excepting Alice"], {}])
|
self.proto.sessionhandler.data_out(self.proto, text=[["Excepting Alice"], {}])
|
||||||
self.proto.sendLine.assert_called_with(json.dumps(['text', ['Excepting Alice'], {}]))
|
self.proto.sendLine.assert_called_with(json.dumps(["text", ["Excepting Alice"], {}]))
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@ def _server_maintenance():
|
||||||
else:
|
else:
|
||||||
# adjust the runtime not with 60s but with the actual elapsed time
|
# adjust the runtime not with 60s but with the actual elapsed time
|
||||||
# in case this may varies slightly from 60s.
|
# in case this may varies slightly from 60s.
|
||||||
_GAMETIME_MODULE.SERVER_RUNTIME += (now - _LAST_SERVER_TIME_SNAPSHOT)
|
_GAMETIME_MODULE.SERVER_RUNTIME += now - _LAST_SERVER_TIME_SNAPSHOT
|
||||||
_LAST_SERVER_TIME_SNAPSHOT = now
|
_LAST_SERVER_TIME_SNAPSHOT = now
|
||||||
|
|
||||||
# update game time and save it across reloads
|
# update game time and save it across reloads
|
||||||
|
|
|
||||||
|
|
@ -221,9 +221,7 @@ class SessionHandler(dict):
|
||||||
elif isinstance(data, (str, bytes)):
|
elif isinstance(data, (str, bytes)):
|
||||||
data = _utf8(data)
|
data = _utf8(data)
|
||||||
|
|
||||||
if (_INLINEFUNC_ENABLED
|
if _INLINEFUNC_ENABLED and not raw and isinstance(self, ServerSessionHandler):
|
||||||
and not raw
|
|
||||||
and isinstance(self, ServerSessionHandler)):
|
|
||||||
# only parse inlinefuncs on the outgoing path (sessionhandler->)
|
# only parse inlinefuncs on the outgoing path (sessionhandler->)
|
||||||
data = parse_inlinefunc(data, strip=strip_inlinefunc, session=session)
|
data = parse_inlinefunc(data, strip=strip_inlinefunc, session=session)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ class EvenniaTestSuiteRunner(DiscoverRunner):
|
||||||
# can't mock it - instead we stop it before starting the test - otherwise
|
# can't mock it - instead we stop it before starting the test - otherwise
|
||||||
# we'd get unclean reactor errors across test boundaries.
|
# we'd get unclean reactor errors across test boundaries.
|
||||||
from evennia.server.portal.portal import PORTAL
|
from evennia.server.portal.portal import PORTAL
|
||||||
|
|
||||||
PORTAL.maintenance_task.stop()
|
PORTAL.maintenance_task.stop()
|
||||||
|
|
||||||
import evennia
|
import evennia
|
||||||
|
|
@ -34,4 +35,3 @@ class EvenniaTestSuiteRunner(DiscoverRunner):
|
||||||
return super(EvenniaTestSuiteRunner, self).build_suite(
|
return super(EvenniaTestSuiteRunner, self).build_suite(
|
||||||
test_labels, extra_tests=extra_tests, **kwargs
|
test_labels, extra_tests=extra_tests, **kwargs
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,14 +31,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
|
||||||
|
|
||||||
# Attribute manager methods
|
# Attribute manager methods
|
||||||
def get_attribute(
|
def get_attribute(
|
||||||
self,
|
self, key=None, category=None, value=None, strvalue=None, obj=None, attrtype=None, **kwargs
|
||||||
key=None,
|
|
||||||
category=None,
|
|
||||||
value=None,
|
|
||||||
strvalue=None,
|
|
||||||
obj=None,
|
|
||||||
attrtype=None,
|
|
||||||
**kwargs
|
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Return Attribute objects by key, by category, by value, by
|
Return Attribute objects by key, by category, by value, by
|
||||||
|
|
@ -82,9 +75,9 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
|
||||||
# no reason to make strvalue/value mutually exclusive at this level
|
# no reason to make strvalue/value mutually exclusive at this level
|
||||||
query.append(("attribute__db_value", value))
|
query.append(("attribute__db_value", value))
|
||||||
return Attribute.objects.filter(
|
return Attribute.objects.filter(
|
||||||
pk__in=self.model.db_attributes.through.objects.filter(
|
pk__in=self.model.db_attributes.through.objects.filter(**dict(query)).values_list(
|
||||||
**dict(query)
|
"attribute_id", flat=True
|
||||||
).values_list("attribute_id", flat=True)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_nick(self, key=None, category=None, value=None, strvalue=None, obj=None):
|
def get_nick(self, key=None, category=None, value=None, strvalue=None, obj=None):
|
||||||
|
|
@ -111,13 +104,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_by_attribute(
|
def get_by_attribute(
|
||||||
self,
|
self, key=None, category=None, value=None, strvalue=None, attrtype=None, **kwargs
|
||||||
key=None,
|
|
||||||
category=None,
|
|
||||||
value=None,
|
|
||||||
strvalue=None,
|
|
||||||
attrtype=None,
|
|
||||||
**kwargs
|
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Return objects having attributes with the given key, category,
|
Return objects having attributes with the given key, category,
|
||||||
|
|
@ -174,15 +161,11 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
|
||||||
obj (list): Objects having the matching Nicks.
|
obj (list): Objects having the matching Nicks.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.get_by_attribute(
|
return self.get_by_attribute(key=key, category=category, strvalue=nick, attrtype="nick")
|
||||||
key=key, category=category, strvalue=nick, attrtype="nick"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Tag manager methods
|
# Tag manager methods
|
||||||
|
|
||||||
def get_tag(
|
def get_tag(self, key=None, category=None, obj=None, tagtype=None, global_search=False):
|
||||||
self, key=None, category=None, obj=None, tagtype=None, global_search=False
|
|
||||||
):
|
|
||||||
"""
|
"""
|
||||||
Return Tag objects by key, by category, by object (it is
|
Return Tag objects by key, by category, by object (it is
|
||||||
stored on) or with a combination of those criteria.
|
stored on) or with a combination of those criteria.
|
||||||
|
|
@ -226,9 +209,9 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
|
||||||
if category:
|
if category:
|
||||||
query.append(("tag__db_category", category))
|
query.append(("tag__db_category", category))
|
||||||
return Tag.objects.filter(
|
return Tag.objects.filter(
|
||||||
pk__in=self.model.db_tags.through.objects.filter(
|
pk__in=self.model.db_tags.through.objects.filter(**dict(query)).values_list(
|
||||||
**dict(query)
|
"tag_id", flat=True
|
||||||
).values_list("tag_id", flat=True)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_permission(self, key=None, category=None, obj=None):
|
def get_permission(self, key=None, category=None, obj=None):
|
||||||
|
|
@ -310,9 +293,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
|
||||||
|
|
||||||
dbmodel = self.model.__dbclass__.__name__.lower()
|
dbmodel = self.model.__dbclass__.__name__.lower()
|
||||||
query = (
|
query = (
|
||||||
self.filter(
|
self.filter(db_tags__db_tagtype__iexact=tagtype, db_tags__db_model__iexact=dbmodel)
|
||||||
db_tags__db_tagtype__iexact=tagtype, db_tags__db_model__iexact=dbmodel
|
|
||||||
)
|
|
||||||
.distinct()
|
.distinct()
|
||||||
.order_by("id")
|
.order_by("id")
|
||||||
)
|
)
|
||||||
|
|
@ -332,9 +313,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
|
||||||
clauses = Q()
|
clauses = Q()
|
||||||
for ikey, key in enumerate(keys):
|
for ikey, key in enumerate(keys):
|
||||||
# ANY mode; must match any one of the given tags/categories
|
# ANY mode; must match any one of the given tags/categories
|
||||||
clauses |= Q(
|
clauses |= Q(db_key__iexact=key, db_category__iexact=categories[ikey])
|
||||||
db_key__iexact=key, db_category__iexact=categories[ikey]
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
# only one or more categories given
|
# only one or more categories given
|
||||||
clauses = Q()
|
clauses = Q()
|
||||||
|
|
@ -344,8 +323,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
|
||||||
|
|
||||||
tags = _Tag.objects.filter(clauses)
|
tags = _Tag.objects.filter(clauses)
|
||||||
query = query.filter(db_tags__in=tags).annotate(
|
query = query.filter(db_tags__in=tags).annotate(
|
||||||
matches=Count("db_tags__pk", filter=Q(db_tags__in=tags),
|
matches=Count("db_tags__pk", filter=Q(db_tags__in=tags), distinct=True)
|
||||||
distinct=True)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if anymatch:
|
if anymatch:
|
||||||
|
|
@ -412,9 +390,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
|
||||||
# try to get old tag
|
# try to get old tag
|
||||||
|
|
||||||
dbmodel = self.model.__dbclass__.__name__.lower()
|
dbmodel = self.model.__dbclass__.__name__.lower()
|
||||||
tag = self.get_tag(
|
tag = self.get_tag(key=key, category=category, tagtype=tagtype, global_search=True)
|
||||||
key=key, category=category, tagtype=tagtype, global_search=True
|
|
||||||
)
|
|
||||||
if tag and data is not None:
|
if tag and data is not None:
|
||||||
# get tag from list returned by get_tag
|
# get tag from list returned by get_tag
|
||||||
tag = tag[0]
|
tag = tag[0]
|
||||||
|
|
@ -428,9 +404,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
|
||||||
from evennia.typeclasses.models import Tag as _Tag
|
from evennia.typeclasses.models import Tag as _Tag
|
||||||
tag = _Tag.objects.create(
|
tag = _Tag.objects.create(
|
||||||
db_key=key.strip().lower() if key is not None else None,
|
db_key=key.strip().lower() if key is not None else None,
|
||||||
db_category=category.strip().lower()
|
db_category=category.strip().lower() if category and key is not None else None,
|
||||||
if category and key is not None
|
|
||||||
else None,
|
|
||||||
db_data=data,
|
db_data=data,
|
||||||
db_model=dbmodel,
|
db_model=dbmodel,
|
||||||
db_tagtype=tagtype.strip().lower() if tagtype is not None else None,
|
db_tagtype=tagtype.strip().lower() if tagtype is not None else None,
|
||||||
|
|
@ -539,8 +513,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
|
||||||
typeclass=F("db_typeclass_path"),
|
typeclass=F("db_typeclass_path"),
|
||||||
# Calculate this class' percentage of total composition
|
# Calculate this class' percentage of total composition
|
||||||
percent=ExpressionWrapper(
|
percent=ExpressionWrapper(
|
||||||
((F("count") / float(self.count())) * 100.0),
|
((F("count") / float(self.count())) * 100.0), output_field=FloatField(),
|
||||||
output_field=FloatField(),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.values("typeclass", "count", "percent")
|
.values("typeclass", "count", "percent")
|
||||||
|
|
@ -560,9 +533,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
|
||||||
stats = self.get_typeclass_totals().order_by("typeclass")
|
stats = self.get_typeclass_totals().order_by("typeclass")
|
||||||
return {x.get("typeclass"): x.get("count") for x in stats}
|
return {x.get("typeclass"): x.get("count") for x in stats}
|
||||||
|
|
||||||
def typeclass_search(
|
def typeclass_search(self, typeclass, include_children=False, include_parents=False):
|
||||||
self, typeclass, include_children=False, include_parents=False
|
|
||||||
):
|
|
||||||
"""
|
"""
|
||||||
Searches through all objects returning those which has a
|
Searches through all objects returning those which has a
|
||||||
certain typeclass. If location is set, limit search to objects
|
certain typeclass. If location is set, limit search to objects
|
||||||
|
|
@ -837,8 +808,7 @@ class TypeclassManager(TypedObjectManager):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
paths = [self.model.path] + [
|
paths = [self.model.path] + [
|
||||||
"%s.%s" % (cls.__module__, cls.__name__)
|
"%s.%s" % (cls.__module__, cls.__name__) for cls in self._get_subclasses(self.model)
|
||||||
for cls in self._get_subclasses(self.model)
|
|
||||||
]
|
]
|
||||||
kwargs.update({"db_typeclass_path__in": paths})
|
kwargs.update({"db_typeclass_path__in": paths})
|
||||||
return super().get(**kwargs)
|
return super().get(**kwargs)
|
||||||
|
|
@ -860,8 +830,7 @@ class TypeclassManager(TypedObjectManager):
|
||||||
"""
|
"""
|
||||||
# query, including all subclasses
|
# query, including all subclasses
|
||||||
paths = [self.model.path] + [
|
paths = [self.model.path] + [
|
||||||
"%s.%s" % (cls.__module__, cls.__name__)
|
"%s.%s" % (cls.__module__, cls.__name__) for cls in self._get_subclasses(self.model)
|
||||||
for cls in self._get_subclasses(self.model)
|
|
||||||
]
|
]
|
||||||
kwargs.update({"db_typeclass_path__in": paths})
|
kwargs.update({"db_typeclass_path__in": paths})
|
||||||
return super().filter(*args, **kwargs)
|
return super().filter(*args, **kwargs)
|
||||||
|
|
@ -876,7 +845,6 @@ class TypeclassManager(TypedObjectManager):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
paths = [self.model.path] + [
|
paths = [self.model.path] + [
|
||||||
"%s.%s" % (cls.__module__, cls.__name__)
|
"%s.%s" % (cls.__module__, cls.__name__) for cls in self._get_subclasses(self.model)
|
||||||
for cls in self._get_subclasses(self.model)
|
|
||||||
]
|
]
|
||||||
return super().all().filter(db_typeclass_path__in=paths)
|
return super().all().filter(db_typeclass_path__in=paths)
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,6 @@ class TypeclassBase(SharedMemoryModelBase):
|
||||||
if not dbmodel:
|
if not dbmodel:
|
||||||
raise TypeError(f"{name} does not appear to inherit from a database model.")
|
raise TypeError(f"{name} does not appear to inherit from a database model.")
|
||||||
|
|
||||||
|
|
||||||
# typeclass proxy setup
|
# typeclass proxy setup
|
||||||
# first check explicit __applabel__ on the typeclass, then figure
|
# first check explicit __applabel__ on the typeclass, then figure
|
||||||
# it out from the dbmodel
|
# it out from the dbmodel
|
||||||
|
|
@ -135,6 +134,7 @@ class TypeclassBase(SharedMemoryModelBase):
|
||||||
attrs["__applabel__"] = dbmodel._meta.app_label
|
attrs["__applabel__"] = dbmodel._meta.app_label
|
||||||
|
|
||||||
if "Meta" not in attrs:
|
if "Meta" not in attrs:
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
proxy = True
|
proxy = True
|
||||||
app_label = attrs.get("__applabel__", "typeclasses")
|
app_label = attrs.get("__applabel__", "typeclasses")
|
||||||
|
|
@ -156,8 +156,7 @@ class TypeclassBase(SharedMemoryModelBase):
|
||||||
|
|
||||||
# attach signals
|
# attach signals
|
||||||
signals.post_save.connect(call_at_first_save, sender=new_class)
|
signals.post_save.connect(call_at_first_save, sender=new_class)
|
||||||
signals.pre_delete.connect(
|
signals.pre_delete.connect(remove_attributes_on_delete, sender=new_class)
|
||||||
remove_attributes_on_delete, sender=new_class)
|
|
||||||
return new_class
|
return new_class
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,10 +43,12 @@ class TestAttributes(EvenniaTest):
|
||||||
self.assertEqual(self.obj1.attributes.get(key), value)
|
self.assertEqual(self.obj1.attributes.get(key), value)
|
||||||
|
|
||||||
def test_batch_add(self):
|
def test_batch_add(self):
|
||||||
attrs = [("key1", "value1"),
|
attrs = [
|
||||||
("key2", "value2", "category2"),
|
("key1", "value1"),
|
||||||
("key3", "value3"),
|
("key2", "value2", "category2"),
|
||||||
("key4", "value4", "category4", "attrread:id(1)", False)]
|
("key3", "value3"),
|
||||||
|
("key4", "value4", "category4", "attrread:id(1)", False),
|
||||||
|
]
|
||||||
new_attrs = self.obj1.attributes.batch_add(*attrs)
|
new_attrs = self.obj1.attributes.batch_add(*attrs)
|
||||||
attrobj = self.obj1.attributes.get(key="key4", category="category4", return_obj=True)
|
attrobj = self.obj1.attributes.get(key="key4", category="category4", return_obj=True)
|
||||||
self.assertEqual(attrobj.value, "value4")
|
self.assertEqual(attrobj.value, "value4")
|
||||||
|
|
@ -69,16 +71,12 @@ class TestTypedObjectManager(EvenniaTest):
|
||||||
self.obj2.tags.add("tag4")
|
self.obj2.tags.add("tag4")
|
||||||
self.obj2.tags.add("tag2c")
|
self.obj2.tags.add("tag2c")
|
||||||
self.assertEqual(self._manager("get_by_tag", "tag1"), [self.obj1])
|
self.assertEqual(self._manager("get_by_tag", "tag1"), [self.obj1])
|
||||||
self.assertEqual(
|
self.assertEqual(set(self._manager("get_by_tag", "tag2")), set([self.obj1, self.obj2]))
|
||||||
set(self._manager("get_by_tag", "tag2")), set([self.obj1, self.obj2])
|
|
||||||
)
|
|
||||||
self.assertEqual(self._manager("get_by_tag", "tag2a"), [self.obj2])
|
self.assertEqual(self._manager("get_by_tag", "tag2a"), [self.obj2])
|
||||||
self.assertEqual(self._manager("get_by_tag", "tag3 with spaces"), [self.obj2])
|
self.assertEqual(self._manager("get_by_tag", "tag3 with spaces"), [self.obj2])
|
||||||
self.assertEqual(self._manager("get_by_tag", ["tag2a", "tag2b"]), [self.obj2])
|
self.assertEqual(self._manager("get_by_tag", ["tag2a", "tag2b"]), [self.obj2])
|
||||||
self.assertEqual(self._manager("get_by_tag", ["tag2a", "tag1"]), [])
|
self.assertEqual(self._manager("get_by_tag", ["tag2a", "tag1"]), [])
|
||||||
self.assertEqual(
|
self.assertEqual(self._manager("get_by_tag", ["tag2a", "tag4", "tag2c"]), [self.obj2])
|
||||||
self._manager("get_by_tag", ["tag2a", "tag4", "tag2c"]), [self.obj2]
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_get_by_tag_and_category(self):
|
def test_get_by_tag_and_category(self):
|
||||||
self.obj1.tags.add("tag5", "category1")
|
self.obj1.tags.add("tag5", "category1")
|
||||||
|
|
@ -94,24 +92,17 @@ class TestTypedObjectManager(EvenniaTest):
|
||||||
self.obj1.tags.add("tag8", "category6")
|
self.obj1.tags.add("tag8", "category6")
|
||||||
self.obj2.tags.add("tag9", "category6")
|
self.obj2.tags.add("tag9", "category6")
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(self._manager("get_by_tag", "tag5", "category1"), [self.obj1, self.obj2])
|
||||||
self._manager("get_by_tag", "tag5", "category1"), [self.obj1, self.obj2]
|
|
||||||
)
|
|
||||||
self.assertEqual(self._manager("get_by_tag", "tag6", "category1"), [])
|
self.assertEqual(self._manager("get_by_tag", "tag6", "category1"), [])
|
||||||
self.assertEqual(
|
self.assertEqual(self._manager("get_by_tag", "tag6", "category3"), [self.obj1, self.obj2])
|
||||||
self._manager("get_by_tag", "tag6", "category3"), [self.obj1, self.obj2]
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self._manager("get_by_tag", ["tag5", "tag6"], ["category1", "category3"]),
|
self._manager("get_by_tag", ["tag5", "tag6"], ["category1", "category3"]),
|
||||||
[self.obj1, self.obj2],
|
[self.obj1, self.obj2],
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self._manager("get_by_tag", ["tag5", "tag7"], "category1"),
|
self._manager("get_by_tag", ["tag5", "tag7"], "category1"), [self.obj1, self.obj2],
|
||||||
[self.obj1, self.obj2],
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
self._manager("get_by_tag", category="category1"), [self.obj1, self.obj2]
|
|
||||||
)
|
)
|
||||||
|
self.assertEqual(self._manager("get_by_tag", category="category1"), [self.obj1, self.obj2])
|
||||||
self.assertEqual(self._manager("get_by_tag", category="category2"), [self.obj2])
|
self.assertEqual(self._manager("get_by_tag", category="category2"), [self.obj2])
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self._manager("get_by_tag", category=["category1", "category3"]),
|
self._manager("get_by_tag", category=["category1", "category3"]),
|
||||||
|
|
@ -121,49 +112,33 @@ class TestTypedObjectManager(EvenniaTest):
|
||||||
self._manager("get_by_tag", category=["category1", "category2"]),
|
self._manager("get_by_tag", category=["category1", "category2"]),
|
||||||
[self.obj1, self.obj2],
|
[self.obj1, self.obj2],
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(self._manager("get_by_tag", category=["category5", "category4"]), [])
|
||||||
self._manager("get_by_tag", category=["category5", "category4"]), []
|
self.assertEqual(self._manager("get_by_tag", category="category1"), [self.obj1, self.obj2])
|
||||||
)
|
self.assertEqual(self._manager("get_by_tag", category="category6"), [self.obj1, self.obj2])
|
||||||
self.assertEqual(
|
|
||||||
self._manager("get_by_tag", category="category1"), [self.obj1, self.obj2]
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
self._manager("get_by_tag", category="category6"), [self.obj1, self.obj2]
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_get_tag_with_all(self):
|
def test_get_tag_with_all(self):
|
||||||
self.obj1.tags.add("tagA", "categoryA")
|
self.obj1.tags.add("tagA", "categoryA")
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self._manager(
|
self._manager("get_by_tag", ["tagA", "tagB"], ["categoryA", "categoryB"], match="all"),
|
||||||
"get_by_tag", ["tagA", "tagB"], ["categoryA", "categoryB"], match="all"
|
|
||||||
),
|
|
||||||
[],
|
[],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_get_tag_with_any(self):
|
def test_get_tag_with_any(self):
|
||||||
self.obj1.tags.add("tagA", "categoryA")
|
self.obj1.tags.add("tagA", "categoryA")
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self._manager(
|
self._manager("get_by_tag", ["tagA", "tagB"], ["categoryA", "categoryB"], match="any"),
|
||||||
"get_by_tag", ["tagA", "tagB"], ["categoryA", "categoryB"], match="any"
|
|
||||||
),
|
|
||||||
[self.obj1],
|
[self.obj1],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_get_tag_withnomatch(self):
|
def test_get_tag_withnomatch(self):
|
||||||
self.obj1.tags.add("tagC", "categoryC")
|
self.obj1.tags.add("tagC", "categoryC")
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self._manager(
|
self._manager("get_by_tag", ["tagA", "tagB"], ["categoryA", "categoryB"], match="any"),
|
||||||
"get_by_tag", ["tagA", "tagB"], ["categoryA", "categoryB"], match="any"
|
|
||||||
),
|
|
||||||
[],
|
[],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_batch_add(self):
|
def test_batch_add(self):
|
||||||
tags = ["tag1",
|
tags = ["tag1", ("tag2", "category2"), "tag3", ("tag4", "category4", "data4")]
|
||||||
("tag2", "category2"),
|
|
||||||
"tag3",
|
|
||||||
("tag4", "category4", "data4")
|
|
||||||
]
|
|
||||||
self.obj1.tags.batch_add(*tags)
|
self.obj1.tags.batch_add(*tags)
|
||||||
self.assertEqual(self.obj1.tags.get("tag1"), "tag1")
|
self.assertEqual(self.obj1.tags.get("tag1"), "tag1")
|
||||||
tagobj = self.obj1.tags.get("tag4", category="category4", return_tagobj=True)
|
tagobj = self.obj1.tags.get("tag4", category="category4", return_tagobj=True)
|
||||||
|
|
|
||||||
|
|
@ -369,8 +369,9 @@ help_entry = create_help_entry
|
||||||
# Comm system methods
|
# Comm system methods
|
||||||
|
|
||||||
|
|
||||||
def create_message(senderobj, message, channels=None, receivers=None,
|
def create_message(
|
||||||
locks=None, tags=None, header=None):
|
senderobj, message, channels=None, receivers=None, locks=None, tags=None, header=None
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Create a new communication Msg. Msgs represent a unit of
|
Create a new communication Msg. Msgs represent a unit of
|
||||||
database-persistent communication between entites.
|
database-persistent communication between entites.
|
||||||
|
|
@ -424,7 +425,9 @@ message = create_message
|
||||||
create_msg = create_message
|
create_msg = create_message
|
||||||
|
|
||||||
|
|
||||||
def create_channel(key, aliases=None, desc=None, locks=None, keep_log=True, typeclass=None, tags=None):
|
def create_channel(
|
||||||
|
key, aliases=None, desc=None, locks=None, keep_log=True, typeclass=None, tags=None
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Create A communication Channel. A Channel serves as a central hub
|
Create A communication Channel. A Channel serves as a central hub
|
||||||
for distributing Msgs to groups of people without specifying the
|
for distributing Msgs to groups of people without specifying the
|
||||||
|
|
|
||||||
|
|
@ -235,7 +235,6 @@ class _SaverMutable(object):
|
||||||
def __gt__(self, other):
|
def __gt__(self, other):
|
||||||
return self._data > other
|
return self._data > other
|
||||||
|
|
||||||
|
|
||||||
@_save
|
@_save
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
self._data.__setitem__(key, self._convert_mutables(value))
|
self._data.__setitem__(key, self._convert_mutables(value))
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,7 @@ _STACK_MAXSIZE = settings.INLINEFUNC_STACK_MAXSIZE
|
||||||
|
|
||||||
# example/testing inline functions
|
# example/testing inline functions
|
||||||
|
|
||||||
|
|
||||||
def random(*args, **kwargs):
|
def random(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Inlinefunc. Returns a random number between
|
Inlinefunc. Returns a random number between
|
||||||
|
|
@ -99,11 +100,11 @@ def random(*args, **kwargs):
|
||||||
nargs = len(args)
|
nargs = len(args)
|
||||||
if nargs == 1:
|
if nargs == 1:
|
||||||
# only maxval given
|
# only maxval given
|
||||||
minval, maxval = '0', args[0]
|
minval, maxval = "0", args[0]
|
||||||
elif nargs > 1:
|
elif nargs > 1:
|
||||||
minval, maxval = args[:2]
|
minval, maxval = args[:2]
|
||||||
else:
|
else:
|
||||||
minval, maxval = ('0', '1')
|
minval, maxval = ("0", "1")
|
||||||
|
|
||||||
if "." in minval or "." in maxval:
|
if "." in minval or "." in maxval:
|
||||||
# float mode
|
# float mode
|
||||||
|
|
@ -518,10 +519,13 @@ def raw(string):
|
||||||
Args:
|
Args:
|
||||||
string (str): String with inlinefuncs to escape.
|
string (str): String with inlinefuncs to escape.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _escape(match):
|
def _escape(match):
|
||||||
return "\\" + match.group(0)
|
return "\\" + match.group(0)
|
||||||
|
|
||||||
return _RE_STARTTOKEN.sub(_escape, string)
|
return _RE_STARTTOKEN.sub(_escape, string)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Nick templating
|
# Nick templating
|
||||||
#
|
#
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,6 @@ def dbsafe_encode(value, compress_object=False, pickle_protocol=DEFAULT_PROTOCOL
|
||||||
|
|
||||||
value = dumps(value, protocol=pickle_protocol)
|
value = dumps(value, protocol=pickle_protocol)
|
||||||
|
|
||||||
|
|
||||||
if compress_object:
|
if compress_object:
|
||||||
value = compress(value)
|
value = compress(value)
|
||||||
value = b64encode(value).decode() # decode bytes to str
|
value = b64encode(value).decode() # decode bytes to str
|
||||||
|
|
|
||||||
|
|
@ -205,29 +205,33 @@ help_entries = search_help
|
||||||
# not the attribute object itself (this is usually what you want)
|
# not the attribute object itself (this is usually what you want)
|
||||||
|
|
||||||
|
|
||||||
def search_object_attribute(key=None, category=None, value=None,
|
def search_object_attribute(
|
||||||
strvalue=None, attrtype=None, **kwargs):
|
key=None, category=None, value=None, strvalue=None, attrtype=None, **kwargs
|
||||||
|
):
|
||||||
return ObjectDB.objects.get_by_attribute(
|
return ObjectDB.objects.get_by_attribute(
|
||||||
key=key, category=category, value=value, strvalue=strvalue, attrtype=attrtype, **kwargs
|
key=key, category=category, value=value, strvalue=strvalue, attrtype=attrtype, **kwargs
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def search_account_attribute(key=None, category=None, value=None,
|
def search_account_attribute(
|
||||||
strvalue=None, attrtype=None, **kwargs):
|
key=None, category=None, value=None, strvalue=None, attrtype=None, **kwargs
|
||||||
|
):
|
||||||
return AccountDB.objects.get_by_attribute(
|
return AccountDB.objects.get_by_attribute(
|
||||||
key=key, category=category, value=value, strvalue=strvalue, attrtype=attrtype, **kwargs
|
key=key, category=category, value=value, strvalue=strvalue, attrtype=attrtype, **kwargs
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def search_script_attribute(key=None, category=None, value=None,
|
def search_script_attribute(
|
||||||
strvalue=None, attrtype=None, **kwargs):
|
key=None, category=None, value=None, strvalue=None, attrtype=None, **kwargs
|
||||||
|
):
|
||||||
return ScriptDB.objects.get_by_attribute(
|
return ScriptDB.objects.get_by_attribute(
|
||||||
key=key, category=category, value=value, strvalue=strvalue, attrtype=attrtype, **kwargs
|
key=key, category=category, value=value, strvalue=strvalue, attrtype=attrtype, **kwargs
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def search_channel_attribute(key=None, category=None, value=None,
|
def search_channel_attribute(
|
||||||
strvalue=None, attrtype=None, **kwargs):
|
key=None, category=None, value=None, strvalue=None, attrtype=None, **kwargs
|
||||||
|
):
|
||||||
return Channel.objects.get_by_attribute(
|
return Channel.objects.get_by_attribute(
|
||||||
key=key, category=category, value=value, strvalue=strvalue, attrtype=attrtype, **kwargs
|
key=key, category=category, value=value, strvalue=strvalue, attrtype=attrtype, **kwargs
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -158,11 +158,13 @@ class EvenniaTest(TestCase):
|
||||||
self.account2.delete()
|
self.account2.delete()
|
||||||
super().tearDown()
|
super().tearDown()
|
||||||
|
|
||||||
|
|
||||||
class LocalEvenniaTest(EvenniaTest):
|
class LocalEvenniaTest(EvenniaTest):
|
||||||
"""
|
"""
|
||||||
This test class is intended for inheriting in mygame tests.
|
This test class is intended for inheriting in mygame tests.
|
||||||
It helps ensure your tests are run with your own objects.
|
It helps ensure your tests are run with your own objects.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
account_typeclass = settings.BASE_ACCOUNT_TYPECLASS
|
account_typeclass = settings.BASE_ACCOUNT_TYPECLASS
|
||||||
object_typeclass = settings.BASE_OBJECT_TYPECLASS
|
object_typeclass = settings.BASE_OBJECT_TYPECLASS
|
||||||
character_typeclass = settings.BASE_CHARACTER_TYPECLASS
|
character_typeclass = settings.BASE_CHARACTER_TYPECLASS
|
||||||
|
|
|
||||||
|
|
@ -109,11 +109,17 @@ class TestCreateHelpEntry(TestCase):
|
||||||
|
|
||||||
def test_create_help_entry__complex(self):
|
def test_create_help_entry__complex(self):
|
||||||
locks = "foo:false();bar:true()"
|
locks = "foo:false();bar:true()"
|
||||||
aliases = ['foo', 'bar', 'tst']
|
aliases = ["foo", "bar", "tst"]
|
||||||
tags = [("tag1", "help"), ("tag2", "help"), ("tag3", "help")]
|
tags = [("tag1", "help"), ("tag2", "help"), ("tag3", "help")]
|
||||||
|
|
||||||
entry = create.create_help_entry("testentry", self.help_entry, category="Testing",
|
entry = create.create_help_entry(
|
||||||
locks=locks, aliases=aliases, tags=tags)
|
"testentry",
|
||||||
|
self.help_entry,
|
||||||
|
category="Testing",
|
||||||
|
locks=locks,
|
||||||
|
aliases=aliases,
|
||||||
|
tags=tags,
|
||||||
|
)
|
||||||
self.assertTrue(all(lock in entry.locks.all() for lock in locks.split(";")))
|
self.assertTrue(all(lock in entry.locks.all() for lock in locks.split(";")))
|
||||||
self.assertEqual(list(entry.aliases.all()).sort(), aliases.sort())
|
self.assertEqual(list(entry.aliases.all()).sort(), aliases.sort())
|
||||||
self.assertEqual(entry.tags.all(return_key_and_category=True), tags)
|
self.assertEqual(entry.tags.all(return_key_and_category=True), tags)
|
||||||
|
|
@ -137,21 +143,28 @@ class TestCreateMessage(EvenniaTest):
|
||||||
def test_create_msg__channel(self):
|
def test_create_msg__channel(self):
|
||||||
chan1 = create.create_channel("DummyChannel1")
|
chan1 = create.create_channel("DummyChannel1")
|
||||||
chan2 = create.create_channel("DummyChannel2")
|
chan2 = create.create_channel("DummyChannel2")
|
||||||
msg = create.create_message(self.char1, self.msgtext, channels=[chan1, chan2], header="TestHeader")
|
msg = create.create_message(
|
||||||
|
self.char1, self.msgtext, channels=[chan1, chan2], header="TestHeader"
|
||||||
|
)
|
||||||
self.assertEqual(list(msg.channels), [chan1, chan2])
|
self.assertEqual(list(msg.channels), [chan1, chan2])
|
||||||
|
|
||||||
def test_create_msg__custom(self):
|
def test_create_msg__custom(self):
|
||||||
locks = "foo:false();bar:true()"
|
locks = "foo:false();bar:true()"
|
||||||
tags = ["tag1", "tag2", "tag3"]
|
tags = ["tag1", "tag2", "tag3"]
|
||||||
msg = create.create_message(self.char1, self.msgtext, header="TestHeader",
|
msg = create.create_message(
|
||||||
receivers=[self.char1, self.char2], locks=locks, tags=tags)
|
self.char1,
|
||||||
|
self.msgtext,
|
||||||
|
header="TestHeader",
|
||||||
|
receivers=[self.char1, self.char2],
|
||||||
|
locks=locks,
|
||||||
|
tags=tags,
|
||||||
|
)
|
||||||
self.assertEqual(msg.receivers, [self.char1, self.char2])
|
self.assertEqual(msg.receivers, [self.char1, self.char2])
|
||||||
self.assertTrue(all(lock in msg.locks.all() for lock in locks.split(";")))
|
self.assertTrue(all(lock in msg.locks.all() for lock in locks.split(";")))
|
||||||
self.assertEqual(msg.tags.all(), tags)
|
self.assertEqual(msg.tags.all(), tags)
|
||||||
|
|
||||||
|
|
||||||
class TestCreateChannel(TestCase):
|
class TestCreateChannel(TestCase):
|
||||||
|
|
||||||
def test_create_channel__simple(self):
|
def test_create_channel__simple(self):
|
||||||
chan = create.create_channel("TestChannel1", desc="Testing channel")
|
chan = create.create_channel("TestChannel1", desc="Testing channel")
|
||||||
self.assertEqual(chan.key, "TestChannel1")
|
self.assertEqual(chan.key, "TestChannel1")
|
||||||
|
|
@ -160,10 +173,11 @@ class TestCreateChannel(TestCase):
|
||||||
def test_create_channel__complex(self):
|
def test_create_channel__complex(self):
|
||||||
locks = "foo:false();bar:true()"
|
locks = "foo:false();bar:true()"
|
||||||
tags = ["tag1", "tag2", "tag3"]
|
tags = ["tag1", "tag2", "tag3"]
|
||||||
aliases = ['foo', 'bar', 'tst']
|
aliases = ["foo", "bar", "tst"]
|
||||||
|
|
||||||
chan = create.create_channel("TestChannel2", desc="Testing channel",
|
chan = create.create_channel(
|
||||||
aliases=aliases, locks=locks, tags=tags)
|
"TestChannel2", desc="Testing channel", aliases=aliases, locks=locks, tags=tags
|
||||||
|
)
|
||||||
self.assertTrue(all(lock in chan.locks.all() for lock in locks.split(";")))
|
self.assertTrue(all(lock in chan.locks.all() for lock in locks.split(";")))
|
||||||
self.assertEqual(chan.tags.all(), tags)
|
self.assertEqual(chan.tags.all(), tags)
|
||||||
self.assertEqual(list(chan.aliases.all()).sort(), aliases.sort())
|
self.assertEqual(list(chan.aliases.all()).sort(), aliases.sort())
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,9 @@ class TestDbSerialize(TestCase):
|
||||||
"""
|
"""
|
||||||
Database serialization operations.
|
Database serialization operations.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.obj = DefaultObject(db_key="Tester", )
|
self.obj = DefaultObject(db_key="Tester",)
|
||||||
self.obj.save()
|
self.obj.save()
|
||||||
|
|
||||||
def test_constants(self):
|
def test_constants(self):
|
||||||
|
|
@ -54,5 +55,5 @@ class TestDbSerialize(TestCase):
|
||||||
self.assertEqual(self.obj.db.test, [[1, 2, 3], [4, 5, 6]])
|
self.assertEqual(self.obj.db.test, [[1, 2, 3], [4, 5, 6]])
|
||||||
self.obj.db.test = [{1: 0}, {0: 1}]
|
self.obj.db.test = [{1: 0}, {0: 1}]
|
||||||
self.assertEqual(self.obj.db.test, [{1: 0}, {0: 1}])
|
self.assertEqual(self.obj.db.test, [{1: 0}, {0: 1}])
|
||||||
self.obj.db.test.sort(key=lambda d: str(d))
|
self.obj.db.test.sort(key=lambda d: str(d))
|
||||||
self.assertEqual(self.obj.db.test, [{0: 1}, {1: 0}])
|
self.assertEqual(self.obj.db.test, [{0: 1}, {1: 0}])
|
||||||
|
|
|
||||||
|
|
@ -390,6 +390,7 @@ def iter_to_string(initer, endsep="and", addquote=False):
|
||||||
return str(initer[0])
|
return str(initer[0])
|
||||||
return ", ".join(str(v) for v in initer[:-1]) + "%s %s" % (endsep, initer[-1])
|
return ", ".join(str(v) for v in initer[:-1]) + "%s %s" % (endsep, initer[-1])
|
||||||
|
|
||||||
|
|
||||||
# legacy alias
|
# legacy alias
|
||||||
list_to_string = iter_to_string
|
list_to_string = iter_to_string
|
||||||
|
|
||||||
|
|
@ -1862,8 +1863,6 @@ def display_len(target):
|
||||||
return len(target)
|
return len(target)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------
|
# -------------------------------------------------------------------
|
||||||
# Search handler function
|
# Search handler function
|
||||||
# -------------------------------------------------------------------
|
# -------------------------------------------------------------------
|
||||||
|
|
@ -1911,7 +1910,9 @@ def at_search_result(matches, caller, query="", quiet=False, **kwargs):
|
||||||
if multimatch_string:
|
if multimatch_string:
|
||||||
error = "%s\n" % multimatch_string
|
error = "%s\n" % multimatch_string
|
||||||
else:
|
else:
|
||||||
error = _("More than one match for '{query}' (please narrow target):\n").format(query=query)
|
error = _("More than one match for '{query}' (please narrow target):\n").format(
|
||||||
|
query=query
|
||||||
|
)
|
||||||
|
|
||||||
for num, result in enumerate(matches):
|
for num, result in enumerate(matches):
|
||||||
# we need to consider Commands, where .aliases is a list
|
# we need to consider Commands, where .aliases is a list
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,11 @@ def datetime(entry, option_key="Datetime", account=None, from_tz=None, **kwargs)
|
||||||
try:
|
try:
|
||||||
from_tz = _pytz.timezone(acct_tz)
|
from_tz = _pytz.timezone(acct_tz)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
raise ValueError(_("Timezone string '{acct_tz}' is not a valid timezone ({err})").format(acct_tz=acct_tz, err=err))
|
raise ValueError(
|
||||||
|
_("Timezone string '{acct_tz}' is not a valid timezone ({err})").format(
|
||||||
|
acct_tz=acct_tz, err=err
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
from_tz = _pytz.UTC
|
from_tz = _pytz.UTC
|
||||||
|
|
||||||
|
|
|
||||||
22
pyproject.toml
Normal file
22
pyproject.toml
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
[tool.black]
|
||||||
|
line-length = 100
|
||||||
|
target-version = ['py37', 'py38']
|
||||||
|
exclude = '''
|
||||||
|
|
||||||
|
(
|
||||||
|
/(
|
||||||
|
\.eggs # exclude a few common directories in the
|
||||||
|
| \.git # root of the project
|
||||||
|
| \.hg
|
||||||
|
| \.mypy_cache
|
||||||
|
| \.tox
|
||||||
|
| \.venv
|
||||||
|
| _build
|
||||||
|
| buck-out
|
||||||
|
| build
|
||||||
|
| dist
|
||||||
|
)/
|
||||||
|
| migrations
|
||||||
|
|
||||||
|
)
|
||||||
|
'''
|
||||||
Loading…
Add table
Add a link
Reference in a new issue