bfabric-web-apps 0.1.2__py3-none-any.whl → 0.1.3__py3-none-any.whl

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.
@@ -20,6 +20,7 @@ from .utils.callbacks import process_url_and_token, submit_bug_report
20
20
 
21
21
  from .utils import defaults
22
22
 
23
+ from bfabric_web_apps.utils.resource_utilities import create_workunit, create_resource
23
24
  HOST = os.getenv("HOST", defaults.HOST)
24
25
  PORT = int(os.getenv("PORT", defaults.PORT)) # Convert to int since env variables are strings
25
26
  DEV = os.getenv("DEV", str(defaults.DEV)).lower() in ["true", "1", "yes"] # Convert to bool
@@ -46,7 +47,9 @@ __all__ = [
46
47
  'CONFIG_FILE_PATH',
47
48
  'DEVELOPER_EMAIL_ADDRESS',
48
49
  'BUG_REPORT_EMAIL_ADDRESS',
49
- 'create_app_in_bfabric'
50
+ 'create_app_in_bfabric',
51
+ 'create_workunit',
52
+ 'create_resource'
50
53
  ]
51
54
 
52
55
 
@@ -16,6 +16,8 @@ HOST = "fgcz-bfabric.uzh.ch"
16
16
 
17
17
 
18
18
  class BfabricInterface( Bfabric ):
19
+ _instance = None # Singleton instance
20
+ _wrapper = None # Shared wrapper instance
19
21
  """
20
22
  A class to interface with the Bfabric API, providing methods to validate tokens,
21
23
  retrieve data, and send bug reports.
@@ -27,6 +29,30 @@ class BfabricInterface( Bfabric ):
27
29
  """
28
30
  pass
29
31
 
32
+ def __new__(cls, *args, **kwargs):
33
+ """Ensure only one instance exists (Singleton Pattern)."""
34
+ if cls._instance is None:
35
+ cls._instance = super(BfabricInterface, cls).__new__(cls)
36
+ return cls._instance
37
+
38
+ def _initialize_wrapper(self, token_data):
39
+ """Internal method to initialize the Bfabric wrapper after token validation."""
40
+ if not token_data:
41
+ raise ValueError("Token data is required to initialize the wrapper.")
42
+
43
+ # Create and store the wrapper
44
+ if self._wrapper is None:
45
+ self._wrapper = self.token_response_to_bfabric(token_data)
46
+
47
+
48
+ def get_wrapper(self):
49
+ """Return the existing wrapper or raise an error if not initialized."""
50
+ if self._wrapper is None:
51
+ raise RuntimeError("Bfabric wrapper is not initialized. Token validation must run first.")
52
+ return self._wrapper
53
+
54
+
55
+
30
56
  def token_to_data(self, token):
31
57
  """
32
58
  Validates the given token and retrieves its associated data.
@@ -70,6 +96,8 @@ class BfabricInterface( Bfabric ):
70
96
 
71
97
  environment_dict = {"Production":"https://fgcz-bfabric.uzh.ch/bfabric","Test":"https://fgcz-bfabric-test.uzh.ch/bfabric"}
72
98
 
99
+ print('userinfo', userinfo)
100
+
73
101
  token_data = dict(
74
102
  environment = userinfo['environment'],
75
103
  user_data = userinfo['user'],
@@ -83,6 +111,9 @@ class BfabricInterface( Bfabric ):
83
111
  jobId = userinfo['jobId']
84
112
  )
85
113
 
114
+ # Initialize the wrapper right after validating the token
115
+ self._initialize_wrapper(token_data)
116
+
86
117
  return json.dumps(token_data)
87
118
 
88
119
 
@@ -133,7 +164,7 @@ class BfabricInterface( Bfabric ):
133
164
  if not token_data:
134
165
  return json.dumps({})
135
166
 
136
- wrapper = self.token_response_to_bfabric(token_data)
167
+ wrapper = self.get_wrapper()
137
168
  entity_class = token_data.get('entityClass_data', None)
138
169
  endpoint = entity_class_map.get(entity_class, None)
139
170
  entity_id = token_data.get('entity_id_data', None)
@@ -209,7 +240,7 @@ class BfabricInterface( Bfabric ):
209
240
  L = get_logger(token_data)
210
241
 
211
242
  # Get API wrapper
212
- wrapper = self.token_response_to_bfabric(token_data) # Same as entity_data
243
+ wrapper = self.get_wrapper()
213
244
  if not wrapper:
214
245
  print("Failed to get Bfabric API wrapper")
215
246
  return json.dumps({})
@@ -234,9 +265,11 @@ class BfabricInterface( Bfabric ):
234
265
  )
235
266
  return json.dumps({})
236
267
 
237
- # Extract Name and Description
268
+ # Extract App ID, Name, and Description
238
269
  app_info = app_data_dict[0] # First (and only) result
270
+ print('app_info', app_info)
239
271
  json_data = json.dumps({
272
+ "id": app_info.get("id", "Unknown"),
240
273
  "name": app_info.get("name", "Unknown"),
241
274
  "description": app_info.get("description", "No description available")
242
275
  })
@@ -283,3 +316,7 @@ class BfabricInterface( Bfabric ):
283
316
 
284
317
 
285
318
 
319
+ # Create a globally accessible instance
320
+ bfabric_interface = BfabricInterface()
321
+
322
+
@@ -0,0 +1,218 @@
1
+ from bfabric_web_apps.utils.get_logger import get_logger
2
+ from bfabric_web_apps.objects.BfabricInterface import bfabric_interface
3
+ from bfabric_web_apps.utils.get_power_user_wrapper import get_power_user_wrapper
4
+ from bfabric_scripts.bfabric_upload_resource import bfabric_upload_resource
5
+ from pathlib import Path
6
+
7
+ def create_workunit(token_data, application_name, application_description, application_id, container_ids):
8
+ """
9
+ Create a new workunit in B-Fabric for each container ID.
10
+
11
+ Args:
12
+ token_data (dict): Authentication token data.
13
+ application_name (str): Name of the application.
14
+ application_description (str): Description of the application.
15
+ application_id (int): Application ID.
16
+ container_ids (list): List of container IDs.
17
+
18
+ Returns:
19
+ list: List of created workunit IDs.
20
+ """
21
+ L = get_logger(token_data)
22
+ wrapper = bfabric_interface.get_wrapper()
23
+ workunit_ids = []
24
+
25
+ # Ensure container_ids is a list
26
+ if not isinstance(container_ids, list):
27
+ container_ids = [container_ids] # Convert to list if single value
28
+
29
+ for container_id in container_ids:
30
+ workunit_data = {
31
+ "name": f"{application_name} - Order {container_id}",
32
+ "description": f"{application_description} for Order {container_id}",
33
+ "applicationid": int(application_id),
34
+ "containerid": container_id, # Assigning order ID dynamically
35
+ }
36
+
37
+ try:
38
+ workunit_response = L.logthis(
39
+ api_call=wrapper.save,
40
+ endpoint="workunit",
41
+ obj=workunit_data,
42
+ params=None,
43
+ flush_logs=True
44
+ )
45
+ workunit_id = workunit_response[0].get("id")
46
+ print(f"Created Workunit ID: {workunit_id} for Order ID: {container_id}")
47
+ workunit_ids.append(workunit_id)
48
+
49
+ except Exception as e:
50
+ L.log_operation(
51
+ "Error",
52
+ f"Failed to create workunit for Order {container_id}: {e}",
53
+ params=None,
54
+ flush_logs=True,
55
+ )
56
+ print(f"Failed to create workunit for Order {container_id}: {e}")
57
+
58
+ return workunit_ids # Returning a list of all created workunits
59
+
60
+
61
+ def create_resource(token_data, workunit_id, gz_file_path):
62
+ """
63
+ Upload a .gz resource to an existing B-Fabric workunit.
64
+
65
+ Args:
66
+ token_data (dict): Authentication token data.
67
+ workunit_id (int): ID of the workunit to associate the resource with.
68
+ gz_file_path (str): Full path to the .gz file to upload.
69
+
70
+ Returns:
71
+ int: Resource ID if successful, None otherwise.
72
+ """
73
+ L = get_logger(token_data)
74
+ wrapper = get_power_user_wrapper(token_data)
75
+
76
+ try:
77
+ file_path = Path(gz_file_path)
78
+
79
+ # Use the proper upload function
80
+ print("test", wrapper, file_path, workunit_id)
81
+ result = bfabric_upload_resource(wrapper, file_path, workunit_id)
82
+
83
+ if result:
84
+ print(f"Resource uploaded: {file_path.name}")
85
+ L.log_operation(
86
+ "upload_resource",
87
+ f"Resource uploaded successfully: {file_path.name}",
88
+ params=None,
89
+ flush_logs=True,
90
+ )
91
+ return result
92
+ else:
93
+ raise ValueError(f"Failed to upload resource: {file_path.name}")
94
+
95
+ except Exception as e:
96
+ L.log_operation(
97
+ "error",
98
+ f"Failed to upload resource: {e}",
99
+ params=None,
100
+ flush_logs=True,
101
+ )
102
+ print(f"Failed to upload resource: {e}")
103
+ return None
104
+
105
+
106
+
107
+ '''
108
+
109
+
110
+
111
+ # Upload a resource to the created workunit
112
+ resource_name = "example_resource.txt"
113
+ resource_content = b"This is an example resource content."
114
+
115
+ try:
116
+ resource_response = bfabric.upload_resource(
117
+ resource_name=resource_name,
118
+ content=resource_content,
119
+ workunit_id=workunit_id
120
+ )
121
+ print(f"Resource '{resource_name}' uploaded successfully.")
122
+ except Exception as e:
123
+ print(f"Failed to upload resource: {e}")
124
+ exit(1)
125
+
126
+
127
+
128
+
129
+
130
+
131
+
132
+
133
+
134
+ import subprocess
135
+ from zeep import Client
136
+ import os
137
+ from bfabric_web_apps.utils.get_logger import get_logger
138
+
139
+ BFABRIC_WORKUNIT_WSDL = "https://fgcz-bfabric-test.uzh.ch:443/bfabric/workunit?wsdl"
140
+ BFABRIC_RESOURCE_WSDL = "https://fgcz-bfabric-test.uzh.ch:443/bfabric/resource?wsdl"
141
+
142
+ def run_pipeline_and_register_in_bfabric(run_name: str, output_dir: str):
143
+ """
144
+ Startet die Nextflow-Pipeline und speichert die Ergebnisse in B-Fabric.
145
+
146
+ :param run_name: Name des Sequenzierungslaufs
147
+ :param output_dir: Verzeichnis, in dem die FASTQ-Dateien gespeichert werden
148
+ """
149
+ print(f"[INFO] Starte Nextflow-Pipeline für {run_name}...")
150
+
151
+ # Nextflow Pipeline starten
152
+ process = subprocess.run([
153
+ "nextflow", "run", "nf-core/bclconvert",
154
+ "-profile", "docker",
155
+ "--outdir", output_dir,
156
+ "-resume"
157
+ ], capture_output=True, text=True)
158
+
159
+ if process.returncode != 0:
160
+ print(f"[ERROR] Nextflow Pipeline fehlgeschlagen: {process.stderr}")
161
+ return False
162
+
163
+ print(f"[INFO] Pipeline abgeschlossen. Ergebnisse werden registriert...")
164
+
165
+ # Workunit in B-Fabric anlegen
166
+ workunit_id = create_bfabric_workunit(run_name)
167
+
168
+ # Falls Workunit erfolgreich erstellt, dann Ressourcen speichern
169
+ if workunit_id:
170
+ register_fastq_files_in_bfabric(output_dir, workunit_id)
171
+ else:
172
+ print("[ERROR] Konnte Workunit nicht in B-Fabric registrieren!")
173
+
174
+ return True
175
+
176
+ def create_bfabric_workunit(run_name: str):
177
+ """Erstellt eine Workunit in B-Fabric."""
178
+ try:
179
+ client = Client(BFABRIC_WORKUNIT_WSDL)
180
+ workunit_data = {
181
+ "name": run_name,
182
+ "description": "Illumina BCL zu FASTQ Konvertierung",
183
+ "status": "Completed"
184
+ }
185
+ L = get_logger({})
186
+ response = L.logthis(
187
+ api_call=client.service.createWorkunit,
188
+ obj=workunit_data
189
+ )[0]
190
+ print(f"[INFO] Workunit erstellt mit ID: {response}")
191
+ return response
192
+ except Exception as e:
193
+ print(f"[ERROR] Fehler beim Erstellen der Workunit: {e}")
194
+ return None
195
+
196
+ def register_fastq_files_in_bfabric(output_dir: str, workunit_id: int):
197
+ """Registriert alle FASTQ-Dateien aus dem Output-Verzeichnis in B-Fabric."""
198
+ try:
199
+ client = Client(BFABRIC_RESOURCE_WSDL)
200
+ L = get_logger({})
201
+ for file_name in os.listdir(output_dir):
202
+ if file_name.endswith(".fastq.gz"):
203
+ file_path = os.path.join(output_dir, file_name)
204
+ resource_data = {
205
+ "name": file_name,
206
+ "description": "Erzeugt von nf-core/bclconvert",
207
+ "path": file_path,
208
+ "type": "FASTQ",
209
+ "workunitId": workunit_id
210
+ }
211
+ response = L.logthis(
212
+ api_call=client.service.createResource,
213
+ obj=resource_data
214
+ )[0]
215
+ print(f"[INFO] Ressource gespeichert mit ID: {response}")
216
+ except Exception as e:
217
+ print(f"[ERROR] Fehler beim Registrieren der Ressourcen: {e}")
218
+ '''
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bfabric-web-apps
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: A package containing handy boilerplate utilities for developing bfabric web-applications
5
5
  Author: Marc Zuber, Griffin White, GWC GmbH
6
6
  Requires-Python: >=3.8,<4.0
@@ -1,6 +1,6 @@
1
- bfabric_web_apps/__init__.py,sha256=zZvM0CQPkiu0y9xOZos-d2hK-h6erc8K_nov7vD1bdE,2362
1
+ bfabric_web_apps/__init__.py,sha256=xqh-kddXaV4xblnMcDA73bTuy3zn5viucueuuIx41HM,2495
2
2
  bfabric_web_apps/layouts/layouts.py,sha256=XoSLcQPcgMBhQz2VfxkUzNL23FLBXFRFvbCL2mNLfnk,11636
3
- bfabric_web_apps/objects/BfabricInterface.py,sha256=nRdU_cYLW2_xp2x1cvP9b30gQ5blavbOz66B-Hi6UZQ,8980
3
+ bfabric_web_apps/objects/BfabricInterface.py,sha256=YC6VimARZfG2t90TK5xhQDsNzgMNljwqbCOT8Qz_Uhs,10247
4
4
  bfabric_web_apps/objects/Logger.py,sha256=62LC94xhm7YG5LUw3yH46NqvJQsAX7wnc9D4zbY16rA,5224
5
5
  bfabric_web_apps/utils/app_init.py,sha256=RCdpCXp19cF74bouYJLPe-KSETZ0Vwqtd02Ta2VXEF8,428
6
6
  bfabric_web_apps/utils/callbacks.py,sha256=PiP1ZJ-QxdrOAZ-Mt-MN-g9wJLSOoLkWkXwPq_TLqDI,6472
@@ -9,7 +9,8 @@ bfabric_web_apps/utils/create_app_in_bfabric.py,sha256=eVk3cQDXxW-yo9b9n_zzGO6kL
9
9
  bfabric_web_apps/utils/defaults.py,sha256=B82j3JEbysLEU9JDZgoDBTX7WGvW3Hn5YMZaWAcjZew,278
10
10
  bfabric_web_apps/utils/get_logger.py,sha256=0Y3SrXW93--eglS0_ZOc34NOriAt6buFPik5n0ltzRA,434
11
11
  bfabric_web_apps/utils/get_power_user_wrapper.py,sha256=T33z64XjmJ0KSlmfEmrEP8eYpbpINCVD6Xld_V7PR2g,1027
12
- bfabric_web_apps-0.1.2.dist-info/LICENSE,sha256=k0O_i2k13i9e35aO-j7FerJafAqzzu8x0kkBs0OWF3c,1065
13
- bfabric_web_apps-0.1.2.dist-info/METADATA,sha256=tvvoNH4-tMyPbWJdoe_pVgC_cDzQpDzdGtqd49vt9QI,480
14
- bfabric_web_apps-0.1.2.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
15
- bfabric_web_apps-0.1.2.dist-info/RECORD,,
12
+ bfabric_web_apps/utils/resource_utilities.py,sha256=AVaqIXEfmCdWZfXDt32QfkZ9ChTL8D8cm1lCHXfT4Nc,7317
13
+ bfabric_web_apps-0.1.3.dist-info/LICENSE,sha256=k0O_i2k13i9e35aO-j7FerJafAqzzu8x0kkBs0OWF3c,1065
14
+ bfabric_web_apps-0.1.3.dist-info/METADATA,sha256=gTd86dYPrHKfypKFPry0SKjYtydW1z17fA-tSxz8vuM,480
15
+ bfabric_web_apps-0.1.3.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
16
+ bfabric_web_apps-0.1.3.dist-info/RECORD,,