From 89e51f99f6371093e60120c43f9c48ea0eadfd19 Mon Sep 17 00:00:00 2001
From: szymekc <szymekc98@gmail.com>
Date: Mon, 7 Feb 2022 12:16:24 +0100
Subject: [PATCH 1/4] added download as dict, filename specification, fixed
 progress bar

---
 lpmn_client/__init__.py     |  4 +++-
 lpmn_client/__main__.py     | 10 ++++++--
 lpmn_client/file_handler.py | 47 +++++++++++++++++++++++++++++++++----
 lpmn_client/task.py         |  2 +-
 setup.py                    |  2 +-
 5 files changed, 56 insertions(+), 9 deletions(-)

diff --git a/lpmn_client/__init__.py b/lpmn_client/__init__.py
index a3d9ab9..e2be96c 100644
--- a/lpmn_client/__init__.py
+++ b/lpmn_client/__init__.py
@@ -1,7 +1,8 @@
 from .config import Config
 from .file_handler import (
     upload_file,
-    download_file
+    download_file,
+    download_file_as_dict
 )
 from .task import Task
 
@@ -11,4 +12,5 @@ __all__ = [
     "Task",
     "upload_file",
     "download_file",
+    "download_file_as_dict"
 ]
diff --git a/lpmn_client/__main__.py b/lpmn_client/__main__.py
index 7d98868..a1cdf6f 100644
--- a/lpmn_client/__main__.py
+++ b/lpmn_client/__main__.py
@@ -25,7 +25,13 @@ def get_args():
     parser.add_argument(
         "-o",
         "--output",
-        help="Path to a output file on local machine."
+        help="Path to a output directory on local machine."
+    )
+    parser.add_argument(
+        "-f",
+        "--filename",
+        help="Downloaded file name.",
+        default=None
     )
     parser.add_argument(
         "lpmn",
@@ -40,7 +46,7 @@ def main():
     file_id = upload_file(file_path=args.input)
     t = Task(args.lpmn)
     output_file_id = t.run(file_id=file_id, verbose=args.verbose, timeout=0)
-    downloaded = download_file(file_id=output_file_id, output_path=args.output)
+    downloaded = download_file(file_id=output_file_id, output_path=args.output, filename=args.filename)
     print(f"Result saved to {downloaded}")
 
 
diff --git a/lpmn_client/file_handler.py b/lpmn_client/file_handler.py
index 8db30b0..21b309d 100644
--- a/lpmn_client/file_handler.py
+++ b/lpmn_client/file_handler.py
@@ -60,15 +60,18 @@ def upload_file(file_path: str) -> FileID:
 
 def download_file(
     file_id: FileID,
-    output_path: tp.Optional[str] = None
+    output_path: tp.Optional[str] = None,
+    filename: tp.Optional[str] = None
 ) -> str:
     """Downloads file by its FileID.
 
     Args:
         file_id (FileID): File id of a file to download
-        path (Optional[str]): Path for downloaded file.
+        output_path (Optional[str]): Directory to save downloaded file in.
             If not given the file will be saved in default location
             (config.ini).
+        filename (Optional[str]): Output filename without .zip format.
+            If not specified, filename is random.
     Returns:
         str. A path to downloaded file.
 
@@ -76,8 +79,8 @@ def download_file(
     response = requests.get(url=f"{Config.get('base_url')}/download{file_id}")
     if response.status_code == 404 or response.status_code == 500:
         raise FileNotFoundError("File not found")
-
-    filename = file_id.split("/")[-1] + ".zip"
+    if not filename:
+        filename = f"{file_id.split('/')[-1]}.zip"
     if not output_path:
         output_path = Config.get("output_path")
     os.makedirs(output_path, exist_ok=True)
@@ -86,3 +89,39 @@ def download_file(
     with open(output_path, "wb") as f:
         f.write(response.content)
     return output_path
+
+
+def download_file_as_dict(
+    file_id: FileID,
+) -> tp.Dict[str, str]:
+    """Downloads file by its FileID.
+
+    Args:
+        file_id (FileID): File id of a file to download
+
+    Returns:
+        dict. Dictionary mapping filenames in output zipfile to file contents.
+
+    """
+    def try_decode(file):
+        try:
+            file.decode("utf-8")
+            return True
+        except UnicodeDecodeError:
+            return False
+
+    response = requests.get(url=f"{Config.get('base_url')}/download{file_id}")
+    if response.status_code == 404 or response.status_code == 500:
+        raise FileNotFoundError("File not found")
+
+    zip_buffer = io.BytesIO(initial_bytes=response.content)
+    with zipfile.ZipFile(
+        zip_buffer,
+        mode="r",
+        compression=zipfile.ZIP_DEFLATED,
+    ) as zip_file:
+        return {i.filename: zip_file.open(i).read().decode("utf-8")
+                for i in filter(
+                lambda x: try_decode(zip_file.open(x).read())
+                    and x.filename[-1] != '/',
+                zip_file.infolist())}
diff --git a/lpmn_client/task.py b/lpmn_client/task.py
index 36be732..24dfa1e 100644
--- a/lpmn_client/task.py
+++ b/lpmn_client/task.py
@@ -103,7 +103,7 @@ class Task(object):
             time.sleep(0.5)
             progress = self.get_progress()
             if pbar:
-                pbar.update(progress * 100)
+                pbar.update(progress * 100 - pbar.n)
 
         if pbar:
             pbar.update(100)
diff --git a/setup.py b/setup.py
index 02a6da2..e31b207 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@ with open("README.md", "r") as fh:
 
 setuptools.setup(
     name="lpmn_client",
-    version="1.4.3",
+    version="1.4.4",
     author="Szymon Ciombor, Mateusz Gniewkowski",
     author_email="Szymon.Ciombor@pwr.edu.pl, mateusz.gniewkowski@pwr.edu.pl",
     description="Client for writing LPMN queries.",
-- 
GitLab


From 4e5953aa7a3edcf3e7f445a4342b8633af26140f Mon Sep 17 00:00:00 2001
From: szymekc <szymekc98@gmail.com>
Date: Mon, 7 Feb 2022 12:18:07 +0100
Subject: [PATCH 2/4] pep8

---
 lpmn_client/__main__.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/lpmn_client/__main__.py b/lpmn_client/__main__.py
index a1cdf6f..c425b30 100644
--- a/lpmn_client/__main__.py
+++ b/lpmn_client/__main__.py
@@ -46,7 +46,9 @@ def main():
     file_id = upload_file(file_path=args.input)
     t = Task(args.lpmn)
     output_file_id = t.run(file_id=file_id, verbose=args.verbose, timeout=0)
-    downloaded = download_file(file_id=output_file_id, output_path=args.output, filename=args.filename)
+    downloaded = download_file(file_id=output_file_id,
+                               output_path=args.output,
+                               filename=args.filename)
     print(f"Result saved to {downloaded}")
 
 
-- 
GitLab


From 4c4d6ab05d6e5cb7584fa3ae9e939ab26621b0c6 Mon Sep 17 00:00:00 2001
From: szymekc <szymekc98@gmail.com>
Date: Mon, 7 Feb 2022 12:43:29 +0100
Subject: [PATCH 3/4] is_dir() check

---
 lpmn_client/file_handler.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lpmn_client/file_handler.py b/lpmn_client/file_handler.py
index 21b309d..5fce077 100644
--- a/lpmn_client/file_handler.py
+++ b/lpmn_client/file_handler.py
@@ -123,5 +123,5 @@ def download_file_as_dict(
         return {i.filename: zip_file.open(i).read().decode("utf-8")
                 for i in filter(
                 lambda x: try_decode(zip_file.open(x).read())
-                    and x.filename[-1] != '/',
+                    and not x.is_dir(),
                 zip_file.infolist())}
-- 
GitLab


From 67f8351de99d16d4bf52aef7889de848e23f6b23 Mon Sep 17 00:00:00 2001
From: szymekc <szymekc98@gmail.com>
Date: Tue, 8 Feb 2022 14:20:56 +0100
Subject: [PATCH 4/4] added test_download_file_as_dict, fixed indentation and
 pbar update

---
 lpmn_client/__main__.py     |  8 +++++---
 lpmn_client/file_handler.py | 17 ++++++++++-------
 lpmn_client/task.py         |  2 +-
 tests/lpmn_test.py          | 11 ++++++++++-
 4 files changed, 26 insertions(+), 12 deletions(-)

diff --git a/lpmn_client/__main__.py b/lpmn_client/__main__.py
index c425b30..6bfee0b 100644
--- a/lpmn_client/__main__.py
+++ b/lpmn_client/__main__.py
@@ -46,9 +46,11 @@ def main():
     file_id = upload_file(file_path=args.input)
     t = Task(args.lpmn)
     output_file_id = t.run(file_id=file_id, verbose=args.verbose, timeout=0)
-    downloaded = download_file(file_id=output_file_id,
-                               output_path=args.output,
-                               filename=args.filename)
+    downloaded = download_file(
+        file_id=output_file_id,
+        output_path=args.output,
+        filename=args.filename
+    )
     print(f"Result saved to {downloaded}")
 
 
diff --git a/lpmn_client/file_handler.py b/lpmn_client/file_handler.py
index 5fce077..96baaa7 100644
--- a/lpmn_client/file_handler.py
+++ b/lpmn_client/file_handler.py
@@ -103,9 +103,9 @@ def download_file_as_dict(
         dict. Dictionary mapping filenames in output zipfile to file contents.
 
     """
-    def try_decode(file):
+    def try_decode(bytes_data):
         try:
-            file.decode("utf-8")
+            bytes_data.decode("utf-8")
             return True
         except UnicodeDecodeError:
             return False
@@ -120,8 +120,11 @@ def download_file_as_dict(
         mode="r",
         compression=zipfile.ZIP_DEFLATED,
     ) as zip_file:
-        return {i.filename: zip_file.open(i).read().decode("utf-8")
-                for i in filter(
-                lambda x: try_decode(zip_file.open(x).read())
-                    and not x.is_dir(),
-                zip_file.infolist())}
+        return {
+            i.filename: zip_file.open(i).read().decode("utf-8")
+            for i in filter(
+                lambda x:
+                    try_decode(zip_file.read(x)) and not x.is_dir(),
+                zip_file.infolist()
+            )
+        }
diff --git a/lpmn_client/task.py b/lpmn_client/task.py
index 24dfa1e..1344380 100644
--- a/lpmn_client/task.py
+++ b/lpmn_client/task.py
@@ -106,7 +106,7 @@ class Task(object):
                 pbar.update(progress * 100 - pbar.n)
 
         if pbar:
-            pbar.update(100)
+            pbar.update(100 - pbar.n)
         self.status = "done"
 
     def run(
diff --git a/tests/lpmn_test.py b/tests/lpmn_test.py
index 050d857..763b4cf 100644
--- a/tests/lpmn_test.py
+++ b/tests/lpmn_test.py
@@ -3,7 +3,7 @@ import os
 import pytest
 import shutil
 
-from lpmn_client import download_file, upload_file
+from lpmn_client import download_file, download_file_as_dict, upload_file
 from lpmn_client import Task
 
 
@@ -37,6 +37,15 @@ class TestLPMN(object):
         path = download_file(file_id, output_path="./out_test")
         assert os.path.isfile(path)
 
+    @pytest.mark.parametrize(
+        "file_id", ["uploaded_file", "uploaded_dir", "uploaded_zip"]
+    )
+    def test_download_file_as_dict(self, file_id, request):
+        """Test downloading of uploaded files as dicts."""
+        file_id = request.getfixturevalue(file_id)
+        data = download_file_as_dict(file_id)
+        assert len(data) > 0
+
     @pytest.mark.parametrize(
         "file_id", ["uploaded_file", "uploaded_dir", "uploaded_zip"]
     )
-- 
GitLab