Repository: PyGithub/PyGithub

Issue:
Add support for searching topics
Searching by topic is a feature offered in the beta version of the API.  We need this feature in order to collect data about repositories from a topic point of view.

[Searching Topics](https://help.github.com/articles/searching-topics/)
[Searching Topics by API](https://developer.github.com/v3/search/#search-topics)

Example of use:
```
g = Github()
# will return all machine-learning related topics
topics = g.search_topics(query=machine-learning) 

for topic in topics:
    print(topic.display_name)
    print(topic.featured)
    print(topic.curated)
```


Discussion:
@edanhauon Thanks for reporting. If you can put in a PR I will be willing to review it.

Resolving patch:
diff --git a/github/MainClass.py b/github/MainClass.py
--- a/github/MainClass.py
+++ b/github/MainClass.py
@@ -510,6 +510,36 @@ def search_commits(self, query, sort=github.GithubObject.NotSet, order=github.Gi
             }
         )
 
+    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`
+        """
+        assert isinstance(query, (str, unicode)), query
+        url_parameters = dict()
+
+        query_chunks = []
+        if query:  # pragma no branch (Should be covered)
+            query_chunks.append(query)
+
+        for qualifier, value in qualifiers.items():
+            query_chunks.append("%s:%s" % (qualifier, value))
+
+        url_parameters["q"] = ' '.join(query_chunks)
+        assert url_parameters["q"], "need at least one qualifier"
+
+        return github.PaginatedList.PaginatedList(
+            github.Repository.Repository,
+            self.__requester,
+            "/search/topics",
+            url_parameters,
+            headers={
+                "Accept": Consts.mediaTypeTopicsPreview
+            }
+        )
+
     def render_markdown(self, text, context=github.GithubObject.NotSet):
         """
         :calls: `POST /markdown <http://developer.github.com/v3/markdown>`_


Test patch:
diff --git a/github/tests/ReplayData/Search.testPaginateSearchTopics.txt b/github/tests/ReplayData/Search.testPaginateSearchTopics.txt
new file mode 100644
--- /dev/null
+++ b/github/tests/ReplayData/Search.testPaginateSearchTopics.txt
@@ -0,0 +1,10 @@
+https
+GET
+api.github.com
+None
+/search/topics?q=python+repositories%3A%3E950&per_page=1
+{'Authorization': 'Basic login_and_password_removed', 'Accept': 'application/vnd.github.mercy-preview+json', 'User-Agent': 'PyGithub/Python'}
+None
+200
+[('access-control-allow-origin', '*'), ('access-control-expose-headers', 'ETag, Link, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval'), ('cache-control', 'no-cache'), ('content-encoding', 'gzip'), ('content-security-policy', "default-src 'none'"), ('content-type', 'application/json; charset=utf-8'), ('date', 'Tue, 04 Sep 2018 19:33:06 GMT'), ('referrer-policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('server', 'GitHub.com'), ('status', '200 OK'), ('strict-transport-security', 'max-age=31536000; includeSubdomains; preload'), ('transfer-encoding', 'chunked'), ('x-accepted-oauth-scopes', ''), ('x-content-type-options', 'nosniff'), ('x-frame-options', 'deny'), ('x-github-media-type', 'github.mercy-preview; format=json'), ('x-github-request-id', '6CB6:35BC:A1C2D7:1AE3E6A:5B8EDDF1'), ('x-oauth-scopes', 'read:user'), ('x-ratelimit-limit', '30'), ('x-ratelimit-remaining', '27'), ('x-ratelimit-reset', '1536089589'), ('x-runtime-rack', '0.034532'), ('x-xss-protection', '1; mode=block')]
+{"total_count":6,"incomplete_results":false,"items":[{"name":"python","display_name":"Python","short_description":"Python is a dynamically typed programming language.","description":"Python is a dynamically typed programming language designed by Guido Van Rossum. Much like the programming language Ruby, Python was designed to be easily read by programmers. Because of its large following and many libraries, Python can be implemented and used to do anything from webpages to scientific research.","created_by":"Guido van Rossum","released":"February 20, 1991","created_at":"2016-12-07T00:07:02Z","updated_at":"2017-10-27T22:45:43Z","featured":true,"curated":true,"score":6000.218},{"name":"django","display_name":"Django","short_description":"Django is a web application framework for Python.","description":"Django is a web application framework for Python. It is designed to prioritize principles of reusability and rapid development.","created_by":"Adrian Holovaty, Simon Willison","released":"21 July 2005","created_at":"2017-01-31T20:40:48Z","updated_at":"2017-10-26T21:33:58Z","featured":true,"curated":true,"score":459.86417},{"name":"flask","display_name":"Flask","short_description":"Flask is a web framework for Python based on the Werkzeug toolkit.","description":"Flask is a web framework for Python, based on the Werkzeug toolkit.","created_by":"Armin Ronacher","released":"April 1, 2010","created_at":"2016-12-25T23:31:26Z","updated_at":"2018-02-05T17:11:09Z","featured":true,"curated":true,"score":311.18997},{"name":"ruby","display_name":"Ruby","short_description":"Ruby is a scripting language designed for simplified object-oriented programming.","description":"Ruby was developed by Yukihiro \"Matz\" Matsumoto in 1995 with the intent of having an easily readable programming language. It is integrated with the Rails framework to create dynamic web-applications. Ruby's syntax is similar to that of Perl and Python.","created_by":"Yukihiro Matsumoto","released":"December 21, 1995","created_at":"2016-11-28T22:03:59Z","updated_at":"2017-10-30T18:16:32Z","featured":true,"curated":true,"score":224.16049},{"name":"scikit-learn","display_name":"scikit-learn","short_description":"scikit-learn is a Python module for machine learning.","description":"scikit-learn is a widely-used Python module for classic machine learning. It is built on top of SciPy.","created_by":"David Cournapeau","released":"January 05, 2010","created_at":"2017-01-31T21:47:19Z","updated_at":"2018-02-22T18:23:42Z","featured":true,"curated":true,"score":169.0507},{"name":"wagtail","display_name":"Wagtail","short_description":"Wagtail is an open source CMS written in Python and built on the Django web framework.","description":"Wagtail is a free and open source content management system (CMS)\nwritten in Python. The project has a focus on developer friendliness\nas well as ease of use of its administration interface,\ntranslated in multiple languages.","created_by":"Torchbox","released":"February 2014","created_at":"2017-01-31T21:34:25Z","updated_at":"2018-03-08T08:16:54Z","featured":true,"curated":true,"score":51.901356}]}
diff --git a/github/tests/ReplayData/Search.testSearchTopics.txt b/github/tests/ReplayData/Search.testSearchTopics.txt
new file mode 100644
--- /dev/null
+++ b/github/tests/ReplayData/Search.testSearchTopics.txt
@@ -0,0 +1,10 @@
+https
+GET
+api.github.com
+None
+/search/topics?q=python+repositories%3A%3E950
+{'Authorization': 'Basic login_and_password_removed', 'Accept': 'application/vnd.github.mercy-preview+json', 'User-Agent': 'PyGithub/Python'}
+None
+200
+[('access-control-allow-origin', '*'), ('access-control-expose-headers', 'ETag, Link, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval'), ('cache-control', 'no-cache'), ('content-encoding', 'gzip'), ('content-security-policy', "default-src 'none'"), ('content-type', 'application/json; charset=utf-8'), ('date', 'Tue, 04 Sep 2018 19:33:06 GMT'), ('referrer-policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('server', 'GitHub.com'), ('status', '200 OK'), ('strict-transport-security', 'max-age=31536000; includeSubdomains; preload'), ('transfer-encoding', 'chunked'), ('x-accepted-oauth-scopes', ''), ('x-content-type-options', 'nosniff'), ('x-frame-options', 'deny'), ('x-github-media-type', 'github.mercy-preview; format=json'), ('x-github-request-id', '6CB6:35BC:A1C2D7:1AE3E6A:5B8EDDF1'), ('x-oauth-scopes', 'read:user'), ('x-ratelimit-limit', '30'), ('x-ratelimit-remaining', '27'), ('x-ratelimit-reset', '1536089589'), ('x-runtime-rack', '0.034532'), ('x-xss-protection', '1; mode=block')]
+{"total_count":6,"incomplete_results":false,"items":[{"name":"python","display_name":"Python","short_description":"Python is a dynamically typed programming language.","description":"Python is a dynamically typed programming language designed by Guido Van Rossum. Much like the programming language Ruby, Python was designed to be easily read by programmers. Because of its large following and many libraries, Python can be implemented and used to do anything from webpages to scientific research.","created_by":"Guido van Rossum","released":"February 20, 1991","created_at":"2016-12-07T00:07:02Z","updated_at":"2017-10-27T22:45:43Z","featured":true,"curated":true,"score":6000.218},{"name":"django","display_name":"Django","short_description":"Django is a web application framework for Python.","description":"Django is a web application framework for Python. It is designed to prioritize principles of reusability and rapid development.","created_by":"Adrian Holovaty, Simon Willison","released":"21 July 2005","created_at":"2017-01-31T20:40:48Z","updated_at":"2017-10-26T21:33:58Z","featured":true,"curated":true,"score":459.86417},{"name":"flask","display_name":"Flask","short_description":"Flask is a web framework for Python based on the Werkzeug toolkit.","description":"Flask is a web framework for Python, based on the Werkzeug toolkit.","created_by":"Armin Ronacher","released":"April 1, 2010","created_at":"2016-12-25T23:31:26Z","updated_at":"2018-02-05T17:11:09Z","featured":true,"curated":true,"score":311.18997},{"name":"ruby","display_name":"Ruby","short_description":"Ruby is a scripting language designed for simplified object-oriented programming.","description":"Ruby was developed by Yukihiro \"Matz\" Matsumoto in 1995 with the intent of having an easily readable programming language. It is integrated with the Rails framework to create dynamic web-applications. Ruby's syntax is similar to that of Perl and Python.","created_by":"Yukihiro Matsumoto","released":"December 21, 1995","created_at":"2016-11-28T22:03:59Z","updated_at":"2017-10-30T18:16:32Z","featured":true,"curated":true,"score":224.16049},{"name":"scikit-learn","display_name":"scikit-learn","short_description":"scikit-learn is a Python module for machine learning.","description":"scikit-learn is a widely-used Python module for classic machine learning. It is built on top of SciPy.","created_by":"David Cournapeau","released":"January 05, 2010","created_at":"2017-01-31T21:47:19Z","updated_at":"2018-02-22T18:23:42Z","featured":true,"curated":true,"score":169.0507},{"name":"wagtail","display_name":"Wagtail","short_description":"Wagtail is an open source CMS written in Python and built on the Django web framework.","description":"Wagtail is a free and open source content management system (CMS)\nwritten in Python. The project has a focus on developer friendliness\nas well as ease of use of its administration interface,\ntranslated in multiple languages.","created_by":"Torchbox","released":"February 2014","created_at":"2017-01-31T21:34:25Z","updated_at":"2018-03-08T08:16:54Z","featured":true,"curated":true,"score":51.901356}]}
diff --git a/github/tests/Search.py b/github/tests/Search.py
--- a/github/tests/Search.py
+++ b/github/tests/Search.py
@@ -61,6 +61,14 @@ def testPaginateSearchCommits(self):
         commits = self.g.search_commits(query="hash:5b0224e868cc9242c9450ef02efbe3097abd7ba2")
         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"])
+
+    def testPaginateSearchTopics(self):
+        repos = self.g.search_topics("python", repositories=">950")
+        self.assertEqual(repos.totalCount, 3)
+
     def testSearchCode(self):
         files = self.g.search_code("toto", sort="indexed", order="asc", user="jacquev6")
         self.assertListKeyEqual(files, lambda f: f.name, [u'Commit.setUp.txt', u'PullRequest.testGetFiles.txt', u'NamedUser.testGetEvents.txt', u'PullRequest.testCreateComment.txt', u'PullRequestFile.setUp.txt', u'Repository.testGetIssuesWithWildcards.txt', u'Repository.testGetIssuesWithArguments.txt', u'test_ebnf.cpp', u'test_abnf.cpp', u'PullRequestFile.py', u'SystemCalls.py', u'tests.py', u'LexerTestCase.py', u'ParserTestCase.py'])