2929 BatchWriteItemInput ,
3030 BatchWriteItemOutput ,
3131 BillingMode ,
32+ ContinuousBackupsDescription ,
33+ ContinuousBackupsStatus ,
3234 CreateGlobalTableOutput ,
3335 CreateTableInput ,
3436 CreateTableOutput ,
3537 DeleteItemInput ,
3638 DeleteItemOutput ,
3739 DeleteTableOutput ,
40+ DescribeContinuousBackupsOutput ,
3841 DescribeGlobalTableOutput ,
3942 DescribeKinesisStreamingDestinationOutput ,
4043 DescribeTableOutput ,
5558 ListTagsOfResourceOutput ,
5659 NextTokenString ,
5760 PartiQLBatchRequest ,
61+ PointInTimeRecoveryDescription ,
62+ PointInTimeRecoverySpecification ,
63+ PointInTimeRecoveryStatus ,
5864 PositiveIntegerObject ,
5965 ProvisionedThroughputExceededException ,
6066 PutItemInput ,
7379 ScanInput ,
7480 ScanOutput ,
7581 StreamArn ,
82+ TableDescription ,
7683 TableName ,
7784 TagKeyList ,
7885 TagList ,
8188 TransactGetItemsOutput ,
8289 TransactWriteItemsInput ,
8390 TransactWriteItemsOutput ,
91+ UpdateContinuousBackupsOutput ,
8492 UpdateGlobalTableOutput ,
8593 UpdateItemInput ,
8694 UpdateItemOutput ,
109117from localstack .utils .aws import arns , aws_stack
110118from localstack .utils .aws .arns import extract_account_id_from_arn , extract_region_from_arn
111119from localstack .utils .aws .aws_stack import get_valid_regions_for_service
112- from localstack .utils .collections import select_attributes
120+ from localstack .utils .collections import select_attributes , select_from_typed_dict
113121from localstack .utils .common import short_uid , to_bytes
114122from localstack .utils .json import BytesEncoder , canonical_json
115123from localstack .utils .strings import long_uid , to_str
@@ -506,11 +514,13 @@ def describe_table(self, context: RequestContext, table_name: TableName) -> Desc
506514 global_table_region = self .get_global_table_region (context , table_name )
507515
508516 result = self ._forward_request (context = context , region = global_table_region )
517+ table_description : TableDescription = result ["Table" ]
509518
510519 # Update table properties from LocalStack stores
511- table_props = get_store (context .account_id , context .region ).table_properties .get (table_name )
512- if table_props :
513- result .get ("Table" , {}).update (table_props )
520+ if table_props := get_store (context .account_id , context .region ).table_properties .get (
521+ table_name
522+ ):
523+ table_description .update (table_props )
514524
515525 store = get_store (context .account_id , context .region )
516526
@@ -530,22 +540,21 @@ def describe_table(self, context: RequestContext, table_name: TableName) -> Desc
530540 RegionName = replicated_region , ReplicaStatus = ReplicaStatus .ACTIVE
531541 )
532542 )
533- result . get ( "Table" , {}) .update ({"Replicas" : replica_description_list })
543+ table_description .update ({"Replicas" : replica_description_list })
534544
535545 # update only TableId and SSEDescription if present
536- table_definitions = get_store (context .account_id , context .region ).table_definitions .get (
537- table_name
538- )
539- if table_definitions :
546+ if table_definitions := store .table_definitions .get (table_name ):
540547 for key in ["TableId" , "SSEDescription" ]:
541548 if table_definitions .get (key ):
542- result . get ( "Table" , {}) [key ] = table_definitions [key ]
549+ table_description [key ] = table_definitions [key ]
543550 if "TableClass" in table_definitions :
544- result . get ( "Table" , {}) ["TableClassSummary" ] = {
551+ table_description ["TableClassSummary" ] = {
545552 "TableClass" : table_definitions ["TableClass" ]
546553 }
547554
548- return result
555+ return DescribeTableOutput (
556+ Table = select_from_typed_dict (TableDescription , table_description )
557+ )
549558
550559 @handler ("UpdateTable" , expand = False )
551560 def update_table (
@@ -1197,6 +1206,55 @@ def describe_kinesis_streaming_destination(
11971206 KinesisDataStreamDestinations = stream_destinations , TableName = table_name
11981207 )
11991208
1209+ #
1210+ # Continuous Backups
1211+ #
1212+
1213+ def describe_continuous_backups (
1214+ self , context : RequestContext , table_name : TableName
1215+ ) -> DescribeContinuousBackupsOutput :
1216+ self .get_global_table_region (context , table_name )
1217+ store = get_store (context .account_id , context .region )
1218+ continuous_backup_description = (
1219+ store .table_properties .get (table_name , {}).get ("ContinuousBackupsDescription" )
1220+ ) or ContinuousBackupsDescription (
1221+ ContinuousBackupsStatus = ContinuousBackupsStatus .ENABLED ,
1222+ PointInTimeRecoveryDescription = PointInTimeRecoveryDescription (
1223+ PointInTimeRecoveryStatus = PointInTimeRecoveryStatus .DISABLED
1224+ ),
1225+ )
1226+
1227+ return DescribeContinuousBackupsOutput (
1228+ ContinuousBackupsDescription = continuous_backup_description
1229+ )
1230+
1231+ def update_continuous_backups (
1232+ self ,
1233+ context : RequestContext ,
1234+ table_name : TableName ,
1235+ point_in_time_recovery_specification : PointInTimeRecoverySpecification ,
1236+ ) -> UpdateContinuousBackupsOutput :
1237+ self .get_global_table_region (context , table_name )
1238+
1239+ store = get_store (context .account_id , context .region )
1240+ pit_recovery_status = (
1241+ PointInTimeRecoveryStatus .ENABLED
1242+ if point_in_time_recovery_specification ["PointInTimeRecoveryEnabled" ]
1243+ else PointInTimeRecoveryStatus .DISABLED
1244+ )
1245+ continuous_backup_description = ContinuousBackupsDescription (
1246+ ContinuousBackupsStatus = ContinuousBackupsStatus .ENABLED ,
1247+ PointInTimeRecoveryDescription = PointInTimeRecoveryDescription (
1248+ PointInTimeRecoveryStatus = pit_recovery_status
1249+ ),
1250+ )
1251+ table_props = store .table_properties .setdefault (table_name , {})
1252+ table_props ["ContinuousBackupsDescription" ] = continuous_backup_description
1253+
1254+ return UpdateContinuousBackupsOutput (
1255+ ContinuousBackupsDescription = continuous_backup_description
1256+ )
1257+
12001258 #
12011259 # Helpers
12021260 #
@@ -1271,7 +1329,7 @@ def prepare_request_headers(headers: Dict, account_id: str, region_name: str):
12711329
12721330 # DynamoDBLocal namespaces based on the value of Credentials
12731331 # Since we want to namespace by both account ID and region, use an aggregate key
1274- # We also replace the region to keep compatibilty with NoSQL Workbench
1332+ # We also replace the region to keep compatibility with NoSQL Workbench
12751333 headers ["Authorization" ] = re .sub (
12761334 AUTH_CREDENTIAL_REGEX ,
12771335 rf"Credential={ key } /\2/{ region_name } /\4/" ,
0 commit comments