diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..6d5f0e5 Binary files /dev/null and b/.DS_Store differ diff --git a/claude/skills/notebook-cleanup/SKILL.md b/claude/skills/notebook-cleanup/SKILL.md new file mode 100644 index 0000000..ea98a10 --- /dev/null +++ b/claude/skills/notebook-cleanup/SKILL.md @@ -0,0 +1,158 @@ +--- + name: notebook-cleanup + description: Clears all JupyterLab notebook cell outputs, lints code and structure, and generates HTML snapshots for review. HTML snapshots are committed to the repo in a directory mirroring the notebook's location. + + --- + + # Notebook Cleanup Skill + + Clean up and lint JupyterLab notebooks for commit by clearing all cell outputs, validating code quality and notebook structure, and generating HTML snapshots for reviewer convenience. + + ## Behavior + + When invoked, this skill will: + + 1. **Discover notebooks** — Find all `.ipynb` files that have been modified (staged or unstaged) in the current Git repository, comparing the changes on the existing branch to the main branch. You should ask the user to confirm the notebooks before proceeding with any changes. If no modified notebooks are found, scan the entire repo and prompt the user to select which notebooks to clean. + + 2. **Detect notebook language** — Read the notebook's kernel metadata to determine the language (Python, R, etc.) and apply language-appropriate linting rules. + + 3. **Lint code cells** — Analyze all code cells for quality issues appropriate to the detected language: + - Unused imports or library loads + - Undefined or shadowed variables + - Style violations (naming conventions, line length, whitespace) + - Invalid syntax + - Hardcoded credentials + - No empty cells + Report findings with cell numbers and suggested fixes + + 4. **Validate standards compliance** — Check adherence to PR standards: + - No cell outputs present in the committed `.ipynb` file + - No data files staged for commit unless publicly available + - Jira ticket referenced in the notebook or PR description + + 5. **Generate HTML snapshots** — For each notebook, export an HTML snapshot before clearing outputs. Store the HTML file in a `notebook-snapshots` directory that mirrors the notebook's relative path in the repo. For example: + - `src/analysis/exploration.ipynb` → `.notebook-snapshots/src/analysis/exploration.html` + + 6. **Ensure provenance and copyright boilerplate** — Check that the notebook ends with the required boilerplate cells. If missing, append them. For Python notebooks, + the provenance section includes: + + **Markdown cell:** + Provenance + + Generate information about this notebook environment and the packages installed. + + **Code cell:** `!date` + + **Markdown cell:** `Conda and pip installed packages:` + + **Code cell:** `!conda env export` + + **Markdown cell:** `JupyterLab extensions:` + + **Code cell:** `!jupyter labextension list` + + **Markdown cell:** `Number of cores:` + + **Code cell:** `!grep ^processor /proc/cpuinfo | wc -l` + + **Markdown cell:** `Memory:` + + **Code cell:** `!grep "^MemTotal:" /proc/meminfo` + + **Markdown cell (copyright):** + --- Copyright Verily Life Sciences LLC + + Use of this source code is governed by a BSD-style + license that can be found in the LICENSE file or at + https://developers.google.com/open-source/licenses/bsd + + For non-Python notebooks, only the copyright cell is appended (provenance cells are skipped). + + 6. **Ensure provenance and copyright boilerplate** — Check that the notebook ends with the required boilerplate cells. If missing, append them. For Python notebooks, the provenance section includes: + + **Markdown cell:** + Provenance + + Generate information about this notebook environment and the packages installed. + + **Code cell:** `!date` + + **Markdown cell:** `Conda and pip installed packages:` + + **Code cell:** `!conda env export` + + **Markdown cell:** `JupyterLab extensions:` + + **Code cell:** `!jupyter labextension list` + + **Markdown cell:** `Number of cores:` + + **Code cell:** `!grep ^processor /proc/cpuinfo | wc -l` + + **Markdown cell:** `Memory:` + + **Code cell:** `!grep "^MemTotal:" /proc/meminfo` + + **Markdown cell (copyright):** + --- Copyright Verily Life Sciences LLC + + Use of this source code is governed by a BSD-style + license that can be found in the LICENSE file or at + https://developers.google.com/open-source/licenses/bsd + + For non-Python notebooks, only the copyright cell is appended (provenance cells are skipped). + + 7. **Generate HTML snapshots** — For each notebook, export an HTML snapshot **before** clearing outputs. Store the HTML file in a `notebook-snapshots/` directory that mirrors the notebook's relative path in the repo. For example: + `src/analysis/exploration.ipynb` → `notebook-snapshots/src/analysis/exploration.html` + + 8. **Clear cell outputs** — Strip all cell outputs and execution counts from each `.ipynb` file in place, preserving the notebook structure and source code. + + 9. **Stage snapshot files** — Add the generated HTML snapshots to the Git staging area alongside the cleaned notebooks so they are included in the commit. + + 10. **Report results** — Summarize linting findings, what was cleaned, and where HTML snapshots were saved. + + ## Usage + + Invoke this skill when: + - Preparing notebooks for a pull request + - The user asks to clean, lint, or prepare notebooks for commit + + ## Requirements + + - The working directory must be within a Git repository + + ## Example + + User calls: /notebook-cleanup + + **Output:** + Linting 3 notebooks... + + src/analysis/exploration.ipynb: + ⚠ Cell 3: unused import 'pandas as pd' (never referenced) + ✓ Structure: title present, markdown sections found + + src/analysis/validation.ipynb: + ✓ Code: no issues found + ✓ Structure: title present, markdown sections found + + src/models/training_run.ipynb: + ✓ Code: no issues found + ⚠ Structure: no markdown heading in first cell + ⚠ Structure: empty cell at position 5 + + Standards compliance: + ✓ No data files staged + ⚠ No Jira ticket reference found — ensure it is included in the PR description + + Cleaned 3 notebooks (outputs cleared): + - src/analysis/exploration.ipynb + - src/analysis/validation.ipynb + - src/models/training_run.ipynb + + HTML snapshots saved to notebook-snapshots/: + - notebook-snapshots/src/analysis/exploration.html + - notebook-snapshots/src/analysis/validation.html + - notebook-snapshots/src/models/training_run.html + + All files staged for commit. Confirm with user if they would like the linting fixes to be made. \ No newline at end of file diff --git a/first_hour_on_vwb/creating_a_data_collection.ipynb b/first_hour_on_vwb/creating_a_data_collection.ipynb index 7f782df..3d7463c 100644 --- a/first_hour_on_vwb/creating_a_data_collection.ipynb +++ b/first_hour_on_vwb/creating_a_data_collection.ipynb @@ -182,6 +182,7 @@ " self.input_name = wu.TextInputWidget(\"\",\"Workspace Name:\").get()\n", " self.input_description = wu.TextInputWidget(\"\",\"Description:\").get()\n", " self.input_workspace_id = wu.TextInputWidget(\"\",\"Workspace ID:\").get()\n", + " self.input_pod = wu.TextInputWidget(\"\",\"Pod ID:\").get()\n", " self.output_workspace_id = widgets.Text()\n", " self.output_workspace_id.value = self.input_workspace_id.value\n", " self.button = wu.StyledButton('Create workspace','Click to create a new workspace','plus').get()\n", @@ -190,7 +191,7 @@ " self.vb = widgets.VBox(\n", " children = [self.label, self.warning,\n", " self.input_name, self.input_description,\n", - " self.input_workspace_id,\n", + " self.input_workspace_id, self.input_pod,\n", " self.button, self.output],\n", " layout = wu.vbox_layout)\n", " \n", @@ -204,6 +205,7 @@ " f\"--id={self.input_workspace_id.value.strip()}\",\n", " f\"--description={self.input_description.value.strip()}\",\n", " f\"--name={self.input_name.value.strip()}\",\n", + " f\"--pod={self.input_pod.value.strip()}\",\n", " ]\n", " print('Running command to create workspace...')\n", " print('\\n'.join(createWorkspaceCommandList))\n", @@ -222,19 +224,20 @@ "tags": [] }, "source": [ - "### Convert new workspace to data collection\n", - "\n", + "### Create a new data collection\n", + "\n", "\n", - "Now you'll convert your newly created workspace, to which you have added resources, into a data collection which can be shared with others and added to other workspaces. \n", - "Run the cell below to create a widget, then populate the widget's input fields and click the button to convert the workspace to a data collection. Please note that until you publish a version in the next section, your data collection will not appear in the data catalog.\n", + "Now you'll create a new data collection which can be shared with others and added to other workspaces. \n", + "Run the cell below to create a widget, then populate the widget's input fields and click the button to create a data collection. Please note that until you publish a version in the next section, your data collection will not appear in the data catalog.\n", "\n", "Widget input parameters include:\n", - "- `Workspace ID`: Automatically populated with the workspace ID of the workspace created in the previous step.\n", + "- `Workspace Name`: Must be a string. This value is displayed in the Data Collection modal once the workspace is converted to a data collection, so the value should communicate the intended purpose (e.g. ` Data Collection`).
While the Workbench UI and this widget require a workspace name to be provided, the CLI does not; if no workspace name is provided to the CLI, a UUID is generated instead.\n", + "- `Workspace ID`: Must be unique and consist only of lowercase letters, numbers and underscores. Provide a workspace ID that suggests something about the contents of the data collection you'd like to create and include the date of its creation, such as `__dc_ws`. *You cannot change the workspace ID after workspace creation.* \n", "- `Short Description`: Must be a string. This description will be visible in the Add a Data Collection modal and should summarize the purpose and/or contents of your data collection.\n", "\n", "The output should resemble:\n", "```\n", - "Workspace properties successfully updated.\n", + "Workspace successfully created.\n", "ID: __dc_ws\n", "Name: -Data-\n", "Description: \n", @@ -247,7 +250,6 @@ "Created: YYYY-MM-DD\n", "Last updated: YYYY-MM-DD\n", "# Resources: \n", - "Workspace properties successfully updated.\n", "```" ] }, @@ -259,53 +261,46 @@ }, "outputs": [], "source": [ - "class ConvertToDataCollectionWidget(object):\n", + "class CreateDataCollectionWidget(object):\n", " def __init__(self,prev_widget):\n", " self.label = widgets.Label(value = 'Please provide appropriate values in the input boxes.')\n", - " self.workspace_ids = self.get_workspace_ids()\n", - " self.new_ws_id = prev_widget.get_workspace_id();\n", - " self.input_workspace_id = wu.DropdownInputWidget([self.new_ws_id],self.new_ws_id,\"Workspace ID:\").get()\n", + " self.input_name = wu.TextInputWidget(\"\",\"Data Collection Name:\").get()\n", + " self.input_data_collection_id = wu.TextInputWidget(\"\",\"Data Collection ID:\").get()\n", + " self.input_pod = wu.TextInputWidget(\"\",\"Pod ID:\").get()\n", " self.input_short_description = wu.TextInputWidget(\"\",\"Short Description:\").get()\n", - " self.button = wu.StyledButton('Convert to data collection','Click to convert to data collection','check').get()\n", - " self.button.on_click(self.convert_to_data_collection)\n", + " self.button = wu.StyledButton('Create data collection','Click to create data collection','check').get()\n", + " self.button.on_click(self.create_data_collection)\n", " self.output = widgets.Output()\n", " self.vb = widgets.VBox([\n", " self.label,\n", - " self.input_workspace_id,\n", + " self.input_data_collection_id,\n", " self.input_short_description,\n", + " self.input_pod,\n", + " self.input_name,\n", " self.button,\n", " self.output\n", " ], layout=wu.vbox_layout)\n", - " \n", + "\n", + "\n", " def get_workspace_id(self):\n", " return self.input_workspace_id.value.strip()\n", - "\n", - " def get_workspace_ids(self):\n", - " result = subprocess.run([\"wb\",\"workspace\",\"list\",\"--format=JSON\"],capture_output=True,text=True)\n", - " ids_list = wu.list_workspace_ids(result.stdout)\n", - " # Insert empty string to display as value of dropdown until changed by user.\n", - " ids_list.insert(0, \" \")\n", - " return ids_list\n", " \n", - " def convert_to_data_collection(self,b):\n", - " workspace_id = self.input_workspace_id.value\n", + " \n", + " def create_data_collection(self,b):\n", " short_desc = self.input_short_description.value\n", " with self.output:\n", - " prettyConvertToDataCollectionCommand = f\"\"\"wb workspace set-property \\\\\n", - " --workspace={workspace_id} \\\\\n", - " --properties=\\\"terra-type=data-collection,terra-workspace-short-description={short_desc}\\\"\n", - " \"\"\"\n", - " print(\"Running command to convert workspace to data collection...\")\n", - " print(prettyConvertToDataCollectionCommand)\n", + " print(\"Running command to create data collection...\")\n", " print(\"Your data collection will be ready in less than one minute...\")\n", - " result = subprocess.run([\"wb\",\"workspace\",\"set-property\",\n", - " f\"--workspace={workspace_id}\",\n", + " result = subprocess.run([\"wb\",\"workspace\",\"create\",\n", + " f\"--id={self.input_data_collection_id.value.strip()}\",\n", + " f\"--name={self.input_name.value.strip()}\",\n", + " f\"--pod={self.input_pod.value.strip()}\",\n", " f\"--properties=terra-type=data-collection,terra-workspace-short-description={short_desc}\"],\n", " capture_output=True,text=True)\n", " print(result.stderr) if not result.stdout else print(result.stdout)\n", "\n", - "convert_to_dc_widget = ConvertToDataCollectionWidget(create_ws_widget)\n", - "display(convert_to_dc_widget.vb)" + "create_dc_widget = CreateDataCollectionWidget(create_ws_widget)\n", + "display(create_dc_widget.vb)" ] }, { @@ -429,7 +424,7 @@ " publishVersionResult = subprocess.run(publishVersionCommand, shell = True, capture_output = True, text = True, check = True)\n", " print(publishVersionResult.stderr) if not publishVersionResult.stdout else print(publishVersionResult.stdout)\n", "\n", - "publish_version_widget = PublishVersionWidget(convert_to_dc_widget)\n", + "publish_version_widget = PublishVersionWidget(create_dc_widget)\n", "display(publish_version_widget.vb)" ] }, @@ -683,13 +678,6 @@ "license that can be found in the LICENSE file or at \n", "https://developers.google.com/open-source/licenses/bsd" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/first_hour_on_vwb/working_with_bq_resources.ipynb b/first_hour_on_vwb/working_with_bq_resources.ipynb index 6a6abf0..702b220 100644 --- a/first_hour_on_vwb/working_with_bq_resources.ipynb +++ b/first_hour_on_vwb/working_with_bq_resources.ipynb @@ -73,43 +73,7 @@ "tags": [] }, "outputs": [], - "source": [ - "from IPython.display import display, HTML\n", - "import ipywidgets as widgets\n", - "import json\n", - "import pandas as pd\n", - "import pandas_gbq\n", - "import os\n", - "import subprocess\n", - "import widget_utils as wu\n", - "\n", - "'''\n", - "Resolves bucket URL from bucket reference in workspace.\n", - "'''\n", - "def get_bucket_url_from_reference(resource_id):\n", - " BUCKET_CMD_OUTPUT = !wb resolve --name={bucket_reference}\n", - " BUCKET = BUCKET_CMD_OUTPUT[0]\n", - " return BUCKET\n", - "\n", - "'''\n", - "Resolves BigQuery dataset from a reference in workspace.\n", - "'''\n", - "def get_bq_dataset_from_reference(resource_id):\n", - " BQ_CMD_OUTPUT = !wb resolve --id={resource_id}\n", - " BQ_DATASET = BQ_CMD_OUTPUT[0]\n", - " return BQ_DATASET\n", - "\n", - "'''\n", - "Resolves current workspace ID from workspace description.\n", - "'''\n", - "def get_current_workspace_id():\n", - " WORKSPACE_CMD_OUTPUT = !wb workspace describe --format=json | jq --raw-output \".id\"\n", - " WORKSPACE_ID = WORKSPACE_CMD_OUTPUT[0]\n", - " return WORKSPACE_ID\n", - "\n", - "CURRENT_WORKSPACE_ID = get_current_workspace_id()\n", - "print(f'Workspace ID: {CURRENT_WORKSPACE_ID}')" - ] + "source": "import pandas as pd\nimport pandas_gbq\n\n'''\nResolves bucket URL from bucket reference in workspace.\n'''\ndef get_bucket_url_from_reference(bucket_reference):\n BUCKET_CMD_OUTPUT = !wb resolve --name={bucket_reference}\n BUCKET = BUCKET_CMD_OUTPUT[0]\n return BUCKET\n\n'''\nResolves current workspace ID from workspace description.\n'''\ndef get_current_workspace_id():\n WORKSPACE_CMD_OUTPUT = !wb workspace describe --format=json | jq --raw-output \".id\"\n WORKSPACE_ID = WORKSPACE_CMD_OUTPUT[0]\n return WORKSPACE_ID\n\nCURRENT_WORKSPACE_ID = get_current_workspace_id()\nprint(f'Workspace ID: {CURRENT_WORKSPACE_ID}')" }, { "cell_type": "markdown", @@ -219,7 +183,12 @@ }, "outputs": [], "source": [ - "%bigquery_stats bigquery-public-data.human_genome_variants.1000_genomes_pedigree" + "from google.cloud import bigquery\n", + "client = bigquery.Client()\n", + "table = client.get_table(\"bigquery-public-data.human_genome_variants.1000_genomes_pedigree\")\n", + "print(f\"Rows: {table.num_rows}, Size: {table.num_bytes} bytes\")\n", + "for field in table.schema:\n", + " print(f\" {field.name}: {field.field_type}\")" ] }, { @@ -233,6 +202,15 @@ "Run the cell below to total the number of distinct families represented in the 1000 Genomes dataset." ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext google.cloud.bigquery" + ] + }, { "cell_type": "code", "execution_count": null, @@ -474,4 +452,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/first_hour_on_vwb/working_with_groups.ipynb b/first_hour_on_vwb/working_with_groups.ipynb index 55fe603..cba5b93 100644 --- a/first_hour_on_vwb/working_with_groups.ipynb +++ b/first_hour_on_vwb/working_with_groups.ipynb @@ -67,20 +67,12 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": { "tags": [] }, "outputs": [], - "source": [ - "from IPython.display import display, HTML\n", - "from typing import List\n", - "import csv\n", - "import widget_utils as wu\n", - "import vwb_org_group_utils as vogu\n", - "import ipywidgets as widgets\n", - "import subprocess" - ] + "source": "from IPython.display import display, HTML\nimport csv\nimport widget_utils as wu\nimport vwb_org_group_utils as vogu\nimport ipywidgets as widgets\nimport subprocess" }, { "cell_type": "markdown", @@ -96,25 +88,12 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": { "scrolled": true, "tags": [] }, - "outputs": [ - { - "data": { - "text/html": [ - "
NAMECURRENT_USER_ROLES
3p-sensors-workspace-write['ADMIN']
aou-drc-gcp-pod['MEMBER']
aou-initial-credit-stable-pod['MEMBER']
aou-stable-rt['ADMIN', 'MEMBER']
cdm-adhd-owner['MEMBER']
cdm-demo-1-ws-owners['MEMBER']
cdm-demo-1-ws-writers['MEMBER']
cdm-sjogren-owner['MEMBER']
cdm-workspace-write['ADMIN']
colgate-ohs-vwb-dd-owners['MEMBER']
colgate-ohs-vwb-demo-ws-owners['ADMIN']
colgate-ohs-vwb-demo-ws-readers['ADMIN']
csp-colgate-ohs-prod-prescreen-screen-owners['MEMBER']
csp-colgate-ohs-prod-prescreen-screen-readers['MEMBER']
csp-colgate-ohs-readers['MEMBER']
dd-prod-vwb['ADMIN']
demo-1-ws-writers['MEMBER']
demo-gcp-pod['MEMBER']
developer-admins['ADMIN']
emmarogge['ADMIN', 'MEMBER']
fraud-model-workspace-write['ADMIN']
gsk-ip-users['ADMIN']
gsk-users['ADMIN']
hhr-internal-users['ADMIN']
huji-users['ADMIN']
jiksak-users['ADMIN']
kyverna-users['ADMIN']
mayo-clinic-users['ADMIN']
michaeljfox-users['ADMIN']
ml-infra-gcp-pod['MEMBER']
ml-ops-breakglass['MEMBER']
nashbio-users['ADMIN']
nashvillebiosciences-users['ADMIN']
onduo-zus-workspace-write['ADMIN']
otsuka-users['ADMIN']
oxford-imcm-gcp-pod['MEMBER']
php-integrations['ADMIN']
polytechnique-users['ADMIN']
post-ov-verifiers['ADMIN']
roche-users['ADMIN']
rometx-ip-users['ADMIN']
rrwd_ds_mimic['ADMIN']
sean-test-users['ADMIN']
tecnico-lisboa-users['ADMIN']
terra-users-devel-shadow['ADMIN']
ucsd-users['ADMIN']
umich-users['ADMIN']
unruh-users['ADMIN']
utsw-workspace-write['ADMIN']
verily-aod-owner['ADMIN', 'MEMBER']
verily-org['MEMBER']
verily-published-data-pod-admins['ADMIN']
verily-published-data-pod-users['ADMIN']
verily-sandbox-pod['MEMBER']
verily-users['ADMIN', 'MEMBER']
verilystudies-test-gcp-pod['MEMBER']
vphp-dd-eng['ADMIN']
vphp-ml-ops['ADMIN']
vumc-early-adopters['ADMIN', 'MEMBER']
vwb-eng-gcp-pod['MEMBER']
vwb-public-data-owners['ADMIN', 'MEMBER']
vwb-public-data-readers['ADMIN', 'MEMBER']
vwb-solutions-team['ADMIN', 'MEMBER']
vwb_support_candidates['MEMBER']
vwb_support_candidates_preprod['ADMIN']
vwb_wbadmin_candidates['MEMBER']
wastewater-test-bucket-dc-reader['ADMIN', 'MEMBER']
workbench-audit-trail-M1-readers['ADMIN', 'MEMBER']
workbench-superadmins-prod['ADMIN']
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "result = subprocess.run(['wb','group','list','--format=JSON'],capture_output=True,text=True)\n", "print(result.stderr) if not result.stdout else display(HTML(wu.list_legacy_groups(result.stdout)))" @@ -133,27 +112,12 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": { "scrolled": true, "tags": [] }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "f58032f10c2542f98109290ea4a4833f", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "VBox(children=(Label(value='Please provide the name for a Verily Workbench group.'), Text(value='', descriptio…" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "class ListMembersWidget(object):\n", " def __init__(self):\n", @@ -168,7 +132,7 @@ " def list_members(self,b):\n", " self.output.clear_output()\n", " with self.output:\n", - " wb_command = [\"wb\",\"group\",\"list-users\",f\"--name={self.input_group_name.value}\",\"--format=JSON\"]\n", + " wb_command = [\"wb\",\"group\",\"role\",\"list\",f\"--name={self.input_group_name.value}\",\"--format=JSON\"]\n", " result = subprocess.run(wb_command,capture_output=True,text=True)\n", " if not result.stdout:\n", " self.output.append_display_data(result.stderr)\n", @@ -191,27 +155,12 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": { "scrolled": true, "tags": [] }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "9cd7c147415a4dfbb9ebc98c8bca2dc9", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "VBox(children=(Label(value='Please provide the org ID for a Verily Workbench org.'), Text(value='', descriptio…" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "class ListOrgGroupsWidget(object):\n", " def __init__(self):\n", @@ -251,27 +200,12 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": { "scrolled": true, "tags": [] }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "ba1659baa0904e85a62e89ed0e040970", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "VBox(children=(Label(value='Please provide the name for a Verily Workbench group.'), Text(value='', descriptio…" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "class ListMembersWidget(object):\n", " def __init__(self):\n", @@ -330,26 +264,11 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "d27bb3a6bfe0495f92c4460ff86a18d8", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "VBox(children=(Label(value='Please provide the name & org ID for your Verily Workbench group.'), Text(value=''…" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "class CreateGroupWidget(object):\n", " def __init__(self):\n", @@ -415,26 +334,11 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "8f738ef67f4a4afb9cdad71e16a84f53", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "VBox(children=(Label(value='Please provide the name for a Verily Workbench group.'), Text(value='', descriptio…" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "class DeleteGroupWidget(object):\n", " def __init__(self):\n", @@ -497,61 +401,12 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "8b94599944f848f5b136ecef79668c86", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "VBox(children=(Label(value='Please provide appropriate values for the fields below.'), Text(value='', descript…" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "class GrantUserGroupRoleWidget(object):\n", - " def __init__(self):\n", - " self.label = widgets.Label(value = 'Please provide appropriate values for the fields below.')\n", - " self.input_group_name = wu.TextInputWidget('',\"Group Name:\").get()\n", - " self.input_user_email = wu.TextInputWidget('',\"User Email:\").get()\n", - " self.input_org_id = wu.TextInputWidget('', \"Organization ID:\").get()\n", - " self.role_drop_down = wu.DropdownInputWidget(['MEMBER','ADMIN'],'MEMBER',\"Role:\").get()\n", - " self.input_reason = wu.TextInputWidget('', \"Reason:\").get()\n", - " self.output = widgets.Output()\n", - " self.button = wu.StyledButton('Add user','Click to add a user to the group.','user-plus').get()\n", - " self.vb = widgets.VBox(\n", - " [self.label,\n", - " self.input_group_name,\n", - " self.input_org_id,\n", - " self.input_user_email,\n", - " self.role_drop_down,\n", - " self.input_reason,\n", - " self.button,\n", - " self.output\n", - " ],layout=wu.vbox_layout)\n", - " self.button.on_click(self.add_user)\n", - "\n", - " def add_user(self,b):\n", - " with self.output:\n", - " wb_command = [\"wb\", \"group\", \"role\", \"grant\", \"user\", f\"--name={self.input_group_name.value}\",f\"--org={self.input_org_id.value}\",f\"--email={self.input_user_email.value}\",f\"--role={self.role_drop_down.value}\"]\n", - " if self.require_grant_reason.value:\n", - " commandList.append(f\"--reason={self.input_reason.value}\")\n", - " result = subprocess.run(wb_command,capture_output=True,text=True)\n", - " print(result.stderr) if not result.stdout else print(result.stdout)\n", - "\n", - "# Instantiate widget\n", - "grant_user_role_widget = GrantUserGroupRoleWidget()\n", - "display(grant_user_role_widget.vb)" - ] + "outputs": [], + "source": "class GrantUserGroupRoleWidget(object):\n def __init__(self):\n self.label = widgets.Label(value = 'Please provide appropriate values for the fields below.')\n self.input_group_name = wu.TextInputWidget('',\"Group Name:\").get()\n self.input_user_email = wu.TextInputWidget('',\"User Email:\").get()\n self.input_org_id = wu.TextInputWidget('', \"Organization ID:\").get()\n self.role_drop_down = wu.DropdownInputWidget(['MEMBER','ADMIN'],'MEMBER',\"Role:\").get()\n self.input_reason = wu.TextInputWidget('', \"Reason:\").get()\n self.require_grant_reason = wu.LongLabelCheckbox('Require admins to provide a reason when granting a role on this group.').get()\n self.output = widgets.Output()\n self.button = wu.StyledButton('Add user','Click to add a user to the group.','user-plus').get()\n self.vb = widgets.VBox(\n [self.label,\n self.input_group_name,\n self.input_org_id,\n self.input_user_email,\n self.role_drop_down,\n self.input_reason,\n self.require_grant_reason,\n self.button,\n self.output\n ],layout=wu.vbox_layout)\n self.button.on_click(self.add_user)\n\n def add_user(self,b):\n with self.output:\n wb_command = [\"wb\", \"group\", \"role\", \"grant\", \"user\", f\"--name={self.input_group_name.value}\",f\"--org={self.input_org_id.value}\",f\"--email={self.input_user_email.value}\",f\"--role={self.role_drop_down.value}\"]\n if self.require_grant_reason.value:\n wb_command.append(f\"--reason={self.input_reason.value}\")\n result = subprocess.run(wb_command,capture_output=True,text=True)\n print(result.stderr) if not result.stdout else print(result.stdout)\n\n# Instantiate widget\ngrant_user_role_widget = GrantUserGroupRoleWidget()\ndisplay(grant_user_role_widget.vb)" }, { "cell_type": "markdown", @@ -573,26 +428,11 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "fd40e0d9e12748e3ba4b23b20ef3711a", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "VBox(children=(Label(value='Please provide appropriate values for the fields below.'), Text(value='', descript…" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "class RevokeUserRoleWidget(object):\n", " def __init__(self):\n", @@ -602,6 +442,7 @@ " self.input_org_id = wu.TextInputWidget('', \"Organization ID:\").get()\n", " self.role_drop_down = wu.DropdownInputWidget(['MEMBER','ADMIN'],'MEMBER',\"Role:\").get()\n", " self.input_reason = wu.TextInputWidget('', \"Reason:\").get()\n", + " self.require_grant_reason = wu.LongLabelCheckbox('Require admins to provide a reason when granting a role on this group.').get()\n", " self.output = widgets.Output()\n", " self.button = wu.StyledButton('Remove user','Click to remove a user from the group.','user-minus').get()\n", " self.vb = widgets.VBox(\n", @@ -620,7 +461,7 @@ " with self.output:\n", " wb_command = [\"wb\", \"group\", \"role\", \"revoke\", \"user\", f\"--name={self.input_group_name.value}\",f\"--org={self.input_org_id.value}\",f\"--email={self.input_user_email.value}\",f\"--role={self.role_drop_down.value}\"]\n", " if self.require_grant_reason.value:\n", - " commandList.append(f\"--reason={self.input_reason.value}\")\n", + " wb_command.append(f\"--reason={self.input_reason.value}\")\n", " result = subprocess.run(wb_command,capture_output=True,text=True)\n", " print(result.stderr) if not result.stdout else print(result.stdout)\n", "\n", @@ -653,26 +494,11 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "faac05f826df4ba2ab735b009e0211fc", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "VBox(children=(Label(value='Please provide appropriate values for the fields below.'), Text(value='', descript…" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "class BatchAddUsersWidget(object):\n", " def __init__(self):\n", @@ -692,9 +518,9 @@ " with open(self.input_file.value) as csv_file:\n", " csv_reader = csv.DictReader(csv_file,delimiter=',')\n", " for user in csv_reader:\n", - " wb_command = [\"wb\", \"group\", \"role\", \"grant\",\"user\",f\"--name={self.input_group_name.value}\",f\"--org={self.input_org_id.value}\",f\"--email={user['WORKBENCH_USER_EMAIL']}\",f\"--policy={user['ROLE']}\"]\n", + " wb_command = [\"wb\", \"group\", \"role\", \"grant\",\"user\",f\"--name={self.input_group_name.value}\",f\"--org={self.input_org_id.value}\",f\"--email={user['WORKBENCH_USER_EMAIL']}\",f\"--role={user['ROLE']}\"]\n", " if self.input_reason.value:\n", - " commandList.append(f\"--reason={self.input_reason.value}\")\n", + " wb_command.append(f\"--reason={self.input_reason.value}\")\n", " result = subprocess.run(wb_command,capture_output=True,text=True)\n", " print(result.stderr) if not result.stdout else print(result.stdout)\n", "\n", @@ -728,26 +554,11 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "0d281747b76f459c9b9d7bde724ac19b", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "VBox(children=(Label(value='Please provide appropriate values for the fields below.'), Text(value='', descript…" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "class BatchRemoveUsersWidget(object):\n", " def __init__(self):\n", @@ -767,9 +578,9 @@ " with open(self.input_file.value) as csv_file:\n", " csv_reader = csv.DictReader(csv_file,delimiter=',')\n", " for user in csv_reader:\n", - " wb_command = [\"wb\", \"group\", \"role\",\"revoke\",\"user\",f\"--name={self.input_group_name.value}\",f\"--org={self.input_org_id.value}\",f\"--email={user['WORKBENCH_USER_EMAIL']}\",f\"--policy={user['POLICY']}\"]\n", + " wb_command = [\"wb\", \"group\", \"role\",\"revoke\",\"user\",f\"--name={self.input_group_name.value}\",f\"--org={self.input_org_id.value}\",f\"--email={user['WORKBENCH_USER_EMAIL']}\",f\"--role={user['POLICY']}\"]\n", " if self.input_reason.value:\n", - " commandList.append(f\"--reason={self.input_reason.value}\")\n", + " wb_command.append(f\"--reason={self.input_reason.value}\")\n", " result = subprocess.run(wb_command,capture_output=True,text=True)\n", " print(result.stderr) if not result.stdout else print(result.stdout)\n", "\n", @@ -789,19 +600,11 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tue May 27 06:33:59 PM UTC 2025\n" - ] - } - ], + "outputs": [], "source": [ "!date" ] @@ -815,766 +618,11 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "name: base\n", - "channels:\n", - " - conda-forge\n", - "dependencies:\n", - " - _libgcc_mutex=0.1=conda_forge\n", - " - _openmp_mutex=4.5=2_gnu\n", - " - _r-mutex=1.0.1=anacondar_1\n", - " - aiohappyeyeballs=2.5.0=pyhd8ed1ab_0\n", - " - aiohttp=3.11.13=py310h89163eb_0\n", - " - aiosignal=1.3.2=pyhd8ed1ab_0\n", - " - alsa-lib=1.2.13=hb9d3cd8_0\n", - " - annotated-types=0.7.0=pyhd8ed1ab_1\n", - " - anyio=4.8.0=pyhd8ed1ab_0\n", - " - aom=3.9.1=hac33072_0\n", - " - archspec=0.2.5=pyhd8ed1ab_0\n", - " - argon2-cffi=23.1.0=pyhd8ed1ab_1\n", - " - argon2-cffi-bindings=21.2.0=py310ha75aee5_5\n", - " - arrow=1.3.0=pyhd8ed1ab_1\n", - " - asttokens=3.0.0=pyhd8ed1ab_1\n", - " - async-lru=2.0.4=pyhd8ed1ab_1\n", - " - async-timeout=5.0.1=pyhd8ed1ab_1\n", - " - attr=2.5.1=h166bdaf_1\n", - " - attrs=25.1.0=pyh71513ae_0\n", - " - aws-c-auth=0.7.31=he1a10d6_2\n", - " - aws-c-cal=0.7.4=hae4d56a_2\n", - " - aws-c-common=0.9.29=hb9d3cd8_0\n", - " - aws-c-compression=0.2.19=h2bff981_2\n", - " - aws-c-event-stream=0.4.3=h19b0707_4\n", - " - aws-c-http=0.8.10=h14a7884_2\n", - " - aws-c-io=0.14.19=hc9e6898_1\n", - " - aws-c-mqtt=0.10.7=hb8d5873_2\n", - " - aws-c-s3=0.6.7=h666547d_0\n", - " - aws-c-sdkutils=0.1.19=h2bff981_4\n", - " - aws-checksums=0.1.20=h2bff981_1\n", - " - aws-crt-cpp=0.28.3=hbe26082_8\n", - " - aws-sdk-cpp=1.11.407=h25d6d5c_1\n", - " - awscli=2.22.15=py310hff52083_0\n", - " - awscrt=0.22.0=py310hab15552_5\n", - " - azure-core-cpp=1.13.0=h935415a_0\n", - " - azure-identity-cpp=1.8.0=hd126650_2\n", - " - azure-storage-blobs-cpp=12.12.0=hd2e3451_0\n", - " - azure-storage-common-cpp=12.7.0=h10ac4d7_1\n", - " - azure-storage-files-datalake-cpp=12.11.0=h325d260_1\n", - " - babel=2.17.0=pyhd8ed1ab_0\n", - " - beautifulsoup4=4.13.3=pyha770c72_0\n", - " - binutils_impl_linux-64=2.43=h4bf12b8_2\n", - " - bleach=6.2.0=pyh29332c3_4\n", - " - bleach-with-css=6.2.0=h82add2a_4\n", - " - blinker=1.9.0=pyhff2d567_0\n", - " - blosc=1.21.6=hef167b5_0\n", - " - boltons=24.0.0=pyhd8ed1ab_1\n", - " - bottleneck=1.4.2=py310hf462985_0\n", - " - branca=0.8.1=pyhd8ed1ab_0\n", - " - brotli=1.1.0=hb9d3cd8_2\n", - " - brotli-bin=1.1.0=hb9d3cd8_2\n", - " - brotli-python=1.1.0=py310hf71b8c6_2\n", - " - bwidget=1.10.1=ha770c72_0\n", - " - bzip2=1.0.8=h4bc722e_7\n", - " - c-ares=1.34.4=hb9d3cd8_0\n", - " - ca-certificates=2025.1.31=hbcca054_0\n", - " - cached-property=1.5.2=hd8ed1ab_1\n", - " - cached_property=1.5.2=pyha770c72_1\n", - " - cachetools=5.5.2=pyhd8ed1ab_0\n", - " - cairo=1.18.4=h3394656_0\n", - " - certifi=2025.1.31=pyhd8ed1ab_0\n", - " - cffi=1.17.1=py310h8deb56e_0\n", - " - charset-normalizer=3.4.1=pyhd8ed1ab_0\n", - " - click=8.1.8=pyh707e725_0\n", - " - click-plugins=1.1.1=pyhd8ed1ab_1\n", - " - cligj=0.7.2=pyhd8ed1ab_2\n", - " - colorama=0.4.6=pyhd8ed1ab_1\n", - " - comm=0.2.2=pyhd8ed1ab_1\n", - " - conda=24.11.3=py310hff52083_0\n", - " - conda-content-trust=0.2.0=pyhd8ed1ab_0\n", - " - conda-libmamba-solver=24.9.0=pyhd8ed1ab_0\n", - " - conda-package-handling=2.4.0=pyh7900ff3_2\n", - " - conda-package-streaming=0.11.0=pyhd8ed1ab_0\n", - " - confuse=2.0.1=pyhd8ed1ab_0\n", - " - contourpy=1.3.1=py310h3788b33_0\n", - " - cpython=3.10.16=py310hd8ed1ab_1\n", - " - cryptography=43.0.1=py310h6c63255_0\n", - " - cuda-crt-tools=12.8.93=ha770c72_0\n", - " - cuda-cudart=12.8.90=h5888daf_1\n", - " - cuda-cudart_linux-64=12.8.90=h3f2d84a_1\n", - " - cuda-cuobjdump=12.8.90=hbd13f7d_0\n", - " - cuda-cupti=12.8.90=hbd13f7d_0\n", - " - cuda-nvcc-tools=12.8.93=he02047a_0\n", - " - cuda-nvdisasm=12.8.90=hbd13f7d_0\n", - " - cuda-nvvm-tools=12.8.93=he02047a_0\n", - " - cuda-version=12.8=h5d125a7_3\n", - " - curl=8.11.1=h332b0f4_0\n", - " - cycler=0.12.1=pyhd8ed1ab_1\n", - " - cyrus-sasl=2.1.27=h54b06d7_7\n", - " - cython=3.0.11=py310h5b1441d_3\n", - " - dal=2025.1.0=h9289deb_124\n", - " - dav1d=1.2.1=hd590300_0\n", - " - db-dtypes=1.4.2=pyhd8ed1ab_0\n", - " - dbus=1.13.6=h5008d03_3\n", - " - debugpy=1.8.13=py310hf71b8c6_0\n", - " - decorator=5.2.1=pyhd8ed1ab_0\n", - " - defusedxml=0.7.1=pyhd8ed1ab_0\n", - " - distro=1.8.0=pyhd8ed1ab_0\n", - " - docstring_parser=0.16=pyhd8ed1ab_0\n", - " - docutils=0.19=py310hff52083_1\n", - " - double-conversion=3.3.1=h5888daf_0\n", - " - dpcpp-cpp-rt=2025.0.4=ha770c72_1519\n", - " - exceptiongroup=1.2.2=pyhd8ed1ab_1\n", - " - executing=2.1.0=pyhd8ed1ab_1\n", - " - expat=2.6.4=h5888daf_0\n", - " - fastavro=1.10.0=py310ha75aee5_0\n", - " - fasteners=0.19=pyhd8ed1ab_1\n", - " - fiona=1.10.1=py310h0aed7a2_3\n", - " - fmt=11.0.2=h434a139_0\n", - " - folium=0.19.5=pyhd8ed1ab_0\n", - " - font-ttf-dejavu-sans-mono=2.37=hab24e00_0\n", - " - font-ttf-inconsolata=3.000=h77eed37_0\n", - " - font-ttf-source-code-pro=2.038=h77eed37_0\n", - " - font-ttf-ubuntu=0.83=h77eed37_3\n", - " - fontconfig=2.15.0=h7e30c49_1\n", - " - fonts-conda-ecosystem=1=0\n", - " - fonts-conda-forge=1=0\n", - " - fonttools=4.56.0=py310h89163eb_0\n", - " - fqdn=1.5.1=pyhd8ed1ab_1\n", - " - freetype=2.12.1=h267a509_2\n", - " - freexl=2.0.0=h9dce30a_2\n", - " - fribidi=1.0.10=h36c2ea0_0\n", - " - frozendict=2.4.6=py310ha75aee5_0\n", - " - frozenlist=1.5.0=py310h89163eb_1\n", - " - gcc_impl_linux-64=14.2.0=hdb7739f_2\n", - " - geopandas=0.14.4=pyhd8ed1ab_0\n", - " - geopandas-base=0.14.4=pyha770c72_0\n", - " - geos=3.13.0=h5888daf_0\n", - " - geotiff=1.7.4=h3551947_0\n", - " - gflags=2.2.2=h5888daf_1005\n", - " - gfortran_impl_linux-64=14.2.0=h0ee6e4a_2\n", - " - giflib=5.2.2=hd590300_0\n", - " - gitdb=4.0.12=pyhd8ed1ab_0\n", - " - gitpython=3.1.44=pyhff2d567_0\n", - " - glog=0.7.1=hbabe93e_0\n", - " - gmp=6.3.0=hac33072_2\n", - " - gmpy2=2.1.5=py310he8512ff_3\n", - " - google-api-core=2.24.1=pyhd8ed1ab_0\n", - " - google-api-core-grpc=2.24.1=hd8ed1ab_0\n", - " - google-api-python-client=2.162.0=pyhff2d567_0\n", - " - google-apitools=0.5.32=pyhd8ed1ab_1\n", - " - google-auth=2.38.0=pyhd8ed1ab_0\n", - " - google-auth-httplib2=0.2.0=pyhd8ed1ab_1\n", - " - google-auth-oauthlib=1.0.0=pyhd8ed1ab_1\n", - " - google-cloud-aiplatform=1.72.0=pyhff2d567_0\n", - " - google-cloud-artifact-registry=1.8.4=pyhd8ed1ab_0\n", - " - google-cloud-bigquery=3.25.0=pyhd8ed1ab_0\n", - " - google-cloud-bigquery-connection=1.16.1=pyhd8ed1ab_0\n", - " - google-cloud-bigquery-core=3.25.0=pyhd8ed1ab_0\n", - " - google-cloud-bigquery-datatransfer=3.19.0=pyhd8ed1ab_0\n", - " - google-cloud-bigquery-storage=2.27.0=pyhd8ed1ab_2\n", - " - google-cloud-bigquery-storage-core=2.27.0=pyhd8ed1ab_2\n", - " - google-cloud-bigtable=2.29.0=pyhd8ed1ab_0\n", - " - google-cloud-core=2.4.1=pyhd8ed1ab_1\n", - " - google-cloud-datastore=2.20.2=pyhd8ed1ab_0\n", - " - google-cloud-resource-manager=1.14.0=pyhd8ed1ab_0\n", - " - google-cloud-storage=2.14.0=pyhca7485f_0\n", - " - google-crc32c=1.1.2=py310hd027165_6\n", - " - google-resumable-media=2.7.2=pyhd8ed1ab_2\n", - " - googleapis-common-protos=1.69.1=pyhd8ed1ab_0\n", - " - googleapis-common-protos-grpc=1.69.1=pyhd8ed1ab_0\n", - " - graphite2=1.3.13=h59595ed_1003\n", - " - grpc-google-iam-v1=0.14.1=pyhd8ed1ab_0\n", - " - grpcio=1.62.2=py310h1b8f574_0\n", - " - grpcio-status=1.62.2=pyhd8ed1ab_0\n", - " - gsl=2.7=he838d99_0\n", - " - gxx_impl_linux-64=14.2.0=h2ead766_2\n", - " - h11=0.14.0=pyhd8ed1ab_1\n", - " - h2=4.1.0=pyhd8ed1ab_1\n", - " - harfbuzz=9.0.0=hda332d3_1\n", - " - hpack=4.0.0=pyhd8ed1ab_1\n", - " - htmlmin=0.1.12=pyhca7485f_2\n", - " - httpcore=1.0.7=pyh29332c3_1\n", - " - httplib2=0.22.0=pyhd8ed1ab_1\n", - " - httpx=0.28.1=pyhd8ed1ab_0\n", - " - hyperframe=6.0.1=pyhd8ed1ab_1\n", - " - icu=75.1=he02047a_0\n", - " - idna=3.10=pyhd8ed1ab_1\n", - " - imagehash=4.3.2=pyhd8ed1ab_0\n", - " - importlib-metadata=8.6.1=pyha770c72_0\n", - " - importlib_resources=6.5.2=pyhd8ed1ab_0\n", - " - intel-cmplr-lib-rt=2025.0.4=h04fd95a_1519\n", - " - intel-cmplr-lib-ur=2025.0.4=h04fd95a_1519\n", - " - intel-cmplr-lic-rt=2025.0.4=ha770c72_1519\n", - " - intel-opencl-rt=2025.0.4=h5a16d59_1519\n", - " - intel-sycl-rt=2025.0.4=h7a4b287_1519\n", - " - ipykernel=6.29.5=pyh3099207_0\n", - " - ipython=8.17.2=pyh41d4057_0\n", - " - ipython_genutils=0.2.0=pyhd8ed1ab_2\n", - " - ipywidgets=8.1.5=pyhd8ed1ab_1\n", - " - isoduration=20.11.0=pyhd8ed1ab_1\n", - " - jedi=0.19.2=pyhd8ed1ab_1\n", - " - jinja2=3.1.6=pyhd8ed1ab_0\n", - " - jmespath=1.0.1=pyhd8ed1ab_1\n", - " - joblib=1.4.2=pyhd8ed1ab_1\n", - " - json-c=0.18=h6688a6e_0\n", - " - json5=0.10.0=pyhd8ed1ab_1\n", - " - jsonpatch=1.33=pyhd8ed1ab_1\n", - " - jsonpointer=3.0.0=py310hff52083_1\n", - " - jsonschema=4.23.0=pyhd8ed1ab_1\n", - " - jsonschema-specifications=2024.10.1=pyhd8ed1ab_1\n", - " - jsonschema-with-format-nongpl=4.23.0=hd8ed1ab_1\n", - " - jupyter-lsp=2.2.5=pyhd8ed1ab_1\n", - " - jupyter-server-mathjax=0.2.6=pyhbbac1ac_2\n", - " - jupyter_client=8.6.3=pyhd8ed1ab_1\n", - " - jupyter_core=5.7.2=pyh31011fe_1\n", - " - jupyter_events=0.12.0=pyh29332c3_0\n", - " - jupyter_server=2.15.0=pyhd8ed1ab_0\n", - " - jupyter_server_terminals=0.5.3=pyhd8ed1ab_1\n", - " - jupyterlab=4.3.4=pyhd8ed1ab_0\n", - " - jupyterlab-git=0.50.2=pyhd8ed1ab_1\n", - " - jupyterlab_pygments=0.3.0=pyhd8ed1ab_2\n", - " - jupyterlab_server=2.27.3=pyhd8ed1ab_1\n", - " - jupyterlab_widgets=3.0.13=pyhd8ed1ab_1\n", - " - jupytext=1.16.4=pyh80e38bb_0\n", - " - kernel-headers_linux-64=3.10.0=he073ed8_18\n", - " - keyutils=1.6.1=h166bdaf_0\n", - " - kiwisolver=1.4.7=py310h3788b33_0\n", - " - krb5=1.21.3=h659f571_0\n", - " - lcms2=2.17=h717163a_0\n", - " - ld_impl_linux-64=2.43=h712a8e2_2\n", - " - lerc=4.0.0=h27087fc_0\n", - " - libabseil=20240116.2=cxx17_he02047a_1\n", - " - libarchive=3.7.7=hadbb8c3_0\n", - " - libarrow=17.0.0=had3b6fe_16_cpu\n", - " - libarrow-acero=17.0.0=h5888daf_16_cpu\n", - " - libarrow-dataset=17.0.0=h5888daf_16_cpu\n", - " - libarrow-substrait=17.0.0=hf54134d_16_cpu\n", - " - libavif16=1.2.0=hf3231e4_0\n", - " - libblas=3.9.0=31_h59b9bed_openblas\n", - " - libbrotlicommon=1.1.0=hb9d3cd8_2\n", - " - libbrotlidec=1.1.0=hb9d3cd8_2\n", - " - libbrotlienc=1.1.0=hb9d3cd8_2\n", - " - libcap=2.71=h39aace5_0\n", - " - libcblas=3.9.0=31_he106b2a_openblas\n", - " - libclang-cpp19.1=19.1.7=default_hb5137d0_1\n", - " - libclang13=19.1.7=default_h9c6a7e4_1\n", - " - libcrc32c=1.1.2=h9c3ff4c_0\n", - " - libcups=2.3.3=h4637d8d_4\n", - " - libcurl=8.11.1=h332b0f4_0\n", - " - libde265=1.0.15=h00ab1b0_0\n", - " - libdeflate=1.22=hb9d3cd8_0\n", - " - libdrm=2.4.124=hb9d3cd8_0\n", - " - libedit=3.1.20240808=pl5321h7949ede_0\n", - " - libegl=1.7.0=ha4b6fd6_2\n", - " - libev=4.33=hd590300_2\n", - " - libevent=2.1.12=hf998b51_1\n", - " - libexpat=2.6.4=h5888daf_0\n", - " - libfabric=2.0.0=ha770c72_1\n", - " - libfabric1=2.0.0=h14e6f36_1\n", - " - libffi=3.4.2=h7f98852_5\n", - " - libgcc=14.2.0=h77fa898_1\n", - " - libgcc-devel_linux-64=14.2.0=h9c4974d_102\n", - " - libgcc-ng=14.2.0=h69a702a_1\n", - " - libgcrypt-lib=1.11.0=hb9d3cd8_2\n", - " - libgdal-core=3.10.0=h7250d82_6\n", - " - libgfortran=14.2.0=h69a702a_2\n", - " - libgfortran-ng=14.2.0=h69a702a_2\n", - " - libgfortran5=14.2.0=hf1ad2bd_2\n", - " - libgl=1.7.0=ha4b6fd6_2\n", - " - libglib=2.82.2=h2ff4ddf_1\n", - " - libglvnd=1.7.0=ha4b6fd6_2\n", - " - libglx=1.7.0=ha4b6fd6_2\n", - " - libgomp=14.2.0=h77fa898_1\n", - " - libgoogle-cloud=2.29.0=h435de7b_0\n", - " - libgoogle-cloud-storage=2.29.0=h0121fbd_0\n", - " - libgpg-error=1.51=hbd13f7d_1\n", - " - libgrpc=1.62.2=h15f2491_0\n", - " - libheif=1.18.2=gpl_hffcb242_100\n", - " - libhwloc=2.11.2=default_h0d58e46_1001\n", - " - libiconv=1.17=hd590300_2\n", - " - libjpeg-turbo=3.0.0=hd590300_1\n", - " - libkml=1.3.0=hf539b9f_1021\n", - " - liblapack=3.9.0=31_h7ac8fdf_openblas\n", - " - libllvm19=19.1.7=ha7bfdaf_1\n", - " - liblzma=5.6.3=hb9d3cd8_1\n", - " - liblzma-devel=5.6.3=hb9d3cd8_1\n", - " - libmamba=1.5.12=h49b8a8d_0\n", - " - libmambapy=1.5.12=py310h446c2ae_0\n", - " - libnghttp2=1.64.0=h161d5f1_0\n", - " - libnl=3.11.0=hb9d3cd8_0\n", - " - libnsl=2.0.1=hd590300_0\n", - " - libntlm=1.8=hb9d3cd8_0\n", - " - libopenblas=0.3.29=pthreads_h94d23a6_0\n", - " - libopengl=1.7.0=ha4b6fd6_2\n", - " - libparquet=17.0.0=h39682fd_16_cpu\n", - " - libpciaccess=0.18=hd590300_0\n", - " - libpng=1.6.47=h943b412_0\n", - " - libpq=17.4=h27ae623_0\n", - " - libprotobuf=4.25.3=hd5b35b9_1\n", - " - libre2-11=2023.09.01=h5a48ba9_2\n", - " - librttopo=1.1.0=h97f6797_17\n", - " - libsanitizer=14.2.0=hed042b8_2\n", - " - libsodium=1.0.20=h4ab18f5_0\n", - " - libsolv=0.7.30=h3509ff9_0\n", - " - libspatialindex=2.1.0=he57a185_0\n", - " - libspatialite=5.1.0=h1b4f908_12\n", - " - libsqlite=3.48.0=hee588c1_0\n", - " - libssh2=1.11.1=hf672d98_0\n", - " - libstdcxx=14.2.0=hc0a3c3a_1\n", - " - libstdcxx-devel_linux-64=14.2.0=h9c4974d_102\n", - " - libstdcxx-ng=14.2.0=h4852527_1\n", - " - libsystemd0=256.9=h2774228_0\n", - " - libthrift=0.20.0=h0e7cc3e_1\n", - " - libtiff=4.7.0=hc4654cb_2\n", - " - libudev1=257.4=h9a4d06a_0\n", - " - libutf8proc=2.8.0=hf23e847_1\n", - " - libuuid=2.38.1=h0b41bf4_0\n", - " - libuv=1.50.0=hb9d3cd8_0\n", - " - libwebp-base=1.5.0=h851e524_0\n", - " - libxcb=1.17.0=h8a09558_0\n", - " - libxcrypt=4.4.36=hd590300_1\n", - " - libxkbcommon=1.8.0=hc4a0caf_0\n", - " - libxml2=2.13.5=h8d12d68_1\n", - " - libxslt=1.1.39=h76b75d6_0\n", - " - libzlib=1.3.1=hb9d3cd8_2\n", - " - lsb-release=11.1.0=pyhd8ed1ab_5\n", - " - lz4-c=1.9.4=hcb278e6_0\n", - " - lzo=2.10=hd590300_1001\n", - " - make=4.4.1=hb9d3cd8_2\n", - " - mamba=1.5.12=py310h51d5547_0\n", - " - mapclassify=2.8.1=pyhd8ed1ab_1\n", - " - markdown-it-py=3.0.0=pyhd8ed1ab_1\n", - " - markupsafe=3.0.2=py310h89163eb_1\n", - " - matplotlib=3.10.1=py310hff52083_0\n", - " - matplotlib-base=3.10.1=py310h68603db_0\n", - " - matplotlib-inline=0.1.7=pyhd8ed1ab_1\n", - " - matplotlib-venn=1.1.1=pyhd8ed1ab_1\n", - " - mdit-py-plugins=0.4.2=pyhd8ed1ab_1\n", - " - mdurl=0.1.2=pyhd8ed1ab_1\n", - " - menuinst=2.2.0=py310hff52083_0\n", - " - minizip=4.0.7=h05a5f5f_3\n", - " - missingno=0.5.2=pyhd8ed1ab_0\n", - " - mistune=3.1.2=pyhd8ed1ab_0\n", - " - mizani=0.13.1=pyhd8ed1ab_0\n", - " - mpc=1.3.1=h24ddda3_1\n", - " - mpfr=4.2.1=h90cbb55_3\n", - " - mpi=1.0.1=mpich\n", - " - mpich=4.3.0=h1a8bee6_100\n", - " - mpmath=1.3.0=pyhd8ed1ab_1\n", - " - multidict=6.1.0=py310h89163eb_2\n", - " - multimethod=1.4=py_0\n", - " - munkres=1.1.4=pyh9f0ad1d_0\n", - " - mysql-common=9.0.1=h266115a_4\n", - " - mysql-libs=9.0.1=he0572af_4\n", - " - narwhals=1.30.0=pyhd8ed1ab_0\n", - " - nb_conda=2.2.1=pyh707e725_7\n", - " - nb_conda_kernels=2.5.1=pyh707e725_2\n", - " - nbclassic=1.2.0=pyhd8ed1ab_0\n", - " - nbclient=0.10.2=pyhd8ed1ab_0\n", - " - nbconvert-core=7.16.6=pyh29332c3_0\n", - " - nbdime=4.0.2=pyhd8ed1ab_1\n", - " - nbformat=5.10.4=pyhd8ed1ab_1\n", - " - ncurses=6.5=h2d0b736_2\n", - " - nest-asyncio=1.6.0=pyhd8ed1ab_1\n", - " - networkx=3.4.2=pyh267e887_2\n", - " - notebook=6.5.4=pyha770c72_0\n", - " - notebook-shim=0.2.4=pyhd8ed1ab_1\n", - " - numpy=1.26.0=py310hb13e2d6_0\n", - " - oauth2client=4.1.3=pyhd8ed1ab_1\n", - " - oauthlib=3.2.2=pyhd8ed1ab_1\n", - " - ocl-icd=2.3.2=hb9d3cd8_2\n", - " - opencl-headers=2024.10.24=h5888daf_0\n", - " - openjpeg=2.5.3=h5fbd93e_0\n", - " - openldap=2.6.9=he970967_0\n", - " - openssl=3.4.1=h7b32b05_0\n", - " - orc=2.0.2=h669347b_0\n", - " - overrides=7.7.0=pyhd8ed1ab_1\n", - " - packaging=24.2=pyhd8ed1ab_2\n", - " - pandas=2.2.1=py310hcc13569_0\n", - " - pandas-gbq=0.27.0=pyhd8ed1ab_0\n", - " - pandas-profiling=3.0.0=pyhd8ed1ab_0\n", - " - pandoc=3.6.3=ha770c72_0\n", - " - pandocfilters=1.5.0=pyhd8ed1ab_0\n", - " - pango=1.54.0=h3a902e7_3\n", - " - parso=0.8.4=pyhd8ed1ab_1\n", - " - patsy=1.0.1=pyhd8ed1ab_1\n", - " - pcre2=10.44=hba22ea6_2\n", - " - pexpect=4.9.0=pyhd8ed1ab_1\n", - " - phik=0.12.3=py310heada3b3_1\n", - " - pickleshare=0.7.5=pyhd8ed1ab_1004\n", - " - pillow=11.1.0=py310h7e6dc6c_0\n", - " - pip=25.0.1=pyh8b19718_0\n", - " - pixman=0.44.2=h29eaf8c_0\n", - " - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_2\n", - " - platformdirs=4.3.6=pyhd8ed1ab_1\n", - " - plotly=6.0.0=pyhd8ed1ab_0\n", - " - plotnine=0.14.5=pyhd8ed1ab_0\n", - " - pluggy=1.5.0=pyhd8ed1ab_1\n", - " - proj=9.5.1=h0054346_0\n", - " - prometheus_client=0.21.1=pyhd8ed1ab_0\n", - " - prompt-toolkit=3.0.38=pyha770c72_0\n", - " - prompt_toolkit=3.0.38=hd8ed1ab_0\n", - " - propcache=0.2.1=py310h89163eb_1\n", - " - proto-plus=1.26.0=pyhd8ed1ab_0\n", - " - protobuf=4.25.3=py310h0e2eeba_1\n", - " - psutil=7.0.0=py310ha75aee5_0\n", - " - pthread-stubs=0.4=hb9d3cd8_1002\n", - " - ptyprocess=0.7.0=pyhd8ed1ab_1\n", - " - pure_eval=0.2.3=pyhd8ed1ab_1\n", - " - py-bgzip=0.5.0=py310h16f6504_0\n", - " - pyarrow=17.0.0=py310hb7f781d_2\n", - " - pyarrow-core=17.0.0=py310hac404ae_2_cpu\n", - " - pyasn1=0.6.1=pyhd8ed1ab_2\n", - " - pyasn1-modules=0.4.1=pyhd8ed1ab_1\n", - " - pybind11-abi=4=hd8ed1ab_3\n", - " - pycares=4.5.0=py310ha75aee5_1\n", - " - pycosat=0.6.6=py310ha75aee5_2\n", - " - pycparser=2.22=pyh29332c3_1\n", - " - pydantic=2.10.6=pyh3cfb1c2_0\n", - " - pydantic-core=2.27.2=py310h505e2c1_0\n", - " - pydata-google-auth=1.9.0=pyhd8ed1ab_0\n", - " - pygments=2.18.0=pyhd8ed1ab_1\n", - " - pyjwt=2.10.1=pyhd8ed1ab_0\n", - " - pyopenssl=25.0.0=pyhd8ed1ab_0\n", - " - pyparsing=3.2.1=pyhd8ed1ab_0\n", - " - pyproj=3.7.1=py310h2e9f774_0\n", - " - pyside6=6.8.1=py310hfd10a26_0\n", - " - pysocks=1.7.1=pyha55dd90_7\n", - " - python=3.10.16=he725a3c_1_cpython\n", - " - python-dateutil=2.9.0=pyhd8ed1ab_0\n", - " - python-fastjsonschema=2.21.1=pyhd8ed1ab_0\n", - " - python-json-logger=2.0.7=pyhd8ed1ab_0\n", - " - python-lzo=1.15=py310h69112cf_2\n", - " - python-tzdata=2025.1=pyhd8ed1ab_0\n", - " - python_abi=3.10=5_cp310\n", - " - pytz=2025.1=pyhd8ed1ab_0\n", - " - pyu2f=0.1.5=pyhd8ed1ab_1\n", - " - pywavelets=1.8.0=py310hf462985_0\n", - " - pyyaml=6.0.2=py310h89163eb_2\n", - " - pyzmq=26.2.1=py310h71f11fc_0\n", - " - qhull=2020.2=h434a139_5\n", - " - qt6-main=6.8.1=h9d28a51_0\n", - " - r-askpass=1.2.1=r44h2b5f3a1_0\n", - " - r-assertthat=0.2.1=r44hc72bb7e_5\n", - " - r-backports=1.5.0=r44hb1dbf0f_1\n", - " - r-base=4.4.2=hbab086e_1\n", - " - r-base64enc=0.1_3=r44hb1dbf0f_1007\n", - " - r-bit=4.6.0=r44h2b5f3a1_0\n", - " - r-bit64=4.5.2=r44h2b5f3a1_0\n", - " - r-blob=1.2.4=r44hc72bb7e_2\n", - " - r-broom=1.0.7=r44hc72bb7e_0\n", - " - r-bslib=0.9.0=r44hc72bb7e_0\n", - " - r-cachem=1.1.0=r44hb1dbf0f_1\n", - " - r-callr=3.7.6=r44hc72bb7e_1\n", - " - r-caret=6.0_94=r44hdb488b9_2\n", - " - r-cellranger=1.1.0=r44hc72bb7e_1007\n", - " - r-class=7.3_23=r44h2b5f3a1_0\n", - " - r-cli=3.6.4=r44h93ab643_1\n", - " - r-clipr=0.8.0=r44hc72bb7e_3\n", - " - r-clock=0.7.1=r44h0d4f4ea_0\n", - " - r-codetools=0.2_20=r44hc72bb7e_1\n", - " - r-colorspace=2.1_1=r44hdb488b9_0\n", - " - r-commonmark=1.9.2=r44h2b5f3a1_0\n", - " - r-conflicted=1.2.0=r44h785f33e_2\n", - " - r-cpp11=0.5.1=r44hc72bb7e_0\n", - " - r-crayon=1.5.3=r44hc72bb7e_1\n", - " - r-curl=6.0.1=r44h2700575_0\n", - " - r-data.table=1.17.0=r44he23165d_0\n", - " - r-dbi=1.2.3=r44hc72bb7e_1\n", - " - r-dbplyr=2.5.0=r44hc72bb7e_1\n", - " - r-diagram=1.6.5=r44ha770c72_3\n", - " - r-dials=1.4.0=r44hc72bb7e_0\n", - " - r-dicedesign=1.10=r44hb1dbf0f_1\n", - " - r-digest=0.6.37=r44h0d4f4ea_0\n", - " - r-dofuture=1.0.1=r44hc72bb7e_1\n", - " - r-dplyr=1.1.4=r44h0d4f4ea_1\n", - " - r-dtplyr=1.3.1=r44hc72bb7e_2\n", - " - r-e1071=1.7_16=r44h93ab643_0\n", - " - r-ellipsis=0.3.2=r44hb1dbf0f_3\n", - " - r-evaluate=1.0.3=r44hc72bb7e_0\n", - " - r-fansi=1.0.6=r44hb1dbf0f_1\n", - " - r-farver=2.1.2=r44ha18555a_1\n", - " - r-fastmap=1.2.0=r44ha18555a_1\n", - " - r-fontawesome=0.5.3=r44hc72bb7e_0\n", - " - r-forcats=1.0.0=r44hc72bb7e_2\n", - " - r-foreach=1.5.2=r44hc72bb7e_3\n", - " - r-fs=1.6.5=r44h93ab643_0\n", - " - r-furrr=0.3.1=r44hc72bb7e_3\n", - " - r-future=1.34.0=r44h785f33e_0\n", - " - r-future.apply=1.11.3=r44hc72bb7e_0\n", - " - r-gargle=1.5.2=r44h785f33e_1\n", - " - r-generics=0.1.3=r44hc72bb7e_3\n", - " - r-ggplot2=3.5.1=r44hc72bb7e_1\n", - " - r-globals=0.16.3=r44hc72bb7e_1\n", - " - r-glue=1.8.0=r44h2b5f3a1_0\n", - " - r-googledrive=2.1.1=r44hc72bb7e_2\n", - " - r-googlesheets4=1.1.1=r44h785f33e_2\n", - " - r-gower=1.0.1=r44hb1dbf0f_2\n", - " - r-gpfit=1.0_8=r44hc72bb7e_4\n", - " - r-gtable=0.3.6=r44hc72bb7e_0\n", - " - r-hardhat=1.4.1=r44hc72bb7e_0\n", - " - r-haven=2.5.4=r44h0d4f4ea_1\n", - " - r-highr=0.11=r44hc72bb7e_1\n", - " - r-hms=1.1.3=r44hc72bb7e_2\n", - " - r-htmltools=0.5.8.1=r44ha18555a_1\n", - " - r-httpuv=1.6.15=r44ha18555a_1\n", - " - r-httr=1.4.7=r44hc72bb7e_1\n", - " - r-ids=1.0.1=r44hc72bb7e_4\n", - " - r-infer=1.0.7=r44hc72bb7e_1\n", - " - r-ipred=0.9_15=r44hdb488b9_1\n", - " - r-irdisplay=1.1=r44hd8ed1ab_3\n", - " - r-irkernel=1.3.2=r44h785f33e_2\n", - " - r-isoband=0.2.7=r44ha18555a_3\n", - " - r-iterators=1.0.14=r44hc72bb7e_3\n", - " - r-jquerylib=0.1.4=r44hc72bb7e_3\n", - " - r-jsonlite=1.9.1=r44h2b5f3a1_0\n", - " - r-kernsmooth=2.23_26=r44h8461fee_0\n", - " - r-knitr=1.49=r44hc72bb7e_0\n", - " - r-labeling=0.4.3=r44hc72bb7e_1\n", - " - r-later=1.4.1=r44h93ab643_0\n", - " - r-lattice=0.22_6=r44hb1dbf0f_1\n", - " - r-lava=1.8.1=r44hc72bb7e_0\n", - " - r-lhs=1.2.0=r44h0d4f4ea_0\n", - " - r-lifecycle=1.0.4=r44hc72bb7e_1\n", - " - r-listenv=0.9.1=r44hc72bb7e_1\n", - " - r-lubridate=1.9.4=r44h2b5f3a1_0\n", - " - r-magrittr=2.0.3=r44hb1dbf0f_3\n", - " - r-mass=7.3_64=r44h2b5f3a1_0\n", - " - r-matrix=1.7_2=r44h2ae2be5_0\n", - " - r-memoise=2.0.1=r44hc72bb7e_3\n", - " - r-mgcv=1.9_1=r44h0d28552_1\n", - " - r-mime=0.12=r44hb1dbf0f_3\n", - " - r-modeldata=1.4.0=r44hc72bb7e_1\n", - " - r-modelenv=0.2.0=r44hc72bb7e_0\n", - " - r-modelmetrics=1.2.2.2=r44h0d4f4ea_4\n", - " - r-modelr=0.1.11=r44hc72bb7e_2\n", - " - r-munsell=0.5.1=r44hc72bb7e_1\n", - " - r-nlme=3.1_167=r44hb67ce94_0\n", - " - r-nnet=7.3_20=r44h2b5f3a1_0\n", - " - r-numderiv=2016.8_1.1=r44hc72bb7e_6\n", - " - r-openssl=2.3.2=r44he8289e2_0\n", - " - r-parallelly=1.42.0=r44h2b5f3a1_0\n", - " - r-parsnip=1.3.0=r44hc72bb7e_0\n", - " - r-patchwork=1.3.0=r44hc72bb7e_0\n", - " - r-pbdzmq=0.3_13=r44h549f438_0\n", - " - r-pillar=1.10.1=r44hc72bb7e_0\n", - " - r-pkgconfig=2.0.3=r44hc72bb7e_4\n", - " - r-plyr=1.8.9=r44ha18555a_1\n", - " - r-prettyunits=1.2.0=r44hc72bb7e_1\n", - " - r-proc=1.18.5=r44ha18555a_1\n", - " - r-processx=3.8.6=r44h2b5f3a1_0\n", - " - r-prodlim=2024.06.25=r44h0d4f4ea_1\n", - " - r-progress=1.2.3=r44hc72bb7e_1\n", - " - r-progressr=0.15.1=r44hc72bb7e_0\n", - " - r-promises=1.3.2=r44h93ab643_0\n", - " - r-proxy=0.4_27=r44hb1dbf0f_3\n", - " - r-ps=1.8.1=r44h2b5f3a1_0\n", - " - r-purrr=1.0.4=r44h2b5f3a1_0\n", - " - r-r6=2.6.1=r44hc72bb7e_0\n", - " - r-ragg=1.3.3=r44h9aa3752_0\n", - " - r-randomforest=4.7_1.2=r44hb67ce94_0\n", - " - r-rappdirs=0.3.3=r44hb1dbf0f_3\n", - " - r-rcolorbrewer=1.1_3=r44h785f33e_3\n", - " - r-rcpp=1.0.14=r44h93ab643_0\n", - " - r-readr=2.1.5=r44h0d4f4ea_1\n", - " - r-readxl=1.4.3=r44he58e087_1\n", - " - r-recipes=1.1.1=r44hc72bb7e_0\n", - " - r-rematch=2.0.0=r44hc72bb7e_1\n", - " - r-rematch2=2.1.2=r44hc72bb7e_4\n", - " - r-repr=1.1.7=r44h785f33e_1\n", - " - r-reprex=2.1.1=r44hc72bb7e_1\n", - " - r-reshape2=1.4.4=r44h0d4f4ea_4\n", - " - r-rlang=1.1.5=r44h93ab643_0\n", - " - r-rmarkdown=2.29=r44hc72bb7e_0\n", - " - r-rpart=4.1.24=r44h2b5f3a1_0\n", - " - r-rsample=1.2.1=r44hc72bb7e_1\n", - " - r-rstudioapi=0.17.1=r44hc72bb7e_0\n", - " - r-rvest=1.0.4=r44hc72bb7e_1\n", - " - r-sass=0.4.9=r44ha18555a_1\n", - " - r-scales=1.3.0=r44hc72bb7e_1\n", - " - r-selectr=0.4_2=r44hc72bb7e_4\n", - " - r-sfd=0.1.0=r44hc72bb7e_1\n", - " - r-shape=1.4.6.1=r44ha770c72_1\n", - " - r-shiny=1.10.0=r44h785f33e_0\n", - " - r-slider=0.3.2=r44h93ab643_0\n", - " - r-sourcetools=0.1.7_1=r44ha18555a_2\n", - " - r-sparsevctrs=0.2.0=r44h2b5f3a1_1\n", - " - r-squarem=2021.1=r44hc72bb7e_3\n", - " - r-stringi=1.8.4=r44h33cde33_3\n", - " - r-stringr=1.5.1=r44h785f33e_1\n", - " - r-survival=3.8_3=r44h2b5f3a1_0\n", - " - r-sys=3.4.3=r44h2b5f3a1_0\n", - " - r-systemfonts=1.2.1=r44h5c043a3_0\n", - " - r-textshaping=0.4.0=r44ha47bcaa_2\n", - " - r-tibble=3.2.1=r44hdb488b9_3\n", - " - r-tidymodels=1.3.0=r44hc72bb7e_0\n", - " - r-tidyr=1.3.1=r44h0d4f4ea_1\n", - " - r-tidyselect=1.2.1=r44hc72bb7e_1\n", - " - r-tidyverse=2.0.0=r44h785f33e_2\n", - " - r-timechange=0.3.0=r44ha18555a_1\n", - " - r-timedate=4041.110=r44hc72bb7e_0\n", - " - r-tinytex=0.56=r44hc72bb7e_0\n", - " - r-tune=1.3.0=r44hc72bb7e_0\n", - " - r-tzdb=0.4.0=r44ha18555a_2\n", - " - r-utf8=1.2.4=r44hb1dbf0f_1\n", - " - r-uuid=1.2_1=r44hdb488b9_0\n", - " - r-vctrs=0.6.5=r44h0d4f4ea_1\n", - " - r-viridislite=0.4.2=r44hc72bb7e_2\n", - " - r-vroom=1.6.5=r44h0d4f4ea_1\n", - " - r-warp=0.2.1=r44hb1dbf0f_1\n", - " - r-withr=3.0.2=r44hc72bb7e_0\n", - " - r-workflows=1.2.0=r44hc72bb7e_0\n", - " - r-workflowsets=1.1.0=r44h785f33e_1\n", - " - r-xfun=0.51=r44h93ab643_0\n", - " - r-xml2=1.3.6=r44h8194278_2\n", - " - r-xtable=1.8_4=r44hc72bb7e_6\n", - " - r-yaml=2.3.10=r44hdb488b9_0\n", - " - r-yardstick=1.3.2=r44h2b5f3a1_0\n", - " - rav1e=0.6.6=he8a937b_2\n", - " - rdma-core=55.0=h5888daf_0\n", - " - re2=2023.09.01=h7f4b329_2\n", - " - readline=8.2=h8228510_1\n", - " - referencing=0.36.2=pyh29332c3_0\n", - " - regex=2024.11.6=py310ha75aee5_0\n", - " - reproc=14.2.5.post0=hb9d3cd8_0\n", - " - reproc-cpp=14.2.5.post0=h5888daf_0\n", - " - requests=2.32.3=pyhd8ed1ab_1\n", - " - requests-oauthlib=2.0.0=pyhd8ed1ab_1\n", - " - rfc3339-validator=0.1.4=pyhd8ed1ab_1\n", - " - rfc3986-validator=0.1.1=pyh9f0ad1d_0\n", - " - rpds-py=0.23.1=py310hc1293b2_0\n", - " - rsa=4.9=pyhd8ed1ab_1\n", - " - rtree=1.4.0=pyh11ca60a_1\n", - " - ruamel.yaml=0.17.21=py310h1fa729e_3\n", - " - ruamel.yaml.clib=0.2.8=py310ha75aee5_1\n", - " - s2n=1.5.5=h3931f03_0\n", - " - scikit-learn=1.6.1=py310h27f47ee_0\n", - " - scikit-learn-intelex=2025.1.0=py310hedb57c4_0\n", - " - scipy=1.15.2=py310h1d65ade_0\n", - " - seaborn=0.13.2=hd8ed1ab_3\n", - " - seaborn-base=0.13.2=pyhd8ed1ab_3\n", - " - sed=4.8=he412f7d_0\n", - " - send2trash=1.8.3=pyh0d859eb_1\n", - " - setuptools=75.8.0=pyhff2d567_0\n", - " - shapely=2.0.7=py310had3dfd6_0\n", - " - six=1.17.0=pyhd8ed1ab_0\n", - " - smmap=5.0.2=pyhd8ed1ab_0\n", - " - snappy=1.2.1=h8bd8927_1\n", - " - sniffio=1.3.1=pyhd8ed1ab_1\n", - " - soupsieve=2.5=pyhd8ed1ab_1\n", - " - sqlite=3.48.0=h9eae976_0\n", - " - stack_data=0.6.3=pyhd8ed1ab_1\n", - " - statsmodels=0.14.4=py310hf462985_0\n", - " - svt-av1=3.0.0=h5888daf_0\n", - " - sympy=1.13.3=pyh2585a3b_105\n", - " - sysroot_linux-64=2.17=h0157908_18\n", - " - tangled-up-in-unicode=0.2.0=pyhd8ed1ab_0\n", - " - tbb=2022.0.0=hceb3a55_0\n", - " - terminado=0.18.1=pyh0d859eb_0\n", - " - threadpoolctl=3.5.0=pyhc1e730c_0\n", - " - tinycss2=1.4.0=pyhd8ed1ab_0\n", - " - tk=8.6.13=noxft_h4845f30_101\n", - " - tktable=2.10=h8bc8fbc_6\n", - " - tomli=2.2.1=pyhd8ed1ab_1\n", - " - tornado=6.4.2=py310ha75aee5_0\n", - " - tqdm=4.67.1=pyhd8ed1ab_1\n", - " - traitlets=5.9.0=pyhd8ed1ab_0\n", - " - triton=3.1.0=cuda126py310h382487b_6\n", - " - truststore=0.10.0=pyhd8ed1ab_0\n", - " - types-python-dateutil=2.9.0.20241206=pyhd8ed1ab_0\n", - " - typing-extensions=4.12.2=hd8ed1ab_1\n", - " - typing_extensions=4.12.2=pyha770c72_1\n", - " - typing_utils=0.1.0=pyhd8ed1ab_1\n", - " - tzdata=2025a=h78e105d_0\n", - " - ucx=1.18.0=h8887438_1\n", - " - umf=2025.0.4=hb3528f5_6\n", - " - unicodedata2=16.0.0=py310ha75aee5_0\n", - " - uri-template=1.3.0=pyhd8ed1ab_1\n", - " - uriparser=0.9.8=hac33072_0\n", - " - uritemplate=4.1.1=pyhd8ed1ab_1\n", - " - urllib3=1.26.19=pyhd8ed1ab_0\n", - " - visions=0.7.1=pyhd8ed1ab_0\n", - " - wayland=1.23.1=h3e06ad9_0\n", - " - wcwidth=0.2.13=pyhd8ed1ab_1\n", - " - webcolors=24.11.1=pyhd8ed1ab_0\n", - " - webencodings=0.5.1=pyhd8ed1ab_3\n", - " - websocket-client=1.8.0=pyhd8ed1ab_1\n", - " - wheel=0.45.1=pyhd8ed1ab_1\n", - " - widgetsnbextension=4.0.13=pyhd8ed1ab_1\n", - " - x265=3.5=h924138e_3\n", - " - xcb-util=0.4.1=hb711507_2\n", - " - xcb-util-cursor=0.1.5=hb9d3cd8_0\n", - " - xcb-util-image=0.4.0=hb711507_2\n", - " - xcb-util-keysyms=0.4.1=hb711507_0\n", - " - xcb-util-renderutil=0.3.10=hb711507_0\n", - " - xcb-util-wm=0.4.2=hb711507_0\n", - " - xerces-c=3.2.5=h988505b_2\n", - " - xkeyboard-config=2.43=hb9d3cd8_0\n", - " - xorg-libice=1.1.2=hb9d3cd8_0\n", - " - xorg-libsm=1.2.5=he73a12e_0\n", - " - xorg-libx11=1.8.11=h4f16b4b_0\n", - " - xorg-libxau=1.0.12=hb9d3cd8_0\n", - " - xorg-libxcomposite=0.4.6=hb9d3cd8_2\n", - " - xorg-libxcursor=1.2.3=hb9d3cd8_0\n", - " - xorg-libxdamage=1.1.6=hb9d3cd8_0\n", - " - xorg-libxdmcp=1.1.5=hb9d3cd8_0\n", - " - xorg-libxext=1.3.6=hb9d3cd8_0\n", - " - xorg-libxfixes=6.0.1=hb9d3cd8_0\n", - " - xorg-libxi=1.8.2=hb9d3cd8_0\n", - " - xorg-libxrandr=1.5.4=hb9d3cd8_0\n", - " - xorg-libxrender=0.9.12=hb9d3cd8_0\n", - " - xorg-libxt=1.3.1=hb9d3cd8_0\n", - " - xorg-libxtst=1.2.5=hb9d3cd8_3\n", - " - xorg-libxxf86vm=1.1.6=hb9d3cd8_0\n", - " - xyzservices=2025.1.0=pyhd8ed1ab_0\n", - " - xz=5.6.3=hbcc6ac9_1\n", - " - xz-gpl-tools=5.6.3=hbcc6ac9_1\n", - " - xz-tools=5.6.3=hb9d3cd8_1\n", - " - yaml=0.2.5=h7f98852_2\n", - " - yaml-cpp=0.8.0=h59595ed_0\n", - " - yarl=1.18.3=py310h89163eb_1\n", - " - zeromq=4.3.5=h3b0a872_7\n", - " - zipp=3.21.0=pyhd8ed1ab_1\n", - " - zlib=1.3.1=hb9d3cd8_2\n", - " - zstandard=0.23.0=py310ha39cb0e_1\n", - " - zstd=1.5.6=ha6fb4c9_0\n", - " - pip:\n", - " - absl-py==2.1.0\n", - " - astunparse==1.6.3\n", - " - distlib==0.3.9\n", - " - filelock==3.18.0\n", - " - flatbuffers==25.2.10\n", - " - gast==0.6.0\n", - " - google-pasta==0.2.0\n", - " - h5py==3.13.0\n", - " - keras==2.14.0\n", - " - libclang==18.1.1\n", - " - markdown==3.7\n", - " - ml-dtypes==0.2.0\n", - " - opt-einsum==3.4.0\n", - " - tensorboard==2.14.1\n", - " - tensorboard-data-server==0.7.2\n", - " - tensorflow==2.14.0\n", - " - tensorflow-estimator==2.14.0\n", - " - tensorflow-io-gcs-filesystem==0.37.1\n", - " - termcolor==2.5.0\n", - " - torch==2.0.1+cu118\n", - " - torchaudio==2.0.2+cu118\n", - " - torchvision==0.15.2+cu118\n", - " - virtualenv==20.31.2\n", - " - werkzeug==3.1.3\n", - " - wrapt==1.14.1\n", - "prefix: /opt/conda\n" - ] - } - ], + "outputs": [], "source": [ "!conda env export" ] @@ -1588,27 +636,11 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[33m[W 2025-05-27 18:34:20.097 LabApp]\u001b[m 'kernel_spec_manager_class' has moved from NotebookApp to ServerApp. This config will be passed to ServerApp. Be sure to update your config before our next release.\n", - "JupyterLab v4.3.4\n", - "/opt/conda/share/jupyter/labextensions\n", - " nbdime-jupyterlab v3.0.2 \u001b[32menabled\u001b[0m \u001b[32mOK\u001b[0m\n", - " jupyterlab-jupytext v1.4.3 \u001b[32menabled\u001b[0m \u001b[32mOK\u001b[0m (python, jupytext)\n", - " jupyterlab_pygments v0.3.0 \u001b[32menabled\u001b[0m \u001b[32mOK\u001b[0m (python, jupyterlab_pygments)\n", - " @jupyter-widgets/jupyterlab-manager v5.0.13 \u001b[32menabled\u001b[0m \u001b[32mOK\u001b[0m (python, jupyterlab_widgets)\n", - " @jupyterlab/git v0.50.2 \u001b[32menabled\u001b[0m \u001b[32mOK\u001b[0m (python, jupyterlab-git)\n", - "\n" - ] - } - ], + "outputs": [], "source": [ "!jupyter labextension list" ] @@ -1622,19 +654,11 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "4\n" - ] - } - ], + "outputs": [], "source": [ "!grep ^processor /proc/cpuinfo | wc -l" ] @@ -1648,19 +672,11 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "MemTotal: 26672900 kB\n" - ] - } - ], + "outputs": [], "source": [ "!grep \"^MemTotal:\" /proc/meminfo" ] @@ -1705,4 +721,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/first_hour_on_vwb/working_with_resources.ipynb b/first_hour_on_vwb/working_with_resources.ipynb index a05eaa4..d5670ba 100644 --- a/first_hour_on_vwb/working_with_resources.ipynb +++ b/first_hour_on_vwb/working_with_resources.ipynb @@ -34,30 +34,7 @@ "id": "d975e698c9a4", "tags": [] }, - "source": [ - "### Objective\n", - "\n", - "Use this notebook to perform common workspace resource operations including:\n", - "- [Add a referenced resource](#add-ref-resources)\n", - " - [Add a GitHub repo](#add-git-repo)\n", - " - [Add a BigQuery dataset](#add-bq-dataset)\n", - " - [Add a BigQuery table](#add-bq-table)\n", - " - [Add a Google Cloud Storage bucket](#add-gcs-bucket)\n", - " - [Add a Google Cloud Storage object](#add-gcs-object)\n", - "- [Create a controlled resource](#add-controlled-resource)\n", - " - [Create a BigQuery dataset](#create-bq-dataset)\n", - " - [Create a Google Cloud Storage bucket](#create-gcs-bucket)\n", - " - [Create a cloud environment](#create-cloud-env)\n", - "\n", - "#### How to run this notebook\n", - "\n", - "1. Run the [Notebook setup](#notebook-setup) section before running the cells of the other sections.\n", - "1. Each subsection provides information about a particular type of workspace resource and creates a widget. Run the cell in a particular subsection to create the widget, then input your resource's information and click the widget's button to add or create a resource.\n", - "\n", - "#### Costs\n", - "\n", - "This notebook takes less than a minute to run, which will typically cost less than $0.01 of compute time on your cloud environment.\n" - ] + "source": "### Objective\n\nUse this notebook to perform common workspace resource operations including:\n- [Add a referenced resource](#add-ref-resources)\n - [Add a GitHub repo](#add-git-repo)\n - [Add a BigQuery dataset](#add-bq-dataset)\n - [Add a BigQuery table](#add-bq-table)\n - [Add a Google Cloud Storage bucket](#add-gcs-bucket)\n - [Add a Google Cloud Storage object](#add-gcs-object)\n- [Create a controlled resource](#add-controlled-resource)\n - [Create a BigQuery dataset](#create-bq-dataset)\n - [Create a Google Cloud Storage bucket](#create-gcs-bucket)\n\n#### How to run this notebook\n\n1. Run the [Notebook setup](#notebook-setup) section before running the cells of the other sections.\n1. Each subsection provides information about a particular type of workspace resource and creates a widget. Run the cell in a particular subsection to create the widget, then input your resource's information and click the widget's button to add or create a resource.\n\n#### Costs\n\nThis notebook takes less than a minute to run, which will typically cost less than $0.01 of compute time on your cloud environment.\n" }, { "cell_type": "markdown", @@ -75,31 +52,7 @@ "tags": [] }, "outputs": [], - "source": [ - "from IPython.display import display, HTML\n", - "import ipywidgets as widgets\n", - "import subprocess\n", - "import widget_utils as wu\n", - "\n", - "'''\n", - "Resolves bucket URL from bucket reference in workspace.\n", - "'''\n", - "def get_bucket_url_from_reference(bucket_reference):\n", - " BUCKET_CMD_OUTPUT = !wb resolve --name={bucket_reference}\n", - " BUCKET = BUCKET_CMD_OUTPUT[0]\n", - " return BUCKET\n", - "\n", - "'''\n", - "Resolves current workspace ID from workspace description.\n", - "'''\n", - "def get_current_workspace_id():\n", - " WORKSPACE_CMD_OUTPUT = !wb workspace describe --format=json | jq --raw-output \".id\"\n", - " WORKSPACE_ID = WORKSPACE_CMD_OUTPUT[0]\n", - " return WORKSPACE_ID\n", - "\n", - "CURRENT_WORKSPACE_ID = get_current_workspace_id()\n", - "print(f'Workspace ID: {CURRENT_WORKSPACE_ID}')" - ] + "source": "from IPython.display import display\nimport ipywidgets as widgets\nimport subprocess\nimport widget_utils as wu\n\n'''\nResolves bucket URL from bucket reference in workspace.\n'''\ndef get_bucket_url_from_reference(bucket_reference):\n BUCKET_CMD_OUTPUT = !wb resolve --name={bucket_reference}\n BUCKET = BUCKET_CMD_OUTPUT[0]\n return BUCKET\n\n'''\nResolves current workspace ID from workspace description.\n'''\ndef get_current_workspace_id():\n WORKSPACE_CMD_OUTPUT = !wb workspace describe --format=json | jq --raw-output \".id\"\n WORKSPACE_ID = WORKSPACE_CMD_OUTPUT[0]\n return WORKSPACE_ID\n\nCURRENT_WORKSPACE_ID = get_current_workspace_id()\nprint(f'Workspace ID: {CURRENT_WORKSPACE_ID}')" }, { "cell_type": "markdown", @@ -1012,149 +965,6 @@ "display(create_gcs_bucket_widget.vb)" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 3. Create a GCP notebook\n", - "\n", - "\n", - "Using the widget in this section, you can create a GCP notebook as a controlled resource of this workspace.\n", - "Run the cell below to create a widget, then populate the widget's input fields and click the button to add a cloud environment as a resource controlled by your workspace.\n", - "\n", - "For complex use cases, the Workbench CLI allows for the specification of some [additional parameters](https://cloud.google.com/vertex-ai/docs/workbench/reference/rest/v1/projects.locations.instances#Instance) which the widget doesn't support.\n", - "\n", - "Widget parameters include:\n", - "\n", - "- `Access`: Defaults to `SHARED_ACCESS`, which grants bucket access to all users with access to the workspace, based on the user's workspace access (Reader or Writer). `PRIVATE_ACCESS` ensures the bucket and its contents cannot be shared.\n", - "- `Cloning`: Read about these options [in the Cloning Instruction section](#choosing-the-right-cloning-instruction). Default is `COPY_REFERENCE`.\n", - "- `Description`: (_Optional_) Should describe the purpose of the cloud environment.\n", - "- `Instance ID`: (_Optional_) A unique name given to the cloud environment which cannot be changed later. If none is provided, the instance ID will be set to the name. This ID is visible in the Google Cloud console for debugging, not in the VWB UI.\n", - "- `Name`: This name is displayed in the VWB UI Environments tab. The value should be brief and memorable while communicating the purpose of the cloud environment (e.g. `analysis-notebooks-cloud-env`).\n", - "- `Post-startup Script`: (_Optional_) Path to a Bash script that automatically runs after your cloud env fully boots up. The path must be a URL or Cloud Storage path, e.g. 'gs://path-to-file/file-name'. If no post-startup script is provided, the [default script](https://github.com/verily-src/terra-workspace-manager/blob/main/service/src/main/java/bio/terra/workspace/service/resource/controlled/cloud/gcp/ainotebook/post-startup.sh) will be used, which is recommended in most cases.\n", - "\n", - "Once you've run the cell below, populated the input fields and clicked the button, the output should resemble:\n", - "\n", - "```\n", - "Successfully added controlled GCP Notebook instance.\n", - "Name: \n", - "Description: \n", - "Type: AI_NOTEBOOK\n", - "Stewardship: CONTROLLED\n", - "Cloning: COPY_NOTHING\n", - "Access scope: PRIVATE_ACCESS\n", - "Managed by: USER\n", - "Region: us-central1\n", - "Private user: \n", - "Properties: class Properties {\n", - " []\n", - "}\n", - "GCP project id: \n", - "Instance id: \n", - "Location: us-central1-a\n", - "Instance name: projects//locations/us-central1-a/instances/\n", - "State: PROVISIONING\n", - "Metadata:\n", - " notebooks-api-version: v1\n", - " post-startup-script: https://raw.githubusercontent.com/verily-src/terra-workspace-manager/main/service/src/main/java/bio/terra/workspace/service/resource/controlled/cloud/gcp/ainotebook/post-startup.sh\n", - " disable-swap-binaries: true\n", - " serial-port-logging-enable: true\n", - " wb-cli-server: verily\n", - " workspace-id: \n", - " proxy-mode: service_account\n", - " enable-guest-attributes: TRUE\n", - " warmup-libraries: matplotlib.pyplot\n", - " shutdown-script: /opt/deeplearning/bin/shutdown_script.sh\n", - " notebooks-api: PROD\n", - "Proxy URL: (undefined)\n", - "Create time: \n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "class CreateGcpNotebookWidget(object):\n", - " def __init__(self):\n", - " self.label = widgets.Label(\n", - " value='Please provide appropriate values in the input boxes.')\n", - " self.access_drop_down = wu.DropdownInputWidget(\n", - " ['SHARED_ACCESS', 'PRIVATE_ACCESS'], 'SHARED_ACCESS', \"Access:\").get()\n", - " self.cloning_drop_down = wu.DropdownInputWidget(\n", - " ['COPY_NOTHING', 'COPY_DEFINITION', 'COPY_RESOURCE', 'COPY_REFERENCE'], 'COPY_REFERENCE', \"Cloning:\").get()\n", - " self.input_name = wu.TextInputWidget(\"\", \"Name:\")\n", - " self.input_description = wu.TextInputWidget(\n", - " \"\", \"Description:\")\n", - " self.input_instance_id = wu.TextInputWidget(\n", - " \"\", \"Instance ID (Cannot Be Changed) - optional:\")\n", - " self.input_post_startup_script = wu.TextInputWidget(\n", - " \"\", \"Post-Startup Script - optional:\")\n", - " self.output = widgets.Output()\n", - " self.button = wu.StyledButton(\n", - " 'Create cloud environment', 'Click to create a cloud environment as a controlled resource.', 'plus').get()\n", - " self.button.on_click(self.create_gcp_notebook)\n", - " self.toggle_optional = wu.ShowOptionalCheckbox().get()\n", - " self.toggle_optional.observe(self.toggle)\n", - " self.required_fields = [\n", - " self.toggle_optional, self.label, self.access_drop_down,\n", - " self.cloning_drop_down, self.input_description.get(),\n", - " self.input_name.get(), self.button, self.output]\n", - " self.vb = widgets.VBox(\n", - " children=self.required_fields,\n", - " layout=wu.vbox_layout\n", - " )\n", - "\n", - " def toggle(self, event):\n", - " self.output.clear_output()\n", - " with self.output:\n", - " if self.toggle_optional.value == True:\n", - " parameterList = []\n", - " for r in self.required_fields:\n", - " parameterList.append(r)\n", - " # Insert optional fields, preserving alphabetical order.\n", - " parameterList.insert(5, self.input_instance_id.get())\n", - " parameterList.insert(7, self.input_post_startup_script.get())\n", - " self.vb.children = parameterList\n", - " else:\n", - " if self.vb.children != self.required_fields:\n", - " self.vb.children = self.required_fields\n", - "\n", - " def create_gcp_notebook(self, b):\n", - " with self.output:\n", - " description_content = f\"\\\"{self.input_description.get().value}\\\"\"\n", - " commandList = [\n", - " \"wb\", \"resource\", \"create\", \"gcp-notebook\",\n", - " f\"--access={self.access_drop_down.value}\",\n", - " f\"--cloning={self.cloning_drop_down.value}\",\n", - " f\"--name={self.input_name.get().value}\",\n", - " f\"--description={description_content}\",\n", - " f\"--workspace={CURRENT_WORKSPACE_ID}\"\n", - " ]\n", - " if self.input_instance_id.get().value != \"\":\n", - " commandList.append(\n", - " f\"--instance-id={self.input_instance_id.get().value}\")\n", - " if self.input_post_startup_script.get().value != \"\":\n", - " commandList.append(\n", - " f\"--post-startup-script={self.input_post_startup_script.get().value}\")\n", - "\n", - " print('Running command:')\n", - " print('\\n'.join(commandList))\n", - " print('')\n", - "\n", - " result = subprocess.run(\n", - " commandList, capture_output=True, text=True)\n", - " print(result.stderr) if not result.stdout else print(result.stdout)\n", - "\n", - "\n", - "create_gcp_notebook_widget = CreateGcpNotebookWidget()\n", - "display(create_gcp_notebook_widget.vb)" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -1259,13 +1069,6 @@ "license that can be found in the LICENSE file or at \n", "https://developers.google.com/open-source/licenses/bsd\n" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { @@ -1297,4 +1100,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/notebook-snapshots/first_hour_on_vwb/creating_a_data_collection.html b/notebook-snapshots/first_hour_on_vwb/creating_a_data_collection.html new file mode 100644 index 0000000..a40d78b --- /dev/null +++ b/notebook-snapshots/first_hour_on_vwb/creating_a_data_collection.html @@ -0,0 +1,8170 @@ + + + + + +creating_a_data_collection + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/notebook-snapshots/first_hour_on_vwb/creating_a_data_collection.pdf b/notebook-snapshots/first_hour_on_vwb/creating_a_data_collection.pdf new file mode 100644 index 0000000..0f2ec88 Binary files /dev/null and b/notebook-snapshots/first_hour_on_vwb/creating_a_data_collection.pdf differ diff --git a/notebook-snapshots/first_hour_on_vwb/working_with_bq_resources.html b/notebook-snapshots/first_hour_on_vwb/working_with_bq_resources.html new file mode 100644 index 0000000..f750278 --- /dev/null +++ b/notebook-snapshots/first_hour_on_vwb/working_with_bq_resources.html @@ -0,0 +1,8049 @@ + + + + + +working_with_bq_resources + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ + diff --git a/notebook-snapshots/first_hour_on_vwb/working_with_bq_resources.pdf b/notebook-snapshots/first_hour_on_vwb/working_with_bq_resources.pdf new file mode 100644 index 0000000..84f0bd3 Binary files /dev/null and b/notebook-snapshots/first_hour_on_vwb/working_with_bq_resources.pdf differ diff --git a/notebook-snapshots/first_hour_on_vwb/working_with_groups.html b/notebook-snapshots/first_hour_on_vwb/working_with_groups.html new file mode 100644 index 0000000..46a9554 --- /dev/null +++ b/notebook-snapshots/first_hour_on_vwb/working_with_groups.html @@ -0,0 +1,9042 @@ + + + + + +working_with_groups + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/notebook-snapshots/first_hour_on_vwb/working_with_groups.pdf b/notebook-snapshots/first_hour_on_vwb/working_with_groups.pdf new file mode 100644 index 0000000..3c6fdd8 Binary files /dev/null and b/notebook-snapshots/first_hour_on_vwb/working_with_groups.pdf differ diff --git a/notebook-snapshots/first_hour_on_vwb/working_with_resources.html b/notebook-snapshots/first_hour_on_vwb/working_with_resources.html new file mode 100644 index 0000000..dd15664 --- /dev/null +++ b/notebook-snapshots/first_hour_on_vwb/working_with_resources.html @@ -0,0 +1,8355 @@ + + + + + +working_with_resources + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/notebook-snapshots/first_hour_on_vwb/working_with_resources.pdf b/notebook-snapshots/first_hour_on_vwb/working_with_resources.pdf new file mode 100644 index 0000000..1b57b4e Binary files /dev/null and b/notebook-snapshots/first_hour_on_vwb/working_with_resources.pdf differ