Repository: Cadair/parfive

Issue:
Command line interface?
It might be useful to create a command line interface, so people can just fire off requests without having to write any code to use the library

As a basic interface, just give it a file with one URL per line, or maybe a lot of URLs as arguments (although that could hit up against limits)

If you wanted to be fancy, have it be able to read a tab delim or CSV file and specify what field it should look at for URLs.  (yes, people could use the unix `cut` command to extract the URLs first, but not everyone's on a posix-type system)

Comments:

Patch:
diff --git a/README.rst b/README.rst
index 8c8c05e..7014682 100644
--- a/README.rst
+++ b/README.rst
@@ -24,6 +24,28 @@ A simple example is::
 
   files = dl.download()
 
+Parfive also bundles a CLI. The following example will download the two files concurrently.::
+
+  $ parfive 'http://212.183.159.230/5MB.zip' 'http://212.183.159.230/10MB.zip'
+  $ parfive --help                                                                           
+  usage: parfive [-h] [--max-conn MAX_CONN] [--overwrite] [--no-file-progress]
+                [--directory DIRECTORY] [--print-filenames]
+                URLS [URLS ...]
+
+  Parfive, the python asyncio based downloader
+
+  positional arguments:
+    URLS                  URLs of files to be downloaded.
+
+  optional arguments:
+    -h, --help            show this help message and exit
+    --max-conn MAX_CONN   Number of maximum connections.
+    --overwrite           Overwrite if the file exists.
+    --no-file-progress    Show progress bar for each file.
+    --directory DIRECTORY
+                          Directory to which downloaded files are saved.
+    --print-filenames     Print successfully downloaded files's names to stdout.
+
 
 Results
 ^^^^^^^
diff --git a/docs/index.rst b/docs/index.rst
index 64d40b0..afe33c5 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -12,12 +12,7 @@ to the user about the in progress downloads. It also aims to provide a clear
 interface for inspecting any failed downloads.
 
 The parfive package was motivated by the needs of
-`SunPy's <https://sunpy.org>`__ ``net`` submodule, but should be generally
-applicable to anyone who wants a user friendly way of downloading multiple
-files in parallel.
-
-Parfive supports downloading files over either HTTP or FTP using
-`aiohttp <http://aiohttp.readthedocs.io/>`__ and `aioftp <https://aioftp.readthedocs.io/>`__
+`SunPy's <https://sunpy.org>`__ ``net`` submodule, but should be generally applicable to anyone who wants a user friendly way of downloading multiple files in parallel. Parfive supports downloading files over either HTTP or FTP using `aiohttp <http://aiohttp.readthedocs.io/>`__ and `aioftp <https://aioftp.readthedocs.io/>`__
 ``aioftp`` is an optional dependency, which does not need to be installed to
 download files over HTTP.
 
@@ -60,6 +55,29 @@ A simple example is::
 
   files = dl.download()
 
+Parfive also bundles a CLI. The following example will download the two files concurrently.::
+
+  $ parfive 'http://212.183.159.230/5MB.zip' 'http://212.183.159.230/10MB.zip'
+  $ parfive --help                                                                           
+  usage: parfive [-h] [--max-conn MAX_CONN] [--overwrite] [--no-file-progress]
+                [--directory DIRECTORY] [--print-filenames]
+                URLS [URLS ...]
+
+  Parfive, the python asyncio based downloader
+
+  positional arguments:
+    URLS                  URLs of files to be downloaded.
+
+  optional arguments:
+    -h, --help            show this help message and exit
+    --max-conn MAX_CONN   Number of maximum connections.
+    --overwrite           Overwrite if the file exists.
+    --no-file-progress    Show progress bar for each file.
+    --directory DIRECTORY
+                          Directory to which downloaded files are saved.
+    --print-filenames     Print successfully downloaded files's names to stdout.
+
+
 
 .. automodapi:: parfive
    :no-heading:
diff --git a/parfive/main.py b/parfive/main.py
new file mode 100644
index 0000000..b49ab8c
--- /dev/null
+++ b/parfive/main.py
@@ -0,0 +1,38 @@
+import argparse
+import sys
+
+from parfive import Downloader
+
+
+def main():
+    args = parse_args(sys.argv[1:])
+    downloader = Downloader(max_conn=args.max_conn, file_progress=not args.no_file_progress, overwrite=args.overwrite)
+    for url in args.urls:
+        downloader.enqueue_file(url, path=args.directory)
+    results = downloader.download()
+    for i in results:
+        print(i)
+
+    err_str = ''
+    for err in results.errors:
+        err_str += f'{err.url} \t {err.exception}\n'
+    if err_str:
+        sys.exit(err_str)
+
+def parse_args(args):
+    parser = argparse.ArgumentParser(description='Parfive, the python asyncio based downloader')
+    parser.add_argument('urls', metavar='URLS', type=str, nargs='+',
+                        help='URLs of files to be downloaded.')
+    parser.add_argument('--max-conn', type=int, default=5,
+                        help='Number of maximum connections.')
+    parser.add_argument('--overwrite', action='store_const', const=True, default=False,
+                        help='Overwrite if the file exists.')
+    parser.add_argument('--no-file-progress', action='store_const', const=True, default=False, dest='no_file_progress',
+                        help='Show progress bar for each file.')
+    parser.add_argument('--directory', type=str, default='./',
+                        help='Directory to which downloaded files are saved.')
+    parser.add_argument('--print-filenames', action='store_const', const=True, default=False, dest='print_filenames',
+                        help='Print successfully downloaded files\'s names to stdout.')
+
+    args = parser.parse_args(args)
+    return args
diff --git a/setup.cfg b/setup.cfg
index 5a57d97..d016fd0 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -20,6 +20,10 @@ setup_requires =
   setuptools_scm
 packages = find:
 
+[options.entry_points]
+console_scripts =
+    parfive = parfive.main:main
+
 [options.extras_require]
 ftp = aioftp
 test =


Test patch:
diff --git a/parfive/tests/test_main.py b/parfive/tests/test_main.py
new file mode 100644
index 0000000..bfcaeab
--- /dev/null
+++ b/parfive/tests/test_main.py
@@ -0,0 +1,38 @@
+from parfive.main import parse_args
+import pytest
+
+REQUIRED_ARGUMENTS = ['test_url']
+
+def test_no_url():
+    with pytest.raises(SystemExit):
+        args = parse_args(['--overwrite'])
+
+
+def helper(args, name, expected):
+    args = parse_args(REQUIRED_ARGUMENTS + args)
+    assert getattr(args, name) == expected
+
+
+def test_overwrite():
+    helper(['--overwrite'], 'overwrite', True)
+    helper([], 'overwrite', False)
+
+
+def test_max_conn():
+    helper(['--max-conn', '10'], 'max_conn', 10)
+    helper([], 'max_conn', 5)
+
+
+def test_no_file_progress():
+    helper(['--no-file-progress'], 'no_file_progress', True)
+    helper([], 'no_file_progress', False)
+
+
+def test_print_filenames():
+    helper(['--print-filenames'], 'print_filenames', True)
+    helper([], 'print_filenames', False)
+
+def test_directory():
+    helper(['--directory', '/tmp'], 'directory', '/tmp')
+    helper([], 'directory', './')
+