1212from pathlib import Path
1313
1414import jsonschema
15- import msgpack
15+ import msgspec
1616import nats
17- import simplejson as json
17+ import simplejson
1818import singer
1919from adjust_precision_for_schema import adjust_decimal_precision_for_schema
20- from jsonschema import Draft4Validator
2120from nats .js .kv import KeyValue
2221from singer .messages import (
2322 ActivateVersionMessage ,
@@ -33,7 +32,8 @@ def emit_state(state: dict | None) -> None:
3332 """Emit the state to stdout in JSON format."""
3433 if state is None :
3534 return
36- line = json .dumps (state )
35+ state_encoder = msgspec .json .Encoder (decimal_format = "number" )
36+ line = state_encoder .encode (state ).decode ("utf-8" )
3737 logger .debug ("Emitting state %s" , line )
3838 sys .stdout .write (f"{ line } \n " )
3939 sys .stdout .flush ()
@@ -71,12 +71,16 @@ async def persist_messages(
7171 schemas : dict [str , dict ] = {}
7272 key_properties : dict [str , list [str ]] = {}
7373 bookmarks : dict [str , (list [str ] | None )] = {}
74- validators : dict [str , Draft4Validator ] = {}
74+ validators : dict [str , jsonschema .Draft4Validator ] = {}
75+ json_encoder = msgspec .json .Encoder (decimal_format = "number" )
76+ msgpack_encoder = msgspec .msgpack .Encoder (decimal_format = "number" )
77+ json_decoder = msgspec .json .Decoder ()
78+ msgpack_decoder = msgspec .msgpack .Decoder ()
7579
7680 for message in next_singer_message ():
7781 try :
7882 o = singer .parse_message (message )
79- except json .JSONDecodeError :
83+ except simplejson .JSONDecodeError :
8084 logger .error ("Unable to parse: %s" , repr (message ))
8185 raise
8286
@@ -184,11 +188,10 @@ async def persist_messages(
184188 # we don't know what format was used when the data was
185189 # originally stored.
186190 try :
187- current_record = msgpack . unpackb (current .value , raw = False )
188- except (msgpack . exceptions . ExtraData , ValueError ):
191+ current_record = msgpack_decoder . decode (current .value )
192+ except (msgspec . DecodeError , ValueError ):
189193 # Fallback to JSON if msgpack fails.
190- current_value = current .value .decode ("utf-8" )
191- current_record = json .loads (current_value )
194+ current_record = json_decoder .decode (current .value )
192195
193196 # Check if the record was deleted.
194197 if "_sdc_deleted_at" in current_record :
@@ -246,9 +249,9 @@ async def persist_messages(
246249 if should_update :
247250 # Update with revision
248251 if use_msgpack :
249- value = msgpack . packb (o .record )
252+ value = msgpack_encoder . encode (o .record )
250253 else :
251- value = json . dumps (o .record ). encode ( "utf-8" )
254+ value = json_encoder . encode (o .record )
252255 await kv_client .update (
253256 key = key ,
254257 value = value ,
@@ -269,9 +272,9 @@ async def persist_messages(
269272 except nats .js .errors .KeyNotFoundError :
270273 # Key doesn't exist, create it.
271274 if use_msgpack :
272- value = msgpack . packb (o .record )
275+ value = msgpack_encoder . encode (o .record )
273276 else :
274- value = json . dumps (o .record ). encode ( "utf-8" )
277+ value = json_encoder . encode (o .record )
275278 await kv_client .create (
276279 key = key ,
277280 value = value ,
@@ -280,9 +283,9 @@ async def persist_messages(
280283 # User has requested "full" sync, so use "put" without
281284 # data checks.
282285 if use_msgpack :
283- value = msgpack . packb (o .record )
286+ value = msgpack_encoder . encode (o .record )
284287 else :
285- value = json . dumps (o .record ). encode ( "utf-8" )
288+ value = json_encoder . encode (o .record )
286289 await kv_client .put (
287290 key = key ,
288291 value = value ,
@@ -296,8 +299,8 @@ async def persist_messages(
296299 stream = o .stream
297300 schemas [stream ] = o .schema
298301 adjust_decimal_precision_for_schema (schemas [stream ])
302+ validators [stream ] = jsonschema .Draft4Validator (o .schema )
299303 bookmarks [stream ] = o .bookmark_properties
300- validators [stream ] = Draft4Validator (o .schema )
301304 key_properties [stream ] = o .key_properties
302305 elif isinstance (o , ActivateVersionMessage ):
303306 logger .warning (
@@ -358,8 +361,9 @@ def main() -> None:
358361 args = parser .parse_args ()
359362
360363 if args .config :
361- with open (args .config ) as input_json :
362- config = json .load (input_json )
364+ config_decoder = msgspec .json .Decoder ()
365+ with open (args .config , "rb" ) as input_json :
366+ config = config_decoder .decode (input_json .read ())
363367 else :
364368 config = {}
365369
0 commit comments