Skip to content

Commit c91f7d0

Browse files
committed
Merge pull request sigmavirus24#315 from sigmavirus24/bug/311
Split up Repository#contents
2 parents 12b0df2 + f85c300 commit c91f7d0

File tree

8 files changed

+715
-51
lines changed

8 files changed

+715
-51
lines changed

LATEST_VERSION_NOTES.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,13 @@ Old name New name
191191
- ``Repository#ignore`` ignores notifications from the repository for the
192192
authenticated user
193193

194+
- ``Repository#contents`` was split into two simpler functions
195+
196+
- ``Repository#file_contents`` returns the contents of a file object
197+
198+
- ``Repository#directory_contents`` returns the contents of files in a
199+
directory.
200+
194201
- ``Organization#add_repo`` and ``Team#add_repo`` have been renamed to
195202
``Organization#add_repository`` and ``Team#add_repository`` respectively.
196203

example-notebooks/contents-api.ipynb

Lines changed: 612 additions & 0 deletions
Large diffs are not rendered by default.

github3/repos/repo.py

Lines changed: 47 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -563,32 +563,6 @@ def compare_commits(self, base, head):
563563
json = self._json(self._get(url), 200)
564564
return self._instance_or_null(Comparison, json)
565565

566-
def contents(self, path, ref=None):
567-
"""Get the contents of the file pointed to by ``path``.
568-
569-
If the path provided is actually a directory, you will receive a
570-
dictionary back of the form::
571-
572-
{
573-
'filename.md': Contents(), # Where Contents an instance
574-
'github.py': Contents(),
575-
}
576-
577-
:param str path: (required), path to file, e.g.
578-
github3/repos/repo.py
579-
:param str ref: (optional), the string name of a commit/branch/tag.
580-
Default: master
581-
:returns: :class:`~github3.repos.contents.Contents` or dict
582-
if successful, else None
583-
"""
584-
url = self._build_url('contents', path, base_url=self._api)
585-
json = self._json(self._get(url, params={'ref': ref}), 200)
586-
if isinstance(json, dict):
587-
return Contents(json, self)
588-
elif isinstance(json, list):
589-
return dict((j.get('name'), Contents(j, self)) for j in json)
590-
return None
591-
592566
def contributor_statistics(self, number=-1, etag=None):
593567
"""Iterate over the contributors list.
594568
@@ -1092,6 +1066,39 @@ def deployments(self, number=-1, etag=None):
10921066
i = self._iter(int(number), url, Deployment, etag=etag)
10931067
return i
10941068

1069+
def directory_contents(self, directory_path, ref=None, return_as=list):
1070+
"""Get the contents of each file in ``directory_path``.
1071+
1072+
If the path provided is actually a directory, you will receive a
1073+
list back of the form::
1074+
1075+
[('filename.md', Contents(...)),
1076+
('github.py', Contents(...)),
1077+
# ...
1078+
('fiz.py', Contents(...))]
1079+
1080+
You can either then transform it into a dictionary::
1081+
1082+
contents = dict(repo.directory_contents('path/to/dir/'))
1083+
1084+
Or you can use the ``return_as`` parameter to have it return a
1085+
dictionary for you::
1086+
1087+
contents = repo.directory_contents('path/to/dir/', return_as=dict)
1088+
1089+
:param str path: (required), path to file, e.g.
1090+
github3/repos/repo.py
1091+
:param str ref: (optional), the string name of a commit/branch/tag.
1092+
Default: master
1093+
:param return_as: (optional), how to return the directory's contents.
1094+
Default: :class:`list`
1095+
:returns: list of tuples of the filename and the Contents returned
1096+
:rtype: list((str, :class:`~github3.repos.contents.Contents`))
1097+
"""
1098+
url = self._build_url('contents', directory_path, base_url=self._api)
1099+
json = self._json(self._get(url, params={'ref': ref}), 200) or []
1100+
return return_as((j.get('name'), Contents(j, self)) for j in json)
1101+
10951102
@requires_auth
10961103
def edit(self, name, description=None, homepage=None, private=None,
10971104
has_issues=None, has_wiki=None, has_downloads=None,
@@ -1145,6 +1152,20 @@ def events(self, number=-1, etag=None):
11451152
url = self._build_url('events', base_url=self._api)
11461153
return self._iter(int(number), url, Event, etag=etag)
11471154

1155+
def file_contents(self, path, ref=None):
1156+
"""Get the contents of the file pointed to by ``path``.
1157+
1158+
:param str path: (required), path to file, e.g.
1159+
github3/repos/repo.py
1160+
:param str ref: (optional), the string name of a commit/branch/tag.
1161+
Default: master
1162+
:returns: the contents of the file requested
1163+
:rtype: :class:`~github3.repos.contents.Contents`
1164+
"""
1165+
url = self._build_url('contents', path, base_url=self._api)
1166+
json = self._json(self._get(url, params={'ref': ref}), 200)
1167+
return self._instance_or_null(Contents, json)
1168+
11481169
def forks(self, sort='', number=-1, etag=None):
11491170
"""Iterate over forks of this repository.
11501171
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"recorded_with": "betamax/0.4.1", "http_interactions": [{"recorded_at": "2014-11-30T00:37:36", "request": {"headers": {"User-Agent": "github3.py/1.0.0b1", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", "Accept": "application/vnd.github.v3.full+json", "Accept-Charset": "utf-8", "Content-Type": "application/json"}, "uri": "https://api.github.com/repos/sigmavirus24/github3.py", "body": {"string": "", "encoding": "utf-8"}, "method": "GET"}, "response": {"headers": {"X-GitHub-Request-Id": "4270732F:1AFB:2A2DA43:547A66D0", "Access-Control-Allow-Credentials": "true", "Content-Security-Policy": "default-src 'none'", "Cache-Control": "public, max-age=60, s-maxage=60", "Content-Type": "application/json; charset=utf-8", "Vary": "Accept, Accept-Encoding", "X-RateLimit-Limit": "60", "X-GitHub-Media-Type": "github.v3; param=full; format=json", "X-Frame-Options": "deny", "Last-Modified": "Sat, 29 Nov 2014 19:17:50 GMT", "X-Content-Type-Options": "nosniff", "Content-Encoding": "gzip", "Access-Control-Expose-Headers": "ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval", "Status": "200 OK", "X-RateLimit-Remaining": "59", "ETag": "\"040841daa4491e82b25e37726481e671\"", "Access-Control-Allow-Origin": "*", "Transfer-Encoding": "chunked", "X-XSS-Protection": "1; mode=block", "X-Served-By": "d594a23ec74671eba905bf91ef329026", "Server": "GitHub.com", "Date": "Sun, 30 Nov 2014 00:37:36 GMT", "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload", "X-RateLimit-Reset": "1417311456"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py", "body": {"base64_string": "H4sIAAAAAAAAA62YwW7jNhCGX8XQtY5p2UmTFbDY7antbQ/tpReDkmiJiEQKJGXDIfLu/SlKluS2thP2Ytgy5+PP4Qw1QxvxPEq2z/H6OY6XkaA1i5Ko4KZs0+2qOUXLaN9W1a7/Q/OipgeuWr15JLNR8iiYihIbVbLgAozpUFDcNJvH9ct2vYzogRqqdq2qMK40ptEJIf6hXnlqq5nKpDBMmFUma9ISb/zt8HULWqF6hsNGeHDBanjP8caAaXIhqDR1dSHBT92ZXAzey6qSR1AuRd+aiJwtnSc7ChfFJymwtESaksF3WNK7cwTX5uOiOiuLDdRmx3PH0dgQxfIPC+vtIMvt/7slijWyA7apzhRvDJfi4wJn1qBJVVDB3+jnaLDWgDhpH5fSWcGaHRCLHzf3ZpY0ih9odnKuUSxj/ABnfxJ5YQ+iOTUubf9EUDjXc8N2NK9dGu5ppdn7MuqmNxjUPVgi6+6N/nma5+y8q5jwx8mUUiwqniqqTou9VAuOnFV7miFWF0ccIwuE6+JXbn5r08UvP34/uOzFuNezkquZ2zl/loxzOY50Y0+uIpCeAEDSKzsFcZy9Jfjs8ylDqtNUKmrkrUPjusAZyJLpTxdLhtE6SHgHAKiUMsyTHQAgrnXL7grt6wvvOJoM+SPaOvVH3j1Zcx3tCdBKNc55wViQB88QS4ZTGekgsjIMOzAs8d+63aZFkFRnD0xayTSIgxcl6SCW6JL695DZhapzVMeYQRXbB0t1jDPUqMD97mQ6yBmJl6DB1gfpHBjE9h6tqChaWoRRzxDsuntVF/TtZhFzPXdGCpCuQlM8bcMPuZHjlPraAfke5tIRM0K7guR6mXPDAZPCpnNBXfNbdcF1Yo+Yhf3/gHVxeol2v2+XMbflOoYl45nsD/2eHuLd/tQfdBI7ztG3A0EhMTCI/amhpnQnF6ZqqGIhonsEsSlFsbVarWzJaFdW10wFZrAnAEVVVqJqDNFpBwaqnpqarlrfO5k5qvdK0jzIt2cIgH4bQ7R6wjTGGvShQQI7wJRY84ppI0XYGTtSpmwhDd/z7J6O5Xq6zUD2m+YiY0taVUtEreEZRxyj1na7iIKThXnIE7AMXAP4TqViCOkgryvmGZb4TjNTDI1IvqMGDcRmHW8e1tuHePtH/CV5ekmetn9hJW2Tz8Y8PsTxw+aLGxM/J09rN6ZpdTnB/NsQnIB9COIbrhjwiWuNf/T3k5bC3RqArXU5Gn4fzZL/uP/ozbIKsXQR9PfPebh8Ld02hdRS1qxBmdDfpJxXuW1OK3g6R/uVy0yv0AMTtzL+hqFxHP/8PKsIMtkKbMhmi8dHalC84t07fThUEueuz81N9c7naZQY1bq2Ek/Gc2Dy8Mhf+dh8YpTTrAcz38b1071scG5ypWR/QySQtrgBaJjoJxt0xdDq+7fE2UxGYIWTdfTLytmetpXZ+XIa68jRB1SywUIEM0c0ggPY0aY1yOCH+P1vzq0EwC8TAAA=", "string": "", "encoding": "utf-8"}}}, {"recorded_at": "2014-11-30T00:37:37", "request": {"headers": {"User-Agent": "github3.py/1.0.0b1", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", "Accept": "application/vnd.github.v3.full+json", "Accept-Charset": "utf-8", "Content-Type": "application/json"}, "uri": "https://api.github.com/repos/sigmavirus24/github3.py/contents/github3/search/", "body": {"string": "", "encoding": "utf-8"}, "method": "GET"}, "response": {"headers": {"X-Frame-Options": "deny", "X-GitHub-Request-Id": "4270732F:1AFB:2A2DA82:547A66D0", "Access-Control-Allow-Credentials": "true", "Content-Security-Policy": "default-src 'none'", "X-RateLimit-Remaining": "58", "Access-Control-Allow-Origin": "*", "X-XSS-Protection": "1; mode=block", "Status": "302 Found", "Content-Type": "text/html;charset=utf-8", "X-Served-By": "2811da37fbdda4367181b328b22b2499", "Server": "GitHub.com", "Vary": "Accept-Encoding", "Location": "https://api.github.com/repositories/3710711/contents/github3/search", "Date": "Sun, 30 Nov 2014 00:37:36 GMT", "X-RateLimit-Limit": "60", "X-RateLimit-Reset": "1417311456", "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload", "Access-Control-Expose-Headers": "ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval", "X-Content-Type-Options": "nosniff", "Content-Length": "0"}, "status": {"message": "Found", "code": 302}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/contents/github3/search/", "body": {"string": "", "encoding": "utf-8"}}}, {"recorded_at": "2014-11-30T00:37:37", "request": {"headers": {"User-Agent": "github3.py/1.0.0b1", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", "Accept": "application/vnd.github.v3.full+json", "Accept-Charset": "utf-8", "Content-Type": "application/json"}, "uri": "https://api.github.com/repositories/3710711/contents/github3/search", "body": {"string": "", "encoding": "utf-8"}, "method": "GET"}, "response": {"headers": {"X-GitHub-Request-Id": "4270732F:1AFB:2A2DA98:547A66D0", "Access-Control-Allow-Credentials": "true", "Content-Security-Policy": "default-src 'none'", "Cache-Control": "public, max-age=60, s-maxage=60", "Content-Type": "application/json; charset=utf-8", "Vary": "Accept, Accept-Encoding", "X-RateLimit-Limit": "60", "X-GitHub-Media-Type": "github.v3; param=full; format=json", "X-Frame-Options": "deny", "Last-Modified": "Sat, 29 Nov 2014 19:17:50 GMT", "X-Content-Type-Options": "nosniff", "Content-Encoding": "gzip", "Access-Control-Expose-Headers": "ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval", "Status": "200 OK", "X-RateLimit-Remaining": "57", "ETag": "\"3929c4826c375ab072c6d6d14bf28aae\"", "Access-Control-Allow-Origin": "*", "Transfer-Encoding": "chunked", "X-XSS-Protection": "1; mode=block", "X-Served-By": "76d9828c7e4f1d910f7ba069e90ce976", "Server": "GitHub.com", "Date": "Sun, 30 Nov 2014 00:37:37 GMT", "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload", "X-RateLimit-Reset": "1417311456"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repositories/3710711/contents/github3/search", "body": {"base64_string": "H4sIAAAAAAAAA72X646bMBCF34XfUewYXyBS1QepKuTLeLFKAGGyUrrKu9dpLpAoi5aVyc+A8Zk5850Yfn0ktdxBsk2KwtWuL4p1e0hWSSv7Mlx8c325VynyIDtdovs1vpRhSS6sEFxlGZGgc2wkMUJCijEwCeFXZgw2hm7Cpt79DUqEiVWy76rwbNn3rd8iJFu3PkutdbNDHbSNR9697eS76/aeUHQpJBSHdFP3UPf+eu1JcT87sD8MvEPVtEG37HdVca84UvtMR1WNQpdNJrTC/mGzh+1nNRQeRycxj2Z42R/a09SsqyBUUFSu/uOT7UfiobKvczaU/l2xb3V9muRIMOIUj8fVLQq6MTAVg+H+OQJEp7DhWGKtqbJWAgBhMlc8BU2FprARWSrJaVDnCGwwzhfJwKWyxfkfHIjG/gwTX8n+c0ejcD+j47jcX6c3Zt55v5+EfrTgTD2mSqXScqkIzRgj4RBglHMSeMcYE4sBcyoEvVHPUr4I9NfKFqd+ZEE07Ge4+ErsP/E0CvczWo7L/W1+Y/D/v2y4vukOU3/5j6vOEQBNcMZyoTKRkXRjrIVUcGkVwQywlQIrTlJqhwgIvEgE7spbPAePZkQLwww/XxmGKXejJGJG33ETcT/JcSz2HrqpQAz3L1Eg4c2HcA2UaU5ylWsQNFPChE+DcBwYnklOuSRDFNgyp8GlsMVDMBgQD/+ve/hK/J87Ggf8r3ccF/zr9I7H3/8A6gjjjwMPAAA=", "string": "", "encoding": "utf-8"}}}]}

tests/cassettes/Repository_file_contents.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

tests/integration/test_repos_repo.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,17 @@ def test_deployments(self):
157157
for d in repository.deployments():
158158
assert isinstance(d, github3.repos.deployment.Deployment)
159159

160+
def test_directory_contents(self):
161+
"""Test that a directory's contents can be retrieved."""
162+
cassette_name = self.cassette_name('directory_contents')
163+
with self.recorder.use_cassette(cassette_name):
164+
repository = self.gh.repository('sigmavirus24', 'github3.py')
165+
contents = repository.directory_contents('github3/search/')
166+
167+
for (filename, content) in contents:
168+
assert content.name == filename
169+
assert isinstance(content, github3.repos.contents.Contents)
170+
160171
def test_events(self):
161172
"""Test that a user can iterate over the events from a repository."""
162173
cassette_name = self.cassette_name('events')
@@ -169,6 +180,15 @@ def test_events(self):
169180
for event in events:
170181
assert isinstance(event, github3.events.Event)
171182

183+
def test_file_contents(self):
184+
"""Test that a file's contents can be retrieved."""
185+
cassette_name = self.cassette_name('file_contents')
186+
with self.recorder.use_cassette(cassette_name):
187+
repository = self.gh.repository('sigmavirus24', 'github3.py')
188+
contents = repository.file_contents('github3/repos/repo.py')
189+
190+
assert isinstance(contents, github3.repos.contents.Contents)
191+
172192
def test_forks(self):
173193
"""Test that a user can iterate over the forks of a repository."""
174194
cassette_name = self.cassette_name('forks')

tests/test_repos.py

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -116,31 +116,6 @@ def test_compare_commits(self):
116116
repos.comparison.Comparison)
117117
self.mock_assertions()
118118

119-
def test_contents(self):
120-
self.response('contents')
121-
filename = 'setup.py'
122-
self.get(self.api + 'contents/' + filename)
123-
124-
assert isinstance(self.repo.contents(filename),
125-
repos.contents.Contents)
126-
self.mock_assertions()
127-
128-
self.response('contents', _iter=True)
129-
files = self.repo.contents(filename)
130-
assert isinstance(files, dict)
131-
132-
self.mock_assertions()
133-
134-
def test_contents_ref(self):
135-
self.response('contents')
136-
filename = 'setup.py'
137-
self.get(self.api + 'contents/' + filename)
138-
self.conf = {'params': {'ref': 'foo'}}
139-
140-
assert isinstance(self.repo.contents(filename, ref='foo'),
141-
repos.contents.Contents)
142-
self.mock_assertions()
143-
144119
def test_create_blob(self):
145120
self.response('blob', 201)
146121
content = 'VGVzdCBibG9i\n'

tests/unit/test_repos_repo.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,33 @@ def test_create_tree_rejects_invalid_trees(self):
185185

186186
assert self.session.post.called is False
187187

188+
def test_directory_contents(self):
189+
"""Verify the request made to retrieve a directory's contents."""
190+
self.instance.directory_contents('path/to/directory')
191+
192+
self.session.get.assert_called_once_with(
193+
url_for('contents/path/to/directory'),
194+
params={'ref': None}
195+
)
196+
197+
def test_directory_contents_with_ref(self):
198+
"""Verify the request made to retrieve a directory's contents."""
199+
self.instance.directory_contents('path/to/directory', ref='some-sha')
200+
201+
self.session.get.assert_called_once_with(
202+
url_for('contents/path/to/directory'),
203+
params={'ref': 'some-sha'}
204+
)
205+
206+
def test_file_contents(self):
207+
"""Verify the request made to retrieve a dictionary's contents."""
208+
self.instance.file_contents('path/to/file.txt', ref='some-sha')
209+
210+
self.session.get.assert_called_once_with(
211+
url_for('contents/path/to/file.txt'),
212+
params={'ref': 'some-sha'}
213+
)
214+
188215
def test_key(self):
189216
"""Test the ability to fetch a deploy key."""
190217
self.instance.key(10)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy