pybiolib 1.2.883__py3-none-any.whl → 1.2.1890__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.
Files changed (124) hide show
  1. biolib/__init__.py +33 -10
  2. biolib/_data_record/data_record.py +220 -126
  3. biolib/_index/index.py +55 -0
  4. biolib/_index/query_result.py +103 -0
  5. biolib/_internal/add_copilot_prompts.py +24 -11
  6. biolib/_internal/add_gui_files.py +81 -0
  7. biolib/_internal/data_record/__init__.py +1 -1
  8. biolib/_internal/data_record/data_record.py +1 -18
  9. biolib/_internal/data_record/push_data.py +65 -16
  10. biolib/_internal/data_record/remote_storage_endpoint.py +18 -13
  11. biolib/_internal/file_utils.py +48 -0
  12. biolib/_internal/lfs/cache.py +4 -2
  13. biolib/_internal/push_application.py +95 -24
  14. biolib/_internal/runtime.py +2 -0
  15. biolib/_internal/string_utils.py +13 -0
  16. biolib/_internal/{llm_instructions → templates/copilot_template}/.github/instructions/style-general.instructions.md +5 -0
  17. biolib/_internal/templates/copilot_template/.github/instructions/style-react-ts.instructions.md +47 -0
  18. biolib/_internal/templates/copilot_template/.github/prompts/biolib_onboard_repo.prompt.md +19 -0
  19. biolib/_internal/templates/dashboard_template/.biolib/config.yml +5 -0
  20. biolib/_internal/templates/{init_template → github_workflow_template}/.github/workflows/biolib.yml +7 -2
  21. biolib/_internal/templates/gitignore_template/.gitignore +10 -0
  22. biolib/_internal/templates/gui_template/.yarnrc.yml +1 -0
  23. biolib/_internal/templates/gui_template/App.tsx +53 -0
  24. biolib/_internal/templates/gui_template/Dockerfile +27 -0
  25. biolib/_internal/templates/gui_template/biolib-sdk.ts +82 -0
  26. biolib/_internal/templates/gui_template/dev-data/output.json +7 -0
  27. biolib/_internal/templates/gui_template/index.css +5 -0
  28. biolib/_internal/templates/gui_template/index.html +13 -0
  29. biolib/_internal/templates/gui_template/index.tsx +10 -0
  30. biolib/_internal/templates/gui_template/package.json +27 -0
  31. biolib/_internal/templates/gui_template/tsconfig.json +24 -0
  32. biolib/_internal/templates/gui_template/vite-plugin-dev-data.ts +50 -0
  33. biolib/_internal/templates/gui_template/vite.config.mts +10 -0
  34. biolib/_internal/templates/init_template/.biolib/config.yml +1 -0
  35. biolib/_internal/templates/init_template/Dockerfile +5 -1
  36. biolib/_internal/templates/init_template/run.py +6 -15
  37. biolib/_internal/templates/init_template/run.sh +1 -0
  38. biolib/_internal/templates/templates.py +21 -1
  39. biolib/_internal/utils/__init__.py +47 -0
  40. biolib/_internal/utils/auth.py +46 -0
  41. biolib/_internal/utils/job_url.py +33 -0
  42. biolib/_internal/utils/multinode.py +12 -14
  43. biolib/_runtime/runtime.py +15 -2
  44. biolib/_session/session.py +7 -5
  45. biolib/_shared/__init__.py +0 -0
  46. biolib/_shared/types/__init__.py +74 -0
  47. biolib/_shared/types/account.py +12 -0
  48. biolib/_shared/types/account_member.py +8 -0
  49. biolib/{_internal → _shared}/types/experiment.py +1 -0
  50. biolib/_shared/types/resource.py +37 -0
  51. biolib/_shared/types/resource_deploy_key.py +11 -0
  52. biolib/{_internal → _shared}/types/resource_version.py +8 -2
  53. biolib/_shared/types/user.py +19 -0
  54. biolib/_shared/utils/__init__.py +7 -0
  55. biolib/_shared/utils/resource_uri.py +75 -0
  56. biolib/api/client.py +5 -48
  57. biolib/app/app.py +97 -55
  58. biolib/biolib_api_client/api_client.py +3 -47
  59. biolib/biolib_api_client/app_types.py +1 -1
  60. biolib/biolib_api_client/biolib_app_api.py +31 -6
  61. biolib/biolib_api_client/biolib_job_api.py +1 -1
  62. biolib/biolib_api_client/user_state.py +34 -2
  63. biolib/biolib_binary_format/module_input.py +8 -0
  64. biolib/biolib_binary_format/remote_endpoints.py +3 -3
  65. biolib/biolib_binary_format/remote_stream_seeker.py +39 -25
  66. biolib/biolib_logging.py +1 -1
  67. biolib/cli/__init__.py +2 -2
  68. biolib/cli/auth.py +4 -16
  69. biolib/cli/data_record.py +82 -0
  70. biolib/cli/index.py +32 -0
  71. biolib/cli/init.py +393 -71
  72. biolib/cli/lfs.py +1 -1
  73. biolib/cli/run.py +9 -6
  74. biolib/cli/start.py +14 -1
  75. biolib/compute_node/job_worker/executors/docker_executor.py +31 -9
  76. biolib/compute_node/job_worker/executors/docker_types.py +1 -1
  77. biolib/compute_node/job_worker/executors/types.py +6 -5
  78. biolib/compute_node/job_worker/job_storage.py +2 -1
  79. biolib/compute_node/job_worker/job_worker.py +155 -90
  80. biolib/compute_node/job_worker/large_file_system.py +2 -6
  81. biolib/compute_node/job_worker/network_alloc.py +99 -0
  82. biolib/compute_node/job_worker/network_buffer.py +240 -0
  83. biolib/compute_node/job_worker/utilization_reporter_thread.py +2 -2
  84. biolib/compute_node/remote_host_proxy.py +163 -79
  85. biolib/compute_node/utils.py +2 -0
  86. biolib/compute_node/webserver/compute_node_results_proxy.py +189 -0
  87. biolib/compute_node/webserver/proxy_utils.py +28 -0
  88. biolib/compute_node/webserver/webserver.py +64 -19
  89. biolib/experiments/experiment.py +111 -16
  90. biolib/jobs/job.py +128 -31
  91. biolib/jobs/job_result.py +74 -34
  92. biolib/jobs/types.py +1 -0
  93. biolib/sdk/__init__.py +28 -3
  94. biolib/typing_utils.py +1 -1
  95. biolib/utils/cache_state.py +8 -5
  96. biolib/utils/multipart_uploader.py +24 -18
  97. biolib/utils/seq_util.py +1 -1
  98. pybiolib-1.2.1890.dist-info/METADATA +41 -0
  99. pybiolib-1.2.1890.dist-info/RECORD +177 -0
  100. {pybiolib-1.2.883.dist-info → pybiolib-1.2.1890.dist-info}/WHEEL +1 -1
  101. pybiolib-1.2.1890.dist-info/entry_points.txt +2 -0
  102. biolib/_internal/llm_instructions/.github/instructions/style-react-ts.instructions.md +0 -22
  103. biolib/_internal/templates/init_template/.gitignore +0 -2
  104. biolib/_internal/types/__init__.py +0 -6
  105. biolib/_internal/types/resource.py +0 -18
  106. biolib/biolib_download_container.py +0 -38
  107. biolib/cli/download_container.py +0 -14
  108. biolib/utils/app_uri.py +0 -57
  109. pybiolib-1.2.883.dist-info/METADATA +0 -50
  110. pybiolib-1.2.883.dist-info/RECORD +0 -148
  111. pybiolib-1.2.883.dist-info/entry_points.txt +0 -3
  112. /biolib/{_internal/llm_instructions → _index}/__init__.py +0 -0
  113. /biolib/_internal/{llm_instructions → templates/copilot_template}/.github/instructions/general-app-knowledge.instructions.md +0 -0
  114. /biolib/_internal/{llm_instructions → templates/copilot_template}/.github/instructions/style-python.instructions.md +0 -0
  115. /biolib/_internal/{llm_instructions → templates/copilot_template}/.github/prompts/biolib_app_inputs.prompt.md +0 -0
  116. /biolib/_internal/{llm_instructions → templates/copilot_template}/.github/prompts/biolib_run_apps.prompt.md +0 -0
  117. /biolib/{_internal → _shared}/types/app.py +0 -0
  118. /biolib/{_internal → _shared}/types/data_record.py +0 -0
  119. /biolib/{_internal → _shared}/types/file_node.py +0 -0
  120. /biolib/{_internal → _shared}/types/push.py +0 -0
  121. /biolib/{_internal → _shared}/types/resource_permission.py +0 -0
  122. /biolib/{_internal → _shared}/types/result.py +0 -0
  123. /biolib/{_internal → _shared}/types/typing.py +0 -0
  124. {pybiolib-1.2.883.dist-info → pybiolib-1.2.1890.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,13 @@
1
+ import re
2
+
3
+
4
+ def normalize_for_docker_tag(name: str) -> str:
5
+ if not name:
6
+ return ''
7
+
8
+ normalized = re.sub(r'[^a-z0-9-]', '-', name.lower())
9
+
10
+ normalized = re.sub(r'-+', '-', normalized)
11
+ normalized = normalized.strip('-')
12
+
13
+ return normalized
@@ -7,6 +7,11 @@ applyTo: '**'
7
7
  - Unit tests are not necessary. Tests should instead be written as simple examples demonstrating the functionality of relevant functions.
8
8
  - Always use 4 spaces for indentation.
9
9
  - Function definitions should be typed as specifically as possible.
10
+ - Always explicitly type function parameters and return values.
11
+ - Avoid using the `Any` type unless absolutely necessary; use specific types instead.
12
+ - Write code with the expectation that a strict type checker will be used.
13
+ - Prefer failing fast with clear errors over silently providing fallback values.
14
+ - Always lock down the exact version of external dependencies (e.g., use `package==1.2.3` instead of `package>=1.2.3`).
10
15
 
11
16
  # Code Comment Guidelines
12
17
  - Code comments should only be added for complex logic or unintuitive code that is not adequately explained by the function names themselves.
@@ -0,0 +1,47 @@
1
+ ---
2
+ applyTo: "**/*.ts,**/*.tsx,**/package.json,**/vite.config.*,**/.yarnrc.yml,**/yarn.lock,**/gui/**"
3
+ ---
4
+
5
+ Apply the [general coding guidelines](./style-general.instructions.md) to all code.
6
+
7
+ # General Project Guidelines
8
+ - Prefer using `export default function` over exporting at the end of the file.
9
+
10
+ # Package Management
11
+ - **Always use yarn instead of npm** for all package management operations
12
+ - Use `yarn install` instead of `npm install`
13
+ - Use `yarn add <package>` instead of `npm install <package>`
14
+ - Use `yarn remove <package>` instead of `npm uninstall <package>`
15
+ - Use `yarn dev` instead of `npm run dev`
16
+ - Use `yarn build` instead of `npm run build`
17
+
18
+ # Build Process
19
+ - BioLib GUI projects use Vite for building and development
20
+ - The build process compiles TypeScript and React into a single HTML file
21
+ - Always run `yarn build` to create the production build before deployment
22
+ - Use `yarn dev` for local development with hot reloading
23
+
24
+ # Configuration Files
25
+ - Respect the `.yarnrc.yml` configuration for yarn settings
26
+ - The `package.json` should specify `"packageManager": "yarn@4.6.0"` or similar
27
+ - Never modify yarn.lock manually - let yarn manage it automatically
28
+
29
+ # Dependencies
30
+ - Add new dependencies using `yarn add <package>` for runtime dependencies
31
+ - Add development dependencies using `yarn add -D <package>`
32
+ - Keep dependencies up to date but test thoroughly after updates
33
+
34
+ # TypeScript Guidelines
35
+ - Use TypeScript for all new code
36
+ - Follow functional programming principles where possible
37
+ - Use interfaces for data structures prefixed with I like `interface IRecord`
38
+ - Prefer immutable data (const, readonly)
39
+ - Use optional chaining (?.) and nullish coalescing (??) operators
40
+
41
+ # React Guidelines
42
+ - Use functional components with hooks
43
+ - Follow the React hooks rules (no conditional hooks)
44
+ - Prefer one component per file
45
+ - Use Tailwindcss for styling
46
+ - Extract props in components with object destructuring like `const { prop1, prop2 } = props;`
47
+ - Instantiate functional components with props like `export default function MyComponent(props: IProps) { ... }`.
@@ -0,0 +1,19 @@
1
+ ---
2
+ mode: 'agent'
3
+ tools: ['githubRepo', 'codebase']
4
+ description: 'Handle onboarding and implementing code from a GitHub repository into a biolib application, with focus on creating easily editable and maintainable code structure.'
5
+ ---
6
+
7
+ # Main task
8
+ Your task is to help onboard and implement code from a GitHub repository into a biolib application. This involves understanding the repository structure, implementing the core functionality, and ensuring the code is easily editable for future iterations.
9
+ Generally, you can do this by adding the repository into an src folder as a submodule, and reading the README.md file to understand how to run the code.
10
+ You will then call the relevant functions or classes from the cloned repository in your biolib application
11
+
12
+ ## Key requirements:
13
+ - Always ask the user for the GitHub repository if not already provided. Inform them that it needs to be in the format `author/repo_name`.
14
+ - Use the #githubRepo tool to examine the repository structure, README, and key files to understand the project.
15
+ - Focus on creating code that is easily editable and maintainable, as it's likely the implementation won't be perfect on the first attempt.
16
+ - Structure the code in a modular way that allows for easy modifications and improvements.
17
+ - Include clear comments for complex logic, but avoid over-commenting obvious code.
18
+ - Follow the existing biolib application patterns and conventions.
19
+ - Ensure all dependencies are properly specified in requirements.txt with versions locked down.
@@ -0,0 +1,5 @@
1
+ biolib_version: 2
2
+ assets: dist/
3
+ modules:
4
+ main:
5
+ image: "assets://index.html"
@@ -9,8 +9,13 @@ jobs:
9
9
  steps:
10
10
  - uses: actions/checkout@v4
11
11
  - name: Build
12
- run: docker build -t BIOLIB_REPLACE_DOCKER_TAG:latest .
12
+ run: BIOLIB_REPLACE_BUILD_COMMAND
13
13
  - name: Push
14
- run: biolib push $([ "$GITHUB_REF_NAME" != "main" ] && echo -n "--dev") BIOLIB_REPLACE_APP_URI
14
+ run: |
15
+ if [ "$GITHUB_REF_NAME" == "main" ]; then
16
+ biolib push BIOLIB_REPLACE_APP_URI
17
+ else
18
+ biolib push --dev BIOLIB_REPLACE_APP_URI:latest-dev
19
+ fi
15
20
  env:
16
21
  BIOLIB_TOKEN: ${{ secrets.BIOLIB_TOKEN }}
@@ -0,0 +1,10 @@
1
+ # Python
2
+ *__pycache__*
3
+ *.pyc
4
+
5
+ # GUI
6
+ .yarn
7
+ dist
8
+ yarn.lock
9
+ tsconfig.tsbuildinfo
10
+ node_modules
@@ -0,0 +1 @@
1
+ nodeLinker: node-modules
@@ -0,0 +1,53 @@
1
+ import { useState, useEffect } from "react";
2
+ import biolib from "./biolib-sdk";
3
+
4
+ export default function App() {
5
+ const [outputFileData, setOutputFileData] = useState<Uint8Array | null>(null);
6
+ const [loading, setLoading] = useState(true);
7
+
8
+ const loadOutputData = async () => {
9
+ setLoading(true);
10
+ try {
11
+ const data = await biolib.getOutputFileData("output.json");
12
+ setOutputFileData(data);
13
+ } catch (error) {
14
+ console.error("Error loading output data:", error);
15
+ setOutputFileData(null);
16
+ } finally {
17
+ setLoading(false);
18
+ }
19
+ };
20
+
21
+ useEffect(() => {
22
+ loadOutputData();
23
+ }, []);
24
+
25
+ return (
26
+ <div className="min-h-screen bg-gray-100 flex items-center justify-center">
27
+ <div className="text-center max-w-2xl mx-auto p-8">
28
+ <h1 className="text-4xl font-bold mb-4">
29
+ Hello, BioLib!
30
+ </h1>
31
+ <p className="text-lg mb-2">
32
+ You have successfully set up your BioLib GUI application.
33
+ </p>
34
+ <p className="italic mb-6">
35
+ This is a simple React template with Tailwind CSS styling.
36
+ </p>
37
+
38
+ <div className="mt-8 p-4 bg-white rounded-lg shadow">
39
+ <h2 className="text-xl font-semibold mb-4">Example: Reading Output Files</h2>
40
+ {loading ? (
41
+ <p className="text-gray-500">Loading output.json...</p>
42
+ ) : outputFileData ? (
43
+ <div className="p-3 bg-gray-50 rounded text-left">
44
+ <pre className="text-sm">{new TextDecoder().decode(outputFileData)}</pre>
45
+ </div>
46
+ ) : (
47
+ <p className="text-red-500">Failed to load output.json</p>
48
+ )}
49
+ </div>
50
+ </div>
51
+ </div>
52
+ );
53
+ }
@@ -0,0 +1,27 @@
1
+ # syntax=docker/dockerfile:1
2
+
3
+ FROM node:24.4.1-alpine3.21 AS gui_builder
4
+
5
+ WORKDIR /home/biolib/
6
+
7
+ RUN corepack enable
8
+ COPY .yarnrc.yml .
9
+ COPY package.json .
10
+ COPY vite.config.mts .
11
+ RUN yarn install
12
+
13
+ COPY gui gui
14
+ RUN yarn build
15
+
16
+ FROM python:3.13.5-slim
17
+ WORKDIR /home/biolib/
18
+
19
+ COPY requirements.txt .
20
+ RUN pip install --no-cache-dir -r requirements.txt
21
+
22
+ COPY run.sh .
23
+ COPY run.py .
24
+
25
+ RUN mkdir output
26
+
27
+ COPY --from=gui_builder /home/biolib/gui/dist/index.html result.html
@@ -0,0 +1,82 @@
1
+ interface IGetFileFromDataRecordOptions {
2
+ uri: string;
3
+ path: string;
4
+ }
5
+
6
+ interface IRunJobPayload {
7
+ appUri: string;
8
+ arguments: string[];
9
+ files: Record<string, { data: Uint8Array }>;
10
+ temporaryClientSecrets?: Record<string, string>;
11
+ openResult?: boolean | 'currentWindow' | 'newTab';
12
+ blocking?: boolean;
13
+ }
14
+
15
+ interface IJobProgress {
16
+ logMessage?: string;
17
+ systemLogMessage?: string;
18
+ jobId: string;
19
+ }
20
+
21
+ interface IJobResult {
22
+ exit_code: number;
23
+ stderr: Uint8Array;
24
+ stdout: Uint8Array;
25
+ files: Record<string, { data: Uint8Array }>;
26
+ jobId: string;
27
+ }
28
+
29
+ interface IPendingJobResult {
30
+ jobId: string;
31
+ authToken: string;
32
+ }
33
+
34
+ interface IBioLibGlobals {
35
+ getFileDataFromDataRecord: (options: IGetFileFromDataRecordOptions) => Promise<Uint8Array>;
36
+ getOutputFileData: (path: string) => Promise<Uint8Array>;
37
+ listOutputFilePaths: () => Promise<string[]>;
38
+ runJob: (payload: IRunJobPayload, jobProgressHandler?: (jobProgress: IJobProgress) => void) => Promise<IJobResult | IPendingJobResult>;
39
+ }
40
+
41
+ declare global {
42
+ const biolib: IBioLibGlobals;
43
+ }
44
+
45
+ // DO NOT MODIFY: Development data files are injected at build time from gui/dev-data/ folder
46
+ const DEV_DATA_FILES: Record<string, string> = {};
47
+
48
+ const devSdkBioLib: IBioLibGlobals = {
49
+ getFileDataFromDataRecord: async (_options: IGetFileFromDataRecordOptions): Promise<Uint8Array> => {
50
+ throw new Error('getFileDataFromDataRecord is not available in local development mode.');
51
+ },
52
+ getOutputFileData: async (path: string): Promise<Uint8Array> => {
53
+ console.log(`[SDK] getOutputFileData called with path: ${path}`);
54
+
55
+ const normalizedPath = path.startsWith('/') ? path.slice(1) : path;
56
+
57
+ if (typeof DEV_DATA_FILES !== 'undefined' && normalizedPath in DEV_DATA_FILES) {
58
+ const base64Data = DEV_DATA_FILES[normalizedPath];
59
+ const binaryString = atob(base64Data);
60
+ const bytes = new Uint8Array(binaryString.length);
61
+ for (let i = 0; i < binaryString.length; i++) {
62
+ bytes[i] = binaryString.charCodeAt(i);
63
+ }
64
+ return bytes;
65
+ }
66
+
67
+ throw new Error(`File not found: ${path}. Add this file to the dev-data/ folder for local development.`);
68
+ },
69
+ listOutputFilePaths: async (): Promise<string[]> => {
70
+ throw new Error('listOutputFilePaths is not available in local development mode.');
71
+ },
72
+ runJob: async (_payload: IRunJobPayload, _jobProgressHandler?: (jobProgress: IJobProgress) => void): Promise<IJobResult | IPendingJobResult> => {
73
+ throw new Error('runJob is not available in local development mode.');
74
+ },
75
+ };
76
+
77
+ const biolib: IBioLibGlobals =
78
+ process.env.NODE_ENV === "development"
79
+ ? devSdkBioLib
80
+ : (window as any).biolib;
81
+
82
+ export default biolib;
@@ -0,0 +1,7 @@
1
+ {
2
+ "message": "Example JSON data for development",
3
+ "results": [
4
+ { "id": 1, "value": "Sample result 1" },
5
+ { "id": 2, "value": "Sample result 2" }
6
+ ]
7
+ }
@@ -0,0 +1,5 @@
1
+ @import "tailwindcss";
2
+
3
+ * {
4
+ font-family: "Noto Sans", sans-serif;
5
+ }
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <link href="index.css" rel="stylesheet">
7
+ <title>BIOLIB_REPLACE_APP_NAME</title>
8
+ </head>
9
+ <body style="overflow: hidden; background: white">
10
+ <div id="root"></div>
11
+ <script type="module" src="index.tsx"></script>
12
+ </body>
13
+ </html>
@@ -0,0 +1,10 @@
1
+ import { StrictMode } from "react";
2
+ import { createRoot } from "react-dom/client";
3
+ import App from "./App.tsx";
4
+ import "./index.css";
5
+
6
+ createRoot(document.getElementById("root")!).render(
7
+ <StrictMode>
8
+ <App />
9
+ </StrictMode>
10
+ );
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "biolib_replace_app_name",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc --noEmit -p gui/tsconfig.json && vite build",
9
+ "preview": "vite preview"
10
+ },
11
+ "dependencies": {
12
+ "react": "18.3.1",
13
+ "react-dom": "18.3.1"
14
+ },
15
+ "devDependencies": {
16
+ "@tailwindcss/vite": "4.0.14",
17
+ "@types/node": "20.17.10",
18
+ "@types/react": "18.3.3",
19
+ "@types/react-dom": "18.3.0",
20
+ "@vitejs/plugin-react": "4.2.1",
21
+ "tailwindcss": "4.0.14",
22
+ "typescript": "5.2.2",
23
+ "vite": "5.3.4",
24
+ "vite-plugin-singlefile": "2.0.2"
25
+ },
26
+ "packageManager": "yarn@4.6.0"
27
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "compilerOptions": {
3
+ "composite": true,
4
+ "target": "ES2020",
5
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
6
+ "module": "ESNext",
7
+ "skipLibCheck": true,
8
+
9
+ /* Bundler mode */
10
+ "moduleResolution": "bundler",
11
+ "allowImportingTsExtensions": true,
12
+ "verbatimModuleSyntax": true,
13
+ "moduleDetection": "force",
14
+ "noEmit": true,
15
+ "jsx": "react-jsx",
16
+
17
+ /* Linting */
18
+ "strict": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "noFallthroughCasesInSwitch": true
22
+ },
23
+ "include": ["."]
24
+ }
@@ -0,0 +1,50 @@
1
+ import type { Plugin } from 'vite';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+
5
+ export function devDataPlugin(): Plugin {
6
+ let isDev = false;
7
+
8
+ return {
9
+ name: 'dev-data-plugin',
10
+ configResolved(config) {
11
+ isDev = config.mode === 'development';
12
+ },
13
+ transform(code: string, id: string) {
14
+ if (id.endsWith('biolib-sdk.ts')) {
15
+ let injectedCode: string;
16
+
17
+ if (isDev) {
18
+ const devDataDir = path.join(__dirname, 'dev-data');
19
+ const devDataMap: Record<string, string> = {};
20
+
21
+ if (fs.existsSync(devDataDir)) {
22
+ const entries = fs.readdirSync(devDataDir, { recursive: true });
23
+ for (const entry of entries) {
24
+ const relativePath = entry.toString();
25
+ const fullPath = path.join(devDataDir, relativePath);
26
+ if (fs.statSync(fullPath).isFile()) {
27
+ const content = fs.readFileSync(fullPath);
28
+ const base64Content = content.toString('base64');
29
+ devDataMap[relativePath] = base64Content;
30
+ }
31
+ }
32
+ }
33
+
34
+ const devDataJson = JSON.stringify(devDataMap);
35
+ injectedCode = code.replace(
36
+ "const DEV_DATA_FILES = {};",
37
+ `const DEV_DATA_FILES = ${devDataJson};`
38
+ );
39
+ } else {
40
+ injectedCode = code;
41
+ }
42
+
43
+ return {
44
+ code: injectedCode,
45
+ map: null
46
+ };
47
+ }
48
+ }
49
+ };
50
+ }
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from "vite";
2
+ import react from "@vitejs/plugin-react";
3
+ import tailwindcss from "@tailwindcss/vite";
4
+ import { viteSingleFile } from "vite-plugin-singlefile";
5
+ import { devDataPlugin } from "./gui/vite-plugin-dev-data";
6
+
7
+ export default defineConfig({
8
+ root: "gui",
9
+ plugins: [react(), tailwindcss(), devDataPlugin(), viteSingleFile()],
10
+ });
@@ -10,6 +10,7 @@ modules:
10
10
  output_files:
11
11
  - COPY /home/biolib/output/ /
12
12
 
13
+ BIOLIB_REPLACE_GUI_CONFIG
13
14
  arguments:
14
15
  -
15
16
  key: --input
@@ -1,8 +1,12 @@
1
+ # syntax=docker/dockerfile:1
2
+
1
3
  FROM python:3.13.3-slim
2
4
  WORKDIR /home/biolib/
3
5
 
6
+ RUN pip install --no-cache-dir uv
7
+
4
8
  COPY requirements.txt .
5
- RUN pip install --no-cache-dir -r requirements.txt
9
+ RUN uv pip install --no-cache-dir --system -r requirements.txt
6
10
 
7
11
  COPY run.sh .
8
12
  COPY run.py .
@@ -2,20 +2,11 @@ import argparse
2
2
 
3
3
  from biolib.sdk import Runtime
4
4
 
5
+ parser = argparse.ArgumentParser(description='Process some biological sequences.')
6
+ parser.add_argument('--input', type=str, required=True, help='Input protein sequences')
7
+ args = parser.parse_args()
5
8
 
6
- def parse_args():
7
- parser = argparse.ArgumentParser(description='Process some biological sequences.')
8
- parser.add_argument('--input', type=str, required=True, help='Input protein sequences')
9
- return parser.parse_args()
9
+ # update the BioLib result name based on the provided file
10
+ Runtime.set_result_name_from_file(args.input)
10
11
 
11
-
12
- def main(args):
13
- sequence = args.input
14
- # Add your processing logic here
15
- print(f'Received sequence: {sequence}')
16
-
17
-
18
- if __name__ == '__main__':
19
- args = parse_args()
20
- Runtime.set_result_name_prefix_from_fasta(args.input)
21
- main(args)
12
+ print(f'Processing input file {args.input}...')
@@ -1,3 +1,4 @@
1
1
  #!/bin/bash
2
2
  set -e
3
+ BIOLIB_REPLACE_GUI_MV_COMMAND
3
4
  python3 run.py "$@"
@@ -1,5 +1,25 @@
1
1
  import os
2
2
 
3
3
 
4
- def init_template():
4
+ def init_template() -> str:
5
5
  return os.path.join(os.path.dirname(__file__), 'init_template')
6
+
7
+
8
+ def copilot_template() -> str:
9
+ return os.path.join(os.path.dirname(__file__), 'copilot_template')
10
+
11
+
12
+ def gui_template() -> str:
13
+ return os.path.join(os.path.dirname(__file__), 'gui_template')
14
+
15
+
16
+ def dashboard_template() -> str:
17
+ return os.path.join(os.path.dirname(__file__), 'dashboard_template')
18
+
19
+
20
+ def gitignore_template() -> str:
21
+ return os.path.join(os.path.dirname(__file__), 'gitignore_template')
22
+
23
+
24
+ def github_workflow_template() -> str:
25
+ return os.path.join(os.path.dirname(__file__), 'github_workflow_template')
@@ -1,5 +1,32 @@
1
+ import base64
2
+ import shutil
1
3
  import time
2
4
  import uuid
5
+ from fnmatch import fnmatch
6
+
7
+ from biolib.biolib_binary_format.utils import LazyLoadedFile
8
+ from biolib.typing_utils import Callable, List, Union, cast
9
+
10
+ PathFilter = Union[str, Callable[[str], bool]]
11
+
12
+
13
+ def filter_lazy_loaded_files(files: List[LazyLoadedFile], path_filter: PathFilter) -> List[LazyLoadedFile]:
14
+ if not (isinstance(path_filter, str) or callable(path_filter)):
15
+ raise Exception('Expected path_filter to be a string or a function')
16
+
17
+ if callable(path_filter):
18
+ return list(filter(lambda x: path_filter(x.path), files)) # type: ignore
19
+
20
+ glob_filter = cast(str, path_filter)
21
+
22
+ # since all file paths start with /, make sure filter does too
23
+ if not glob_filter.startswith('/'):
24
+ glob_filter = '/' + glob_filter
25
+
26
+ def _filter_function(file: LazyLoadedFile) -> bool:
27
+ return fnmatch(file.path, glob_filter)
28
+
29
+ return list(filter(_filter_function, files))
3
30
 
4
31
 
5
32
  def open_browser_window_from_notebook(url_to_open: str) -> None:
@@ -16,3 +43,23 @@ def open_browser_window_from_notebook(url_to_open: str) -> None:
16
43
  display(Javascript(f'window.open("{url_to_open}");'), display_id=display_id)
17
44
  time.sleep(1)
18
45
  update_display(Javascript(''), display_id=display_id)
46
+
47
+
48
+ def base64_encode_string(input_str: str) -> str:
49
+ input_bytes = input_str.encode('utf-8')
50
+ base64_bytes = base64.b64encode(input_bytes)
51
+ base64_str = base64_bytes.decode('utf-8')
52
+ return base64_str
53
+
54
+
55
+ def decode_base64_string(base64_str: str) -> str:
56
+ base64_bytes = base64_str.encode('utf-8')
57
+ input_bytes = base64.b64decode(base64_bytes)
58
+ input_str = input_bytes.decode('utf-8')
59
+ return input_str
60
+
61
+
62
+ def get_pip_command() -> str:
63
+ if shutil.which('uv'):
64
+ return 'uv pip'
65
+ return 'pip'
@@ -0,0 +1,46 @@
1
+ import base64
2
+ import binascii
3
+ import json
4
+ from typing import Any, Dict
5
+
6
+
7
+ class JwtDecodeError(Exception):
8
+ pass
9
+
10
+
11
+ def decode_jwt_without_checking_signature(jwt: str) -> Dict[str, Any]:
12
+ jwt_bytes = jwt.encode('utf-8')
13
+
14
+ try:
15
+ signing_input, _ = jwt_bytes.rsplit(b'.', 1)
16
+ header_segment, payload_segment = signing_input.split(b'.', 1)
17
+ except ValueError as error:
18
+ raise JwtDecodeError('Not enough segments') from error
19
+
20
+ try:
21
+ header_data = base64.urlsafe_b64decode(header_segment)
22
+ except (TypeError, binascii.Error) as error:
23
+ raise JwtDecodeError('Invalid header padding') from error
24
+
25
+ try:
26
+ header = json.loads(header_data)
27
+ except ValueError as error:
28
+ raise JwtDecodeError(f'Invalid header string: {error}') from error
29
+
30
+ if not isinstance(header, dict):
31
+ raise JwtDecodeError('Invalid header string: must be a json object')
32
+
33
+ try:
34
+ payload_data = base64.urlsafe_b64decode(payload_segment)
35
+ except (TypeError, binascii.Error) as error:
36
+ raise JwtDecodeError('Invalid payload padding') from error
37
+
38
+ try:
39
+ payload = json.loads(payload_data)
40
+ except ValueError as error:
41
+ raise JwtDecodeError(f'Invalid payload string: {error}') from error
42
+
43
+ if not isinstance(payload, dict):
44
+ raise JwtDecodeError('Invalid payload string: must be a json object')
45
+
46
+ return dict(header=header, payload=payload)