{"record":{"id":"59d707c8a760490d","repo":"ZhuLinsen/daily_stock_analysis","slug":"tushare-http-url-http-https-u","errorCode":null,"errorMessage":"TUSHARE_HTTP_URL 必须以 http:// 或 https:// 开头，当前值为 {url!r}","messagePattern":"TUSHARE_HTTP_URL 必须以 http:// 或 https:// 开头，当前值为 (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"data_provider/tushare_fetcher.py","lineNumber":90,"sourceCode":"    return bool(re.match(r'^[A-Z]{1,5}(\\.[A-Z])?$', code))\n\n\ndef _resolve_tushare_http_url() -> Optional[str]:\n    \"\"\"读取 ``TUSHARE_HTTP_URL`` 环境变量并做基本校验。\n\n    - 留空 / 仅空白 / 未设置 → 返回 ``None``，调用方继续走官方默认地址。\n    - 设置则去掉首尾空白后返回，并校验必须是 ``http://`` 或 ``https://`` 前缀，\n      避免有人误填成纯主机名（如 ``api.tushare.pro``）导致 ``requests`` 把它\n      当成相对路径请求失败。\n    \"\"\"\n    raw = os.getenv(\"TUSHARE_HTTP_URL\")\n    if not raw:\n        return None\n    url = raw.strip()\n    if not url:\n        return None\n    if not (url.startswith(\"http://\") or url.startswith(\"https://\")):\n        raise ValueError(\n            \"TUSHARE_HTTP_URL 必须以 http:// 或 https:// 开头，\"\n            f\"当前值为 {url!r}\"\n        )\n    return url\n\n\nclass _TushareHttpClient:\n    \"\"\"Lightweight Tushare Pro client that does not require the tushare SDK.\"\"\"\n\n    def __init__(self, token: str, timeout: int = 30, api_url: str = \"http://api.tushare.pro\") -> None:\n        self._token = token\n        self._timeout = timeout\n        self._api_url = api_url\n\n    def query(self, api_name: str, fields: str = \"\", **kwargs) -> pd.DataFrame:\n        req_params = {\n            \"api_name\": api_name,\n            \"token\": self._token,","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/data_provider/tushare_fetcher.py#L72-L108","documentation":"ValueError raised while parsing the TUSHARE_HTTP_URL environment variable: if set, the value must start with http:// or https://. The guard exists because requests treats a bare hostname like 'api.tushare.pro' as a relative URL and fails confusingly later, so the fetcher fails fast at config-load time instead.","triggerScenarios":"Setting TUSHARE_HTTP_URL to a hostname without scheme (e.g. TUSHARE_HTTP_URL=api.tushare.pro), with a typo like 'ttp://', or with leading whitespace plus a missing scheme; the error is raised the first time the env helper reads the variable.","commonSituations":"Copy-pasting a host:port into .env without the scheme; switching from a proxy hostname to URL and forgetting the prefix; CI secrets storing only the hostname.","solutions":["Edit .env / environment and prefix the value with http:// or https:// (e.g. https://api.tushare.pro).","Leave TUSHARE_HTTP_URL unset or blank to use the official default endpoint.","Add a config lint step or startup validation that scheme-checks all *_URL variables."],"exampleFix":"# before\n# .env\nTUSHARE_HTTP_URL=api.tushare.pro   # ValueError\n\n# after\n# .env\nTUSHARE_HTTP_URL=https://api.tushare.pro\n# or simply remove the line to use the default","handlingStrategy":"validation","validationCode":"import os\n\nurl = (os.getenv(\"TUSHARE_HTTP_URL\") or \"\").strip()\nif url and not url.startswith((\"http://\", \"https://\")):\n    raise SystemExit(f\"TUSHARE_HTTP_URL must start with http:// or https://, got {url!r}\")","typeGuard":null,"tryCatchPattern":"try:\n    fetcher = TushareFetcher()\nexcept ValueError as e:\n    if \"TUSHARE_HTTP_URL\" in str(e):\n        fix_and_restart(\"set TUSHARE_HTTP_URL=https://... or unset it\")\n    else:\n        raise","preventionTips":["Always include the scheme when writing URL env vars.","Add a config lint check for all *_URL variables at application startup.","Leave the variable unset when the default endpoint is fine."],"tags":["tushare","configuration","env-var","validation"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}