Add support for downloading http and ftp urls - #22
Conversation
|
@MaJuRG how it looks initially, please review it :D |
|
|
||
|
|
||
| def fetch(url): | ||
| def fetch(url, filename=None): |
There was a problem hiding this comment.
What is the purpose of filename?
There was a problem hiding this comment.
If user wants to save the file at a customised location, then can specify the location here.
There was a problem hiding this comment.
Ok, I would change this variable name to something more descriptive, like location or download_path or something similar.
There was a problem hiding this comment.
Agreed, changing the name
There was a problem hiding this comment.
@MaJuRG can you please also tell what is left in this PR :D
| try: | ||
| r = urlopen(url) | ||
|
|
||
| except: |
There was a problem hiding this comment.
Can you except the exact Exception here? This way we know if some other unknown exception is raised, instead of catching everything.
| if 'Content-Type' in info: | ||
| content_type = info['Content-Type'] | ||
|
|
||
| if 'Content-length' in info: | ||
| size = int(info['Content-length']) |
There was a problem hiding this comment.
Couldnt these be replaced with something like content_type = info.get('Content-Type') instead of using if statements.
There was a problem hiding this comment.
I have added another if for handling type of size, it will be None if its not found else it's needed to be converted into int
pombredanne
left a comment
There was a problem hiding this comment.
Thank you... Please see my comments inline.
| import shutil | ||
| import tempfile | ||
|
|
||
| import requests |
There was a problem hiding this comment.
Are you really dropping using requests?
There was a problem hiding this comment.
Yes, I thought I should use urllib since it can support both http and ftp urls
There was a problem hiding this comment.
hum... I am not sure that the convenience is worth the possible trouble. "requests" is a tad more robust than the plain urllib AFAIK. Also have you considered https://pypi.org/project/ftputil/ also for FTP?
There was a problem hiding this comment.
what about we use ftplib ?
| - `content_type`: content type of the file | ||
| - `size`: size of the retrieved content in bytes | ||
| - `url`: fetched URL | ||
| - `scheme` : scheme of the URL |
There was a problem hiding this comment.
What I thought thay since earlier our code was only for http based URLs, since we are also supporting ftp based URLs, so I should also save the scheme, so what's your thoughts over it? Should we save it or not :)
There was a problem hiding this comment.
It is already in the URL, so what will you do with the returned value?
There was a problem hiding this comment.
Okay got this, making changes for this :D
|
|
||
|
|
||
| def fetch(url): | ||
| def fetch(url, location=None): |
There was a problem hiding this comment.
If user wants to give a customised location of its own choice, while using this library, they can use this location parameter.
There was a problem hiding this comment.
OK, then explain that in the function docstring
| url_parts = urlparse(url) | ||
|
|
||
| scheme = url_parts.scheme | ||
|
|
There was a problem hiding this comment.
Why the blank line? Does it help with readability here?
| @@ -14,19 +14,148 @@ | |||
| # CONDITIONS OF ANY KIND, either express or implied. See the License for the | |||
There was a problem hiding this comment.
Please tiny test files that are just a few bytes. https://github.com/nexB/fetchcode/blob/4ad6ca4384e789e4b3cff5e1daf28a927f07be7f/tests/data/img.png is way too big we like to try to avoid polluting the version control history with big test files when possible.
Furthermore it may a copyrighted image?
| @mock.patch('fetchcode.api.requests.get') | ||
| def test_fetch(mock_get): | ||
|
|
||
| @mock.patch('fetchcode.api.urlopen') |
There was a problem hiding this comment.
Do we really need an "api" module?
There was a problem hiding this comment.
Can you elaborate a little 😅
There was a problem hiding this comment.
may be you could use a flatter namespace and have your api functions attached directly under fetchcode.init.py?
pombredanne
left a comment
There was a problem hiding this comment.
Thanks!
See some comments inilne.
| - `location`: the absolute location of the files that was fetched | ||
| - `content_type`: content type of the file | ||
| - `size`: size of the retrieved content in bytes | ||
| - `url`: fetched URL |
There was a problem hiding this comment.
Indent by 4 spaces ... but you likely would want these to be in the init docstring
| """ | ||
|
|
||
| def __init__(self, location, content_type, size, url): | ||
| self.location = location |
There was a problem hiding this comment.
What is the most salient attribute of a Response? IMHO you should order the attributes as: url, size, content_type, location
| def fetch_via_http(url, location): | ||
| """ | ||
| Return a `Response` object built from fetching the content at a HTTP/HTTPS based `url` URL string | ||
| at the `location` location string |
There was a problem hiding this comment.
For "at the location location string"
what about instead:
"saving the content in a file at location"
?
There was a problem hiding this comment.
Makes sense to me too
| size = ftp.size(path) | ||
| mime = MimeTypes() | ||
| mime_type = mime.guess_type(file) | ||
| content_type = mime_type[0] |
There was a problem hiding this comment.
What if no content_type is returned?
| """ | ||
| Return a `Response` object built from fetching the content at the `url` URL string. | ||
| Take `location` as an optional parameter and store content at that location if specified, | ||
| else use tempfile. |
There was a problem hiding this comment.
else use tempfile. --> otherwise create and return a temporary file may be better?
There was a problem hiding this comment.
Makes sense to me too
| Take `location` as an optional parameter and store content at that location if specified, | ||
| else use tempfile. | ||
| """ | ||
| if location == None: |
There was a problem hiding this comment.
Use instead if not location:
But is it really a worthy convenience to have that optional feature?
There was a problem hiding this comment.
I need your suggestion over this, what are your thoughts over this
|
|
||
| fetcher = {"ftp": fetch_via_ftp, "http": fetch_via_http, "https": fetch_via_http} | ||
|
|
||
| return fetcher.get(scheme)(url, location) |
There was a problem hiding this comment.
What if fetcher.get(scheme) returns None?
| from fetchcode import api | ||
|
|
||
| @mock.patch('fetchcode.api.requests.get') | ||
| def test_fetch(mock_get): |
There was a problem hiding this comment.
Did you keep the tests somehow?
There was a problem hiding this comment.
These all are deleted :p
| assert hasattr(response,'size') | ||
| assert hasattr(response,'location') | ||
| assert hasattr(response,'url') | ||
| assert hasattr(response,'content_type') |
There was a problem hiding this comment.
Note that rather than only checking the presence of an attribute, check its value
There was a problem hiding this comment.
This is also deleted
There was a problem hiding this comment.
test_fetch is the new file now where tests reside regarding this code
|
@pombredanne please review the changes :) |
| size = ftp.size(path) | ||
| mime = MimeTypes() | ||
| mime_type = mime.guess_type(file) | ||
| content_type = mime_type[0] if mime_type and len(mime_type) >= 1 else None |
There was a problem hiding this comment.
This is not very readable.
| self.location = location | ||
|
|
||
|
|
||
| def fetch_via_http(url, location): |
There was a problem hiding this comment.
Lets remove the via string from all these methods.
| else: | ||
| return |
There was a problem hiding this comment.
Oops, making it right, Thanks :)
steven-esser
left a comment
There was a problem hiding this comment.
This is looking OK. From what I can see, we are not getting the actual content that these URLs are pointing to. Is this by design?
Perhaps we do not want this content, but I had thought we did need it. @pombredanne ping
pombredanne
left a comment
There was a problem hiding this comment.
Thank you!
See some comments inline.
| @@ -13,3 +13,16 @@ Then install all the requirements using | |||
| To run test suite | |||
There was a problem hiding this comment.
Please RestructuredText (.rst) rather than Markdown for docs.
|
|
||
| def test_fetch_with_scheme_not_present(): | ||
| url = "abc://speedtest/1KB.zip" | ||
| response = fetch(url=url) |
There was a problem hiding this comment.
IMHO this should raise an exception when there is an unsupported/unknown scheme.
| url_parts = urlparse(url) | ||
| scheme = url_parts.scheme | ||
|
|
||
| fetcher = {"ftp": fetch_ftp, "http": fetch_http, "https": fetch_http} |
There was a problem hiding this comment.
that's a collection, so the variable name should be plural
|
|
||
| fetcher = {"ftp": fetch_ftp, "http": fetch_http, "https": fetch_http} | ||
|
|
||
| if scheme in fetcher: |
There was a problem hiding this comment.
When the scheme is not there we should have an exception and not return None.
Signed-off-by: TG1999 <tushar.goel.dav@gmail.com>
steven-esser
left a comment
There was a problem hiding this comment.
Looks good to me.
@pombredanne Anything to add here?
pombredanne
left a comment
There was a problem hiding this comment.
All good now. Thank you ++
Merging!
I have modified the existing API according to issue #20 and #21, test cases are pending I will try to update them by tommorow.
Signed-off-by: TG1999 tushar.goel.dav@gmail.com