Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit02f357c

Browse files
committed
Handleobject in union so that conversion to other types is attempted
Earlier no conversion was attempted if argument was typed like `arg:int | object`. Nowadays conversion to types before `object` isattempted.Fixes#5529.We plant to change `Any` conversion this way as well. See#5571 fordetails.Also simplify `Should Be Equal` typing. The old approach would havecaused issues if `Any` handling was changed.
1 parentb0cfca4 commit02f357c

File tree

10 files changed

+147
-31
lines changed

10 files changed

+147
-31
lines changed

‎atest/robot/keywords/type_conversion/unions.robot‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ Union with None and str
1515
Union with ABC
1616
Check Test Case${TESTNAME}
1717

18+
Union with Any
19+
Check Test Case${TESTNAME}
20+
21+
Union with object
22+
Check Test Case${TESTNAME}
23+
1824
Union with subscripted generics
1925
Check Test Case${TESTNAME}
2026

‎atest/robot/keywords/type_conversion/unionsugar.robot‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ Union with None and str
1616
Union with ABC
1717
Check Test Case${TESTNAME}
1818

19+
Union with Any
20+
Check Test Case${TESTNAME}
21+
22+
Union with object
23+
Check Test Case${TESTNAME}
24+
1925
Union with subscripted generics
2026
Check Test Case${TESTNAME}
2127

‎atest/testdata/keywords/type_conversion/unions.py‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
fromcollections.abcimportMapping
22
fromdatetimeimportdate,timedelta
33
fromnumbersimportRational
4-
fromtypingimportList,Optional,TypedDict,Union
4+
fromtypingimportAny,List,Optional,TypedDict,Union
55

66
fromrobot.utils.assertsimportassert_equal
77

@@ -55,6 +55,14 @@ def union_with_str_and_abc(argument: Union[str, Rational], expected):
5555
assert_equal(argument,expected)
5656

5757

58+
defunion_with_any(argument:Union[int,Any,float],expected):
59+
assert_equal(argument,expected)
60+
61+
62+
defunion_with_object(argument:Union[int,object,float],expected):
63+
assert_equal(argument,expected)
64+
65+
5866
defunion_with_subscripted_generics(argument:Union[List[int],int],expected=object()):
5967
assert_equal(argument,eval(expected))
6068

‎atest/testdata/keywords/type_conversion/unions.robot‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,24 @@ Union with ABC
3333
${1}${1}
3434
1${1}
3535

36+
Union with Any
37+
[Documentation] Any value is accepted without conversion
38+
[Template] Union with Any
39+
${1}${1}
40+
${1.2}${1.2}
41+
${None}${None}
42+
1 1
43+
1.2 1.2
44+
45+
Union with object
46+
[Documentation] Any value is accepted but conversion is attempted
47+
[Template] Union with object
48+
${1}${1}
49+
${1.2}${1.2}
50+
${None}${None}
51+
1${1}
52+
1.2 1.2
53+
3654
Union with subscripted generics
3755
[Template] Union with subscripted generics
3856
\[1, 2] [1, 2]

‎atest/testdata/keywords/type_conversion/unionsugar.py‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
fromnumbersimportRational
2-
fromtypingimportTypedDict
2+
fromtypingimportAny,TypedDict
33

44

55
classMyObject:
@@ -51,6 +51,14 @@ def union_with_str_and_abc(argument: str | Rational, expected):
5151
assertargument==expected
5252

5353

54+
defunion_with_any(argument:int|Any|float,expected):
55+
assertargument==expected
56+
57+
58+
defunion_with_object(argument:int|object|float,expected):
59+
assertargument==expected
60+
61+
5462
defunion_with_subscripted_generics(argument:list[int]|int,expected=object()):
5563
assertargument==eval(expected),f"{argument!r} !={expected!r}"
5664

‎atest/testdata/keywords/type_conversion/unionsugar.robot‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,24 @@ Union with ABC
3333
${1}${1}
3434
1${1}
3535

36+
Union with Any
37+
[Documentation] Any value is accepted without conversion
38+
[Template] Union with Any
39+
${1}${1}
40+
${1.2}${1.2}
41+
${None}${None}
42+
1 1
43+
1.2 1.2
44+
45+
Union with object
46+
[Documentation] Any value is accepted but conversion is attempted
47+
[Template] Union with object
48+
${1}${1}
49+
${1.2}${1.2}
50+
${None}${None}
51+
1${1}
52+
1.2 1.2
53+
3654
Union with subscripted generics
3755
[Template] Union with subscripted generics
3856
\[1, 2] [1, 2]

‎doc/userguide/src/ExtendingRobotFramework/CreatingTestLibraries.rst‎

Lines changed: 68 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,13 +1526,16 @@ Other types cause conversion failures.
15261526
Specifying multiple possible types
15271527
''''''''''''''''''''''''''''''''''
15281528

1529-
Starting from Robot Framework 4.0, it is possible to specify that an argument
1530-
has multiple possible types. In this situation argument conversion is attempted
1531-
based on each type and the whole conversion fails if none of these conversions
1532-
succeed.
1529+
It is possible to specify that an argument has multiple possible types. In this
1530+
situation argument conversion is attempted based on each type, from left to right,
1531+
and the value of the first succeeding conversion is used. If none of these conversions
1532+
succeeds, the whole conversion fails.
1533+
1534+
Union syntax
1535+
````````````
15331536

15341537
When using function annotations, the natural syntax to specify that an argument
1535-
has multiple possible types is usingUnion_:
1538+
has multiple possible types is usingaUnion_:
15361539

15371540
..sourcecode::python
15381541

@@ -1542,23 +1545,29 @@ has multiple possible types is using Union_:
15421545
def example(length: Union[int, float], padding: Union[int, str, None] = None):
15431546
...
15441547

1545-
When using Python 3.10 or newer, it is possible to use the native`type1 | type2`__
1546-
syntax instead:
1548+
When using Python 3.10 or newer, it is possible to use the`nativeunion syntax`__
1549+
like `int | float` instead:
15471550

15481551
..sourcecode::python
15491552

15501553
def example(length: int | float, padding: int | str | None = None):
15511554
...
15521555

15531556
Robot Framework 7.0 enhanced the support for the union syntax so that also
1554-
"stringly typed" unions like `'type1 |type2'` work. This syntax works also
1557+
"stringly typed" unions like `"int |float"` work. This syntax works also
15551558
with older Python versions:
15561559

15571560
..sourcecode::python
15581561

1559-
def example(length:'int | float', padding:'int | str | None' = None):
1562+
def example(length:"int | float", padding:"int | str | None" = None):
15601563
...
15611564

1565+
__https://peps.python.org/pep-0604/
1566+
.. _Union:https://docs.python.org/3/library/typing.html#typing.Union
1567+
1568+
Using tuples
1569+
````````````
1570+
15621571
An alternative is specifying types as a tuple. It is not recommended with annotations,
15631572
because that syntax is not supported by other tools, but it works well with
15641573
the `@keyword` decorator:
@@ -1576,11 +1585,15 @@ With the above examples the `length` argument would first be converted to an
15761585
integer and if that fails then to a float. The `padding` would be first
15771586
converted to an integer, then to a string, and finally to `None`.
15781587

1588+
When argument matches one of the types
1589+
``````````````````````````````````````
1590+
15791591
If the given argument has one of the accepted types, then no conversion is done
1580-
and the argument is used as-is. For example, if the `length` argument gets
1581-
value `1.5` as a float, it would not be converted to an integer. Notice that
1582-
using non-string values like floats as an argument requires using variables as
1583-
these examples giving different values to the `length` argument demonstrate:
1592+
and the argument is used as-is. For example, if the `length` argument typed
1593+
like `length: int | float` is used with a floating point number `1.5`, it is not
1594+
converted to an integer. Notice that using non-string values like floats as an
1595+
argument requires using variables as these examples giving different values to
1596+
the `length` argument demonstrate:
15841597

15851598
..sourcecode::robotframework
15861599

@@ -1591,10 +1604,10 @@ these examples giving different values to the `length` argument demonstrate:
15911604
Example ${10} # Argument is an integer. Accepted as-is.
15921605
Example ${1.5} # Argument is a float. Accepted as-is.
15931606

1594-
If one of the accepted types is string, then no conversion is done if the given
1595-
argument is a string. Asthefollowing examples giving different values to the
1596-
`padding` argument demonstrate, also in these cases passing other types is
1597-
possible using variables:
1607+
If one of the accepted types is string like in `padding: int | str | None`,
1608+
then no conversion is done ifthegiven argument is a string. As the following
1609+
examples giving different values to the`padding` argument demonstrate, also in
1610+
these cases passing other types ispossible using variables:
15981611

15991612
..sourcecode::robotframework
16001613

@@ -1607,9 +1620,7 @@ possible using variables:
16071620
Example 1 ${1.5} # Argument is a float. Converted to an integer.
16081621

16091622
If the given argument does not have any of the accepted types, conversion is
1610-
attempted in the order types are specified. If any conversion succeeds, the
1611-
resulting value is used without attempting remaining conversions. If no individual
1612-
conversion succeeds, the whole conversion fails.
1623+
attempted in the order types are specified.
16131624

16141625
..note::The order of types changes the conversion result in cases where the used
16151626
value does not match any of the types, but conversion to multiple types
@@ -1626,9 +1637,43 @@ conversion succeeds, the whole conversion fails.
16261637
the value is already an integer or a float either, because there is no
16271638
need for conversion in such cases.
16281639

1629-
If a specified type is not recognized by Robot Framework, then the original argument
1630-
value is used as-is. For example, with this keyword conversion would first be attempted
1631-
to an integer, but if that fails the keyword would get the original argument:
1640+
Handling `Any` and `object`
1641+
```````````````````````````
1642+
1643+
If `Any` or `object` is used as a type hint on its own like `arg: Any` or `arg: object`,
1644+
any value is accepted without conversion. How they work when used in an union differs,
1645+
though.
1646+
1647+
If `Any` is used in a union like `arg: int | Any`, any value is accepted without
1648+
conversion. This allows using `Any` as an escape hatch that disables argument conversion
1649+
altogether.
1650+
1651+
On the other hand, if `object` is used in an union like `arg: int | object`,
1652+
conversion is attempted to types before `object`. This allows attempting conversion
1653+
to certain type or types, but getting the original value if conversions fail.
1654+
1655+
..note::Although this subtle difference in behavior may be useful, it is also
1656+
somewhat confusing and the plan is to change it in Robot Framework 8.0
1657+
so that `Any` behaves like `object`. See the issue `#5571`__ for more
1658+
information and comment the issue if you do not think the planned change
1659+
is a good idea.
1660+
1661+
__https://github.com/robotframework/robotframework/issues/5571
1662+
1663+
Handling unrecognized types
1664+
```````````````````````````
1665+
1666+
If types that are not recognized by Robot Framework are used in an union, they are
1667+
handled like this:
1668+
1669+
- If a used value matches any of the types, including unrecognized types, the value
1670+
is used as-is without conversion.
1671+
- Otherwise conversion is attempted to recognized types from left to right.
1672+
- If any conversion succeeds, the converted value is returned.
1673+
- If no conversion succeeds, the original value is returned.
1674+
1675+
For example, with the following keyword string `"7"` would be converted to an integer,
1676+
but string `"something"` would be used as-is:
16321677

16331678
..sourcecode::python
16341679

@@ -1641,9 +1686,6 @@ Also in this case `int` conversion is attempted, and the argument id passed as-i
16411686
if it fails. With earlier Robot Framework versions, `int` conversion would not be
16421687
attempted at all.
16431688

1644-
__https://peps.python.org/pep-0604/
1645-
.. _Union:https://docs.python.org/3/library/typing.html#typing.Union
1646-
16471689
Parameterized types
16481690
'''''''''''''''''''
16491691

‎doc/userguide/src/userguide.css‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,9 @@ h4 {
591591
h5 {
592592
font-size:1em;
593593
}
594+
h6 {
595+
font-size:0.9em;
596+
}
594597
cite {
595598
font-size:0.95em;
596599
}

‎src/robot/libraries/BuiltIn.py‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -657,8 +657,9 @@ def should_be_equal(
657657
formatter:Literal["str","repr","ascii"]="str",
658658
strip_spaces:StripSpaces=False,
659659
collapse_spaces:bool=False,
660-
type:"type | str | Literal['AUTO'] | Any | None"=None,
661-
types:"type | str | Any | None"=None,
660+
type:"Literal['AUTO'] | Any | None"=None,
661+
types:"Any | None"=None,
662+
# TODO: 'Any' -> 'TypeForm' with 'type' and 'types' once PEP 747 lands.
662663
):
663664
r"""Fails if the given objects are unequal.
664665

‎src/robot/running/arguments/typeconverters.py‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -795,7 +795,13 @@ def _handles_value(self, value):
795795
returnTrue
796796

797797
defno_conversion_needed(self,value):
798-
returnany(converter.no_conversion_needed(value)forconverterinself.nested)
798+
forconverterinself.nested:
799+
if (
800+
converter.no_conversion_needed(value)
801+
andnotisinstance(converter,ObjectConverter)
802+
):# fmt:skip
803+
returnTrue
804+
returnFalse
799805

800806
def_convert(self,value):
801807
unknown_types=False

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp