# 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_premsupport/'; 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=['index.html','PREREG.md','PROGRESS.md','scripts/s7_premsupport.py','scripts/s8_prem_stats.py','scripts/gen_page.py','scripts/backup_s3_premsupport.py','results/s7.log']+['results/'+f for f in os.listdir(L+'/results') if f.startswith('prem_')] 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))