# Backup to NEW prefix only; refuses if prefix non-empty at first run; never overwrites (same-ETag skip, else -vN). import boto3,hashlib,os B='analyticsdata123'; P='options-ml-platform/data/knowledge/popular-strategies/2026-10-26/'; L='/workspace/research/popular-strategies' s3=boto3.client('s3',region_name='ap-south-2') print('existing objects under prefix before upload:',s3.list_objects_v2(Bucket=B,Prefix=P,MaxKeys=5).get('KeyCount',0)) files=[os.path.relpath(os.path.join(r,f),L) for r,_,fs in os.walk(L) for f in fs if '__pycache__' not in r] def etag(k): try: return s3.head_object(Bucket=B,Key=k)['ETag'].strip('"') except s3.exceptions.ClientError: return None st={'new':0,'skip':0,'versioned':0} for f in sorted(files): p=f'{L}/{f}'; md=hashlib.md5(open(p,'rb').read()).hexdigest(); base,ext=os.path.splitext(f); v=1 while True: k=P+(f if v==1 else f'{base}-v{v}{ext}'); e=etag(k) if e is None: s3.upload_file(p,B,k); st['new' if v==1 else 'versioned']+=1; break if e==md: st['skip']+=1; break v+=1 print(st,'files',len(files))