Repository: PyGithub/PyGithub

Issue:
Github.search_topics returning list of repos that throw an error when trying to fetch undefined data
Hello,

I was trying to fetch a list of repositories with a specific topic and then play with the returned attributes, but the Repository objects returned in the PaginatedList throw an error when trying to fetch unknown data:
```bash
Traceback (most recent call last):
  File "github-crawler.py", line 6, in <module>
    print(i, repo.archive_url)
  File "/home/user/.local/lib/python3.6/site-packages/github/Repository.py", line 2407, in get_topics
    self.url + "/topics",
  File "/home/user/.local/lib/python3.6/site-packages/github/Repository.py", line 745, in url
    self._completeIfNotSet(self._url)
  File "/home/user/.local/lib/python3.6/site-packages/github/GithubObject.py", line 259, in _completeIfNotSet
    self._completeIfNeeded()
  File "/home/user/.local/lib/python3.6/site-packages/github/GithubObject.py", line 263, in _completeIfNeeded
    self.__complete()
  File "/home/user/.local/lib/python3.6/site-packages/github/GithubObject.py", line 268, in __complete
    self._url.value
  File "/home/user/.local/lib/python3.6/site-packages/github/Requester.py", line 262, in requestJsonAndCheck
    return self.__check(*self.requestJson(verb, url, parameters, headers, input, self.__customConnection(url)))
  File "/home/user/.local/lib/python3.6/site-packages/github/Requester.py", line 278, in __customConnection
    if not url.startswith("/"):
AttributeError: 'NoneType' object has no attribute 'startswith'
```

Below is an example of the code:
```python
from github import Github

g = Github(per_page=300)
i = 1
for repo in g.search_topics('security'):
    print(i, repo.archive_url)
    i += 1
```

It can be tested here: [https://repl.it/repls/LawngreenPlushBetaversion](https://repl.it/repls/LawngreenPlushBetaversion)

Environment:
Linux ubuntu 4.15.0-36-generic x86_64 GNU/Linux
Python 3.6.6
PyGithub 1.43.2

Any help with that ?
And thanks


Discussion:
I will fix it later :p
Maybe, wrong code is [here](https://github.com/PyGithub/PyGithub/blob/ac8966cc8cb0b9acf3c9ea14162ae800474d4265/github/GithubObject.py#L272). @jacquerie 
> Maybe, wrong code is [here](https://github.com/PyGithub/PyGithub/blob/ac8966cc8cb0b9acf3c9ea14162ae800474d4265/github/GithubObject.py#L272). @jacquerie

Uhm? I don't think I contributed code to any of this...
Just glancing at the code.  It appears that search_topics is returning a paginated list of GitHub repositories, but the API seems to return a list of topics, including the following properties:

- name
- display_name
- short_description
- description
- created_by
- released
- created_at
- updated_at
- featured
- curated
- score

I think this may be the root problem.

Yes indeed, the API endpoint /search/topics returns a list of topics that are related to the provided keyword and not a list of repositories tagged with that topic (which is a little bit confusing, maybe ?).
In my code I used the other API endpoints and it worked fine.

But still, the method in PyGithub should be fixed.
PR welcome

Resolving patch:
diff --git a/github/MainClass.py b/github/MainClass.py
--- a/github/MainClass.py
+++ b/github/MainClass.py
@@ -66,6 +66,7 @@
 import Installation
 import Legacy
 import License
+import Topic
 import github.GithubObject
 import HookDescription
 import GitignoreTemplate
@@ -542,7 +543,7 @@ def search_topics(self, query, **qualifiers):
         :calls: `GET /search/topics <http://developer.github.com/v3/search>`_
         :param query: string
         :param qualifiers: keyword dict query qualifiers
-        :rtype: :class:`github.PaginatedList.PaginatedList` of :class:`github.Repository.Repository`
+        :rtype: :class:`github.PaginatedList.PaginatedList` of :class:`github.Topic.Topic`
         """
         assert isinstance(query, (str, unicode)), query
         url_parameters = dict()
@@ -558,7 +559,7 @@ def search_topics(self, query, **qualifiers):
         assert url_parameters["q"], "need at least one qualifier"
 
         return github.PaginatedList.PaginatedList(
-            github.Repository.Repository,
+            github.Topic.Topic,
             self.__requester,
             "/search/topics",
             url_parameters,
diff --git a/github/Topic.py b/github/Topic.py
new file mode 100644
--- /dev/null
+++ b/github/Topic.py
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+
+############################ Copyrights and license ############################
+#                                                                              #
+# Copyright 2018 Steve Kowalik <steven@wedontsleep.org>                        #
+#                                                                              #
+# This file is part of PyGithub.                                               #
+# http://pygithub.readthedocs.io/                                              #
+#                                                                              #
+# PyGithub is free software: you can redistribute it and/or modify it under    #
+# the terms of the GNU Lesser General Public License as published by the Free  #
+# Software Foundation, either version 3 of the License, or (at your option)    #
+# any later version.                                                           #
+#                                                                              #
+# PyGithub is distributed in the hope that it will be useful, but WITHOUT ANY  #
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS    #
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more #
+# details.                                                                     #
+#                                                                              #
+# You should have received a copy of the GNU Lesser General Public License     #
+# along with PyGithub. If not, see <http://www.gnu.org/licenses/>.             #
+#                                                                              #
+################################################################################
+
+import github.GithubObject
+
+
+class Topic(github.GithubObject.CompletableGithubObject):
+    """
+    This class represents topics as used by https://github.com/topics. The object refereence can be found here https://developer.github.com/v3/search/#search-topics
+    """
+
+    def __repr__(self):
+        return self.get__repr__({"name": self._name.value})
+
+    @property
+    def name(self):
+        """
+        :type: string
+        """
+        self._completeIfNotSet(self._name)
+        return self._name.value
+
+    @property
+    def display_name(self):
+        """
+        :type: string
+        """
+        self._completeIfNotSet(self._display_name)
+        return self._display_name.value
+
+    @property
+    def short_description(self):
+        """
+        :type: string
+        """
+        self._completeIfNotSet(self._short_description)
+        return self._short_description.value
+
+    @property
+    def description(self):
+        """
+        :type: string
+        """
+        self._completeIfNotSet(self._description)
+        return self._description.value
+
+    def _initAttributes(self):
+        self._name = github.GithubObject.NotSet
+        self._display_name = github.GithubObject.NotSet
+        self._short_description = github.GithubObject.NotSet
+        self._description = github.GithubObject.NotSet
+
+    def _useAttributes(self, attributes):
+        if "name" in attributes:  # pragma no branch
+            self._name = self._makeStringAttribute(attributes["name"])
+        if "display_name" in attributes:  # pragma no branch
+            self._display_name = self._makeStringAttribute(attributes["display_name"])
+        if "short_description" in attributes:  # pragma no branch
+            self._short_description = self._makeStringAttribute(attributes["short_description"])
+        if "description" in attributes:  # pragma no branch
+            self._description = self._makeStringAttribute(attributes["description"])


Test patch:
diff --git a/github/tests/Search.py b/github/tests/Search.py
--- a/github/tests/Search.py
+++ b/github/tests/Search.py
@@ -62,8 +62,8 @@ def testPaginateSearchCommits(self):
         self.assertEqual(commits.totalCount, 3)
 
     def testSearchTopics(self):
-        repos = self.g.search_topics("python", repositories=">950")
-        self.assertListKeyBegin(repos, lambda r: r.name, [u"python", u"django", u"flask", u"ruby", u"scikit-learn", u"wagtail"])
+        topics = self.g.search_topics("python", repositories=">950")
+        self.assertListKeyBegin(topics, lambda r: r.name, [u"python", u"django", u"flask", u"ruby", u"scikit-learn", u"wagtail"])
 
     def testPaginateSearchTopics(self):
         repos = self.g.search_topics("python", repositories=">950")