Compare commits

...

9 Commits

Author SHA1 Message Date
Gergő Jedlicska 1fb9a4f5fe Merge pull request #252 from specklesystems/gergo/set_type_fix
fix(typing-system): add set type into type validation
2023-01-11 16:10:28 +01:00
Gergő Jedlicska 1668c80bed fix(typing-system): add set type into type validation 2023-01-11 16:07:04 +01:00
Gergő Jedlicska ac6ba87c68 Merge pull request #251 from specklesystems/gergo/unionTriples
fix(type-validation): fix union types with more than 2 arguments
2023-01-10 13:02:36 +01:00
Gergő Jedlicska 3db8565f57 fix(type-validation): fix union types with more than 2 arguments 2023-01-10 12:58:19 +01:00
Alan Rynne a32822f4e3 ci: Updated github actions to use new actions repo 2023-01-09 20:42:24 +01:00
Gergő Jedlicska 40956927c8 Merge pull request #250 from specklesystems/gergo/nonGenericTFix
fix(typing): fix non generic typedefed lists and tuples
2023-01-09 15:54:36 +01:00
Gergő Jedlicska 4628f111ba fix(type-checking): fix py >= 3.9 dict type checking 2023-01-09 15:53:15 +01:00
Gergő Jedlicska 9c952b432d fix(typing): fix non specificed generic types for py 3.7 py 3.8 2023-01-09 15:39:45 +01:00
Gergő Jedlicska f075988e4b fix(typing): fix non generic typedefed lists and tuples 2023-01-09 15:10:23 +01:00
4 changed files with 73 additions and 117 deletions
+4 -69
View File
@@ -6,72 +6,7 @@ on:
jobs:
update_issue:
runs-on: ubuntu-latest
steps:
- name: Get project data
env:
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
ORGANIZATION: specklesystems
PROJECT_NUMBER: 9
run: |
gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
query($org: String!, $number: Int!) {
organization(login: $org){
projectNext(number: $number) {
id
fields(first:20) {
nodes {
id
name
settings
}
}
}
}
}' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json
echo 'PROJECT_ID='$(jq '.data.organization.projectNext.id' project_data.json) >> $GITHUB_ENV
echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV
echo "$PROJECT_ID"
echo "$STATUS_FIELD_ID"
echo 'DONE_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Status") | .settings | fromjson | .options[] | select(.name== "Done") | .id' project_data.json) >> $GITHUB_ENV
echo "$DONE_ID"
- name: Add Issue to project #it's already in the project, but we do this to get its node id!
env:
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
ISSUE_ID: ${{ github.event.issue.node_id }}
run: |
item_id="$( gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
mutation($project:ID!, $id:ID!) {
addProjectNextItem(input: {projectId: $project, contentId: $id}) {
projectNextItem {
id
}
}
}' -f project=$PROJECT_ID -f id=$ISSUE_ID --jq '.data.addProjectNextItem.projectNextItem.id')"
echo 'ITEM_ID='$item_id >> $GITHUB_ENV
- name: Update Status
env:
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
ISSUE_ID: ${{ github.event.issue.node_id }}
run: |
gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
mutation($project:ID!, $status:ID!, $id:ID!, $value:String!) {
set_status: updateProjectNextItemField(
input: {
projectId: $project
itemId: $id
fieldId: $status
value: $value
}
) {
projectNextItem {
id
}
}
}' -f project=$PROJECT_ID -f status=$STATUS_FIELD_ID -f id=$ITEM_ID -f value=${{ env.DONE_ID }}
uses: specklesystems/github-actions/.github/workflows/project-add-issue.yml@main
secrets: inherit
with:
issue-id: ${{ github.event.issue.node_id }}
+4 -42
View File
@@ -6,45 +6,7 @@ on:
jobs:
track_issue:
runs-on: ubuntu-latest
steps:
- name: Get project data
env:
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
ORGANIZATION: specklesystems
PROJECT_NUMBER: 9
run: |
gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
query($org: String!, $number: Int!) {
organization(login: $org){
projectNext(number: $number) {
id
fields(first:20) {
nodes {
id
name
settings
}
}
}
}
}' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json
echo 'PROJECT_ID='$(jq '.data.organization.projectNext.id' project_data.json) >> $GITHUB_ENV
echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV
- name: Add Issue to project
env:
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
ISSUE_ID: ${{ github.event.issue.node_id }}
run: |
item_id="$( gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
mutation($project:ID!, $id:ID!) {
addProjectNextItem(input: {projectId: $project, contentId: $id}) {
projectNextItem {
id
}
}
}' -f project=$PROJECT_ID -f id=$ISSUE_ID --jq '.data.addProjectNextItem.projectNextItem.id')"
echo 'ITEM_ID='$item_id >> $GITHUB_ENV
uses: specklesystems/github-actions/.github/workflows/project-add-issue.yml@main
secrets: inherit
with:
issue-id: ${{ github.event.issue.node_id }}
+33 -5
View File
@@ -223,19 +223,28 @@ def _validate_type(t: Optional[type], value: Any) -> Tuple[bool, Any]:
# recursive validation for Unions on both types preferring the fist type
if origin is Union:
t_1, t_2 = t.__args__ # type: ignore
# below is what in nicer for >= py38
# t_1, t_2 = get_args(t)
t_1_success, t_1_value = _validate_type(t_1, value)
if t_1_success:
return True, t_1_value
return _validate_type(t_2, value)
args = t.__args__ # type: ignore
for arg_t in args:
t_success, t_value = _validate_type(arg_t, value)
if t_success:
return True, t_value
return False, value
if origin is dict:
if not isinstance(value, dict):
return False, value
if value == {}:
return True, value
if not getattr(t, "__args__", None):
return True, value
t_key, t_value = t.__args__ # type: ignore
if (
getattr(t_key, "__name__", None),
getattr(t_value, "__name__", None),
) == ("KT", "VT"):
return True, value
# we're only checking the first item, but the for loop and return after
# evaluating the first item is the fastest way
for dict_key, dict_value in value.items():
@@ -251,7 +260,11 @@ def _validate_type(t: Optional[type], value: Any) -> Tuple[bool, Any]:
return False, value
if value == []:
return True, value
if not hasattr(t, "__args__"):
return True, value
t_items = t.__args__[0] # type: ignore
if getattr(t_items, "__name__", None) == "T":
return True, value
first_item_valid, _ = _validate_type(t_items, value[0])
if first_item_valid:
return True, value
@@ -260,7 +273,11 @@ def _validate_type(t: Optional[type], value: Any) -> Tuple[bool, Any]:
if origin is tuple:
if not isinstance(value, tuple):
return False, value
if not hasattr(t, "__args__"):
return True, value
args = t.__args__ # type: ignore
if args == tuple():
return True, value
# we're not checking for empty tuple, cause tuple lengths must match
if len(args) != len(value):
return False, value
@@ -272,6 +289,17 @@ def _validate_type(t: Optional[type], value: Any) -> Tuple[bool, Any]:
values.append(item_value)
return True, tuple(values)
if origin is set:
if not isinstance(value, set):
return False, value
if not hasattr(t, "__args__"):
return True, value
t_items = t.__args__[0] # type: ignore
first_item_valid, _ = _validate_type(t_items, next(iter(value)))
if first_item_valid:
return True, value
return False, value
if isinstance(value, t):
return True, value
+32 -1
View File
@@ -1,5 +1,5 @@
from enum import Enum, IntEnum
from typing import Any, Dict, List, Optional, Tuple
from typing import Any, Dict, List, Optional, Set, Tuple, Union
import pytest
@@ -18,6 +18,16 @@ class FakeIntEnum(IntEnum):
one = 1
class FakeBase(Base):
foo: Optional[str]
def __init__(self, foo: str) -> None:
self.foo = foo
fake_bases = [FakeBase("foo"), FakeBase("bar")]
@pytest.mark.parametrize(
"input_type, value, is_valid, return_value",
[
@@ -64,7 +74,9 @@ class FakeIntEnum(IntEnum):
# same as the dict typing below...
(List[int], [None, 2], True, [None, 2]),
(List[Optional[int]], [None, 2], True, [None, 2]),
(List, ["foo", 2, "bar"], True, ["foo", 2, "bar"]),
(Dict[str, int], {"foo": 1}, True, {"foo": 1}),
(Dict, {"foo": 1}, True, {"foo": 1}),
(Dict[str, Optional[int]], {"foo": None}, True, {"foo": None}),
# this case should be
# (Dict[int, Base], {1: None}, False, {1: None}),
@@ -72,9 +84,28 @@ class FakeIntEnum(IntEnum):
(Dict[int, Base], {1: None}, True, {1: None}),
(Dict[int, Base], {1: test_base}, True, {1: test_base}),
(Tuple[int, str, str], (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"), True, ("1", "foo", "bar")),
(Tuple[str, Optional[str], str], (1, None, "bar"), True, ("1", None, "bar")),
(Set[bool], set([1, 2]), False, set([1, 2])),
(Set[int], set([1, 2]), True, set([1, 2])),
(Set[int], set([None, 2]), True, set([None, 2])),
# not testing this, since order of input iterables in sets are not preserved
# easily produces false reports since we're only checking the type of the
# first item
# (Set[int], set(["None", 2]), False, set(["None", 2])),
(Set[Optional[int]], set([None, 2]), True, set([None, 2])),
(Optional[Union[List[int], List[FakeBase]]], None, True, None),
(Optional[Union[List[int], List[FakeBase]]], "foo", False, "foo"),
(Union[List[int], List[FakeBase], None], "foo", False, "foo"),
(Optional[Union[List[int], List[FakeBase]]], [1, 2, 3], True, [1, 2, 3]),
(
Optional[Union[List[int], List[FakeBase]]],
fake_bases,
True,
fake_bases,
),
],
)
def test_validate_type(