Repository: AgnostiqHQ/covalent (python)

Issue:
S3 file transfer strategy upload/download file path bug
### Environment

- **Covalent version**: 0.198.0
- **Python version**: 3.8.13
- **Operating system**: MacOS


### What is happening?

The upload "to file path" and the download "from file path" in the file transfer with the S3 strategy is broken.

When it comes to downloading, the presence of a backslash because the "from file path" (/train.csv) is not decomposed properly from the `s3://covalent-batch-job-resources/train.csv`. this gives the following error:

```
botocore.exceptions.ClientError: An error occurred (404) when calling the HeadObject operation: Not Found
```

When it comes to uploading, the presence of a backslash, first creates a directory in the s3 before uploading the file.

### How can we reproduce the issue?

Start by uploading the test/train csv files in the s3 bucket and creating a csv file test_v2 locally in datasets folder.

```
import covalent as ct
import pandas as pd

remote_train_file = ct.fs.File('s3://covalent-batch-job-resources/train.csv')
remote_test_file = ct.fs.File('s3://covalent-batch-job-resources/test.csv')
local_train_file = ct.fs.File('/home/user/datasets/train.csv')
local_test_file = ct.fs.File('/home/user/datasets/test.csv')

local_test_file_v2 = ct.fs.File('/home/user/datasets/test_v2.csv')
remote_test_file_v2 = ct.fs.File('s3://covalent-batch-job-resources/test_v2.csv')

strategy = ct.fs_strategies.S3(
    credentials='/home/user/.aws/credentials', 
    profile='default', 
    region_name = 'us-east-1')

@ct.electron(
    files=[
        ct.fs.FileTransfer(remote_train_file, local_train_file, strategy=strategy, order=ct.fs.Order.BEFORE),
        ct.fs.FileTransfer(remote_test_file, local_test_file, strategy=strategy, order=ct.fs.Order.BEFORE),
        ct.fs.FileTransfer(local_test_file_v2, remote_test_file_v2, strategy=strategy, order=ct.fs.Order.AFTER)
    ]
)
def fetch_and_validate_data(files=[]):
    _, local_train = files[0]
    _, local_test = files[1]
    train = pd.read_csv(local_train, parse_dates=['date'])
    test = pd.read_csv(local_test, parse_dates=['date'])
    return train, test

@ct.lattice
def compare_models():
    # Fetch and validate source data
    train, test = fetch_and_validate_data()
    return train, test

dispatch_id = ct.dispatch(compare_models)()
```

Check the local file directory and the s3 buckets after running this code as well as the covalent logs to see all the relevant issues mentioned above.

### What should happen?

When the code is working properly, the test and train csv files will be downloaded without any errors and the test_v2 file will be uploaded in the appropriate directory.

### Any suggestions?

A possibly incomplete fix could be to change `from_filepath = from_file.filepath` to `from_filepath = os.path.basename(from_file.filepath)` in the download method and a similar change for the to_filepath in the upload method.



Pull request:
Fix s3 file transfer path
Fixes #1276 

<!--
⚠️ Your pull request title should be short detailed and understandable for all.
⚠️ Increment the version number in the /VERSION file. If this is a bugfix, increment the patch version (the rightmost number), for example 0.18.2 becomes 0.18.3. If it's a new feature, increment the minor version (the middle number), for example 0.18.2 becomes 0.19.0.
⚠️ Add a note to /CHANGELOG.md with your version number and the date, summarizing the changes.
⚠️ If your pull request fixes an open issue, please link to the issue.
⚠️ Rebase the latest changes from the develop branch. Assuming origin points to https://github.com/AgnostiqHQ/covalent, you should run git rebase origin/develop.
-->

- [x] I have added the tests to cover my changes.
- [x] I have updated the documentation and CHANGELOG accordingly.
- [x] I have read the CONTRIBUTING document.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 83497540..864fb9af 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 - Config file is now locked during reads and writes to mitigate concurrency issues
 - In `defaults.py/get_default_executor`, condition to return `local` or `dask` is now fixed
+- Strip "/" from the S3 bucket download "from file path" and the upload "to file path"
 - Correctly return stderr in get_node_result
 
 ### Changed
diff --git a/covalent/_file_transfer/strategies/s3_strategy.py b/covalent/_file_transfer/strategies/s3_strategy.py
index 21309405..37ed92bc 100644
--- a/covalent/_file_transfer/strategies/s3_strategy.py
+++ b/covalent/_file_transfer/strategies/s3_strategy.py
@@ -22,9 +22,13 @@ import os
 
 from furl import furl
 
+from ..._shared_files import logger
 from .. import File
 from .transfer_strategy_base import FileTransferStrategy
 
+app_log = logger.app_log
+log_stack_info = logger.log_stack_info
+
 
 class S3(FileTransferStrategy):
 
@@ -65,9 +69,12 @@ class S3(FileTransferStrategy):
 
     # return callable to download here implies 'from' is a remote source
     def download(self, from_file: File, to_file: File = File()) -> File:
-        from_filepath = from_file.filepath
+        from_filepath = from_file.filepath.strip("/")
         to_filepath = to_file.filepath
         bucket_name = furl(from_file.uri).origin[5:]
+        app_log.debug(
+            f"S3 download bucket: {bucket_name}, from_filepath: {from_filepath}, to_filepath {to_filepath}."
+        )
 
         def callable():
             import boto3
@@ -84,8 +91,11 @@ class S3(FileTransferStrategy):
     def upload(self, from_file: File, to_file: File = File()) -> File:
 
         from_filepath = from_file.filepath
-        to_filepath = to_file.filepath
+        to_filepath = to_file.filepath.strip("/")
         bucket_name = furl(to_file.uri).origin[5:]
+        app_log.debug(
+            f"S3 download bucket: {bucket_name}, from_filepath: {from_filepath}, to_filepath {to_filepath}."
+        )
 
         def callable():
             import boto3


Test patch:
diff --git a/tests/covalent_tests/file_transfer/strategies/s3_strategy_test.py b/tests/covalent_tests/file_transfer/strategies/s3_strategy_test.py
index 596298ff..02644ea2 100644
--- a/tests/covalent_tests/file_transfer/strategies/s3_strategy_test.py
+++ b/tests/covalent_tests/file_transfer/strategies/s3_strategy_test.py
@@ -54,7 +54,7 @@ class TestS3Strategy:
         S3().download(from_file, to_file)()
 
         boto3_client_mock().download_file.assert_called_with(
-            bucket_name, from_file.filepath, to_file.filepath
+            bucket_name, from_file.filepath.strip("/"), to_file.filepath
         )
 
     def test_upload(self, mocker):
@@ -74,7 +74,7 @@ class TestS3Strategy:
         S3().upload(from_file, to_file)()
 
         boto3_client_mock().upload_file.assert_called_with(
-            from_file.filepath, bucket_name, to_file.filepath
+            from_file.filepath, bucket_name, to_file.filepath.strip("/")
         )
 
     def test_cp_failure(self, mocker):