Skip to content

Add support for downloading http and ftp urls - #22

Merged
pombredanne merged 1 commit into
aboutcode-org:masterfrom
TG1999:http_ftp_urls
Jul 22, 2020
Merged

Add support for downloading http and ftp urls#22
pombredanne merged 1 commit into
aboutcode-org:masterfrom
TG1999:http_ftp_urls

Conversation

@TG1999

@TG1999 TG1999 commented May 12, 2020

Copy link
Copy Markdown
Collaborator

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

@TG1999
TG1999 marked this pull request as draft May 12, 2020 18:33
@TG1999
TG1999 marked this pull request as ready for review May 13, 2020 05:29
@TG1999

TG1999 commented May 13, 2020

Copy link
Copy Markdown
Collaborator Author

@MaJuRG how it looks initially, please review it :D

Comment thread fetchcode/api.py Outdated


def fetch(url):
def fetch(url, filename=None):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of filename?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If user wants to save the file at a customised location, then can specify the location here.

@steven-esser steven-esser May 14, 2020

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I would change this variable name to something more descriptive, like location or download_path or something similar.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, changing the name

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MaJuRG , I have changed the name

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MaJuRG can you please also tell what is left in this PR :D

@TG1999 TG1999 linked an issue May 15, 2020 that may be closed by this pull request
@TG1999 TG1999 removed a link to an issue May 15, 2020
Comment thread fetchcode/api.py Outdated
try:
r = urlopen(url)

except:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you except the exact Exception here? This way we know if some other unknown exception is raised, instead of catching everything.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay got this

Comment thread fetchcode/api.py Outdated
Comment on lines +64 to +68
if 'Content-Type' in info:
content_type = info['Content-Type']

if 'Content-length' in info:
size = int(info['Content-length'])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldnt these be replaced with something like content_type = info.get('Content-Type') instead of using if statements.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got this one

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MaJuRG review it please :D

@pombredanne pombredanne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you... Please see my comments inline.

Comment thread fetchcode/api.py
import shutil
import tempfile

import requests

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you really dropping using requests?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I thought I should use urllib since it can support both http and ftp urls

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about we use ftplib ?

Comment thread fetchcode/api.py Outdated
- `content_type`: content type of the file
- `size`: size of the retrieved content in bytes
- `url`: fetched URL
- `scheme` : scheme of the URL

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why return the scheme too?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 :)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is already in the URL, so what will you do with the returned value?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay got this, making changes for this :D

Comment thread fetchcode/api.py Outdated


def fetch(url):
def fetch(url, location=None):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is location about?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If user wants to give a customised location of its own choice, while using this library, they can use this location parameter.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, then explain that in the function docstring

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got this one

Comment thread fetchcode/api.py Outdated
url_parts = urlparse(url)

scheme = url_parts.scheme

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the blank line? Does it help with readability here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay got this one,

Comment thread tests/test_api.py Outdated
@@ -14,19 +14,148 @@
# CONDITIONS OF ANY KIND, either express or implied. See the License for the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay got this one

Comment thread tests/test_api.py Outdated
@mock.patch('fetchcode.api.requests.get')
def test_fetch(mock_get):

@mock.patch('fetchcode.api.urlopen')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need an "api" module?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate a little 😅

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

may be you could use a flatter namespace and have your api functions attached directly under fetchcode.init.py?

@pombredanne pombredanne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!
See some comments inilne.

Comment thread fetchcode/__init__.py Outdated
- `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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indent by 4 spaces ... but you likely would want these to be in the init docstring

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it

Comment thread fetchcode/__init__.py Outdated
"""

def __init__(self, location, content_type, size, url):
self.location = location

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the most salient attribute of a Response? IMHO you should order the attributes as: url, size, content_type, location

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure

Comment thread fetchcode/__init__.py Outdated
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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For "at the location location string"
what about instead:
"saving the content in a file at location"
?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense to me too

Comment thread fetchcode/__init__.py Outdated
size = ftp.size(path)
mime = MimeTypes()
mime_type = mime.guess_type(file)
content_type = mime_type[0]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if no content_type is returned?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got this

Comment thread fetchcode/__init__.py Outdated
"""
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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else use tempfile. --> otherwise create and return a temporary file may be better?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense to me too

Comment thread fetchcode/__init__.py Outdated
Take `location` as an optional parameter and store content at that location if specified,
else use tempfile.
"""
if location == None:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use instead if not location:
But is it really a worthy convenience to have that optional feature?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need your suggestion over this, what are your thoughts over this

Comment thread fetchcode/__init__.py Outdated

fetcher = {"ftp": fetch_via_ftp, "http": fetch_via_http, "https": fetch_via_http}

return fetcher.get(scheme)(url, location)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if fetcher.get(scheme) returns None?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got this

Comment thread tests/test_api.py
from fetchcode import api

@mock.patch('fetchcode.api.requests.get')
def test_fetch(mock_get):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you keep the tests somehow?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These all are deleted :p

Comment thread tests/test_api.py
assert hasattr(response,'size')
assert hasattr(response,'location')
assert hasattr(response,'url')
assert hasattr(response,'content_type')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that rather than only checking the presence of an attribute, check its value

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also deleted

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test_fetch is the new file now where tests reside regarding this code

@TG1999
TG1999 requested a review from pombredanne June 22, 2020 16:15
@TG1999

TG1999 commented Jun 22, 2020

Copy link
Copy Markdown
Collaborator Author

@pombredanne please review the changes :)

Comment thread fetchcode/__init__.py Outdated
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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not very readable.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got this one

Comment thread fetchcode/__init__.py Outdated
self.location = location


def fetch_via_http(url, location):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets remove the via string from all these methods.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay got this !!

Comment thread fetchcode/__init__.py Outdated
Comment on lines +104 to +105
else:
return

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is redundant.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, making it right, Thanks :)

Comment thread fetchcode/__init__.py

@steven-esser steven-esser left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread fetchcode/__init__.py

@pombredanne pombredanne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!
See some comments inline.

Comment thread README.md
@@ -13,3 +13,16 @@ Then install all the requirements using
To run test suite

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please RestructuredText (.rst) rather than Markdown for docs.

Comment thread tests/test_fetch.py Outdated

def test_fetch_with_scheme_not_present():
url = "abc://speedtest/1KB.zip"
response = fetch(url=url)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO this should raise an exception when there is an unsupported/unknown scheme.

Comment thread fetchcode/__init__.py Outdated
url_parts = urlparse(url)
scheme = url_parts.scheme

fetcher = {"ftp": fetch_ftp, "http": fetch_http, "https": fetch_http}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's a collection, so the variable name should be plural

Comment thread fetchcode/__init__.py Outdated

fetcher = {"ftp": fetch_ftp, "http": fetch_http, "https": fetch_http}

if scheme in fetcher:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the scheme is not there we should have an exception and not return None.

Signed-off-by: TG1999 <tushar.goel.dav@gmail.com>
Comment thread fetchcode/__init__.py

@steven-esser steven-esser left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.

@pombredanne Anything to add here?

@TG1999 TG1999 changed the title [WIP] Add support for downloading http and ftp urls Add support for downloading http and ftp urls Jul 22, 2020

@pombredanne pombredanne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All good now. Thank you ++
Merging!

@pombredanne
pombredanne merged commit 85f46ba into aboutcode-org:master Jul 22, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants