{"action":"created","comment":{"url":"https://api.github.com/repos/boto/botocore/pulls/comments/50589029","id":50589029,"diff_hunk":"@@ -0,0 +1,201 @@\n+# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n+#\n+# Licensed under the Apache License, Version 2.0 (the \"License\"). You\n+# may not use this file except in compliance with the License. A copy of\n+# the License is located at\n+#\n+# http://aws.amazon.com/apache2.0/\n+#\n+# or in the \"license\" file accompanying this file. This file is\n+# distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n+# ANY KIND, either express or implied. See the License for the specific\n+# language governing permissions and limitations under the License.\n+import copy\n+from collections import deque\n+from botocore.validate import validate_parameters\n+from botocore.exceptions import ParamValidationError, StubResponseError\n+from botocore.vendored.requests.models import Response\n+\n+\n+class Stubber(object):\n+    \"\"\"\n+    This class will allow you to stub out requests so you don't have to hit\n+    an endpoint to write tests. Responses are returned first in, first out.\n+    If operations are called out of order, or are called with no remaining\n+    queued responses, an error will be raised.\n+\n+    Example::\n+        import datetime\n+        import botocore.session\n+        from botocore.stub import Stubber\n+\n+\n+        s3 = botocore.session.get_session().create_client('s3')\n+        stubber = Stubber(s3)\n+\n+        response = {\n+            'IsTruncated': False,\n+            'Name': 'test-bucket',\n+            'MaxKeys': 1000, 'Prefix': '',\n+            'Contents': [{\n+                'Key': 'test.txt',\n+                'ETag': '\"abc123\"',\n+                'StorageClass': 'STANDARD',\n+                'LastModified': datetime.datetime(2016, 1, 20, 22, 9),\n+                'Owner': {'ID': 'abc123', 'DisplayName': 'myname'},\n+                'Size': 14814\n+            }],\n+            'EncodingType': 'url',\n+            'ResponseMetadata': {\n+                'RequestId': 'abc123',\n+                'HTTPStatusCode': 200,\n+                'HostId': 'abc123'\n+            },\n+            'Marker': ''\n+        }\n+\n+        stubber.add_response('list_objects', response)\n+        stubber.activate()\n+\n+        service_response = s3.list_objects(Bucket='test-bucket')\n+        assert service_response == response\n+    \"\"\"\n+    def __init__(self, client):\n+        \"\"\"\n+        :param client: The client to add your stubs to.\n+        \"\"\"\n+        self.client = client\n+        self._event_id = 'boto_stubber'\n+        self._queue = deque()\n+\n+    def activate(self):\n+        \"\"\"\n+        Activates the stubber on the client\n+        \"\"\"\n+        self.client.meta.events.register(\n+                'before-call.*.*',\n+                self._get_response_handler,\n+                unique_id=self._event_id)\n+\n+    def deactivate(self):\n+        \"\"\"\n+        Deactivates the stubber on the client\n+        \"\"\"\n+        self.client.meta.events.unregister(\n+                'before-call.*.*',\n+                self._get_response_handler,\n+                unique_id=self._event_id)\n+\n+    def add_response(self, method, service_response):","path":"botocore/stub.py","position":89,"original_position":89,"commit_id":"bb1eb373021d51b4307fa1fbed156965181625a3","original_commit_id":"252c87568c6e3c4494133db06ba226e23f7126d0","user":{"login":"kyleknap","id":4605355,"avatar_url":"https://avatars.githubusercontent.com/u/4605355?v=3","gravatar_id":"","url":"https://api.github.com/users/kyleknap","html_url":"https://github.com/kyleknap","followers_url":"https://api.github.com/users/kyleknap/followers","following_url":"https://api.github.com/users/kyleknap/following{/other_user}","gists_url":"https://api.github.com/users/kyleknap/gists{/gist_id}","starred_url":"https://api.github.com/users/kyleknap/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kyleknap/subscriptions","organizations_url":"https://api.github.com/users/kyleknap/orgs","repos_url":"https://api.github.com/users/kyleknap/repos","events_url":"https://api.github.com/users/kyleknap/events{/privacy}","received_events_url":"https://api.github.com/users/kyleknap/received_events","type":"User","site_admin":false},"body":"Yeah it may be tricky but it would be very useful because we currently do not have a way to do mock's ``assert_called_with()`` method.","created_at":"2016-01-22T20:50:38Z","updated_at":"2016-01-22T20:50:38Z","html_url":"https://github.com/boto/botocore/pull/741#discussion_r50589029","pull_request_url":"https://api.github.com/repos/boto/botocore/pulls/741","_links":{"self":{"href":"https://api.github.com/repos/boto/botocore/pulls/comments/50589029"},"html":{"href":"https://github.com/boto/botocore/pull/741#discussion_r50589029"},"pull_request":{"href":"https://api.github.com/repos/boto/botocore/pulls/741"}}},"pull_request":{"url":"https://api.github.com/repos/boto/botocore/pulls/741","id":53765824,"html_url":"https://github.com/boto/botocore/pull/741","diff_url":"https://github.com/boto/botocore/pull/741.diff","patch_url":"https://github.com/boto/botocore/pull/741.patch","issue_url":"https://api.github.com/repos/boto/botocore/issues/741","number":741,"state":"open","locked":false,"title":"Support stubbing out operations.","user":{"login":"JordonPhillips","id":2643092,"avatar_url":"https://avatars.githubusercontent.com/u/2643092?v=3","gravatar_id":"","url":"https://api.github.com/users/JordonPhillips","html_url":"https://github.com/JordonPhillips","followers_url":"https://api.github.com/users/JordonPhillips/followers","following_url":"https://api.github.com/users/JordonPhillips/following{/other_user}","gists_url":"https://api.github.com/users/JordonPhillips/gists{/gist_id}","starred_url":"https://api.github.com/users/JordonPhillips/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JordonPhillips/subscriptions","organizations_url":"https://api.github.com/users/JordonPhillips/orgs","repos_url":"https://api.github.com/users/JordonPhillips/repos","events_url":"https://api.github.com/users/JordonPhillips/events{/privacy}","received_events_url":"https://api.github.com/users/JordonPhillips/received_events","type":"User","site_admin":false},"body":"This will allow customers to stub out operations, providing their own responses so that they don't have to hit an endpoint to test their code. The interface for this is the `Stubber` class, which will manage the response queue and and handle validating the provided response stubs.\r\n\r\nUsage example:\r\n\r\n```python\r\nimport botocore.session\r\nimport botocore.stub\r\nimport datetime\r\n\r\n\r\ns3_client = botocore.session.get_session().create_client('s3')\r\nstubber = botocore.stub.Stubber(s3_client)\r\nlist_objects_response = {\r\n   'IsTruncated': False,\r\n   'EncodingType': 'url',\r\n   'Marker': '',\r\n   'Prefix': '',\r\n   'Name': 'test-bucket',\r\n   'Contents': [\r\n      {\r\n         'Size': 123,\r\n         'Owner': {\r\n            'DisplayName': 'display_name',\r\n            'ID': '123abc'\r\n         },\r\n         'Key': 'file.txt',\r\n         'StorageClass': 'STANDARD',\r\n         'ETag': '\"abc123\"',\r\n         'LastModified': datetime.datetime(2015, 12, 7, 18, 5, 52)\r\n      },\r\n      {\r\n         'Size': 456,\r\n         'Owner': {\r\n            'DisplayName': 'display_name',\r\n            'ID': '123abc'\r\n         },\r\n         'Key': 'file.py',\r\n         'StorageClass': 'STANDARD',\r\n         'ETag': '\"abc123\"',\r\n         'LastModified': datetime.datetime(2015, 12, 7, 17, 38, 49)\r\n      }\r\n   ],\r\n   'MaxKeys': 1000\r\n}\r\nstubber.add_response('list_objects', list_objects_response)\r\nstubber.activate()\r\nresponse = s3_client.list_objects(Bucket='test-bucket')\r\nassert(response == list_objects_response)\r\n```\r\n\r\ncc @rayluo @kyleknap @mtdowling @jamesls ","created_at":"2015-12-15T21:37:05Z","updated_at":"2016-01-22T20:50:38Z","closed_at":null,"merged_at":null,"merge_commit_sha":"a5ee8b52dd7d8594428da5f44208af6f95e473bd","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/boto/botocore/pulls/741/commits","review_comments_url":"https://api.github.com/repos/boto/botocore/pulls/741/comments","review_comment_url":"https://api.github.com/repos/boto/botocore/pulls/comments{/number}","comments_url":"https://api.github.com/repos/boto/botocore/issues/741/comments","statuses_url":"https://api.github.com/repos/boto/botocore/statuses/bb1eb373021d51b4307fa1fbed156965181625a3","head":{"label":"JordonPhillips:stubbing","ref":"stubbing","sha":"bb1eb373021d51b4307fa1fbed156965181625a3","user":{"login":"JordonPhillips","id":2643092,"avatar_url":"https://avatars.githubusercontent.com/u/2643092?v=3","gravatar_id":"","url":"https://api.github.com/users/JordonPhillips","html_url":"https://github.com/JordonPhillips","followers_url":"https://api.github.com/users/JordonPhillips/followers","following_url":"https://api.github.com/users/JordonPhillips/following{/other_user}","gists_url":"https://api.github.com/users/JordonPhillips/gists{/gist_id}","starred_url":"https://api.github.com/users/JordonPhillips/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JordonPhillips/subscriptions","organizations_url":"https://api.github.com/users/JordonPhillips/orgs","repos_url":"https://api.github.com/users/JordonPhillips/repos","events_url":"https://api.github.com/users/JordonPhillips/events{/privacy}","received_events_url":"https://api.github.com/users/JordonPhillips/received_events","type":"User","site_admin":false},"repo":{"id":41875883,"name":"botocore","full_name":"JordonPhillips/botocore","owner":{"login":"JordonPhillips","id":2643092,"avatar_url":"https://avatars.githubusercontent.com/u/2643092?v=3","gravatar_id":"","url":"https://api.github.com/users/JordonPhillips","html_url":"https://github.com/JordonPhillips","followers_url":"https://api.github.com/users/JordonPhillips/followers","following_url":"https://api.github.com/users/JordonPhillips/following{/other_user}","gists_url":"https://api.github.com/users/JordonPhillips/gists{/gist_id}","starred_url":"https://api.github.com/users/JordonPhillips/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JordonPhillips/subscriptions","organizations_url":"https://api.github.com/users/JordonPhillips/orgs","repos_url":"https://api.github.com/users/JordonPhillips/repos","events_url":"https://api.github.com/users/JordonPhillips/events{/privacy}","received_events_url":"https://api.github.com/users/JordonPhillips/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/JordonPhillips/botocore","description":"The low-level, core functionality of boto 3.","fork":true,"url":"https://api.github.com/repos/JordonPhillips/botocore","forks_url":"https://api.github.com/repos/JordonPhillips/botocore/forks","keys_url":"https://api.github.com/repos/JordonPhillips/botocore/keys{/key_id}","collaborators_url":"https://api.github.com/repos/JordonPhillips/botocore/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/JordonPhillips/botocore/teams","hooks_url":"https://api.github.com/repos/JordonPhillips/botocore/hooks","issue_events_url":"https://api.github.com/repos/JordonPhillips/botocore/issues/events{/number}","events_url":"https://api.github.com/repos/JordonPhillips/botocore/events","assignees_url":"https://api.github.com/repos/JordonPhillips/botocore/assignees{/user}","branches_url":"https://api.github.com/repos/JordonPhillips/botocore/branches{/branch}","tags_url":"https://api.github.com/repos/JordonPhillips/botocore/tags","blobs_url":"https://api.github.com/repos/JordonPhillips/botocore/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/JordonPhillips/botocore/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/JordonPhillips/botocore/git/refs{/sha}","trees_url":"https://api.github.com/repos/JordonPhillips/botocore/git/trees{/sha}","statuses_url":"https://api.github.com/repos/JordonPhillips/botocore/statuses/{sha}","languages_url":"https://api.github.com/repos/JordonPhillips/botocore/languages","stargazers_url":"https://api.github.com/repos/JordonPhillips/botocore/stargazers","contributors_url":"https://api.github.com/repos/JordonPhillips/botocore/contributors","subscribers_url":"https://api.github.com/repos/JordonPhillips/botocore/subscribers","subscription_url":"https://api.github.com/repos/JordonPhillips/botocore/subscription","commits_url":"https://api.github.com/repos/JordonPhillips/botocore/commits{/sha}","git_commits_url":"https://api.github.com/repos/JordonPhillips/botocore/git/commits{/sha}","comments_url":"https://api.github.com/repos/JordonPhillips/botocore/comments{/number}","issue_comment_url":"https://api.github.com/repos/JordonPhillips/botocore/issues/comments{/number}","contents_url":"https://api.github.com/repos/JordonPhillips/botocore/contents/{+path}","compare_url":"https://api.github.com/repos/JordonPhillips/botocore/compare/{base}...{head}","merges_url":"https://api.github.com/repos/JordonPhillips/botocore/merges","archive_url":"https://api.github.com/repos/JordonPhillips/botocore/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/JordonPhillips/botocore/downloads","issues_url":"https://api.github.com/repos/JordonPhillips/botocore/issues{/number}","pulls_url":"https://api.github.com/repos/JordonPhillips/botocore/pulls{/number}","milestones_url":"https://api.github.com/repos/JordonPhillips/botocore/milestones{/number}","notifications_url":"https://api.github.com/repos/JordonPhillips/botocore/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/JordonPhillips/botocore/labels{/name}","releases_url":"https://api.github.com/repos/JordonPhillips/botocore/releases{/id}","deployments_url":"https://api.github.com/repos/JordonPhillips/botocore/deployments","created_at":"2015-09-03T18:13:17Z","updated_at":"2016-01-11T18:57:53Z","pushed_at":"2016-01-22T20:48:43Z","git_url":"git://github.com/JordonPhillips/botocore.git","ssh_url":"git@github.com:JordonPhillips/botocore.git","clone_url":"https://github.com/JordonPhillips/botocore.git","svn_url":"https://github.com/JordonPhillips/botocore","homepage":null,"size":19619,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"develop"}},"base":{"label":"boto:develop","ref":"develop","sha":"71a95fb7a8c961d87439f50e9a5bdee0757061de","user":{"login":"boto","id":327752,"avatar_url":"https://avatars.githubusercontent.com/u/327752?v=3","gravatar_id":"","url":"https://api.github.com/users/boto","html_url":"https://github.com/boto","followers_url":"https://api.github.com/users/boto/followers","following_url":"https://api.github.com/users/boto/following{/other_user}","gists_url":"https://api.github.com/users/boto/gists{/gist_id}","starred_url":"https://api.github.com/users/boto/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/boto/subscriptions","organizations_url":"https://api.github.com/users/boto/orgs","repos_url":"https://api.github.com/users/boto/repos","events_url":"https://api.github.com/users/boto/events{/privacy}","received_events_url":"https://api.github.com/users/boto/received_events","type":"Organization","site_admin":false},"repo":{"id":6670942,"name":"botocore","full_name":"boto/botocore","owner":{"login":"boto","id":327752,"avatar_url":"https://avatars.githubusercontent.com/u/327752?v=3","gravatar_id":"","url":"https://api.github.com/users/boto","html_url":"https://github.com/boto","followers_url":"https://api.github.com/users/boto/followers","following_url":"https://api.github.com/users/boto/following{/other_user}","gists_url":"https://api.github.com/users/boto/gists{/gist_id}","starred_url":"https://api.github.com/users/boto/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/boto/subscriptions","organizations_url":"https://api.github.com/users/boto/orgs","repos_url":"https://api.github.com/users/boto/repos","events_url":"https://api.github.com/users/boto/events{/privacy}","received_events_url":"https://api.github.com/users/boto/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/boto/botocore","description":"The low-level, core functionality of boto 3.","fork":false,"url":"https://api.github.com/repos/boto/botocore","forks_url":"https://api.github.com/repos/boto/botocore/forks","keys_url":"https://api.github.com/repos/boto/botocore/keys{/key_id}","collaborators_url":"https://api.github.com/repos/boto/botocore/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/boto/botocore/teams","hooks_url":"https://api.github.com/repos/boto/botocore/hooks","issue_events_url":"https://api.github.com/repos/boto/botocore/issues/events{/number}","events_url":"https://api.github.com/repos/boto/botocore/events","assignees_url":"https://api.github.com/repos/boto/botocore/assignees{/user}","branches_url":"https://api.github.com/repos/boto/botocore/branches{/branch}","tags_url":"https://api.github.com/repos/boto/botocore/tags","blobs_url":"https://api.github.com/repos/boto/botocore/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/boto/botocore/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/boto/botocore/git/refs{/sha}","trees_url":"https://api.github.com/repos/boto/botocore/git/trees{/sha}","statuses_url":"https://api.github.com/repos/boto/botocore/statuses/{sha}","languages_url":"https://api.github.com/repos/boto/botocore/languages","stargazers_url":"https://api.github.com/repos/boto/botocore/stargazers","contributors_url":"https://api.github.com/repos/boto/botocore/contributors","subscribers_url":"https://api.github.com/repos/boto/botocore/subscribers","subscription_url":"https://api.github.com/repos/boto/botocore/subscription","commits_url":"https://api.github.com/repos/boto/botocore/commits{/sha}","git_commits_url":"https://api.github.com/repos/boto/botocore/git/commits{/sha}","comments_url":"https://api.github.com/repos/boto/botocore/comments{/number}","issue_comment_url":"https://api.github.com/repos/boto/botocore/issues/comments{/number}","contents_url":"https://api.github.com/repos/boto/botocore/contents/{+path}","compare_url":"https://api.github.com/repos/boto/botocore/compare/{base}...{head}","merges_url":"https://api.github.com/repos/boto/botocore/merges","archive_url":"https://api.github.com/repos/boto/botocore/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/boto/botocore/downloads","issues_url":"https://api.github.com/repos/boto/botocore/issues{/number}","pulls_url":"https://api.github.com/repos/boto/botocore/pulls{/number}","milestones_url":"https://api.github.com/repos/boto/botocore/milestones{/number}","notifications_url":"https://api.github.com/repos/boto/botocore/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/boto/botocore/labels{/name}","releases_url":"https://api.github.com/repos/boto/botocore/releases{/id}","deployments_url":"https://api.github.com/repos/boto/botocore/deployments","created_at":"2012-11-13T13:25:36Z","updated_at":"2016-01-20T04:47:10Z","pushed_at":"2016-01-22T20:48:43Z","git_url":"git://github.com/boto/botocore.git","ssh_url":"git@github.com:boto/botocore.git","clone_url":"https://github.com/boto/botocore.git","svn_url":"https://github.com/boto/botocore","homepage":null,"size":21188,"stargazers_count":216,"watchers_count":216,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":135,"mirror_url":null,"open_issues_count":23,"forks":135,"open_issues":23,"watchers":216,"default_branch":"develop"}},"_links":{"self":{"href":"https://api.github.com/repos/boto/botocore/pulls/741"},"html":{"href":"https://github.com/boto/botocore/pull/741"},"issue":{"href":"https://api.github.com/repos/boto/botocore/issues/741"},"comments":{"href":"https://api.github.com/repos/boto/botocore/issues/741/comments"},"review_comments":{"href":"https://api.github.com/repos/boto/botocore/pulls/741/comments"},"review_comment":{"href":"https://api.github.com/repos/boto/botocore/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/boto/botocore/pulls/741/commits"},"statuses":{"href":"https://api.github.com/repos/boto/botocore/statuses/bb1eb373021d51b4307fa1fbed156965181625a3"}}}}