Repository: getmoto/moto

Issue:
mock_sns create_topic() does not reflect boto3 v1.9.45 Atribute key addition
As of boto3 v1.9.45 the create_topic method accepts the following format:
`response = client.create_topic(
    Name='string',
    Attributes={
        'string': 'string'
    }
)`

The latest version of moto (v1.3.7) only supports the previous way of calling the method:
`response = client.create_topic(
    Name='string'
)`

I am using Moto v1.3.7 installed via pip
```
pip show moto
Name: moto`Version: 1.3.7
Summary: A library that allows your python tests to easily mock out the boto library
Home-page: https://github.com/spulec/moto
Author: Steve Pulec
Author-email: spulec@gmail.com
License: Apache
Location: c:\users\emr0327\.virtualenvs\venv-name\lib\site-packages
Requires: boto3, python-jose, six, botocore, boto, werkzeug, cryptography, Jinja2, xmltodict, pyaml, aws-xray-sdk, docker, responses, jsondiff, pytz, requests, python-dateutil, mock
Required-by:
```




Discussion:

Resolving patch:
diff --git a/moto/sns/models.py b/moto/sns/models.py
--- a/moto/sns/models.py
+++ b/moto/sns/models.py
@@ -12,7 +12,7 @@
 
 from moto.compat import OrderedDict
 from moto.core import BaseBackend, BaseModel
-from moto.core.utils import iso_8601_datetime_with_milliseconds
+from moto.core.utils import iso_8601_datetime_with_milliseconds, camelcase_to_underscores
 from moto.sqs import sqs_backends
 from moto.awslambda import lambda_backends
 
@@ -243,11 +243,14 @@ def reset(self):
     def update_sms_attributes(self, attrs):
         self.sms_attributes.update(attrs)
 
-    def create_topic(self, name):
+    def create_topic(self, name, attributes=None):
         fails_constraints = not re.match(r'^[a-zA-Z0-9_-]{1,256}$', name)
         if fails_constraints:
             raise InvalidParameterValue("Topic names must be made up of only uppercase and lowercase ASCII letters, numbers, underscores, and hyphens, and must be between 1 and 256 characters long.")
         candidate_topic = Topic(name, self)
+        if attributes:
+            for attribute in attributes:
+                setattr(candidate_topic, camelcase_to_underscores(attribute), attributes[attribute])
         if candidate_topic.arn in self.topics:
             return self.topics[candidate_topic.arn]
         else:
diff --git a/moto/sns/responses.py b/moto/sns/responses.py
--- a/moto/sns/responses.py
+++ b/moto/sns/responses.py
@@ -75,7 +75,8 @@ def _parse_message_attributes(self, prefix='', value_namespace='Value.'):
 
     def create_topic(self):
         name = self._get_param('Name')
-        topic = self.backend.create_topic(name)
+        attributes = self._get_attributes()
+        topic = self.backend.create_topic(name, attributes)
 
         if self.request_json:
             return json.dumps({


Test patch:
diff --git a/tests/test_sns/test_topics_boto3.py b/tests/test_sns/test_topics_boto3.py
--- a/tests/test_sns/test_topics_boto3.py
+++ b/tests/test_sns/test_topics_boto3.py
@@ -32,6 +32,18 @@ def test_create_and_delete_topic():
         topics = topics_json["Topics"]
         topics.should.have.length_of(0)
 
+
+@mock_sns
+def test_create_topic_with_attributes():
+    conn = boto3.client("sns", region_name="us-east-1")
+    conn.create_topic(Name='some-topic-with-attribute', Attributes={'DisplayName': 'test-topic'})
+    topics_json = conn.list_topics()
+    topic_arn = topics_json["Topics"][0]['TopicArn']
+
+    attributes = conn.get_topic_attributes(TopicArn=topic_arn)['Attributes']
+    attributes['DisplayName'].should.equal('test-topic')
+
+
 @mock_sns
 def test_create_topic_should_be_indempodent():
     conn = boto3.client("sns", region_name="us-east-1")