@@ -84,39 +84,79 @@ static PyObject *
8484structseq_new (PyTypeObject * type , PyObject * args , PyObject * kwds )
8585{
8686 PyObject * arg = NULL ;
87+ PyObject * dict = NULL ;
88+ PyObject * ob ;
8789 PyStructSequence * res = NULL ;
88- int len , required_len , i ;
89- static char * kwlist [] = {"sequence" , 0 };
90- static char msgbuf [128 ];
90+ int len , min_len , max_len , i ;
91+ static char * kwlist [] = {"sequence" , "dict" , 0 };
9192
92- if (!PyArg_ParseTupleAndKeywords (args , kwds , "O:structseq" ,
93- kwlist , & arg ))
93+ if (!PyArg_ParseTupleAndKeywords (args , kwds , "O|O :structseq" ,
94+ kwlist , & arg , & dict ))
9495 return NULL ;
9596
96- if (! PySequence_Check ( arg )) {
97- PyErr_SetString ( PyExc_TypeError ,
98- "constructor requires a sequence" );
97+ arg = PySequence_Fast ( arg , "constructor requires a sequence" );
98+
99+ if (! arg ) {
99100 return NULL ;
100101 }
101102
102- len = PySequence_Length (arg );
103- required_len = REAL_SIZE_TP (type );
104- if (len != required_len ) {
105- PyOS_snprintf (
106- msgbuf , sizeof (msgbuf ),
107- "constructor takes exactly %d arguments (%d given)" ,
108- required_len ,
109- len );
110- PyErr_SetString (PyExc_TypeError , msgbuf );
103+ if (dict && !PyDict_Check (dict )) {
104+ PyErr_Format (PyExc_TypeError ,
105+ "%.500s() takes a dict as second arg, if any" ,
106+ type -> tp_name );
107+ Py_DECREF (arg );
111108 return NULL ;
112109 }
113110
111+ len = PySequence_Fast_GET_SIZE (arg );
112+ min_len = VISIBLE_SIZE_TP (type );
113+ max_len = REAL_SIZE_TP (type );
114+
115+ if (min_len != max_len ) {
116+ if (len < min_len ) {
117+ PyErr_Format (PyExc_TypeError ,
118+ "%.500s() takes an at least %d-sequence (%d-sequence given)" ,
119+ type -> tp_name , min_len , len );
120+ Py_DECREF (arg );
121+ return NULL ;
122+ }
123+
124+ if (len > max_len ) {
125+ PyErr_Format (PyExc_TypeError ,
126+ "%.500s() takes an at most %d-sequence (%d-sequence given)" ,
127+ type -> tp_name , max_len , len );
128+ Py_DECREF (arg );
129+ return NULL ;
130+ }
131+ }
132+ else {
133+ if (len != min_len ) {
134+ PyErr_Format (PyExc_TypeError ,
135+ "%.500s() takes a %d-sequence (%d-sequence given)" ,
136+ type -> tp_name , min_len , len );
137+ Py_DECREF (arg );
138+ return NULL ;
139+ }
140+ }
141+
114142 res = (PyStructSequence * ) PyStructSequence_New (type );
115143 for (i = 0 ; i < len ; ++ i ) {
116- /* INCREF???? XXXX */
117- res -> ob_item [i ] = PySequence_GetItem (arg , i );
144+ PyObject * v = PySequence_Fast_GET_ITEM (arg , i );
145+ Py_INCREF (v );
146+ res -> ob_item [i ] = v ;
147+ }
148+ for (; i < max_len ; ++ i ) {
149+ if (dict && (ob = PyDict_GetItemString (
150+ dict , type -> tp_members [i ].name ))) {
151+ }
152+ else {
153+ ob = Py_None ;
154+ }
155+ Py_INCREF (ob );
156+ res -> ob_item [i ] = ob ;
118157 }
119158
159+ Py_DECREF (arg );
120160 return (PyObject * ) res ;
121161}
122162
@@ -192,21 +232,34 @@ static PyObject *
192232structseq_reduce (PyStructSequence * self )
193233{
194234 PyObject * tup ;
195- long n_fields ;
235+ PyObject * dict ;
236+ long n_fields , n_visible_fields ;
196237 int i ;
197238
198239 n_fields = REAL_SIZE (self );
199- tup = PyTuple_New (n_fields );
240+ n_visible_fields = VISIBLE_SIZE (self );
241+ tup = PyTuple_New (n_visible_fields );
200242 if (!tup ) {
201243 return NULL ;
202244 }
203245
204- for (i = 0 ; i < n_fields ; i ++ ) {
246+ dict = PyDict_New ();
247+ if (!dict ) {
248+ Py_DECREF (tup );
249+ return NULL ;
250+ }
251+
252+ for (i = 0 ; i < n_visible_fields ; i ++ ) {
205253 Py_INCREF (self -> ob_item [i ]);
206254 PyTuple_SET_ITEM (tup , i , self -> ob_item [i ]);
207255 }
208256
209- return Py_BuildValue ("(O(O))" , self -> ob_type , tup );
257+ for (; i < n_fields ; i ++ ) {
258+ PyDict_SetItemString (dict , self -> ob_type -> tp_members [i ].name ,
259+ self -> ob_item [i ]);
260+ }
261+
262+ return Py_BuildValue ("(O(OO))" , self -> ob_type , tup , dict );
210263}
211264
212265static PySequenceMethods structseq_as_sequence = {
0 commit comments