geoseeq 0.7.3.dev1__tar.gz → 0.7.3.dev2__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 (138) hide show
  1. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/PKG-INFO +1 -1
  2. geoseeq-0.7.3.dev2/docs/examples/simple_python_example/project_dashboard_example.py +61 -0
  3. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/docs/examples/simple_python_example/sample_dashboard_example.py +3 -2
  4. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/docs/examples/simple_python_example/smart_table_example.py +3 -2
  5. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/dashboard/dashboard.py +38 -26
  6. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/project.py +172 -54
  7. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/sample.py +5 -0
  8. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/pyproject.toml +1 -1
  9. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/.devcontainer/devcontainer.json +0 -0
  10. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/.github/workflows/python-publish.yml +0 -0
  11. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/.github/workflows/run_unit_tests.yml +0 -0
  12. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/.gitignore +0 -0
  13. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/.pre-commit-config.yaml +0 -0
  14. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/AGENTS.md +0 -0
  15. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/LICENSE +0 -0
  16. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/Makefile +0 -0
  17. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/README.md +0 -0
  18. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/commit_pylintrc +0 -0
  19. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/docs/about_geoseeq.md +0 -0
  20. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/docs/contributing.md +0 -0
  21. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/docs/downloading_data_examples.md +0 -0
  22. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/docs/examples/simple_python_example/README.md +0 -0
  23. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/docs/examples/simple_python_example/simple_python_example.py +0 -0
  24. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/docs/examples/simple_snakemake_example/README.md +0 -0
  25. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/docs/examples/simple_snakemake_example/Snakefile +0 -0
  26. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/docs/examples/simple_snakemake_example/config.yaml +0 -0
  27. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/docs/uploading_data_examples.md +0 -0
  28. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/__init__.py +0 -0
  29. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/app.py +0 -0
  30. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/blob_constructors.py +0 -0
  31. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/bulk_creators.py +0 -0
  32. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/__init__.py +0 -0
  33. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/constants.py +0 -0
  34. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/copy.py +0 -0
  35. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/detail.py +0 -0
  36. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/download.py +0 -0
  37. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/fastq_utils.py +0 -0
  38. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/find_grn.py +0 -0
  39. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/get_eula.py +0 -0
  40. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/main.py +0 -0
  41. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/manage.py +0 -0
  42. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/progress_bar.py +0 -0
  43. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/project.py +0 -0
  44. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/raw.py +0 -0
  45. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/run.py +0 -0
  46. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/search.py +0 -0
  47. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/shared_params/__init__.py +0 -0
  48. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/shared_params/common_state.py +0 -0
  49. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/shared_params/config.py +0 -0
  50. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/shared_params/id_handlers.py +0 -0
  51. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/shared_params/obj_getters.py +0 -0
  52. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/shared_params/opts_and_args.py +0 -0
  53. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/upload/__init__.py +0 -0
  54. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/upload/upload.py +0 -0
  55. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/upload/upload_advanced.py +0 -0
  56. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/upload/upload_reads.py +0 -0
  57. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/user.py +0 -0
  58. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/utils.py +0 -0
  59. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/cli/view.py +0 -0
  60. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/constants.py +0 -0
  61. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/contrib/__init__.py +0 -0
  62. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/contrib/ncbi/README.md +0 -0
  63. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/contrib/ncbi/__init__.py +0 -0
  64. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/contrib/ncbi/api.py +0 -0
  65. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/contrib/ncbi/bioproject.py +0 -0
  66. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/contrib/ncbi/cli.py +0 -0
  67. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/contrib/ncbi/setup_logging.py +0 -0
  68. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/file_system/filesystem_download.py +0 -0
  69. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/file_system/main.py +0 -0
  70. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/file_system_cache.py +0 -0
  71. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/id_constructors/__init__.py +0 -0
  72. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/id_constructors/from_blobs.py +0 -0
  73. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/id_constructors/from_ids.py +0 -0
  74. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/id_constructors/from_names.py +0 -0
  75. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/id_constructors/from_uuids.py +0 -0
  76. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/id_constructors/resolvers.py +0 -0
  77. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/id_constructors/utils.py +0 -0
  78. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/knex.py +0 -0
  79. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/organization.py +0 -0
  80. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/pipeline.py +0 -0
  81. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/plotting/README.md +0 -0
  82. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/plotting/__init__.py +0 -0
  83. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/plotting/constants.py +0 -0
  84. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/plotting/highcharts.py +0 -0
  85. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/plotting/map/__init__.py +0 -0
  86. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/plotting/map/base_layer.py +0 -0
  87. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/plotting/map/map.py +0 -0
  88. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/plotting/map/overlay.py +0 -0
  89. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/plotting/selectable.py +0 -0
  90. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/remote_object.py +0 -0
  91. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/result/__init__.py +0 -0
  92. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/result/bioinfo.py +0 -0
  93. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/result/file_chunker.py +0 -0
  94. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/result/file_download.py +0 -0
  95. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/result/file_upload.py +0 -0
  96. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/result/result_file.py +0 -0
  97. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/result/result_folder.py +0 -0
  98. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/result/resumable_download_tracker.py +0 -0
  99. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/result/resumable_upload_tracker.py +0 -0
  100. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/result/smart_objects.py +0 -0
  101. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/result/utils.py +0 -0
  102. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/search.py +0 -0
  103. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/smart_table.py +0 -0
  104. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/smart_tree.py +0 -0
  105. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/upload_download_manager.py +0 -0
  106. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/user.py +0 -0
  107. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/utils.py +0 -0
  108. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/vc/README.md +0 -0
  109. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/vc/__init__.py +0 -0
  110. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/vc/checksum.py +0 -0
  111. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/vc/cli.py +0 -0
  112. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/vc/clone.py +0 -0
  113. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/vc/constants.py +0 -0
  114. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/vc/vc_cache.py +0 -0
  115. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/vc/vc_dir.py +0 -0
  116. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/vc/vc_sample.py +0 -0
  117. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/vc/vc_stub.py +0 -0
  118. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/geoseeq/work_orders.py +0 -0
  119. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/setup.py +0 -0
  120. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/tests/__init__.py +0 -0
  121. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/tests/conftest.py +0 -0
  122. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/tests/test_api_client.py +0 -0
  123. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/tests/test_download.py +0 -0
  124. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/tests/test_download_cli.py +0 -0
  125. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/tests/test_file_chunker.py +0 -0
  126. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/tests/test_file_system_cache.py +0 -0
  127. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/tests/test_files/files_path.txt +0 -0
  128. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/tests/test_files/sampleclit.R1.fastq.gz +0 -0
  129. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/tests/test_files/sampleclit.R2.fastq.gz +0 -0
  130. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/tests/test_files/single-end.fastq.gz +0 -0
  131. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/tests/test_files/test_metadata.csv +0 -0
  132. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/tests/test_files/test_small.R1.fastq.gz +0 -0
  133. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/tests/test_files/test_small.R2.fastq.gz +0 -0
  134. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/tests/test_plotting.py +0 -0
  135. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/tests/test_remote_object.py +0 -0
  136. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/tests/test_upload.py +0 -0
  137. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/tests/test_upload_cli.py +0 -0
  138. {geoseeq-0.7.3.dev1 → geoseeq-0.7.3.dev2}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: geoseeq
3
- Version: 0.7.3.dev1
3
+ Version: 0.7.3.dev2
4
4
  Summary: GeoSeeq command line tools and python API
5
5
  Project-URL: Homepage, https://github.com/biotia/geoseeq_api_client
6
6
  Project-URL: Issues, https://github.com/biotia/geoseeq_api_client/issues
@@ -0,0 +1,61 @@
1
+ import os
2
+ from geoseeq import Knex
3
+ from geoseeq.dashboard.dashboard import Dashboard
4
+ from geoseeq.id_constructors.from_uuids import (
5
+ project_from_uuid,
6
+ sample_group_ar_field_from_uuid,
7
+ )
8
+
9
+
10
+ endpoint = os.environ.get("GEOSEEQ_ENDPOINT", "")
11
+ token = os.environ.get("GEOSEEQ_API_TOKEN", "")
12
+ project_id = ""
13
+ file_id = ""
14
+ file2_id = ""
15
+
16
+
17
+ knex = Knex(endpoint)
18
+ knex.add_api_token(token)
19
+
20
+
21
+ project = project_from_uuid(knex, project_id)
22
+ dashboard = project.get_or_create_default_dashbaord()
23
+
24
+ # Rename dashboard
25
+ dashboard.title = "My default dashboard"
26
+
27
+ # Add tile
28
+ file = sample_group_ar_field_from_uuid(knex, file_id)
29
+ dashboard.add_tile(file, title="Tile title", width="full")
30
+ dashboard.save()
31
+
32
+ # Remove tiles
33
+ dashboard.tiles = []
34
+ dashboard.save()
35
+
36
+ # Add multiple tiles
37
+ file = sample_group_ar_field_from_uuid(knex, file_id)
38
+ dashboard.add_tile(file, title="Tile title", width="full")
39
+ file2 = sample_group_ar_field_from_uuid(knex, file2_id)
40
+ dashboard.add_tile(file2, title="Tile title 2", width="half")
41
+ dashboard.save()
42
+
43
+
44
+ dashboard2 = project.get_or_create_dashbaord_by_title(title="Dashboard Dix")
45
+ dashboard2.title = "Renamed dashboard"
46
+
47
+ # Set dashboard to default
48
+ dashboard2.default = True
49
+ dashboard2.add_tile(file, title="Best tile", width="half")
50
+ dashboard2.save()
51
+
52
+ # Delete dashboard
53
+ # dashboard2.delete()
54
+
55
+ # Using the constructors
56
+ dashboard3 = Dashboard(knex=knex, project=project, title="Third dashboard")
57
+ dashboard3.create()
58
+
59
+ dashboard2 = Dashboard(knex=knex, project=project, title="Renamed dashboard")
60
+ dashboard2.get() # Load tiles
61
+ print(dashboard.tiles)
@@ -1,3 +1,4 @@
1
+ import os
1
2
  from geoseeq import Knex
2
3
  from geoseeq.dashboard.dashboard import SampleDashboard
3
4
  from geoseeq.id_constructors.from_uuids import (
@@ -6,8 +7,8 @@ from geoseeq.id_constructors.from_uuids import (
6
7
  )
7
8
 
8
9
 
9
- endpoint = ""
10
- token = ""
10
+ endpoint = os.environ.get("GEOSEEQ_ENDPOINT", "")
11
+ token = os.environ.get("GEOSEEQ_API_TOKEN", "")
11
12
  sample_id = ""
12
13
  file_id = ""
13
14
  file2_id = ""
@@ -1,3 +1,4 @@
1
+ import os
1
2
  import pandas as pd
2
3
 
3
4
  from geoseeq import Knex
@@ -7,8 +8,8 @@ from geoseeq.id_constructors.from_uuids import (
7
8
  )
8
9
  from geoseeq.smart_table import SmartTable
9
10
 
10
- endpoint = "https://backend.geoseeq.com"
11
- token = ""
11
+ endpoint = os.environ.get("GEOSEEQ_ENDPOINT", "")
12
+ token = os.environ.get("GEOSEEQ_API_TOKEN", "")
12
13
  folder_id = ""
13
14
 
14
15
  knex = Knex(endpoint)
@@ -5,6 +5,7 @@ from geoseeq import ProjectResultFile
5
5
  from geoseeq.id_constructors import result_file_from_blob
6
6
  from geoseeq.id_constructors.from_ids import result_file_from_id
7
7
  from geoseeq.remote_object import RemoteObject
8
+ from geoseeq import GeoseeqNotFoundError
8
9
 
9
10
  logger = logging.getLogger("geoseeq_api")
10
11
 
@@ -13,17 +14,22 @@ class Dashboard(RemoteObject):
13
14
  parent_field = "project"
14
15
  remote_fields = ["is_default"]
15
16
 
16
- def __init__(self, knex, project, name="Default dashboard", is_default=False):
17
+ def __init__(
18
+ self, knex, project, title="Default dashboard", default=False, tiles=[]
19
+ ):
17
20
  super().__init__(self)
18
21
  self.knex = knex
19
22
  self.project = project
20
- self._name = name
21
- self.tiles = []
22
- self.is_default = is_default
23
+ self.title = title
24
+ self._original_title = title
25
+ self.tiles = tiles
26
+ self.default = default
23
27
 
24
28
  def _get(self, allow_overwrite=False):
25
29
  blob = self.knex.get(f"sample_groups/{self.project.uuid}/dashboard-list")
26
- blob = blob["dashboard_data"][self.name]
30
+ if self.title not in blob["dashboard_data"].keys():
31
+ raise GeoseeqNotFoundError(f"Dashboard '{self.title}' not found.")
32
+ blob = blob["dashboard_data"][self.title]
27
33
  for tile_blob in blob["tiles"]:
28
34
  tile = DashboardTile.from_blob(self, tile_blob)
29
35
  self.tiles.append(tile)
@@ -31,56 +37,62 @@ class Dashboard(RemoteObject):
31
37
  self.load_blob(blob, allow_overwrite=allow_overwrite)
32
38
 
33
39
  def save(self):
40
+ put_data = {
41
+ "name": self._original_title,
42
+ "is_default": self.default,
43
+ "new_name": self.title,
44
+ }
45
+ self.knex.put(
46
+ f"sample_groups/{self.project.uuid}/dashboard-list",
47
+ json=put_data,
48
+ json_response=False,
49
+ )
50
+ self._original_title = self.title
34
51
  self.save_tiles()
35
52
 
36
53
  def save_tiles(self):
37
54
  post_data = {"tiles": [tile._get_post_data() for tile in self.tiles]}
38
- blob = self.knex.post(
39
- f"sample_groups/{self.project.uuid}/dashboard/{self.name}/tiles",
55
+ self.knex.post(
56
+ f"sample_groups/{self.project.uuid}/dashboard/{self._original_title}/tiles",
40
57
  json=post_data,
41
58
  json_response=False,
42
59
  )
43
- print(blob)
44
60
 
45
61
  def _create(self):
46
- post_data = {"name": self.name, "is_default": self.is_default}
47
- blob = self.knex.post(
48
- f"sample_groups/{self.project.uuid}/dashboard", json=post_data
62
+ post_data = {"name": self.title, "is_default": self.default}
63
+ self.knex.post(
64
+ f"sample_groups/{self.project.uuid}/dashboard-list", json=post_data
49
65
  )
50
- self.load_blob(blob)
51
66
 
52
- def tile(
67
+ def add_tile(
53
68
  self,
54
- title,
55
69
  result_file,
56
- style: Literal["col-span-1", "col-span-2"] = "col-span-1",
70
+ title,
71
+ width: Literal["hafl", "full"] = "half",
57
72
  ):
73
+ style = "col-span-1" if width == "half" else "col-span-2"
58
74
  result_file.get()
59
75
  tile = DashboardTile(self.knex, self, title, result_file, style=style)
60
76
  self.tiles.append(tile)
61
77
  self._modified = True
62
- return tile
63
-
64
- def add_tile(self, tile):
65
- self.tiles.append(tile)
66
- self._modified = True
67
78
 
68
- @property
69
- def name(self):
70
- return self._name
79
+ def delete(self):
80
+ self.knex.delete(
81
+ f"sample_groups/{self.project.uuid}/dashboard-list?name={self._original_title}"
82
+ )
71
83
 
72
84
  def __str__(self):
73
- return f'<Geoseeq Dashboard: {self.project.grn} "{self.name}"/>'
85
+ return f'<Geoseeq Dashboard: {self.project.grn} "{self._original_title}"/>'
74
86
 
75
87
  def __repr__(self):
76
88
  return str(self)
77
89
 
78
90
  @property
79
91
  def grn(self):
80
- return f'grn:dashboard:{self.project.uuid}:"{self.name}"'
92
+ return f'grn:dashboard:{self.project.uuid}:"{self._original_title}"'
81
93
 
82
94
  def pre_hash(self):
83
- return "DASH" + self.project.uuid + self.name
95
+ return "DASH" + self.project.uuid + self._original_title
84
96
 
85
97
 
86
98
  class DashboardTile:
@@ -3,6 +3,7 @@ import urllib
3
3
 
4
4
  import pandas as pd
5
5
 
6
+
6
7
  from .pipeline import Pipeline
7
8
  from .remote_object import RemoteObject
8
9
  from .result import ProjectResultFolder
@@ -59,11 +60,23 @@ class Project(RemoteObject):
59
60
  self._modified = True
60
61
 
61
62
  def get_post_data(self):
62
- data = {field: getattr(self, field) for field in self.remote_fields if hasattr(self, field)}
63
+ data = {
64
+ field: getattr(self, field)
65
+ for field in self.remote_fields
66
+ if hasattr(self, field)
67
+ }
63
68
  data["organization"] = self.org.uuid
64
- data['description'] = self.description if hasattr(self, 'description') and self.description else self.name
65
- data['privacy_level'] = self.privacy_level if hasattr(self, 'privacy_level') and self.privacy_level else 'private'
66
- data['storage_provider_name'] = self.storage_provider
69
+ data["description"] = (
70
+ self.description
71
+ if hasattr(self, "description") and self.description
72
+ else self.name
73
+ )
74
+ data["privacy_level"] = (
75
+ self.privacy_level
76
+ if hasattr(self, "privacy_level") and self.privacy_level
77
+ else "private"
78
+ )
79
+ data["storage_provider_name"] = self.storage_provider
67
80
  if self.new_org:
68
81
  if isinstance(self.new_org, RemoteObject):
69
82
  data["organization"] = self.new_org.uuid
@@ -90,7 +103,9 @@ class Project(RemoteObject):
90
103
  url = f"sample_groups/{self.uuid}/samples"
91
104
  chunk_size = 100
92
105
  for i in range(0, len(sample_uuids), chunk_size):
93
- self.knex.post(url, json={"sample_uuids": sample_uuids[i : i + chunk_size]})
106
+ self.knex.post(
107
+ url, json={"sample_uuids": sample_uuids[i : i + chunk_size]}
108
+ )
94
109
  self._sample_cache = []
95
110
 
96
111
  def _delete_sample_list(self):
@@ -126,7 +141,7 @@ class Project(RemoteObject):
126
141
  json=post_data,
127
142
  )
128
143
  self.load_blob(blob)
129
-
144
+
130
145
  def add_sample_uuids(self, sample_uuids):
131
146
  """Return this group and add a sample to this group.
132
147
 
@@ -166,7 +181,7 @@ class Project(RemoteObject):
166
181
 
167
182
  def analysis_result(self, *args, **kwargs):
168
183
  """Return a ProjectResultFolder object for this project.
169
-
184
+
170
185
  Alias for result_folder."""
171
186
  return self.result_folder(*args, **kwargs)
172
187
 
@@ -177,7 +192,9 @@ class Project(RemoteObject):
177
192
  yield sample
178
193
  return
179
194
  url = f"sample_groups/{self.uuid}/samples-list?page=1&page_size=100"
180
- for sample_blob in paginated_iterator(self.knex, url, error_handler=error_handler):
195
+ for sample_blob in paginated_iterator(
196
+ self.knex, url, error_handler=error_handler
197
+ ):
181
198
  sample = self.sample(sample_blob["name"])
182
199
  sample.uuid = sample_blob["uuid"]
183
200
  sample.metadata = sample_blob["metadata"]
@@ -199,12 +216,16 @@ class Project(RemoteObject):
199
216
  yield sample.uuid
200
217
  return
201
218
  url = f"sample_groups/{self.uuid}/samples-list?page=1"
202
- for sample_blob in paginated_iterator(self.knex, url, error_handler=error_handler):
203
- yield sample_blob['uuid']
219
+ for sample_blob in paginated_iterator(
220
+ self.knex, url, error_handler=error_handler
221
+ ):
222
+ yield sample_blob["uuid"]
204
223
 
205
224
  def _batch_sample_uuids(self, batch_size, input_sample_uuids=[]):
206
225
  """Yield batches of sample uuids."""
207
- uuids_to_batch = input_sample_uuids if input_sample_uuids else self.get_sample_uuids()
226
+ uuids_to_batch = (
227
+ input_sample_uuids if input_sample_uuids else self.get_sample_uuids()
228
+ )
208
229
  sample_uuids = []
209
230
  for sample_uuid in uuids_to_batch:
210
231
  sample_uuids.append(sample_uuid)
@@ -216,7 +237,7 @@ class Project(RemoteObject):
216
237
 
217
238
  def get_analysis_results(self, cache=True):
218
239
  """Yield ProjectResultFolder objects for this project fetched from the server.
219
-
240
+
220
241
  Alias for get_result_folders."""
221
242
  return self.get_result_folders(cache=cache)
222
243
 
@@ -262,24 +283,25 @@ class Project(RemoteObject):
262
283
  rows.extend(blob["results"])
263
284
  url = blob["next"]
264
285
  return pd.DataFrame(rows)
265
-
266
-
286
+
267
287
  @property
268
288
  def n_samples(self):
269
289
  """Return the number of samples in this project."""
270
- if hasattr(self, 'samples_count') and self.samples_count is not None:
290
+ if hasattr(self, "samples_count") and self.samples_count is not None:
271
291
  return self.samples_count
272
292
  return len(list(self.get_sample_uuids()))
273
-
274
- def bulk_find_files(self,
275
- sample_uuids=[],
276
- sample_name_includes=[],
277
- folder_types="all",
278
- folder_names=[],
279
- file_names=[],
280
- extensions=[],
281
- with_versions=False,
282
- use_batches_cutoff=500):
293
+
294
+ def bulk_find_files(
295
+ self,
296
+ sample_uuids=[],
297
+ sample_name_includes=[],
298
+ folder_types="all",
299
+ folder_names=[],
300
+ file_names=[],
301
+ extensions=[],
302
+ with_versions=False,
303
+ use_batches_cutoff=500,
304
+ ):
283
305
  """Return a dict with links to download files that match the given criteria.
284
306
 
285
307
  Options:
@@ -291,36 +313,48 @@ class Project(RemoteObject):
291
313
  - extensions: list of strings; finds files with these file extensions
292
314
  - with_versions: bool; if True, include all versions of files in results
293
315
  """
316
+
294
317
  def _my_bulk_find(sample_uuids=None): # curry to save typing
295
- return self._bulk_find_files_batch(sample_uuids=sample_uuids or [],
296
- sample_name_includes=sample_name_includes,
297
- folder_types=folder_types,
298
- folder_names=folder_names,
299
- file_names=file_names,
300
- extensions=extensions,
301
- with_versions=with_versions)
318
+ return self._bulk_find_files_batch(
319
+ sample_uuids=sample_uuids or [],
320
+ sample_name_includes=sample_name_includes,
321
+ folder_types=folder_types,
322
+ folder_names=folder_names,
323
+ file_names=file_names,
324
+ extensions=extensions,
325
+ with_versions=with_versions,
326
+ )
327
+
302
328
  n_samples = len(sample_uuids) if sample_uuids else self.n_samples
303
329
  if n_samples < use_batches_cutoff:
304
330
  logger.debug(f"Using single batch bulk_find for {n_samples} samples")
305
331
  return _my_bulk_find(sample_uuids=sample_uuids)
306
332
  else:
307
333
  logger.debug(f"Using multi batch bulk_find for {n_samples} samples")
308
- merged_response = {'file_size_bytes': 0, 'links': {}, 'no_size_info_count': 0}
309
- for batch in self._batch_sample_uuids(use_batches_cutoff - 1, input_sample_uuids=sample_uuids):
334
+ merged_response = {
335
+ "file_size_bytes": 0,
336
+ "links": {},
337
+ "no_size_info_count": 0,
338
+ }
339
+ for batch in self._batch_sample_uuids(
340
+ use_batches_cutoff - 1, input_sample_uuids=sample_uuids
341
+ ):
310
342
  response = _my_bulk_find(sample_uuids=batch)
311
- merged_response['file_size_bytes'] += response['file_size_bytes']
312
- merged_response['links'].update(response['links'])
313
- merged_response['no_size_info_count'] += response['no_size_info_count']
343
+ merged_response["file_size_bytes"] += response["file_size_bytes"]
344
+ merged_response["links"].update(response["links"])
345
+ merged_response["no_size_info_count"] += response["no_size_info_count"]
314
346
  return merged_response
315
-
316
- def _bulk_find_files_batch(self,
317
- sample_uuids=None,
318
- sample_name_includes=None,
319
- folder_types=None,
320
- folder_names=None,
321
- file_names=None,
322
- extensions=None,
323
- with_versions=False):
347
+
348
+ def _bulk_find_files_batch(
349
+ self,
350
+ sample_uuids=None,
351
+ sample_name_includes=None,
352
+ folder_types=None,
353
+ folder_names=None,
354
+ file_names=None,
355
+ extensions=None,
356
+ with_versions=False,
357
+ ):
324
358
  data = {
325
359
  "sample_uuids": sample_uuids or [],
326
360
  "sample_names": sample_name_includes or [],
@@ -328,22 +362,105 @@ class Project(RemoteObject):
328
362
  "folder_names": folder_names or [],
329
363
  "file_names": file_names or [],
330
364
  "extensions": extensions or [],
331
- "with_versions": with_versions
365
+ "with_versions": with_versions,
332
366
  }
333
367
  url = f"sample_groups/{self.uuid}/download"
334
368
  response = self.knex.post(url, data)
335
369
  return response
336
-
370
+
337
371
  def run_app(self, app: Pipeline, input_parameters=None):
338
372
  """Run an app on this group."""
339
373
  if not input_parameters:
340
374
  input_parameters = app.get_input_parameters()
341
375
  params = {
342
- 'pipeline_id': app.uuid,
343
- 'sample_uuids': list(self.get_sample_uuids()),
344
- 'input_parameters': input_parameters,
376
+ "pipeline_id": app.uuid,
377
+ "sample_uuids": list(self.get_sample_uuids()),
378
+ "input_parameters": input_parameters,
345
379
  }
346
- self.knex.post(f"sample_groups/{self.uuid}/run_app", json=params, json_response=False)
380
+ self.knex.post(
381
+ f"sample_groups/{self.uuid}/run_app", json=params, json_response=False
382
+ )
383
+
384
+ def create_dashboard(self, title="Default dashboard", default=False):
385
+ """Create a dashboard for this project."""
386
+ from geoseeq.dashboard.dashboard import Dashboard
387
+
388
+ post_data = {"name": title, "is_default": default}
389
+ self.knex.post(f"sample_groups/{self.uuid}/dashboard-list", json=post_data)
390
+
391
+ return Dashboard(knex=self.knex, project=self, title=title, default=default)
392
+
393
+ def get_default_dashbaord(self):
394
+ """Get the default dashboard for this project."""
395
+ from geoseeq.dashboard.dashboard import Dashboard, DashboardTile
396
+
397
+ resp = self.knex.get(f"sample_groups/{self.uuid}/dashboard-list")
398
+ try:
399
+ dashboard_name = [
400
+ name
401
+ for name, data in resp["dashboard_data"].items()
402
+ if data["is_default"] == True
403
+ ][0]
404
+ blob = resp["dashboard_data"][dashboard_name]
405
+ tiles = []
406
+ for tile_blob in blob["tiles"]:
407
+ tile = DashboardTile.from_blob(self, tile_blob)
408
+ tiles.append(tile)
409
+ dashboard = Dashboard(
410
+ self.knex,
411
+ project=self,
412
+ title=dashboard_name,
413
+ default=blob["is_default"],
414
+ tiles=tiles,
415
+ )
416
+ return dashboard
417
+ except IndexError:
418
+ logger.warning("Default dashboard not found.")
419
+ pass
420
+ return None
421
+
422
+ def get_or_create_default_dashbaord(self):
423
+ """Get the default dashboard for this project or create it if does not exist."""
424
+ default_dashboard = self.get_default_dashbaord()
425
+ if default_dashboard:
426
+ return default_dashboard
427
+ else:
428
+ return self.create_dashboard(default=True)
429
+
430
+ def get_dashbaord_by_title(self, title):
431
+ """Get dashboard for this project by the title of the dashboard."""
432
+ from geoseeq.dashboard.dashboard import Dashboard, DashboardTile
433
+
434
+ resp = self.knex.get(f"sample_groups/{self.uuid}/dashboard-list")
435
+ try:
436
+ dashboard_name = [
437
+ name for name in resp["dashboard_data"].keys() if name == title
438
+ ][0]
439
+ blob = resp["dashboard_data"][dashboard_name]
440
+ tiles = []
441
+ for tile_blob in blob["tiles"]:
442
+ tile = DashboardTile.from_blob(self, tile_blob)
443
+ tiles.append(tile)
444
+ dashboard = Dashboard(
445
+ knex=self.knex,
446
+ project=self,
447
+ title=dashboard_name,
448
+ default=blob["is_default"],
449
+ tiles=tiles,
450
+ )
451
+ return dashboard
452
+ except IndexError:
453
+ logger.warning(f"Dashboard {title} not found.")
454
+ pass
455
+ return None
456
+
457
+ def get_or_create_dashbaord_by_title(self, title: str):
458
+ """Get dashboard by title for this project or create it if does not exist."""
459
+ default_dashboard = self.get_dashbaord_by_title(title)
460
+ if default_dashboard:
461
+ return default_dashboard
462
+ else:
463
+ return self.create_dashboard(title=title, default=False)
347
464
 
348
465
  def __str__(self):
349
466
  return f"<Geoseeq::Project {self.name} {self.uuid} />"
@@ -353,7 +470,7 @@ class Project(RemoteObject):
353
470
 
354
471
  def pre_hash(self):
355
472
  return "PROJ" + self.name + self.org.pre_hash()
356
-
473
+
357
474
  @property
358
475
  def grn(self):
359
476
  return f"grn::project:{self.uuid}"
@@ -363,4 +480,5 @@ class Project(RemoteObject):
363
480
  self._modified = True
364
481
  return self
365
482
 
366
- SampleGroup = Project # alias for backwards compatibility
483
+
484
+ SampleGroup = Project # alias for backwards compatibility
@@ -233,6 +233,7 @@ class Sample(RemoteObject):
233
233
  return file, blob["read_type"]
234
234
 
235
235
  def create_dashboard(self, title="Default dashboard", default=False):
236
+ "Create a new dashboard for the sample"
236
237
  from geoseeq.dashboard.dashboard import SampleDashboard
237
238
 
238
239
  post_data = {
@@ -249,6 +250,7 @@ class Sample(RemoteObject):
249
250
  return dashboard
250
251
 
251
252
  def get_default_dashbaord(self):
253
+ """Get the default dashboard for this sample."""
252
254
  from geoseeq.dashboard.dashboard import SampleDashboard
253
255
 
254
256
  dashboard_resp = self.knex.get(f"samples/{self.uuid}/dashboards")
@@ -266,6 +268,7 @@ class Sample(RemoteObject):
266
268
  return None
267
269
 
268
270
  def get_or_create_default_dashbaord(self):
271
+ """Get the default dashboard for this sample or create it if does not exist."""
269
272
  default_dashboard = self.get_default_dashbaord()
270
273
  if default_dashboard:
271
274
  return default_dashboard
@@ -273,6 +276,7 @@ class Sample(RemoteObject):
273
276
  return self.create_dashboard(default=True)
274
277
 
275
278
  def get_dashbaord_by_title(self, title):
279
+ """Get dashboard by title for this sample."""
276
280
  from geoseeq.dashboard.dashboard import SampleDashboard
277
281
 
278
282
  dashboard_resp = self.knex.get(f"samples/{self.uuid}/dashboards")
@@ -290,6 +294,7 @@ class Sample(RemoteObject):
290
294
  return None
291
295
 
292
296
  def get_or_create_dashbaord_by_title(self, title):
297
+ """Get dashboard by title for this sample or create it if does not exist."""
293
298
  default_dashboard = self.get_dashbaord_by_title(title)
294
299
  if default_dashboard:
295
300
  return default_dashboard
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "geoseeq"
7
- version = "0.7.3dev1"
7
+ version = "0.7.3dev2"
8
8
  authors = [
9
9
  { name="David C. Danko", email="dcdanko@biotia.io" },
10
10
  ]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes