{"action":"created","comment":{"url":"https://api.github.com/repos/pydata/pandas/pulls/comments/29548887","id":29548887,"diff_hunk":"@@ -3299,6 +3322,415 @@ def _wrap_joined_index(self, joined, other):\n Int64Index._add_logical_methods()\n \n \n+class RangeIndex(Int64Index):\n+\n+    \"\"\"\n+    Immutable Index implementing an monotonic range. RangeIndex is a \n+    memory-saving special case of `Int64Index` limited to representing \n+    monotonic ranges.\n+\n+    Parameters\n+    ----------\n+    start : int (default: 0)\n+    stop : int (default: 0)\n+    step : int (default: 1)\n+    name : object, optional\n+        Name to be stored in the index\n+    \"\"\"\n+\n+    _typ = 'rangeindex'\n+    _engine_type = _index.Int64Engine\n+    _attributes = ['name', 'start', 'stop', 'step']\n+\n+    def __new__(cls, start=None, stop=None, step=None, name=None, fastpath=False):\n+        if fastpath:\n+            return cls._simple_new(start, stop, step, name=name)\n+\n+        # RangeIndex() constructor\n+        if start is None and stop is None and step is None:\n+            return cls._simple_new(0, 0, 1, name=name)\n+\n+        # sort the arguments depending on which are provided\n+        if step is None:\n+            step = 1\n+        if stop is None:\n+            stop = start\n+            start = 0\n+\n+        # check validity of inputs\n+        start = cls._ensure_int(start)\n+        stop = cls._ensure_int(stop)\n+        step = cls._ensure_int(step)\n+        if step == 0:\n+            raise ValueError(\"Step must not be zero\")\n+\n+        return cls._simple_new(start, stop, step, name)\n+\n+    @classmethod\n+    def _simple_new(cls, start, stop, step, name=None):\n+        result = object.__new__(cls)\n+        result._start = start\n+        result._stop = stop\n+        result._step = step\n+        result.name = name\n+        return result\n+\n+    @classmethod\n+    def _ensure_int(cls, value):\n+        try:\n+            int_value = int(value)\n+            if int_value != value:\n+                raise Exception\n+        except Exception:\n+            raise TypeError(\"Need to pass integral values\")\n+        return int_value\n+\n+    @property\n+    def _data(self):\n+        return np.arange(self.start, self.stop, self.step, dtype=np.int64)\n+\n+    @property\n+    def dtype(self):\n+        return np.dtype(np.int64)\n+\n+    @property\n+    def start(self):\n+        return self._start\n+\n+    @start.setter\n+    def start(self, value):\n+        self._start = self._ensure_int(value)\n+\n+    @property\n+    def stop(self):\n+        return self._stop\n+\n+    @stop.setter\n+    def stop(self, value):\n+        self._stop = self._ensure_int(value)\n+\n+    @property\n+    def step(self):\n+        return self._step\n+\n+    @step.setter\n+    def step(self, value):\n+        self._step = self._ensure_int(value)\n+\n+    @cache_readonly(allow_setting=True)\n+    def is_unique(self):\n+        \"\"\" return if the index has unique values \"\"\"\n+        return True\n+\n+    @property\n+    def has_duplicates(self):\n+        return not self.is_unique\n+\n+    def tolist(self):\n+        return list(range(self.start, self.stop, self.step))\n+\n+    def _shallow_copy(self, values=None, **kwargs):\n+        \"\"\" create a new Index, don't copy the data, use the same object attributes\n+            with passed in attributes taking precedence \"\"\"\n+        if values is None:\n+            return RangeIndex(self.start, self.stop, self.step, \n+                              name=self.name, fastpath=True)\n+        else:\n+            name = kwargs.get('name', self.name)\n+            return Int64Index(self.values, name=name, copy=False)._shallow_copy(values, **kwargs)\n+\n+    def copy(self, names=None, name=None, dtype=None, deep=False):\n+        \"\"\"\n+        Make a copy of this object.  Name and dtype sets those attributes on\n+        the new object.\n+\n+        Parameters\n+        ----------\n+        name : string, optional\n+        dtype : numpy dtype or pandas type\n+\n+        Returns\n+        -------\n+        copy : Index\n+\n+        Notes\n+        -----\n+        In most cases, there should be no functional difference from using\n+        ``deep``, but if ``deep`` is passed it will attempt to deepcopy.\n+        \"\"\"\n+        if dtype is not None and not is_int64_dtype(dtype):\n+            return super(RangeIndex, self).copy(names, name, dtype, deep)\n+\n+        if name is None:\n+            name = self.name\n+        return RangeIndex(self.start, self.stop, self.step, name, fastpath=True)\n+\n+    def argsort(self, *args, **kwargs):\n+        \"\"\"\n+        return an ndarray indexer of the underlying data\n+\n+        See also\n+        --------\n+        numpy.ndarray.argsort\n+        \"\"\"\n+        return self._data.argsort(*args, **kwargs)\n+\n+    def __repr__(self):\n+        attrs = [('start', default_pprint(self.start)),\n+                 ('stop', default_pprint(self.stop)),\n+                 ('step', default_pprint(self.step)),\n+                 ('name', default_pprint(self.name))]\n+\n+        prepr = u(\", \").join([u(\"%s=%s\") % (k, v)\n+                                          for k, v in attrs])\n+        res = u(\"%s(%s)\") % (self.__class__.__name__, prepr)\n+\n+        if not compat.PY3:\n+            # needs to be str in Python 2\n+            encoding = get_option('display.encoding')\n+            res = res.encode(encoding)\n+        return res\n+\n+    def __unicode__(self):\n+        \"\"\"\n+        Return a string representation for this object.\n+\n+        Invoked by unicode(df) in py2 only. Yields a Unicode String in both\n+        py2/py3.\n+        \"\"\"\n+        if self.start != 0 or self.step != 1:\n+            start = u('%s, ') % default_pprint(self.start)\n+        else:\n+            start = u('')\n+        stop = default_pprint(self.stop)\n+        step = u('') if self.step == 1 else u(', %s') % default_pprint(self.step)\n+        if self.name is None:\n+            name = u('')\n+        else:\n+            name = u(', name=%s') % default_pprint(self.name)\n+\n+        res = u(\"%s(%s%s%s%s)\") % (self.__class__.__name__, \n+                                   start, stop, step, name)\n+        return res\n+\n+    def equals(self, other):\n+        \"\"\"\n+        Determines if two Index objects contain the same elements.\n+        \"\"\"\n+        if self.is_(other):\n+            return True\n+\n+        elif isinstance(other, RangeIndex):\n+            return (self.start == other.start and\n+                    self.stop == other.stop and\n+                    self.step == other.step)\n+\n+        try:\n+            return array_equivalent(_values_from_object(self),\n+                                    _values_from_object(other))\n+        except TypeError:\n+            # e.g. fails in numpy 1.6 with DatetimeIndex #1681\n+            return False\n+\n+    def __reduce__(self):\n+        d = self._get_attributes_dict()\n+        return _new_Index, (self.__class__, d), None\n+\n+    def view(self, cls=None):\n+        if cls is None or is_int64_dtype(cls):\n+            return self\n+        else:\n+            result = self._shallow_copy()\n+        if isinstance(result, Index):\n+            result._id = self._id\n+        return result\n+\n+    def intersection(self, other):\n+        \"\"\"\n+        Form the intersection of two Index objects. Sortedness of the result is\n+        not guaranteed\n+\n+        Parameters\n+        ----------\n+        other : Index or array-like\n+\n+        Returns\n+        -------\n+        intersection : Index\n+        \"\"\"\n+        if not isinstance(other, RangeIndex):\n+            return super(RangeIndex, self).intersection(other)\n+\n+        # check whether intervals intersect\n+        # deals with in- and decreasing ranges\n+        int_low = max(min(self.start, self.stop+1), \n+                      min(other.start, other.stop+1))\n+        int_high = min(max(self.stop, self.start+1), \n+                       max(other.stop, other.start+1))\n+        if int_high <= int_low:\n+            return RangeIndex()\n+\n+        ### Method hint: linear Diophantine equation\n+        # solve intersection\n+        # perf: for identical step sizes, could use cheaper alternative\n+        gcd, s, t = self._extended_gcd(self.step, other.step)\n+        \n+        # check whether element sets intersect\n+        if (self.start - other.start) % gcd:\n+            return RangeIndex()\n+        \n+        # calculate parameters for the RangeIndex describing the intersection\n+        # disregarding the lower bounds\n+        tmp_start = self.start + (other.start-self.start)*self.step//gcd*s\n+        new_step = self.step * other.step // gcd\n+        new_index = RangeIndex(tmp_start, int_high, new_step, fastpath=True)\n+\n+        # adjust index to limiting interval\n+        new_index.start = new_index._min_fitting_element(int_low)\n+        return new_index\n+\n+    def _min_fitting_element(self, lower_limit):\n+        \"\"\"Returns the value of the smallest element greater than the limit\"\"\"\n+        round = ceil if self.step > 0 else floor\n+        no_steps = round( (float(lower_limit)-self.start) / self.step )\n+        return self.start + self.step * no_steps\n+\n+    def _max_fitting_element(self, upper_limit):\n+        \"\"\"Returns the value of the largest element smaller than the limit\"\"\"\n+        round = floor if self.step > 0 else ceil\n+        no_steps = round( (float(upper_limit)-self.start) / self.step )\n+        return self.start + self.step * no_steps\n+\n+    def _extended_gcd(self, a, b):\n+        \"\"\"\n+        Extended Euclidean algorithms to solve Bezout's identity:\n+           a*x + b*y = gcd(x, y)\n+        Finds one particular solution for x, y: s, t\n+        Returns: gcd, s, t\n+        \"\"\"\n+        s, old_s = 0, 1\n+        t, old_t = 1, 0\n+        r, old_r = b, a\n+        while r:\n+            quotient = old_r // r\n+            old_r, r = r, old_r - quotient * r\n+            old_s, s = s, old_s - quotient * s\n+            old_t, t = t, old_t - quotient * t\n+        return old_r, old_s, old_t\n+\n+    def union(self, other):\n+        \"\"\"\n+        Form the union of two Index objects and sorts if possible\n+\n+        Parameters\n+        ----------\n+        other : Index or array-like\n+\n+        Returns\n+        -------\n+        union : Index\n+        \"\"\"\n+        # note: could return a RangeIndex in some circumstances\n+        return Int64Index(self.values, copy=False).union(other)\n+\n+    def join(self, other, how='left', level=None, return_indexers=False):\n+        \"\"\"\n+        *this is an internal non-public method*\n+\n+        Compute join_index and indexers to conform data\n+        structures to the new index.\n+\n+        Parameters\n+        ----------\n+        other : Index\n+        how : {'left', 'right', 'inner', 'outer'}\n+        level : int or level name, default None\n+        return_indexers : boolean, default False\n+\n+        Returns\n+        -------\n+        join_index, (left_indexer, right_indexer)\n+        \"\"\"\n+        if how == 'outer' and self is not other:\n+            # note: could return RangeIndex in more circumstances\n+            return Int64Index(self.values, copy=False).join(other, how, level, return_indexers)\n+\n+        return super(RangeIndex, self).join(other, how, level, return_indexers)\n+\n+    def _mul(self, other):\n+        \"__mul__() implementation\"\n+        try:\n+            int_input = other == int(other)\n+            if int_input:\n+                other = int(other)\n+        except Exception:\n+            int_input = False\n+\n+        if int_input == True and other != 0:\n+            return RangeIndex(self.start*other, self.stop*other, self.step*other,\n+                              fastpath=True)\n+        else:\n+            return super(RangeIndex, self).__mul__(other)\n+\n+    def __len__(self):\n+        \"\"\"\n+        return the length of the RangeIndex\n+        \"\"\"\n+        return (self.stop-self.start) // self.step\n+\n+    @property\n+    def size(self):\n+        return len(self)\n+\n+    def __getitem__(self, key):\n+        \"\"\"\n+        Conserve RangeIndex type for scalar and slice keys.\n+        \"\"\"\n+        super_getitem = super(RangeIndex, self).__getitem__\n+\n+        if np.isscalar(key):\n+            n = int(key)\n+            if n != key:\n+                return super_getitem(key)","path":"pandas/core/index.py","position":446,"original_position":423,"commit_id":"c9ac12f6043dfc1aba8f871086b6c69b26940ba4","original_commit_id":"872775d8b2f0311321a7986bb97a164c284029a1","user":{"login":"ARF1","id":5834577,"avatar_url":"https://avatars.githubusercontent.com/u/5834577?v=3","gravatar_id":"","url":"https://api.github.com/users/ARF1","html_url":"https://github.com/ARF1","followers_url":"https://api.github.com/users/ARF1/followers","following_url":"https://api.github.com/users/ARF1/following{/other_user}","gists_url":"https://api.github.com/users/ARF1/gists{/gist_id}","starred_url":"https://api.github.com/users/ARF1/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ARF1/subscriptions","organizations_url":"https://api.github.com/users/ARF1/orgs","repos_url":"https://api.github.com/users/ARF1/repos","events_url":"https://api.github.com/users/ARF1/events{/privacy}","received_events_url":"https://api.github.com/users/ARF1/received_events","type":"User","site_admin":false},"body":"Ok, that changes things. Can we then for consistency reject all non-int-type inputs for `RangeIndex`? Especially for the constructor.","created_at":"2015-05-02T17:03:33Z","updated_at":"2015-05-02T17:03:33Z","html_url":"https://github.com/pydata/pandas/pull/9977#discussion_r29548887","pull_request_url":"https://api.github.com/repos/pydata/pandas/pulls/9977","_links":{"self":{"href":"https://api.github.com/repos/pydata/pandas/pulls/comments/29548887"},"html":{"href":"https://github.com/pydata/pandas/pull/9977#discussion_r29548887"},"pull_request":{"href":"https://api.github.com/repos/pydata/pandas/pulls/9977"}}},"pull_request":{"url":"https://api.github.com/repos/pydata/pandas/pulls/9977","id":34039686,"html_url":"https://github.com/pydata/pandas/pull/9977","diff_url":"https://github.com/pydata/pandas/pull/9977.diff","patch_url":"https://github.com/pydata/pandas/pull/9977.patch","issue_url":"https://api.github.com/repos/pydata/pandas/issues/9977","number":9977,"state":"open","locked":false,"title":"Introduction of RangeIndex","user":{"login":"ARF1","id":5834577,"avatar_url":"https://avatars.githubusercontent.com/u/5834577?v=3","gravatar_id":"","url":"https://api.github.com/users/ARF1","html_url":"https://github.com/ARF1","followers_url":"https://api.github.com/users/ARF1/followers","following_url":"https://api.github.com/users/ARF1/following{/other_user}","gists_url":"https://api.github.com/users/ARF1/gists{/gist_id}","starred_url":"https://api.github.com/users/ARF1/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ARF1/subscriptions","organizations_url":"https://api.github.com/users/ARF1/orgs","repos_url":"https://api.github.com/users/ARF1/repos","events_url":"https://api.github.com/users/ARF1/events{/privacy}","received_events_url":"https://api.github.com/users/ARF1/received_events","type":"User","site_admin":false},"body":"closes #939\r\n \r\n`RangeIndex(1, 10, 2)` is a memory saving alternative to `Index(np.arange(1, 10,2))`: c.f. #939.\r\n\r\nThis re-implementation is compatible with the current `Index()` api and is a drop-in replacement for `Int64Index()`. It automatically converts to Int64Index() when required by operations.\r\n\r\nAt present only for a minimum number of operations the type is conserved (e.g. slicing, inner-, left- and right-joins). Most other operations trigger creation of an equivalent Int64Index (or at least an equivalent numpy array) and fall back to its implementation.\r\n\r\nThis PR also extends the functionality of the `Index()` constructor to allow creation of `RangeIndex()` with\r\n```\r\nIndex(20)\r\nIndex(2, 20)\r\nIndex(0, 20, 2)\r\n```\r\nin analogy to\r\n```\r\nrange(20)\r\nrange(2, 20)\r\nrange(0, 20, 2)\r\n```\r\n\r\n---\r\nTODO:\r\n - [x] Cache a private `Int64Index` object the first time it or its values are required.\r\n - [x] Restore `Index(5)` as error. Restore its test. Allow `Index(0, 5)` and `Index(0, 5, 1)`.\r\n - [x] Make `RangeIndex` immutable. See `start`, `stop`, `step` properties.\r\n - [x] In `test_constructor()`: check class, attributes (possibly including dtype).\r\n - [x] In `test_copy()`: check that copy is not identical (but equal) to the existing.\r\n - [ ] In `test_join_non_unique()`: test .append for ri.append(int64index) and int64index.append(ri).\r\n - [x] In `test_duplicates()`: Assert `is_unique` and `has_duplicates` return correct values.\r\n - [ ] After consensus on desired behaviour, adjust `test_view()`.\r\n - [ ] After consensus on constructor, adjust `test_constructor()` and possible add further tests.\r\n - [x] After consensus on `RangeIndex()` validity, adjust `test_pickle_compat_construction()`.\r\n - [ ] After consensus on slice behaviour, test for correct return type in `test_slice_specialised()`.\r\n - [ ] Accept `xrange` objects as input\r\n - [x] Setting `RangeIndex` as the default index.\r\n - [ ] Clean up `Index` constructor: use ABCs and named arguments\r\n - [ ] In `__getitem__()`: replace `np.isscalar` to exclude singe-element numpy arrays\r\n - [ ] Tests for `pandas.io.packers`\r\n\r\nIn need of consensus:\r\n - [x] If we disallow `Index(10)` should we also disallow `RangeIndex(10)`? That would seem like an unfortunate api break with respect to built-in `range()`,  `xrange()` and numpy `arange()`. *Decision: allow*\r\n - [x] Should `RangeIndex()` be allowed as a constructor alternative to the kludgy `Index(np.empty(0, dtype='...'))`? *Decision: allow*\r\n - [x] Should `RangeIndex` accept array inputs? If so, what should it do with them? Should it try to infer a corresponding `RangeIndex`? What should it do with inputs it cannot infer? *Decision: delegate all array inputs to `Int64Index`.*\r\n - [x] Should the `RangeIndex` constructor accept `dtype` as an argument? *Decision: accept, but only for array inputs.*\r\n - [x] If so, should it accept non-int64 dtypes as valid input? *Decision: Irrelevant due to delegation.* \r\n - [x] If so, does it need to check that the other inputs are within the range of the dtype? *Decision: Irrelevant due to delegation.*\r\n - [x] Related to constructor question, should slicing with a list return? Always `Int64Index` or `RangeIndex` when possible and `Int64Index` when not? *Decision: slicing with list will always return `Int64Index`.*\r\n - [x] What should `RangeIndex(10).view('i8')` return? I believe `RangeIndex(10)`. *Decision: return `RangeIndex(10)`.*\r\n - [x] What should `RangeIndex(10).view('i4')` return? I believe `Index(RangeIndex(10), dtype='i4')`. *Decision: return `Index(RangeIndex(10), dtype='i4')`.*\r\n","created_at":"2015-04-24T11:21:15Z","updated_at":"2015-05-02T17:03:33Z","closed_at":null,"merged_at":null,"merge_commit_sha":"abf19b22e8d53cbe9edcda3e8d1a75817642153f","assignee":null,"milestone":{"url":"https://api.github.com/repos/pydata/pandas/milestones/34","html_url":"https://github.com/pydata/pandas/milestones/0.17.0","labels_url":"https://api.github.com/repos/pydata/pandas/milestones/34/labels","id":1033710,"number":34,"title":"0.17.0","description":"","creator":{"login":"jreback","id":953992,"avatar_url":"https://avatars.githubusercontent.com/u/953992?v=3","gravatar_id":"","url":"https://api.github.com/users/jreback","html_url":"https://github.com/jreback","followers_url":"https://api.github.com/users/jreback/followers","following_url":"https://api.github.com/users/jreback/following{/other_user}","gists_url":"https://api.github.com/users/jreback/gists{/gist_id}","starred_url":"https://api.github.com/users/jreback/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jreback/subscriptions","organizations_url":"https://api.github.com/users/jreback/orgs","repos_url":"https://api.github.com/users/jreback/repos","events_url":"https://api.github.com/users/jreback/events{/privacy}","received_events_url":"https://api.github.com/users/jreback/received_events","type":"User","site_admin":false},"open_issues":79,"closed_issues":1,"state":"open","created_at":"2015-03-23T10:47:38Z","updated_at":"2015-04-29T23:49:49Z","due_on":"2015-06-30T04:00:00Z","closed_at":null},"commits_url":"https://api.github.com/repos/pydata/pandas/pulls/9977/commits","review_comments_url":"https://api.github.com/repos/pydata/pandas/pulls/9977/comments","review_comment_url":"https://api.github.com/repos/pydata/pandas/pulls/comments{/number}","comments_url":"https://api.github.com/repos/pydata/pandas/issues/9977/comments","statuses_url":"https://api.github.com/repos/pydata/pandas/statuses/c9ac12f6043dfc1aba8f871086b6c69b26940ba4","head":{"label":"ARF1:range_index_rebased","ref":"range_index_rebased","sha":"c9ac12f6043dfc1aba8f871086b6c69b26940ba4","user":{"login":"ARF1","id":5834577,"avatar_url":"https://avatars.githubusercontent.com/u/5834577?v=3","gravatar_id":"","url":"https://api.github.com/users/ARF1","html_url":"https://github.com/ARF1","followers_url":"https://api.github.com/users/ARF1/followers","following_url":"https://api.github.com/users/ARF1/following{/other_user}","gists_url":"https://api.github.com/users/ARF1/gists{/gist_id}","starred_url":"https://api.github.com/users/ARF1/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ARF1/subscriptions","organizations_url":"https://api.github.com/users/ARF1/orgs","repos_url":"https://api.github.com/users/ARF1/repos","events_url":"https://api.github.com/users/ARF1/events{/privacy}","received_events_url":"https://api.github.com/users/ARF1/received_events","type":"User","site_admin":false},"repo":{"id":34319082,"name":"pandas","full_name":"ARF1/pandas","owner":{"login":"ARF1","id":5834577,"avatar_url":"https://avatars.githubusercontent.com/u/5834577?v=3","gravatar_id":"","url":"https://api.github.com/users/ARF1","html_url":"https://github.com/ARF1","followers_url":"https://api.github.com/users/ARF1/followers","following_url":"https://api.github.com/users/ARF1/following{/other_user}","gists_url":"https://api.github.com/users/ARF1/gists{/gist_id}","starred_url":"https://api.github.com/users/ARF1/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ARF1/subscriptions","organizations_url":"https://api.github.com/users/ARF1/orgs","repos_url":"https://api.github.com/users/ARF1/repos","events_url":"https://api.github.com/users/ARF1/events{/privacy}","received_events_url":"https://api.github.com/users/ARF1/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/ARF1/pandas","description":"Flexible and powerful data analysis / manipulation library for Python, providing labeled data structures similar to R data.frame objects, statistical functions, and much more","fork":true,"url":"https://api.github.com/repos/ARF1/pandas","forks_url":"https://api.github.com/repos/ARF1/pandas/forks","keys_url":"https://api.github.com/repos/ARF1/pandas/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ARF1/pandas/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ARF1/pandas/teams","hooks_url":"https://api.github.com/repos/ARF1/pandas/hooks","issue_events_url":"https://api.github.com/repos/ARF1/pandas/issues/events{/number}","events_url":"https://api.github.com/repos/ARF1/pandas/events","assignees_url":"https://api.github.com/repos/ARF1/pandas/assignees{/user}","branches_url":"https://api.github.com/repos/ARF1/pandas/branches{/branch}","tags_url":"https://api.github.com/repos/ARF1/pandas/tags","blobs_url":"https://api.github.com/repos/ARF1/pandas/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ARF1/pandas/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ARF1/pandas/git/refs{/sha}","trees_url":"https://api.github.com/repos/ARF1/pandas/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ARF1/pandas/statuses/{sha}","languages_url":"https://api.github.com/repos/ARF1/pandas/languages","stargazers_url":"https://api.github.com/repos/ARF1/pandas/stargazers","contributors_url":"https://api.github.com/repos/ARF1/pandas/contributors","subscribers_url":"https://api.github.com/repos/ARF1/pandas/subscribers","subscription_url":"https://api.github.com/repos/ARF1/pandas/subscription","commits_url":"https://api.github.com/repos/ARF1/pandas/commits{/sha}","git_commits_url":"https://api.github.com/repos/ARF1/pandas/git/commits{/sha}","comments_url":"https://api.github.com/repos/ARF1/pandas/comments{/number}","issue_comment_url":"https://api.github.com/repos/ARF1/pandas/issues/comments{/number}","contents_url":"https://api.github.com/repos/ARF1/pandas/contents/{+path}","compare_url":"https://api.github.com/repos/ARF1/pandas/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ARF1/pandas/merges","archive_url":"https://api.github.com/repos/ARF1/pandas/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ARF1/pandas/downloads","issues_url":"https://api.github.com/repos/ARF1/pandas/issues{/number}","pulls_url":"https://api.github.com/repos/ARF1/pandas/pulls{/number}","milestones_url":"https://api.github.com/repos/ARF1/pandas/milestones{/number}","notifications_url":"https://api.github.com/repos/ARF1/pandas/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ARF1/pandas/labels{/name}","releases_url":"https://api.github.com/repos/ARF1/pandas/releases{/id}","created_at":"2015-04-21T10:00:44Z","updated_at":"2015-04-21T10:00:49Z","pushed_at":"2015-05-02T14:11:57Z","git_url":"git://github.com/ARF1/pandas.git","ssh_url":"git@github.com:ARF1/pandas.git","clone_url":"https://github.com/ARF1/pandas.git","svn_url":"https://github.com/ARF1/pandas","homepage":"http://pandas.pydata.org","size":50449,"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":"pydata:master","ref":"master","sha":"76571d03562ca5e87b0b27a8664ce75b7bbdb65d","user":{"login":"pydata","id":1284191,"avatar_url":"https://avatars.githubusercontent.com/u/1284191?v=3","gravatar_id":"","url":"https://api.github.com/users/pydata","html_url":"https://github.com/pydata","followers_url":"https://api.github.com/users/pydata/followers","following_url":"https://api.github.com/users/pydata/following{/other_user}","gists_url":"https://api.github.com/users/pydata/gists{/gist_id}","starred_url":"https://api.github.com/users/pydata/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pydata/subscriptions","organizations_url":"https://api.github.com/users/pydata/orgs","repos_url":"https://api.github.com/users/pydata/repos","events_url":"https://api.github.com/users/pydata/events{/privacy}","received_events_url":"https://api.github.com/users/pydata/received_events","type":"Organization","site_admin":false},"repo":{"id":858127,"name":"pandas","full_name":"pydata/pandas","owner":{"login":"pydata","id":1284191,"avatar_url":"https://avatars.githubusercontent.com/u/1284191?v=3","gravatar_id":"","url":"https://api.github.com/users/pydata","html_url":"https://github.com/pydata","followers_url":"https://api.github.com/users/pydata/followers","following_url":"https://api.github.com/users/pydata/following{/other_user}","gists_url":"https://api.github.com/users/pydata/gists{/gist_id}","starred_url":"https://api.github.com/users/pydata/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pydata/subscriptions","organizations_url":"https://api.github.com/users/pydata/orgs","repos_url":"https://api.github.com/users/pydata/repos","events_url":"https://api.github.com/users/pydata/events{/privacy}","received_events_url":"https://api.github.com/users/pydata/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/pydata/pandas","description":"Flexible and powerful data analysis / manipulation library for Python, providing labeled data structures similar to R data.frame objects, statistical functions, and much more","fork":false,"url":"https://api.github.com/repos/pydata/pandas","forks_url":"https://api.github.com/repos/pydata/pandas/forks","keys_url":"https://api.github.com/repos/pydata/pandas/keys{/key_id}","collaborators_url":"https://api.github.com/repos/pydata/pandas/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/pydata/pandas/teams","hooks_url":"https://api.github.com/repos/pydata/pandas/hooks","issue_events_url":"https://api.github.com/repos/pydata/pandas/issues/events{/number}","events_url":"https://api.github.com/repos/pydata/pandas/events","assignees_url":"https://api.github.com/repos/pydata/pandas/assignees{/user}","branches_url":"https://api.github.com/repos/pydata/pandas/branches{/branch}","tags_url":"https://api.github.com/repos/pydata/pandas/tags","blobs_url":"https://api.github.com/repos/pydata/pandas/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/pydata/pandas/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/pydata/pandas/git/refs{/sha}","trees_url":"https://api.github.com/repos/pydata/pandas/git/trees{/sha}","statuses_url":"https://api.github.com/repos/pydata/pandas/statuses/{sha}","languages_url":"https://api.github.com/repos/pydata/pandas/languages","stargazers_url":"https://api.github.com/repos/pydata/pandas/stargazers","contributors_url":"https://api.github.com/repos/pydata/pandas/contributors","subscribers_url":"https://api.github.com/repos/pydata/pandas/subscribers","subscription_url":"https://api.github.com/repos/pydata/pandas/subscription","commits_url":"https://api.github.com/repos/pydata/pandas/commits{/sha}","git_commits_url":"https://api.github.com/repos/pydata/pandas/git/commits{/sha}","comments_url":"https://api.github.com/repos/pydata/pandas/comments{/number}","issue_comment_url":"https://api.github.com/repos/pydata/pandas/issues/comments{/number}","contents_url":"https://api.github.com/repos/pydata/pandas/contents/{+path}","compare_url":"https://api.github.com/repos/pydata/pandas/compare/{base}...{head}","merges_url":"https://api.github.com/repos/pydata/pandas/merges","archive_url":"https://api.github.com/repos/pydata/pandas/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/pydata/pandas/downloads","issues_url":"https://api.github.com/repos/pydata/pandas/issues{/number}","pulls_url":"https://api.github.com/repos/pydata/pandas/pulls{/number}","milestones_url":"https://api.github.com/repos/pydata/pandas/milestones{/number}","notifications_url":"https://api.github.com/repos/pydata/pandas/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/pydata/pandas/labels{/name}","releases_url":"https://api.github.com/repos/pydata/pandas/releases{/id}","created_at":"2010-08-24T01:37:33Z","updated_at":"2015-05-02T16:59:06Z","pushed_at":"2015-05-02T15:04:51Z","git_url":"git://github.com/pydata/pandas.git","ssh_url":"git@github.com:pydata/pandas.git","clone_url":"https://github.com/pydata/pandas.git","svn_url":"https://github.com/pydata/pandas","homepage":"http://pandas.pydata.org","size":138542,"stargazers_count":4343,"watchers_count":4343,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1597,"mirror_url":null,"open_issues_count":1406,"forks":1597,"open_issues":1406,"watchers":4343,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/pydata/pandas/pulls/9977"},"html":{"href":"https://github.com/pydata/pandas/pull/9977"},"issue":{"href":"https://api.github.com/repos/pydata/pandas/issues/9977"},"comments":{"href":"https://api.github.com/repos/pydata/pandas/issues/9977/comments"},"review_comments":{"href":"https://api.github.com/repos/pydata/pandas/pulls/9977/comments"},"review_comment":{"href":"https://api.github.com/repos/pydata/pandas/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/pydata/pandas/pulls/9977/commits"},"statuses":{"href":"https://api.github.com/repos/pydata/pandas/statuses/c9ac12f6043dfc1aba8f871086b6c69b26940ba4"}}}}