{"action":"created","comment":{"url":"https://api.github.com/repos/spulec/moto/pulls/comments/45325529","id":45325529,"diff_hunk":"@@ -0,0 +1,405 @@\n+from __future__ import unicode_literals\n+import six\n+\n+import boto.swf\n+\n+from moto.core import BaseBackend\n+\n+from ..exceptions import (\n+    SWFUnknownResourceFault,\n+    SWFDomainAlreadyExistsFault,\n+    SWFDomainDeprecatedFault,\n+    SWFSerializationException,\n+    SWFTypeAlreadyExistsFault,\n+    SWFTypeDeprecatedFault,\n+    SWFValidationException,\n+)\n+from .activity_task import ActivityTask\n+from .activity_type import ActivityType\n+from .decision_task import DecisionTask\n+from .domain import Domain\n+from .generic_type import GenericType\n+from .history_event import HistoryEvent\n+from .timeout import Timeout\n+from .workflow_type import WorkflowType\n+from .workflow_execution import WorkflowExecution\n+\n+\n+class SWFBackend(BaseBackend):\n+    def __init__(self, region_name):\n+        self.region_name = region_name\n+        self.domains = []\n+        super(SWFBackend, self).__init__()\n+\n+    def reset(self):\n+        region_name = self.region_name\n+        self.__dict__ = {}\n+        self.__init__(region_name)\n+\n+    def _get_domain(self, name, ignore_empty=False):\n+        matching = [domain for domain in self.domains if domain.name == name]\n+        if not matching and not ignore_empty:\n+            raise SWFUnknownResourceFault(\"domain\", name)\n+        if matching:\n+            return matching[0]\n+        return None\n+\n+    def _check_none_or_string(self, parameter):\n+        if parameter is not None:\n+            self._check_string(parameter)\n+\n+    def _check_string(self, parameter):\n+        if not isinstance(parameter, six.string_types):\n+            raise SWFSerializationException(parameter)\n+\n+    def _check_none_or_list_of_strings(self, parameter):\n+        if parameter is not None:\n+            self._check_list_of_strings(parameter)\n+\n+    def _check_list_of_strings(self, parameter):\n+        if not isinstance(parameter, list):\n+            raise SWFSerializationException(parameter)\n+        for i in parameter:\n+            if not isinstance(i, six.string_types):\n+                raise SWFSerializationException(parameter)\n+\n+    def _process_timeouts(self):\n+        for domain in self.domains:\n+            for wfe in domain.workflow_executions:\n+                wfe._process_timeouts()\n+\n+    def list_domains(self, status, reverse_order=None):\n+        self._check_string(status)\n+        domains = [domain for domain in self.domains\n+                   if domain.status == status]\n+        domains = sorted(domains, key=lambda domain: domain.name)\n+        if reverse_order:\n+            domains = reversed(domains)\n+        return domains\n+\n+    def register_domain(self, name, workflow_execution_retention_period_in_days,\n+                        description=None):\n+        self._check_string(name)\n+        self._check_string(workflow_execution_retention_period_in_days)\n+        self._check_none_or_string(description)\n+        if self._get_domain(name, ignore_empty=True):\n+            raise SWFDomainAlreadyExistsFault(name)\n+        domain = Domain(name, workflow_execution_retention_period_in_days,\n+                        description)\n+        self.domains.append(domain)\n+\n+    def deprecate_domain(self, name):\n+        self._check_string(name)\n+        domain = self._get_domain(name)\n+        if domain.status == \"DEPRECATED\":\n+            raise SWFDomainDeprecatedFault(name)\n+        domain.status = \"DEPRECATED\"\n+\n+    def describe_domain(self, name):\n+        self._check_string(name)\n+        return self._get_domain(name)\n+\n+    def list_types(self, kind, domain_name, status, reverse_order=None):\n+        self._check_string(domain_name)\n+        self._check_string(status)\n+        domain = self._get_domain(domain_name)\n+        _types = domain.find_types(kind, status)\n+        _types = sorted(_types, key=lambda domain: domain.name)\n+        if reverse_order:\n+            _types = reversed(_types)\n+        return _types\n+\n+    def register_type(self, kind, domain_name, name, version, **kwargs):\n+        self._check_string(domain_name)","path":"moto/swf/models/__init__.py","position":113,"original_position":113,"commit_id":"76bea30f4bc6c75bd8053186fcb442d9539685b7","original_commit_id":"76bea30f4bc6c75bd8053186fcb442d9539685b7","user":{"login":"jbbarth","id":29363,"avatar_url":"https://avatars.githubusercontent.com/u/29363?v=3","gravatar_id":"","url":"https://api.github.com/users/jbbarth","html_url":"https://github.com/jbbarth","followers_url":"https://api.github.com/users/jbbarth/followers","following_url":"https://api.github.com/users/jbbarth/following{/other_user}","gists_url":"https://api.github.com/users/jbbarth/gists{/gist_id}","starred_url":"https://api.github.com/users/jbbarth/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jbbarth/subscriptions","organizations_url":"https://api.github.com/users/jbbarth/orgs","repos_url":"https://api.github.com/users/jbbarth/repos","events_url":"https://api.github.com/users/jbbarth/events{/privacy}","received_events_url":"https://api.github.com/users/jbbarth/received_events","type":"User","site_admin":false},"body":"I'll move them no problem, makes sense!","created_at":"2015-11-19T10:47:56Z","updated_at":"2015-11-19T10:47:56Z","html_url":"https://github.com/spulec/moto/pull/451#discussion_r45325529","pull_request_url":"https://api.github.com/repos/spulec/moto/pulls/451","_links":{"self":{"href":"https://api.github.com/repos/spulec/moto/pulls/comments/45325529"},"html":{"href":"https://github.com/spulec/moto/pull/451#discussion_r45325529"},"pull_request":{"href":"https://api.github.com/repos/spulec/moto/pulls/451"}}},"pull_request":{"url":"https://api.github.com/repos/spulec/moto/pulls/451","id":50193563,"html_url":"https://github.com/spulec/moto/pull/451","diff_url":"https://github.com/spulec/moto/pull/451.diff","patch_url":"https://github.com/spulec/moto/pull/451.patch","issue_url":"https://api.github.com/repos/spulec/moto/issues/451","number":451,"state":"open","locked":false,"title":"[wip] Add SWF support","user":{"login":"jbbarth","id":29363,"avatar_url":"https://avatars.githubusercontent.com/u/29363?v=3","gravatar_id":"","url":"https://api.github.com/users/jbbarth","html_url":"https://github.com/jbbarth","followers_url":"https://api.github.com/users/jbbarth/followers","following_url":"https://api.github.com/users/jbbarth/following{/other_user}","gists_url":"https://api.github.com/users/jbbarth/gists{/gist_id}","starred_url":"https://api.github.com/users/jbbarth/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jbbarth/subscriptions","organizations_url":"https://api.github.com/users/jbbarth/orgs","repos_url":"https://api.github.com/users/jbbarth/repos","events_url":"https://api.github.com/users/jbbarth/events{/privacy}","received_events_url":"https://api.github.com/users/jbbarth/received_events","type":"User","site_admin":false},"body":"*Work in progress, do NOT merge!*\r\n\r\nSee #429. This branch implements mocks for SWF endpoints, mapping directly to `boto.swf.Layer1`, which is the low-level layer used by `boto.swf.Layer2` and libraries above. As SWF is mostly a coordination service with complex logic, so making moto/swf useful boils down to reimplementing part of the logic behind SWF (much more easy though: non distributed, few limits, no permissions).\r\n\r\n## Implementation progress\r\n\r\nImplemented endpoints ([by category](http://docs.aws.amazon.com/amazonswf/latest/developerguide/swf-api-by-category.html)):\r\n- **Actions Related to Activities**\r\n  - [x] PollForActivityTask\r\n  - [x] RespondActivityTaskCompleted\r\n  - [x] RespondActivityTaskFailed\r\n  - [ ] RespondActivityTaskCanceled\r\n  - [x] RecordActivityTaskHeartbeat\r\n- **Actions Related to Deciders**\r\n  - [x] PollForDecisionTask\r\n  - [x] RespondDecisionTaskCompleted (partial; see below)\r\n- **Actions Related to Workflow Executions**\r\n  - [ ] RequestCancelWorkflowExecution\r\n  - [x] StartWorkflowExecution\r\n  - [ ] SignalWorkflowExecution\r\n  - [x] TerminateWorkflowExecution\r\n- **Actions Related to Administration**\r\n  - *Activity Management*\r\n    - [x] RegisterActivityType\r\n    - [x] DeprecateActivityType\r\n  - *Workflow Management*\r\n    - [x] RegisterWorkflowType\r\n    - [x] DeprecateWorkflowType\r\n  - *Domain Management*\r\n    - [x] RegisterDomain\r\n    - [x] DeprecateDomain\r\n- **Visibility Actions**\r\n  - *Activity Visibility*\r\n    - [x] ListActivityTypes\r\n    - [x] DescribeActivityType\r\n  - *Workflow Visibility*\r\n    - [x] ListWorkflowTypes\r\n    - [x] DescribeWorkflowType\r\n  - *Workflow Execution Visibility*\r\n    - [x] DescribeWorkflowExecution\r\n    - [ ] ListOpenWorkflowExecutions\r\n    - [ ] ListClosedWorkflowExecutions\r\n    - [ ] CountOpenWorkflowExecutions\r\n    - [ ] CountClosedWorkflowExecutions\r\n    - [x] GetWorkflowExecutionHistory\r\n  - *Domain Visibility*\r\n    - [x] ListDomains\r\n    - [x] DescribeDomain\r\n  - *Task List Visibility*\r\n    - [x] CountPendingActivityTasks\r\n    - [x] CountPendingDecisionTasks\r\n\r\nImplemented decision types for [RespondDecisionTaskCompleted endpoint](http://docs.aws.amazon.com/amazonswf/latest/apireference/API_RespondDecisionTaskCompleted.html):\r\n- [ ] CancelTimer\r\n- [ ] CancelWorkflowExecution\r\n- [ ] ContinueAsNewWorkflowExecution\r\n- [x] CompleteWorkflowExecution\r\n- [x] FailWorkflowExecution\r\n- [ ] RecordMarker\r\n- [ ] RequestCancelActivityTask\r\n- [ ] RequestCancelExternalWorkflowExecution\r\n- [x] ScheduleActivityTask\r\n- [ ] ScheduleLambdaFunction\r\n- [ ] SignalExternalWorkflowExecution\r\n- [ ] StartChildWorkflowExecution\r\n- [ ] StartTimer\r\n\r\nImplemented [timeout types](http://docs.aws.amazon.com/amazonswf/latest/developerguide/swf-timeout-types.html):\r\n- [x] Workflow Execution: Execution Start to Close\r\n- [x] Decision Task: Start to Close\r\n- [x] Activity Task: Heartbeat\r\n- [ ] Activity Task: Schedule to Close\r\n- [ ] Activity Task: Schedule to Start\r\n- [ ] Activity Task: Start to Close\r\n\r\nImplemented [limits](http://docs.aws.amazon.com/amazonswf/latest/developerguide/swf-dg-limits.html) (most are hard to test or implement, this section is only there as reference):\r\n\r\n- *General limits*\r\n  - [ ] Maximum registered domains: 100\r\n  - [ ] Maximum workflow and activity types: 10,000 each per domain [likely never]\r\n  - [ ] Maximum request size: 1 MB per request\r\n- *Limits on Workflow Executions*\r\n  - [ ] Maximum open workflow executions: 100,000 per domain [likely never]\r\n  - [ ] Maximum workflow execution time: 1 year [likely never]\r\n  - [ ] Maximum workflow execution history size: 25,000 events [will do]\r\n  - [ ] Maximum child workflow executions: 1,000 per workflow execution. [will do]\r\n  - [ ] Workflow execution idle time limit: 1 year [likely never]\r\n- *Limits on Task Executions*\r\n  - [ ] Maximum task execution time: 1 year (constrained by workflow execution time limit) [likely never]\r\n  - [ ] Maximum time SWF will keep a task in the queue: 1 year (constrained by workflow execution time limit) [likely never]\r\n  - [ ] Maximum open activity tasks: 1,000 per workflow execution. [will do]\r\n  - [ ] Maximum open timers: 1,000 per workflow execution [will do]\r\n  - [ ] Maximum input/result data size: 32,000 characters [will do]\r\n  - Maximum decisions in a decision task response [will do]\r\n- *Throttling limits*\r\n  - none: too hard and few benefits in the general case\r\n\r\n## Known limitations\r\n\r\n- permissions and request limits are not implemented, namely `LimitExceededFault` and `OperationNotPermittedFault` ; I don't think it's needed for now\r\n- pagination and max number of results are generally not implemented (`nextPageToken` is omitted in responses ; `nextPageToken` and `maximumPageSize` have no effect in requests) ; but I think I'll implement them because I need to test SWF limits in our client library\r\n- in case of timeouts, the timeout events are properly timestamped but the successive decisions may not be ; this is because we don't have a running daemon to handle things at regular interval, so history is computed on demand afterwards ; this will eventually be fixed\r\n- + some TODO comments in the code\r\n\r\n\r\n## Some remarks\r\n\r\n- I wanted to have a working service before submitting a PR, but I do understand that it is a lot of code to review ; you can mostly follow the progress commit by commit, should be easier to handle\r\n- I'm not happy with `moto.swf.responses.SWFResponse.call_action()`, which is completely copied from `BaseResponse` except one modified line (see comment inside) ; I don't know if it could be changed though,  what do you think?\r\n- I had trouble working with freezed dates + timestamps ; Travis assumes dates are in UTC it seems, so I personnally run the tests with `TZ=GMT`; don't know if it should be part of the Makefile or something else\r\n- I'm not sure which names should have been namespaced, let me know ; \"Timeout\" for instance may be too generic (?)\r\n- I wonder where to keep some documentation, especially where to keep track of a status of what is implemented like I did above\r\n\r\nAs a general remark, I'm just a beginner in Python so let me know if you see any improvement, I'd be happy to learn.\r\n\r\nAlso I realize the end result might be a bit complicated for now. It could be simplified or released as a separate lib if you tell me so.\r\n\r\nI'll continue to work on this PR in the next few days. Thanks!","created_at":"2015-11-09T23:26:14Z","updated_at":"2015-11-19T10:47:56Z","closed_at":null,"merged_at":null,"merge_commit_sha":"67c79eaec6792e83a21998b281091d201e4227be","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/spulec/moto/pulls/451/commits","review_comments_url":"https://api.github.com/repos/spulec/moto/pulls/451/comments","review_comment_url":"https://api.github.com/repos/spulec/moto/pulls/comments{/number}","comments_url":"https://api.github.com/repos/spulec/moto/issues/451/comments","statuses_url":"https://api.github.com/repos/spulec/moto/statuses/76bea30f4bc6c75bd8053186fcb442d9539685b7","head":{"label":"botify-labs:feature/add-swf","ref":"feature/add-swf","sha":"76bea30f4bc6c75bd8053186fcb442d9539685b7","user":{"login":"botify-labs","id":2925517,"avatar_url":"https://avatars.githubusercontent.com/u/2925517?v=3","gravatar_id":"","url":"https://api.github.com/users/botify-labs","html_url":"https://github.com/botify-labs","followers_url":"https://api.github.com/users/botify-labs/followers","following_url":"https://api.github.com/users/botify-labs/following{/other_user}","gists_url":"https://api.github.com/users/botify-labs/gists{/gist_id}","starred_url":"https://api.github.com/users/botify-labs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/botify-labs/subscriptions","organizations_url":"https://api.github.com/users/botify-labs/orgs","repos_url":"https://api.github.com/users/botify-labs/repos","events_url":"https://api.github.com/users/botify-labs/events{/privacy}","received_events_url":"https://api.github.com/users/botify-labs/received_events","type":"Organization","site_admin":false},"repo":{"id":9237416,"name":"moto","full_name":"botify-labs/moto","owner":{"login":"botify-labs","id":2925517,"avatar_url":"https://avatars.githubusercontent.com/u/2925517?v=3","gravatar_id":"","url":"https://api.github.com/users/botify-labs","html_url":"https://github.com/botify-labs","followers_url":"https://api.github.com/users/botify-labs/followers","following_url":"https://api.github.com/users/botify-labs/following{/other_user}","gists_url":"https://api.github.com/users/botify-labs/gists{/gist_id}","starred_url":"https://api.github.com/users/botify-labs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/botify-labs/subscriptions","organizations_url":"https://api.github.com/users/botify-labs/orgs","repos_url":"https://api.github.com/users/botify-labs/repos","events_url":"https://api.github.com/users/botify-labs/events{/privacy}","received_events_url":"https://api.github.com/users/botify-labs/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/botify-labs/moto","description":"Moto is a library that allows your python tests to easily mock out the boto library","fork":true,"url":"https://api.github.com/repos/botify-labs/moto","forks_url":"https://api.github.com/repos/botify-labs/moto/forks","keys_url":"https://api.github.com/repos/botify-labs/moto/keys{/key_id}","collaborators_url":"https://api.github.com/repos/botify-labs/moto/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/botify-labs/moto/teams","hooks_url":"https://api.github.com/repos/botify-labs/moto/hooks","issue_events_url":"https://api.github.com/repos/botify-labs/moto/issues/events{/number}","events_url":"https://api.github.com/repos/botify-labs/moto/events","assignees_url":"https://api.github.com/repos/botify-labs/moto/assignees{/user}","branches_url":"https://api.github.com/repos/botify-labs/moto/branches{/branch}","tags_url":"https://api.github.com/repos/botify-labs/moto/tags","blobs_url":"https://api.github.com/repos/botify-labs/moto/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/botify-labs/moto/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/botify-labs/moto/git/refs{/sha}","trees_url":"https://api.github.com/repos/botify-labs/moto/git/trees{/sha}","statuses_url":"https://api.github.com/repos/botify-labs/moto/statuses/{sha}","languages_url":"https://api.github.com/repos/botify-labs/moto/languages","stargazers_url":"https://api.github.com/repos/botify-labs/moto/stargazers","contributors_url":"https://api.github.com/repos/botify-labs/moto/contributors","subscribers_url":"https://api.github.com/repos/botify-labs/moto/subscribers","subscription_url":"https://api.github.com/repos/botify-labs/moto/subscription","commits_url":"https://api.github.com/repos/botify-labs/moto/commits{/sha}","git_commits_url":"https://api.github.com/repos/botify-labs/moto/git/commits{/sha}","comments_url":"https://api.github.com/repos/botify-labs/moto/comments{/number}","issue_comment_url":"https://api.github.com/repos/botify-labs/moto/issues/comments{/number}","contents_url":"https://api.github.com/repos/botify-labs/moto/contents/{+path}","compare_url":"https://api.github.com/repos/botify-labs/moto/compare/{base}...{head}","merges_url":"https://api.github.com/repos/botify-labs/moto/merges","archive_url":"https://api.github.com/repos/botify-labs/moto/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/botify-labs/moto/downloads","issues_url":"https://api.github.com/repos/botify-labs/moto/issues{/number}","pulls_url":"https://api.github.com/repos/botify-labs/moto/pulls{/number}","milestones_url":"https://api.github.com/repos/botify-labs/moto/milestones{/number}","notifications_url":"https://api.github.com/repos/botify-labs/moto/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/botify-labs/moto/labels{/name}","releases_url":"https://api.github.com/repos/botify-labs/moto/releases{/id}","created_at":"2013-04-05T08:55:30Z","updated_at":"2015-09-29T23:50:07Z","pushed_at":"2015-11-18T21:04:29Z","git_url":"git://github.com/botify-labs/moto.git","ssh_url":"git@github.com:botify-labs/moto.git","clone_url":"https://github.com/botify-labs/moto.git","svn_url":"https://github.com/botify-labs/moto","homepage":null,"size":2249,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"spulec:master","ref":"master","sha":"ab3682a55c1c4f2983819e73a8cc59c0159a33f3","user":{"login":"spulec","id":292606,"avatar_url":"https://avatars.githubusercontent.com/u/292606?v=3","gravatar_id":"","url":"https://api.github.com/users/spulec","html_url":"https://github.com/spulec","followers_url":"https://api.github.com/users/spulec/followers","following_url":"https://api.github.com/users/spulec/following{/other_user}","gists_url":"https://api.github.com/users/spulec/gists{/gist_id}","starred_url":"https://api.github.com/users/spulec/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/spulec/subscriptions","organizations_url":"https://api.github.com/users/spulec/orgs","repos_url":"https://api.github.com/users/spulec/repos","events_url":"https://api.github.com/users/spulec/events{/privacy}","received_events_url":"https://api.github.com/users/spulec/received_events","type":"User","site_admin":false},"repo":{"id":8277372,"name":"moto","full_name":"spulec/moto","owner":{"login":"spulec","id":292606,"avatar_url":"https://avatars.githubusercontent.com/u/292606?v=3","gravatar_id":"","url":"https://api.github.com/users/spulec","html_url":"https://github.com/spulec","followers_url":"https://api.github.com/users/spulec/followers","following_url":"https://api.github.com/users/spulec/following{/other_user}","gists_url":"https://api.github.com/users/spulec/gists{/gist_id}","starred_url":"https://api.github.com/users/spulec/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/spulec/subscriptions","organizations_url":"https://api.github.com/users/spulec/orgs","repos_url":"https://api.github.com/users/spulec/repos","events_url":"https://api.github.com/users/spulec/events{/privacy}","received_events_url":"https://api.github.com/users/spulec/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/spulec/moto","description":"Moto is a library that allows your python tests to easily mock out the boto library","fork":false,"url":"https://api.github.com/repos/spulec/moto","forks_url":"https://api.github.com/repos/spulec/moto/forks","keys_url":"https://api.github.com/repos/spulec/moto/keys{/key_id}","collaborators_url":"https://api.github.com/repos/spulec/moto/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/spulec/moto/teams","hooks_url":"https://api.github.com/repos/spulec/moto/hooks","issue_events_url":"https://api.github.com/repos/spulec/moto/issues/events{/number}","events_url":"https://api.github.com/repos/spulec/moto/events","assignees_url":"https://api.github.com/repos/spulec/moto/assignees{/user}","branches_url":"https://api.github.com/repos/spulec/moto/branches{/branch}","tags_url":"https://api.github.com/repos/spulec/moto/tags","blobs_url":"https://api.github.com/repos/spulec/moto/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/spulec/moto/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/spulec/moto/git/refs{/sha}","trees_url":"https://api.github.com/repos/spulec/moto/git/trees{/sha}","statuses_url":"https://api.github.com/repos/spulec/moto/statuses/{sha}","languages_url":"https://api.github.com/repos/spulec/moto/languages","stargazers_url":"https://api.github.com/repos/spulec/moto/stargazers","contributors_url":"https://api.github.com/repos/spulec/moto/contributors","subscribers_url":"https://api.github.com/repos/spulec/moto/subscribers","subscription_url":"https://api.github.com/repos/spulec/moto/subscription","commits_url":"https://api.github.com/repos/spulec/moto/commits{/sha}","git_commits_url":"https://api.github.com/repos/spulec/moto/git/commits{/sha}","comments_url":"https://api.github.com/repos/spulec/moto/comments{/number}","issue_comment_url":"https://api.github.com/repos/spulec/moto/issues/comments{/number}","contents_url":"https://api.github.com/repos/spulec/moto/contents/{+path}","compare_url":"https://api.github.com/repos/spulec/moto/compare/{base}...{head}","merges_url":"https://api.github.com/repos/spulec/moto/merges","archive_url":"https://api.github.com/repos/spulec/moto/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/spulec/moto/downloads","issues_url":"https://api.github.com/repos/spulec/moto/issues{/number}","pulls_url":"https://api.github.com/repos/spulec/moto/pulls{/number}","milestones_url":"https://api.github.com/repos/spulec/moto/milestones{/number}","notifications_url":"https://api.github.com/repos/spulec/moto/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/spulec/moto/labels{/name}","releases_url":"https://api.github.com/repos/spulec/moto/releases{/id}","created_at":"2013-02-18T21:10:59Z","updated_at":"2015-11-18T19:13:42Z","pushed_at":"2015-11-17T17:47:15Z","git_url":"git://github.com/spulec/moto.git","ssh_url":"git@github.com:spulec/moto.git","clone_url":"https://github.com/spulec/moto.git","svn_url":"https://github.com/spulec/moto","homepage":null,"size":4908,"stargazers_count":573,"watchers_count":573,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":166,"mirror_url":null,"open_issues_count":37,"forks":166,"open_issues":37,"watchers":573,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/spulec/moto/pulls/451"},"html":{"href":"https://github.com/spulec/moto/pull/451"},"issue":{"href":"https://api.github.com/repos/spulec/moto/issues/451"},"comments":{"href":"https://api.github.com/repos/spulec/moto/issues/451/comments"},"review_comments":{"href":"https://api.github.com/repos/spulec/moto/pulls/451/comments"},"review_comment":{"href":"https://api.github.com/repos/spulec/moto/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/spulec/moto/pulls/451/commits"},"statuses":{"href":"https://api.github.com/repos/spulec/moto/statuses/76bea30f4bc6c75bd8053186fcb442d9539685b7"}}}}