@@ -558,18 +558,11 @@ cdef class TextReader:
558558 pass
559559
560560 def __dealloc__ (self ):
561- self .close( )
561+ _close( self )
562562 parser_del(self .parser)
563563
564- def close (self ) -> None:
565- # also preemptively free all allocated memory
566- parser_free(self.parser )
567- if self.true_set:
568- kh_destroy_str_starts(self.true_set )
569- self.true_set = NULL
570- if self.false_set:
571- kh_destroy_str_starts(self.false_set )
572- self.false_set = NULL
564+ def close (self ):
565+ _close(self )
573566
574567 def _set_quoting (self , quote_char: str | bytes | None , quoting: int ):
575568 if not isinstance (quoting, int ):
@@ -1292,6 +1285,21 @@ cdef class TextReader:
12921285 return None
12931286
12941287
1288+ # Factor out code common to TextReader.__dealloc__ and TextReader.close
1289+ # It cannot be a class method, since calling self.close() in __dealloc__
1290+ # which causes a class attribute lookup and violates best parctices
1291+ # https://cython.readthedocs.io/en/latest/src/userguide/special_methods.html#finalization-method-dealloc
1292+ cdef _close(TextReader reader):
1293+ # also preemptively free all allocated memory
1294+ parser_free(reader.parser)
1295+ if reader.true_set:
1296+ kh_destroy_str_starts(reader.true_set)
1297+ reader.true_set = NULL
1298+ if reader.false_set:
1299+ kh_destroy_str_starts(reader.false_set)
1300+ reader.false_set = NULL
1301+
1302+
12951303cdef:
12961304 object _true_values = [b' True' , b' TRUE' , b' true' ]
12971305 object _false_values = [b' False' , b' FALSE' , b' false' ]
0 commit comments