Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f4863a89d8 | |||
| 856f12e57c | |||
| 10e639d19a | |||
| c209cdaec4 | |||
| 169dd00fac | |||
| 58190c378a |
@@ -13,12 +13,14 @@ jobs:
|
|||||||
name: Test (internal)
|
name: Test (internal)
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
python-version:
|
python-version:
|
||||||
- "3.10"
|
- "3.10"
|
||||||
- "3.11"
|
- "3.11"
|
||||||
- "3.12"
|
- "3.12"
|
||||||
- "3.13"
|
- "3.13"
|
||||||
|
- "3.14"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -62,12 +64,14 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
IS_PUBLIC: "true"
|
IS_PUBLIC: "true"
|
||||||
strategy:
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
python-version:
|
python-version:
|
||||||
- "3.10"
|
- "3.10"
|
||||||
- "3.11"
|
- "3.11"
|
||||||
- "3.12"
|
- "3.12"
|
||||||
- "3.13"
|
- "3.13"
|
||||||
|
- "3.14"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import contextlib
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from inspect import isclass
|
from inspect import isclass
|
||||||
|
from types import UnionType
|
||||||
from typing import (
|
from typing import (
|
||||||
Any,
|
Any,
|
||||||
ClassVar,
|
ClassVar,
|
||||||
@@ -13,11 +13,13 @@ from typing import (
|
|||||||
Tuple,
|
Tuple,
|
||||||
Type,
|
Type,
|
||||||
Union,
|
Union,
|
||||||
|
get_origin,
|
||||||
get_type_hints,
|
get_type_hints,
|
||||||
)
|
)
|
||||||
from warnings import warn
|
from warnings import warn
|
||||||
|
|
||||||
from pydantic.alias_generators import to_pascal
|
from pydantic.alias_generators import to_pascal
|
||||||
|
from typing_extensions import get_args
|
||||||
|
|
||||||
from specklepy.logging.exceptions import SpeckleException
|
from specklepy.logging.exceptions import SpeckleException
|
||||||
from specklepy.transports.memory import MemoryTransport
|
from specklepy.transports.memory import MemoryTransport
|
||||||
@@ -220,32 +222,28 @@ def _validate_type(t: Optional[type], value: Any) -> Tuple[bool, Any]:
|
|||||||
if value in t._value2member_map_:
|
if value in t._value2member_map_:
|
||||||
return True, t(value)
|
return True, t(value)
|
||||||
|
|
||||||
if getattr(t, "__module__", None) == "typing":
|
if isinstance(t, ForwardRef):
|
||||||
if isinstance(t, ForwardRef):
|
return True, value
|
||||||
return True, value
|
|
||||||
|
|
||||||
origin = t.__origin__
|
if getattr(t, "__module__", None) in ["typing", "types"]:
|
||||||
# below is what in nicer for >= py38
|
origin = get_origin(t)
|
||||||
# origin = get_origin(t)
|
args = get_args(t)
|
||||||
|
|
||||||
# recursive validation for Unions on both types preferring the fist type
|
# recursive validation for Unions on both types preferring the fist type
|
||||||
if origin is Union:
|
if origin is Union or isinstance(t, UnionType):
|
||||||
# below is what in nicer for >= py38
|
|
||||||
# t_1, t_2 = get_args(t)
|
|
||||||
args = t.__args__ # type: ignore
|
|
||||||
for arg_t in args:
|
for arg_t in args:
|
||||||
t_success, t_value = _validate_type(arg_t, value)
|
ok, v = _validate_type(arg_t, value)
|
||||||
if t_success:
|
if ok:
|
||||||
return True, t_value
|
return True, v
|
||||||
return False, value
|
return False, value
|
||||||
if origin is dict:
|
if origin is dict:
|
||||||
if not isinstance(value, dict):
|
if not isinstance(value, dict):
|
||||||
return False, value
|
return False, value
|
||||||
if value == {}:
|
if not value:
|
||||||
return True, value
|
return True, value
|
||||||
if not getattr(t, "__args__", None):
|
if not args:
|
||||||
return True, value
|
return True, value
|
||||||
t_key, t_value = t.__args__ # type: ignore
|
t_key, t_value = args
|
||||||
|
|
||||||
if (
|
if (
|
||||||
getattr(t_key, "__name__", None),
|
getattr(t_key, "__name__", None),
|
||||||
@@ -265,11 +263,11 @@ def _validate_type(t: Optional[type], value: Any) -> Tuple[bool, Any]:
|
|||||||
if origin is list:
|
if origin is list:
|
||||||
if not isinstance(value, list):
|
if not isinstance(value, list):
|
||||||
return False, value
|
return False, value
|
||||||
if value == []:
|
if not value:
|
||||||
return True, value
|
return True, value
|
||||||
if not hasattr(t, "__args__"):
|
if not args:
|
||||||
return True, value
|
return True, value
|
||||||
t_items = t.__args__[0] # type: ignore
|
t_items = args[0]
|
||||||
if getattr(t_items, "__name__", None) == "T":
|
if getattr(t_items, "__name__", None) == "T":
|
||||||
return True, value
|
return True, value
|
||||||
first_item_valid, _ = _validate_type(t_items, value[0])
|
first_item_valid, _ = _validate_type(t_items, value[0])
|
||||||
@@ -280,10 +278,10 @@ def _validate_type(t: Optional[type], value: Any) -> Tuple[bool, Any]:
|
|||||||
if origin is tuple:
|
if origin is tuple:
|
||||||
if not isinstance(value, tuple):
|
if not isinstance(value, tuple):
|
||||||
return False, value
|
return False, value
|
||||||
if not hasattr(t, "__args__"):
|
if not args:
|
||||||
return True, value
|
return True, value
|
||||||
args = t.__args__ # type: ignore
|
args = t.__args__ # type: ignore
|
||||||
if args == tuple():
|
if not args:
|
||||||
return True, value
|
return True, value
|
||||||
# we're not checking for empty tuple, cause tuple lengths must match
|
# we're not checking for empty tuple, cause tuple lengths must match
|
||||||
if len(args) != len(value):
|
if len(args) != len(value):
|
||||||
@@ -299,7 +297,7 @@ def _validate_type(t: Optional[type], value: Any) -> Tuple[bool, Any]:
|
|||||||
if origin is set:
|
if origin is set:
|
||||||
if not isinstance(value, set):
|
if not isinstance(value, set):
|
||||||
return False, value
|
return False, value
|
||||||
if not hasattr(t, "__args__"):
|
if not args:
|
||||||
return True, value
|
return True, value
|
||||||
t_items = t.__args__[0] # type: ignore
|
t_items = t.__args__[0] # type: ignore
|
||||||
first_item_valid, _ = _validate_type(t_items, next(iter(value)))
|
first_item_valid, _ = _validate_type(t_items, next(iter(value)))
|
||||||
@@ -310,13 +308,16 @@ def _validate_type(t: Optional[type], value: Any) -> Tuple[bool, Any]:
|
|||||||
if isinstance(value, t):
|
if isinstance(value, t):
|
||||||
return True, value
|
return True, value
|
||||||
|
|
||||||
with contextlib.suppress(ValueError, TypeError):
|
if t is float and type(value) is int:
|
||||||
if t is float and value is not None:
|
return True, float(value)
|
||||||
return True, float(value)
|
|
||||||
# TODO: dafuq, i had to add this not list check
|
# with contextlib.suppress(ValueError, TypeError):
|
||||||
# but it would also fail for objects and other complex values
|
# if t is float and value is not None:
|
||||||
if t is str and value and not isinstance(value, list):
|
# return True, float(value)
|
||||||
return True, str(value)
|
# # TODO: dafuq, i had to add this not list check
|
||||||
|
# # but it would also fail for objects and other complex values
|
||||||
|
# if t is str and value and not isinstance(value, list):
|
||||||
|
# return True, str(value)
|
||||||
|
|
||||||
return False, value
|
return False, value
|
||||||
|
|
||||||
|
|||||||
@@ -264,6 +264,7 @@ class TestIngestionResource:
|
|||||||
with pytest.raises(GraphQLException):
|
with pytest.raises(GraphQLException):
|
||||||
_ = client.model_ingestion.fail_with_error(input)
|
_ = client.model_ingestion.fail_with_error(input)
|
||||||
|
|
||||||
|
@pytest.mark.skip(reason="TEST FAILS - server behaviour was changed")
|
||||||
def test_complete_non_existent_root_object(
|
def test_complete_non_existent_root_object(
|
||||||
self, client: SpeckleClient, ingestion: ModelIngestion, project: Project
|
self, client: SpeckleClient, ingestion: ModelIngestion, project: Project
|
||||||
):
|
):
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ def sample_text_all_properties(sample_point: Point, sample_plane: Plane) -> Text
|
|||||||
alignmentH=AlignmentHorizontal.Center,
|
alignmentH=AlignmentHorizontal.Center,
|
||||||
alignmentV=AlignmentVertical.Center,
|
alignmentV=AlignmentVertical.Center,
|
||||||
plane=sample_plane,
|
plane=sample_plane,
|
||||||
maxWidth=20,
|
maxWidth=20.0,
|
||||||
units=Units.m,
|
units=Units.m,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ def test_text_creation_minimal(sample_point: Point):
|
|||||||
|
|
||||||
def test_text_creation_extended(sample_point: Point, sample_plane: Plane):
|
def test_text_creation_extended(sample_point: Point, sample_plane: Plane):
|
||||||
text_value = "text"
|
text_value = "text"
|
||||||
max_width = 20
|
max_width = 20.0
|
||||||
|
|
||||||
text_obj = Text(
|
text_obj = Text(
|
||||||
value=text_value,
|
value=text_value,
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ def test_type_checking() -> None:
|
|||||||
order = FrozenYoghurt()
|
order = FrozenYoghurt()
|
||||||
|
|
||||||
order.servings = 2
|
order.servings = 2
|
||||||
order.price = "7" # type: ignore - it will get converted
|
order.price = 7
|
||||||
order.customer = "izzy"
|
order.customer = "izzy"
|
||||||
order.dietary = DietaryRestrictions.VEGAN
|
order.dietary = DietaryRestrictions.VEGAN
|
||||||
order.tag = "preorder"
|
order.tag = "preorder"
|
||||||
|
|||||||
@@ -31,13 +31,13 @@ fake_bases = [FakeBase("foo"), FakeBase("bar")]
|
|||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"input_type, value, is_valid, return_value",
|
"input_type, value, is_valid, return_value",
|
||||||
[
|
[
|
||||||
(str, 10, True, "10"),
|
(str, 10, False, 10),
|
||||||
(str, "foo_bar", True, "foo_bar"),
|
(str, "foo_bar", True, "foo_bar"),
|
||||||
(
|
(
|
||||||
str,
|
str,
|
||||||
{"foo": "bar"},
|
{"foo": "bar"},
|
||||||
True,
|
False,
|
||||||
"{'foo': 'bar'}",
|
{"foo": "bar"},
|
||||||
),
|
),
|
||||||
(float, 1, True, 1),
|
(float, 1, True, 1),
|
||||||
# why are we allowing this??? We're lying to our users and ourselves too.
|
# why are we allowing this??? We're lying to our users and ourselves too.
|
||||||
@@ -85,9 +85,8 @@ fake_bases = [FakeBase("foo"), FakeBase("bar")]
|
|||||||
(Dict[int, Base], {1: test_base}, True, {1: test_base}),
|
(Dict[int, Base], {1: test_base}, True, {1: test_base}),
|
||||||
(Tuple[int, str, str], (1, "foo", "bar"), True, (1, "foo", "bar")),
|
(Tuple[int, str, str], (1, "foo", "bar"), True, (1, "foo", "bar")),
|
||||||
(Tuple, (1, "foo", "bar"), True, (1, "foo", "bar")),
|
(Tuple, (1, "foo", "bar"), True, (1, "foo", "bar")),
|
||||||
# given our current rules, this is the reality. Its just sad...
|
(Tuple[str, str, str], (1, "foo", "bar"), False, (1, "foo", "bar")),
|
||||||
(Tuple[str, str, str], (1, "foo", "bar"), True, ("1", "foo", "bar")),
|
(Tuple[str, Optional[str], str], (1, None, "bar"), False, (1, None, "bar")),
|
||||||
(Tuple[str, Optional[str], str], (1, None, "bar"), True, ("1", None, "bar")),
|
|
||||||
(Set[bool], set([1, 2]), False, set([1, 2])),
|
(Set[bool], set([1, 2]), False, set([1, 2])),
|
||||||
(Set[int], set([1, 2]), True, set([1, 2])),
|
(Set[int], set([1, 2]), True, set([1, 2])),
|
||||||
(Set[int], set([None, 2]), True, set([None, 2])),
|
(Set[int], set([None, 2]), True, set([None, 2])),
|
||||||
|
|||||||
Reference in New Issue
Block a user