From 21d62e651aca723d64a9f4c659f09c385d1798f6 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sun, 12 Apr 2020 12:19:15 +0200 Subject: [PATCH] Ran black on sources --- evennia/commands/command.py | 2 +- evennia/commands/default/help.py | 85 +++---- evennia/contrib/django/__init__.py | 2 +- evennia/contrib/django/aws_s3_cdn.py | 2 +- evennia/contrib/django/tests.py | 326 ++++++++++++--------------- evennia/help/models.py | 4 +- evennia/objects/objects.py | 3 +- evennia/objects/tests.py | 4 +- evennia/settings_default.py | 40 +--- evennia/utils/evmore.py | 5 +- evennia/utils/tests/test_utils.py | 19 +- evennia/utils/utils.py | 2 +- evennia/web/api/filters.py | 27 ++- evennia/web/api/permissions.py | 1 + evennia/web/api/serializers.py | 32 ++- evennia/web/api/tests.py | 91 +++++--- evennia/web/api/urls.py | 14 +- evennia/web/api/views.py | 23 +- evennia/web/urls.py | 2 +- 19 files changed, 362 insertions(+), 322 deletions(-) diff --git a/evennia/commands/command.py b/evennia/commands/command.py index 648a31f553..fa2c3265b4 100644 --- a/evennia/commands/command.py +++ b/evennia/commands/command.py @@ -90,7 +90,7 @@ def _init_command(cls, **kwargs): "aliases": " ".join(cls.aliases), "category": cls.help_category, "text": cls.__doc__, - "tags": "" + "tags": "", } diff --git a/evennia/commands/default/help.py b/evennia/commands/default/help.py index 2d9967b48c..3d6899987e 100644 --- a/evennia/commands/default/help.py +++ b/evennia/commands/default/help.py @@ -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) diff --git a/evennia/contrib/django/__init__.py b/evennia/contrib/django/__init__.py index 02fe3ff90b..2ba7f2b5e2 100644 --- a/evennia/contrib/django/__init__.py +++ b/evennia/contrib/django/__init__.py @@ -1,3 +1,3 @@ """ Intended to be a collecting folder for Django-specific contribs that do not have observable effects to players. -""" \ No newline at end of file +""" diff --git a/evennia/contrib/django/aws_s3_cdn.py b/evennia/contrib/django/aws_s3_cdn.py index 048c1c4c8c..85f3cc90f8 100644 --- a/evennia/contrib/django/aws_s3_cdn.py +++ b/evennia/contrib/django/aws_s3_cdn.py @@ -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)) diff --git a/evennia/contrib/django/tests.py b/evennia/contrib/django/tests.py index 584005cf68..667ea185ad 100644 --- a/evennia/contrib/django/tests.py +++ b/evennia/contrib/django/tests.py @@ -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") diff --git a/evennia/help/models.py b/evennia/help/models.py index 2e30e0c6b7..cb3df222b1 100644 --- a/evennia/help/models.py +++ b/evennia/help/models.py @@ -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()), } # diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index 23d623bfb9..98922ddbf9 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -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): """ diff --git a/evennia/objects/tests.py b/evennia/objects/tests.py index 5944ee5aad..0cacfcea89 100644 --- a/evennia/objects/tests.py +++ b/evennia/objects/tests.py @@ -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") diff --git a/evennia/settings_default.py b/evennia/settings_default.py index d7b6cd1836..751791b549 100644 --- a/evennia/settings_default.py +++ b/evennia/settings_default.py @@ -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", diff --git a/evennia/utils/evmore.py b/evennia/utils/evmore.py index ade28a37f0..9257e67ea8 100644 --- a/evennia/utils/evmore.py +++ b/evennia/utils/evmore.py @@ -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 diff --git a/evennia/utils/tests/test_utils.py b/evennia/utils/tests/test_utils.py index d685ef090d..39cbdbf2fa 100644 --- a/evennia/utils/tests/test_utils.py +++ b/evennia/utils/tests/test_utils.py @@ -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: diff --git a/evennia/utils/utils.py b/evennia/utils/utils.py index 162aa879ad..4faf76ca42 100644 --- a/evennia/utils/utils.py +++ b/evennia/utils/utils.py @@ -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: diff --git a/evennia/web/api/filters.py b/evennia/web/api/filters.py index 6284af08ae..592668ea48 100644 --- a/evennia/web/api/filters.py +++ b/evennia/web/api/filters.py @@ -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", + ] diff --git a/evennia/web/api/permissions.py b/evennia/web/api/permissions.py index b68fa0769c..87efe07a23 100644 --- a/evennia/web/api/permissions.py +++ b/evennia/web/api/permissions.py @@ -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") diff --git a/evennia/web/api/serializers.py b/evennia/web/api/serializers.py index 6fab237da4..29132699a9 100644 --- a/evennia/web/api/serializers.py +++ b/evennia/web/api/serializers.py @@ -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"] diff --git a/evennia/web/api/tests.py b/evennia/web/api/tests.py index 4e17b424b9..3d07ad2311 100644 --- a/evennia/web/api/tests.py +++ b/evennia/web/api/tests.py @@ -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") diff --git a/evennia/web/api/urls.py b/evennia/web/api/urls.py index 0594e26d16..70c18c43c8 100644 --- a/evennia/web/api/urls.py +++ b/evennia/web/api/urls.py @@ -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 diff --git a/evennia/web/api/views.py b/evennia/web/api/views.py index 1c5988f1db..eefb717982 100644 --- a/evennia/web/api/views.py +++ b/evennia/web/api/views.py @@ -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 diff --git a/evennia/web/urls.py b/evennia/web/urls.py index 6fce632ca1..f03930b4c2 100644 --- a/evennia/web/urls.py +++ b/evennia/web/urls.py @@ -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"))]