{"action":"created","comment":{"url":"https://api.github.com/repos/makaimann/smt-switch/pulls/comments/125101859","pull_request_review_id":47463392,"id":125101859,"diff_hunk":"@@ -1,480 +1,222 @@\n-from abc import ABCMeta, abstractmethod\n-from functools import reduce\n-import inspect\n-from . import sorts\n-from . import smtutils\n+from functools import partial, update_wrapper\n+from collections import namedtuple\n+import sys\n from ..config import config\n+from . import sorts\n \n \n-__MAXARGS__ = 6000\n-\n-\n-class FunctionBase(metaclass=ABCMeta):\n-    def __init__(self, arity, usage):\n-        self._arity = arity\n-        self._usage = usage\n-\n-    @property\n-    def arity(self):\n-        return self._arity\n-\n-    @property\n-    def usage(self):\n-        return self._usage\n-\n-    @property\n-    def params(self):\n-        '''\n-            Holds the parameters needed to apply the function.\n-            Ex// (_ extract 12 6)\n-            Functions with nontrivial params overload this property\n-        '''\n-        return ()\n-\n-    @abstractmethod\n-    def osort(self, *args):\n-        pass\n-\n-    def __call__(self, *args):\n-        if config.strict:\n-            raise ValueError('Functions are not callable in strict mode.' +\n-                            ' Use solver.apply_fun(fun, *args)')\n-        # handle list argument\n-        if args and isinstance(args[0], list):\n-            args = args[0]\n-\n-        if args:\n-            # Not pretty but trying to avoid circular dependency\n-            s_terms = list(filter(lambda arg: 'TermBase' in [base.__name__ for base in arg.__class__.__bases__], args))\n-            if not s_terms:\n-                raise ValueError('There needs to be at least one argument of type [Solver Name]Term')\n-            return s_terms[0].solver.apply_fun(self, *args)\n-        else:\n-            raise ValueError('Incorrect number of arguments for' +\n-                             'function: {}'.format(self.__class__.__name__))\n-\n-    def __repr__(self):\n-        return self.__class__.__name__\n-\n-    def __eq__(self, other):\n-        '''\n-           Functions are defined by name and params only\n-        '''\n-        return self.__class__ == other.__class__ and self.params == other.params\n-\n-\n-class No_op(FunctionBase):\n-    arity = {'min': 0,\n-             'max': 0}\n-\n-    def __init__(self):\n-        super().__init__(self.arity, 'No_op')\n-\n-    def osort(self, *args):\n-        if len(args) == 0:\n-            raise ValueError('No_op is used when constructing constants. ' +\n-                             'Therefore its output sort is parameterized by a Term.' +\n-                             'Need to provide an argument to determine output sort')\n-        else:\n-            return args[0].sort\n-\n-\n-class Equals(FunctionBase):\n-    arity = {'min': 2,\n-             'max': 2}\n-\n-    def __init__(self):\n-        super().__init__(self.arity, '(= arg1 arg2)')\n-\n-    def osort(self, *args):\n-        return sorts.Bool()\n-\n-\n-class Not(FunctionBase):\n-    arity = {'min': 1,\n-             'max': 1}\n-\n-    def __init__(self):\n-        super().__init__(self.arity, '(not formula)')\n-\n-    def osort(self, *args):\n-        return sorts.Bool()\n-\n-\n-class And(FunctionBase):\n-    arity = {'min': 2,\n-             'max': __MAXARGS__}\n-\n-    def __init__(self):\n-        super().__init__(self.arity, '(and args)')\n-\n-    def osort(self, *args):\n-        return sorts.Bool()\n-\n-    # Overloading callable FunctionBase\n-    def __call__(self, *args):\n-        if config.strict:\n-            raise ValueError('Functions are not callable in strict mode. ' +\n-                             'Use solver.apply_fun(fun, *args)')\n-\n-        if args and isinstance(args[0], list):\n-            args = args[0]\n-\n-        # With strict=False, (and arg1) --> arg1, (and ) --> True\n-        if len(args) > 1:\n-            return args[0].solver.apply_fun(self, *args)\n-        elif len(args) == 1:\n-            return args[0]\n-        else:\n-            return True\n-\n-\n-class Or(FunctionBase):\n-    arity = {'min': 2,\n-             'max': __MAXARGS__}\n-\n-    def __init__(self):\n-        super().__init__(self.arity, '(or args)')\n-\n-    def osort(self, *args):\n-        return sorts.Bool()\n-\n-    # Overloading callable FunctionBase\n-    def __call__(self, *args):\n-        if config.strict:\n-            raise ValueError('Functions are not callable in strict mode. ' +\n-                             'Use solver.apply_fun(fun, *args)')\n-        if args and isinstance(args[0], list):\n-            args = args[0]\n-\n-        # With strict=False, (and arg1) --> arg1, (and ) --> True\n-        if len(args) > 1:\n-            return args[0].solver.apply_fun(self, *args)\n-        elif len(args) == 1:\n-            return args[0]\n-        else:\n-            return False\n-\n-\n-class Ite(FunctionBase):\n-    arity = {'min': 3,\n-             'max': 3}\n-\n-    def __init__(self):\n-        super().__init__(self.arity, '(ite cond arg1 arg2)')\n-\n-    def osort(self, *args):\n-        if len(args) != 3:\n-            raise ValueError(self.__class__name +\n-                             '\\'s output sort is parameterized by its arguments. ' +\n-                             'Need all three inputs to determine output sort.')\n-\n-        arg_sorts = smtutils.sorts_list(args)\n-\n-        # TODO: check for consistent output sort\n-        if not reduce(lambda x, y: x and y, arg_sorts[1:]):\n-            raise ValueError('Ite needs to have a consistent output sort. ' +\n-                             'Received {} and {}'.format(args[1].sort, args[2].sort))\n-        ite_sorts = list(filter(lambda arg: arg is not None, arg_sorts[1:]))\n-        if not ite_sorts:\n-            raise ValueError('Can\\'t determine output sort based on inputs {} and {}'.format(args[1], args[2]))\n-        return ite_sorts[0]\n-\n-\n-class Sub(FunctionBase):\n-    arity = {'min': 2,\n-             'max': 2}\n-\n-    def __init__(self):\n-        super().__init__(self.arity, '(- arg1 arg2)')\n-\n-    def osort(self, *args):\n-        if len(args) == 0:\n-            raise ValueError(self.__class__name +\n-                             '\\'s output sort is parameterized by its arguments. ' +\n-                             'Need an argument to determine output sort.')\n-        return args[0].sort\n-\n-\n-class Plus(FunctionBase):\n-    arity = {'min': 2,\n-             'max': __MAXARGS__}\n-\n-    def __init__(self):\n-        super().__init__(self.arity, '(+ arg1 arg2)')\n-\n-    def osort(self, *args):\n-        if len(args) == 0:\n-            raise ValueError(self.__class__name +\n-                             '\\'s output sort is parameterized by its arguments. ' +\n-                             'Need an argument to determine output sort.')\n-        return args[0].sort\n-\n-\n-class LT(FunctionBase):\n-    arity = {'min': 2,\n-             'max': 2}\n-\n-    def __init__(self):\n-        super().__init__(self.arity, '(< arg1 arg2)')\n-\n-    def osort(self, *args):\n-        return sorts.Bool()\n-\n-\n-class LEQ(FunctionBase):\n-    arity = {'min': 2,\n-             'max': 2}\n-\n-    def __init__(self):\n-        super().__init__(self.arity, '(<= arg1 arg2)')\n-\n-    def osort(self, *args):\n-        return sorts.Bool()\n-\n-\n-class GT(FunctionBase):\n-    arity = {'min': 2,\n-             'max': 2}\n+__all__ = ['And', 'Or']  # append to list in generate functions\n \n-    def __init__(self):\n-        super().__init__(self.arity, '(> arg1 arg2)')\n \n-    def osort(self, *args):\n-        return sorts.Bool()\n+fdata = namedtuple('fdata', 'num_indices, min_arity, max_arity')\n+__MAXARGS__ = 6000","path":"smt_switch/src/functions.py","position":251,"original_position":251,"commit_id":"973c04407dffdc290b686c7f36d2b7c98e877df0","original_commit_id":"973c04407dffdc290b686c7f36d2b7c98e877df0","user":{"login":"mpreiner","id":4653598,"avatar_url":"https://avatars3.githubusercontent.com/u/4653598?v=3","gravatar_id":"","url":"https://api.github.com/users/mpreiner","html_url":"https://github.com/mpreiner","followers_url":"https://api.github.com/users/mpreiner/followers","following_url":"https://api.github.com/users/mpreiner/following{/other_user}","gists_url":"https://api.github.com/users/mpreiner/gists{/gist_id}","starred_url":"https://api.github.com/users/mpreiner/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mpreiner/subscriptions","organizations_url":"https://api.github.com/users/mpreiner/orgs","repos_url":"https://api.github.com/users/mpreiner/repos","events_url":"https://api.github.com/users/mpreiner/events{/privacy}","received_events_url":"https://api.github.com/users/mpreiner/received_events","type":"User","site_admin":false},"body":"Is there a reason why 6000? Would it make sense to use -1 for an arbitrary number of arguments?","created_at":"2017-06-30T18:25:15Z","updated_at":"2017-06-30T18:25:16Z","html_url":"https://github.com/makaimann/smt-switch/pull/4#discussion_r125101859","pull_request_url":"https://api.github.com/repos/makaimann/smt-switch/pulls/4","_links":{"self":{"href":"https://api.github.com/repos/makaimann/smt-switch/pulls/comments/125101859"},"html":{"href":"https://github.com/makaimann/smt-switch/pull/4#discussion_r125101859"},"pull_request":{"href":"https://api.github.com/repos/makaimann/smt-switch/pulls/4"}}},"pull_request":{"url":"https://api.github.com/repos/makaimann/smt-switch/pulls/4","id":128280032,"html_url":"https://github.com/makaimann/smt-switch/pull/4","diff_url":"https://github.com/makaimann/smt-switch/pull/4.diff","patch_url":"https://github.com/makaimann/smt-switch/pull/4.patch","issue_url":"https://api.github.com/repos/makaimann/smt-switch/issues/4","number":4,"state":"open","locked":false,"title":"One operator class wrapping generated functions","user":{"login":"makaimann","id":23203473,"avatar_url":"https://avatars0.githubusercontent.com/u/23203473?v=3","gravatar_id":"","url":"https://api.github.com/users/makaimann","html_url":"https://github.com/makaimann","followers_url":"https://api.github.com/users/makaimann/followers","following_url":"https://api.github.com/users/makaimann/following{/other_user}","gists_url":"https://api.github.com/users/makaimann/gists{/gist_id}","starred_url":"https://api.github.com/users/makaimann/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/makaimann/subscriptions","organizations_url":"https://api.github.com/users/makaimann/orgs","repos_url":"https://api.github.com/users/makaimann/repos","events_url":"https://api.github.com/users/makaimann/events{/privacy}","received_events_url":"https://api.github.com/users/makaimann/received_events","type":"User","site_admin":false},"body":"Finished the updates to functions I mentioned in our meeting today and also incorporated your comments on how to handle them.\r\n\r\nI verified that does this not break the Travis tests in the Stanford AHA project (although some of that code can be simplified because of these changes).\r\n\r\nPersonally I like this structure a lot. Primarily because it makes adding functions very simple. But please let me know if you think there's a better way or if the operator/generators are too confusing. My hope is that users would never have to interact with those at all. They would just add function names/parameters to a dict and the rest happens magically. See below for change summary and small example.\r\n\r\nSummary of changes:\r\n\r\nThere is a class, operator, which uses the type functools.partial to hold partial evaluations of functions.\r\n\r\nGiven a name and a namedtuple, fdata, functions are automatically generated.\r\nfdata contains the number of indices (this is for indexed operators, it's 0 for non-indexed operators), the minimum arity, and the maximum arity.\r\n\r\nNon-indexed operators are immediately wrapped by the operator class. Thus, they look like operators with zero index arguments. Indexed operators are a closure which calls generate_operator. This allows you to either evaluate the function entirely or only add the index arguments. However, you cannot pass less than the number of index arguments, or any number of arguments between num_indexes and min_arity.\r\n\r\ni.e.\r\n\r\nfunctions.bvult(bv1) <--- not allowed\r\nfunctions.extract(4) <--- not allowed\r\n\r\nfunctions.bvult(bv1, bv2) <--- allowed\r\nfunctions.extract(4, 2) <--- allowed\r\nfunctions.extract(4, 2, bv1) <--- allowed\r\n\r\nSmall example:\r\n\r\nfrom smt_switch import functions, solvers, sorts\r\n\r\n\\# prints <operator: bvult, () {}>\r\n\\# i.e. it is an operator named bvult with no positional arguments and no keyword arguments\r\nprint(functions.bvult)\r\n\r\ns = solvers.BoolectorSolver()\r\nbv = s.declare_const('bv', sorts.BitVec(8))\r\n\r\nex4_2 = functions.extract(4, 2)\r\n\r\n\\# the following are all equivalent\r\nbvex1 = ex4_2(bv)\r\nbvex2 = s.apply_fun(ex4_2, bv)\r\nbvex3 = functions.extract(4, 2, bv)  \\# syntactic sugar for s.apply_fun(ex4_2, bv)\r\n\r\ns.Assert(bvex1 == bvex2 == bvex3)  \\# trivially true\r\n\r\nassert s.check_sat()","created_at":"2017-06-30T01:34:02Z","updated_at":"2017-06-30T18:25:16Z","closed_at":null,"merged_at":null,"merge_commit_sha":"1b71d31013058ce9538cc28d306bd96957ff8b02","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/makaimann/smt-switch/pulls/4/commits","review_comments_url":"https://api.github.com/repos/makaimann/smt-switch/pulls/4/comments","review_comment_url":"https://api.github.com/repos/makaimann/smt-switch/pulls/comments{/number}","comments_url":"https://api.github.com/repos/makaimann/smt-switch/issues/4/comments","statuses_url":"https://api.github.com/repos/makaimann/smt-switch/statuses/973c04407dffdc290b686c7f36d2b7c98e877df0","head":{"label":"makaimann:frf","ref":"frf","sha":"973c04407dffdc290b686c7f36d2b7c98e877df0","user":{"login":"makaimann","id":23203473,"avatar_url":"https://avatars0.githubusercontent.com/u/23203473?v=3","gravatar_id":"","url":"https://api.github.com/users/makaimann","html_url":"https://github.com/makaimann","followers_url":"https://api.github.com/users/makaimann/followers","following_url":"https://api.github.com/users/makaimann/following{/other_user}","gists_url":"https://api.github.com/users/makaimann/gists{/gist_id}","starred_url":"https://api.github.com/users/makaimann/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/makaimann/subscriptions","organizations_url":"https://api.github.com/users/makaimann/orgs","repos_url":"https://api.github.com/users/makaimann/repos","events_url":"https://api.github.com/users/makaimann/events{/privacy}","received_events_url":"https://api.github.com/users/makaimann/received_events","type":"User","site_admin":false},"repo":{"id":87487066,"name":"smt-switch","full_name":"makaimann/smt-switch","owner":{"login":"makaimann","id":23203473,"avatar_url":"https://avatars0.githubusercontent.com/u/23203473?v=3","gravatar_id":"","url":"https://api.github.com/users/makaimann","html_url":"https://github.com/makaimann","followers_url":"https://api.github.com/users/makaimann/followers","following_url":"https://api.github.com/users/makaimann/following{/other_user}","gists_url":"https://api.github.com/users/makaimann/gists{/gist_id}","starred_url":"https://api.github.com/users/makaimann/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/makaimann/subscriptions","organizations_url":"https://api.github.com/users/makaimann/orgs","repos_url":"https://api.github.com/users/makaimann/repos","events_url":"https://api.github.com/users/makaimann/events{/privacy}","received_events_url":"https://api.github.com/users/makaimann/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/makaimann/smt-switch","description":null,"fork":false,"url":"https://api.github.com/repos/makaimann/smt-switch","forks_url":"https://api.github.com/repos/makaimann/smt-switch/forks","keys_url":"https://api.github.com/repos/makaimann/smt-switch/keys{/key_id}","collaborators_url":"https://api.github.com/repos/makaimann/smt-switch/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/makaimann/smt-switch/teams","hooks_url":"https://api.github.com/repos/makaimann/smt-switch/hooks","issue_events_url":"https://api.github.com/repos/makaimann/smt-switch/issues/events{/number}","events_url":"https://api.github.com/repos/makaimann/smt-switch/events","assignees_url":"https://api.github.com/repos/makaimann/smt-switch/assignees{/user}","branches_url":"https://api.github.com/repos/makaimann/smt-switch/branches{/branch}","tags_url":"https://api.github.com/repos/makaimann/smt-switch/tags","blobs_url":"https://api.github.com/repos/makaimann/smt-switch/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/makaimann/smt-switch/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/makaimann/smt-switch/git/refs{/sha}","trees_url":"https://api.github.com/repos/makaimann/smt-switch/git/trees{/sha}","statuses_url":"https://api.github.com/repos/makaimann/smt-switch/statuses/{sha}","languages_url":"https://api.github.com/repos/makaimann/smt-switch/languages","stargazers_url":"https://api.github.com/repos/makaimann/smt-switch/stargazers","contributors_url":"https://api.github.com/repos/makaimann/smt-switch/contributors","subscribers_url":"https://api.github.com/repos/makaimann/smt-switch/subscribers","subscription_url":"https://api.github.com/repos/makaimann/smt-switch/subscription","commits_url":"https://api.github.com/repos/makaimann/smt-switch/commits{/sha}","git_commits_url":"https://api.github.com/repos/makaimann/smt-switch/git/commits{/sha}","comments_url":"https://api.github.com/repos/makaimann/smt-switch/comments{/number}","issue_comment_url":"https://api.github.com/repos/makaimann/smt-switch/issues/comments{/number}","contents_url":"https://api.github.com/repos/makaimann/smt-switch/contents/{+path}","compare_url":"https://api.github.com/repos/makaimann/smt-switch/compare/{base}...{head}","merges_url":"https://api.github.com/repos/makaimann/smt-switch/merges","archive_url":"https://api.github.com/repos/makaimann/smt-switch/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/makaimann/smt-switch/downloads","issues_url":"https://api.github.com/repos/makaimann/smt-switch/issues{/number}","pulls_url":"https://api.github.com/repos/makaimann/smt-switch/pulls{/number}","milestones_url":"https://api.github.com/repos/makaimann/smt-switch/milestones{/number}","notifications_url":"https://api.github.com/repos/makaimann/smt-switch/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/makaimann/smt-switch/labels{/name}","releases_url":"https://api.github.com/repos/makaimann/smt-switch/releases{/id}","deployments_url":"https://api.github.com/repos/makaimann/smt-switch/deployments","created_at":"2017-04-07T00:22:06Z","updated_at":"2017-05-02T02:34:23Z","pushed_at":"2017-06-30T16:44:54Z","git_url":"git://github.com/makaimann/smt-switch.git","ssh_url":"git@github.com:makaimann/smt-switch.git","clone_url":"https://github.com/makaimann/smt-switch.git","svn_url":"https://github.com/makaimann/smt-switch","homepage":null,"size":72,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"base":{"label":"makaimann:master","ref":"master","sha":"cbf303b6eb4cbcc7b1551cd76c3070c2e6831f74","user":{"login":"makaimann","id":23203473,"avatar_url":"https://avatars0.githubusercontent.com/u/23203473?v=3","gravatar_id":"","url":"https://api.github.com/users/makaimann","html_url":"https://github.com/makaimann","followers_url":"https://api.github.com/users/makaimann/followers","following_url":"https://api.github.com/users/makaimann/following{/other_user}","gists_url":"https://api.github.com/users/makaimann/gists{/gist_id}","starred_url":"https://api.github.com/users/makaimann/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/makaimann/subscriptions","organizations_url":"https://api.github.com/users/makaimann/orgs","repos_url":"https://api.github.com/users/makaimann/repos","events_url":"https://api.github.com/users/makaimann/events{/privacy}","received_events_url":"https://api.github.com/users/makaimann/received_events","type":"User","site_admin":false},"repo":{"id":87487066,"name":"smt-switch","full_name":"makaimann/smt-switch","owner":{"login":"makaimann","id":23203473,"avatar_url":"https://avatars0.githubusercontent.com/u/23203473?v=3","gravatar_id":"","url":"https://api.github.com/users/makaimann","html_url":"https://github.com/makaimann","followers_url":"https://api.github.com/users/makaimann/followers","following_url":"https://api.github.com/users/makaimann/following{/other_user}","gists_url":"https://api.github.com/users/makaimann/gists{/gist_id}","starred_url":"https://api.github.com/users/makaimann/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/makaimann/subscriptions","organizations_url":"https://api.github.com/users/makaimann/orgs","repos_url":"https://api.github.com/users/makaimann/repos","events_url":"https://api.github.com/users/makaimann/events{/privacy}","received_events_url":"https://api.github.com/users/makaimann/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/makaimann/smt-switch","description":null,"fork":false,"url":"https://api.github.com/repos/makaimann/smt-switch","forks_url":"https://api.github.com/repos/makaimann/smt-switch/forks","keys_url":"https://api.github.com/repos/makaimann/smt-switch/keys{/key_id}","collaborators_url":"https://api.github.com/repos/makaimann/smt-switch/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/makaimann/smt-switch/teams","hooks_url":"https://api.github.com/repos/makaimann/smt-switch/hooks","issue_events_url":"https://api.github.com/repos/makaimann/smt-switch/issues/events{/number}","events_url":"https://api.github.com/repos/makaimann/smt-switch/events","assignees_url":"https://api.github.com/repos/makaimann/smt-switch/assignees{/user}","branches_url":"https://api.github.com/repos/makaimann/smt-switch/branches{/branch}","tags_url":"https://api.github.com/repos/makaimann/smt-switch/tags","blobs_url":"https://api.github.com/repos/makaimann/smt-switch/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/makaimann/smt-switch/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/makaimann/smt-switch/git/refs{/sha}","trees_url":"https://api.github.com/repos/makaimann/smt-switch/git/trees{/sha}","statuses_url":"https://api.github.com/repos/makaimann/smt-switch/statuses/{sha}","languages_url":"https://api.github.com/repos/makaimann/smt-switch/languages","stargazers_url":"https://api.github.com/repos/makaimann/smt-switch/stargazers","contributors_url":"https://api.github.com/repos/makaimann/smt-switch/contributors","subscribers_url":"https://api.github.com/repos/makaimann/smt-switch/subscribers","subscription_url":"https://api.github.com/repos/makaimann/smt-switch/subscription","commits_url":"https://api.github.com/repos/makaimann/smt-switch/commits{/sha}","git_commits_url":"https://api.github.com/repos/makaimann/smt-switch/git/commits{/sha}","comments_url":"https://api.github.com/repos/makaimann/smt-switch/comments{/number}","issue_comment_url":"https://api.github.com/repos/makaimann/smt-switch/issues/comments{/number}","contents_url":"https://api.github.com/repos/makaimann/smt-switch/contents/{+path}","compare_url":"https://api.github.com/repos/makaimann/smt-switch/compare/{base}...{head}","merges_url":"https://api.github.com/repos/makaimann/smt-switch/merges","archive_url":"https://api.github.com/repos/makaimann/smt-switch/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/makaimann/smt-switch/downloads","issues_url":"https://api.github.com/repos/makaimann/smt-switch/issues{/number}","pulls_url":"https://api.github.com/repos/makaimann/smt-switch/pulls{/number}","milestones_url":"https://api.github.com/repos/makaimann/smt-switch/milestones{/number}","notifications_url":"https://api.github.com/repos/makaimann/smt-switch/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/makaimann/smt-switch/labels{/name}","releases_url":"https://api.github.com/repos/makaimann/smt-switch/releases{/id}","deployments_url":"https://api.github.com/repos/makaimann/smt-switch/deployments","created_at":"2017-04-07T00:22:06Z","updated_at":"2017-05-02T02:34:23Z","pushed_at":"2017-06-30T16:44:54Z","git_url":"git://github.com/makaimann/smt-switch.git","ssh_url":"git@github.com:makaimann/smt-switch.git","clone_url":"https://github.com/makaimann/smt-switch.git","svn_url":"https://github.com/makaimann/smt-switch","homepage":null,"size":72,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/makaimann/smt-switch/pulls/4"},"html":{"href":"https://github.com/makaimann/smt-switch/pull/4"},"issue":{"href":"https://api.github.com/repos/makaimann/smt-switch/issues/4"},"comments":{"href":"https://api.github.com/repos/makaimann/smt-switch/issues/4/comments"},"review_comments":{"href":"https://api.github.com/repos/makaimann/smt-switch/pulls/4/comments"},"review_comment":{"href":"https://api.github.com/repos/makaimann/smt-switch/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/makaimann/smt-switch/pulls/4/commits"},"statuses":{"href":"https://api.github.com/repos/makaimann/smt-switch/statuses/973c04407dffdc290b686c7f36d2b7c98e877df0"}}}}
{"actor":{"display_login":"mpreiner"}}