Repository: docarray/docarray

Issue:
bug(v2): relative file paths in url types
Passing relative file paths gives a validation error:

```python
from docarray import Image

url = 'Test/05978.jpg'
img = Image(url=url)
```

```text
Test/05978.jpg
Traceback (most recent call last):
  File "/home/johannes/.config/JetBrains/PyCharmCE2022.3/scratches/scratch_116.py", line 12, in <module>
    img = Image(url=url)
  File "pydantic/main.py", line 342, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for Image
url
  unsupported operand type(s) for +: 'NoneType' and 'str' (type=type_error)
```




Discussion:

Resolving patch:
diff --git a/docarray/typing/url/any_url.py b/docarray/typing/url/any_url.py
--- a/docarray/typing/url/any_url.py
+++ b/docarray/typing/url/any_url.py
@@ -1,4 +1,4 @@
-from typing import TYPE_CHECKING, Type, TypeVar
+from typing import TYPE_CHECKING, Optional, Type, TypeVar
 
 from pydantic import AnyUrl as BaseAnyUrl
 from pydantic import errors, parse_obj_as
@@ -34,11 +34,14 @@ def validate_parts(cls, parts: 'Parts', validate_port: bool = True) -> 'Parts':
         """
         A method used to validate parts of a URL.
         Our URLs should be able to function both in local and remote settings.
-        Therefore, we allow missing `scheme`, making it possible to pass a file path.
+        Therefore, we allow missing `scheme`, making it possible to pass a file
+        path without prefix.
+        If `scheme` is missing, we assume it is a local file path.
         """
         scheme = parts['scheme']
         if scheme is None:
-            pass  # allow missing scheme, unlike pydantic
+            # allow missing scheme, unlike pydantic
+            pass
 
         elif cls.allowed_schemes and scheme.lower() not in cls.allowed_schemes:
             raise errors.UrlSchemePermittedError(set(cls.allowed_schemes))
@@ -52,6 +55,44 @@ def validate_parts(cls, parts: 'Parts', validate_port: bool = True) -> 'Parts':
 
         return parts
 
+    @classmethod
+    def build(
+        cls,
+        *,
+        scheme: str,
+        user: Optional[str] = None,
+        password: Optional[str] = None,
+        host: str,
+        port: Optional[str] = None,
+        path: Optional[str] = None,
+        query: Optional[str] = None,
+        fragment: Optional[str] = None,
+        **_kwargs: str,
+    ) -> str:
+        """
+        Build a URL from its parts.
+        The only difference from the pydantic implementation is that we allow
+        missing `scheme`, making it possible to pass a file path without prefix.
+        """
+
+        # allow missing scheme, unlike pydantic
+        scheme_ = scheme if scheme is not None else ''
+        url = super().build(
+            scheme=scheme_,
+            user=user,
+            password=password,
+            host=host,
+            port=port,
+            path=path,
+            query=query,
+            fragment=fragment,
+            **_kwargs,
+        )
+        if scheme is None and url.startswith('://'):
+            # remove the `://` prefix, since scheme is missing
+            url = url[3:]
+        return url
+
     @classmethod
     def from_protobuf(cls: Type[T], pb_msg: 'str') -> T:
         """


Test patch:
diff --git a/tests/units/typing/url/test_any_url.py b/tests/units/typing/url/test_any_url.py
--- a/tests/units/typing/url/test_any_url.py
+++ b/tests/units/typing/url/test_any_url.py
@@ -18,3 +18,9 @@ def test_json_schema():
 def test_dump_json():
     url = parse_obj_as(AnyUrl, 'http://jina.ai/img.png')
     orjson_dumps(url)
+
+
+def test_relative_path():
+    # see issue: https://github.com/docarray/docarray/issues/978
+    url = parse_obj_as(AnyUrl, 'data/05978.jpg')
+    assert url == 'data/05978.jpg'