@@ -85,10 +85,12 @@ def __init__(cls, name, bases, dct):
8585
8686
8787class _MessageType (object , metaclass = _RegisterMessageType ):
88+ __slots__ = ('custom_payload' , 'tracing' , 'allow_beta_protocol_version' )
8889
89- tracing = False
90- custom_payload = None
91- warnings = None
90+ def __init__ (self ):
91+ self .custom_payload = None
92+ self .tracing = False
93+ self .allow_beta_protocol_version = False
9294
9395 def update_custom_payload (self , other ):
9496 if other :
@@ -102,18 +104,28 @@ def __repr__(self):
102104 return '<%s(%s)>' % (self .__class__ .__name__ , ', ' .join ('%s=%r' % i for i in _get_params (self )))
103105
104106
107+ class _DecodableMessageType (_MessageType ):
108+ """Base class for messages that can be decoded and receive protocol attributes"""
109+ __slots__ = ('stream_id' , 'trace_id' , 'warnings' )
110+
111+
105112def _get_params (message_obj ):
106113 base_attrs = dir (_MessageType )
114+ # Use __slots__ to get attributes since we no longer have __dict__
115+ all_slots = []
116+ for cls in type (message_obj ).__mro__ :
117+ if hasattr (cls , '__slots__' ):
118+ all_slots .extend (cls .__slots__ )
107119 return (
108- (n , a ) for n , a in message_obj . __dict__ . items ()
109- if n not in base_attrs and not n .startswith ('_' ) and not callable ( a )
120+ (n , getattr ( message_obj , n , None )) for n in all_slots
121+ if n not in base_attrs and not n .startswith ('_' ) and hasattr ( message_obj , n )
110122 )
111123
112124
113125error_classes = {}
114126
115127
116- class ErrorMessage (_MessageType , Exception ):
128+ class ErrorMessage (Exception ):
117129 opcode = 0x00
118130 name = 'ERROR'
119131 summary = 'Unknown'
@@ -407,6 +419,10 @@ class ClientWriteError(RequestExecutionException):
407419 error_code = 0x8000
408420
409421
422+ # Manually register ErrorMessage since it doesn't use _RegisterMessageType metaclass
423+ register_class (ErrorMessage )
424+
425+
410426class StartupMessage (_MessageType ):
411427 opcode = 0x01
412428 name = 'STARTUP'
@@ -418,6 +434,7 @@ class StartupMessage(_MessageType):
418434 ))
419435
420436 def __init__ (self , cqlversion , options ):
437+ super ().__init__ ()
421438 self .cqlversion = cqlversion
422439 self .options = options
423440
@@ -427,7 +444,9 @@ def send_body(self, f, protocol_version):
427444 write_stringmap (f , optmap )
428445
429446
430- class ReadyMessage (_MessageType ):
447+ class ReadyMessage (_DecodableMessageType ):
448+ __slots__ = ()
449+
431450 opcode = 0x02
432451 name = 'READY'
433452
@@ -436,11 +455,14 @@ def recv_body(cls, *args):
436455 return cls ()
437456
438457
439- class AuthenticateMessage (_MessageType ):
458+ class AuthenticateMessage (_DecodableMessageType ):
459+ __slots__ = ('authenticator' ,)
460+
440461 opcode = 0x03
441462 name = 'AUTHENTICATE'
442463
443464 def __init__ (self , authenticator ):
465+ super ().__init__ ()
444466 self .authenticator = authenticator
445467
446468 @classmethod
@@ -454,6 +476,7 @@ class CredentialsMessage(_MessageType):
454476 name = 'CREDENTIALS'
455477
456478 def __init__ (self , creds ):
479+ super ().__init__ ()
457480 self .creds = creds
458481
459482 def send_body (self , f , protocol_version ):
@@ -468,11 +491,14 @@ def send_body(self, f, protocol_version):
468491 write_string (f , credval )
469492
470493
471- class AuthChallengeMessage (_MessageType ):
494+ class AuthChallengeMessage (_DecodableMessageType ):
495+ __slots__ = ('challenge' ,)
496+
472497 opcode = 0x0E
473498 name = 'AUTH_CHALLENGE'
474499
475500 def __init__ (self , challenge ):
501+ super ().__init__ ()
476502 self .challenge = challenge
477503
478504 @classmethod
@@ -485,17 +511,21 @@ class AuthResponseMessage(_MessageType):
485511 name = 'AUTH_RESPONSE'
486512
487513 def __init__ (self , response ):
514+ super ().__init__ ()
488515 self .response = response
489516
490517 def send_body (self , f , protocol_version ):
491518 write_longstring (f , self .response )
492519
493520
494- class AuthSuccessMessage (_MessageType ):
521+ class AuthSuccessMessage (_DecodableMessageType ):
522+ __slots__ = ('token' ,)
523+
495524 opcode = 0x10
496525 name = 'AUTH_SUCCESS'
497526
498527 def __init__ (self , token ):
528+ super ().__init__ ()
499529 self .token = token
500530
501531 @classmethod
@@ -511,11 +541,14 @@ def send_body(self, f, protocol_version):
511541 pass
512542
513543
514- class SupportedMessage (_MessageType ):
544+ class SupportedMessage (_DecodableMessageType ):
545+ __slots__ = ('cql_versions' , 'options' )
546+
515547 opcode = 0x06
516548 name = 'SUPPORTED'
517549
518550 def __init__ (self , cql_versions , options ):
551+ super ().__init__ ()
519552 self .cql_versions = cql_versions
520553 self .options = options
521554
@@ -541,11 +574,15 @@ def recv_body(cls, f, *args):
541574
542575
543576class _QueryMessage (_MessageType ):
544-
545- def __init__ (self , query_params , consistency_level ,
546- serial_consistency_level = None , fetch_size = None ,
547- paging_state = None , timestamp = None , skip_meta = False ,
548- continuous_paging_options = None , keyspace = None ):
577+ __slots__ = ('query_params' , 'consistency_level' , 'serial_consistency_level' ,
578+ 'fetch_size' , 'paging_state' , 'skip_meta' , 'timestamp' , 'keyspace' )
579+
580+ def __init__ (self , query_params , consistency_level , serial_consistency_level = None ,
581+ fetch_size = None , paging_state = None , skip_meta = False ,
582+ timestamp = None , keyspace = None , continuous_paging_options = None ):
583+ super ().__init__ ()
584+ # Note: continuous_paging_options is accepted for backward compatibility
585+ # but is not currently implemented (not stored or used)
549586 self .query_params = query_params
550587 self .consistency_level = consistency_level
551588 self .serial_consistency_level = serial_consistency_level
@@ -607,32 +644,46 @@ def _write_paging_options(self, f, paging_options, protocol_version):
607644
608645
609646class QueryMessage (_QueryMessage ):
647+ __slots__ = ('query' ,)
648+
610649 opcode = 0x07
611650 name = 'QUERY'
612651
613652 def __init__ (self , query , consistency_level , serial_consistency_level = None ,
614653 fetch_size = None , paging_state = None , timestamp = None , continuous_paging_options = None , keyspace = None ):
654+ # Note: continuous_paging_options is accepted for backward compatibility
655+ # but is not currently implemented (not stored or used)
615656 self .query = query
616- super (QueryMessage , self ).__init__ (None , consistency_level , serial_consistency_level , fetch_size ,
617- paging_state , timestamp , False , continuous_paging_options , keyspace )
657+ super (QueryMessage , self ).__init__ (query_params = None , consistency_level = consistency_level ,
658+ serial_consistency_level = serial_consistency_level ,
659+ fetch_size = fetch_size , paging_state = paging_state ,
660+ skip_meta = False , timestamp = timestamp , keyspace = keyspace ,
661+ continuous_paging_options = continuous_paging_options )
618662
619663 def send_body (self , f , protocol_version ):
620664 write_longstring (f , self .query )
621665 self ._write_query_params (f , protocol_version )
622666
623667
624668class ExecuteMessage (_QueryMessage ):
669+ __slots__ = ('query_id' , 'result_metadata_id' )
670+
625671 opcode = 0x0A
626672 name = 'EXECUTE'
627673
628674 def __init__ (self , query_id , query_params , consistency_level ,
629675 serial_consistency_level = None , fetch_size = None ,
630676 paging_state = None , timestamp = None , skip_meta = False ,
631677 continuous_paging_options = None , result_metadata_id = None ):
678+ # Note: continuous_paging_options is accepted for backward compatibility
679+ # but is not currently implemented (not stored or used)
632680 self .query_id = query_id
633681 self .result_metadata_id = result_metadata_id
634- super (ExecuteMessage , self ).__init__ (query_params , consistency_level , serial_consistency_level , fetch_size ,
635- paging_state , timestamp , skip_meta , continuous_paging_options )
682+ super (ExecuteMessage , self ).__init__ (query_params = query_params , consistency_level = consistency_level ,
683+ serial_consistency_level = serial_consistency_level ,
684+ fetch_size = fetch_size , paging_state = paging_state ,
685+ skip_meta = skip_meta , timestamp = timestamp , keyspace = None ,
686+ continuous_paging_options = continuous_paging_options )
636687
637688 def _write_query_params (self , f , protocol_version ):
638689 super (ExecuteMessage , self )._write_query_params (f , protocol_version )
@@ -653,14 +704,14 @@ def send_body(self, f, protocol_version):
653704RESULT_KIND_SCHEMA_CHANGE = 0x0005
654705
655706
656- class ResultMessage (_MessageType ):
707+ class ResultMessage (_DecodableMessageType ):
708+ __slots__ = ('kind' , 'result_metadata_id' , 'results' , 'paging_state' , 'column_names' , 'column_types' ,
709+ 'parsed_rows' , 'continuous_paging_seq' , 'continuous_paging_last' , 'new_keyspace' ,
710+ 'column_metadata' , 'query_id' , 'bind_metadata' , 'pk_indexes' , 'schema_change_event' , 'is_lwt' )
711+
657712 opcode = 0x08
658713 name = 'RESULT'
659714
660- kind = None
661- results = None
662- paging_state = None
663-
664715 # Names match type name in module scope. Most are imported from cassandra.cqltypes (except CUSTOM_TYPE)
665716 type_codes = _cqltypes_by_code = dict ((v , globals ()[k ]) for k , v in type_codes .__dict__ .items () if not k .startswith ('_' ))
666717
@@ -671,25 +722,25 @@ class ResultMessage(_MessageType):
671722 _CONTINUOUS_PAGING_LAST_FLAG = 0x80000000
672723 _METADATA_ID_FLAG = 0x0008
673724
674- kind = None
675-
676- # These are all the things a result message might contain. They are populated according to 'kind'
677- column_names = None
678- column_types = None
679- parsed_rows = None
680- paging_state = None
681- continuous_paging_seq = None
682- continuous_paging_last = None
683- new_keyspace = None
684- column_metadata = None
685- query_id = None
686- bind_metadata = None
687- pk_indexes = None
688- schema_change_event = None
689- is_lwt = False
690-
691725 def __init__ (self , kind ):
726+ super ().__init__ ()
692727 self .kind = kind
728+ # Initialize all slot attributes to None
729+ self .result_metadata_id = None
730+ self .results = None
731+ self .paging_state = None
732+ self .column_names = None
733+ self .column_types = None
734+ self .parsed_rows = None
735+ self .continuous_paging_seq = None
736+ self .continuous_paging_last = None
737+ self .new_keyspace = None
738+ self .column_metadata = None
739+ self .query_id = None
740+ self .bind_metadata = None
741+ self .pk_indexes = None
742+ self .schema_change_event = None
743+ self .is_lwt = None
693744
694745 def recv (self , f , protocol_version , protocol_features , user_type_map , result_metadata , column_encryption_policy ):
695746 if self .kind == RESULT_KIND_VOID :
@@ -859,10 +910,13 @@ def recv_row(f, colcount):
859910
860911
861912class PrepareMessage (_MessageType ):
913+ __slots__ = ('query' , 'keyspace' )
914+
862915 opcode = 0x09
863916 name = 'PREPARE'
864917
865918 def __init__ (self , query , keyspace = None ):
919+ super ().__init__ ()
866920 self .query = query
867921 self .keyspace = keyspace
868922
@@ -897,12 +951,15 @@ def send_body(self, f, protocol_version):
897951
898952
899953class BatchMessage (_MessageType ):
954+ __slots__ = ('batch_type' , 'queries' , 'consistency_level' , 'serial_consistency_level' ,
955+ 'timestamp' , 'keyspace' )
956+
900957 opcode = 0x0D
901958 name = 'BATCH'
902959
903960 def __init__ (self , batch_type , queries , consistency_level ,
904- serial_consistency_level = None , timestamp = None ,
905- keyspace = None ):
961+ serial_consistency_level = None , timestamp = None , keyspace = None ):
962+ super (). __init__ ()
906963 self .batch_type = batch_type
907964 self .queries = queries
908965 self .consistency_level = consistency_level
@@ -962,21 +1019,27 @@ def send_body(self, f, protocol_version):
9621019
9631020
9641021class RegisterMessage (_MessageType ):
1022+ __slots__ = ('event_list' ,)
1023+
9651024 opcode = 0x0B
9661025 name = 'REGISTER'
9671026
9681027 def __init__ (self , event_list ):
1028+ super ().__init__ ()
9691029 self .event_list = event_list
9701030
9711031 def send_body (self , f , protocol_version ):
9721032 write_stringlist (f , self .event_list )
9731033
9741034
975- class EventMessage (_MessageType ):
1035+ class EventMessage (_DecodableMessageType ):
1036+ __slots__ = ('event_type' , 'event_args' )
1037+
9761038 opcode = 0x0C
9771039 name = 'EVENT'
9781040
9791041 def __init__ (self , event_type , event_args ):
1042+ super ().__init__ ()
9801043 self .event_type = event_type
9811044 self .event_args = event_args
9821045
@@ -1038,6 +1101,7 @@ class RevisionType(object):
10381101 name = 'REVISE_REQUEST'
10391102
10401103 def __init__ (self , op_type , op_id , next_pages = 0 ):
1104+ super ().__init__ ()
10411105 self .op_type = op_type
10421106 self .op_id = op_id
10431107 self .next_pages = next_pages
0 commit comments