@@ -299,6 +299,24 @@ is_unionable(PyObject *obj)
299299 return 0 ;
300300}
301301
302+ static int
303+ is_args_unionable (PyObject * args )
304+ {
305+ Py_ssize_t nargs = PyTuple_GET_SIZE (args );
306+ for (Py_ssize_t iarg = 0 ; iarg < nargs ; iarg ++ ) {
307+ PyObject * arg = PyTuple_GET_ITEM (args , iarg );
308+ int is_arg_unionable = is_unionable (arg );
309+ if (is_arg_unionable <= 0 ) {
310+ if (is_arg_unionable == 0 ) {
311+ PyErr_Format (PyExc_TypeError ,
312+ "Each union argument must be a type, got %.100R" , arg );
313+ }
314+ return 0 ;
315+ }
316+ }
317+ return 1 ;
318+ }
319+
302320PyObject *
303321_Py_union_type_or (PyObject * self , PyObject * other )
304322{
@@ -422,15 +440,36 @@ static PyObject *
422440union_reduce (PyObject * self , PyObject * Py_UNUSED (ignored ))
423441{
424442 unionobject * alias = (unionobject * )self ;
425- return Py_BuildValue ("O(O)" , Py_TYPE (alias ), alias -> args );
443+ PyObject * from_args = PyObject_GetAttrString (self , "from_args" );
444+ if (from_args == NULL ) {
445+ return NULL ;
446+ }
447+
448+ return Py_BuildValue ("O(O)" , from_args , alias -> args );
426449}
427450
428451static PyMemberDef union_members [] = {
429452 {"__args__" , T_OBJECT , offsetof(unionobject , args ), READONLY },
430453 {0 }
431454};
432455
456+ static PyObject *
457+ union_from_args (PyObject * cls , PyObject * args )
458+ {
459+ if (!PyTuple_CheckExact (args )) {
460+ _PyArg_BadArgument ("Union.from_args" , "argument '__args__'" , "tuple" , args );
461+ return NULL ;
462+ }
463+
464+ if (is_args_unionable (args ) <= 0 ) {
465+ return NULL ;
466+ }
467+
468+ return make_union (args );
469+ }
470+
433471static PyMethodDef union_methods [] = {
472+ {"from_args" , union_from_args , METH_O | METH_CLASS },
434473 {"__instancecheck__" , union_instancecheck , METH_O },
435474 {"__subclasscheck__" , union_subclasscheck , METH_O },
436475 {"__reduce__" , union_reduce , METH_NOARGS },
@@ -455,18 +494,9 @@ union_getitem(PyObject *self, PyObject *item)
455494 }
456495
457496 // Check arguments are unionable.
458- Py_ssize_t nargs = PyTuple_GET_SIZE (newargs );
459- for (Py_ssize_t iarg = 0 ; iarg < nargs ; iarg ++ ) {
460- PyObject * arg = PyTuple_GET_ITEM (newargs , iarg );
461- int is_arg_unionable = is_unionable (arg );
462- if (is_arg_unionable <= 0 ) {
463- Py_DECREF (newargs );
464- if (is_arg_unionable == 0 ) {
465- PyErr_Format (PyExc_TypeError ,
466- "Each union argument must be a type, got %.100R" , arg );
467- }
468- return NULL ;
469- }
497+ if (is_args_unionable (newargs ) <= 0 ) {
498+ Py_DECREF (newargs );
499+ return NULL ;
470500 }
471501
472502 PyObject * res = make_union (newargs );
@@ -502,34 +532,6 @@ static PyNumberMethods union_as_number = {
502532 .nb_or = _Py_union_type_or , // Add __or__ function
503533};
504534
505- static PyObject *
506- union_new (PyTypeObject * type , PyObject * args , PyObject * kwds )
507- {
508- if (!_PyArg_NoKeywords ("Union" , kwds )) {
509- return NULL ;
510- }
511- if (!_PyArg_CheckPositional ("Union" , PyTuple_GET_SIZE (args ), 1 , 1 )) {
512- return NULL ;
513- }
514-
515- PyObject * unionargs = PyTuple_GET_ITEM (args , 0 );
516-
517- if (!PyTuple_CheckExact (unionargs )) {
518- _PyArg_BadArgument ("Union" , "argument '__args__'" , "tuple" , unionargs );
519- return NULL ;
520- }
521-
522- PyObject * result = _Py_Union (unionargs );
523-
524- if (result == Py_NotImplemented ) {
525- Py_DECREF (result );
526- PyErr_SetString (PyExc_TypeError , "__args__ argument of typing.Union object is not a valid as type" );
527- return NULL ;
528- }
529-
530- return result ;
531- }
532-
533535static const char * const cls_attrs [] = {
534536 "__name__" ,
535537 "__qualname__" ,
@@ -574,7 +576,6 @@ PyTypeObject _PyUnion_Type = {
574576 .tp_as_number = & union_as_number ,
575577 .tp_repr = union_repr ,
576578 .tp_getset = union_properties ,
577- .tp_new = union_new ,
578579};
579580
580581static PyObject *
0 commit comments