From f476a24ec57ad691af4ecdd1234e194242768e2e Mon Sep 17 00:00:00 2001 From: andreasjansson Date: Mon, 15 Apr 2024 17:06:23 +0200 Subject: [PATCH] Vendor Python packages (take 2) This PR vendors all Python packages using the [vendoring](https://pypi.org/project/vendoring/) library. Vendoring allows users to install packages that rely on versions of libraries that are in conflict with Cog's dependencies (e.g. Pydantic, see #1562, #1384, #1186, #1586, #1336, #785). This PR is broken up into two commits: First one adds all the files in the `_vendor` directory, second one is the actually changed code. Closes #409 Signed-off-by: andreasjansson --- CONTRIBUTING.md | 20 ++++ pyproject.toml | 42 ++++++-- python/cog/__init__.py | 2 +- python/cog/files.py | 2 +- python/cog/json.py | 2 +- python/cog/logging.py | 4 +- python/cog/predictor.py | 10 +- python/cog/schema.py | 2 +- python/cog/server/eventtypes.py | 2 +- python/cog/server/http.py | 18 ++-- python/cog/server/runner.py | 12 +-- python/cog/server/webhook.py | 8 +- python/cog/types.py | 4 +- python/tests/server/conftest.py | 4 +- .../tests/server/fixtures/complex_output.py | 2 +- .../server/fixtures/input_unsupported_type.py | 2 +- .../fixtures/openapi_custom_output_type.py | 2 +- .../server/fixtures/openapi_output_type.py | 2 +- .../tests/server/fixtures/output_complex.py | 2 +- .../fixtures/output_iterator_complex.py | 2 +- python/tests/server/test_http_input.py | 2 + python/tests/server/test_http_output.py | 2 + python/tests/server/test_webhook.py | 2 +- python/tests/server/test_worker.py | 2 +- python/tests/test_json.py | 2 +- python/tools/vendoring/patches/pydantic.patch | 96 +++++++++++++++++++ .../tools/vendoring/patches/starlette.patch | 29 ++++++ python/tools/vendoring/patches/urrlib3.patch | 63 ++++++++++++ .../complex_output_project/predict.py | 2 +- 29 files changed, 290 insertions(+), 54 deletions(-) create mode 100644 python/tools/vendoring/patches/pydantic.patch create mode 100644 python/tools/vendoring/patches/starlette.patch create mode 100644 python/tools/vendoring/patches/urrlib3.patch diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 39db059526..10274b628b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -207,6 +207,26 @@ To publish a prerelease version, append a [SemVer prerelease identifer](https:// git tag -a v0.1.0-alpha -m "Prerelease v0.1.0" git push --tags +## Vendoring Python packages + +We vendor the few Python libraries we depend on to avoid dependency hell. We use [vendoring](https://pypi.org/project/vendoring/), the same tool used by pip. + +The vendored packages are defined in `python/cog/_vendor/vendor.txt`. If you add/change anything in there, run this to update the vendored libraries: + + pip install vendoring + vendoring sync -v . + +If you run into issues you may need to manually add a patch. Patches are stored in `python/tools/vendoring/patches`. + +To create a new patch, copy the file you want to patch to `$FILENAME.new`, and edit that file as needed. For example: + + cp python/cog/_vendor/curio/__main__.py python/cog/_vendor/curio/__main__.py.new + +Then `diff` the new and old version to a patch file in `python/tools/vendoring/patches/$PACKAGE.patch` and re-run vendoring. For example: + + diff -u ./python/cog/_vendor/curio/__main__.py ./python/cog/_vendor/curio/__main__.py.new >> python/tools/vendoring/patches/curio.patch + vendoring sync -v . + ## Troubleshooting ### `cog command not found` diff --git a/pyproject.toml b/pyproject.toml index a7438613bd..fed6abd26a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,16 +12,7 @@ urls."Source" = "https://github.com/replicate/cog" requires-python = ">=3.7" dependencies = [ - # intentionally loose. perhaps these should be vendored to not collide with user code? - "attrs>=20.1,<24", - "fastapi>=0.75.2,<0.99.0", - "pydantic>=1.9,<2", - "PyYAML", - "requests>=2,<3", - "structlog>=20,<25", 'typing-compat; python_version < "3.8"', - "typing_extensions>=4.4.0", - "uvicorn[standard]>=0.12,<1", ] optional-dependencies = { "dev" = [ @@ -111,3 +102,36 @@ extend-exclude = [ "S607", # Starting a process with a partial executable path" "ANN", ] + +[tool.black] +exclude = '(\.eggs|\.git|\.hg|\.mypy|_cache|\.nox|\.tox|\.venv|\.svn|_build|buck-out|build|dist|_vendor)' + +[tool.vendoring] +destination = "python/cog/_vendor/" +requirements = "python/cog/_vendor/vendor.txt" +namespace = "cog._vendor" + +protected-files = ["__init__.py", "README.rst", "vendor.txt"] +patches-dir = "python/tools/vendoring/patches" + +[tool.vendoring.transformations] +substitute = [] +drop = [ + # pyyaml falls back to plain python + "_yaml.*.so", + + # sniffio ships with tests + "sniffio/_tests", + + # h11 ships with tests + "h11/tests", + + # pydantic hypothesis plugin, fall back to python + "pydantic/_hypothesis_plugin.*.so", +] + +[tool.vendoring.typing-stubs] + +[tool.vendoring.license.directories] + +[tool.vendoring.license.fallback-urls] \ No newline at end of file diff --git a/python/cog/__init__.py b/python/cog/__init__.py index b8371e0f09..e42be4a4fc 100644 --- a/python/cog/__init__.py +++ b/python/cog/__init__.py @@ -1,4 +1,4 @@ -from pydantic import BaseModel +from ._vendor.pydantic import BaseModel from .predictor import BasePredictor from .types import ConcatenateIterator, File, Input, Path, Secret diff --git a/python/cog/files.py b/python/cog/files.py index 2ca8cd383a..9a010e1bdb 100644 --- a/python/cog/files.py +++ b/python/cog/files.py @@ -4,7 +4,7 @@ import os from urllib.parse import urlparse -import requests +from ._vendor import requests def upload_file(fh: io.IOBase, output_file_prefix: str = None) -> str: diff --git a/python/cog/json.py b/python/cog/json.py index 843572eea0..5cc99c8d98 100644 --- a/python/cog/json.py +++ b/python/cog/json.py @@ -4,7 +4,7 @@ from types import GeneratorType from typing import Any, Callable -from pydantic import BaseModel +from ._vendor.pydantic import BaseModel from .types import Path diff --git a/python/cog/logging.py b/python/cog/logging.py index 7b25214543..934170cb81 100644 --- a/python/cog/logging.py +++ b/python/cog/logging.py @@ -1,8 +1,8 @@ import logging import os -import structlog -from structlog.typing import EventDict +from ._vendor import structlog +from ._vendor.structlog.typing import EventDict def replace_level_with_severity( diff --git a/python/cog/predictor.py b/python/cog/predictor.py index 46f6920d20..89dddea405 100644 --- a/python/cog/predictor.py +++ b/python/cog/predictor.py @@ -21,7 +21,7 @@ ) from unittest.mock import patch -import structlog +from ._vendor import structlog import cog.code_xforms as code_xforms @@ -30,12 +30,12 @@ except ImportError: # Python < 3.8 from typing_compat import get_args, get_origin # type: ignore -import yaml -from pydantic import BaseModel, Field, create_model -from pydantic.fields import FieldInfo +from ._vendor import yaml +from ._vendor.pydantic import BaseModel, Field, create_model +from ._vendor.pydantic.fields import FieldInfo # Added in Python 3.9. Can be from typing if we drop support for <3.9 -from typing_extensions import Annotated +from ._vendor.typing_extensions import Annotated from .errors import ConfigDoesNotExist, PredictorNotSet from .types import ( diff --git a/python/cog/schema.py b/python/cog/schema.py index 508c1f0f12..c7de412520 100644 --- a/python/cog/schema.py +++ b/python/cog/schema.py @@ -7,7 +7,7 @@ from enum import Enum from types import ModuleType -import pydantic +from ._vendor import pydantic BUNDLED_SCHEMA_PATH = ".cog/schema.py" diff --git a/python/cog/server/eventtypes.py b/python/cog/server/eventtypes.py index 4f9a6643a5..b333e47542 100644 --- a/python/cog/server/eventtypes.py +++ b/python/cog/server/eventtypes.py @@ -1,6 +1,6 @@ from typing import Any, Dict -from attrs import define, field, validators +from .._vendor.attrs import define, field, validators # From worker parent process diff --git a/python/cog/server/http.py b/python/cog/server/http.py index 0a2be6aaf6..e21eadc5ce 100644 --- a/python/cog/server/http.py +++ b/python/cog/server/http.py @@ -25,15 +25,15 @@ if TYPE_CHECKING: from typing import ParamSpec -import attrs -import structlog -import uvicorn -from fastapi import Body, FastAPI, Header, HTTPException, Path, Response -from fastapi.encoders import jsonable_encoder -from fastapi.exceptions import RequestValidationError -from fastapi.responses import JSONResponse -from pydantic import ValidationError -from pydantic.error_wrappers import ErrorWrapper +from .._vendor import attrs +from .._vendor import structlog +from .._vendor import uvicorn +from .._vendor.fastapi import Body, FastAPI, Header, HTTPException, Path, Response +from .._vendor.fastapi.encoders import jsonable_encoder +from .._vendor.fastapi.exceptions import RequestValidationError +from .._vendor.fastapi.responses import JSONResponse +from .._vendor.pydantic import ValidationError +from .._vendor.pydantic.error_wrappers import ErrorWrapper from .. import schema from ..errors import PredictorNotSet diff --git a/python/cog/server/runner.py b/python/cog/server/runner.py index 54e1360901..73c7118619 100644 --- a/python/cog/server/runner.py +++ b/python/cog/server/runner.py @@ -7,12 +7,12 @@ from multiprocessing.pool import AsyncResult, ThreadPool from typing import Any, Callable, Optional, Tuple, Union, cast -import requests -import structlog -from attrs import define -from fastapi.encoders import jsonable_encoder -from requests.adapters import HTTPAdapter -from requests.packages.urllib3.util.retry import Retry # type: ignore +from .._vendor import requests +from .._vendor import structlog +from .._vendor.attrs import define +from .._vendor.fastapi.encoders import jsonable_encoder +from .._vendor.requests.adapters import HTTPAdapter +from .._vendor.urllib3.util.retry import Retry # type: ignore from .. import schema, types from ..files import put_file_to_signed_endpoint diff --git a/python/cog/server/webhook.py b/python/cog/server/webhook.py index d71cf81e25..79d3135c6d 100644 --- a/python/cog/server/webhook.py +++ b/python/cog/server/webhook.py @@ -1,10 +1,10 @@ import os from typing import Any, Callable, Set -import requests -import structlog -from requests.adapters import HTTPAdapter -from requests.packages.urllib3.util.retry import Retry # type: ignore +from .._vendor import requests +from .._vendor import structlog +from .._vendor.requests.adapters import HTTPAdapter +from .._vendor.urllib3.util.retry import Retry # type: ignore from ..schema import Status, WebhookEvent from .response_throttler import ResponseThrottler diff --git a/python/cog/types.py b/python/cog/types.py index a75b48d99b..e6d5b88e2f 100644 --- a/python/cog/types.py +++ b/python/cog/types.py @@ -8,8 +8,8 @@ import urllib.request from typing import Any, Dict, Iterator, List, Optional, TypeVar, Union -import requests -from pydantic import Field, SecretStr +from ._vendor import requests +from ._vendor.pydantic import Field, SecretStr FILENAME_ILLEGAL_CHARS = set("\u0000/") diff --git a/python/tests/server/conftest.py b/python/tests/server/conftest.py index b332c87c15..56eaccb5bf 100644 --- a/python/tests/server/conftest.py +++ b/python/tests/server/conftest.py @@ -6,10 +6,10 @@ from unittest import mock import pytest -from attrs import define +from cog._vendor.attrs import define from cog.command import ast_openapi_schema from cog.server.http import create_app -from fastapi.testclient import TestClient +from cog._vendor.fastapi.testclient import TestClient @define diff --git a/python/tests/server/fixtures/complex_output.py b/python/tests/server/fixtures/complex_output.py index 3be75bd2a6..db0f6fdfaa 100644 --- a/python/tests/server/fixtures/complex_output.py +++ b/python/tests/server/fixtures/complex_output.py @@ -1,4 +1,4 @@ -from pydantic import BaseModel +from cog import BaseModel class Output(BaseModel): diff --git a/python/tests/server/fixtures/input_unsupported_type.py b/python/tests/server/fixtures/input_unsupported_type.py index 10518d659f..ed0532b5bc 100644 --- a/python/tests/server/fixtures/input_unsupported_type.py +++ b/python/tests/server/fixtures/input_unsupported_type.py @@ -1,5 +1,5 @@ from cog import BasePredictor -from pydantic import BaseModel +from cog import BaseModel class Input(BaseModel): diff --git a/python/tests/server/fixtures/openapi_custom_output_type.py b/python/tests/server/fixtures/openapi_custom_output_type.py index f04ed1e5ea..3cbec0fd1f 100644 --- a/python/tests/server/fixtures/openapi_custom_output_type.py +++ b/python/tests/server/fixtures/openapi_custom_output_type.py @@ -1,5 +1,5 @@ from cog import BasePredictor -from pydantic import BaseModel +from cog import BaseModel # Calling this `MyOutput` to test if cog renames it to `Output` in the schema diff --git a/python/tests/server/fixtures/openapi_output_type.py b/python/tests/server/fixtures/openapi_output_type.py index a22d6aa2f8..2ec3b650f6 100644 --- a/python/tests/server/fixtures/openapi_output_type.py +++ b/python/tests/server/fixtures/openapi_output_type.py @@ -1,5 +1,5 @@ from cog import BasePredictor -from pydantic import BaseModel +from cog import BaseModel # An output object called `Output` needs to be special cased because pydantic tries to dedupe it with the internal `Output` diff --git a/python/tests/server/fixtures/output_complex.py b/python/tests/server/fixtures/output_complex.py index 0a38809114..d2fab5ee6c 100644 --- a/python/tests/server/fixtures/output_complex.py +++ b/python/tests/server/fixtures/output_complex.py @@ -1,7 +1,7 @@ import io from cog import BasePredictor, File -from pydantic import BaseModel +from cog import BaseModel class Output(BaseModel): diff --git a/python/tests/server/fixtures/output_iterator_complex.py b/python/tests/server/fixtures/output_iterator_complex.py index 737093a628..fd039f5301 100644 --- a/python/tests/server/fixtures/output_iterator_complex.py +++ b/python/tests/server/fixtures/output_iterator_complex.py @@ -1,7 +1,7 @@ from typing import Iterator, List from cog import BasePredictor -from pydantic import BaseModel +from cog import BaseModel class Output(BaseModel): diff --git a/python/tests/server/test_http_input.py b/python/tests/server/test_http_input.py index a64bb0104f..16cf548f3b 100644 --- a/python/tests/server/test_http_input.py +++ b/python/tests/server/test_http_input.py @@ -10,6 +10,8 @@ from .conftest import uses_predictor +responses.mock.target = "cog._vendor.requests.adapters.HTTPAdapter.send" + @uses_predictor("input_none") def test_no_input(client, match): diff --git a/python/tests/server/test_http_output.py b/python/tests/server/test_http_output.py index 281134cf9e..534dcf49b1 100644 --- a/python/tests/server/test_http_output.py +++ b/python/tests/server/test_http_output.py @@ -6,6 +6,8 @@ from .conftest import uses_predictor, uses_predictor_with_client_options +responses.mock.target = "cog._vendor.requests.adapters.HTTPAdapter.send" + @uses_predictor("output_wrong_type") def test_return_wrong_type(client): diff --git a/python/tests/server/test_webhook.py b/python/tests/server/test_webhook.py index 8a6bfb8543..9f2a102aab 100644 --- a/python/tests/server/test_webhook.py +++ b/python/tests/server/test_webhook.py @@ -1,4 +1,4 @@ -import requests +from cog._vendor import requests import responses from cog.schema import WebhookEvent from cog.server.webhook import webhook_caller, webhook_caller_filtered diff --git a/python/tests/server/test_worker.py b/python/tests/server/test_worker.py index 2895e0c81f..0cdd5b970e 100644 --- a/python/tests/server/test_worker.py +++ b/python/tests/server/test_worker.py @@ -3,7 +3,7 @@ from typing import Any, Optional import pytest -from attrs import define +from cog._vendor.attrs import define from cog.server.eventtypes import ( Done, Heartbeat, diff --git a/python/tests/test_json.py b/python/tests/test_json.py index 6311e34be1..7adefba870 100644 --- a/python/tests/test_json.py +++ b/python/tests/test_json.py @@ -5,7 +5,7 @@ import numpy as np from cog.files import upload_file from cog.json import make_encodeable, upload_files -from pydantic import BaseModel +from cog._vendor.pydantic import BaseModel def test_make_encodeable_recursively_encodes_tuples(): diff --git a/python/tools/vendoring/patches/pydantic.patch b/python/tools/vendoring/patches/pydantic.patch new file mode 100644 index 0000000000..0fd5d700c3 --- /dev/null +++ b/python/tools/vendoring/patches/pydantic.patch @@ -0,0 +1,96 @@ +--- ./python/cog/_vendor/pydantic/_hypothesis_plugin.py 2024-04-15 16:14:31 ++++ ./python/cog/_vendor/pydantic/_hypothesis_plugin.py.new 2024-04-15 16:16:29 +@@ -33,8 +33,8 @@ + import hypothesis.strategies as st + + import pydantic +-import pydantic.color +-import pydantic.types ++import pydantic.color as pydantic_color ++import pydantic.types as pydantic_types + from pydantic.utils import lenient_issubclass + + # FilePath and DirectoryPath are explicitly unsupported, as we'd have to create +@@ -88,23 +88,23 @@ + _color_regexes = ( + '|'.join( + ( +- pydantic.color.r_hex_short, +- pydantic.color.r_hex_long, +- pydantic.color.r_rgb, +- pydantic.color.r_rgba, +- pydantic.color.r_hsl, +- pydantic.color.r_hsla, ++ pydantic_color.r_hex_short, ++ pydantic_color.r_hex_long, ++ pydantic_color.r_rgb, ++ pydantic_color.r_rgba, ++ pydantic_color.r_hsl, ++ pydantic_color.r_hsla, + ) + ) + # Use more precise regex patterns to avoid value-out-of-range errors +- .replace(pydantic.color._r_sl, r'(?:(\d\d?(?:\.\d+)?|100(?:\.0+)?)%)') +- .replace(pydantic.color._r_alpha, r'(?:(0(?:\.\d+)?|1(?:\.0+)?|\.\d+|\d{1,2}%))') +- .replace(pydantic.color._r_255, r'(?:((?:\d|\d\d|[01]\d\d|2[0-4]\d|25[0-4])(?:\.\d+)?|255(?:\.0+)?))') ++ .replace(pydantic_color._r_sl, r'(?:(\d\d?(?:\.\d+)?|100(?:\.0+)?)%)') ++ .replace(pydantic_color._r_alpha, r'(?:(0(?:\.\d+)?|1(?:\.0+)?|\.\d+|\d{1,2}%))') ++ .replace(pydantic_color._r_255, r'(?:((?:\d|\d\d|[01]\d\d|2[0-4]\d|25[0-4])(?:\.\d+)?|255(?:\.0+)?))') + ) + st.register_type_strategy( +- pydantic.color.Color, ++ pydantic_color.Color, + st.one_of( +- st.sampled_from(sorted(pydantic.color.COLORS_BY_NAME)), ++ st.sampled_from(sorted(pydantic_color.COLORS_BY_NAME)), + st.tuples( + st.integers(0, 255), + st.integers(0, 255), +@@ -182,22 +182,22 @@ + + + @overload +-def _registered(typ: Type[pydantic.types.T]) -> Type[pydantic.types.T]: ++def _registered(typ: Type[pydantic_types.T]) -> Type[pydantic_types.T]: + pass + + + @overload +-def _registered(typ: pydantic.types.ConstrainedNumberMeta) -> pydantic.types.ConstrainedNumberMeta: ++def _registered(typ: pydantic_types.ConstrainedNumberMeta) -> pydantic_types.ConstrainedNumberMeta: + pass + + + def _registered( +- typ: Union[Type[pydantic.types.T], pydantic.types.ConstrainedNumberMeta] +-) -> Union[Type[pydantic.types.T], pydantic.types.ConstrainedNumberMeta]: +- # This function replaces the version in `pydantic.types`, in order to ++ typ: Union[Type[pydantic_types.T], pydantic_types.ConstrainedNumberMeta] ++) -> Union[Type[pydantic_types.T], pydantic_types.ConstrainedNumberMeta]: ++ # This function replaces the version in `pydantic_types`, in order to + # effect the registration of new constrained types so that Hypothesis + # can generate valid examples. +- pydantic.types._DEFINED_TYPES.add(typ) ++ pydantic_types._DEFINED_TYPES.add(typ) + for supertype, resolver in RESOLVERS.items(): + if issubclass(typ, supertype): + st.register_type_strategy(typ, resolver(typ)) # type: ignore +@@ -206,7 +206,7 @@ + + + def resolves( +- typ: Union[type, pydantic.types.ConstrainedNumberMeta] ++ typ: Union[type, pydantic_types.ConstrainedNumberMeta] + ) -> Callable[[Callable[..., st.SearchStrategy]], Callable[..., st.SearchStrategy]]: # type: ignore[type-arg] + def inner(f): # type: ignore + assert f not in RESOLVERS +@@ -385,7 +385,7 @@ + + + # Finally, register all previously-defined types, and patch in our new function +-for typ in list(pydantic.types._DEFINED_TYPES): ++for typ in list(pydantic_types._DEFINED_TYPES): + _registered(typ) +-pydantic.types._registered = _registered ++pydantic_types._registered = _registered + st.register_type_strategy(pydantic.Json, resolve_json) diff --git a/python/tools/vendoring/patches/starlette.patch b/python/tools/vendoring/patches/starlette.patch new file mode 100644 index 0000000000..18463cf109 --- /dev/null +++ b/python/tools/vendoring/patches/starlette.patch @@ -0,0 +1,29 @@ +--- ./python/cog/_vendor/starlette/testclient.py 2023-04-17 13:38:36 ++++ ./python/cog/_vendor/starlette/testclient.py 2023-04-17 13:45:59 +@@ -12,7 +12,7 @@ + from urllib.parse import unquote, urljoin + + import anyio +-import anyio.from_thread ++import anyio.from_thread as from_thread + import httpx + from anyio.streams.stapled import StapledObjectStream + +@@ -410,7 +410,7 @@ + if self.portal is not None: + yield self.portal + else: +- with anyio.from_thread.start_blocking_portal( ++ with from_thread.start_blocking_portal( + **self.async_backend + ) as portal: + yield portal +@@ -728,7 +728,7 @@ + def __enter__(self) -> "TestClient": + with contextlib.ExitStack() as stack: + self.portal = portal = stack.enter_context( +- anyio.from_thread.start_blocking_portal(**self.async_backend) ++ from_thread.start_blocking_portal(**self.async_backend) + ) + + @stack.callback diff --git a/python/tools/vendoring/patches/urrlib3.patch b/python/tools/vendoring/patches/urrlib3.patch new file mode 100644 index 0000000000..1d0fdc1aa9 --- /dev/null +++ b/python/tools/vendoring/patches/urrlib3.patch @@ -0,0 +1,63 @@ +--- ./python/cog/_vendor/urllib3/http2.py 2024-04-15 16:10:22 ++++ ./python/cog/_vendor/urllib3/http2.py.new 2024-04-15 16:10:50 +@@ -8,8 +8,8 @@ + import h2.connection # type: ignore[import-untyped] + import h2.events # type: ignore[import-untyped] + +-import urllib3.connection +-import urllib3.util.ssl_ ++import urllib3.connection as urllib3_connection ++import urllib3.util.ssl_ as urllib3_util_ssl_ + from urllib3.response import BaseHTTPResponse + + from ._collections import HTTPHeaderDict +@@ -216,14 +216,14 @@ + + def inject_into_urllib3() -> None: + HTTPSConnectionPool.ConnectionCls = HTTP2Connection +- urllib3.connection.HTTPSConnection = HTTP2Connection # type: ignore[misc] ++ urllib3_connection.HTTPSConnection = HTTP2Connection # type: ignore[misc] + + # TODO: Offer 'http/1.1' as well, but for testing purposes this is handy. +- urllib3.util.ssl_.ALPN_PROTOCOLS = ["h2"] ++ urllib3_util.ssl_.ALPN_PROTOCOLS = ["h2"] + + + def extract_from_urllib3() -> None: + HTTPSConnectionPool.ConnectionCls = orig_HTTPSConnection +- urllib3.connection.HTTPSConnection = orig_HTTPSConnection # type: ignore[misc] ++ urllib3_connection.HTTPSConnection = orig_HTTPSConnection # type: ignore[misc] + +- urllib3.util.ssl_.ALPN_PROTOCOLS = ["http/1.1"] ++ urllib3_util.ssl_.ALPN_PROTOCOLS = ["http/1.1"] +--- ./python/cog/_vendor/urllib3/contrib/emscripten/__init__.py 2024-04-15 16:11:00 ++++ ./python/cog/_vendor/urllib3/contrib/emscripten/__init__.py.new 2024-04-15 16:12:12 +@@ -1,6 +1,6 @@ + from __future__ import annotations + +-import urllib3.connection ++import urllib3.connection as urllib3_connection + + from ...connectionpool import HTTPConnectionPool, HTTPSConnectionPool + from .connection import EmscriptenHTTPConnection, EmscriptenHTTPSConnection +@@ -12,5 +12,5 @@ + # if it isn't ignored + HTTPConnectionPool.ConnectionCls = EmscriptenHTTPConnection + HTTPSConnectionPool.ConnectionCls = EmscriptenHTTPSConnection +- urllib3.connection.HTTPConnection = EmscriptenHTTPConnection # type: ignore[misc,assignment] +- urllib3.connection.HTTPSConnection = EmscriptenHTTPSConnection # type: ignore[misc,assignment] ++ urllib3_connection.HTTPConnection = EmscriptenHTTPConnection # type: ignore[misc,assignment] ++ urllib3_connection.HTTPSConnection = EmscriptenHTTPSConnection # type: ignore[misc,assignment] +--- ./python/cog/_vendor/urllib3/contrib/pyopenssl.py 2024-04-15 16:12:51 ++++ ./python/cog/_vendor/urllib3/contrib/pyopenssl.py.new 2024-04-15 16:14:12 +@@ -28,8 +28,8 @@ + .. code-block:: python + + try: +- import urllib3.contrib.pyopenssl +- urllib3.contrib.pyopenssl.inject_into_urllib3() ++ import urllib3.contrib.pyopenssl as urllib3_contrib_pyopenssl ++ urllib3_contrib_pyopenssl.inject_into_urllib3() + except ImportError: + pass + diff --git a/test-integration/test_integration/fixtures/complex_output_project/predict.py b/test-integration/test_integration/fixtures/complex_output_project/predict.py index b1fb8d0e14..6d137ffde0 100644 --- a/test-integration/test_integration/fixtures/complex_output_project/predict.py +++ b/test-integration/test_integration/fixtures/complex_output_project/predict.py @@ -2,7 +2,7 @@ from cog import BasePredictor, Path from typing import Optional -from pydantic import BaseModel +from cog._vendor.pydantic import BaseModel class ModelOutput(BaseModel):