diff --git a/README.md b/README.md index 10552d6e..2e0288f3 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,9 @@ Uni-Lab-OS recommends using `mamba` for environment management. Choose the appro ```bash # Create new environment -mamba create -n unilab uni-lab::unilabos -c robostack-staging -c conda-forge +mamba create -n unilab python=3.11.11 +mamba activate unilab +mamba install -n unilab uni-lab::unilabos -c robostack-staging -c conda-forge ``` ## Install Dev Uni-Lab-OS diff --git a/README_zh.md b/README_zh.md index 810e2c55..76976ebf 100644 --- a/README_zh.md +++ b/README_zh.md @@ -41,7 +41,9 @@ Uni-Lab-OS 建议使用 `mamba` 管理环境。根据您的操作系统选择适 ```bash # 创建新环境 -mamba create -n unilab uni-lab::unilabos -c robostack-staging -c conda-forge +mamba create -n unilab python=3.11.11 +mamba activate unilab +mamba install -n unilab uni-lab::unilabos -c robostack-staging -c conda-forge ``` 2. 安装开发版 Uni-Lab-OS: diff --git a/docs/user_guide/installation.md b/docs/user_guide/installation.md index 6513150d..d3fd4982 100644 --- a/docs/user_guide/installation.md +++ b/docs/user_guide/installation.md @@ -317,45 +317,6 @@ unilab --help 如果所有命令都正常输出,说明开发环境配置成功! -### 开发工具推荐 - -#### IDE - -- **PyCharm Professional**: 强大的 Python IDE,支持远程调试 -- **VS Code**: 轻量级,配合 Python 扩展使用 -- **Vim/Emacs**: 适合终端开发 - -#### 推荐的 VS Code 扩展 - -- Python -- Pylance -- ROS -- URDF -- YAML - -#### 调试工具 - -```bash -# 安装调试工具 -pip install ipdb pytest pytest-cov -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple - -# 代码质量检查 -pip install black flake8 mypy -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple -``` - -### 设置 pre-commit 钩子(可选) - -```bash -# 安装 pre-commit -pip install pre-commit -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple - -# 设置钩子 -pre-commit install - -# 手动运行检查 -pre-commit run --all-files -``` - --- ## 验证安装 diff --git a/unilabos/app/main.py b/unilabos/app/main.py index 58875524..af8388d6 100644 --- a/unilabos/app/main.py +++ b/unilabos/app/main.py @@ -159,9 +159,10 @@ def parse_args(): def main(): """主函数""" # 解析命令行参数 - args = parse_args() - convert_argv_dashes_to_underscores(args) - args_dict = vars(args.parse_args()) + parser = parse_args() + convert_argv_dashes_to_underscores(parser) + args = parser.parse_args() + args_dict = vars(args) # 环境检查 - 检查并自动安装必需的包 (可选) if not args_dict.get("skip_env_check", False): @@ -220,17 +221,18 @@ def main(): logger.info(f"Log level set to '{BasicConfig.log_level}' from config file.") configure_logger(loglevel=BasicConfig.log_level, working_dir=working_dir) - if args_dict["addr"] == "test": - print_status("使用测试环境地址", "info") - HTTPConfig.remote_addr = "https://uni-lab.test.bohrium.com/api/v1" - elif args_dict["addr"] == "uat": - print_status("使用uat环境地址", "info") - HTTPConfig.remote_addr = "https://uni-lab.uat.bohrium.com/api/v1" - elif args_dict["addr"] == "local": - print_status("使用本地环境地址", "info") - HTTPConfig.remote_addr = "http://127.0.0.1:48197/api/v1" - else: - HTTPConfig.remote_addr = args_dict.get("addr", "") + if args.addr != parser.get_default("addr"): + if args.addr == "test": + print_status("使用测试环境地址", "info") + HTTPConfig.remote_addr = "https://uni-lab.test.bohrium.com/api/v1" + elif args.addr == "uat": + print_status("使用uat环境地址", "info") + HTTPConfig.remote_addr = "https://uni-lab.uat.bohrium.com/api/v1" + elif args.addr == "local": + print_status("使用本地环境地址", "info") + HTTPConfig.remote_addr = "http://127.0.0.1:48197/api/v1" + else: + HTTPConfig.remote_addr = args.addr # 设置BasicConfig参数 if args_dict.get("ak", ""): diff --git a/unilabos/config/config.py b/unilabos/config/config.py index c13064ef..a9fa5789 100644 --- a/unilabos/config/config.py +++ b/unilabos/config/config.py @@ -41,7 +41,7 @@ class WSConfig: # HTTP配置 class HTTPConfig: - remote_addr = "http://127.0.0.1:48197/api/v1" + remote_addr = "https://uni-lab.bohrium.com/api/v1" # ROS配置 diff --git a/unilabos/devices/laiyu_liquid_test/__init__.py b/unilabos/devices/laiyu_liquid_test/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/unilabos/devices/liquid_handling/laiyu/__init__.py b/unilabos/devices/liquid_handling/laiyu/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/unilabos/devices/liquid_handling/liquid_handler_abstract.py b/unilabos/devices/liquid_handling/liquid_handler_abstract.py index 9bc56d4d..e849ffb9 100644 --- a/unilabos/devices/liquid_handling/liquid_handler_abstract.py +++ b/unilabos/devices/liquid_handling/liquid_handler_abstract.py @@ -988,6 +988,18 @@ class LiquidHandlerAbstract(LiquidHandlerMiddleware): dis_vols = [float(dis_vols)] else: dis_vols = [float(v) for v in dis_vols] + + # 统一混合次数为标量,防止数组/列表与 int 比较时报错 + if mix_times is not None and not isinstance(mix_times, (int, float)): + try: + mix_times = mix_times[0] if len(mix_times) > 0 else None + except Exception: + try: + mix_times = next(iter(mix_times)) + except Exception: + pass + if mix_times is not None: + mix_times = int(mix_times) # 识别传输模式 num_sources = len(sources) diff --git a/unilabos/devices/liquid_handling/prcxi/prcxi.py b/unilabos/devices/liquid_handling/prcxi/prcxi.py index cca11f84..cd20f4c9 100644 --- a/unilabos/devices/liquid_handling/prcxi/prcxi.py +++ b/unilabos/devices/liquid_handling/prcxi/prcxi.py @@ -5,6 +5,7 @@ import json import os import socket import time +import uuid from typing import Any, List, Dict, Optional, Tuple, TypedDict, Union, Sequence, Iterator, Literal from pylabrobot.liquid_handling import ( @@ -856,7 +857,30 @@ class PRCXI9300Api: def _raw_request(self, payload: str) -> str: if self.debug: - return " " + # 调试/仿真模式下直接返回可解析的模拟 JSON,避免后续 json.loads 报错 + try: + req = json.loads(payload) + method = req.get("MethodName") + except Exception: + method = None + + data: Any = True + if method in {"AddSolution"}: + data = str(uuid.uuid4()) + elif method in {"AddWorkTabletMatrix", "AddWorkTabletMatrix2"}: + data = {"Success": True, "Message": "debug mock"} + elif method in {"GetErrorCode"}: + data = "" + elif method in {"RemoveErrorCodet", "Reset", "Start", "LoadSolution", "Pause", "Resume", "Stop"}: + data = True + elif method in {"GetStepStateList", "GetStepStatus", "GetStepState"}: + data = [] + elif method in {"GetLocation"}: + data = {"X": 0, "Y": 0, "Z": 0} + elif method in {"GetResetStatus"}: + data = False + + return json.dumps({"Success": True, "Msg": "debug mock", "Data": data}) with contextlib.closing(socket.socket()) as sock: sock.settimeout(self.timeout) sock.connect((self.host, self.port)) diff --git a/unilabos/registry/devices/bioyond_dispensing_station.yaml b/unilabos/registry/devices/bioyond_dispensing_station.yaml index 9ae76b7f..5f3e1dde 100644 --- a/unilabos/registry/devices/bioyond_dispensing_station.yaml +++ b/unilabos/registry/devices/bioyond_dispensing_station.yaml @@ -174,35 +174,6 @@ bioyond_dispensing_station: title: query_resource_by_name参数 type: object type: UniLabJsonCommand - auto-transfer_materials_to_reaction_station: - feedback: {} - goal: {} - goal_default: - target_device_id: null - transfer_groups: null - handles: {} - placeholder_keys: {} - result: {} - schema: - description: '' - properties: - feedback: {} - goal: - properties: - target_device_id: - type: string - transfer_groups: - type: array - required: - - target_device_id - - transfer_groups - type: object - result: {} - required: - - goal - title: transfer_materials_to_reaction_station参数 - type: object - type: UniLabJsonCommand auto-workflow_sample_locations: feedback: {} goal: {}