You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by GitBox <gi...@apache.org> on 2021/07/03 14:19:32 UTC

[GitHub] [airflow] AngryHelper opened a new pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

AngryHelper opened a new pull request #16792:
URL: https://github.com/apache/airflow/pull/16792


   closes: AIRFLOW-5703
   
   Added next features: transfer list of files, transfer directory, transfer files on regex pattern  in directories.
   ![image](https://user-images.githubusercontent.com/86562687/124356884-4c799500-dc21-11eb-9277-06038473aba9.png)
   
   <details>
   <summary>I writen next dag for tests</summary>
   
   ```
   from airflow.utils.edgemodifier import Label
   
   from airflow.operators.bash import BashOperator
   
   from airflow import DAG
   from airflow.providers.sftp.operators.sftp import SFTPOperator, SFTPOperation
   from airflow.providers.ssh.operators.ssh import SSHOperator
   from airflow.utils.dates import days_ago
   
   with DAG(
       dag_id="test_stfp",
       schedule_interval="@once",
       start_date=days_ago(1),
       max_active_runs=1
   ) as dag:
       create_test_files = BashOperator(
           task_id="create_test_files",
           bash_command="""
           touch /tmp/file.txt & echo "transfer data from local" >> /tmp/file.txt &
           touch /tmp/file1.txt & echo "transfer data from local" >> /tmp/file1.txt &
           touch /tmp/file2.txt & echo "transfer data from local" >> /tmp/file2.txt &
           touch /tmp/file3.txt & echo "transfer data from local" >> /tmp/file3.txt &
           mkdir /tmp/dir_for_remote_transfer &
           touch /tmp/dir_for_remote_transfer/file2.txt &
           touch /tmp/dir_for_remote_transfer/file3.csv &
           ls /tmp """
       )
   
       put_file = SFTPOperator(
           task_id="put_file",
           ssh_conn_id="ssh_default",
           local_filepath="/tmp/file.txt",
           remote_filepath="/tmp/tmp1/tmp2/file.txt",
           operation=SFTPOperation.PUT,
           create_intermediate_dirs=True
       )
   
       put_file_without_full_remote_path = SFTPOperator(
           task_id="put_file_without_full_remote_path",
           ssh_conn_id="ssh_default",
           local_filepath="/tmp/file3.txt",
           remote_filepath="/tmp/tmp1/tmp2/",
           operation=SFTPOperation.PUT,
           create_intermediate_dirs=True
       )
   
       put_dir_txt_files = SFTPOperator(
           task_id="put_dir_txt_files",
           ssh_conn_id="ssh_default",
           local_folder="/tmp/dir_for_remote_transfer/",
           remote_folder="/tmp/dir_for_remote_transfer/txt",
           regexp_mask=".*.txt",
           operation=SFTPOperation.PUT,
           create_intermediate_dirs=True
       )
   
       put_dir_csv_files = SFTPOperator(
           task_id="put_dir_csv_files",
           ssh_conn_id="ssh_default",
           local_folder="/tmp/dir_for_remote_transfer/",
           remote_folder="/tmp/dir_for_remote_transfer/csv/",
           regexp_mask=".*.csv",
           operation=SFTPOperation.PUT,
           create_intermediate_dirs=True
       )
   
       put_files = SFTPOperator(
           task_id="put_files",
           ssh_conn_id="ssh_default",
           local_filepath=["/tmp/file1.txt", "/tmp/file2.txt"],
           remote_filepath="/tmp/tmp1/tmp2/",
           operation=SFTPOperation.PUT,
           create_intermediate_dirs=True
       )
   
       drop_local_test_files = BashOperator(
           task_id="drop_local_test_files",
           bash_command="""rm -rf /tmp/file* & rm -rf  /tmp/dir_for_remote_transfer/ & ls /tmp/"""
       )
   
       get_file = SFTPOperator(
           task_id="get_file",
           ssh_conn_id="ssh_default",
           local_filepath="/tmp/file.txt",
           remote_filepath="/tmp/tmp1/tmp2/file.txt",
           operation=SFTPOperation.GET,
           create_intermediate_dirs=True
       )
   
       get_files = SFTPOperator(
           task_id="get_files",
           ssh_conn_id="ssh_default",
           local_filepath="/tmp/",
           remote_filepath=["/tmp/tmp1/tmp2/file1.txt", "/tmp/tmp1/tmp2/file2.txt"],
           operation=SFTPOperation.GET,
           create_intermediate_dirs=True
       )
   
       get_dir = SFTPOperator(
           task_id="get_dir",
           ssh_conn_id="ssh_default",
           local_folder="/tmp/dir_for_remote_transfer/csv",
           remote_folder="/tmp/dir_for_remote_transfer/csv",
           operation=SFTPOperation.GET,
           create_intermediate_dirs=True
       )
   
       drop_remote_files = SSHOperator(
           task_id="drop_remote_files",
           ssh_conn_id="ssh_default",
           command="rm -rf /tmp/tmp1 & ls /tmp/"
       )
   
       create_test_files >> Label("transfer data to remote server") >> \
       [put_file, put_files, put_file_without_full_remote_path, put_dir_txt_files, put_dir_csv_files] >> \
       drop_local_test_files >> Label("transfer data to local server") >> \
       [get_file, get_files, get_dir] >> drop_remote_files
   ```
   
   </details>
   
   
   <details>
   <summary>Pre-commit Tests</summary>
   
   ```
   ubuntu@ubuntu-advanced-8-16-10gb:~/airflow$ pre-commit run  --files airflow/providers/sftp/operators/sftp.py
   identity.................................................................................Passed
   - hook id: identity
   - duration: 0.04s
   
   airflow/providers/sftp/operators/sftp.py
   
   Check hooks apply to the repository..................................(no files to check)Skipped
   No-tabs checker..........................................................................Passed
   Add license for all SQL files........................................(no files to check)Skipped
   Add license for all other files......................................(no files to check)Skipped
   Add license for all rst files........................................(no files to check)Skipped
   Add license for all JS/TS/TSX/CSS/PUML files.........................(no files to check)Skipped
   Add license for all JINJA template files.............................(no files to check)Skipped
   Add license for all shell files......................................(no files to check)Skipped
   Add license for all Python files.........................................................Passed
   Add license for all XML files........................................(no files to check)Skipped
   Add license for all YAML files.......................................(no files to check)Skipped
   Add license for all md files.........................................(no files to check)Skipped
   Add license for all mermaid files....................................(no files to check)Skipped
   Add TOC for md files.................................................(no files to check)Skipped
   black....................................................................................Passed
   blacken-docs.............................................................................Passed
   Check for merge conflicts................................................................Passed
   Debug Statements (Python)................................................................Passed
   Check builtin type constructor use.......................................................Passed
   Detect Private Key.......................................................................Passed
   Fix End of Files.........................................................................Passed
   Mixed line ending........................................................................Passed
   Check that executables have shebangs.................................(no files to check)Skipped
   Check Xml............................................................(no files to check)Skipped
   Trim Trailing Whitespace.................................................................Passed
   Fix python encoding pragma...............................................................Passed
   Pretty format JSON...................................................(no files to check)Skipped
   pyupgrade................................................................................Passed
   rst ``code`` is two backticks........................................(no files to check)Skipped
   use logger.warning(......................................................................Passed
   Check YAML files with yamllint.......................................(no files to check)Skipped
   Run isort to sort imports in Python files................................................Passed
   Run pydocstyle...........................................................................Passed
   Strip unnecessary `# noqa`s..............................................................Passed
   Lint OpenAPI using spectral..........................................(no files to check)Skipped
   Lint OpenAPI using openapi-spec-validator............................(no files to check)Skipped
   Lint dockerfile......................................................(no files to check)Skipped
   Check order of dependencies in setup.cfg and setup.py................(no files to check)Skipped
   Checks setup extra packages..........................................(no files to check)Skipped
   Update output of breeze command in BREEZE.rst........................(no files to check)Skipped
   Update mounts in the local yml file..................................(no files to check)Skipped
   Update setup.cfg file with all licenses..............................(no files to check)Skipped
   Build cross-dependencies for providers packages..........................................Passed
   Update extras in documentation.......................................(no files to check)Skipped
   Check for pydevd debug statements accidentally left......................................Passed
   Don't use safe in templates..........................................(no files to check)Skipped
   No providers imports in core example DAGs............................(no files to check)Skipped
   No relative imports......................................................................Passed
   Check for language that we do not accept as community....................................Passed
   Check BaseOperator[Link] core imports................................(no files to check)Skipped
   Check BaseOperator[Link] other imports...................................................Passed
   Check provide_session and create_session imports.........................................Passed
   Make sure LoggingMixin is not used alone.................................................Passed
   Make sure days_ago is imported from airflow.utils.dates..................................Passed
   'start_date' should not be defined in default_args in example_dags...(no files to check)Skipped
   Check if integration list is aligned.................................(no files to check)Skipped
   Check if licenses are OK for Apache..................................(no files to check)Skipped
   Checks for consistency between config.yml and default_config.cfg.....(no files to check)Skipped
   Verify that DB Migrations have been documented.......................(no files to check)Skipped
   Checks for Boring Cyborg configuration consistency.......................................Passed
   Sort INTHEWILD.md alphabetically.....................................(no files to check)Skipped
   Sort alphabetically and uniquify spelling_wordlist.txt...............(no files to check)Skipped
   Lint Helm Chart......................................................(no files to check)Skipped
   Check Shell scripts syntax correctness...............................(no files to check)Skipped
   Run BATS bash tests for changed Breeze bash files....................(no files to check)Skipped
   Run BATS bash tests for changed bash files...........................(no files to check)Skipped
   stylelint............................................................(no files to check)Skipped
   Provider init file.......................................................................Passed
   Validate providers.yaml files........................................(no files to check)Skipped
   Generate mermaid images..............................................(no files to check)Skipped
   Check if pre-commits are described...................................(no files to check)Skipped
   Ensure hook ids are not overly long..................................(no files to check)Skipped
   Checks providers available when declared by extras in setup.py...........................Passed
   Run markdownlint.....................................................(no files to check)Skipped
   Lint JSON Schema files with JSON Schema..............................(no files to check)Skipped
   Lint NodePort Service with JSON Schema...............................(no files to check)Skipped
   Lint Docker compose files with JSON Schema...........................(no files to check)Skipped
   Lint chart/values.schema.json file with JSON Schema..................(no files to check)Skipped
   Lint chart/values.yaml file with JSON Schema.........................(no files to check)Skipped
   Lint airflow/config_templates/config.yml file with JSON Schema.......(no files to check)Skipped
   Convert to f-strings with flynt..........................................................Passed
   ESLint against airflow/ui............................................(no files to check)Skipped
   ESLint against current UI js files...................................(no files to check)Skipped
   Check if image build is needed...........................................................Passed
   Run in container bats tests..........................................(no files to check)Skipped
   Run mypy.................................................................................Passed
   Run mypy for helm chart tests........................................(no files to check)Skipped
   Run mypy for /docs/ folder...........................................(no files to check)Skipped
   Run flake8...............................................................................Passed
   ```
   
   </details>
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [airflow] uranusjr commented on a change in pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

Posted by GitBox <gi...@apache.org>.
uranusjr commented on a change in pull request #16792:
URL: https://github.com/apache/airflow/pull/16792#discussion_r663497737



##########
File path: airflow/providers/sftp/operators/sftp.py
##########
@@ -134,29 +176,68 @@ def execute(self, context: Any) -> str:
 
             with self.ssh_hook.get_conn() as ssh_client:
                 sftp_client = ssh_client.open_sftp()
-                if self.operation.lower() == SFTPOperation.GET:
-                    local_folder = os.path.dirname(self.local_filepath)
-                    if self.create_intermediate_dirs:
-                        Path(local_folder).mkdir(parents=True, exist_ok=True)
-                    file_msg = f"from {self.remote_filepath} to {self.local_filepath}"
-                    self.log.info("Starting to transfer %s", file_msg)
-                    sftp_client.get(self.remote_filepath, self.local_filepath)
+                if self.local_filepath and self.remote_filepath:
+                    if isinstance(self.local_filepath, list) and isinstance(self.remote_filepath, str):
+                        for file_path in self.local_filepath:
+                            local_folder = os.path.dirname(file_path)
+                            remote_folder = os.path.dirname(self.remote_filepath)
+                            local_file = ntpath.basename(file_path)

Review comment:
       Why `ntpath` specifically, and only this function?




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [airflow] AngryHelper commented on pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

Posted by GitBox <gi...@apache.org>.
AngryHelper commented on pull request #16792:
URL: https://github.com/apache/airflow/pull/16792#issuecomment-908647425


   sorry for flood, I want create another PR with true commits


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [airflow] potiuk commented on a change in pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

Posted by GitBox <gi...@apache.org>.
potiuk commented on a change in pull request #16792:
URL: https://github.com/apache/airflow/pull/16792#discussion_r671712201



##########
File path: airflow/providers/sftp/operators/sftp.py
##########
@@ -134,29 +176,68 @@ def execute(self, context: Any) -> str:
 
             with self.ssh_hook.get_conn() as ssh_client:
                 sftp_client = ssh_client.open_sftp()
-                if self.operation.lower() == SFTPOperation.GET:
-                    local_folder = os.path.dirname(self.local_filepath)
-                    if self.create_intermediate_dirs:
-                        Path(local_folder).mkdir(parents=True, exist_ok=True)
-                    file_msg = f"from {self.remote_filepath} to {self.local_filepath}"
-                    self.log.info("Starting to transfer %s", file_msg)
-                    sftp_client.get(self.remote_filepath, self.local_filepath)
+                if self.local_filepath and self.remote_filepath:
+                    if isinstance(self.local_filepath, list) and isinstance(self.remote_filepath, str):
+                        for file_path in self.local_filepath:
+                            local_folder = os.path.dirname(file_path)
+                            remote_folder = os.path.dirname(self.remote_filepath)
+                            local_file = ntpath.basename(file_path)

Review comment:
       You have mistake in your second comparision (missing "txt" in second example) - that's why you have difference 




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [airflow] AngryHelper commented on a change in pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

Posted by GitBox <gi...@apache.org>.
AngryHelper commented on a change in pull request #16792:
URL: https://github.com/apache/airflow/pull/16792#discussion_r663529864



##########
File path: airflow/providers/sftp/operators/sftp.py
##########
@@ -134,29 +176,68 @@ def execute(self, context: Any) -> str:
 
             with self.ssh_hook.get_conn() as ssh_client:
                 sftp_client = ssh_client.open_sftp()
-                if self.operation.lower() == SFTPOperation.GET:
-                    local_folder = os.path.dirname(self.local_filepath)
-                    if self.create_intermediate_dirs:
-                        Path(local_folder).mkdir(parents=True, exist_ok=True)
-                    file_msg = f"from {self.remote_filepath} to {self.local_filepath}"
-                    self.log.info("Starting to transfer %s", file_msg)
-                    sftp_client.get(self.remote_filepath, self.local_filepath)
+                if self.local_filepath and self.remote_filepath:
+                    if isinstance(self.local_filepath, list) and isinstance(self.remote_filepath, str):
+                        for file_path in self.local_filepath:
+                            local_folder = os.path.dirname(file_path)
+                            remote_folder = os.path.dirname(self.remote_filepath)
+                            local_file = ntpath.basename(file_path)

Review comment:
       I needed to take the name of file from full path, this function was just right for this task :)




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [airflow] AngryHelper commented on pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

Posted by GitBox <gi...@apache.org>.
AngryHelper commented on pull request #16792:
URL: https://github.com/apache/airflow/pull/16792#issuecomment-907842770


   > Need to fix linter issues. See guide: https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst#contribution-workflow
   
   sorry for your waiting, I was solving the issue with my cloud provider. 
   I pushed fix about linter issues, you may see and pls run workflow, as I understand, I don`t have access for this


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [airflow] potiuk commented on pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

Posted by GitBox <gi...@apache.org>.
potiuk commented on pull request #16792:
URL: https://github.com/apache/airflow/pull/16792#issuecomment-908509451


   Can you please rebase to latest `main` @AngryHelper ? This will fix the failing image build, 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [airflow] AngryHelper commented on pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

Posted by GitBox <gi...@apache.org>.
AngryHelper commented on pull request #16792:
URL: https://github.com/apache/airflow/pull/16792#issuecomment-873417015


   > Also the DAG you wrote for tests is great to have an example dag in documentation. So I think it should be added too as a really nice documentation similarly as we have in other providers. It should not be difficult to add them.
   > 
   > You can take as an example the airbyte provider:
   > 
   > Example dag here for airbyte:
   > 
   > https://github.com/apache/airflow/tree/main/airflow/providers/airbyte/example_dags
   > 
   > And parts of the example dag are included in airbyte documentation:
   > 
   > https://github.com/apache/airflow/blob/main/docs/apache-airflow-providers-airbyte/operators/airbyte.rst
   > 
   > This way your example dag will become a guide for others :)
   
   thanks for the examples, I will definitely improve it!


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [airflow] AngryHelper commented on a change in pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

Posted by GitBox <gi...@apache.org>.
AngryHelper commented on a change in pull request #16792:
URL: https://github.com/apache/airflow/pull/16792#discussion_r671713104



##########
File path: airflow/providers/sftp/operators/sftp.py
##########
@@ -134,29 +176,68 @@ def execute(self, context: Any) -> str:
 
             with self.ssh_hook.get_conn() as ssh_client:
                 sftp_client = ssh_client.open_sftp()
-                if self.operation.lower() == SFTPOperation.GET:
-                    local_folder = os.path.dirname(self.local_filepath)
-                    if self.create_intermediate_dirs:
-                        Path(local_folder).mkdir(parents=True, exist_ok=True)
-                    file_msg = f"from {self.remote_filepath} to {self.local_filepath}"
-                    self.log.info("Starting to transfer %s", file_msg)
-                    sftp_client.get(self.remote_filepath, self.local_filepath)
+                if self.local_filepath and self.remote_filepath:
+                    if isinstance(self.local_filepath, list) and isinstance(self.remote_filepath, str):
+                        for file_path in self.local_filepath:
+                            local_folder = os.path.dirname(file_path)
+                            remote_folder = os.path.dirname(self.remote_filepath)
+                            local_file = ntpath.basename(file_path)

Review comment:
       you right, tnx




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [airflow] uranusjr commented on a change in pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

Posted by GitBox <gi...@apache.org>.
uranusjr commented on a change in pull request #16792:
URL: https://github.com/apache/airflow/pull/16792#discussion_r698291886



##########
File path: airflow/providers/sftp/operators/sftp.py
##########
@@ -134,29 +176,81 @@ def execute(self, context: Any) -> str:
 
             with self.ssh_hook.get_conn() as ssh_client:
                 sftp_client = ssh_client.open_sftp()
-                if self.operation.lower() == SFTPOperation.GET:
-                    local_folder = os.path.dirname(self.local_filepath)
-                    if self.create_intermediate_dirs:
-                        Path(local_folder).mkdir(parents=True, exist_ok=True)
-                    file_msg = f"from {self.remote_filepath} to {self.local_filepath}"
-                    self.log.info("Starting to transfer %s", file_msg)
-                    sftp_client.get(self.remote_filepath, self.local_filepath)
-                else:
-                    remote_folder = os.path.dirname(self.remote_filepath)
-                    if self.create_intermediate_dirs:
-                        _make_intermediate_dirs(
-                            sftp_client=sftp_client,
-                            remote_directory=remote_folder,
+                if self.local_filepath and self.remote_filepath:
+                    if isinstance(self.local_filepath, list) and isinstance(self.remote_filepath, str):
+                        for file_path in self.local_filepath:
+                            local_folder = os.path.dirname(file_path)
+                            local_file = os.path.basename(file_path)
+                            file_msg = file_path
+                            self._transfer(sftp_client, local_folder, local_file, self.remote_filepath)
+                    elif isinstance(self.remote_filepath, list) and isinstance(self.local_filepath, str):
+                        for file_path in self.remote_filepath:
+                            remote_folder = os.path.dirname(file_path)
+                            remote_file = os.path.basename(file_path)
+                            file_msg = file_path
+                            self._transfer(sftp_client, self.local_filepath, remote_file, remote_folder)
+                    elif isinstance(self.remote_filepath, str) and isinstance(self.local_filepath, str):
+                        local_folder = os.path.dirname(self.local_filepath)
+                        file_msg = self.local_filepath
+                        self._transfer(
+                            sftp_client,
+                            local_folder,
+                            self.local_filepath,
+                            self.remote_filepath,
+                            only_file=True,
                         )
-                    file_msg = f"from {self.local_filepath} to {self.remote_filepath}"
-                    self.log.info("Starting to transfer file %s", file_msg)
-                    sftp_client.put(self.local_filepath, self.remote_filepath, confirm=self.confirm)
+                elif self.local_folder and self.remote_folder:
+                    if self.operation.lower() == SFTPOperation.PUT:
+                        files_list = self._search_files(os.listdir(self.local_folder))
+                        for file in files_list:
+                            local_file = os.path.basename(file)
+                            file_msg = file
+                            self._transfer(sftp_client, self.local_folder, local_file, self.remote_folder)
+                    elif self.operation.lower() == SFTPOperation.GET:
+                        files_list = self._search_files(sftp_client.listdir(self.remote_folder))
+                        for file in files_list:
+                            remote_file = ntpath.basename(file)

Review comment:
       I think this should be `os.path.basename` like in the `PUT` block.

##########
File path: airflow/providers/sftp/operators/sftp.py
##########
@@ -88,6 +124,9 @@ def __init__(
         remote_host=None,
         local_filepath=None,
         remote_filepath=None,
+        local_folder=None,
+        remote_folder=None,
+        regexp_mask=None,

Review comment:
       I am really not fond of this argument list since it’s too easy to pass in nonsensical combinations e.g.
   
   ```python
   SFTPOperator(
       local_filepath="/my/file",
       local_folder="/my/dir",
   )
   ```
   
   But I understand this is not easy to change the arguments due to compatibility considerations.
   
   Perhapes what we should do is to introduce a separate operator (say `SFTPBatchOperator`) to handle the new feature, instead of bolting it onto the existing one.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [airflow] AngryHelper edited a comment on pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

Posted by GitBox <gi...@apache.org>.
AngryHelper edited a comment on pull request #16792:
URL: https://github.com/apache/airflow/pull/16792#issuecomment-907842770


   > Need to fix linter issues. See guide: https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst#contribution-workflow
   
   @uranusjr @potiuk  sorry for your waiting, I was solving the issue with my cloud provider. 
   I pushed fix about linter issues, you may see and pls run workflow, as I understand, I don`t have access for this


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [airflow] AngryHelper commented on a change in pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

Posted by GitBox <gi...@apache.org>.
AngryHelper commented on a change in pull request #16792:
URL: https://github.com/apache/airflow/pull/16792#discussion_r698559013



##########
File path: airflow/providers/sftp/operators/sftp.py
##########
@@ -88,6 +124,9 @@ def __init__(
         remote_host=None,
         local_filepath=None,
         remote_filepath=None,
+        local_folder=None,
+        remote_folder=None,
+        regexp_mask=None,

Review comment:
       for this case will print AirflowException with examples
   https://github.com/apache/airflow/pull/16792/files#diff-911f39c07d851bc2f0a2958674ed940ddc68aea6ecc7d71c29567816c182eaf6R216
   
   I checked the example of dag again, I am comfortable working with one operetor, even if he has combined arguments.
   
   Your idea i understand too, may be we will wait @potiuk and hear his opinion




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [airflow] potiuk commented on a change in pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

Posted by GitBox <gi...@apache.org>.
potiuk commented on a change in pull request #16792:
URL: https://github.com/apache/airflow/pull/16792#discussion_r671712201



##########
File path: airflow/providers/sftp/operators/sftp.py
##########
@@ -134,29 +176,68 @@ def execute(self, context: Any) -> str:
 
             with self.ssh_hook.get_conn() as ssh_client:
                 sftp_client = ssh_client.open_sftp()
-                if self.operation.lower() == SFTPOperation.GET:
-                    local_folder = os.path.dirname(self.local_filepath)
-                    if self.create_intermediate_dirs:
-                        Path(local_folder).mkdir(parents=True, exist_ok=True)
-                    file_msg = f"from {self.remote_filepath} to {self.local_filepath}"
-                    self.log.info("Starting to transfer %s", file_msg)
-                    sftp_client.get(self.remote_filepath, self.local_filepath)
+                if self.local_filepath and self.remote_filepath:
+                    if isinstance(self.local_filepath, list) and isinstance(self.remote_filepath, str):
+                        for file_path in self.local_filepath:
+                            local_folder = os.path.dirname(file_path)
+                            remote_folder = os.path.dirname(self.remote_filepath)
+                            local_file = ntpath.basename(file_path)

Review comment:
       You have mistake in your second comparision (missing "txt" in third example) - that's why you have difference 




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [airflow] AngryHelper commented on a change in pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

Posted by GitBox <gi...@apache.org>.
AngryHelper commented on a change in pull request #16792:
URL: https://github.com/apache/airflow/pull/16792#discussion_r671711913



##########
File path: airflow/providers/sftp/operators/sftp.py
##########
@@ -134,29 +176,68 @@ def execute(self, context: Any) -> str:
 
             with self.ssh_hook.get_conn() as ssh_client:
                 sftp_client = ssh_client.open_sftp()
-                if self.operation.lower() == SFTPOperation.GET:
-                    local_folder = os.path.dirname(self.local_filepath)
-                    if self.create_intermediate_dirs:
-                        Path(local_folder).mkdir(parents=True, exist_ok=True)
-                    file_msg = f"from {self.remote_filepath} to {self.local_filepath}"
-                    self.log.info("Starting to transfer %s", file_msg)
-                    sftp_client.get(self.remote_filepath, self.local_filepath)
+                if self.local_filepath and self.remote_filepath:
+                    if isinstance(self.local_filepath, list) and isinstance(self.remote_filepath, str):
+                        for file_path in self.local_filepath:
+                            local_folder = os.path.dirname(file_path)
+                            remote_folder = os.path.dirname(self.remote_filepath)
+                            local_file = ntpath.basename(file_path)

Review comment:
       ![image](https://user-images.githubusercontent.com/86562687/126042276-6861f2cd-ae0f-4b70-a5cc-74d4f5a25ceb.png)
   its difference between functions




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [airflow] potiuk commented on pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

Posted by GitBox <gi...@apache.org>.
potiuk commented on pull request #16792:
URL: https://github.com/apache/airflow/pull/16792#issuecomment-873416594


   Also the DAG you wrote for tests is great to have an example dag in documentation. So I think it should be added too as a really nice documentation similarly as we have in other providers. It should not be difficult to add them.
   
   You can take as an example the airbyte provider:
   
   Example dag here for airbyte:
   
   https://github.com/apache/airflow/tree/main/airflow/providers/airbyte/example_dags
   
   And parts of the example dag are included in airbyte documentation:
   
   https://github.com/apache/airflow/blob/main/docs/apache-airflow-providers-airbyte/operators/airbyte.rst
   
   This way your example dag will become a guide for others :)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [airflow] potiuk commented on pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

Posted by GitBox <gi...@apache.org>.
potiuk commented on pull request #16792:
URL: https://github.com/apache/airflow/pull/16792#issuecomment-908509451


   Can you please rebase to latest `main` @AngryHelper ? This will fix the failing image build, 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [airflow] AngryHelper commented on a change in pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

Posted by GitBox <gi...@apache.org>.
AngryHelper commented on a change in pull request #16792:
URL: https://github.com/apache/airflow/pull/16792#discussion_r698591513



##########
File path: airflow/providers/sftp/operators/sftp.py
##########
@@ -134,29 +176,81 @@ def execute(self, context: Any) -> str:
 
             with self.ssh_hook.get_conn() as ssh_client:
                 sftp_client = ssh_client.open_sftp()
-                if self.operation.lower() == SFTPOperation.GET:
-                    local_folder = os.path.dirname(self.local_filepath)
-                    if self.create_intermediate_dirs:
-                        Path(local_folder).mkdir(parents=True, exist_ok=True)
-                    file_msg = f"from {self.remote_filepath} to {self.local_filepath}"
-                    self.log.info("Starting to transfer %s", file_msg)
-                    sftp_client.get(self.remote_filepath, self.local_filepath)
-                else:
-                    remote_folder = os.path.dirname(self.remote_filepath)
-                    if self.create_intermediate_dirs:
-                        _make_intermediate_dirs(
-                            sftp_client=sftp_client,
-                            remote_directory=remote_folder,
+                if self.local_filepath and self.remote_filepath:
+                    if isinstance(self.local_filepath, list) and isinstance(self.remote_filepath, str):
+                        for file_path in self.local_filepath:
+                            local_folder = os.path.dirname(file_path)
+                            local_file = os.path.basename(file_path)
+                            file_msg = file_path
+                            self._transfer(sftp_client, local_folder, local_file, self.remote_filepath)
+                    elif isinstance(self.remote_filepath, list) and isinstance(self.local_filepath, str):
+                        for file_path in self.remote_filepath:
+                            remote_folder = os.path.dirname(file_path)
+                            remote_file = os.path.basename(file_path)
+                            file_msg = file_path
+                            self._transfer(sftp_client, self.local_filepath, remote_file, remote_folder)
+                    elif isinstance(self.remote_filepath, str) and isinstance(self.local_filepath, str):
+                        local_folder = os.path.dirname(self.local_filepath)
+                        file_msg = self.local_filepath
+                        self._transfer(
+                            sftp_client,
+                            local_folder,
+                            self.local_filepath,
+                            self.remote_filepath,
+                            only_file=True,
                         )
-                    file_msg = f"from {self.local_filepath} to {self.remote_filepath}"
-                    self.log.info("Starting to transfer file %s", file_msg)
-                    sftp_client.put(self.local_filepath, self.remote_filepath, confirm=self.confirm)
+                elif self.local_folder and self.remote_folder:
+                    if self.operation.lower() == SFTPOperation.PUT:
+                        files_list = self._search_files(os.listdir(self.local_folder))
+                        for file in files_list:
+                            local_file = os.path.basename(file)
+                            file_msg = file
+                            self._transfer(sftp_client, self.local_folder, local_file, self.remote_folder)
+                    elif self.operation.lower() == SFTPOperation.GET:
+                        files_list = self._search_files(sftp_client.listdir(self.remote_folder))
+                        for file in files_list:
+                            remote_file = ntpath.basename(file)

Review comment:
       yep, sorry, fixed




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [airflow] uranusjr commented on a change in pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

Posted by GitBox <gi...@apache.org>.
uranusjr commented on a change in pull request #16792:
URL: https://github.com/apache/airflow/pull/16792#discussion_r663567017



##########
File path: airflow/providers/sftp/operators/sftp.py
##########
@@ -134,29 +176,68 @@ def execute(self, context: Any) -> str:
 
             with self.ssh_hook.get_conn() as ssh_client:
                 sftp_client = ssh_client.open_sftp()
-                if self.operation.lower() == SFTPOperation.GET:
-                    local_folder = os.path.dirname(self.local_filepath)
-                    if self.create_intermediate_dirs:
-                        Path(local_folder).mkdir(parents=True, exist_ok=True)
-                    file_msg = f"from {self.remote_filepath} to {self.local_filepath}"
-                    self.log.info("Starting to transfer %s", file_msg)
-                    sftp_client.get(self.remote_filepath, self.local_filepath)
+                if self.local_filepath and self.remote_filepath:
+                    if isinstance(self.local_filepath, list) and isinstance(self.remote_filepath, str):
+                        for file_path in self.local_filepath:
+                            local_folder = os.path.dirname(file_path)
+                            remote_folder = os.path.dirname(self.remote_filepath)
+                            local_file = ntpath.basename(file_path)

Review comment:
       But why not `os.path.basename`? `ntpath` splits on backslashes (as it should) and that would cause issues on Linux (where ``\`` is a valid character in file name).




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [airflow] AngryHelper commented on a change in pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

Posted by GitBox <gi...@apache.org>.
AngryHelper commented on a change in pull request #16792:
URL: https://github.com/apache/airflow/pull/16792#discussion_r698559013



##########
File path: airflow/providers/sftp/operators/sftp.py
##########
@@ -88,6 +124,9 @@ def __init__(
         remote_host=None,
         local_filepath=None,
         remote_filepath=None,
+        local_folder=None,
+        remote_folder=None,
+        regexp_mask=None,

Review comment:
       for this case will print AirflowException with examples
   https://github.com/apache/airflow/pull/16792/files#diff-911f39c07d851bc2f0a2958674ed940ddc68aea6ecc7d71c29567816c182eaf6R216
   
   I checked the example of dag again, I am comfortable working with one operetor, even if he has combined arguments.
   
   Your idea i understand too, may be we will wait @potiuk and hear his opinion

##########
File path: airflow/providers/sftp/operators/sftp.py
##########
@@ -134,29 +176,81 @@ def execute(self, context: Any) -> str:
 
             with self.ssh_hook.get_conn() as ssh_client:
                 sftp_client = ssh_client.open_sftp()
-                if self.operation.lower() == SFTPOperation.GET:
-                    local_folder = os.path.dirname(self.local_filepath)
-                    if self.create_intermediate_dirs:
-                        Path(local_folder).mkdir(parents=True, exist_ok=True)
-                    file_msg = f"from {self.remote_filepath} to {self.local_filepath}"
-                    self.log.info("Starting to transfer %s", file_msg)
-                    sftp_client.get(self.remote_filepath, self.local_filepath)
-                else:
-                    remote_folder = os.path.dirname(self.remote_filepath)
-                    if self.create_intermediate_dirs:
-                        _make_intermediate_dirs(
-                            sftp_client=sftp_client,
-                            remote_directory=remote_folder,
+                if self.local_filepath and self.remote_filepath:
+                    if isinstance(self.local_filepath, list) and isinstance(self.remote_filepath, str):
+                        for file_path in self.local_filepath:
+                            local_folder = os.path.dirname(file_path)
+                            local_file = os.path.basename(file_path)
+                            file_msg = file_path
+                            self._transfer(sftp_client, local_folder, local_file, self.remote_filepath)
+                    elif isinstance(self.remote_filepath, list) and isinstance(self.local_filepath, str):
+                        for file_path in self.remote_filepath:
+                            remote_folder = os.path.dirname(file_path)
+                            remote_file = os.path.basename(file_path)
+                            file_msg = file_path
+                            self._transfer(sftp_client, self.local_filepath, remote_file, remote_folder)
+                    elif isinstance(self.remote_filepath, str) and isinstance(self.local_filepath, str):
+                        local_folder = os.path.dirname(self.local_filepath)
+                        file_msg = self.local_filepath
+                        self._transfer(
+                            sftp_client,
+                            local_folder,
+                            self.local_filepath,
+                            self.remote_filepath,
+                            only_file=True,
                         )
-                    file_msg = f"from {self.local_filepath} to {self.remote_filepath}"
-                    self.log.info("Starting to transfer file %s", file_msg)
-                    sftp_client.put(self.local_filepath, self.remote_filepath, confirm=self.confirm)
+                elif self.local_folder and self.remote_folder:
+                    if self.operation.lower() == SFTPOperation.PUT:
+                        files_list = self._search_files(os.listdir(self.local_folder))
+                        for file in files_list:
+                            local_file = os.path.basename(file)
+                            file_msg = file
+                            self._transfer(sftp_client, self.local_folder, local_file, self.remote_folder)
+                    elif self.operation.lower() == SFTPOperation.GET:
+                        files_list = self._search_files(sftp_client.listdir(self.remote_folder))
+                        for file in files_list:
+                            remote_file = ntpath.basename(file)

Review comment:
       yep, sorry, fixed




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [airflow] potiuk commented on pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

Posted by GitBox <gi...@apache.org>.
potiuk commented on pull request #16792:
URL: https://github.com/apache/airflow/pull/16792#issuecomment-873415902


   Seems like very useful set of functionality. Could you please add unit tests for those @AngryHelper ?


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [airflow] AngryHelper closed pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

Posted by GitBox <gi...@apache.org>.
AngryHelper closed pull request #16792:
URL: https://github.com/apache/airflow/pull/16792


   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [airflow] AngryHelper commented on pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

Posted by GitBox <gi...@apache.org>.
AngryHelper commented on pull request #16792:
URL: https://github.com/apache/airflow/pull/16792#issuecomment-908647425


   sorry for flood, I want create another PR with true commits


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [airflow] uranusjr commented on pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

Posted by GitBox <gi...@apache.org>.
uranusjr commented on pull request #16792:
URL: https://github.com/apache/airflow/pull/16792#issuecomment-890806062


   Need to fix linter issues. See guide: https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst#contribution-workflow


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [airflow] AngryHelper closed pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

Posted by GitBox <gi...@apache.org>.
AngryHelper closed pull request #16792:
URL: https://github.com/apache/airflow/pull/16792


   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [airflow] boring-cyborg[bot] commented on pull request #16792: [AIRFLOW-5703] SFTP Provider list of files and directories

Posted by GitBox <gi...@apache.org>.
boring-cyborg[bot] commented on pull request #16792:
URL: https://github.com/apache/airflow/pull/16792#issuecomment-873414449


   Congratulations on your first Pull Request and welcome to the Apache Airflow community! If you have any issues or are unsure about any anything please check our Contribution Guide (https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst)
   Here are some useful points:
   - Pay attention to the quality of your code (flake8, mypy and type annotations). Our [pre-commits]( https://github.com/apache/airflow/blob/main/STATIC_CODE_CHECKS.rst#prerequisites-for-pre-commit-hooks) will help you with that.
   - In case of a new feature add useful documentation (in docstrings or in `docs/` directory). Adding a new operator? Check this short [guide](https://github.com/apache/airflow/blob/main/docs/apache-airflow/howto/custom-operator.rst) Consider adding an example DAG that shows how users should use it.
   - Consider using [Breeze environment](https://github.com/apache/airflow/blob/main/BREEZE.rst) for testing locally, it’s a heavy docker but it ships with a working Airflow and a lot of integrations.
   - Be patient and persistent. It might take some time to get a review or get the final approval from Committers.
   - Please follow [ASF Code of Conduct](https://www.apache.org/foundation/policies/conduct) for all communication including (but not limited to) comments on Pull Requests, Mailing list and Slack.
   - Be sure to read the [Airflow Coding style]( https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst#coding-style-and-best-practices).
   Apache Airflow is a community-driven project and together we are making it better 🚀.
   In case of doubts contact the developers at:
   Mailing List: dev@airflow.apache.org
   Slack: https://s.apache.org/airflow-slack
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org