@@ -95,15 +95,15 @@ impl PyProperty {
95
95
match value {
96
96
PySetterValue :: Assign ( value) => {
97
97
if let Some ( setter) = zelf. setter . read ( ) . as_ref ( ) {
98
- setter. call ( ( obj. clone ( ) , value) , vm) . map ( drop)
98
+ setter. call ( ( obj, value) , vm) . map ( drop)
99
99
} else {
100
100
let error_msg = zelf. format_property_error ( & obj, "setter" , vm) ?;
101
101
Err ( vm. new_attribute_error ( error_msg) )
102
102
}
103
103
}
104
104
PySetterValue :: Delete => {
105
105
if let Some ( deleter) = zelf. deleter . read ( ) . as_ref ( ) {
106
- deleter. call ( ( obj. clone ( ) , ) , vm) . map ( drop)
106
+ deleter. call ( ( obj, ) , vm) . map ( drop)
107
107
} else {
108
108
let error_msg = zelf. format_property_error ( & obj, "deleter" , vm) ?;
109
109
Err ( vm. new_attribute_error ( error_msg) )
@@ -166,29 +166,33 @@ impl PyProperty {
166
166
167
167
// Python builder functions
168
168
169
- # [ pymethod ]
170
- fn getter (
169
+ // Helper method to create a new property with updated attributes
170
+ fn clone_property_with (
171
171
zelf : PyRef < Self > ,
172
- getter : Option < PyObjectRef > ,
172
+ new_getter : Option < PyObjectRef > ,
173
+ new_setter : Option < PyObjectRef > ,
174
+ new_deleter : Option < PyObjectRef > ,
173
175
vm : & VirtualMachine ,
174
176
) -> PyResult < PyRef < Self > > {
175
- let new_getter = getter. or_else ( || zelf. fget ( ) ) ;
176
-
177
- // Determine doc based on getter_doc flag
177
+ // Determine doc based on getter_doc flag and whether we're updating the getter
178
178
let doc = if zelf. getter_doc . load ( Ordering :: Relaxed ) && new_getter. is_some ( ) {
179
179
// If the original property uses getter doc and we have a new getter,
180
180
// pass Py_None to let __init__ get the doc from the new getter
181
181
Some ( vm. ctx . none ( ) )
182
+ } else if zelf. getter_doc . load ( Ordering :: Relaxed ) {
183
+ // If original used getter_doc but we're not changing the getter,
184
+ // pass None to let init get doc from existing getter
185
+ Some ( vm. ctx . none ( ) )
182
186
} else {
183
187
// Otherwise use the existing doc
184
188
zelf. doc_getter ( )
185
189
} ;
186
190
187
- // Create property args
191
+ // Create property args with updated values
188
192
let args = PropertyArgs {
189
- fget : new_getter,
190
- fset : zelf. fset ( ) ,
191
- fdel : zelf. fdel ( ) ,
193
+ fget : new_getter. or_else ( || zelf . fget ( ) ) ,
194
+ fset : new_setter . or_else ( || zelf. fset ( ) ) ,
195
+ fdel : new_deleter . or_else ( || zelf. fdel ( ) ) ,
192
196
doc,
193
197
name : None ,
194
198
} ;
@@ -206,38 +210,22 @@ impl PyProperty {
206
210
Ok ( new_prop_ref)
207
211
}
208
212
213
+ #[ pymethod]
214
+ fn getter (
215
+ zelf : PyRef < Self > ,
216
+ getter : Option < PyObjectRef > ,
217
+ vm : & VirtualMachine ,
218
+ ) -> PyResult < PyRef < Self > > {
219
+ Self :: clone_property_with ( zelf, getter, None , None , vm)
220
+ }
221
+
209
222
#[ pymethod]
210
223
fn setter (
211
224
zelf : PyRef < Self > ,
212
225
setter : Option < PyObjectRef > ,
213
226
vm : & VirtualMachine ,
214
227
) -> PyResult < PyRef < Self > > {
215
- // For setter, we need to preserve doc handling from the original property
216
- let doc = if zelf. getter_doc . load ( Ordering :: Relaxed ) {
217
- // If original used getter_doc, pass None to let init get doc from getter
218
- Some ( vm. ctx . none ( ) )
219
- } else {
220
- zelf. doc_getter ( )
221
- } ;
222
-
223
- let args = PropertyArgs {
224
- fget : zelf. fget ( ) ,
225
- fset : setter. or_else ( || zelf. fset ( ) ) ,
226
- fdel : zelf. fdel ( ) ,
227
- doc,
228
- name : None ,
229
- } ;
230
-
231
- let new_prop = PyProperty :: py_new ( zelf. class ( ) . to_owned ( ) , FuncArgs :: default ( ) , vm) ?;
232
- let new_prop_ref = new_prop. downcast :: < PyProperty > ( ) . unwrap ( ) ;
233
- PyProperty :: init ( new_prop_ref. clone ( ) , args, vm) ?;
234
-
235
- // Copy the name if it exists
236
- if let Some ( name) = zelf. name . read ( ) . clone ( ) {
237
- * new_prop_ref. name . write ( ) = Some ( name) ;
238
- }
239
-
240
- Ok ( new_prop_ref)
228
+ Self :: clone_property_with ( zelf, None , setter, None , vm)
241
229
}
242
230
243
231
#[ pymethod]
@@ -246,32 +234,7 @@ impl PyProperty {
246
234
deleter : Option < PyObjectRef > ,
247
235
vm : & VirtualMachine ,
248
236
) -> PyResult < PyRef < Self > > {
249
- // For deleter, we need to preserve doc handling from the original property
250
- let doc = if zelf. getter_doc . load ( Ordering :: Relaxed ) {
251
- // If original used getter_doc, pass None to let init get doc from getter
252
- Some ( vm. ctx . none ( ) )
253
- } else {
254
- zelf. doc_getter ( )
255
- } ;
256
-
257
- let args = PropertyArgs {
258
- fget : zelf. fget ( ) ,
259
- fset : zelf. fset ( ) ,
260
- fdel : deleter. or_else ( || zelf. fdel ( ) ) ,
261
- doc,
262
- name : None ,
263
- } ;
264
-
265
- let new_prop = PyProperty :: py_new ( zelf. class ( ) . to_owned ( ) , FuncArgs :: default ( ) , vm) ?;
266
- let new_prop_ref = new_prop. downcast :: < PyProperty > ( ) . unwrap ( ) ;
267
- PyProperty :: init ( new_prop_ref. clone ( ) , args, vm) ?;
268
-
269
- // Copy the name if it exists
270
- if let Some ( name) = zelf. name . read ( ) . clone ( ) {
271
- * new_prop_ref. name . write ( ) = Some ( name) ;
272
- }
273
-
274
- Ok ( new_prop_ref)
237
+ Self :: clone_property_with ( zelf, None , None , deleter, vm)
275
238
}
276
239
277
240
#[ pygetset( magic) ]
@@ -365,11 +328,6 @@ impl Initializer for PyProperty {
365
328
type Args = PropertyArgs ;
366
329
367
330
fn init ( zelf : PyRef < Self > , args : Self :: Args , vm : & VirtualMachine ) -> PyResult < ( ) > {
368
- * zelf. getter . write ( ) = args. fget . clone ( ) ;
369
- * zelf. setter . write ( ) = args. fset ;
370
- * zelf. deleter . write ( ) = args. fdel ;
371
- * zelf. name . write ( ) = args. name . map ( |a| a. as_object ( ) . to_owned ( ) ) ;
372
-
373
331
// Set doc and getter_doc flag
374
332
let mut getter_doc = false ;
375
333
@@ -411,6 +369,10 @@ impl Initializer for PyProperty {
411
369
}
412
370
}
413
371
372
+ * zelf. getter . write ( ) = args. fget ;
373
+ * zelf. setter . write ( ) = args. fset ;
374
+ * zelf. deleter . write ( ) = args. fdel ;
375
+ * zelf. name . write ( ) = args. name . map ( |a| a. as_object ( ) . to_owned ( ) ) ;
414
376
zelf. getter_doc . store ( getter_doc, Ordering :: Relaxed ) ;
415
377
416
378
Ok ( ( ) )
0 commit comments