Ran black on sources

This commit is contained in:
Griatch 2020-04-12 12:19:15 +02:00
parent cc5aa91be1
commit 21d62e651a
19 changed files with 362 additions and 322 deletions

View file

@ -90,7 +90,7 @@ def _init_command(cls, **kwargs):
"aliases": " ".join(cls.aliases),
"category": cls.help_category,
"text": cls.__doc__,
"tags": ""
"tags": "",
}

View file

@ -34,13 +34,7 @@ class HelpCategory:
@property
def search_index_entry(self):
return {
"key": str(self),
"aliases": "",
"category": self.key,
"tags": "",
"text": ""
}
return {"key": str(self), "aliases": "", "category": self.key, "tags": "", "text": ""}
def __str__(self):
return f"Category: {self.key}"
@ -59,28 +53,13 @@ def help_search_with_index(query, candidate_entries, suggestion_maxnum=5):
search_index = lunr(
ref="key",
fields=[
{
"field_name": "key",
"boost": 10,
},
{
"field_name": "aliases",
"boost": 9,
},
{
"field_name": "category",
"boost": 8,
},
{
"field_name": "tags",
"boost": 5
},
{
"field_name": "text",
"boost": 1,
},
{"field_name": "key", "boost": 10,},
{"field_name": "aliases", "boost": 9,},
{"field_name": "category", "boost": 8,},
{"field_name": "tags", "boost": 5},
{"field_name": "text", "boost": 1,},
],
documents=indx
documents=indx,
)
try:
matches = search_index.search(query)[:suggestion_maxnum]
@ -89,9 +68,10 @@ def help_search_with_index(query, candidate_entries, suggestion_maxnum=5):
matches = []
# matches (objs), suggestions (strs)
return ([mapping[match["ref"]] for match in matches],
[str(match["ref"]) # + f" (score {match['score']})") # good debug
for match in matches])
return (
[mapping[match["ref"]] for match in matches],
[str(match["ref"]) for match in matches], # + f" (score {match['score']})") # good debug
)
class CmdHelp(Command):
@ -195,11 +175,11 @@ class CmdHelp(Command):
for category in sorted(set(list(hdict_cmds.keys()) + list(hdict_db.keys()))):
category_str = f"-- {category.title()} "
grid.append(ANSIString(
category_clr
+ category_str
+ "-" * (width - len(category_str))
+ topic_clr))
grid.append(
ANSIString(
category_clr + category_str + "-" * (width - len(category_str)) + topic_clr
)
)
verbatim_elements.append(len(grid) - 1)
entries = sorted(set(hdict_cmds.get(category, []) + hdict_db.get(category, [])))
@ -281,8 +261,8 @@ class CmdHelp(Command):
]
all_categories = list(
set(
[HelpCategory(cmd.help_category) for cmd in all_cmds] +
[HelpCategory(topic.help_category) for topic in all_topics]
[HelpCategory(cmd.help_category) for cmd in all_cmds]
+ [HelpCategory(topic.help_category) for topic in all_topics]
)
)
@ -302,38 +282,47 @@ class CmdHelp(Command):
return
# Try to access a particular help entry or category
entries = ([cmd for cmd in all_cmds if cmd] +
list(HelpEntry.objects.all()) +
all_categories)
entries = [cmd for cmd in all_cmds if cmd] + list(HelpEntry.objects.all()) + all_categories
for match_query in [f"{query}~1", f"{query}*"]:
# We first do an exact word-match followed by a start-by query
matches, suggestions = help_search_with_index(
match_query, entries, suggestion_maxnum=self.suggestion_maxnum)
match_query, entries, suggestion_maxnum=self.suggestion_maxnum
)
if matches:
match = matches[0]
if isinstance(match, HelpCategory):
formatted = self.format_help_list(
{match.key: [cmd.key for cmd in all_cmds
if match.key.lower() == cmd.help_category]},
{match.key: [topic.key for topic in all_topics
if match.key.lower() == topic.help_category]}
{
match.key: [
cmd.key
for cmd in all_cmds
if match.key.lower() == cmd.help_category
]
},
{
match.key: [
topic.key
for topic in all_topics
if match.key.lower() == topic.help_category
]
},
)
elif inherits_from(match, "evennia.commands.command.Command"):
formatted = self.format_help_entry(
match.key,
match.get_help(caller, cmdset),
aliases=match.aliases,
suggested=suggestions[1:]
suggested=suggestions[1:],
)
else:
formatted = self.format_help_entry(
match.key,
match.entrytext,
aliases=match.aliases.all(),
suggested=suggestions[1:]
suggested=suggestions[1:],
)
self.msg_help(formatted)

View file

@ -1,3 +1,3 @@
"""
Intended to be a collecting folder for Django-specific contribs that do not have observable effects to players.
"""
"""

View file

@ -420,7 +420,7 @@ class S3Boto3StorageFile(File):
if "r" in mode and "w" in mode:
raise ValueError("Can't combine 'r' and 'w' in mode.")
self._storage = storage
self.name = name[len(self._storage.location):].lstrip("/")
self.name = name[len(self._storage.location) :].lstrip("/")
self._mode = mode
self._force_mode = (lambda b: b) if "b" in mode else force_text
self.obj = storage.bucket.Object(storage._encode_name(name))

View file

@ -30,7 +30,6 @@ class S3Boto3TestCase(TestCase):
class S3Boto3StorageTests(S3Boto3TestCase):
def test_clean_name(self):
"""
Test the base case of _clean_name
@ -94,87 +93,75 @@ class S3Boto3StorageTests(S3Boto3TestCase):
"""
Test URL generation.
"""
self.storage.custom_domain = 'example.com'
self.storage.custom_domain = "example.com"
# We expect no leading slashes in the path,
# and trailing slashes should be preserved.
self.assertEqual(self.storage.url(''), 'https://example.com/')
self.assertEqual(self.storage.url('path'), 'https://example.com/path')
self.assertEqual(self.storage.url('path/'), 'https://example.com/path/')
self.assertEqual(self.storage.url('path/1'), 'https://example.com/path/1')
self.assertEqual(self.storage.url('path/1/'), 'https://example.com/path/1/')
self.assertEqual(self.storage.url(""), "https://example.com/")
self.assertEqual(self.storage.url("path"), "https://example.com/path")
self.assertEqual(self.storage.url("path/"), "https://example.com/path/")
self.assertEqual(self.storage.url("path/1"), "https://example.com/path/1")
self.assertEqual(self.storage.url("path/1/"), "https://example.com/path/1/")
def test_storage_save(self):
"""
Test saving a file
"""
name = 'test_storage_save.txt'
content = ContentFile('new content')
name = "test_storage_save.txt"
content = ContentFile("new content")
self.storage.save(name, content)
self.storage.bucket.Object.assert_called_once_with(name)
obj = self.storage.bucket.Object.return_value
obj.upload_fileobj.assert_called_with(
content,
ExtraArgs={
'ContentType': 'text/plain',
'ACL': self.storage.default_acl,
}
content, ExtraArgs={"ContentType": "text/plain", "ACL": self.storage.default_acl,}
)
def test_storage_save_with_acl(self):
"""
Test saving a file with user defined ACL.
"""
name = 'test_storage_save.txt'
content = ContentFile('new content')
self.storage.default_acl = 'private'
name = "test_storage_save.txt"
content = ContentFile("new content")
self.storage.default_acl = "private"
self.storage.save(name, content)
self.storage.bucket.Object.assert_called_once_with(name)
obj = self.storage.bucket.Object.return_value
obj.upload_fileobj.assert_called_with(
content,
ExtraArgs={
'ContentType': 'text/plain',
'ACL': 'private',
}
content, ExtraArgs={"ContentType": "text/plain", "ACL": "private",}
)
def test_content_type(self):
"""
Test saving a file with a None content type.
"""
name = 'test_image.jpg'
content = ContentFile('data')
name = "test_image.jpg"
content = ContentFile("data")
content.content_type = None
self.storage.save(name, content)
self.storage.bucket.Object.assert_called_once_with(name)
obj = self.storage.bucket.Object.return_value
obj.upload_fileobj.assert_called_with(
content,
ExtraArgs={
'ContentType': 'image/jpeg',
'ACL': self.storage.default_acl,
}
content, ExtraArgs={"ContentType": "image/jpeg", "ACL": self.storage.default_acl,}
)
def test_storage_save_gzipped(self):
"""
Test saving a gzipped file
"""
name = 'test_storage_save.gz'
name = "test_storage_save.gz"
content = ContentFile("I am gzip'd")
self.storage.save(name, content)
obj = self.storage.bucket.Object.return_value
obj.upload_fileobj.assert_called_with(
content,
ExtraArgs={
'ContentType': 'application/octet-stream',
'ContentEncoding': 'gzip',
'ACL': self.storage.default_acl,
}
"ContentType": "application/octet-stream",
"ContentEncoding": "gzip",
"ACL": self.storage.default_acl,
},
)
def test_storage_save_gzip(self):
@ -182,21 +169,21 @@ class S3Boto3StorageTests(S3Boto3TestCase):
Test saving a file with gzip enabled.
"""
self.storage.gzip = True
name = 'test_storage_save.css'
name = "test_storage_save.css"
content = ContentFile("I should be gzip'd")
self.storage.save(name, content)
obj = self.storage.bucket.Object.return_value
obj.upload_fileobj.assert_called_with(
mock.ANY,
ExtraArgs={
'ContentType': 'text/css',
'ContentEncoding': 'gzip',
'ACL': self.storage.default_acl,
}
"ContentType": "text/css",
"ContentEncoding": "gzip",
"ACL": self.storage.default_acl,
},
)
args, kwargs = obj.upload_fileobj.call_args
content = args[0]
zfile = gzip.GzipFile(mode='rb', fileobj=content)
zfile = gzip.GzipFile(mode="rb", fileobj=content)
self.assertEqual(zfile.read(), b"I should be gzip'd")
def test_storage_save_gzip_twice(self):
@ -205,26 +192,26 @@ class S3Boto3StorageTests(S3Boto3TestCase):
"""
# Given
self.storage.gzip = True
name = 'test_storage_save.css'
name = "test_storage_save.css"
content = ContentFile("I should be gzip'd")
# When
self.storage.save(name, content)
self.storage.save('test_storage_save_2.css', content)
self.storage.save("test_storage_save_2.css", content)
# Then
obj = self.storage.bucket.Object.return_value
obj.upload_fileobj.assert_called_with(
mock.ANY,
ExtraArgs={
'ContentType': 'text/css',
'ContentEncoding': 'gzip',
'ACL': self.storage.default_acl,
}
"ContentType": "text/css",
"ContentEncoding": "gzip",
"ACL": self.storage.default_acl,
},
)
args, kwargs = obj.upload_fileobj.call_args
content = args[0]
zfile = gzip.GzipFile(mode='rb', fileobj=content)
zfile = gzip.GzipFile(mode="rb", fileobj=content)
self.assertEqual(zfile.read(), b"I should be gzip'd")
def test_compress_content_len(self):
@ -240,15 +227,15 @@ class S3Boto3StorageTests(S3Boto3TestCase):
"""
Test opening a file in write mode
"""
name = 'test_open_for_writïng.txt'
content = 'new content'
name = "test_open_for_writïng.txt"
content = "new content"
# Set the encryption flag used for multipart uploads
self.storage.encryption = True
self.storage.reduced_redundancy = True
self.storage.default_acl = 'public-read'
self.storage.default_acl = "public-read"
file = self.storage.open(name, 'w')
file = self.storage.open(name, "w")
self.storage.bucket.Object.assert_called_with(name)
obj = self.storage.bucket.Object.return_value
# Set the name of the mock object
@ -256,21 +243,22 @@ class S3Boto3StorageTests(S3Boto3TestCase):
file.write(content)
obj.initiate_multipart_upload.assert_called_with(
ACL='public-read',
ContentType='text/plain',
ServerSideEncryption='AES256',
StorageClass='REDUCED_REDUNDANCY'
ACL="public-read",
ContentType="text/plain",
ServerSideEncryption="AES256",
StorageClass="REDUCED_REDUNDANCY",
)
# Save the internal file before closing
multipart = obj.initiate_multipart_upload.return_value
multipart.parts.all.return_value = [mock.MagicMock(e_tag='123', part_number=1)]
multipart.parts.all.return_value = [mock.MagicMock(e_tag="123", part_number=1)]
file.close()
multipart.Part.assert_called_with(1)
part = multipart.Part.return_value
part.upload.assert_called_with(Body=content.encode('utf-8'))
part.upload.assert_called_with(Body=content.encode("utf-8"))
multipart.complete.assert_called_once_with(
MultipartUpload={'Parts': [{'ETag': '123', 'PartNumber': 1}]})
MultipartUpload={"Parts": [{"ETag": "123", "PartNumber": 1}]}
)
def test_storage_open_no_write(self):
"""
@ -278,19 +266,19 @@ class S3Boto3StorageTests(S3Boto3TestCase):
A file should be created as by obj.put(...).
"""
name = 'test_open_no_write.txt'
name = "test_open_no_write.txt"
# Set the encryption flag used for puts
self.storage.encryption = True
self.storage.reduced_redundancy = True
self.storage.default_acl = 'public-read'
self.storage.default_acl = "public-read"
file = self.storage.open(name, 'w')
file = self.storage.open(name, "w")
self.storage.bucket.Object.assert_called_with(name)
obj = self.storage.bucket.Object.return_value
obj.load.side_effect = ClientError({'Error': {},
'ResponseMetadata': {'HTTPStatusCode': 404}},
'head_bucket')
obj.load.side_effect = ClientError(
{"Error": {}, "ResponseMetadata": {"HTTPStatusCode": 404}}, "head_bucket"
)
# Set the name of the mock object
obj.key = name
@ -300,25 +288,25 @@ class S3Boto3StorageTests(S3Boto3TestCase):
obj.load.assert_called_once_with()
obj.put.assert_called_once_with(
ACL='public-read',
ACL="public-read",
Body=b"",
ContentType='text/plain',
ServerSideEncryption='AES256',
StorageClass='REDUCED_REDUNDANCY'
ContentType="text/plain",
ServerSideEncryption="AES256",
StorageClass="REDUCED_REDUNDANCY",
)
def test_storage_open_no_overwrite_existing(self):
"""
Test opening an existing file in write mode and closing without writing.
"""
name = 'test_open_no_overwrite_existing.txt'
name = "test_open_no_overwrite_existing.txt"
# Set the encryption flag used for puts
self.storage.encryption = True
self.storage.reduced_redundancy = True
self.storage.default_acl = 'public-read'
self.storage.default_acl = "public-read"
file = self.storage.open(name, 'w')
file = self.storage.open(name, "w")
self.storage.bucket.Object.assert_called_with(name)
obj = self.storage.bucket.Object.return_value
@ -335,125 +323,111 @@ class S3Boto3StorageTests(S3Boto3TestCase):
"""
Test writing content that exceeds the buffer size
"""
name = 'test_open_for_writïng_beyond_buffer_size.txt'
name = "test_open_for_writïng_beyond_buffer_size.txt"
# Set the encryption flag used for multipart uploads
self.storage.encryption = True
self.storage.reduced_redundancy = True
self.storage.default_acl = 'public-read'
self.storage.default_acl = "public-read"
file = self.storage.open(name, 'w')
file = self.storage.open(name, "w")
self.storage.bucket.Object.assert_called_with(name)
obj = self.storage.bucket.Object.return_value
# Set the name of the mock object
obj.key = name
# Initiate the multipart upload
file.write('')
file.write("")
obj.initiate_multipart_upload.assert_called_with(
ACL='public-read',
ContentType='text/plain',
ServerSideEncryption='AES256',
StorageClass='REDUCED_REDUNDANCY'
ACL="public-read",
ContentType="text/plain",
ServerSideEncryption="AES256",
StorageClass="REDUCED_REDUNDANCY",
)
multipart = obj.initiate_multipart_upload.return_value
# Write content at least twice as long as the buffer size
written_content = ''
written_content = ""
counter = 1
while len(written_content) < 2 * file.buffer_size:
content = 'hello, aws {counter}\n'.format(counter=counter)
content = "hello, aws {counter}\n".format(counter=counter)
# Write more than just a few bytes in each iteration to keep the
# test reasonably fast
content += '*' * int(file.buffer_size / 10)
content += "*" * int(file.buffer_size / 10)
file.write(content)
written_content += content
counter += 1
# Save the internal file before closing
multipart.parts.all.return_value = [
mock.MagicMock(e_tag='123', part_number=1),
mock.MagicMock(e_tag='456', part_number=2)
mock.MagicMock(e_tag="123", part_number=1),
mock.MagicMock(e_tag="456", part_number=2),
]
file.close()
self.assertListEqual(
multipart.Part.call_args_list,
[mock.call(1), mock.call(2)]
)
self.assertListEqual(multipart.Part.call_args_list, [mock.call(1), mock.call(2)])
part = multipart.Part.return_value
uploaded_content = ''.join(
args_list[1]['Body'].decode('utf-8')
for args_list in part.upload.call_args_list
uploaded_content = "".join(
args_list[1]["Body"].decode("utf-8") for args_list in part.upload.call_args_list
)
self.assertEqual(uploaded_content, written_content)
multipart.complete.assert_called_once_with(
MultipartUpload={'Parts': [
{'ETag': '123', 'PartNumber': 1},
{'ETag': '456', 'PartNumber': 2},
]}
MultipartUpload={
"Parts": [{"ETag": "123", "PartNumber": 1}, {"ETag": "456", "PartNumber": 2},]
}
)
def test_auto_creating_bucket(self):
self.storage.auto_create_bucket = True
Bucket = mock.MagicMock()
self.storage._connections.connection.Bucket.return_value = Bucket
self.storage._connections.connection.meta.client.meta.region_name = 'sa-east-1'
self.storage._connections.connection.meta.client.meta.region_name = "sa-east-1"
Bucket.meta.client.head_bucket.side_effect = ClientError({'Error': {},
'ResponseMetadata': {'HTTPStatusCode': 404}},
'head_bucket')
self.storage._get_or_create_bucket('testbucketname')
Bucket.meta.client.head_bucket.side_effect = ClientError(
{"Error": {}, "ResponseMetadata": {"HTTPStatusCode": 404}}, "head_bucket"
)
self.storage._get_or_create_bucket("testbucketname")
Bucket.create.assert_called_once_with(
ACL='public-read',
CreateBucketConfiguration={
'LocationConstraint': 'sa-east-1',
}
ACL="public-read", CreateBucketConfiguration={"LocationConstraint": "sa-east-1",}
)
def test_auto_creating_bucket_with_acl(self):
self.storage.auto_create_bucket = True
self.storage.bucket_acl = 'public-read'
self.storage.bucket_acl = "public-read"
Bucket = mock.MagicMock()
self.storage._connections.connection.Bucket.return_value = Bucket
self.storage._connections.connection.meta.client.meta.region_name = 'sa-east-1'
self.storage._connections.connection.meta.client.meta.region_name = "sa-east-1"
Bucket.meta.client.head_bucket.side_effect = ClientError({'Error': {},
'ResponseMetadata': {'HTTPStatusCode': 404}},
'head_bucket')
self.storage._get_or_create_bucket('testbucketname')
Bucket.meta.client.head_bucket.side_effect = ClientError(
{"Error": {}, "ResponseMetadata": {"HTTPStatusCode": 404}}, "head_bucket"
)
self.storage._get_or_create_bucket("testbucketname")
Bucket.create.assert_called_once_with(
ACL='public-read',
CreateBucketConfiguration={
'LocationConstraint': 'sa-east-1',
}
ACL="public-read", CreateBucketConfiguration={"LocationConstraint": "sa-east-1",}
)
def test_storage_exists(self):
self.assertTrue(self.storage.exists("file.txt"))
self.storage.connection.meta.client.head_object.assert_called_with(
Bucket=self.storage.bucket_name,
Key="file.txt",
Bucket=self.storage.bucket_name, Key="file.txt",
)
def test_storage_exists_false(self):
self.storage.connection.meta.client.head_object.side_effect = ClientError(
{'Error': {'Code': '404', 'Message': 'Not Found'}},
'HeadObject',
{"Error": {"Code": "404", "Message": "Not Found"}}, "HeadObject",
)
self.assertFalse(self.storage.exists("file.txt"))
self.storage.connection.meta.client.head_object.assert_called_with(
Bucket=self.storage.bucket_name,
Key='file.txt',
Bucket=self.storage.bucket_name, Key="file.txt",
)
def test_storage_exists_doesnt_create_bucket(self):
with mock.patch.object(self.storage, '_get_or_create_bucket') as method:
self.storage.exists('file.txt')
with mock.patch.object(self.storage, "_get_or_create_bucket") as method:
self.storage.exists("file.txt")
self.assertFalse(method.called)
def test_storage_delete(self):
self.storage.delete("path/to/file.txt")
self.storage.bucket.Object.assert_called_with('path/to/file.txt')
self.storage.bucket.Object.assert_called_with("path/to/file.txt")
self.storage.bucket.Object.return_value.delete.assert_called_with()
def test_storage_listdir_base(self):
@ -464,14 +438,8 @@ class S3Boto3StorageTests(S3Boto3TestCase):
# 4.txt
pages = [
{
'CommonPrefixes': [
{'Prefix': 'some'},
{'Prefix': 'other'},
],
'Contents': [
{'Key': '2.txt'},
{'Key': '4.txt'},
],
"CommonPrefixes": [{"Prefix": "some"}, {"Prefix": "other"},],
"Contents": [{"Key": "2.txt"}, {"Key": "4.txt"},],
},
]
@ -479,42 +447,35 @@ class S3Boto3StorageTests(S3Boto3TestCase):
paginator.paginate.return_value = pages
self.storage._connections.connection.meta.client.get_paginator.return_value = paginator
dirs, files = self.storage.listdir('')
paginator.paginate.assert_called_with(Bucket=None, Delimiter='/', Prefix='')
dirs, files = self.storage.listdir("")
paginator.paginate.assert_called_with(Bucket=None, Delimiter="/", Prefix="")
self.assertEqual(dirs, ['some', 'other'])
self.assertEqual(files, ['2.txt', '4.txt'])
self.assertEqual(dirs, ["some", "other"])
self.assertEqual(files, ["2.txt", "4.txt"])
def test_storage_listdir_subdir(self):
# Files:
# some/path/1.txt
# some/2.txt
pages = [
{
'CommonPrefixes': [
{'Prefix': 'some/path'},
],
'Contents': [
{'Key': 'some/2.txt'},
],
},
{"CommonPrefixes": [{"Prefix": "some/path"},], "Contents": [{"Key": "some/2.txt"},],},
]
paginator = mock.MagicMock()
paginator.paginate.return_value = pages
self.storage._connections.connection.meta.client.get_paginator.return_value = paginator
dirs, files = self.storage.listdir('some/')
paginator.paginate.assert_called_with(Bucket=None, Delimiter='/', Prefix='some/')
dirs, files = self.storage.listdir("some/")
paginator.paginate.assert_called_with(Bucket=None, Delimiter="/", Prefix="some/")
self.assertEqual(dirs, ['path'])
self.assertEqual(files, ['2.txt'])
self.assertEqual(dirs, ["path"])
self.assertEqual(files, ["2.txt"])
def test_storage_size(self):
obj = self.storage.bucket.Object.return_value
obj.content_length = 4098
name = 'file.txt'
name = "file.txt"
self.assertEqual(self.storage.size(name), obj.content_length)
def test_storage_mtime(self):
@ -527,30 +488,29 @@ class S3Boto3StorageTests(S3Boto3TestCase):
obj = self.storage.bucket.Object.return_value
obj.last_modified = datetime.datetime.now(utc)
name = 'file.txt'
name = "file.txt"
self.assertFalse(
is_aware(self.storage.modified_time(name)),
'Naive datetime object expected from modified_time()'
"Naive datetime object expected from modified_time()",
)
self.assertIs(
settings.USE_TZ,
is_aware(self.storage.get_modified_time(name)),
'{} datetime object expected from get_modified_time() when USE_TZ={}'.format(
('Naive', 'Aware')[settings.USE_TZ],
settings.USE_TZ
)
"{} datetime object expected from get_modified_time() when USE_TZ={}".format(
("Naive", "Aware")[settings.USE_TZ], settings.USE_TZ
),
)
def test_storage_url(self):
name = 'test_storage_size.txt'
url = 'http://aws.amazon.com/%s' % name
name = "test_storage_size.txt"
url = "http://aws.amazon.com/%s" % name
self.storage.bucket.meta.client.generate_presigned_url.return_value = url
self.storage.bucket.name = 'bucket'
self.storage.bucket.name = "bucket"
self.assertEqual(self.storage.url(name), url)
self.storage.bucket.meta.client.generate_presigned_url.assert_called_with(
'get_object',
Params={'Bucket': self.storage.bucket.name, 'Key': name},
"get_object",
Params={"Bucket": self.storage.bucket.name, "Key": name},
ExpiresIn=self.storage.querystring_expire,
)
@ -558,26 +518,24 @@ class S3Boto3StorageTests(S3Boto3TestCase):
self.assertEqual(self.storage.url(name, expire=custom_expire), url)
self.storage.bucket.meta.client.generate_presigned_url.assert_called_with(
'get_object',
Params={'Bucket': self.storage.bucket.name, 'Key': name},
"get_object",
Params={"Bucket": self.storage.bucket.name, "Key": name},
ExpiresIn=custom_expire,
)
def test_generated_url_is_encoded(self):
self.storage.custom_domain = "mock.cloudfront.net"
filename = "whacky & filename.mp4"
url = self.storage.url(filename)
parsed_url = urlparse.urlparse(url)
self.assertEqual(parsed_url.path,
"/whacky%20%26%20filename.mp4")
self.assertEqual(parsed_url.path, "/whacky%20%26%20filename.mp4")
self.assertFalse(self.storage.bucket.meta.client.generate_presigned_url.called)
def test_special_characters(self):
self.storage.custom_domain = "mock.cloudfront.net"
name = "ãlöhâ.jpg"
content = ContentFile('new content')
content = ContentFile("new content")
self.storage.save(name, content)
self.storage.bucket.Object.assert_called_once_with(name)
@ -586,13 +544,21 @@ class S3Boto3StorageTests(S3Boto3TestCase):
self.assertEqual(parsed_url.path, "/%C3%A3l%C3%B6h%C3%A2.jpg")
def test_strip_signing_parameters(self):
expected = 'http://bucket.s3-aws-region.amazonaws.com/foo/bar'
self.assertEqual(self.storage._strip_signing_parameters(
'%s?X-Amz-Date=12345678&X-Amz-Signature=Signature' % expected), expected)
self.assertEqual(self.storage._strip_signing_parameters(
'%s?expires=12345678&signature=Signature' % expected), expected)
expected = "http://bucket.s3-aws-region.amazonaws.com/foo/bar"
self.assertEqual(
self.storage._strip_signing_parameters(
"%s?X-Amz-Date=12345678&X-Amz-Signature=Signature" % expected
),
expected,
)
self.assertEqual(
self.storage._strip_signing_parameters(
"%s?expires=12345678&signature=Signature" % expected
),
expected,
)
@skipIf(threading is None, 'Test requires threading')
@skipIf(threading is None, "Test requires threading")
def test_connection_threading(self):
connections = []
@ -613,23 +579,23 @@ class S3Boto3StorageTests(S3Boto3TestCase):
"Found '/'. Use '' instead."
)
with self.assertRaises(ImproperlyConfigured, msg=msg):
s3boto3.S3Boto3Storage(location='/')
s3boto3.S3Boto3Storage(location="/")
def test_override_class_variable(self):
class MyStorage1(s3boto3.S3Boto3Storage):
location = 'foo1'
location = "foo1"
storage = MyStorage1()
self.assertEqual(storage.location, 'foo1')
self.assertEqual(storage.location, "foo1")
class MyStorage2(s3boto3.S3Boto3Storage):
location = 'foo2'
location = "foo2"
storage = MyStorage2()
self.assertEqual(storage.location, 'foo2')
self.assertEqual(storage.location, "foo2")
def test_override_init_argument(self):
storage = s3boto3.S3Boto3Storage(location='foo1')
self.assertEqual(storage.location, 'foo1')
storage = s3boto3.S3Boto3Storage(location='foo2')
self.assertEqual(storage.location, 'foo2')
storage = s3boto3.S3Boto3Storage(location="foo1")
self.assertEqual(storage.location, "foo1")
storage = s3boto3.S3Boto3Storage(location="foo2")
self.assertEqual(storage.location, "foo2")

View file

@ -74,7 +74,7 @@ class HelpEntry(SharedMemoryModel):
Tag,
blank=True,
help_text="tags on this object. Tags are simple string markers to "
"identify, group and alias objects.",
"identify, group and alias objects.",
)
# (deprecated, only here to allow MUX helpfile load (don't use otherwise)).
# TODO: remove this when not needed anymore.
@ -134,7 +134,7 @@ class HelpEntry(SharedMemoryModel):
"aliases": " ".join(self.aliases.all()),
"category": self.db_help_category,
"text": self.db_entrytext,
"tags": " ".join(str(tag) for tag in self.tags.all())
"tags": " ".join(str(tag) for tag in self.tags.all()),
}
#

View file

@ -2134,6 +2134,7 @@ class DefaultCharacter(DefaultObject):
"""
from evennia.utils.utils import latinify
latin_name = latinify(name, default="X")
return latin_name
@ -2148,7 +2149,7 @@ class DefaultCharacter(DefaultObject):
"""
return True # Default validator does not perform any operations
return True # Default validator does not perform any operations
def basetype_setup(self):
"""

View file

@ -40,7 +40,9 @@ class DefaultObjectTest(EvenniaTest):
self.assertEqual(obj.db_home, self.room1)
def test_character_create_weirdname(self):
obj, errors = DefaultCharacter.create("SigurðurÞórarinsson", self.account, home=self.room1.dbref)
obj, errors = DefaultCharacter.create(
"SigurðurÞórarinsson", self.account, home=self.room1.dbref
)
self.assertTrue(obj, errors)
self.assertFalse(errors, errors)
self.assertEqual(obj.name, "SigurXurXorarinsson")

View file

@ -255,9 +255,7 @@ IN_GAME_ERRORS = True
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": os.getenv(
"TEST_DB_PATH", os.path.join(GAME_DIR, "server", "evennia.db3")
),
"NAME": os.getenv("TEST_DB_PATH", os.path.join(GAME_DIR, "server", "evennia.db3")),
"USER": "",
"PASSWORD": "",
"HOST": "",
@ -872,9 +870,7 @@ TEMPLATES = [
os.path.join(GAME_DIR, "web", "template_overrides"),
os.path.join(EVENNIA_DIR, "web", "website", "templates", WEBSITE_TEMPLATE),
os.path.join(EVENNIA_DIR, "web", "website", "templates"),
os.path.join(
EVENNIA_DIR, "web", "webclient", "templates", WEBCLIENT_TEMPLATE
),
os.path.join(EVENNIA_DIR, "web", "webclient", "templates", WEBCLIENT_TEMPLATE),
os.path.join(EVENNIA_DIR, "web", "webclient", "templates"),
],
"APP_DIRS": True,
@ -946,9 +942,7 @@ AUTH_USER_MODEL = "accounts.AccountDB"
# Password validation plugins
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"
},
{"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
"OPTIONS": {"min_length": 8},
@ -961,14 +955,8 @@ AUTH_PASSWORD_VALIDATORS = [
# Username validation plugins
AUTH_USERNAME_VALIDATORS = [
{"NAME": "django.contrib.auth.validators.ASCIIUsernameValidator"},
{
"NAME": "django.core.validators.MinLengthValidator",
"OPTIONS": {"limit_value": 3},
},
{
"NAME": "django.core.validators.MaxLengthValidator",
"OPTIONS": {"limit_value": 30},
},
{"NAME": "django.core.validators.MinLengthValidator", "OPTIONS": {"limit_value": 3},},
{"NAME": "django.core.validators.MaxLengthValidator", "OPTIONS": {"limit_value": 30},},
{"NAME": "evennia.server.validators.EvenniaUsernameAvailabilityValidator"},
]
@ -982,22 +970,18 @@ MESSAGE_TAGS = {messages.ERROR: "danger"}
# Django REST Framework settings
REST_FRAMEWORK = {
# django_filters allows you to specify search fields for models in an API View
'DEFAULT_FILTER_BACKENDS': (
'django_filters.rest_framework.DjangoFilterBackend',
),
"DEFAULT_FILTER_BACKENDS": ("django_filters.rest_framework.DjangoFilterBackend",),
# whether to paginate results and how many per page
"DEFAULT_PAGINATION_CLASS": 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 25,
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.LimitOffsetPagination",
"PAGE_SIZE": 25,
# require logged in users to call API so that access checks can work on them
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
"DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.IsAuthenticated",],
# These are the different ways people can authenticate for API requests - via
# session or with user/password. Other ways are possible, such as via tokens
# or oauth, but require additional dependencies.
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework.authentication.BasicAuthentication",
"rest_framework.authentication.SessionAuthentication",
],
# default permission checks used by the EvenniaPermission class
"DEFAULT_CREATE_PERMISSION": "builder",

View file

@ -335,8 +335,9 @@ class EvMore(object):
# no justification. Simple division by line
lines = text.split("\n")
self._data = [_LBR.join(lines[i: i + self.height])
for i in range(0, len(lines), self.height)]
self._data = [
_LBR.join(lines[i : i + self.height]) for i in range(0, len(lines), self.height)
]
self._npages = len(self._data)
self._paginator = self.paginator_index

View file

@ -246,6 +246,7 @@ class LatinifyTest(TestCase):
class TestFormatGrid(TestCase):
maxDiff = None
def setUp(self):
# make the random only semi-random with a fixed seed
random.seed(1)
@ -283,9 +284,21 @@ class TestFormatGrid(TestCase):
def test_overlap(self):
"""Grid with elements overlapping into the next slot"""
elements = ("alias", "batchcode", "batchcommands", "cmdsets",
"copy", "cpattr", "desc", "destroy", "dig",
"examine", "find", "force", "lock")
elements = (
"alias",
"batchcode",
"batchcommands",
"cmdsets",
"copy",
"cpattr",
"desc",
"destroy",
"dig",
"examine",
"find",
"force",
"lock",
)
rows = utils.format_grid(elements, width=78)
self.assertEqual(len(rows), 2)
for element in elements:

View file

@ -1748,7 +1748,7 @@ def format_grid(elements, width=78, sep=" ", verbatim_elements=None):
# debugger.Debugger().set_trace()
# get the nth percentile as a good representation of average width
averlen = int(percentile(sorted(wls_percentile), 0.9)) + 2 # include extra space
averlen = int(percentile(sorted(wls_percentile), 0.9)) + 2 # include extra space
aver_per_row = width // averlen + 1
if aver_per_row == 1:

View file

@ -33,6 +33,7 @@ class TagTypeFilter(CharFilter):
"""
This class lets you create different filters for tags of a specified db_tagtype.
"""
tag_type = None
def filter(self, qs, value):
@ -45,11 +46,13 @@ class TagTypeFilter(CharFilter):
class AliasFilter(TagTypeFilter):
"""A filter for objects by their aliases (tags with a tagtype of 'alias'"""
tag_type = "alias"
class PermissionFilter(TagTypeFilter):
"""A filter for objects by their permissions (tags with a tagtype of 'permission'"""
tag_type = "permission"
@ -58,6 +61,7 @@ SHARED_FIELDS = ["db_key", "db_typeclass_path", "db_tags__db_key", "db_tags__db_
class BaseTypeclassFilterSet(FilterSet):
"""A parent class with filters for aliases and permissions"""
alias = AliasFilter(lookup_expr="iexact")
permission = PermissionFilter(lookup_expr="iexact")
name = CharFilter(lookup_expr="iexact", method="filter_name", field_name="db_key")
@ -81,14 +85,20 @@ class BaseTypeclassFilterSet(FilterSet):
class ObjectDBFilterSet(BaseTypeclassFilterSet):
"""This adds filters for ObjectDB instances - characters, rooms, exits, etc"""
class Meta:
model = ObjectDB
fields = SHARED_FIELDS + ["db_location__db_key", "db_home__db_key", "db_location__id",
"db_home__id"]
fields = SHARED_FIELDS + [
"db_location__db_key",
"db_home__db_key",
"db_location__id",
"db_home__id",
]
class AccountDBFilterSet(BaseTypeclassFilterSet):
"""This adds filters for Account objects"""
name = CharFilter(lookup_expr="iexact", method="filter_name", field_name="username")
class Meta:
@ -98,7 +108,16 @@ class AccountDBFilterSet(BaseTypeclassFilterSet):
class ScriptDBFilterSet(BaseTypeclassFilterSet):
"""This adds filters for Script objects"""
class Meta:
model = ScriptDB
fields = SHARED_FIELDS + ["db_desc", "db_obj__db_key", "db_obj__id", "db_account__id",
"db_account__username", "db_is_active", "db_persistent", "db_interval"]
fields = SHARED_FIELDS + [
"db_desc",
"db_obj__db_key",
"db_obj__id",
"db_account__id",
"db_account__username",
"db_is_active",
"db_persistent",
"db_interval",
]

View file

@ -9,6 +9,7 @@ class EvenniaPermission(permissions.BasePermission):
Evennia's permission structure. Based on the action in a given
view, we'll check a corresponding Evennia access/lock check.
"""
# subclass this to change these permissions
MINIMUM_LIST_PERMISSION = settings.REST_FRAMEWORK.get("DEFAULT_LIST_PERMISSION", "builder")
MINIMUM_CREATE_PERMISSION = settings.REST_FRAMEWORK.get("DEFAULT_CREATE_PERMISSION", "builder")

View file

@ -62,7 +62,15 @@ class TypeclassSerializerMixin(object):
not have them render PK-related fields.
"""
shared_fields = ["id", "db_key", "attributes", "db_typeclass_path", "aliases", "tags", "permissions"]
shared_fields = [
"id",
"db_key",
"attributes",
"db_typeclass_path",
"aliases",
"tags",
"permissions",
]
@staticmethod
def get_tags(obj):
@ -98,7 +106,9 @@ class TypeclassSerializerMixin(object):
Returns:
List of TagSerializer data
"""
return TagSerializer(obj.permissions.get(return_tagobj=True, return_list=True), many=True).data
return TagSerializer(
obj.permissions.get(return_tagobj=True, return_list=True), many=True
).data
@staticmethod
def get_attributes(obj):
@ -136,7 +146,13 @@ class ObjectDBSerializer(TypeclassSerializerMixin, serializers.ModelSerializer):
class Meta:
model = DefaultObject
fields = ["db_location", "db_home", "contents", "exits", "nicks"] + TypeclassSerializerMixin.shared_fields
fields = [
"db_location",
"db_home",
"contents",
"exits",
"nicks",
] + TypeclassSerializerMixin.shared_fields
read_only_fields = ["id"]
@staticmethod
@ -168,6 +184,7 @@ class ObjectDBSerializer(TypeclassSerializerMixin, serializers.ModelSerializer):
class AccountSerializer(TypeclassSerializerMixin, serializers.ModelSerializer):
"""This uses the DefaultAccount object to have access to the sessions property"""
attributes = serializers.SerializerMethodField()
nicks = serializers.SerializerMethodField()
db_key = serializers.CharField(required=False)
@ -202,6 +219,11 @@ class ScriptDBSerializer(TypeclassSerializerMixin, serializers.ModelSerializer):
class Meta:
model = ScriptDB
fields = ["db_interval", "db_persistent", "db_start_delay",
"db_is_active", "db_repeats"] + TypeclassSerializerMixin.shared_fields
fields = [
"db_interval",
"db_persistent",
"db_start_delay",
"db_is_active",
"db_repeats",
] + TypeclassSerializerMixin.shared_fields
read_only_fields = ["id"]

View file

@ -14,9 +14,7 @@ urlpatterns = [
]
@override_settings(
REST_API_ENABLED=True, ROOT_URLCONF=__name__, AUTH_USERNAME_VALIDATORS=[]
)
@override_settings(REST_API_ENABLED=True, ROOT_URLCONF=__name__, AUTH_USERNAME_VALIDATORS=[])
class TestEvenniaRESTApi(EvenniaTest):
client_class = APIClient
maxDiff = None
@ -37,27 +35,58 @@ class TestEvenniaRESTApi(EvenniaTest):
def get_view_details(self, action):
"""Helper function for generating list of named tuples"""
View = namedtuple("View", ["view_name", "obj", "list", "serializer", "create_data", "retrieve_data"])
View = namedtuple(
"View", ["view_name", "obj", "list", "serializer", "create_data", "retrieve_data"]
)
views = [
View("object-%s" % action, self.obj1, [self.obj1, self.char1, self.exit, self.room1, self.room2, self.obj2,
self.char2], serializers.ObjectDBSerializer,
{"db_key": "object-create-test-name"},
serializers.ObjectDBSerializer(self.obj1).data),
View("character-%s" % action, self.char1, [self.char1, self.char2], serializers.ObjectDBSerializer,
{"db_key": "character-create-test-name"},
serializers.ObjectDBSerializer(self.char1).data),
View("exit-%s" % action, self.exit, [self.exit], serializers.ObjectDBSerializer,
{"db_key": "exit-create-test-name"},
serializers.ObjectDBSerializer(self.exit).data),
View("room-%s" % action, self.room1, [self.room1, self.room2], serializers.ObjectDBSerializer,
{"db_key": "room-create-test-name"},
serializers.ObjectDBSerializer(self.room1).data),
View("script-%s" % action, self.script, [self.script], serializers.ScriptDBSerializer,
{"db_key": "script-create-test-name"},
serializers.ScriptDBSerializer(self.script).data),
View("account-%s" % action, self.account2, [self.account, self.account2], serializers.AccountSerializer,
{"username": "account-create-test-name"},
serializers.AccountSerializer(self.account2).data),
View(
"object-%s" % action,
self.obj1,
[self.obj1, self.char1, self.exit, self.room1, self.room2, self.obj2, self.char2],
serializers.ObjectDBSerializer,
{"db_key": "object-create-test-name"},
serializers.ObjectDBSerializer(self.obj1).data,
),
View(
"character-%s" % action,
self.char1,
[self.char1, self.char2],
serializers.ObjectDBSerializer,
{"db_key": "character-create-test-name"},
serializers.ObjectDBSerializer(self.char1).data,
),
View(
"exit-%s" % action,
self.exit,
[self.exit],
serializers.ObjectDBSerializer,
{"db_key": "exit-create-test-name"},
serializers.ObjectDBSerializer(self.exit).data,
),
View(
"room-%s" % action,
self.room1,
[self.room1, self.room2],
serializers.ObjectDBSerializer,
{"db_key": "room-create-test-name"},
serializers.ObjectDBSerializer(self.room1).data,
),
View(
"script-%s" % action,
self.script,
[self.script],
serializers.ScriptDBSerializer,
{"db_key": "script-create-test-name"},
serializers.ScriptDBSerializer(self.script).data,
),
View(
"account-%s" % action,
self.account2,
[self.account, self.account2],
serializers.AccountSerializer,
{"username": "account-create-test-name"},
serializers.AccountSerializer(self.account2).data,
),
]
return views
@ -65,9 +94,7 @@ class TestEvenniaRESTApi(EvenniaTest):
views = self.get_view_details("detail")
for view in views:
with self.subTest(msg="Testing {} retrieve".format(view.view_name)):
view_url = reverse(
"api:{}".format(view.view_name), kwargs={"pk": view.obj.pk}
)
view_url = reverse("api:{}".format(view.view_name), kwargs={"pk": view.obj.pk})
response = self.client.get(view_url)
self.assertEqual(response.status_code, 200)
self.assertDictEqual(response.data, view.retrieve_data)
@ -76,9 +103,7 @@ class TestEvenniaRESTApi(EvenniaTest):
views = self.get_view_details("detail")
for view in views:
with self.subTest(msg="Testing {} update".format(view.view_name)):
view_url = reverse(
"api:{}".format(view.view_name), kwargs={"pk": view.obj.pk}
)
view_url = reverse("api:{}".format(view.view_name), kwargs={"pk": view.obj.pk})
# test both PUT (update) and PATCH (partial update) here
for new_key, method in (("foobar", "put"), ("fizzbuzz", "patch")):
field = "username" if "account" in view.view_name else "db_key"
@ -93,9 +118,7 @@ class TestEvenniaRESTApi(EvenniaTest):
views = self.get_view_details("detail")
for view in views:
with self.subTest(msg="Testing {} delete".format(view.view_name)):
view_url = reverse(
"api:{}".format(view.view_name), kwargs={"pk": view.obj.pk}
)
view_url = reverse("api:{}".format(view.view_name), kwargs={"pk": view.obj.pk})
response = self.client.delete(view_url)
self.assertEqual(response.status_code, 204)
with self.assertRaises(ObjectDoesNotExist):
@ -108,7 +131,9 @@ class TestEvenniaRESTApi(EvenniaTest):
view_url = reverse(f"api:{view.view_name}")
response = self.client.get(view_url)
self.assertEqual(response.status_code, 200)
self.assertCountEqual(response.data['results'], [view.serializer(obj).data for obj in view.list])
self.assertCountEqual(
response.data["results"], [view.serializer(obj).data for obj in view.list]
)
def test_create(self):
views = self.get_view_details("list")

View file

@ -22,18 +22,18 @@ from evennia.web.api.views import (
CharacterViewSet,
ExitViewSet,
RoomViewSet,
ScriptDBViewSet
ScriptDBViewSet,
)
app_name = "api"
router = routers.DefaultRouter()
router.trailing_slash = "/?"
router.register(r'accounts', AccountDBViewSet, basename="account")
router.register(r'objects', ObjectDBViewSet, basename="object")
router.register(r'characters', CharacterViewSet, basename="character")
router.register(r'exits', ExitViewSet, basename="exit")
router.register(r'rooms', RoomViewSet, basename="room")
router.register(r'scripts', ScriptDBViewSet, basename="script")
router.register(r"accounts", AccountDBViewSet, basename="account")
router.register(r"objects", ObjectDBViewSet, basename="object")
router.register(r"characters", CharacterViewSet, basename="character")
router.register(r"exits", ExitViewSet, basename="exit")
router.register(r"rooms", RoomViewSet, basename="room")
router.register(r"scripts", ScriptDBViewSet, basename="script")
urlpatterns = router.urls

View file

@ -14,7 +14,12 @@ from evennia.objects.models import ObjectDB
from evennia.objects.objects import DefaultCharacter, DefaultExit, DefaultRoom
from evennia.accounts.models import AccountDB
from evennia.scripts.models import ScriptDB
from evennia.web.api.serializers import ObjectDBSerializer, AccountSerializer, ScriptDBSerializer, AttributeSerializer
from evennia.web.api.serializers import (
ObjectDBSerializer,
AccountSerializer,
ScriptDBSerializer,
AttributeSerializer,
)
from evennia.web.api.filters import ObjectDBFilterSet, AccountDBFilterSet, ScriptDBFilterSet
from evennia.web.api.permissions import EvenniaPermission
@ -24,6 +29,7 @@ class TypeclassViewSetMixin(object):
This mixin adds some shared functionality to each viewset of a typeclass. They all use the same
permission classes and filter backend. You can override any of these in your own viewsets.
"""
# permission classes determine who is authorized to call the view
permission_classes = [EvenniaPermission]
# the filter backend allows for retrieval views to have filter arguments passed to it,
@ -58,7 +64,10 @@ class TypeclassViewSetMixin(object):
handler.add(key=key, value=value, category=category)
else:
handler.remove(key=key, category=category)
return Response(AttributeSerializer(obj.db_attributes.all(), many=True).data, status=status.HTTP_200_OK)
return Response(
AttributeSerializer(obj.db_attributes.all(), many=True).data,
status=status.HTTP_200_OK,
)
return Response(attr.errors, status=status.HTTP_400_BAD_REQUEST)
@ -69,6 +78,7 @@ class ObjectDBViewSet(TypeclassViewSetMixin, ModelViewSet):
instances. Serializers are similar to django forms, used for the
transmitting of data (typically json).
"""
serializer_class = ObjectDBSerializer
queryset = ObjectDB.objects.all()
filterset_class = ObjectDBFilterSet
@ -79,21 +89,27 @@ class CharacterViewSet(ObjectDBViewSet):
This overrides the queryset to only retrieve Character objects
based on your DefaultCharacter typeclass path.
"""
queryset = DefaultCharacter.objects.typeclass_search(DefaultCharacter.path, include_children=True)
queryset = DefaultCharacter.objects.typeclass_search(
DefaultCharacter.path, include_children=True
)
class RoomViewSet(ObjectDBViewSet):
"""Viewset for Room objects"""
queryset = DefaultRoom.objects.typeclass_search(DefaultRoom.path, include_children=True)
class ExitViewSet(ObjectDBViewSet):
"""Viewset for Exit objects"""
queryset = DefaultExit.objects.typeclass_search(DefaultExit.path, include_children=True)
class AccountDBViewSet(TypeclassViewSetMixin, ModelViewSet):
"""Viewset for Account objects"""
serializer_class = AccountSerializer
queryset = AccountDB.objects.all()
filterset_class = AccountDBFilterSet
@ -101,6 +117,7 @@ class AccountDBViewSet(TypeclassViewSetMixin, ModelViewSet):
class ScriptDBViewSet(TypeclassViewSetMixin, ModelViewSet):
"""Viewset for Script objects"""
serializer_class = ScriptDBSerializer
queryset = ScriptDB.objects.all()
filterset_class = ScriptDBFilterSet

View file

@ -24,4 +24,4 @@ urlpatterns = [
]
if settings.REST_API_ENABLED:
urlpatterns += [url(r'^api/', include("evennia.web.api.urls", namespace="api"))]
urlpatterns += [url(r"^api/", include("evennia.web.api.urls", namespace="api"))]