cloudos-cli 2.94.1__tar.gz → 2.95.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/PKG-INFO +22 -37
  2. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/README.md +21 -36
  3. cloudos_cli-2.95.1/cloudos_cli/_version.py +1 -0
  4. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/datasets/cli.py +13 -53
  5. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/interactive_session/link.py +19 -140
  6. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/jobs/cli.py +7 -2
  7. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/jobs/job.py +170 -44
  8. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli.egg-info/PKG-INFO +22 -37
  9. cloudos_cli-2.94.1/cloudos_cli/_version.py +0 -1
  10. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/LICENSE +0 -0
  11. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/__init__.py +0 -0
  12. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/__main__.py +0 -0
  13. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/bash/__init__.py +0 -0
  14. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/bash/cli.py +0 -0
  15. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/clos.py +0 -0
  16. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/configure/__init__.py +0 -0
  17. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/configure/cli.py +0 -0
  18. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/configure/configure.py +0 -0
  19. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/constants.py +0 -0
  20. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/cost/__init__.py +0 -0
  21. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/cost/cost.py +0 -0
  22. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/cromwell/__init__.py +0 -0
  23. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/cromwell/cli.py +0 -0
  24. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/datasets/__init__.py +0 -0
  25. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/datasets/datasets.py +0 -0
  26. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/import_wf/__init__.py +0 -0
  27. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/import_wf/import_wf.py +0 -0
  28. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/interactive_session/__init__.py +0 -0
  29. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/interactive_session/cli.py +0 -0
  30. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/interactive_session/interactive_session.py +0 -0
  31. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/jobs/__init__.py +0 -0
  32. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/logging/__init__.py +0 -0
  33. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/logging/logger.py +0 -0
  34. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/procurement/__init__.py +0 -0
  35. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/procurement/cli.py +0 -0
  36. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/procurement/images.py +0 -0
  37. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/projects/__init__.py +0 -0
  38. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/projects/cli.py +0 -0
  39. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/queue/__init__.py +0 -0
  40. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/queue/cli.py +0 -0
  41. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/queue/queue.py +0 -0
  42. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/related_analyses/__init__.py +0 -0
  43. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/related_analyses/related_analyses.py +0 -0
  44. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/utils/__init__.py +0 -0
  45. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/utils/array_job.py +0 -0
  46. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/utils/cli_helpers.py +0 -0
  47. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/utils/cloud.py +0 -0
  48. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/utils/details.py +0 -0
  49. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/utils/errors.py +0 -0
  50. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/utils/last_wf.py +0 -0
  51. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/utils/nextflow_version.py +0 -0
  52. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/utils/requests.py +0 -0
  53. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/utils/resources.py +0 -0
  54. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/workflows/__init__.py +0 -0
  55. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli/workflows/cli.py +0 -0
  56. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli.egg-info/SOURCES.txt +0 -0
  57. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli.egg-info/dependency_links.txt +0 -0
  58. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli.egg-info/entry_points.txt +0 -0
  59. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli.egg-info/requires.txt +0 -0
  60. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/cloudos_cli.egg-info/top_level.txt +0 -0
  61. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/setup.cfg +0 -0
  62. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/setup.py +0 -0
  63. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/tests/__init__.py +0 -0
  64. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/tests/functions_for_pytest.py +0 -0
  65. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/tests/test_cli_project_create.py +0 -0
  66. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/tests/test_cost/__init__.py +0 -0
  67. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/tests/test_cost/test_job_cost.py +0 -0
  68. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/tests/test_details.py +0 -0
  69. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/tests/test_error_messages.py +0 -0
  70. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/tests/test_interactive_session/__init__.py +0 -0
  71. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/tests/test_interactive_session/test_create_session.py +0 -0
  72. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/tests/test_interactive_session/test_link_error_handling.py +0 -0
  73. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/tests/test_interactive_session/test_link_session.py +0 -0
  74. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/tests/test_interactive_session/test_list_sessions.py +0 -0
  75. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/tests/test_interactive_session/test_normalize_path.py +0 -0
  76. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/tests/test_logging/__init__.py +0 -0
  77. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/tests/test_logging/test_logger.py +0 -0
  78. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/tests/test_nextflow_version.py +0 -0
  79. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/tests/test_related_analyses/__init__.py +0 -0
  80. {cloudos_cli-2.94.1 → cloudos_cli-2.95.1}/tests/test_related_analyses/test_related_analyses.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloudos_cli
3
- Version: 2.94.1
3
+ Version: 2.95.1
4
4
  Summary: Python package for interacting with the Lifebit Platform
5
5
  Home-page: https://github.com/lifebit-ai/cloudos-cli
6
6
  Author: David Piñeyro
@@ -609,7 +609,7 @@ First, configure your local environment to ease parameter input. We will try to
609
609
  cloudos job run --profile my_profile --workflow-name rnatoy --job-config cloudos_cli/examples/rnatoy.config --resumable
610
610
  ```
611
611
 
612
- As you can see, a file with the job parameters is used to configure the job. This file could be a regular `nextflow.config` file or any file with the following structure:
612
+ As you can see, a file with the job parameters is used to configure the job. This file is a list of the parameters to pass to your job, and nothing else. It has the following structure:
613
613
 
614
614
  ```
615
615
  params {
@@ -618,6 +618,24 @@ params {
618
618
  }
619
619
  ```
620
620
 
621
+ `--job-config` is shorthand for repeating `--parameter` on the command line: the CLI reads the file line by line, splits each line on the first `=`, and sends each result as one named parameter.
622
+
623
+ Every value is passed through as text, exactly as it would be when launching Nextflow from the command line.
624
+
625
+ > **IMPORTANT: `[ ]` is not expanded into a Nextflow list.** In a real `nextflow.config`, `my_param = ['a', 'b']` gives the pipeline a list of two items. Through `--job-config` it gives the pipeline the *string* `[a,b]`. The line is accepted and the job is submitted, so this fails silently at the point where your pipeline tries to iterate over the value. The CLI prints a warning when it sees a value that looks like a list, showing exactly what the pipeline will receive.
626
+
627
+ To pass a genuine list, define it in the pipeline's own `nextflow.config` in the git repository, or use `--params-file` with a JSON or YAML file (see below), which preserves types.
628
+
629
+ What a `--job-config` file cannot contain, because it is **not** a `nextflow.config` file:
630
+
631
+ - values spanning several lines
632
+ - nested blocks (e.g. `genomes { ... }`)
633
+ - `process`, `profiles`, `docker` or other config sections
634
+
635
+ Comments are supported, both on their own line and after a value, using `//` or `#`.
636
+
637
+ If a parameter needs a genuinely structured value rather than a string, either define it in the pipeline's own `nextflow.config` in the git repository and expose the parts you want to change as individual parameters, or pass it with `--params-file` (see below), which supports JSON and YAML with full type fidelity.
638
+
621
639
  In addition, parameters can also be specified using the command-line `-p` or `--parameter`. For instance:
622
640
 
623
641
  ```bash
@@ -2648,7 +2666,7 @@ All configuration parameters are optional. If not specified, the session resumes
2648
2666
 
2649
2667
  ### Link
2650
2668
 
2651
- The `cloudos interactive-session link` command provides a unified interface for linking files and folders to interactive analysis sessions. It consolidates functionality previously available through separate commands (`cloudos job results --link`, `cloudos job workdir --link`, `cloudos job logs --link`, and `cloudos datasets link`) into a single, intuitive interface.
2669
+ The `cloudos interactive-session link` command provides a unified interface for linking files and folders to interactive analysis sessions. It consolidates functionality previously available through separate commands (`cloudos job results --link`, `cloudos job workdir --link`, and `cloudos job logs --link`) into a single, intuitive interface.
2652
2670
 
2653
2671
  #### Link Files and Folders to Interactive Analysis
2654
2672
 
@@ -2880,41 +2898,8 @@ cloudos datasets cp AnalysesResults/my_analysis/results/my_plot.png Data/plots
2880
2898
  ```
2881
2899
 
2882
2900
 
2883
- #### Link Files and Folders to Interactive Analysis
2884
-
2885
- Connect external S3 buckets, S3 files, or File Explorer files/folders to your interactive analysis sessions. This provides direct access to data without needing to copy files.
2886
-
2887
- This subcommand uses the `--session-id` option to access the correct interactive session. This option can be added to the CLI or defined in a profile, for convenience.
2888
-
2889
- ```bash
2890
- cloudos datasets link <PATH> --profile <profile> --session-id <SESSION_ID>
2891
- ```
2892
-
2893
- Link an S3 folder:
2894
- ```console
2895
- cloudos datasets link s3://bucket/path/folder --profile test --session-id 1234
2896
- ```
2897
-
2898
- Link an S3 file:
2899
- ```console
2900
- cloudos datasets link s3://bucket/path/data.csv --profile test --session-id 1234
2901
- ```
2902
-
2903
- Link a File Explorer folder (requires `--project-name`):
2904
- ```console
2905
- cloudos datasets link "Data/HLA" --project-name my-project --session-id 1234
2906
- ```
2907
-
2908
- Link a File Explorer file (requires `--project-name`):
2909
- ```console
2910
- cloudos datasets link "Data/observations.csv" --project-name my-project --session-id 1234
2911
- ```
2912
-
2913
- > [!NOTE]
2914
- > If running the CLI inside a jupyter session, the pre-configured CLI installation will have the session ID already installed and only the `--apikey` needs to be added.
2915
-
2916
2901
  > [!NOTE]
2917
- > Virtual folders in File Explorer (folders created in File Explorer that are not actual storage locations) cannot be linked.
2902
+ > To link files or folders (S3 or File Explorer) to an interactive analysis session, use `cloudos interactive-session link` or the `--link` option of `cloudos interactive-session create`. Virtual folders in File Explorer cannot be linked.
2918
2903
 
2919
2904
  > [!NOTE]
2920
2905
  > A maximum of 100 items can be linked per session. If the new items combined with already-linked items exceed this limit, the entire request is rejected.
@@ -574,7 +574,7 @@ First, configure your local environment to ease parameter input. We will try to
574
574
  cloudos job run --profile my_profile --workflow-name rnatoy --job-config cloudos_cli/examples/rnatoy.config --resumable
575
575
  ```
576
576
 
577
- As you can see, a file with the job parameters is used to configure the job. This file could be a regular `nextflow.config` file or any file with the following structure:
577
+ As you can see, a file with the job parameters is used to configure the job. This file is a list of the parameters to pass to your job, and nothing else. It has the following structure:
578
578
 
579
579
  ```
580
580
  params {
@@ -583,6 +583,24 @@ params {
583
583
  }
584
584
  ```
585
585
 
586
+ `--job-config` is shorthand for repeating `--parameter` on the command line: the CLI reads the file line by line, splits each line on the first `=`, and sends each result as one named parameter.
587
+
588
+ Every value is passed through as text, exactly as it would be when launching Nextflow from the command line.
589
+
590
+ > **IMPORTANT: `[ ]` is not expanded into a Nextflow list.** In a real `nextflow.config`, `my_param = ['a', 'b']` gives the pipeline a list of two items. Through `--job-config` it gives the pipeline the *string* `[a,b]`. The line is accepted and the job is submitted, so this fails silently at the point where your pipeline tries to iterate over the value. The CLI prints a warning when it sees a value that looks like a list, showing exactly what the pipeline will receive.
591
+
592
+ To pass a genuine list, define it in the pipeline's own `nextflow.config` in the git repository, or use `--params-file` with a JSON or YAML file (see below), which preserves types.
593
+
594
+ What a `--job-config` file cannot contain, because it is **not** a `nextflow.config` file:
595
+
596
+ - values spanning several lines
597
+ - nested blocks (e.g. `genomes { ... }`)
598
+ - `process`, `profiles`, `docker` or other config sections
599
+
600
+ Comments are supported, both on their own line and after a value, using `//` or `#`.
601
+
602
+ If a parameter needs a genuinely structured value rather than a string, either define it in the pipeline's own `nextflow.config` in the git repository and expose the parts you want to change as individual parameters, or pass it with `--params-file` (see below), which supports JSON and YAML with full type fidelity.
603
+
586
604
  In addition, parameters can also be specified using the command-line `-p` or `--parameter`. For instance:
587
605
 
588
606
  ```bash
@@ -2613,7 +2631,7 @@ All configuration parameters are optional. If not specified, the session resumes
2613
2631
 
2614
2632
  ### Link
2615
2633
 
2616
- The `cloudos interactive-session link` command provides a unified interface for linking files and folders to interactive analysis sessions. It consolidates functionality previously available through separate commands (`cloudos job results --link`, `cloudos job workdir --link`, `cloudos job logs --link`, and `cloudos datasets link`) into a single, intuitive interface.
2634
+ The `cloudos interactive-session link` command provides a unified interface for linking files and folders to interactive analysis sessions. It consolidates functionality previously available through separate commands (`cloudos job results --link`, `cloudos job workdir --link`, and `cloudos job logs --link`) into a single, intuitive interface.
2617
2635
 
2618
2636
  #### Link Files and Folders to Interactive Analysis
2619
2637
 
@@ -2845,41 +2863,8 @@ cloudos datasets cp AnalysesResults/my_analysis/results/my_plot.png Data/plots
2845
2863
  ```
2846
2864
 
2847
2865
 
2848
- #### Link Files and Folders to Interactive Analysis
2849
-
2850
- Connect external S3 buckets, S3 files, or File Explorer files/folders to your interactive analysis sessions. This provides direct access to data without needing to copy files.
2851
-
2852
- This subcommand uses the `--session-id` option to access the correct interactive session. This option can be added to the CLI or defined in a profile, for convenience.
2853
-
2854
- ```bash
2855
- cloudos datasets link <PATH> --profile <profile> --session-id <SESSION_ID>
2856
- ```
2857
-
2858
- Link an S3 folder:
2859
- ```console
2860
- cloudos datasets link s3://bucket/path/folder --profile test --session-id 1234
2861
- ```
2862
-
2863
- Link an S3 file:
2864
- ```console
2865
- cloudos datasets link s3://bucket/path/data.csv --profile test --session-id 1234
2866
- ```
2867
-
2868
- Link a File Explorer folder (requires `--project-name`):
2869
- ```console
2870
- cloudos datasets link "Data/HLA" --project-name my-project --session-id 1234
2871
- ```
2872
-
2873
- Link a File Explorer file (requires `--project-name`):
2874
- ```console
2875
- cloudos datasets link "Data/observations.csv" --project-name my-project --session-id 1234
2876
- ```
2877
-
2878
- > [!NOTE]
2879
- > If running the CLI inside a jupyter session, the pre-configured CLI installation will have the session ID already installed and only the `--apikey` needs to be added.
2880
-
2881
2866
  > [!NOTE]
2882
- > Virtual folders in File Explorer (folders created in File Explorer that are not actual storage locations) cannot be linked.
2867
+ > To link files or folders (S3 or File Explorer) to an interactive analysis session, use `cloudos interactive-session link` or the `--link` option of `cloudos interactive-session create`. Virtual folders in File Explorer cannot be linked.
2883
2868
 
2884
2869
  > [!NOTE]
2885
2870
  > A maximum of 100 items can be linked per session. If the new items combined with already-linked items exceed this limit, the entire request is rejected.
@@ -0,0 +1 @@
1
+ __version__ = '2.95.1'
@@ -4,7 +4,6 @@ import rich_click as click
4
4
  import csv
5
5
  import sys
6
6
  from cloudos_cli.datasets import Datasets
7
- from cloudos_cli.interactive_session.link import Link
8
7
  from cloudos_cli.utils.resources import ssl_selector, format_bytes
9
8
  from cloudos_cli.configure.configure import with_profile_config, CLOUDOS_URL
10
9
  from cloudos_cli.logging.logger import update_command_context_from_click
@@ -727,57 +726,18 @@ def rm_item(ctx,
727
726
  raise ValueError(f"Remove operation failed. {str(e)}")
728
727
 
729
728
 
730
- @datasets.command(name="link")
731
- @click.argument("path", required=True)
732
- @click.option('-k', '--apikey', help='Your Lifebit Platform API key', required=True)
733
- @click.option('-c', '--cloudos-url',
734
- help=(f'The Lifebit Platform url you are trying to access to. Default={CLOUDOS_URL}.'),
735
- default=CLOUDOS_URL)
736
- @click.option('--project-name',
737
- help='The name of a Lifebit Platform project.',
738
- required=False)
739
- @click.option('--workspace-id', help='The specific Lifebit Platform workspace id.', required=True)
740
- @click.option('--session-id', help='The specific Lifebit Platform interactive session id.', required=True)
741
- @click.option('--disable-ssl-verification', is_flag=True, help='Disable SSL certificate verification.')
742
- @click.option('--ssl-cert', help='Path to your SSL certificate file.')
743
- @click.option('--profile', help='Profile to use from the config file', default='default')
729
+ @datasets.command(
730
+ name="link",
731
+ hidden=True,
732
+ add_help_option=False,
733
+ context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
734
+ )
744
735
  @click.pass_context
745
- @with_profile_config(required_params=['apikey', 'workspace_id', 'session_id'])
746
- def link(ctx,
747
- path,
748
- apikey,
749
- cloudos_url,
750
- project_name,
751
- workspace_id,
752
- session_id,
753
- disable_ssl_verification,
754
- ssl_cert,
755
- profile):
756
- """
757
- Link a file or folder (S3 or File Explorer) to an active interactive analysis.
758
-
759
- PATH [path]: the full path to the S3 file/folder or relative path in File Explorer
760
- (relative to the project specified by --project-name).
761
- E.g.: 's3://bucket-name/folder/subfolder', 's3://bucket/data/file.csv',
762
- 'Data/Downloads', 'Data', or 'Data/file.csv'.
763
- """
764
- if not path.startswith("s3://") and project_name is None:
765
- raise click.UsageError("When using File Explorer paths '--project-name' needs to be defined")
766
-
767
- verify_ssl = ssl_selector(disable_ssl_verification, ssl_cert)
768
-
769
- link_p = Link(
770
- cloudos_url=cloudos_url,
771
- apikey=apikey,
772
- workspace_id=workspace_id,
773
- cromwell_token=None,
774
- project_name=project_name,
775
- verify=verify_ssl
736
+ def link_deprecated(ctx):
737
+ raise click.ClickException(
738
+ "'cloudos datasets link' has been removed.\n\n"
739
+ "Use one of the supported alternatives:\n"
740
+ " cloudos interactive-session link <PATH> --session-id <SESSION_ID>\n"
741
+ " cloudos interactive-session create --link <PATH> [...]\n\n"
742
+ "Add --profile <my_profile> to either command to use a saved profile."
776
743
  )
777
-
778
- try:
779
- success = link_p.link_folder(path, session_id)
780
- except Exception as e:
781
- raise ValueError(f"Could not link item. {e}")
782
- if not success:
783
- raise click.ClickException("Linking failed: mount verification did not reach 'mounted' status.")
@@ -78,8 +78,7 @@ class Link(Cloudos):
78
78
  committed_count: int = 0) -> bool:
79
79
  """Link multiple folders/files (S3 or File Explorer) to an interactive session in one request.
80
80
 
81
- Attempts to use API v2 (which supports multiple items per request) first,
82
- with automatic fallback to v1 (individual requests) if v2 is not available.
81
+ Uses API v2 which supports multiple items per request.
83
82
 
84
83
  Parameters
85
84
  ----------
@@ -112,17 +111,13 @@ class Link(Cloudos):
112
111
  # Parse and validate all items
113
112
  data_items, folder_info = self._parse_items_to_data_items(folders, existing_mount_names)
114
113
 
115
- # Try v2 API first (supports batch)
114
+ # Mount via v2 API (supports batch)
116
115
  status_code = self._try_mount_v2(data_items, session_id)
117
116
 
118
- if status_code is None:
119
- # v2 failed or not available, fall back to v1
120
- status_code = self._fallback_mount_v1(folder_info, session_id)
121
-
122
117
  # Verify mount completion for all items (any 2xx response means success)
123
- if status_code is not None and 200 <= status_code < 300:
118
+ if 200 <= status_code < 300:
124
119
  return self._verify_all_mounts(folder_info, session_id)
125
- return True
120
+ return False
126
121
 
127
122
  def _parse_items_to_data_items(self, folders: list, existing_mount_names: set = None) -> tuple:
128
123
  """Parse and validate folders/files, extracting data items for API payload.
@@ -206,7 +201,7 @@ class Link(Cloudos):
206
201
  )
207
202
 
208
203
  def _try_mount_v2(self, data_items: list, session_id: str) -> int:
209
- """Attempt to mount folders using API v2.
204
+ """Mount items using API v2.
210
205
 
211
206
  Parameters
212
207
  ----------
@@ -217,151 +212,35 @@ class Link(Cloudos):
217
212
 
218
213
  Returns
219
214
  -------
220
- int or None
221
- Status code if successful, None if v2 unavailable (triggering fallback).
215
+ int
216
+ HTTP status code on success.
222
217
 
223
218
  Raises
224
219
  ------
225
220
  ValueError
226
- If v2 fails for reasons other than unavailability.
221
+ If the mount request fails.
227
222
  """
228
223
  v2_payload = {"dataItems": data_items}
229
224
 
230
225
  try:
231
- status_code = self.mount_fuse_filesystem_v2(
226
+ return self.mount_fuse_filesystem_v2(
232
227
  session_id=session_id,
233
228
  team_id=self.workspace_id,
234
229
  payload=v2_payload,
235
230
  verify=self.verify
236
231
  )
237
- return status_code
238
232
  except Exception as v2_error:
239
- # Check if error indicates v2 endpoint not available (404 only, but not session-not-found)
240
- error_str = str(v2_error)
241
- # Only fall back to v1 if it's a genuine endpoint-not-available 404
242
- # Session-not-found errors should propagate immediately
243
- if "Session not found" in error_str:
244
- raise # Re-raise session-not-found errors immediately
245
-
246
- should_fallback = (
247
- "404" in error_str or "Not Found" in error_str or "not found" in error_str.lower()
248
- )
249
-
250
- if should_fallback:
251
- return None # Trigger v1 fallback
252
- else:
253
- # v2 failed for reasons other than not available
254
- self._handle_mount_error(v2_error, "folder")
255
-
256
- def _fallback_mount_v1(self, folder_info: list, session_id: str) -> int:
257
- """Fall back to v1 API, mounting folders one at a time.
258
-
259
- Parameters
260
- ----------
261
- folder_info : list
262
- List of folder metadata dictionaries.
263
- session_id : str
264
- The interactive session ID.
265
-
266
- Returns
267
- -------
268
- int
269
- Status code from the last successful mount (typically 204).
270
-
271
- Raises
272
- ------
273
- ValueError
274
- If any item is a file (v1 only supports folders), or if any folder
275
- fails to mount. Note: Earlier folders may have successfully mounted
276
- before the failure.
277
- """
278
- for f in folder_info:
279
- item_type = f['data'].get('type', '')
280
- item_kind = f['data'].get('kind', '')
281
- if item_type == 'S3File' or item_kind == 'File':
233
+ if isinstance(v2_error, ValueError):
234
+ raise
235
+ if isinstance(v2_error, BadRequestException) and v2_error.rv.status_code == 404:
282
236
  raise ValueError(
283
- f"File linking requires API v2, which is not available for this session. "
284
- f"Only folder linking is supported via the v1 API fallback."
285
- )
286
-
287
- status_code = None
288
- mounted_folders = []
289
-
290
- for folder_data in folder_info:
291
- try:
292
- status_code = self._mount_single_folder_v1(folder_data, session_id)
293
- mounted_folders.append(folder_data['path'])
294
- except ValueError as e:
295
- # If we've already mounted some folders, inform the user
296
- if mounted_folders:
297
- error_msg = f"{str(e)}\n\nNote: The following folders were successfully mounted before this error: {', '.join(mounted_folders)}"
298
- raise ValueError(error_msg)
299
- else:
300
- raise
301
- return status_code
302
-
303
- def _mount_single_folder_v1(self, folder_data: dict, session_id: str) -> int:
304
- """Mount a single folder using API v1.
305
-
306
- Parameters
307
- ----------
308
- folder_data : dict
309
- Folder metadata including type, path, and data.
310
- session_id : str
311
- The interactive session ID.
312
-
313
- Returns
314
- -------
315
- int
316
- Status code (typically 204 on success).
317
-
318
- Raises
319
- ------
320
- ValueError
321
- If the mount request fails.
322
- """
323
- v1_payload = {"dataItem": folder_data["data"]}
324
-
325
- url = (
326
- f"{self.cloudos_url}/api/v1/"
327
- f"interactive-sessions/{session_id}/fuse-filesystem/mount"
328
- f"?teamId={self.workspace_id}"
329
- )
330
- headers = {
331
- "Content-type": "application/json",
332
- "apikey": self.apikey
333
- }
334
-
335
- try:
336
- r = retry_requests_post(url, headers=headers, json=v1_payload, verify=self.verify)
337
-
338
- if r.status_code >= 400:
339
- # Handle v1 errors using consolidated error handling
340
- if r.status_code == 403:
341
- raise ValueError(f"Provided {folder_data['type']} item already exists with 'mounted' status")
342
- elif r.status_code == 401:
343
- raise ValueError("Unauthorized. Invalid API key or insufficient permissions.")
344
- elif r.status_code == 400:
345
- try:
346
- r_content = json.loads(r.content)
347
- if r_content.get("message") == "Invalid Supported DataItem folderType. Supported values are S3Folder":
348
- raise ValueError(f"Invalid Supported DataItem '{folder_data['type']}' folderType. Virtual folders cannot be linked.")
349
- elif r_content.get("message") == "Request failed with status code 403":
350
- raise ValueError(f"Interactive Analysis session is not active")
351
- else:
352
- raise ValueError(f"Cannot link item")
353
- except json.JSONDecodeError:
354
- raise ValueError(f"Bad request (400): Unable to parse error response")
355
- else:
356
- raise ValueError(f"Failed to mount item: HTTP {r.status_code}")
357
-
358
- return r.status_code
359
-
360
- except ValueError:
361
- # Re-raise ValueError as-is
362
- raise
363
- except Exception as v1_error:
364
- raise ValueError(f"Failed to mount {folder_data['type']} item: {str(v1_error)}")
237
+ "The linking API (v2) is not available on this platform. "
238
+ "Contact your platform administrator."
239
+ ) from v2_error
240
+ all_s3 = all(item.get("type", "").startswith("S3") for item in data_items)
241
+ all_fe = all(not item.get("type", "").startswith("S3") for item in data_items)
242
+ label = "S3" if all_s3 else "File Explorer" if all_fe else "item"
243
+ self._handle_mount_error(v2_error, label)
365
244
 
366
245
  def _verify_all_mounts(self, folder_info: list, session_id: str):
367
246
  """Verify mount completion status for all items (files and folders).
@@ -62,8 +62,13 @@ def job():
62
62
  help=('When the workflows are duplicated, use the latest imported workflow (by date).'),
63
63
  is_flag=True)
64
64
  @click.option('--job-config',
65
- help=('A config file similar to a nextflow.config file, ' +
66
- 'but only with the parameters to use with your job.'))
65
+ help=('A file listing the parameters to use with your job, as ' +
66
+ '\'name = value\' pairs inside a \'params\' block. It is ' +
67
+ 'equivalent to repeating --parameter, so only flat ' +
68
+ 'parameters are supported: it is not a nextflow.config ' +
69
+ 'and cannot contain multi-line parameters, nested blocks or sections ' +
70
+ 'such as \'process\' and \'profiles\'. Use --params-file ' +
71
+ 'for parameters that need a structured value.'))
67
72
  @click.option('--params-file',
68
73
  help=('A file containing the parameters to pass to the job call. ' +
69
74
  'It should be a .json or .yaml file with a dictionary structure ' +
@@ -176,6 +176,167 @@ class Job(Cloudos):
176
176
  else:
177
177
  raise ValueError(f'No {name} element in {resource} was found')
178
178
 
179
+ @staticmethod
180
+ def strip_inline_comment(line):
181
+ """Remove a trailing '//' or '#' comment from a job config line.
182
+
183
+ Only comments preceded by whitespace are removed, so that values
184
+ containing these characters, such as 's3://bucket/key', are preserved.
185
+
186
+ Parameters
187
+ ----------
188
+ line : string
189
+ A single raw line from a job config file.
190
+
191
+ Returns
192
+ -------
193
+ string
194
+ The line with any trailing comment removed.
195
+ """
196
+ return re.sub(r'\s+(?://|#).*$', '', line)
197
+
198
+ @staticmethod
199
+ def list_literal_warning(p_name, p_value):
200
+ """Build a warning for a value that looks like a list but is sent as text.
201
+
202
+ A '[a, b]' literal in a job config file is not expanded into a Nextflow
203
+ list: every job config value is sent as text. Users coming from real
204
+ nextflow.config files expect the expansion, so warn and show the value
205
+ the pipeline actually receives.
206
+
207
+ Parameters
208
+ ----------
209
+ p_name : string
210
+ The parameter name.
211
+ p_value : string
212
+ The parameter value, as it will be sent.
213
+
214
+ Returns
215
+ -------
216
+ string or None
217
+ The warning message, or None if the value is not a list literal.
218
+ """
219
+ if not (p_value.startswith('[') and p_value.endswith(']')):
220
+ return None
221
+ elements = [e for e in p_value[1:-1].split(',') if len(e) > 0]
222
+ element_noun = 'element' if len(elements) == 1 else 'elements'
223
+ listed = ', '.join(f"'{e}'" for e in elements) if elements else 'nothing'
224
+ return (f"Warning: parameter '{p_name}' looks like a list of "
225
+ f"{len(elements)} {element_noun} ({listed}), but every "
226
+ '--job-config value is sent as text.\n'
227
+ f"\tThe pipeline will receive the string --{p_name} '{p_value}', "
228
+ 'not a Nextflow list of '
229
+ f'{len(elements)} {element_noun}.\n'
230
+ "\tTo pass a real list, define it in the pipeline's own "
231
+ 'nextflow.config, or use --params-file with a JSON or YAML file.')
232
+
233
+ @staticmethod
234
+ def parse_job_config_params(job_config, workflow_type='nextflow'):
235
+ """Parse a job config file into a list of (name, value) parameter pairs.
236
+
237
+ The job config file is a list of parameters, equivalent to repeating
238
+ '--parameter name=value' on the command line. Every value is sent as
239
+ text, exactly as when launching Nextflow from the command line, so a
240
+ literal such as "['a', 'b']" is passed through as a string. Values
241
+ spanning several lines and nested blocks cannot be represented.
242
+
243
+ Parameters
244
+ ----------
245
+ job_config : string
246
+ Path to the job config file.
247
+ workflow_type : string
248
+ The type of workflow to run. Quotes are kept for 'wdl' workflows.
249
+
250
+ Returns
251
+ -------
252
+ list
253
+ A list of (name, value) tuples, in file order.
254
+
255
+ Raises
256
+ ------
257
+ ValueError
258
+ If the file has no 'params' block, if the block is opened and closed
259
+ on the same line, or if a line inside the block is not a
260
+ 'name = value' pair, has a value spanning several lines, or has no
261
+ value at all. Every message reports the offending line, and all but
262
+ the missing block report its line number.
263
+
264
+ Notes
265
+ -----
266
+ A value that looks like a list is parsed and returned, but prints a
267
+ warning first, since it is sent as text rather than as a Nextflow list.
268
+ The warning is skipped for 'wdl' workflows.
269
+ """
270
+ parsed = []
271
+ with open(job_config, 'r') as p:
272
+ reading = False
273
+ found_params_block = False
274
+ for line_no, p_l in enumerate(p, start=1):
275
+ if re.match(r'^\s*params\s*\{', p_l, re.IGNORECASE):
276
+ found_params_block = True
277
+ reading = True
278
+ remainder = Job.strip_inline_comment(p_l).split('{', 1)[1].strip()
279
+ if len(remainder) > 0 and remainder[0] not in ('/', '#'):
280
+ raise ValueError(
281
+ f'Could not parse line {line_no} of {job_config}: ' +
282
+ f'"{p_l.strip()}". The \'params\' block must span ' +
283
+ 'several lines, with one \'name = value\' pair per ' +
284
+ 'line.')
285
+ continue
286
+ if not reading:
287
+ continue
288
+ p_l_no_comment = Job.strip_inline_comment(p_l)
289
+ if workflow_type == 'wdl':
290
+ p_l_strip = p_l_no_comment.strip().replace(' ', '')
291
+ else:
292
+ p_l_strip = p_l_no_comment.strip().replace(
293
+ ' ', '').replace('\"', '').replace('\'', '')
294
+ if len(p_l_strip) == 0:
295
+ continue
296
+ elif p_l_strip[0] in ('/', '#', '*'):
297
+ continue
298
+ elif p_l_strip == '}':
299
+ reading = False
300
+ continue
301
+ p_list = p_l_strip.split('=')
302
+ if len(p_list) < 2:
303
+ raise ValueError(
304
+ f'Could not parse line {line_no} of {job_config}: ' +
305
+ f'"{p_l.strip()}". Expected a \'name = value\' pair. ' +
306
+ 'The job config file is a list of parameters, not a ' +
307
+ 'Nextflow config: it cannot contain values spanning ' +
308
+ 'several lines, nested blocks, or sections such as ' +
309
+ '\'process\' and \'profiles\'.')
310
+ p_name = p_list[0]
311
+ p_value = '='.join(p_list[1:])
312
+ if p_value.count('[') > p_value.count(']'):
313
+ raise ValueError(
314
+ f'Could not parse line {line_no} of {job_config}: ' +
315
+ f'"{p_l.strip()}". Values spanning several lines are ' +
316
+ 'not supported. Keep the value on a single line, ' +
317
+ 'define it in the pipeline\'s own nextflow.config, ' +
318
+ 'or pass it with --params-file using a JSON or YAML ' +
319
+ 'file.')
320
+ if len(p_value) == 0:
321
+ raise ValueError(
322
+ f'Could not parse line {line_no} of {job_config}: ' +
323
+ f'"{p_l.strip()}". Parameter \'{p_name}\' has no ' +
324
+ 'value. Give it a value, or remove the line. A value ' +
325
+ 'that starts with \'//\' or \'#\' must be quoted, ' +
326
+ 'otherwise it is read as a comment.')
327
+ if workflow_type != 'wdl':
328
+ warning = Job.list_literal_warning(p_name, p_value)
329
+ if warning is not None:
330
+ click.secho(warning, fg='yellow', bold=True)
331
+ parsed.append((p_name, p_value))
332
+ if not found_params_block:
333
+ raise ValueError(
334
+ f'No \'params\' block was found in {job_config}. ' +
335
+ 'The parameters must be listed inside a \'params { ... }\' ' +
336
+ 'block, one \'name = value\' pair per line. The ' +
337
+ '\'params.name = value\' form is not supported.')
338
+ return parsed
339
+
179
340
  def build_parameters_file_payload(self, params_file):
180
341
  """Build the parametersFile payload for a params file path."""
181
342
  if params_file is None:
@@ -323,12 +484,12 @@ class Job(Cloudos):
323
484
  command,
324
485
  cpus,
325
486
  memory):
326
- """Converts a nextflow.config file into a json formatted dict.
487
+ """Converts a job config file into a json formatted dict.
327
488
 
328
489
  Parameters
329
490
  ----------
330
491
  job_config : string
331
- Path to a nextflow.config file with parameters scope.
492
+ Path to a file with parameters scope.
332
493
  params_file : string
333
494
  S3 or File Explorer path to a JSON/YAML file with Nextflow parameters.
334
495
  parameter : tuple
@@ -422,47 +583,12 @@ class Job(Cloudos):
422
583
  raise ValueError('No --job-config or --parameter were provided. At least one of ' +
423
584
  'these are required for WDL workflows.')
424
585
  if job_config is not None:
425
- with open(job_config, 'r') as p:
426
- reading = False
427
- for p_l in p:
428
- if 'params' in p_l.lower():
429
- reading = True
430
- else:
431
- if reading:
432
- if workflow_type == 'wdl':
433
- p_l_strip = p_l.strip().replace(
434
- ' ', '')
435
- else:
436
- p_l_strip = p_l.strip().replace(
437
- ' ', '').replace('\"', '').replace('\'', '')
438
- if len(p_l_strip) == 0:
439
- continue
440
- elif p_l_strip[0] == '/' or p_l_strip[0] == '#':
441
- continue
442
- elif p_l_strip == '}':
443
- reading = False
444
- else:
445
- p_list = p_l_strip.split('=')
446
- p_name = p_list[0]
447
- p_value = '='.join(p_list[1:])
448
- if len(p_list) < 2:
449
- raise ValueError('Please, specify your ' +
450
- 'parameters in ' +
451
- f'{job_config} using ' +
452
- 'the \'=\' as spacer. ' +
453
- 'E.g: name = my_name')
454
- elif workflow_type == 'wdl':
455
- param = {"prefix": "",
456
- "name": p_name,
457
- "parameterKind": "textValue",
458
- "textValue": p_value}
459
- workflow_params.append(param)
460
- else:
461
- param = {"prefix": "--",
462
- "name": p_name,
463
- "parameterKind": "textValue",
464
- "textValue": p_value}
465
- workflow_params.append(param)
586
+ p_prefix = "" if workflow_type == 'wdl' else "--"
587
+ for p_name, p_value in Job.parse_job_config_params(job_config, workflow_type):
588
+ workflow_params.append({"prefix": p_prefix,
589
+ "name": p_name,
590
+ "parameterKind": "textValue",
591
+ "textValue": p_value})
466
592
  if len(workflow_params) == 0:
467
593
  raise ValueError(f'The {job_config} file did not contain any ' +
468
594
  'valid parameter')
@@ -611,7 +737,7 @@ class Job(Cloudos):
611
737
  Parameters
612
738
  ----------
613
739
  job_config : string
614
- Path to a nextflow.config file with parameters scope.
740
+ Path to a file with parameters scope.
615
741
  params_file : string
616
742
  S3 or File Explorer path to a JSON/YAML file with Nextflow parameters.
617
743
  parameter : tuple
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloudos_cli
3
- Version: 2.94.1
3
+ Version: 2.95.1
4
4
  Summary: Python package for interacting with the Lifebit Platform
5
5
  Home-page: https://github.com/lifebit-ai/cloudos-cli
6
6
  Author: David Piñeyro
@@ -609,7 +609,7 @@ First, configure your local environment to ease parameter input. We will try to
609
609
  cloudos job run --profile my_profile --workflow-name rnatoy --job-config cloudos_cli/examples/rnatoy.config --resumable
610
610
  ```
611
611
 
612
- As you can see, a file with the job parameters is used to configure the job. This file could be a regular `nextflow.config` file or any file with the following structure:
612
+ As you can see, a file with the job parameters is used to configure the job. This file is a list of the parameters to pass to your job, and nothing else. It has the following structure:
613
613
 
614
614
  ```
615
615
  params {
@@ -618,6 +618,24 @@ params {
618
618
  }
619
619
  ```
620
620
 
621
+ `--job-config` is shorthand for repeating `--parameter` on the command line: the CLI reads the file line by line, splits each line on the first `=`, and sends each result as one named parameter.
622
+
623
+ Every value is passed through as text, exactly as it would be when launching Nextflow from the command line.
624
+
625
+ > **IMPORTANT: `[ ]` is not expanded into a Nextflow list.** In a real `nextflow.config`, `my_param = ['a', 'b']` gives the pipeline a list of two items. Through `--job-config` it gives the pipeline the *string* `[a,b]`. The line is accepted and the job is submitted, so this fails silently at the point where your pipeline tries to iterate over the value. The CLI prints a warning when it sees a value that looks like a list, showing exactly what the pipeline will receive.
626
+
627
+ To pass a genuine list, define it in the pipeline's own `nextflow.config` in the git repository, or use `--params-file` with a JSON or YAML file (see below), which preserves types.
628
+
629
+ What a `--job-config` file cannot contain, because it is **not** a `nextflow.config` file:
630
+
631
+ - values spanning several lines
632
+ - nested blocks (e.g. `genomes { ... }`)
633
+ - `process`, `profiles`, `docker` or other config sections
634
+
635
+ Comments are supported, both on their own line and after a value, using `//` or `#`.
636
+
637
+ If a parameter needs a genuinely structured value rather than a string, either define it in the pipeline's own `nextflow.config` in the git repository and expose the parts you want to change as individual parameters, or pass it with `--params-file` (see below), which supports JSON and YAML with full type fidelity.
638
+
621
639
  In addition, parameters can also be specified using the command-line `-p` or `--parameter`. For instance:
622
640
 
623
641
  ```bash
@@ -2648,7 +2666,7 @@ All configuration parameters are optional. If not specified, the session resumes
2648
2666
 
2649
2667
  ### Link
2650
2668
 
2651
- The `cloudos interactive-session link` command provides a unified interface for linking files and folders to interactive analysis sessions. It consolidates functionality previously available through separate commands (`cloudos job results --link`, `cloudos job workdir --link`, `cloudos job logs --link`, and `cloudos datasets link`) into a single, intuitive interface.
2669
+ The `cloudos interactive-session link` command provides a unified interface for linking files and folders to interactive analysis sessions. It consolidates functionality previously available through separate commands (`cloudos job results --link`, `cloudos job workdir --link`, and `cloudos job logs --link`) into a single, intuitive interface.
2652
2670
 
2653
2671
  #### Link Files and Folders to Interactive Analysis
2654
2672
 
@@ -2880,41 +2898,8 @@ cloudos datasets cp AnalysesResults/my_analysis/results/my_plot.png Data/plots
2880
2898
  ```
2881
2899
 
2882
2900
 
2883
- #### Link Files and Folders to Interactive Analysis
2884
-
2885
- Connect external S3 buckets, S3 files, or File Explorer files/folders to your interactive analysis sessions. This provides direct access to data without needing to copy files.
2886
-
2887
- This subcommand uses the `--session-id` option to access the correct interactive session. This option can be added to the CLI or defined in a profile, for convenience.
2888
-
2889
- ```bash
2890
- cloudos datasets link <PATH> --profile <profile> --session-id <SESSION_ID>
2891
- ```
2892
-
2893
- Link an S3 folder:
2894
- ```console
2895
- cloudos datasets link s3://bucket/path/folder --profile test --session-id 1234
2896
- ```
2897
-
2898
- Link an S3 file:
2899
- ```console
2900
- cloudos datasets link s3://bucket/path/data.csv --profile test --session-id 1234
2901
- ```
2902
-
2903
- Link a File Explorer folder (requires `--project-name`):
2904
- ```console
2905
- cloudos datasets link "Data/HLA" --project-name my-project --session-id 1234
2906
- ```
2907
-
2908
- Link a File Explorer file (requires `--project-name`):
2909
- ```console
2910
- cloudos datasets link "Data/observations.csv" --project-name my-project --session-id 1234
2911
- ```
2912
-
2913
- > [!NOTE]
2914
- > If running the CLI inside a jupyter session, the pre-configured CLI installation will have the session ID already installed and only the `--apikey` needs to be added.
2915
-
2916
2901
  > [!NOTE]
2917
- > Virtual folders in File Explorer (folders created in File Explorer that are not actual storage locations) cannot be linked.
2902
+ > To link files or folders (S3 or File Explorer) to an interactive analysis session, use `cloudos interactive-session link` or the `--link` option of `cloudos interactive-session create`. Virtual folders in File Explorer cannot be linked.
2918
2903
 
2919
2904
  > [!NOTE]
2920
2905
  > A maximum of 100 items can be linked per session. If the new items combined with already-linked items exceed this limit, the entire request is rejected.
@@ -1 +0,0 @@
1
- __version__ = '2.94.1'
File without changes
File without changes
File without changes