{"action":"created","comment":{"url":"https://api.github.com/repos/apache/spark/pulls/comments/67079701","id":67079701,"diff_hunk":"@@ -905,6 +764,503 @@ def jdbc(self, url, table, mode=None, properties=None):\n         self._jwrite.mode(mode).jdbc(url, table, jprop)\n \n \n+class DataStreamReader(object):\n+    \"\"\"\n+    Interface used to load a streaming :class:`DataFrame` from external storage systems\n+    (e.g. file systems, key-value stores, etc). Use :func:`spark.readStream`\n+    to access this.\n+\n+    .. note:: Experimental.\n+\n+    .. versionadded:: 2.0\n+    \"\"\"\n+\n+    def __init__(self, spark):\n+        self._jreader = spark._ssql_ctx.readStream()\n+        self._spark = spark\n+\n+    def _df(self, jdf):\n+        from pyspark.sql.dataframe import DataFrame\n+        return DataFrame(jdf, self._spark)\n+\n+    @since(2.0)\n+    def format(self, source):\n+        \"\"\"Specifies the input data source format.\n+\n+        .. note:: Experimental.\n+\n+        :param source: string, name of the data source, e.g. 'json', 'parquet'.\n+\n+        \"\"\"\n+        self._jreader = self._jreader.format(source)\n+        return self\n+\n+    @since(2.0)\n+    def schema(self, schema):\n+        \"\"\"Specifies the input schema.\n+\n+        Some data sources (e.g. JSON) can infer the input schema automatically from data.\n+        By specifying the schema here, the underlying data source can skip the schema\n+        inference step, and thus speed up data loading.\n+\n+        .. note:: Experimental.\n+\n+        :param schema: a StructType object\n+        \"\"\"\n+        if not isinstance(schema, StructType):\n+            raise TypeError(\"schema should be StructType\")\n+        jschema = self._spark._ssql_ctx.parseDataType(schema.json())\n+        self._jreader = self._jreader.schema(jschema)\n+        return self\n+\n+    @since(2.0)\n+    def option(self, key, value):\n+        \"\"\"Adds an input option for the underlying data source.\n+\n+        .. note:: Experimental.\n+        \"\"\"\n+        self._jreader = self._jreader.option(key, to_str(value))\n+        return self\n+\n+    @since(2.0)\n+    def options(self, **options):\n+        \"\"\"Adds input options for the underlying data source.\n+\n+        .. note:: Experimental.\n+        \"\"\"\n+        for k in options:\n+            self._jreader = self._jreader.option(k, to_str(options[k]))\n+        return self\n+\n+    @since(2.0)\n+    def load(self, path=None, format=None, schema=None, **options):\n+        \"\"\"Loads a data stream from a data source and returns it as a :class`DataFrame`.\n+\n+        .. note:: Experimental.\n+\n+        :param path: optional string for file-system backed data sources.\n+        :param format: optional string for format of the data source. Default to 'parquet'.\n+        :param schema: optional :class:`StructType` for the input schema.\n+        :param options: all other string options\n+\n+        \"\"\"\n+        if format is not None:\n+            self.format(format)\n+        if schema is not None:\n+            self.schema(schema)\n+        self.options(**options)\n+        if path is not None:\n+            if type(path) != str or len(path.strip()) == 0:\n+                raise ValueError(\"If the path is provided for stream, it needs to be a \" +\n+                                 \"non-empty string. List of paths are not supported.\")\n+            return self._df(self._jreader.load(path))\n+        else:\n+            return self._df(self._jreader.load())\n+\n+    @since(2.0)\n+    def json(self, path, schema=None, primitivesAsString=None, prefersDecimal=None,\n+             allowComments=None, allowUnquotedFieldNames=None, allowSingleQuotes=None,\n+             allowNumericLeadingZero=None, allowBackslashEscapingAnyCharacter=None,\n+             mode=None, columnNameOfCorruptRecord=None):\n+        \"\"\"\n+        Loads a JSON file stream (one object per line) and returns a :class`DataFrame`.\n+\n+        If the ``schema`` parameter is not specified, this function goes\n+        through the input once to determine the input schema.\n+\n+        .. note:: Experimental.\n+\n+        :param path: string represents path to the JSON dataset,\n+                     or RDD of Strings storing JSON objects.\n+        :param schema: an optional :class:`StructType` for the input schema.\n+        :param primitivesAsString: infers all primitive values as a string type. If None is set,\n+                                   it uses the default value, ``false``.\n+        :param prefersDecimal: infers all floating-point values as a decimal type. If the values\n+                               do not fit in decimal, then it infers them as doubles. If None is\n+                               set, it uses the default value, ``false``.\n+        :param allowComments: ignores Java/C++ style comment in JSON records. If None is set,\n+                              it uses the default value, ``false``.\n+        :param allowUnquotedFieldNames: allows unquoted JSON field names. If None is set,\n+                                        it uses the default value, ``false``.\n+        :param allowSingleQuotes: allows single quotes in addition to double quotes. If None is\n+                                        set, it uses the default value, ``true``.\n+        :param allowNumericLeadingZero: allows leading zeros in numbers (e.g. 00012). If None is\n+                                        set, it uses the default value, ``false``.\n+        :param allowBackslashEscapingAnyCharacter: allows accepting quoting of all character\n+                                                   using backslash quoting mechanism. If None is\n+                                                   set, it uses the default value, ``false``.\n+        :param mode: allows a mode for dealing with corrupt records during parsing. If None is\n+                     set, it uses the default value, ``PERMISSIVE``.\n+\n+                *  ``PERMISSIVE`` : sets other fields to ``null`` when it meets a corrupted \\\n+                  record and puts the malformed string into a new field configured by \\\n+                 ``columnNameOfCorruptRecord``. When a schema is set by user, it sets \\\n+                 ``null`` for extra fields.\n+                *  ``DROPMALFORMED`` : ignores the whole corrupted records.\n+                *  ``FAILFAST`` : throws an exception when it meets corrupted records.\n+\n+        :param columnNameOfCorruptRecord: allows renaming the new field having malformed string\n+                                          created by ``PERMISSIVE`` mode. This overrides\n+                                          ``spark.sql.columnNameOfCorruptRecord``. If None is set,\n+                                          it uses the value specified in\n+                                          ``spark.sql.columnNameOfCorruptRecord``.\n+\n+        \"\"\"\n+        if schema is not None:\n+            self.schema(schema)\n+        if primitivesAsString is not None:\n+            self.option(\"primitivesAsString\", primitivesAsString)\n+        if prefersDecimal is not None:\n+            self.option(\"prefersDecimal\", prefersDecimal)\n+        if allowComments is not None:\n+            self.option(\"allowComments\", allowComments)\n+        if allowUnquotedFieldNames is not None:\n+            self.option(\"allowUnquotedFieldNames\", allowUnquotedFieldNames)\n+        if allowSingleQuotes is not None:\n+            self.option(\"allowSingleQuotes\", allowSingleQuotes)\n+        if allowNumericLeadingZero is not None:\n+            self.option(\"allowNumericLeadingZero\", allowNumericLeadingZero)\n+        if allowBackslashEscapingAnyCharacter is not None:\n+            self.option(\"allowBackslashEscapingAnyCharacter\", allowBackslashEscapingAnyCharacter)\n+        if mode is not None:\n+            self.option(\"mode\", mode)\n+        if columnNameOfCorruptRecord is not None:\n+            self.option(\"columnNameOfCorruptRecord\", columnNameOfCorruptRecord)\n+        if isinstance(path, basestring):\n+            path = [path]\n+            return self._df(self._jreader.json(path))\n+        else:\n+            raise TypeError(\"path can be only a single string\")\n+\n+    @since(2.0)\n+    def parquet(self, path):\n+        \"\"\"Loads a Parquet file stream, returning the result as a :class:`DataFrame`.\n+\n+        You can set the following Parquet-specific option(s) for reading Parquet files:\n+            * ``mergeSchema``: sets whether we should merge schemas collected from all \\\n+                Parquet part-files. This will override ``spark.sql.parquet.mergeSchema``. \\\n+                The default value is specified in ``spark.sql.parquet.mergeSchema``.\n+\n+        .. note:: Experimental.\n+\n+        \"\"\"\n+        if isinstance(path, basestring):\n+            path = [path]\n+            return self._df(self._jreader.parquet(self._spark._sc._jvm.PythonUtils.toSeq(path)))\n+        else:\n+            raise TypeError(\"path can be only a single string\")\n+\n+    @ignore_unicode_prefix\n+    @since(2.0)\n+    def text(self, path):\n+        \"\"\"\n+        Loads a text file stream and returns a :class:`DataFrame` whose schema starts with a\n+        string column named \"value\", and followed by partitioned columns if there\n+        are any.\n+\n+        Each line in the text file is a new row in the resulting DataFrame.\n+\n+        .. note:: Experimental.\n+\n+        :param paths: string, or list of strings, for input path(s).\n+\n+        \"\"\"\n+        if isinstance(path, basestring):\n+            path = [path]\n+            return self._df(self._jreader.text(self._spark._sc._jvm.PythonUtils.toSeq(path)))\n+        else:\n+            raise TypeError(\"path can be only a single string\")\n+\n+    @since(2.0)\n+    def csv(self, path, schema=None, sep=None, encoding=None, quote=None, escape=None,","path":"python/pyspark/sql/readwriter.py","position":381,"original_position":381,"commit_id":"29ca23b74c16440dbb1e440423615357ec8015bf","original_commit_id":"29ca23b74c16440dbb1e440423615357ec8015bf","user":{"login":"zsxwing","id":1000778,"avatar_url":"https://avatars.githubusercontent.com/u/1000778?v=3","gravatar_id":"","url":"https://api.github.com/users/zsxwing","html_url":"https://github.com/zsxwing","followers_url":"https://api.github.com/users/zsxwing/followers","following_url":"https://api.github.com/users/zsxwing/following{/other_user}","gists_url":"https://api.github.com/users/zsxwing/gists{/gist_id}","starred_url":"https://api.github.com/users/zsxwing/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zsxwing/subscriptions","organizations_url":"https://api.github.com/users/zsxwing/orgs","repos_url":"https://api.github.com/users/zsxwing/repos","events_url":"https://api.github.com/users/zsxwing/events{/privacy}","received_events_url":"https://api.github.com/users/zsxwing/received_events","type":"User","site_admin":false},"body":"I'm wondering if we can create util methods for `csv` and `json` to make DataFrameReader and DataStreamReader share most of codes here. Otherwise, it's hard to make them consistent in future.","created_at":"2016-06-15T00:04:54Z","updated_at":"2016-06-15T00:04:54Z","html_url":"https://github.com/apache/spark/pull/13653#discussion_r67079701","pull_request_url":"https://api.github.com/repos/apache/spark/pulls/13653","_links":{"self":{"href":"https://api.github.com/repos/apache/spark/pulls/comments/67079701"},"html":{"href":"https://github.com/apache/spark/pull/13653#discussion_r67079701"},"pull_request":{"href":"https://api.github.com/repos/apache/spark/pulls/13653"}}},"pull_request":{"url":"https://api.github.com/repos/apache/spark/pulls/13653","id":73659934,"html_url":"https://github.com/apache/spark/pull/13653","diff_url":"https://github.com/apache/spark/pull/13653.diff","patch_url":"https://github.com/apache/spark/pull/13653.patch","issue_url":"https://api.github.com/repos/apache/spark/issues/13653","number":13653,"state":"open","locked":false,"title":"[SPARK-15933][SQL][STREAMING] Refactored DF reader-writer to use readStream and writeStream for streaming DFs","user":{"login":"tdas","id":663212,"avatar_url":"https://avatars.githubusercontent.com/u/663212?v=3","gravatar_id":"","url":"https://api.github.com/users/tdas","html_url":"https://github.com/tdas","followers_url":"https://api.github.com/users/tdas/followers","following_url":"https://api.github.com/users/tdas/following{/other_user}","gists_url":"https://api.github.com/users/tdas/gists{/gist_id}","starred_url":"https://api.github.com/users/tdas/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tdas/subscriptions","organizations_url":"https://api.github.com/users/tdas/orgs","repos_url":"https://api.github.com/users/tdas/repos","events_url":"https://api.github.com/users/tdas/events{/privacy}","received_events_url":"https://api.github.com/users/tdas/received_events","type":"User","site_admin":false},"body":"## What changes were proposed in this pull request?\r\nCurrently, the DataFrameReader/Writer has method that are needed for streaming and non-streaming DFs. This is quite awkward because each method in them through runtime exception for one case or the other. So rather having half the methods throw runtime exceptions, its just better to have a different reader/writer API for streams.\r\n\r\n- [x] Python API!!\r\n\r\n## How was this patch tested?\r\nExisting unit tests + two sets of unit tests for DataFrameReader/Writer and DataStreamReader/Writer.","created_at":"2016-06-13T23:35:58Z","updated_at":"2016-06-15T00:04:54Z","closed_at":null,"merged_at":null,"merge_commit_sha":"ba8c4112a10c04fc81b2c5f25fd474eb905d53a3","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/apache/spark/pulls/13653/commits","review_comments_url":"https://api.github.com/repos/apache/spark/pulls/13653/comments","review_comment_url":"https://api.github.com/repos/apache/spark/pulls/comments{/number}","comments_url":"https://api.github.com/repos/apache/spark/issues/13653/comments","statuses_url":"https://api.github.com/repos/apache/spark/statuses/29ca23b74c16440dbb1e440423615357ec8015bf","head":{"label":"tdas:SPARK-15933","ref":"SPARK-15933","sha":"29ca23b74c16440dbb1e440423615357ec8015bf","user":{"login":"tdas","id":663212,"avatar_url":"https://avatars.githubusercontent.com/u/663212?v=3","gravatar_id":"","url":"https://api.github.com/users/tdas","html_url":"https://github.com/tdas","followers_url":"https://api.github.com/users/tdas/followers","following_url":"https://api.github.com/users/tdas/following{/other_user}","gists_url":"https://api.github.com/users/tdas/gists{/gist_id}","starred_url":"https://api.github.com/users/tdas/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tdas/subscriptions","organizations_url":"https://api.github.com/users/tdas/orgs","repos_url":"https://api.github.com/users/tdas/repos","events_url":"https://api.github.com/users/tdas/events{/privacy}","received_events_url":"https://api.github.com/users/tdas/received_events","type":"User","site_admin":false},"repo":{"id":17603343,"name":"spark","full_name":"tdas/spark","owner":{"login":"tdas","id":663212,"avatar_url":"https://avatars.githubusercontent.com/u/663212?v=3","gravatar_id":"","url":"https://api.github.com/users/tdas","html_url":"https://github.com/tdas","followers_url":"https://api.github.com/users/tdas/followers","following_url":"https://api.github.com/users/tdas/following{/other_user}","gists_url":"https://api.github.com/users/tdas/gists{/gist_id}","starred_url":"https://api.github.com/users/tdas/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tdas/subscriptions","organizations_url":"https://api.github.com/users/tdas/orgs","repos_url":"https://api.github.com/users/tdas/repos","events_url":"https://api.github.com/users/tdas/events{/privacy}","received_events_url":"https://api.github.com/users/tdas/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/tdas/spark","description":"Mirror of Apache Spark","fork":true,"url":"https://api.github.com/repos/tdas/spark","forks_url":"https://api.github.com/repos/tdas/spark/forks","keys_url":"https://api.github.com/repos/tdas/spark/keys{/key_id}","collaborators_url":"https://api.github.com/repos/tdas/spark/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/tdas/spark/teams","hooks_url":"https://api.github.com/repos/tdas/spark/hooks","issue_events_url":"https://api.github.com/repos/tdas/spark/issues/events{/number}","events_url":"https://api.github.com/repos/tdas/spark/events","assignees_url":"https://api.github.com/repos/tdas/spark/assignees{/user}","branches_url":"https://api.github.com/repos/tdas/spark/branches{/branch}","tags_url":"https://api.github.com/repos/tdas/spark/tags","blobs_url":"https://api.github.com/repos/tdas/spark/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/tdas/spark/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/tdas/spark/git/refs{/sha}","trees_url":"https://api.github.com/repos/tdas/spark/git/trees{/sha}","statuses_url":"https://api.github.com/repos/tdas/spark/statuses/{sha}","languages_url":"https://api.github.com/repos/tdas/spark/languages","stargazers_url":"https://api.github.com/repos/tdas/spark/stargazers","contributors_url":"https://api.github.com/repos/tdas/spark/contributors","subscribers_url":"https://api.github.com/repos/tdas/spark/subscribers","subscription_url":"https://api.github.com/repos/tdas/spark/subscription","commits_url":"https://api.github.com/repos/tdas/spark/commits{/sha}","git_commits_url":"https://api.github.com/repos/tdas/spark/git/commits{/sha}","comments_url":"https://api.github.com/repos/tdas/spark/comments{/number}","issue_comment_url":"https://api.github.com/repos/tdas/spark/issues/comments{/number}","contents_url":"https://api.github.com/repos/tdas/spark/contents/{+path}","compare_url":"https://api.github.com/repos/tdas/spark/compare/{base}...{head}","merges_url":"https://api.github.com/repos/tdas/spark/merges","archive_url":"https://api.github.com/repos/tdas/spark/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/tdas/spark/downloads","issues_url":"https://api.github.com/repos/tdas/spark/issues{/number}","pulls_url":"https://api.github.com/repos/tdas/spark/pulls{/number}","milestones_url":"https://api.github.com/repos/tdas/spark/milestones{/number}","notifications_url":"https://api.github.com/repos/tdas/spark/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/tdas/spark/labels{/name}","releases_url":"https://api.github.com/repos/tdas/spark/releases{/id}","deployments_url":"https://api.github.com/repos/tdas/spark/deployments","created_at":"2014-03-10T18:19:48Z","updated_at":"2016-03-15T03:03:38Z","pushed_at":"2016-06-14T22:47:07Z","git_url":"git://github.com/tdas/spark.git","ssh_url":"git@github.com:tdas/spark.git","clone_url":"https://github.com/tdas/spark.git","svn_url":"https://github.com/tdas/spark","homepage":null,"size":175431,"stargazers_count":2,"watchers_count":2,"language":"Scala","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":2,"mirror_url":null,"open_issues_count":3,"forks":2,"open_issues":3,"watchers":2,"default_branch":"master"}},"base":{"label":"apache:master","ref":"master","sha":"bd39ffe35c6f939debe5d3c5eb4970b4e62507b0","user":{"login":"apache","id":47359,"avatar_url":"https://avatars.githubusercontent.com/u/47359?v=3","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"repo":{"id":17165658,"name":"spark","full_name":"apache/spark","owner":{"login":"apache","id":47359,"avatar_url":"https://avatars.githubusercontent.com/u/47359?v=3","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/apache/spark","description":"Mirror of Apache Spark","fork":false,"url":"https://api.github.com/repos/apache/spark","forks_url":"https://api.github.com/repos/apache/spark/forks","keys_url":"https://api.github.com/repos/apache/spark/keys{/key_id}","collaborators_url":"https://api.github.com/repos/apache/spark/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/apache/spark/teams","hooks_url":"https://api.github.com/repos/apache/spark/hooks","issue_events_url":"https://api.github.com/repos/apache/spark/issues/events{/number}","events_url":"https://api.github.com/repos/apache/spark/events","assignees_url":"https://api.github.com/repos/apache/spark/assignees{/user}","branches_url":"https://api.github.com/repos/apache/spark/branches{/branch}","tags_url":"https://api.github.com/repos/apache/spark/tags","blobs_url":"https://api.github.com/repos/apache/spark/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/apache/spark/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/apache/spark/git/refs{/sha}","trees_url":"https://api.github.com/repos/apache/spark/git/trees{/sha}","statuses_url":"https://api.github.com/repos/apache/spark/statuses/{sha}","languages_url":"https://api.github.com/repos/apache/spark/languages","stargazers_url":"https://api.github.com/repos/apache/spark/stargazers","contributors_url":"https://api.github.com/repos/apache/spark/contributors","subscribers_url":"https://api.github.com/repos/apache/spark/subscribers","subscription_url":"https://api.github.com/repos/apache/spark/subscription","commits_url":"https://api.github.com/repos/apache/spark/commits{/sha}","git_commits_url":"https://api.github.com/repos/apache/spark/git/commits{/sha}","comments_url":"https://api.github.com/repos/apache/spark/comments{/number}","issue_comment_url":"https://api.github.com/repos/apache/spark/issues/comments{/number}","contents_url":"https://api.github.com/repos/apache/spark/contents/{+path}","compare_url":"https://api.github.com/repos/apache/spark/compare/{base}...{head}","merges_url":"https://api.github.com/repos/apache/spark/merges","archive_url":"https://api.github.com/repos/apache/spark/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/apache/spark/downloads","issues_url":"https://api.github.com/repos/apache/spark/issues{/number}","pulls_url":"https://api.github.com/repos/apache/spark/pulls{/number}","milestones_url":"https://api.github.com/repos/apache/spark/milestones{/number}","notifications_url":"https://api.github.com/repos/apache/spark/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/apache/spark/labels{/name}","releases_url":"https://api.github.com/repos/apache/spark/releases{/id}","deployments_url":"https://api.github.com/repos/apache/spark/deployments","created_at":"2014-02-25T08:00:08Z","updated_at":"2016-06-14T23:50:31Z","pushed_at":"2016-06-14T23:59:37Z","git_url":"git://github.com/apache/spark.git","ssh_url":"git@github.com:apache/spark.git","clone_url":"https://github.com/apache/spark.git","svn_url":"https://github.com/apache/spark","homepage":null,"size":495504,"stargazers_count":8911,"watchers_count":8911,"language":"Scala","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":8283,"mirror_url":"git://git.apache.org/spark.git","open_issues_count":444,"forks":8283,"open_issues":444,"watchers":8911,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/apache/spark/pulls/13653"},"html":{"href":"https://github.com/apache/spark/pull/13653"},"issue":{"href":"https://api.github.com/repos/apache/spark/issues/13653"},"comments":{"href":"https://api.github.com/repos/apache/spark/issues/13653/comments"},"review_comments":{"href":"https://api.github.com/repos/apache/spark/pulls/13653/comments"},"review_comment":{"href":"https://api.github.com/repos/apache/spark/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/apache/spark/pulls/13653/commits"},"statuses":{"href":"https://api.github.com/repos/apache/spark/statuses/29ca23b74c16440dbb1e440423615357ec8015bf"}}}}
{"actor":{"display_login":"zsxwing"}}