api.py 175 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490
  1. # -*- coding: utf-8 -*-
  2. """
  3. 文件上传方法中的data参数
  4. ------------------------
  5. 诸如 :func:`put_object <Bucket.put_object>` 这样的上传接口都会有 `data` 参数用于接收用户数据。`data` 可以是下述类型
  6. - unicode类型(对于Python3则是str类型):内部会自动转换为UTF-8的bytes
  7. - bytes类型:不做任何转换
  8. - file-like object:对于可以seek和tell的file object,从当前位置读取直到结束。其他类型,请确保当前位置是文件开始。
  9. - 可迭代类型:对于无法探知长度的数据,要求一定是可迭代的。此时会通过Chunked Encoding传输。
  10. Bucket配置修改方法中的input参数
  11. -----------------------------
  12. 诸如 :func:`put_bucket_cors <Bucket.put_bucket_cors>` 这样的Bucket配置修改接口都会有 `input` 参数接收用户提供的配置数据。
  13. `input` 可以是下述类型
  14. - Bucket配置信息相关的类,如 `BucketCors`
  15. - unicode类型(对于Python3则是str类型)
  16. - 经过utf-8编码的bytes类型
  17. - file-like object
  18. - 可迭代类型,会通过Chunked Encoding传输
  19. 也就是说 `input` 参数可以比 `data` 参数多接受第一种类型的输入。
  20. 返回值
  21. ------
  22. :class:`Service` 和 :class:`Bucket` 类的大多数方法都是返回 :class:`RequestResult <oss2.models.RequestResult>`
  23. 及其子类。`RequestResult` 包含了HTTP响应的状态码、头部以及OSS Request ID,而它的子类则包含用户真正想要的结果。例如,
  24. `ListBucketsResult.buckets` 就是返回的Bucket信息列表;`GetObjectResult` 则是一个file-like object,可以调用 `read()` 来获取响应的
  25. HTTP包体。
  26. :class:`CryptoBucket`:
  27. 加密接口
  28. -------
  29. CryptoBucket仅提供上传下载加密数据的接口,诸如`get_object` 、 `put_object` ,返回值与Bucket相应接口一致。
  30. 异常
  31. ----
  32. 一般来说Python SDK可能会抛出三种类型的异常,这些异常都继承于 :class:`OssError <oss2.exceptions.OssError>` :
  33. - :class:`ClientError <oss2.exceptions.ClientError>` :由于用户参数错误而引发的异常;
  34. - :class:`ServerError <oss2.exceptions.ServerError>` 及其子类:OSS服务器返回非成功的状态码,如4xx或5xx;
  35. - :class:`RequestError <oss2.exceptions.RequestError>` :底层requests库抛出的异常,如DNS解析错误,超时等;
  36. 当然,`Bucket.put_object_from_file` 和 `Bucket.get_object_to_file` 这类函数还会抛出文件相关的异常。
  37. .. _byte_range:
  38. 指定下载范围
  39. ------------
  40. 诸如 :func:`get_object <Bucket.get_object>` 以及 :func:`upload_part_copy <Bucket.upload_part_copy>` 这样的函数,可以接受
  41. `byte_range` 参数,表明读取数据的范围。该参数是一个二元tuple:(start, last)。这些接口会把它转换为Range头部的值,如:
  42. - byte_range 为 (0, 99) 转换为 'bytes=0-99',表示读取前100个字节
  43. - byte_range 为 (None, 99) 转换为 'bytes=-99',表示读取最后99个字节
  44. - byte_range 为 (100, None) 转换为 'bytes=100-',表示读取第101个字节到文件结尾的部分(包含第101个字节)
  45. 分页罗列
  46. -------
  47. 罗列各种资源的接口,如 :func:`list_buckets <Service.list_buckets>` 、 :func:`list_objects <Bucket.list_objects>` 都支持
  48. 分页查询。通过设定分页标记(如:`marker` 、 `key_marker` )的方式可以指定查询某一页。首次调用将分页标记设为空(缺省值,可以不设),
  49. 后续的调用使用返回值中的 `next_marker` 、 `next_key_marker` 等。每次调用后检查返回值中的 `is_truncated` ,其值为 `False` 说明
  50. 已经到了最后一页。
  51. .. _line_range:
  52. 指定查询CSV文件范围
  53. ------------
  54. 诸如 :func:`select_object <Bucket.select_object>` 以及 :func:`select_object_to_file <Bucket.select_object_to_file>` 这样的函数的select_csv_params参数,可以接受
  55. `LineRange` 参数,表明读取CSV数据的范围。该参数是一个二元tuple:(start, last):
  56. - LineRange 为 (0, 99) 表示读取前100行
  57. - LineRange 为 (None, 99) 表示读取最后99行
  58. - LineRange 为 (100, None) 表示读取第101行到文件结尾的部分(包含第101行)
  59. .. _split_range:
  60. 指定查询CSV文件范围
  61. ------------
  62. split可以认为是切分好的大小大致相等的csv行簇。每个Split大小大致相等,这样以便更好的做到负载均衡。
  63. 诸如 :func:`select_object <Bucket.select_object>` 以及 :func:`select_object_to_file <Bucket.select_object_to_file>` 这样的函数的select_csv_params参数,可以接受
  64. `SplitRange` 参数,表明读取CSV数据的范围。该参数是一个二元tuple:(start, last):
  65. - SplitRange 为 (0, 9) 表示读取前10个Split
  66. - SplitRange 为 (None, 9) 表示读取最后9个split
  67. - SplitRange 为 (10, None) 表示读取第11个split到文件结尾的部分(包含第11个Split)
  68. 分页查询
  69. -------
  70. 和create_csv_object_meta配合使用,有两种方法:
  71. - 方法1:先获取文件总的行数(create_csv_object_meta返回),然后把文件以line_range分成若干部分并行查询
  72. - 方法2:先获取文件总的Split数(create_csv_object_meta返回), 然后把文件分成若干个请求,每个请求含有大致相等的Split
  73. .. _progress_callback:
  74. 上传下载进度
  75. -----------
  76. 上传下载接口,诸如 `get_object` 、 `put_object` 、`resumable_upload`,都支持进度回调函数,可以用它实现进度条等功能。
  77. `progress_callback` 的函数原型如下 ::
  78. def progress_callback(bytes_consumed, total_bytes):
  79. '''进度回调函数。
  80. :param int bytes_consumed: 已经消费的字节数。对于上传,就是已经上传的量;对于下载,就是已经下载的量。
  81. :param int total_bytes: 总长度。
  82. '''
  83. 其中 `total_bytes` 对于上传和下载有不同的含义:
  84. - 上传:当输入是bytes或可以seek/tell的文件对象,那么它的值就是总的字节数;否则,其值为None
  85. - 下载:当返回的HTTP相应中有Content-Length头部,那么它的值就是Content-Length的值;否则,其值为None
  86. .. _unix_time:
  87. Unix Time
  88. ---------
  89. OSS Python SDK会把从服务器获得时间戳都转换为自1970年1月1日UTC零点以来的秒数,即Unix Time。
  90. 参见 `Unix Time <https://en.wikipedia.org/wiki/Unix_time>`_
  91. OSS中常用的时间格式有
  92. - HTTP Date格式,形如 `Sat, 05 Dec 2015 11:04:39 GMT` 这样的GMT时间。
  93. 用在If-Modified-Since、Last-Modified这些HTTP请求、响应头里。
  94. - ISO8601格式,形如 `2015-12-05T00:00:00.000Z`。
  95. 用在生命周期管理配置、列举Bucket结果中的创建时间、列举文件结果中的最后修改时间等处。
  96. `http_date` 函数把Unix Time转换为HTTP Date;而 `http_to_unixtime` 则做相反的转换。如 ::
  97. >>> import oss2, time
  98. >>> unix_time = int(time.time()) # 当前UNIX Time,设其值为 1449313829
  99. >>> date_str = oss2.http_date(unix_time) # 得到 'Sat, 05 Dec 2015 11:10:29 GMT'
  100. >>> oss2.http_to_unixtime(date_str) # 得到 1449313829
  101. .. note::
  102. 生成HTTP协议所需的日期(即HTTP Date)时,请使用 `http_date` , 不要使用 `strftime` 这样的函数。因为后者是和locale相关的。
  103. 比如,`strftime` 结果中可能会出现中文,而这样的格式,OSS服务器是不能识别的。
  104. `iso8601_to_unixtime` 把ISO8601格式转换为Unix Time;`date_to_iso8601` 和 `iso8601_to_date` 则在ISO8601格式的字符串和
  105. datetime.date之间相互转换。如 ::
  106. >>> import oss2
  107. >>> d = oss2.iso8601_to_date('2015-12-05T00:00:00.000Z') # 得到 datetime.date(2015, 12, 5)
  108. >>> date_str = oss2.date_to_iso8601(d) # 得到 '2015-12-05T00:00:00.000Z'
  109. >>> oss2.iso8601_to_unixtime(date_str) # 得到 1449273600
  110. .. _select_params:
  111. 指定OSS Select的文件格式。
  112. 对于Csv文件,支持如下Keys:
  113. >>> CsvHeaderInfo: None|Use|Ignore #None表示没有CSV Schema头,Use表示启用CSV Schema头,可以在Select语句中使用Name,Ignore表示有CSV Schema头,但忽略它(Select语句中不可以使用Name)
  114. 默认值是None
  115. >>> CommentCharacter: Comment字符,默认值是#,不支持多个字符
  116. >>> RecordDelimiter: 行分隔符,默认是\n,最多支持两个字符分隔符(比如:\r\n)
  117. >>> FieldDelimiter: 列分隔符,默认是逗号(,), 不支持多个字符
  118. >>> QuoteCharacter: 列Quote字符,默认是双引号("),不支持多个字符。注意转义符合Quote字符相同。
  119. >>> LineRange: 指定查询CSV文件的行范围,参见 `line_range`。
  120. >>> SplitRange: 指定查询CSV文件的Split范围,参见 `split_range`.
  121. 注意LineRange和SplitRange两种不能同时指定。若同时指定LineRange会被忽略。
  122. >>> CompressionType: 文件的压缩格式,默认值是None, 支持GZIP。
  123. >>> OutputRawData: 指定是响应Body返回Raw数据,默认值是False.
  124. >>> SkipPartialDataRecord: 当CSV行数据不完整时(select语句中出现的列在该行为空),是否跳过该行。默认是False。
  125. >>> OutputHeader:是否输出CSV Header,默认是False.
  126. >>> EnablePayloadCrc:是否启用对Payload的CRC校验,默认是False. 该选项不能和OutputRawData:True混用。
  127. >>> MaxSkippedRecordsAllowed: 允许跳过的最大行数。默认值是0表示一旦有一行跳过就报错。当下列两种情况下该行CSV被跳过:1)当SkipPartialDataRecord为True时且该行不完整时 2)当该行的数据类型和SQL不匹配时
  128. 对于Json 文件, 支持如下Keys:
  129. >>> Json_Type: DOCUMENT | LINES . DOCUMENT就是指一般的Json文件,LINES是指每一行是一个合法的JSON对象,文件由多行Json对象组成,整个文件本身不是合法的Json对象。
  130. >>> LineRange: 指定查询JSON LINE文件的行范围,参见 `line_range`。注意该参数仅支持LINES类型
  131. >>> SplitRange: 指定查询JSON LINE文件的Split范围,参见 `split_range`.注意该参数仅支持LINES类型
  132. >>> CompressionType: 文件的压缩格式,默认值是None, 支持GZIP。
  133. >>> OutputRawData: 指定是响应Body返回Raw数据,默认值是False.
  134. >>> SkipPartialDataRecord: 当一条JSON记录数据不完整时(select语句中出现的Key在该对象为空),是否跳过该Json记录。默认是False。
  135. >>> EnablePayloadCrc:是否启用对Payload的CRC校验,默认是False. 该选项不能和OutputRawData:True混用。
  136. >>> MaxSkippedRecordsAllowed: 允许跳过的最大Json记录数。默认值是0表示一旦有一条Json记录跳过就报错。当下列两种情况下该JSON被跳过:1)当SkipPartialDataRecord为True时且该条Json记录不完整时 2)当该记录的数据类型和SQL不匹配时
  137. >>> ParseJsonNumberAsString: 将Json文件中的数字解析成字符串。使用场景是当Json文件中的浮点数精度较高时,系统默认的浮点数精度无法达到要求,当解析成字符串时将完整保留原始数据精度,在Sql中使用Cast可以将字符串无精度损失地转成decimal.
  138. >>> AllowQuotedRecordDelimiter: 允许CSV中的列包含转义过的换行符。默认为true。当值为False时,select API可以用Range:bytes来设置选取目标对象内容的范围
  139. .. _select_meta_params:
  140. create_select_object_meta参数集合,支持如下Keys:
  141. - RecordDelimiter: CSV换行符,最多支持两个字符
  142. - FieldDelimiter: CSV列分隔符,最多支持一个字符
  143. - QuoteCharacter: CSV转移Quote符,最多支持一个字符
  144. - OverwriteIfExists: true|false. true表示重新获得csv meta,并覆盖原有的meta。一般情况下不需要使用
  145. """
  146. import logging
  147. from . import xml_utils
  148. from . import http
  149. from . import utils
  150. from . import exceptions
  151. from . import defaults
  152. from . import models
  153. from . import select_params
  154. from .models import *
  155. from .compat import urlquote, urlparse, to_unicode, to_string
  156. from .headers import *
  157. from .select_params import *
  158. import time
  159. import shutil
  160. logger = logging.getLogger(__name__)
  161. class _Base(object):
  162. def __init__(self, auth, endpoint, is_cname, session, connect_timeout,
  163. app_name='', enable_crc=True, proxies=None, region=None, cloudbox_id= None, is_path_style=False, is_verify_object_strict=True):
  164. self.auth = auth
  165. self.endpoint = _normalize_endpoint(endpoint.strip())
  166. if utils.is_valid_endpoint(self.endpoint) is not True:
  167. raise ClientError('The endpoint you has specified is not valid, endpoint: {0}'.format(endpoint))
  168. self.session = session or http.Session()
  169. self.timeout = defaults.get(connect_timeout, defaults.connect_timeout)
  170. self.app_name = app_name
  171. self.enable_crc = enable_crc
  172. self.proxies = proxies
  173. self.region = region
  174. self.product = 'oss'
  175. self.cloudbox_id = cloudbox_id
  176. if self.cloudbox_id is not None:
  177. self.product = 'oss-cloudbox'
  178. self._make_url = _UrlMaker(self.endpoint, is_cname, is_path_style)
  179. self.is_verify_object_strict = is_verify_object_strict
  180. if hasattr(self.auth, 'auth_version') and self.auth.auth_version() != 'v1' :
  181. self.is_verify_object_strict = False
  182. def _do(self, method, bucket_name, key, **kwargs):
  183. key = to_string(key)
  184. req = http.Request(method, self._make_url(bucket_name, key),
  185. app_name=self.app_name,
  186. proxies=self.proxies,
  187. region=self.region,
  188. product=self.product,
  189. cloudbox_id=self.cloudbox_id,
  190. **kwargs)
  191. self.auth._sign_request(req, bucket_name, key)
  192. resp = self.session.do_request(req, timeout=self.timeout)
  193. if resp.status // 100 != 2:
  194. e = exceptions.make_exception(resp)
  195. logger.info("Exception: {0}".format(e))
  196. raise e
  197. # Note that connections are only released back to the pool for reuse once all body data has been read;
  198. # be sure to either set stream to False or read the content property of the Response object.
  199. # For more details, please refer to http://docs.python-requests.org/en/master/user/advanced/#keep-alive.
  200. content_length = models._hget(resp.headers, 'content-length', int)
  201. if content_length is not None and content_length == 0:
  202. resp.read()
  203. return resp
  204. def _do_url(self, method, sign_url, **kwargs):
  205. req = http.Request(method, sign_url, app_name=self.app_name, proxies=self.proxies, **kwargs)
  206. resp = self.session.do_request(req, timeout=self.timeout)
  207. if resp.status // 100 != 2:
  208. e = exceptions.make_exception(resp)
  209. logger.info("Exception: {0}".format(e))
  210. raise e
  211. # Note that connections are only released back to the pool for reuse once all body data has been read;
  212. # be sure to either set stream to False or read the content property of the Response object.
  213. # For more details, please refer to http://docs.python-requests.org/en/master/user/advanced/#keep-alive.
  214. content_length = models._hget(resp.headers, 'content-length', int)
  215. if content_length is not None and content_length == 0:
  216. resp.read()
  217. return resp
  218. @staticmethod
  219. def _parse_result(resp, parse_func, klass):
  220. result = klass(resp)
  221. parse_func(result, resp.read())
  222. return result
  223. class Service(_Base):
  224. """用于Service操作的类,如罗列用户所有的Bucket。
  225. 用法 ::
  226. >>> import oss2
  227. >>> auth = oss2.Auth('your-access-key-id', 'your-access-key-secret')
  228. >>> service = oss2.Service(auth, 'oss-cn-hangzhou.aliyuncs.com')
  229. >>> service.list_buckets()
  230. <oss2.models.ListBucketsResult object at 0x0299FAB0>
  231. :param auth: 包含了用户认证信息的Auth对象
  232. :type auth: oss2.Auth
  233. :param str endpoint: 访问域名,如杭州区域的域名为oss-cn-hangzhou.aliyuncs.com
  234. :param session: 会话。如果是None表示新开会话,非None则复用传入的会话
  235. :type session: oss2.Session
  236. :param float connect_timeout: 连接超时时间,以秒为单位。
  237. :param str app_name: 应用名。该参数不为空,则在User Agent中加入其值。
  238. 注意到,最终这个字符串是要作为HTTP Header的值传输的,所以必须要遵循HTTP标准。
  239. """
  240. QOS_INFO = 'qosInfo'
  241. REGIONS = 'regions'
  242. WRITE_GET_OBJECT_RESPONSE = 'x-oss-write-get-object-response'
  243. PUBLIC_ACCESS_BLOCK = 'publicAccessBlock'
  244. REQUESTER_QOS_INFO = 'requesterQosInfo'
  245. QOS_REQUESTER = 'qosRequester'
  246. RESOURCE_POOL_INFO = 'resourcePoolInfo'
  247. RESOURCE_POOL = 'resourcePool'
  248. RESOURCE_POOL_BUCKETS = 'resourcePoolBuckets'
  249. def __init__(self, auth, endpoint,
  250. session=None,
  251. connect_timeout=None,
  252. app_name='',
  253. proxies=None,
  254. region=None,
  255. cloudbox_id=None,
  256. is_path_style=False):
  257. logger.debug("Init oss service, endpoint: {0}, connect_timeout: {1}, app_name: {2}, proxies: {3}".format(
  258. endpoint, connect_timeout, app_name, proxies))
  259. super(Service, self).__init__(auth, endpoint, False, session, connect_timeout,
  260. app_name=app_name, proxies=proxies,
  261. region=region, cloudbox_id=cloudbox_id, is_path_style=is_path_style)
  262. def list_buckets(self, prefix='', marker='', max_keys=100, params=None, headers=None):
  263. """根据前缀罗列用户的Bucket。
  264. :param str prefix: 只罗列Bucket名为该前缀的Bucket,空串表示罗列所有的Bucket
  265. :param str marker: 分页标志。首次调用传空串,后续使用返回值中的next_marker
  266. :param int max_keys: 每次调用最多返回的Bucket数目
  267. :param dict params: list操作参数,传入'tag-key','tag-value'对结果进行过滤
  268. :param headers: 用户指定的HTTP头部。可以指定Content-Type、Content-MD5、x-oss-meta-开头的头部等。可以是dict,建议是oss2.CaseInsensitiveDict
  269. :return: 罗列的结果
  270. :rtype: oss2.models.ListBucketsResult
  271. """
  272. logger.debug("Start to list buckets, prefix: {0}, marker: {1}, max-keys: {2}".format(prefix, marker, max_keys))
  273. listParam = {}
  274. listParam['prefix'] = prefix
  275. listParam['marker'] = marker
  276. listParam['max-keys'] = str(max_keys)
  277. headers = http.CaseInsensitiveDict(headers)
  278. if params is not None:
  279. listParam.update(params)
  280. resp = self._do('GET', '', '', params=listParam, headers=headers)
  281. logger.debug("List buckets done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  282. return self._parse_result(resp, xml_utils.parse_list_buckets, ListBucketsResult)
  283. def get_user_qos_info(self):
  284. """获取User的QoSInfo
  285. :return: :class:`GetUserQosInfoResult <oss2.models.GetUserQosInfoResult>`
  286. """
  287. logger.debug("Start to get user qos info.")
  288. resp = self._do('GET', '', '', params={Service.QOS_INFO: ''})
  289. logger.debug("get use qos, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  290. return self._parse_result(resp, xml_utils.parse_get_qos_info, GetUserQosInfoResult)
  291. def describe_regions(self, regions=''):
  292. """查询所有支持地域或者指定地域对应的Endpoint信息,包括外网Endpoint、内网Endpoint和传输加速Endpoint。
  293. :param str regions : 地域。
  294. :return: :class:`DescribeRegionsResult <oss2.models.DescribeRegionsResult>`
  295. """
  296. logger.debug("Start to describe regions")
  297. resp = self._do('GET', '', '', params={Service.REGIONS: regions})
  298. logger.debug("Describe regions done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  299. return self._parse_result(resp, xml_utils.parse_describe_regions, DescribeRegionsResult)
  300. def write_get_object_response(self, route, token, fwd_status, data, headers=None):
  301. """write get object response.
  302. :param route: fc return route
  303. :param token: fc return token
  304. :param fwd_status: fwd_status
  305. :param data: 待上传的内容。
  306. :type data: bytes,str或file-like object
  307. :param headers: 用户指定的HTTP头部。可以指定Content-Type、Content-MD5、x-oss-meta-开头的头部等
  308. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  309. :return: :class:`RequestResult <oss2.models.RequestResult>`
  310. """
  311. logger.debug("Start to write get object response, headers: {0}".format(headers))
  312. headers = http.CaseInsensitiveDict(headers)
  313. if route:
  314. headers['x-oss-request-route'] = route
  315. if token:
  316. headers['x-oss-request-token'] = token
  317. if fwd_status:
  318. headers['x-oss-fwd-status'] = fwd_status
  319. resp = self._do('POST', '', '', params={Service.WRITE_GET_OBJECT_RESPONSE: ''}, headers=headers, data=data)
  320. logger.debug("write get object response done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  321. return RequestResult(resp)
  322. def list_user_data_redundancy_transition(self, continuation_token='', max_keys=100):
  323. """列举请求者所有的存储冗余转换任务。
  324. :param str continuation_token: 分页标志,首次调用传空串
  325. :param int max_keys: 最多返回数目
  326. :return: :class:`ListUserDataRedundancyTransitionResult <oss2.models.ListUserDataRedundancyTransitionResult>`
  327. """
  328. logger.debug("Start to list user data redundancy transition, continuation token: {0}, max keys: {1}".format(continuation_token, max_keys))
  329. resp = self._do('GET', '', '', params={Bucket.REDUNDANCY_TRANSITION: '', 'continuation-token': continuation_token, 'max-keys': str(max_keys)})
  330. logger.debug("List user data redundancy transition done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  331. return self._parse_result(resp, xml_utils.parse_list_user_data_redundancy_transition, ListUserDataRedundancyTransitionResult)
  332. def list_access_points(self, max_keys=100, continuation_token=''):
  333. """查询某个Bucket下所有接入点。
  334. param: int max_keys: 本次list返回access point的最大个数
  335. param: str continuation_token: list时指定的起始标记
  336. :return: :class:`ListBucketStyleResult <oss2.models.ListBucketStyleResult>`
  337. """
  338. logger.debug("Start to list bucket access point")
  339. resp = self._do('GET', '', '', params={Bucket.ACCESS_POINT: '', 'max-keys': str(max_keys), 'continuation-token': continuation_token})
  340. logger.debug("query list access point done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  341. return self._parse_result(resp, xml_utils.parse_list_access_point_result, ListAccessPointResult)
  342. def put_public_access_block(self, block_public_access=False):
  343. """为OSS全局开启阻止公共访问。
  344. :param bool block_public_access : 是否开启阻止公共访问。
  345. :return: :class:`RequestResult <oss2.models.RequestResult>`
  346. """
  347. logger.debug("Start to put public access block")
  348. data = xml_utils.to_put_public_access_block_request(block_public_access)
  349. resp = self._do('PUT', '', '', data=data, params={Service.PUBLIC_ACCESS_BLOCK: ''})
  350. logger.debug("Put public access block done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  351. return RequestResult(resp)
  352. def get_public_access_block(self):
  353. """获取OSS全局阻止公共访问的配置信息。
  354. :return: :class:`GetPublicAccessBlockResult <oss2.models.GetPublicAccessBlockResult>`
  355. """
  356. logger.debug("Start to get public access block")
  357. resp = self._do('GET', '', '', params={Service.PUBLIC_ACCESS_BLOCK: ''})
  358. logger.debug("Get public access block done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  359. return self._parse_result(resp, xml_utils.parse_get_public_access_block_result, GetPublicAccessBlockResult)
  360. def delete_public_access_block(self):
  361. """删除OSS全局阻止公共访问配置信息。
  362. :return: :class:`RequestResult <oss2.models.RequestResult>`
  363. """
  364. logger.debug("Start to delete public access block")
  365. resp = self._do('DELETE', '', '', params={Service.PUBLIC_ACCESS_BLOCK: ''})
  366. logger.debug("Delete public access block done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  367. return RequestResult(resp)
  368. def list_resource_pools(self, continuation_token='', max_keys=100):
  369. """列举当前主账号在当前地域下的资源池。
  370. :param str continuation_token: 分页标志,首次调用传空串
  371. :param int max_keys: 最多返回数目
  372. :return: :class:`ListResourcePoolsResult <oss2.models.ListResourcePoolsResult>`
  373. """
  374. logger.debug("Start to list resource pools, continuation_token: {0}, max_keys: {1}".format(continuation_token, max_keys))
  375. resp = self._do('GET', '', '', params={Service.RESOURCE_POOL: '', 'continuation-token': continuation_token, 'max-keys': str(max_keys)})
  376. logger.debug("List resource pools done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  377. return self._parse_result(resp, xml_utils.parse_list_resource_pools, ListResourcePoolsResult)
  378. def get_resource_pool_info(self, resource_pool_name):
  379. """获取特定资源池的基本信息。
  380. :param str resource_pool_name : 请求的资源池的名称。
  381. :return: :class:`ResourcePoolInfoResult <oss2.models.ResourcePoolInfoResult>`
  382. """
  383. logger.debug("Start to get resource pool info, uid: {0}.".format(resource_pool_name))
  384. if not resource_pool_name:
  385. raise ClientError('resource_pool_name should not be empty')
  386. resp = self._do('GET', '', '', params={Service.RESOURCE_POOL_INFO: '', Service.RESOURCE_POOL: resource_pool_name})
  387. logger.debug("Get resource pool info done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  388. return self._parse_result(resp, xml_utils.parse_get_resource_pool_info, ResourcePoolInfoResult)
  389. def list_resource_pool_buckets(self, resource_pool_name, continuation_token='', max_keys=100):
  390. """获取特定资源池中的Bucket列表。
  391. :param str resource_pool_name : 请求的资源池的名称。
  392. :param str continuation_token: 分页标志,首次调用传空串
  393. :param int max_keys: 最多返回数目
  394. :return: :class:`ListResourcePoolBucketsResult <oss2.models.ListResourcePoolBucketsResult>`
  395. """
  396. logger.debug("Start to list resource pool buckets, resource_pool_name:{0} continuation_token: {1}, max_keys: {2}".format(resource_pool_name, continuation_token, max_keys))
  397. if not resource_pool_name:
  398. raise ClientError('resource_pool_name should not be empty')
  399. resp = self._do('GET', '', '', params={Service.RESOURCE_POOL_BUCKETS: '', Service.RESOURCE_POOL: resource_pool_name, 'continuation-token': continuation_token, 'max-keys': str(max_keys)})
  400. logger.debug("List resource pool buckets done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  401. return self._parse_result(resp, xml_utils.parse_list_resource_pool_buckets, ListResourcePoolBucketsResult)
  402. def put_resource_pool_requester_qos_info(self, uid, resource_pool_name, qos_configuration):
  403. """修改子账号在资源池的请求者流控配置。
  404. :param str uid: 请求者UID
  405. :param str resource_pool_name: 请求的资源池的名称
  406. :param qos_configuration :class:`QoSConfiguration <oss2.models.QoSConfiguration>`
  407. :return: :class:`RequestResult <oss2.models.RequestResult>`
  408. """
  409. logger.debug("Start to put resource pool requester qos info, uid: {0}, resource_pool_name: {1}, qos_configuration: {2}".format(uid, resource_pool_name, qos_configuration))
  410. if not uid:
  411. raise ClientError('uid should not be empty')
  412. if not resource_pool_name:
  413. raise ClientError('resource_pool_name should not be empty')
  414. data = xml_utils.to_put_qos_info(qos_configuration)
  415. resp = self._do('PUT', '', '', data=data, params={Service.REQUESTER_QOS_INFO: '', Service.QOS_REQUESTER: uid, Service.RESOURCE_POOL: resource_pool_name})
  416. logger.debug("Put resource pool requester qos info done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  417. return RequestResult(resp)
  418. def get_resource_pool_requester_qos_info(self, uid, resource_pool_name):
  419. """获取子账号在资源池的流控配置。
  420. :return: :class:`RequesterQoSInfoResult <oss2.models.RequesterQoSInfoResult>`
  421. """
  422. logger.debug("Start to get resource pool requester qos info, uid: {0}, resource_pool_name: {1}.".format(uid, resource_pool_name))
  423. if not uid:
  424. raise ClientError('uid should not be empty')
  425. if not resource_pool_name:
  426. raise ClientError('resource_pool_name should not be empty')
  427. resp = self._do('GET', '', '', params={Service.REQUESTER_QOS_INFO: '', Service.QOS_REQUESTER: uid, Service.RESOURCE_POOL: resource_pool_name})
  428. logger.debug("Get resource pool requester qos info done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  429. return self._parse_result(resp, xml_utils.parse_get_requester_qos_info, RequesterQoSInfoResult)
  430. def list_resource_pool_requester_qos_infos(self, resource_pool_name, continuation_token='', max_keys=100):
  431. """列举子账号账号在资源池的流控配置。
  432. :param str resource_pool_name : 请求的资源池的名称。
  433. :param str continuation_token: 分页标志,首次调用传空串
  434. :param int max_keys: 最多返回数目
  435. :return: :class:`ListResourcePoolRequesterQoSInfosResult <oss2.models.ListResourcePoolRequesterQoSInfosResult>`
  436. """
  437. logger.debug("Start to list resource pool requester qos infos, resource_pool_name:{0} continuation_token: {1}, max_keys: {2}".format(resource_pool_name, continuation_token, max_keys))
  438. if not resource_pool_name:
  439. raise ClientError('resource_pool_name should not be empty')
  440. resp = self._do('GET', '', '', params={Service.REQUESTER_QOS_INFO: '', Service.RESOURCE_POOL: resource_pool_name, 'continuation-token': continuation_token, 'max-keys': str(max_keys)})
  441. logger.debug("List resource pool requester qos infos done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  442. return self._parse_result(resp, xml_utils.parse_list_resource_pool_requester_qos_infos, ListResourcePoolRequesterQoSInfosResult)
  443. def delete_resource_pool_requester_qos_info(self, uid, resource_pool_name):
  444. """删除子账号在资源池的请求者流控配置。
  445. :return: :class:`RequestResult <oss2.models.RequestResult>`
  446. """
  447. logger.debug("Start to delete resource pool requester qos info, uid: {0}, resource_pool_name: {1}.".format(uid, resource_pool_name))
  448. if not uid:
  449. raise ClientError('uid should not be empty')
  450. if not resource_pool_name:
  451. raise ClientError('resource_pool_name should not be empty')
  452. resp = self._do('DELETE', '', '', params={Service.REQUESTER_QOS_INFO: '', Service.QOS_REQUESTER: uid, Service.RESOURCE_POOL: resource_pool_name})
  453. logger.debug("Delete resource pool requester qos info done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  454. return RequestResult(resp)
  455. class Bucket(_Base):
  456. """用于Bucket和Object操作的类,诸如创建、删除Bucket,上传、下载Object等。
  457. 用法(假设Bucket属于杭州区域) ::
  458. >>> import oss2
  459. >>> auth = oss2.Auth('your-access-key-id', 'your-access-key-secret')
  460. >>> bucket = oss2.Bucket(auth, 'http://oss-cn-hangzhou.aliyuncs.com', 'your-bucket')
  461. >>> bucket.put_object('readme.txt', 'content of the object')
  462. <oss2.models.PutObjectResult object at 0x029B9930>
  463. :param auth: 包含了用户认证信息的Auth对象
  464. :type auth: oss2.Auth
  465. :param str endpoint: 访问域名或者CNAME
  466. :param str bucket_name: Bucket名
  467. :param bool is_cname: 如果endpoint是CNAME则设为True;反之,则为False。
  468. :param session: 会话。如果是None表示新开会话,非None则复用传入的会话
  469. :type session: oss2.Session
  470. :param float connect_timeout: 连接超时时间,以秒为单位。
  471. :param str app_name: 应用名。该参数不为空,则在User Agent中加入其值。
  472. 注意到,最终这个字符串是要作为HTTP Header的值传输的,所以必须要遵循HTTP标准。
  473. :param bool is_verify_object_strict: 严格验证对象名称的标志。默认为True。
  474. """
  475. ACL = 'acl'
  476. CORS = 'cors'
  477. LIFECYCLE = 'lifecycle'
  478. LOCATION = 'location'
  479. LOGGING = 'logging'
  480. REFERER = 'referer'
  481. WEBSITE = 'website'
  482. LIVE = 'live'
  483. COMP = 'comp'
  484. STATUS = 'status'
  485. VOD = 'vod'
  486. SYMLINK = 'symlink'
  487. STAT = 'stat'
  488. BUCKET_INFO = 'bucketInfo'
  489. PROCESS = 'x-oss-process'
  490. TAGGING = 'tagging'
  491. ENCRYPTION = 'encryption'
  492. VERSIONS = 'versions'
  493. VERSIONING = 'versioning'
  494. VERSIONID = 'versionId'
  495. RESTORE = 'restore'
  496. OBJECTMETA = 'objectMeta'
  497. POLICY = 'policy'
  498. REQUESTPAYMENT = 'requestPayment'
  499. QOS_INFO = 'qosInfo'
  500. USER_QOS = 'qos'
  501. ASYNC_FETCH = 'asyncFetch'
  502. SEQUENTIAL = 'sequential'
  503. INVENTORY = "inventory"
  504. INVENTORY_CONFIG_ID = "inventoryId"
  505. CONTINUATION_TOKEN = "continuation-token"
  506. WORM = "worm"
  507. WORM_ID = "wormId"
  508. WORM_EXTEND = "wormExtend"
  509. REPLICATION = "replication"
  510. REPLICATION_LOCATION = 'replicationLocation'
  511. REPLICATION_PROGRESS = 'replicationProgress'
  512. TRANSFER_ACCELERATION = 'transferAcceleration'
  513. CNAME = 'cname'
  514. META_QUERY = 'metaQuery'
  515. ACCESS_MONITOR = 'accessmonitor'
  516. RESOURCE_GROUP = 'resourceGroup'
  517. STYLE = 'style'
  518. STYLE_NAME = 'styleName'
  519. ASYNC_PROCESS = 'x-oss-async-process'
  520. CALLBACK = 'callback'
  521. ARCHIVE_DIRECT_READ = "bucketArchiveDirectRead"
  522. HTTPS_CONFIG = 'httpsConfig'
  523. REDUNDANCY_TRANSITION = "redundancyTransition"
  524. TARGET_REDUNDANCY_TYPE = "x-oss-target-redundancy-type"
  525. REDUNDANCY_TRANSITION_TASK_ID = "x-oss-redundancy-transition-taskid"
  526. ACCESS_POINT = 'accessPoint'
  527. ACCESS_POINT_POLICY = 'accessPointPolicy'
  528. OSS_ACCESS_POINT_NAME = 'x-oss-access-point-name'
  529. PUBLIC_ACCESS_BLOCK = 'publicAccessBlock'
  530. OSS_ACCESS_POINT_NAME = 'x-oss-access-point-name'
  531. REQUESTER_QOS_INFO = 'requesterQosInfo'
  532. QOS_REQUESTER = 'qosRequester'
  533. RESOURCE_POOL_INFO = 'resourcePoolInfo'
  534. RESOURCE_POOL = 'resourcePool'
  535. def __init__(self, auth, endpoint, bucket_name,
  536. is_cname=False,
  537. session=None,
  538. connect_timeout=None,
  539. app_name='',
  540. enable_crc=True,
  541. proxies=None,
  542. region=None,
  543. cloudbox_id=None,
  544. is_path_style=False,
  545. is_verify_object_strict=True):
  546. logger.debug("Init Bucket: {0}, endpoint: {1}, isCname: {2}, connect_timeout: {3}, app_name: {4}, enabled_crc: {5}, region: {6}"
  547. ", proxies: {6}".format(bucket_name, endpoint, is_cname, connect_timeout, app_name, enable_crc, proxies, region))
  548. super(Bucket, self).__init__(auth, endpoint, is_cname, session, connect_timeout,
  549. app_name=app_name, enable_crc=enable_crc, proxies=proxies,
  550. region=region, cloudbox_id=cloudbox_id, is_path_style=is_path_style, is_verify_object_strict=is_verify_object_strict)
  551. self.bucket_name = bucket_name.strip()
  552. if utils.is_valid_bucket_name(self.bucket_name) is not True:
  553. raise ClientError("The bucket_name is invalid, please check it.")
  554. def sign_url(self, method, key, expires, headers=None, params=None, slash_safe=False, additional_headers=None):
  555. """生成签名URL。
  556. 常见的用法是生成加签的URL以供授信用户下载,如为log.jpg生成一个5分钟后过期的下载链接::
  557. >>> bucket.sign_url('GET', 'log.jpg', 5 * 60)
  558. r'http://your-bucket.oss-cn-hangzhou.aliyuncs.com/logo.jpg?OSSAccessKeyId=YourAccessKeyId\&Expires=1447178011&Signature=UJfeJgvcypWq6Q%2Bm3IJcSHbvSak%3D'
  559. :param method: HTTP方法,如'GET'、'PUT'、'DELETE'等
  560. :type method: str
  561. :param key: 文件名
  562. :param expires: 过期时间(单位:秒),链接在当前时间再过expires秒后过期
  563. :param headers: 需要签名的HTTP头部,如名称以x-oss-meta-开头的头部(作为用户自定义元数据)、
  564. Content-Type头部等。对于下载,不需要填。
  565. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  566. :param params: 需要签名的HTTP查询参数
  567. :param slash_safe: 是否开启key名称中的‘/’转义保护,如果不开启'/'将会转义成%2F
  568. :type slash_safe: bool
  569. :param additional_headers: 额外的需要签名的HTTP头
  570. :return: 签名URL。
  571. """
  572. if key is None or len(key.strip()) <= 0:
  573. raise ClientError("The key is invalid, please check it.")
  574. key = to_string(key)
  575. if self.is_verify_object_strict and key.startswith('?'):
  576. raise ClientError("The key cannot start with `?`, please check it.")
  577. logger.debug(
  578. "Start to sign_url, method: {0}, bucket: {1}, key: {2}, expires: {3}, headers: {4}, params: {5}, slash_safe: {6}".format(
  579. method, self.bucket_name, to_string(key), expires, headers, params, slash_safe))
  580. req = http.Request(method, self._make_url(self.bucket_name, key, slash_safe),
  581. headers=headers,
  582. params=params,
  583. region=self.region,
  584. product=self.product,
  585. cloudbox_id=self.cloudbox_id)
  586. sign_url = ''
  587. if additional_headers is None:
  588. sign_url = self.auth._sign_url(req, self.bucket_name, key, expires)
  589. else:
  590. sign_url = self.auth._sign_url(req, self.bucket_name, key, expires, in_additional_headers=additional_headers)
  591. return sign_url
  592. def sign_rtmp_url(self, channel_name, playlist_name, expires):
  593. """生成RTMP推流的签名URL。
  594. 常见的用法是生成加签的URL以供授信用户向OSS推RTMP流。
  595. :param channel_name: 直播频道的名称
  596. :param expires: 过期时间(单位:秒),链接在当前时间再过expires秒后过期
  597. :param playlist_name: 播放列表名称,注意与创建live channel时一致
  598. :param params: 需要签名的HTTP查询参数
  599. :return: 签名URL。
  600. """
  601. logger.debug("Sign RTMP url, bucket: {0}, channel_name: {1}, playlist_name: {2}, expires: {3}".format(
  602. self.bucket_name, channel_name, playlist_name, expires))
  603. url = self._make_url(self.bucket_name, 'live').replace('http://', 'rtmp://').replace(
  604. 'https://', 'rtmp://') + '/' + channel_name
  605. params = {}
  606. if playlist_name is not None and playlist_name != "":
  607. params['playlistName'] = playlist_name
  608. return self.auth._sign_rtmp_url(url, self.bucket_name, channel_name, expires, params)
  609. def list_objects(self, prefix='', delimiter='', marker='', max_keys=100, headers=None):
  610. """根据前缀罗列Bucket里的文件。
  611. :param str prefix: 只罗列文件名为该前缀的文件
  612. :param str delimiter: 分隔符。可以用来模拟目录
  613. :param str marker: 分页标志。首次调用传空串,后续使用返回值的next_marker
  614. :param int max_keys: 最多返回文件的个数,文件和目录的和不能超过该值
  615. :param headers: HTTP头部
  616. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  617. :return: :class:`ListObjectsResult <oss2.models.ListObjectsResult>`
  618. """
  619. headers = http.CaseInsensitiveDict(headers)
  620. logger.debug(
  621. "Start to List objects, bucket: {0}, prefix: {1}, delimiter: {2}, marker: {3}, max-keys: {4}".format(
  622. self.bucket_name, to_string(prefix), delimiter, to_string(marker), max_keys))
  623. resp = self.__do_bucket('GET',
  624. params={'prefix': prefix,
  625. 'delimiter': delimiter,
  626. 'marker': marker,
  627. 'max-keys': str(max_keys),
  628. 'encoding-type': 'url'},
  629. headers=headers)
  630. logger.debug("List objects done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  631. return self._parse_result(resp, xml_utils.parse_list_objects, ListObjectsResult)
  632. def list_objects_v2(self, prefix='', delimiter='', continuation_token='', start_after='', fetch_owner=False, encoding_type='url', max_keys=100, headers=None):
  633. """根据前缀罗列Bucket里的文件。
  634. :param str prefix: 只罗列文件名为该前缀的文件
  635. :param str delimiter: 分隔符。可以用来模拟目录
  636. :param str continuation_token: 分页标志。首次调用传空串,后续使用返回值的next_continuation_token
  637. :param str start_after: 起始文件名称,OSS会返回按照字典序排列start_after之后的文件。
  638. :param bool fetch_owner: 是否获取文件的owner信息,默认不返回。
  639. :param int max_keys: 最多返回文件的个数,文件和目录的和不能超过该值
  640. :param headers: HTTP头部
  641. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  642. :return: :class:`ListObjectsV2Result <oss2.models.ListObjectsV2Result>`
  643. """
  644. headers = http.CaseInsensitiveDict(headers)
  645. logger.debug(
  646. "Start to List objects, bucket: {0}, prefix: {1}, delimiter: {2}, continuation_token: {3}, "
  647. "start-after: {4}, fetch-owner: {5}, encoding_type: {6}, max-keys: {7}".format(
  648. self.bucket_name, to_string(prefix), delimiter, continuation_token, start_after, fetch_owner, encoding_type, max_keys))
  649. resp = self.__do_bucket('GET',
  650. params={'list-type': '2',
  651. 'prefix': prefix,
  652. 'delimiter': delimiter,
  653. 'continuation-token': continuation_token,
  654. 'start-after': start_after,
  655. 'fetch-owner': str(fetch_owner).lower(),
  656. 'max-keys': str(max_keys),
  657. 'encoding-type': encoding_type},
  658. headers=headers)
  659. logger.debug("List objects V2 done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  660. return self._parse_result(resp, xml_utils.parse_list_objects_v2, ListObjectsV2Result)
  661. def put_object(self, key, data,
  662. headers=None,
  663. progress_callback=None):
  664. """上传一个普通文件。
  665. 用法 ::
  666. >>> bucket.put_object('readme.txt', 'content of readme.txt')
  667. >>> with open(u'local_file.txt', 'rb') as f:
  668. >>> bucket.put_object('remote_file.txt', f)
  669. :param key: 上传到OSS的文件名
  670. :param data: 待上传的内容。
  671. :type data: bytes,str或file-like object
  672. :param headers: 用户指定的HTTP头部。可以指定Content-Type、Content-MD5、x-oss-meta-开头的头部等
  673. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  674. :param progress_callback: 用户指定的进度回调函数。可以用来实现进度条等功能。参考 :ref:`progress_callback` 。
  675. :return: :class:`PutObjectResult <oss2.models.PutObjectResult>`
  676. """
  677. headers = utils.set_content_type(http.CaseInsensitiveDict(headers), key)
  678. if progress_callback:
  679. data = utils.make_progress_adapter(data, progress_callback)
  680. if self.enable_crc:
  681. data = utils.make_crc_adapter(data)
  682. logger.debug("Start to put object, bucket: {0}, key: {1}, headers: {2}".format(self.bucket_name, to_string(key),
  683. headers))
  684. resp = self.__do_object('PUT', key, data=data, headers=headers)
  685. logger.debug("Put object done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  686. result = PutObjectResult(resp)
  687. if self.enable_crc and result.crc is not None:
  688. utils.check_crc('put object', data.crc, result.crc, result.request_id)
  689. return result
  690. def put_object_from_file(self, key, filename,
  691. headers=None,
  692. progress_callback=None):
  693. """上传一个本地文件到OSS的普通文件。
  694. :param str key: 上传到OSS的文件名
  695. :param str filename: 本地文件名,需要有可读权限
  696. :param headers: 用户指定的HTTP头部。可以指定Content-Type、Content-MD5、x-oss-meta-开头的头部等
  697. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  698. :param progress_callback: 用户指定的进度回调函数。参考 :ref:`progress_callback`
  699. :return: :class:`PutObjectResult <oss2.models.PutObjectResult>`
  700. """
  701. headers = utils.set_content_type(http.CaseInsensitiveDict(headers), filename)
  702. logger.debug("Put object from file, bucket: {0}, key: {1}, file path: {2}".format(
  703. self.bucket_name, to_string(key), filename))
  704. with open(to_unicode(filename), 'rb') as f:
  705. return self.put_object(key, f, headers=headers, progress_callback=progress_callback)
  706. def put_object_with_url(self, sign_url, data, headers=None, progress_callback=None):
  707. """ 使用加签的url上传对象
  708. :param sign_url: 加签的url
  709. :param data: 待上传的数据
  710. :param headers: 用户指定的HTTP头部。可以指定Content-Type、Content-MD5、x-oss-meta-开头的头部等,必须和签名时保持一致
  711. :param progress_callback: 用户指定的进度回调函数。参考 :ref:`progress_callback`
  712. :return:
  713. """
  714. headers = http.CaseInsensitiveDict(headers)
  715. if progress_callback:
  716. data = utils.make_progress_adapter(data, progress_callback)
  717. if self.enable_crc:
  718. data = utils.make_crc_adapter(data)
  719. logger.debug("Start to put object with signed url, bucket: {0}, sign_url: {1}, headers: {2}".format(
  720. self.bucket_name, sign_url, headers))
  721. resp = self._do_url('PUT', sign_url, data=data, headers=headers)
  722. logger.debug("Put object with url done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  723. result = PutObjectResult(resp)
  724. if self.enable_crc and result.crc is not None:
  725. utils.check_crc('put object', data.crc, result.crc, result.request_id)
  726. return result
  727. def put_object_with_url_from_file(self, sign_url, filename,
  728. headers=None,
  729. progress_callback=None):
  730. """ 使用加签的url上传本地文件到oss
  731. :param sign_url: 加签的url
  732. :param filename: 本地文件路径
  733. :param headers: 用户指定的HTTP头部。可以指定Content-Type、Content-MD5、x-oss-meta-开头的头部等,必须和签名时保持一致
  734. :param progress_callback: 用户指定的进度回调函数。参考 :ref:`progress_callback`
  735. :return:
  736. """
  737. logger.debug("Put object from file with signed url, bucket: {0}, sign_url: {1}, file path: {2}".format(
  738. self.bucket_name, sign_url, filename))
  739. with open(to_unicode(filename), 'rb') as f:
  740. return self.put_object_with_url(sign_url, f, headers=headers, progress_callback=progress_callback)
  741. def append_object(self, key, position, data,
  742. headers=None,
  743. progress_callback=None,
  744. init_crc=None):
  745. """追加上传一个文件。
  746. :param str key: 新的文件名,或已经存在的可追加文件名
  747. :param int position: 追加上传一个新的文件, `position` 设为0;追加一个已经存在的可追加文件, `position` 设为文件的当前长度。
  748. `position` 可以从上次追加的结果 `AppendObjectResult.next_position` 中获得。
  749. :param data: 用户数据
  750. :type data: str、bytes、file-like object或可迭代对象
  751. :param headers: 用户指定的HTTP头部。可以指定Content-Type、Content-MD5、x-oss-开头的头部等
  752. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  753. :param progress_callback: 用户指定的进度回调函数。参考 :ref:`progress_callback`
  754. :return: :class:`AppendObjectResult <oss2.models.AppendObjectResult>`
  755. :raises: 如果 `position` 和当前文件长度不一致,抛出 :class:`PositionNotEqualToLength <oss2.exceptions.PositionNotEqualToLength>` ;
  756. 如果当前文件不是可追加类型,抛出 :class:`ObjectNotAppendable <oss2.exceptions.ObjectNotAppendable>` ;
  757. 还会抛出其他一些异常
  758. """
  759. headers = utils.set_content_type(http.CaseInsensitiveDict(headers), key)
  760. if progress_callback:
  761. data = utils.make_progress_adapter(data, progress_callback)
  762. if self.enable_crc and init_crc is not None:
  763. data = utils.make_crc_adapter(data, init_crc)
  764. logger.debug("Start to append object, bucket: {0}, key: {1}, headers: {2}, position: {3}".format(
  765. self.bucket_name, to_string(key), headers, position))
  766. resp = self.__do_object('POST', key,
  767. data=data,
  768. headers=headers,
  769. params={'append': '', 'position': str(position)})
  770. logger.debug("Append object done, req_id: {0}, statu_code: {1}".format(resp.request_id, resp.status))
  771. result = AppendObjectResult(resp)
  772. if self.enable_crc and result.crc is not None and init_crc is not None:
  773. utils.check_crc('append object', data.crc, result.crc, result.request_id)
  774. return result
  775. def get_object(self, key,
  776. byte_range=None,
  777. headers=None,
  778. progress_callback=None,
  779. process=None,
  780. params=None):
  781. """下载一个文件。
  782. 用法 ::
  783. >>> result = bucket.get_object('readme.txt')
  784. >>> print(result.read())
  785. 'hello world'
  786. :param key: 文件名
  787. :param byte_range: 指定下载范围。参见 :ref:`byte_range`
  788. :param headers: HTTP头部
  789. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  790. :param progress_callback: 用户指定的进度回调函数。参考 :ref:`progress_callback`
  791. :param process: oss文件处理,如图像服务等。指定后process,返回的内容为处理后的文件。
  792. :param params: http 请求的查询字符串参数
  793. :type params: dict
  794. :return: file-like object
  795. :raises: 如果文件不存在,则抛出 :class:`NoSuchKey <oss2.exceptions.NoSuchKey>` ;还可能抛出其他异常
  796. """
  797. headers = http.CaseInsensitiveDict(headers)
  798. range_string = _make_range_string(byte_range)
  799. if range_string:
  800. headers['range'] = range_string
  801. params = {} if params is None else params
  802. if process:
  803. params.update({Bucket.PROCESS: process})
  804. logger.debug("Start to get object, bucket: {0}, key: {1}, range: {2}, headers: {3}, params: {4}".format(
  805. self.bucket_name, to_string(key), range_string, headers, params))
  806. resp = self.__do_object('GET', key, headers=headers, params=params)
  807. logger.debug("Get object done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  808. return GetObjectResult(resp, progress_callback, self.enable_crc)
  809. def select_object(self, key, sql,
  810. progress_callback=None,
  811. select_params=None,
  812. byte_range=None,
  813. headers=None
  814. ):
  815. """Select一个文件内容,支持(Csv,Json Doc,Json Lines及其GZIP压缩文件).
  816. 用法 ::
  817. 对于Csv:
  818. >>> result = bucket.select_object('access.log', 'select * from ossobject where _4 > 40')
  819. >>> print(result.read())
  820. 'hello world'
  821. 对于Json Doc: { contacts:[{"firstName":"abc", "lastName":"def"},{"firstName":"abc1", "lastName":"def1"}]}
  822. >>> result = bucket.select_object('sample.json', 'select s.firstName, s.lastName from ossobject.contacts[*] s', select_params = {"Json_Type":"DOCUMENT"})
  823. 对于Json Lines: {"firstName":"abc", "lastName":"def"},{"firstName":"abc1", "lastName":"def1"}
  824. >>> result = bucket.select_object('sample.json', 'select s.firstName, s.lastName from ossobject s', select_params = {"Json_Type":"LINES"})
  825. :param key: 文件名
  826. :param sql: sql statement
  827. :param select_params: select参数集合,对于Json文件必须制定Json_Type类型。参见 :ref:`select_params`
  828. :param progress_callback: 用户指定的进度回调函数。参考 :ref:`progress_callback`
  829. :param byte_range: select content of specific range。可以设置Bytes header指定select csv时的文件起始offset和长度。
  830. :param headers: HTTP头部
  831. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  832. :return: file-like object
  833. :raises: 如果文件不存在,则抛出 :class:`NoSuchKey <oss2.exceptions.NoSuchKey>` ;还可能抛出其他异常
  834. """
  835. range_select = False
  836. headers = http.CaseInsensitiveDict(headers)
  837. range_string = _make_range_string(byte_range)
  838. if range_string:
  839. headers['range'] = range_string
  840. range_select = True
  841. if (range_select == True and
  842. (select_params is None or
  843. (SelectParameters.AllowQuotedRecordDelimiter not in select_params or str(select_params[SelectParameters.AllowQuotedRecordDelimiter]).lower() != 'false'))):
  844. raise ClientError('"AllowQuotedRecordDelimiter" must be specified in select_params as False when "Range" is specified in header.')
  845. body = xml_utils.to_select_object(sql, select_params)
  846. params = {'x-oss-process': 'csv/select'}
  847. if select_params is not None and SelectParameters.Json_Type in select_params:
  848. params['x-oss-process'] = 'json/select'
  849. self.timeout = 3600
  850. resp = self.__do_object('POST', key, data=body, headers=headers, params=params)
  851. crc_enabled = False
  852. if select_params is not None and SelectParameters.EnablePayloadCrc in select_params:
  853. if str(select_params[SelectParameters.EnablePayloadCrc]).lower() == "true":
  854. crc_enabled = True
  855. return SelectObjectResult(resp, progress_callback, crc_enabled)
  856. def get_object_to_file(self, key, filename,
  857. byte_range=None,
  858. headers=None,
  859. progress_callback=None,
  860. process=None,
  861. params=None):
  862. """下载一个文件到本地文件。
  863. :param key: 文件名
  864. :param filename: 本地文件名。要求父目录已经存在,且有写权限。
  865. :param byte_range: 指定下载范围。参见 :ref:`byte_range`
  866. :param headers: HTTP头部
  867. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  868. :param progress_callback: 用户指定的进度回调函数。参考 :ref:`progress_callback`
  869. :param process: oss文件处理,如图像服务等。指定后process,返回的内容为处理后的文件。
  870. :param params: http 请求的查询字符串参数
  871. :type params: dict
  872. :return: 如果文件不存在,则抛出 :class:`NoSuchKey <oss2.exceptions.NoSuchKey>` ;还可能抛出其他异常
  873. """
  874. logger.debug("Start to get object to file, bucket: {0}, key: {1}, file path: {2}".format(
  875. self.bucket_name, to_string(key), filename))
  876. with open(to_unicode(filename), 'wb') as f:
  877. result = self.get_object(key, byte_range=byte_range, headers=headers, progress_callback=progress_callback,
  878. process=process, params=params)
  879. if result.content_length is None:
  880. shutil.copyfileobj(result, f)
  881. else:
  882. utils.copyfileobj_and_verify(result, f, result.content_length, request_id=result.request_id)
  883. if self.enable_crc and byte_range is None:
  884. if (headers is None) or ('Accept-Encoding' not in headers) or (headers['Accept-Encoding'] != 'gzip'):
  885. utils.check_crc('get', result.client_crc, result.server_crc, result.request_id)
  886. return result
  887. def get_object_with_url(self, sign_url,
  888. byte_range=None,
  889. headers=None,
  890. progress_callback=None):
  891. """使用加签的url下载文件
  892. :param sign_url: 加签的url
  893. :param byte_range: 指定下载范围。参见 :ref:`byte_range`
  894. :param headers: HTTP头部
  895. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict,必须和签名时保持一致
  896. :param progress_callback: 用户指定的进度回调函数。参考 :ref:`progress_callback`
  897. :return: file-like object
  898. :raises: 如果文件不存在,则抛出 :class:`NoSuchKey <oss2.exceptions.NoSuchKey>` ;还可能抛出其他异常
  899. """
  900. headers = http.CaseInsensitiveDict(headers)
  901. range_string = _make_range_string(byte_range)
  902. if range_string:
  903. headers['range'] = range_string
  904. logger.debug("Start to get object with url, bucket: {0}, sign_url: {1}, range: {2}, headers: {3}".format(
  905. self.bucket_name, sign_url, range_string, headers))
  906. resp = self._do_url('GET', sign_url, headers=headers)
  907. return GetObjectResult(resp, progress_callback, self.enable_crc)
  908. def get_object_with_url_to_file(self, sign_url,
  909. filename,
  910. byte_range=None,
  911. headers=None,
  912. progress_callback=None):
  913. """使用加签的url下载文件
  914. :param sign_url: 加签的url
  915. :param filename: 本地文件名。要求父目录已经存在,且有写权限。
  916. :param byte_range: 指定下载范围。参见 :ref:`byte_range`
  917. :param headers: HTTP头部
  918. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict,,必须和签名时保持一致
  919. :param progress_callback: 用户指定的进度回调函数。参考 :ref:`progress_callback`
  920. :return: file-like object
  921. :raises: 如果文件不存在,则抛出 :class:`NoSuchKey <oss2.exceptions.NoSuchKey>` ;还可能抛出其他异常
  922. """
  923. logger.debug(
  924. "Start to get object with url, bucket: {0}, sign_url: {1}, file path: {2}, range: {3}, headers: {4}"
  925. .format(self.bucket_name, sign_url, filename, byte_range, headers))
  926. with open(to_unicode(filename), 'wb') as f:
  927. result = self.get_object_with_url(sign_url, byte_range=byte_range, headers=headers,
  928. progress_callback=progress_callback)
  929. if result.content_length is None:
  930. shutil.copyfileobj(result, f)
  931. else:
  932. utils.copyfileobj_and_verify(result, f, result.content_length, request_id=result.request_id)
  933. return result
  934. def select_object_to_file(self, key, filename, sql,
  935. progress_callback=None,
  936. select_params=None,
  937. headers=None
  938. ):
  939. """Select一个文件的内容到本地文件
  940. :param key: OSS文件名
  941. :param filename: 本地文件名。其父亲目录已经存在且有写权限。
  942. :param progress_callback: 调用进度的callback。参考 :ref:`progress_callback`
  943. :param select_params: select参数集合。参见 :ref:`select_params`
  944. :param headers: HTTP头部
  945. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  946. :return: 如果文件不存在, 抛出 :class:`NoSuchKey <oss2.exceptions.NoSuchKey>`
  947. """
  948. with open(to_unicode(filename), 'wb') as f:
  949. result = self.select_object(key, sql, progress_callback=progress_callback,
  950. select_params=select_params, headers=headers)
  951. for chunk in result:
  952. f.write(chunk)
  953. return result
  954. def head_object(self, key, headers=None, params=None):
  955. """获取文件元信息。
  956. HTTP响应的头部包含了文件元信息,可以通过 `RequestResult` 的 `headers` 成员获得。
  957. 用法 ::
  958. >>> result = bucket.head_object('readme.txt')
  959. >>> print(result.content_type)
  960. text/plain
  961. :param key: 文件名
  962. :param headers: HTTP头部
  963. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  964. :param params: HTTP请求参数,传入versionId,获取指定版本Object元信息
  965. :type params: 可以是dict,建议是oss2.CaseInsensitiveDict
  966. :return: :class:`HeadObjectResult <oss2.models.HeadObjectResult>`
  967. :raises: 如果Bucket不存在或者Object不存在,则抛出 :class:`NotFound <oss2.exceptions.NotFound>`
  968. """
  969. logger.debug("Start to head object, bucket: {0}, key: {1}, headers: {2}".format(
  970. self.bucket_name, to_string(key), headers))
  971. resp = self.__do_object('HEAD', key, headers=headers, params=params)
  972. logger.debug("Head object done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  973. return self._parse_result(resp, xml_utils.parse_dummy_result, HeadObjectResult)
  974. def create_select_object_meta(self, key, select_meta_params=None, headers=None):
  975. """获取或创建CSV,JSON LINES 文件元信息。如果元信息存在,返回之;不然则创建后返回之
  976. HTTP响应的头部包含了文件元信息,可以通过 `RequestResult` 的 `headers` 成员获得。
  977. CSV文件用法 ::
  978. >>> select_meta_params = { 'FieldDelimiter': ',',
  979. 'RecordDelimiter': '\r\n',
  980. 'QuoteCharacter': '"',
  981. 'OverwriteIfExists' : 'false'}
  982. >>> result = bucket.create_select_object_meta('csv.txt', select_meta_params)
  983. >>> print(result.rows)
  984. JSON LINES文件用法 ::
  985. >>> select_meta_params = { 'Json_Type':'LINES', 'OverwriteIfExists':'False'}
  986. >>> result = bucket.create_select_object_meta('jsonlines.json', select_meta_params)
  987. :param key: 文件名
  988. :param select_meta_params: 参数词典,可以是dict,参见ref:`csv_meta_params`
  989. :param headers: HTTP头部
  990. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  991. :return: :class:`GetSelectObjectMetaResult <oss2.models.HeadObjectResult>`.
  992. 除了 rows 和splits 属性之外, 它也返回head object返回的其他属性。
  993. rows表示该文件的总记录数。
  994. splits表示该文件的总Split个数,一个Split包含若干条记录,每个Split的总字节数大致相当。用户可以以Split为单位进行分片查询。
  995. :raises: 如果Bucket不存在或者Object不存在,则抛出:class:`NotFound <oss2.exceptions.NotFound>`
  996. """
  997. headers = http.CaseInsensitiveDict(headers)
  998. body = xml_utils.to_get_select_object_meta(select_meta_params)
  999. params = {'x-oss-process': 'csv/meta'}
  1000. if select_meta_params is not None and 'Json_Type' in select_meta_params:
  1001. params['x-oss-process'] = 'json/meta'
  1002. self.timeout = 3600
  1003. resp = self.__do_object('POST', key, data=body, headers=headers, params=params)
  1004. return GetSelectObjectMetaResult(resp)
  1005. def get_object_meta(self, key, params=None, headers=None):
  1006. """获取文件基本元信息,包括该Object的ETag、Size(文件大小)、LastModified,并不返回其内容。
  1007. HTTP响应的头部包含了文件基本元信息,可以通过 `GetObjectMetaResult` 的 `last_modified`,`content_length`,`etag` 成员获得。
  1008. :param key: 文件名
  1009. :param dict params: 请求参数
  1010. :param headers: HTTP头部
  1011. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  1012. :return: :class:`GetObjectMetaResult <oss2.models.GetObjectMetaResult>`
  1013. :raises: 如果文件不存在,则抛出 :class:`NoSuchKey <oss2.exceptions.NoSuchKey>` ;还可能抛出其他异常
  1014. """
  1015. headers = http.CaseInsensitiveDict(headers)
  1016. logger.debug("Start to get object metadata, bucket: {0}, key: {1}".format(self.bucket_name, to_string(key)))
  1017. if params is None:
  1018. params = dict()
  1019. if Bucket.OBJECTMETA not in params:
  1020. params[Bucket.OBJECTMETA] = ''
  1021. resp = self.__do_object('HEAD', key, params=params, headers=headers)
  1022. logger.debug("Get object metadata done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1023. return GetObjectMetaResult(resp)
  1024. def object_exists(self, key, headers=None):
  1025. """如果文件存在就返回True,否则返回False。如果Bucket不存在,或是发生其他错误,则抛出异常。"""
  1026. #:param key: 文件名
  1027. #:param headers: HTTP头部
  1028. #:type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  1029. # 如果我们用head_object来实现的话,由于HTTP HEAD请求没有响应体,只有响应头部,这样当发生404时,
  1030. # 我们无法区分是NoSuchBucket还是NoSuchKey错误。
  1031. #
  1032. # 2.2.0之前的实现是通过get_object的if-modified-since头部,把date设为当前时间24小时后,这样如果文件存在,则会返回
  1033. # 304 (NotModified);不存在,则会返回NoSuchKey。get_object会受回源的影响,如果配置会404回源,get_object会判断错误。
  1034. #
  1035. # 目前的实现是通过get_object_meta判断文件是否存在。
  1036. # get_object_meta 为200时,不会返回响应体,所以该接口把GET方法修改为HEAD 方式
  1037. # 同时, 对于head 请求,服务端会通过x-oss-err 返回 错误响应信息,
  1038. # 考虑到兼容之前的行为,增加exceptions.NotFound 异常 当作NoSuchKey
  1039. logger.debug("Start to check if object exists, bucket: {0}, key: {1}".format(self.bucket_name, to_string(key)))
  1040. try:
  1041. self.get_object_meta(key, headers=headers)
  1042. except exceptions.NoSuchKey:
  1043. return False
  1044. except exceptions.NoSuchBucket:
  1045. raise
  1046. except exceptions.NotFound:
  1047. return False
  1048. except:
  1049. raise
  1050. return True
  1051. def copy_object(self, source_bucket_name, source_key, target_key, headers=None, params=None):
  1052. """拷贝一个文件到当前Bucket。
  1053. :param str source_bucket_name: 源Bucket名
  1054. :param str source_key: 源文件名
  1055. :param str target_key: 目标文件名
  1056. :param dict params: 请求参数
  1057. :param headers: HTTP头部
  1058. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  1059. :return: :class:`PutObjectResult <oss2.models.PutObjectResult>`
  1060. """
  1061. headers = http.CaseInsensitiveDict(headers)
  1062. if params and Bucket.VERSIONID in params:
  1063. headers[OSS_COPY_OBJECT_SOURCE] = '/' + source_bucket_name + \
  1064. '/' + urlquote(source_key, '') + '?versionId=' + params[Bucket.VERSIONID]
  1065. else:
  1066. headers[OSS_COPY_OBJECT_SOURCE] = '/' + source_bucket_name + '/' + urlquote(source_key, '')
  1067. logger.debug(
  1068. "Start to copy object, source bucket: {0}, source key: {1}, bucket: {2}, key: {3}, headers: {4}".format(
  1069. source_bucket_name, to_string(source_key), self.bucket_name, to_string(target_key), headers))
  1070. resp = self.__do_object('PUT', target_key, headers=headers)
  1071. logger.debug("Copy object done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1072. return PutObjectResult(resp)
  1073. def update_object_meta(self, key, headers):
  1074. """更改Object的元数据信息,包括Content-Type这类标准的HTTP头部,以及以x-oss-meta-开头的自定义元数据。
  1075. 用户可以通过 :func:`head_object` 获得元数据信息。
  1076. :param str key: 文件名
  1077. :param headers: HTTP头部,包含了元数据信息
  1078. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  1079. :return: :class:`RequestResult <oss2.models.RequestResults>`
  1080. """
  1081. if headers is not None:
  1082. headers[OSS_METADATA_DIRECTIVE] = 'REPLACE'
  1083. logger.debug("Start to update object metadata, bucket: {0}, key: {1}".format(self.bucket_name, to_string(key)))
  1084. return self.copy_object(self.bucket_name, key, key, headers=headers)
  1085. def delete_object(self, key, params=None, headers=None):
  1086. """删除一个文件。
  1087. :param str key: 文件名
  1088. :param params: 请求参数
  1089. :param headers: HTTP头部
  1090. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  1091. :return: :class:`RequestResult <oss2.models.RequestResult>`
  1092. """
  1093. headers = http.CaseInsensitiveDict(headers)
  1094. logger.info("Start to delete object, bucket: {0}, key: {1}".format(self.bucket_name, to_string(key)))
  1095. resp = self.__do_object('DELETE', key, params=params, headers=headers)
  1096. logger.debug("Delete object done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1097. return RequestResult(resp)
  1098. def restore_object(self, key, params=None, headers=None, input=None):
  1099. """restore an object
  1100. 如果是第一次针对该object调用接口,返回RequestResult.status = 202;
  1101. 如果已经成功调用过restore接口,且服务端仍处于解冻中,抛异常RestoreAlreadyInProgress(status=409)
  1102. 如果已经成功调用过restore接口,且服务端解冻已经完成,再次调用时返回RequestResult.status = 200,且会将object的可下载时间延长一天,最多延长7天。
  1103. 如果object不存在,则抛异常NoSuchKey(status=404);
  1104. 对非Archive类型的Object提交restore,则抛异常OperationNotSupported(status=400)
  1105. 也可以通过调用head_object接口来获取meta信息来判断是否可以restore与restore的状态
  1106. 代码示例::
  1107. >>> meta = bucket.head_object(key)
  1108. >>> if meta.resp.headers['x-oss-storage-class'] == oss2.BUCKET_STORAGE_CLASS_ARCHIVE:
  1109. >>> bucket.restore_object(key)
  1110. >>> while True:
  1111. >>> meta = bucket.head_object(key)
  1112. >>> if meta.resp.headers['x-oss-restore'] == 'ongoing-request="true"':
  1113. >>> time.sleep(5)
  1114. >>> else:
  1115. >>> break
  1116. :param str key: object name
  1117. :param params: 请求参数
  1118. :param headers: HTTP头部
  1119. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  1120. :param input: 解冻配置。
  1121. :type input: class:`RestoreConfiguration <oss2.models.RestoreConfiguration>`
  1122. :return: :class:`RequestResult <oss2.models.RequestResult>`
  1123. """
  1124. headers = http.CaseInsensitiveDict(headers)
  1125. logger.debug("Start to restore object, bucket: {0}, key: {1}".format(self.bucket_name, to_string(key)))
  1126. if params is None:
  1127. params = dict()
  1128. if Bucket.RESTORE not in params:
  1129. params[Bucket.RESTORE] = ''
  1130. data = self.__convert_data(RestoreConfiguration, xml_utils.to_put_restore_config, input)
  1131. resp = self.__do_object('POST', key, params=params, headers=headers, data=data)
  1132. logger.debug("Restore object done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1133. return RequestResult(resp)
  1134. def put_object_acl(self, key, permission, params=None, headers=None):
  1135. """设置文件的ACL。
  1136. :param str key: 文件名
  1137. :param str permission: 可以是oss2.OBJECT_ACL_DEFAULT、oss2.OBJECT_ACL_PRIVATE、oss2.OBJECT_ACL_PUBLIC_READ或
  1138. oss2.OBJECT_ACL_PUBLIC_READ_WRITE。
  1139. :param dict params: 请求参数
  1140. :param headers: HTTP头部
  1141. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  1142. :return: :class:`RequestResult <oss2.models.RequestResult>`
  1143. """
  1144. logger.debug("Start to put object acl, bucket: {0}, key: {1}, acl: {2}".format(
  1145. self.bucket_name, to_string(key), permission))
  1146. headers = http.CaseInsensitiveDict(headers)
  1147. headers[OSS_OBJECT_ACL] = permission
  1148. if params is None:
  1149. params = dict()
  1150. if Bucket.ACL not in params:
  1151. params[Bucket.ACL] = ''
  1152. resp = self.__do_object('PUT', key, params=params, headers=headers)
  1153. logger.debug("Put object acl done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1154. return RequestResult(resp)
  1155. def get_object_acl(self, key, params=None, headers=None):
  1156. """获取文件的ACL。
  1157. :param key: 文件名
  1158. :param params: 请求参数
  1159. :param headers: HTTP头部
  1160. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  1161. :return: :class:`GetObjectAclResult <oss2.models.GetObjectAclResult>`
  1162. """
  1163. logger.debug("Start to get object acl, bucket: {0}, key: {1}".format(self.bucket_name, to_string(key)))
  1164. headers = http.CaseInsensitiveDict(headers)
  1165. if params is None:
  1166. params = dict()
  1167. if Bucket.ACL not in params:
  1168. params[Bucket.ACL] = ''
  1169. resp = self.__do_object('GET', key, params=params, headers=headers)
  1170. logger.debug("Get object acl done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1171. return self._parse_result(resp, xml_utils.parse_get_object_acl, GetObjectAclResult)
  1172. def batch_delete_objects(self, key_list, headers=None):
  1173. """批量删除文件。待删除文件列表不能为空。
  1174. :param key_list: 文件名列表,不能为空。
  1175. :type key_list: list of str
  1176. :param headers: HTTP头部
  1177. :return: :class:`BatchDeleteObjectsResult <oss2.models.BatchDeleteObjectsResult>`
  1178. """
  1179. if not key_list:
  1180. raise ClientError('key_list should not be empty')
  1181. logger.debug("Start to delete objects, bucket: {0}, keys: {1}".format(self.bucket_name, key_list))
  1182. data = xml_utils.to_batch_delete_objects_request(key_list, False)
  1183. headers = http.CaseInsensitiveDict(headers)
  1184. headers['Content-MD5'] = utils.content_md5(data)
  1185. resp = self.__do_bucket('POST',
  1186. data=data,
  1187. params={'delete': '', 'encoding-type': 'url'},
  1188. headers=headers)
  1189. logger.debug("Delete objects done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1190. return self._parse_result(resp, xml_utils.parse_batch_delete_objects, BatchDeleteObjectsResult)
  1191. def delete_object_versions(self, keylist_versions, headers=None):
  1192. """批量删除带版本文件。待删除文件列表不能为空。
  1193. :param key_list_with_version: 带版本的文件名列表,不能为空。(如果传入,则不能为空)
  1194. :type key_list: list of BatchDeleteObjectsList
  1195. :param headers: HTTP头部
  1196. :return: :class:`BatchDeleteObjectsResult <oss2.models.BatchDeleteObjectsResult>`
  1197. """
  1198. if not keylist_versions:
  1199. raise ClientError('keylist_versions should not be empty')
  1200. logger.debug("Start to delete object versions, bucket: {0}".format(self.bucket_name))
  1201. data = xml_utils.to_batch_delete_objects_version_request(keylist_versions, False)
  1202. headers = http.CaseInsensitiveDict(headers)
  1203. headers['Content-MD5'] = utils.content_md5(data)
  1204. resp = self.__do_bucket('POST',
  1205. data=data,
  1206. params={'delete': '', 'encoding-type': 'url'},
  1207. headers=headers)
  1208. logger.debug("Delete object versions done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1209. return self._parse_result(resp, xml_utils.parse_batch_delete_objects, BatchDeleteObjectsResult)
  1210. def init_multipart_upload(self, key, headers=None, params=None):
  1211. """初始化分片上传。
  1212. 返回值中的 `upload_id` 以及Bucket名和Object名三元组唯一对应了此次分片上传事件。
  1213. :param str key: 待上传的文件名
  1214. :param headers: HTTP头部
  1215. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  1216. :return: :class:`InitMultipartUploadResult <oss2.models.InitMultipartUploadResult>`
  1217. """
  1218. headers = utils.set_content_type(http.CaseInsensitiveDict(headers), key)
  1219. if params is None:
  1220. tmp_params = dict()
  1221. else:
  1222. tmp_params = params.copy()
  1223. tmp_params['uploads'] = ''
  1224. logger.debug("Start to init multipart upload, bucket: {0}, keys: {1}, headers: {2}, params: {3}".format(
  1225. self.bucket_name, to_string(key), headers, tmp_params))
  1226. resp = self.__do_object('POST', key, params=tmp_params, headers=headers)
  1227. logger.debug("Init multipart upload done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1228. return self._parse_result(resp, xml_utils.parse_init_multipart_upload, InitMultipartUploadResult)
  1229. def upload_part(self, key, upload_id, part_number, data, progress_callback=None, headers=None):
  1230. """上传一个分片。
  1231. :param str key: 待上传文件名,这个文件名要和 :func:`init_multipart_upload` 的文件名一致。
  1232. :param str upload_id: 分片上传ID
  1233. :param int part_number: 分片号,最小值是1.
  1234. :param data: 待上传数据。
  1235. :param progress_callback: 用户指定进度回调函数。可以用来实现进度条等功能。参考 :ref:`progress_callback` 。
  1236. :param headers: 用户指定的HTTP头部。可以指定Content-MD5头部等
  1237. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  1238. :return: :class:`PutObjectResult <oss2.models.PutObjectResult>`
  1239. """
  1240. headers = http.CaseInsensitiveDict(headers)
  1241. if progress_callback:
  1242. data = utils.make_progress_adapter(data, progress_callback)
  1243. if self.enable_crc:
  1244. data = utils.make_crc_adapter(data)
  1245. logger.debug(
  1246. "Start to upload multipart, bucket: {0}, key: {1}, upload_id: {2}, part_number: {3}, headers: {4}".format(
  1247. self.bucket_name, to_string(key), upload_id, part_number, headers))
  1248. resp = self.__do_object('PUT', key,
  1249. params={'uploadId': upload_id, 'partNumber': str(part_number)},
  1250. headers=headers,
  1251. data=data)
  1252. logger.debug("Upload multipart done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1253. result = PutObjectResult(resp)
  1254. if self.enable_crc and result.crc is not None:
  1255. utils.check_crc('upload part', data.crc, result.crc, result.request_id)
  1256. return result
  1257. def complete_multipart_upload(self, key, upload_id, parts, headers=None):
  1258. """完成分片上传,创建文件。
  1259. :param str key: 待上传的文件名,这个文件名要和 :func:`init_multipart_upload` 的文件名一致。
  1260. :param str upload_id: 分片上传ID
  1261. :param parts: PartInfo列表。PartInfo中的part_number和etag是必填项。其中的etag可以从 :func:`upload_part` 的返回值中得到。
  1262. :type parts: list of `PartInfo <oss2.models.PartInfo>`
  1263. :param headers: HTTP头部
  1264. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  1265. :return: :class:`PutObjectResult <oss2.models.PutObjectResult>`
  1266. """
  1267. headers = http.CaseInsensitiveDict(headers)
  1268. data = None
  1269. if parts is not None:
  1270. parts = sorted(parts, key=lambda p: p.part_number)
  1271. data = xml_utils.to_complete_upload_request(parts)
  1272. logger.debug("Start to complete multipart upload, bucket: {0}, key: {1}, upload_id: {2}, parts: {3}".format(
  1273. self.bucket_name, to_string(key), upload_id, data))
  1274. resp = self.__do_object('POST', key,
  1275. params={'uploadId': upload_id},
  1276. data=data,
  1277. headers=headers)
  1278. logger.debug(
  1279. "Complete multipart upload done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1280. result = PutObjectResult(resp)
  1281. if self.enable_crc and parts is not None:
  1282. object_crc = utils.calc_obj_crc_from_parts(parts)
  1283. utils.check_crc('multipart upload', object_crc, result.crc, result.request_id)
  1284. return result
  1285. def abort_multipart_upload(self, key, upload_id, headers=None):
  1286. """取消分片上传。
  1287. :param str key: 待上传的文件名,这个文件名要和 :func:`init_multipart_upload` 的文件名一致。
  1288. :param str upload_id: 分片上传ID
  1289. :param headers: HTTP头部
  1290. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  1291. :return: :class:`RequestResult <oss2.models.RequestResult>`
  1292. """
  1293. logger.debug("Start to abort multipart upload, bucket: {0}, key: {1}, upload_id: {2}".format(
  1294. self.bucket_name, to_string(key), upload_id))
  1295. headers = http.CaseInsensitiveDict(headers)
  1296. resp = self.__do_object('DELETE', key,
  1297. params={'uploadId': upload_id}, headers=headers)
  1298. logger.debug("Abort multipart done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1299. return RequestResult(resp)
  1300. def list_multipart_uploads(self,
  1301. prefix='',
  1302. delimiter='',
  1303. key_marker='',
  1304. upload_id_marker='',
  1305. max_uploads=1000,
  1306. headers=None):
  1307. """罗列正在进行中的分片上传。支持分页。
  1308. :param str prefix: 只罗列匹配该前缀的文件的分片上传
  1309. :param str delimiter: 目录分割符
  1310. :param str key_marker: 文件名分页符。第一次调用可以不传,后续设为返回值中的 `next_key_marker`
  1311. :param str upload_id_marker: 分片ID分页符。第一次调用可以不传,后续设为返回值中的 `next_upload_id_marker`
  1312. :param int max_uploads: 一次罗列最多能够返回的条目数
  1313. :param headers: HTTP头部
  1314. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  1315. :return: :class:`ListMultipartUploadsResult <oss2.models.ListMultipartUploadsResult>`
  1316. """
  1317. logger.debug("Start to list multipart uploads, bucket: {0}, prefix: {1}, delimiter: {2}, key_marker: {3}, "
  1318. "upload_id_marker: {4}, max_uploads: {5}".format(self.bucket_name, to_string(prefix), delimiter,
  1319. to_string(key_marker), upload_id_marker,
  1320. max_uploads))
  1321. headers = http.CaseInsensitiveDict(headers)
  1322. resp = self.__do_bucket('GET',
  1323. params={'uploads': '',
  1324. 'prefix': prefix,
  1325. 'delimiter': delimiter,
  1326. 'key-marker': key_marker,
  1327. 'upload-id-marker': upload_id_marker,
  1328. 'max-uploads': str(max_uploads),
  1329. 'encoding-type': 'url'},
  1330. headers=headers)
  1331. logger.debug("List multipart uploads done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1332. return self._parse_result(resp, xml_utils.parse_list_multipart_uploads, ListMultipartUploadsResult)
  1333. def upload_part_copy(self, source_bucket_name, source_key, byte_range,
  1334. target_key, target_upload_id, target_part_number,
  1335. headers=None, params=None):
  1336. """分片拷贝。把一个已有文件的一部分或整体拷贝成目标文件的一个分片。
  1337. :source_bucket_name: 源文件所在bucket的名称
  1338. :source_key:源文件名称
  1339. :param byte_range: 指定待拷贝内容在源文件里的范围。参见 :ref:`byte_range`
  1340. :target_key: 目的文件的名称
  1341. :target_upload_id: 目的文件的uploadid
  1342. :target_part_number: 目的文件的分片号
  1343. :param params: 请求参数
  1344. :param headers: HTTP头部
  1345. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  1346. :return: :class:`PutObjectResult <oss2.models.PutObjectResult>`
  1347. """
  1348. headers = http.CaseInsensitiveDict(headers)
  1349. if params and Bucket.VERSIONID in params:
  1350. headers[OSS_COPY_OBJECT_SOURCE] = '/' + source_bucket_name + \
  1351. '/' + urlquote(source_key, '') + '?versionId=' + params[Bucket.VERSIONID]
  1352. else:
  1353. headers[OSS_COPY_OBJECT_SOURCE] = '/' + source_bucket_name + '/' + urlquote(source_key, '')
  1354. range_string = _make_range_string(byte_range)
  1355. if range_string:
  1356. headers[OSS_COPY_OBJECT_SOURCE_RANGE] = range_string
  1357. logger.debug("Start to upload part copy, source bucket: {0}, source key: {1}, bucket: {2}, key: {3}, range"
  1358. ": {4}, upload id: {5}, part_number: {6}, headers: {7}".format(source_bucket_name,
  1359. to_string(source_key),self.bucket_name,to_string(target_key),
  1360. byte_range, target_upload_id,target_part_number, headers))
  1361. if params is None:
  1362. params = dict()
  1363. params['uploadId'] = target_upload_id
  1364. params['partNumber'] = str(target_part_number)
  1365. resp = self.__do_object('PUT', target_key,
  1366. params=params,headers=headers)
  1367. logger.debug("Upload part copy done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1368. return PutObjectResult(resp)
  1369. def list_parts(self, key, upload_id,
  1370. marker='', max_parts=1000, headers=None):
  1371. """列举已经上传的分片。支持分页。
  1372. :param headers: HTTP头部
  1373. :param str key: 文件名
  1374. :param str upload_id: 分片上传ID
  1375. :param str marker: 分页符
  1376. :param int max_parts: 一次最多罗列多少分片
  1377. :param headers: HTTP头部
  1378. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  1379. :return: :class:`ListPartsResult <oss2.models.ListPartsResult>`
  1380. """
  1381. logger.debug("Start to list parts, bucket: {0}, key: {1}, upload_id: {2}, marker: {3}, max_parts: {4}".format(
  1382. self.bucket_name, to_string(key), upload_id, marker, max_parts))
  1383. headers = http.CaseInsensitiveDict(headers)
  1384. resp = self.__do_object('GET', key,
  1385. params={'uploadId': upload_id,
  1386. 'part-number-marker': marker,
  1387. 'max-parts': str(max_parts)},
  1388. headers=headers)
  1389. logger.debug("List parts done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1390. return self._parse_result(resp, xml_utils.parse_list_parts, ListPartsResult)
  1391. def put_symlink(self, target_key, symlink_key, headers=None):
  1392. """创建Symlink。
  1393. :param str target_key: 目标文件,目标文件不能为符号连接
  1394. :param str symlink_key: 符号连接类文件,其实质是一个特殊的文件,数据指向目标文件
  1395. :param headers: HTTP头部
  1396. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  1397. :return: :class:`RequestResult <oss2.models.RequestResult>`
  1398. """
  1399. headers = http.CaseInsensitiveDict(headers)
  1400. headers[OSS_SYMLINK_TARGET] = urlquote(target_key, '')
  1401. logger.debug("Start to put symlink, bucket: {0}, target_key: {1}, symlink_key: {2}, headers: {3}".format(
  1402. self.bucket_name, to_string(target_key), to_string(symlink_key), headers))
  1403. resp = self.__do_object('PUT', symlink_key, headers=headers, params={Bucket.SYMLINK: ''})
  1404. logger.debug("Put symlink done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1405. return RequestResult(resp)
  1406. def get_symlink(self, symlink_key, params=None, headers=None):
  1407. """获取符号连接文件的目标文件。
  1408. :param str symlink_key: 符号连接类文件
  1409. :param dict params: 请求参数
  1410. :param headers: HTTP头部
  1411. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  1412. :return: :class:`GetSymlinkResult <oss2.models.GetSymlinkResult>`
  1413. :raises: 如果文件的符号链接不存在,则抛出 :class:`NoSuchKey <oss2.exceptions.NoSuchKey>` ;还可能抛出其他异常
  1414. """
  1415. logger.debug(
  1416. "Start to get symlink, bucket: {0}, symlink_key: {1}".format(self.bucket_name, to_string(symlink_key)))
  1417. headers = http.CaseInsensitiveDict(headers)
  1418. if params is None:
  1419. params = dict()
  1420. if Bucket.SYMLINK not in params:
  1421. params[Bucket.SYMLINK] = ''
  1422. resp = self.__do_object('GET', symlink_key, params=params, headers=headers)
  1423. logger.debug("Get symlink done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1424. return GetSymlinkResult(resp)
  1425. def create_bucket(self, permission=None, input=None, headers=None):
  1426. """创建新的Bucket。
  1427. :param str permission: 指定Bucket的ACL。可以是oss2.BUCKET_ACL_PRIVATE(推荐、缺省)、oss2.BUCKET_ACL_PUBLIC_READ或是
  1428. oss2.BUCKET_ACL_PUBLIC_READ_WRITE。
  1429. :param input: :class:`BucketCreateConfig <oss2.models.BucketCreateConfig>` object
  1430. """
  1431. headers = http.CaseInsensitiveDict(headers)
  1432. if permission:
  1433. headers[OSS_CANNED_ACL] = permission
  1434. data = self.__convert_data(BucketCreateConfig, xml_utils.to_put_bucket_config, input)
  1435. logger.debug("Start to create bucket, bucket: {0}, permission: {1}, config: {2}".format(self.bucket_name,
  1436. permission, data))
  1437. resp = self.__do_bucket('PUT', headers=headers, data=data)
  1438. logger.debug("Create bucket done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1439. return RequestResult(resp)
  1440. def delete_bucket(self):
  1441. """删除一个Bucket。只有没有任何文件,也没有任何未完成的分片上传的Bucket才能被删除。
  1442. :return: :class:`RequestResult <oss2.models.RequestResult>`
  1443. ":raises: 如果试图删除一个非空Bucket,则抛出 :class:`BucketNotEmpty <oss2.exceptions.BucketNotEmpty>`
  1444. """
  1445. logger.info("Start to delete bucket, bucket: {0}".format(self.bucket_name))
  1446. resp = self.__do_bucket('DELETE')
  1447. logger.debug("Delete bucket done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1448. return RequestResult(resp)
  1449. def put_bucket_acl(self, permission):
  1450. """设置Bucket的ACL。
  1451. :param str permission: 新的ACL,可以是oss2.BUCKET_ACL_PRIVATE、oss2.BUCKET_ACL_PUBLIC_READ或
  1452. oss2.BUCKET_ACL_PUBLIC_READ_WRITE
  1453. """
  1454. logger.debug("Start to put bucket acl, bucket: {0}, acl: {1}".format(self.bucket_name, permission))
  1455. resp = self.__do_bucket('PUT', headers={OSS_CANNED_ACL: permission}, params={Bucket.ACL: ''})
  1456. logger.debug("Put bucket acl done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1457. return RequestResult(resp)
  1458. def get_bucket_acl(self):
  1459. """获取Bucket的ACL。
  1460. :return: :class:`GetBucketAclResult <oss2.models.GetBucketAclResult>`
  1461. """
  1462. logger.debug("Start to get bucket acl, bucket: {0}".format(self.bucket_name))
  1463. resp = self.__do_bucket('GET', params={Bucket.ACL: ''})
  1464. logger.debug("Get bucket acl done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1465. return self._parse_result(resp, xml_utils.parse_get_bucket_acl, GetBucketAclResult)
  1466. def put_bucket_cors(self, input):
  1467. """设置Bucket的CORS。
  1468. :param input: :class:`BucketCors <oss2.models.BucketCors>` 对象或其他
  1469. """
  1470. data = self.__convert_data(BucketCors, xml_utils.to_put_bucket_cors, input)
  1471. logger.debug("Start to put bucket cors, bucket: {0}, cors: {1}".format(self.bucket_name, data))
  1472. resp = self.__do_bucket('PUT', data=data, params={Bucket.CORS: ''})
  1473. logger.debug("Put bucket cors done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1474. return RequestResult(resp)
  1475. def get_bucket_cors(self):
  1476. """获取Bucket的CORS配置。
  1477. :return: :class:`GetBucketCorsResult <oss2.models.GetBucketCorsResult>`
  1478. """
  1479. logger.debug("Start to get bucket CORS, bucket: {0}".format(self.bucket_name))
  1480. resp = self.__do_bucket('GET', params={Bucket.CORS: ''})
  1481. logger.debug("Get bucket CORS done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1482. return self._parse_result(resp, xml_utils.parse_get_bucket_cors, GetBucketCorsResult)
  1483. def delete_bucket_cors(self):
  1484. """删除Bucket的CORS配置。"""
  1485. logger.debug("Start to delete bucket CORS, bucket: {0}".format(self.bucket_name))
  1486. resp = self.__do_bucket('DELETE', params={Bucket.CORS: ''})
  1487. logger.debug("Delete bucket CORS done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1488. return RequestResult(resp)
  1489. def put_bucket_lifecycle(self, input, headers=None):
  1490. """设置生命周期管理的配置。
  1491. :param input: :class:`BucketLifecycle <oss2.models.BucketLifecycle>` 对象或其他
  1492. """
  1493. headers = http.CaseInsensitiveDict(headers)
  1494. data = self.__convert_data(BucketLifecycle, xml_utils.to_put_bucket_lifecycle, input)
  1495. logger.debug("Start to put bucket lifecycle, bucket: {0}, lifecycle: {1}".format(self.bucket_name, data))
  1496. resp = self.__do_bucket('PUT', data=data, params={Bucket.LIFECYCLE: ''}, headers=headers)
  1497. logger.debug("Put bucket lifecycle done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1498. return RequestResult(resp)
  1499. def get_bucket_lifecycle(self):
  1500. """获取生命周期管理配置。
  1501. :return: :class:`GetBucketLifecycleResult <oss2.models.GetBucketLifecycleResult>`
  1502. :raises: 如果没有设置Lifecycle,则抛出 :class:`NoSuchLifecycle <oss2.exceptions.NoSuchLifecycle>`
  1503. """
  1504. logger.debug("Start to get bucket lifecycle, bucket: {0}".format(self.bucket_name))
  1505. resp = self.__do_bucket('GET', params={Bucket.LIFECYCLE: ''})
  1506. logger.debug("Get bucket lifecycle done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1507. return self._parse_result(resp, xml_utils.parse_get_bucket_lifecycle, GetBucketLifecycleResult)
  1508. def delete_bucket_lifecycle(self):
  1509. """删除生命周期管理配置。如果Lifecycle没有设置,也返回成功。"""
  1510. logger.debug("Start to delete bucket lifecycle, bucket: {0}".format(self.bucket_name))
  1511. resp = self.__do_bucket('DELETE', params={Bucket.LIFECYCLE: ''})
  1512. logger.debug("Delete bucket lifecycle done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1513. return RequestResult(resp)
  1514. def get_bucket_location(self):
  1515. """获取Bucket的数据中心。
  1516. :return: :class:`GetBucketLocationResult <oss2.models.GetBucketLocationResult>`
  1517. """
  1518. logger.debug("Start to get bucket location, bucket: {0}".format(self.bucket_name))
  1519. resp = self.__do_bucket('GET', params={Bucket.LOCATION: ''})
  1520. logger.debug("Get bucket location done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1521. return self._parse_result(resp, xml_utils.parse_get_bucket_location, GetBucketLocationResult)
  1522. def put_bucket_logging(self, input):
  1523. """设置Bucket的访问日志功能。
  1524. :param input: :class:`BucketLogging <oss2.models.BucketLogging>` 对象或其他
  1525. """
  1526. data = self.__convert_data(BucketLogging, xml_utils.to_put_bucket_logging, input)
  1527. logger.debug("Start to put bucket logging, bucket: {0}, logging: {1}".format(self.bucket_name, data))
  1528. resp = self.__do_bucket('PUT', data=data, params={Bucket.LOGGING: ''})
  1529. logger.debug("Put bucket logging done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1530. return RequestResult(resp)
  1531. def get_bucket_logging(self):
  1532. """获取Bucket的访问日志功能配置。
  1533. :return: :class:`GetBucketLoggingResult <oss2.models.GetBucketLoggingResult>`
  1534. """
  1535. logger.debug("Start to get bucket logging, bucket: {0}".format(self.bucket_name))
  1536. resp = self.__do_bucket('GET', params={Bucket.LOGGING: ''})
  1537. logger.debug("Get bucket logging done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1538. return self._parse_result(resp, xml_utils.parse_get_bucket_logging, GetBucketLoggingResult)
  1539. def delete_bucket_logging(self):
  1540. """关闭Bucket的访问日志功能。"""
  1541. logger.debug("Start to delete bucket loggging, bucket: {0}".format(self.bucket_name))
  1542. resp = self.__do_bucket('DELETE', params={Bucket.LOGGING: ''})
  1543. logger.debug("Put bucket lifecycle done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1544. return RequestResult(resp)
  1545. def put_bucket_referer(self, input):
  1546. """为Bucket设置防盗链。
  1547. :param input: :class:`BucketReferer <oss2.models.BucketReferer>` 对象或其他
  1548. """
  1549. data = self.__convert_data(BucketReferer, xml_utils.to_put_bucket_referer, input)
  1550. logger.debug("Start to put bucket referer, bucket: {0}, referer: {1}".format(self.bucket_name, to_string(data)))
  1551. resp = self.__do_bucket('PUT', data=data, params={Bucket.REFERER: ''})
  1552. logger.debug("Put bucket referer done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1553. return RequestResult(resp)
  1554. def get_bucket_referer(self):
  1555. """获取Bucket的防盗链配置。
  1556. :return: :class:`GetBucketRefererResult <oss2.models.GetBucketRefererResult>`
  1557. """
  1558. logger.debug("Start to get bucket referer, bucket: {0}".format(self.bucket_name))
  1559. resp = self.__do_bucket('GET', params={Bucket.REFERER: ''})
  1560. logger.debug("Get bucket referer done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1561. return self._parse_result(resp, xml_utils.parse_get_bucket_referer, GetBucketRefererResult)
  1562. def get_bucket_stat(self):
  1563. """查看Bucket的状态,目前包括bucket大小,bucket的object数量,bucket正在上传的Multipart Upload事件个数等。
  1564. :return: :class:`GetBucketStatResult <oss2.models.GetBucketStatResult>`
  1565. """
  1566. logger.debug("Start to get bucket stat, bucket: {0}".format(self.bucket_name))
  1567. resp = self.__do_bucket('GET', params={Bucket.STAT: ''})
  1568. logger.debug("Get bucket stat done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1569. return self._parse_result(resp, xml_utils.parse_get_bucket_stat, GetBucketStatResult)
  1570. def get_bucket_info(self):
  1571. """获取bucket相关信息,如创建时间,访问Endpoint,Owner与ACL等。
  1572. :return: :class:`GetBucketInfoResult <oss2.models.GetBucketInfoResult>`
  1573. """
  1574. logger.debug("Start to get bucket info, bucket: {0}".format(self.bucket_name))
  1575. resp = self.__do_bucket('GET', params={Bucket.BUCKET_INFO: ''})
  1576. logger.debug("Get bucket info done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1577. return self._parse_result(resp, xml_utils.parse_get_bucket_info, GetBucketInfoResult)
  1578. def put_bucket_website(self, input):
  1579. """为Bucket配置静态网站托管功能。
  1580. :param input: :class:`BucketWebsite <oss2.models.BucketWebsite>`
  1581. """
  1582. data = self.__convert_data(BucketWebsite, xml_utils.to_put_bucket_website, input)
  1583. headers = http.CaseInsensitiveDict()
  1584. headers['Content-MD5'] = utils.content_md5(data)
  1585. logger.debug("Start to put bucket website, bucket: {0}, website: {1}".format(self.bucket_name, to_string(data)))
  1586. resp = self.__do_bucket('PUT', data=data, params={Bucket.WEBSITE: ''}, headers=headers)
  1587. logger.debug("Put bucket website done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1588. return RequestResult(resp)
  1589. def get_bucket_website(self):
  1590. """获取Bucket的静态网站托管配置。
  1591. :return: :class:`GetBucketWebsiteResult <oss2.models.GetBucketWebsiteResult>`
  1592. :raises: 如果没有设置静态网站托管,那么就抛出 :class:`NoSuchWebsite <oss2.exceptions.NoSuchWebsite>`
  1593. """
  1594. logger.debug("Start to get bucket website, bucket: {0}".format(self.bucket_name))
  1595. resp = self.__do_bucket('GET', params={Bucket.WEBSITE: ''})
  1596. logger.debug("Get bucket website done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1597. return self._parse_result(resp, xml_utils.parse_get_bucket_website, GetBucketWebsiteResult)
  1598. def delete_bucket_website(self):
  1599. """关闭Bucket的静态网站托管功能。"""
  1600. logger.debug("Start to delete bucket website, bucket: {0}".format(self.bucket_name))
  1601. resp = self.__do_bucket('DELETE', params={Bucket.WEBSITE: ''})
  1602. logger.debug("Delete bucket website done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1603. return RequestResult(resp)
  1604. def create_live_channel(self, channel_name, input):
  1605. """创建推流直播频道
  1606. :param str channel_name: 要创建的live channel的名称
  1607. :param input: LiveChannelInfo类型,包含了live channel中的描述信息
  1608. :return: :class:`CreateLiveChannelResult <oss2.models.CreateLiveChannelResult>`
  1609. """
  1610. data = self.__convert_data(LiveChannelInfo, xml_utils.to_create_live_channel, input)
  1611. logger.debug("Start to create live-channel, bucket: {0}, channel_name: {1}, info: {2}".format(
  1612. self.bucket_name, to_string(channel_name), to_string(data)))
  1613. resp = self.__do_object('PUT', channel_name, data=data, params={Bucket.LIVE: ''})
  1614. logger.debug("Create live-channel done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1615. return self._parse_result(resp, xml_utils.parse_create_live_channel, CreateLiveChannelResult)
  1616. def delete_live_channel(self, channel_name):
  1617. """删除推流直播频道
  1618. :param str channel_name: 要删除的live channel的名称
  1619. """
  1620. logger.debug("Start to delete live-channel, bucket: {0}, live_channel: {1}".format(
  1621. self.bucket_name, to_string(channel_name)))
  1622. resp = self.__do_object('DELETE', channel_name, params={Bucket.LIVE: ''})
  1623. logger.debug("Delete live-channel done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1624. return RequestResult(resp)
  1625. def get_live_channel(self, channel_name):
  1626. """获取直播频道配置
  1627. :param str channel_name: 要获取的live channel的名称
  1628. :return: :class:`GetLiveChannelResult <oss2.models.GetLiveChannelResult>`
  1629. """
  1630. logger.debug("Start to get live-channel info: bucket: {0}, live_channel: {1}".format(
  1631. self.bucket_name, to_string(channel_name)))
  1632. resp = self.__do_object('GET', channel_name, params={Bucket.LIVE: ''})
  1633. logger.debug("Get live-channel done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1634. return self._parse_result(resp, xml_utils.parse_get_live_channel, GetLiveChannelResult)
  1635. def list_live_channel(self, prefix='', marker='', max_keys=100):
  1636. """列举出Bucket下所有符合条件的live channel
  1637. param: str prefix: list时channel_id的公共前缀
  1638. param: str marker: list时指定的起始标记
  1639. param: int max_keys: 本次list返回live channel的最大个数
  1640. return: :class:`ListLiveChannelResult <oss2.models.ListLiveChannelResult>`
  1641. """
  1642. logger.debug("Start to list live-channels, bucket: {0}, prefix: {1}, marker: {2}, max_keys: {3}".format(
  1643. self.bucket_name, to_string(prefix), to_string(marker), max_keys))
  1644. resp = self.__do_bucket('GET', params={Bucket.LIVE: '',
  1645. 'prefix': prefix,
  1646. 'marker': marker,
  1647. 'max-keys': str(max_keys)})
  1648. logger.debug("List live-channel done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1649. return self._parse_result(resp, xml_utils.parse_list_live_channel, ListLiveChannelResult)
  1650. def get_live_channel_stat(self, channel_name):
  1651. """获取live channel当前推流的状态
  1652. param str channel_name: 要获取推流状态的live channel的名称
  1653. return: :class:`GetLiveChannelStatResult <oss2.models.GetLiveChannelStatResult>`
  1654. """
  1655. logger.debug("Start to get live-channel stat, bucket: {0}, channel_name: {1}".format(
  1656. self.bucket_name, to_string(channel_name)))
  1657. resp = self.__do_object('GET', channel_name, params={Bucket.LIVE: '', Bucket.COMP: 'stat'})
  1658. logger.debug("Get live-channel stat done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1659. return self._parse_result(resp, xml_utils.parse_live_channel_stat, GetLiveChannelStatResult)
  1660. def put_live_channel_status(self, channel_name, status):
  1661. """更改live channel的status,仅能在“enabled”和“disabled”两种状态中更改
  1662. param str channel_name: 要更改status的live channel的名称
  1663. param str status: live channel的目标status
  1664. """
  1665. logger.debug("Start to put live-channel status, bucket: {0}, channel_name: {1}, status: {2}".format(
  1666. self.bucket_name, to_string(channel_name), status))
  1667. resp = self.__do_object('PUT', channel_name, params={Bucket.LIVE: '', Bucket.STATUS: status})
  1668. logger.debug("Put live-channel status done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1669. return RequestResult(resp)
  1670. def get_live_channel_history(self, channel_name):
  1671. """获取live channel中最近的最多十次的推流记录,记录中包含推流的起止时间和远端的地址
  1672. param str channel_name: 要获取最近推流记录的live channel的名称
  1673. return: :class:`GetLiveChannelHistoryResult <oss2.models.GetLiveChannelHistoryResult>`
  1674. """
  1675. logger.debug("Start to get live-channel history, bucket: {0}, channel_name: {1}".format(
  1676. self.bucket_name, to_string(channel_name)))
  1677. resp = self.__do_object('GET', channel_name, params={Bucket.LIVE: '', Bucket.COMP: 'history'})
  1678. logger.debug(
  1679. "Get live-channel history done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1680. return self._parse_result(resp, xml_utils.parse_live_channel_history, GetLiveChannelHistoryResult)
  1681. def post_vod_playlist(self, channel_name, playlist_name, start_time=0, end_time=0):
  1682. """根据指定的playlist name以及startTime和endTime生成一个点播的播放列表
  1683. param str channel_name: 要生成点播列表的live channel的名称
  1684. param str playlist_name: 要生成点播列表m3u8文件的名称
  1685. param int start_time: 点播的起始时间,Unix Time格式,可以使用int(time.time())获取
  1686. param int end_time: 点播的结束时间,Unix Time格式,可以使用int(time.time())获取
  1687. """
  1688. logger.debug("Start to post vod playlist, bucket: {0}, channel_name: {1}, playlist_name: {2}, start_time: "
  1689. "{3}, end_time: {4}".format(self.bucket_name, to_string(channel_name), playlist_name, start_time,
  1690. end_time))
  1691. key = channel_name + "/" + playlist_name
  1692. resp = self.__do_object('POST', key, params={Bucket.VOD: '', 'startTime': str(start_time),
  1693. 'endTime': str(end_time)})
  1694. logger.debug("Post vod playlist done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1695. return RequestResult(resp)
  1696. def get_vod_playlist(self, channel_name, start_time, end_time):
  1697. """查看指定时间段内的播放列表
  1698. param str channel_name: 要获取点播列表的live channel的名称
  1699. param int start_time: 点播的起始时间,Unix Time格式,可以使用int(time.time())获取
  1700. param int end_time: 点播的结束时间,Unix Time格式,可以使用int(time.time())获取
  1701. """
  1702. logger.debug("Start to get vod playlist, bucket: {0}, channel_name: {1}, start_time: "
  1703. "{2}, end_time: {3}".format(self.bucket_name, to_string(channel_name), start_time, end_time))
  1704. resp = self.__do_object('GET', channel_name, params={Bucket.VOD: '', 'startTime': str(start_time),
  1705. 'endTime': str(end_time)})
  1706. logger.debug("get vod playlist done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1707. result = GetVodPlaylistResult(resp)
  1708. return result
  1709. def process_object(self, key, process, headers=None):
  1710. """处理图片的接口,支持包括调整大小,旋转,裁剪,水印,格式转换等,支持多种方式组合处理。
  1711. :param str key: 处理的图片的对象名称
  1712. :param str process: 处理的字符串,例如"image/resize,w_100|sys/saveas,o_dGVzdC5qcGc,b_dGVzdA"
  1713. :param headers: HTTP头部
  1714. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  1715. """
  1716. headers = http.CaseInsensitiveDict(headers)
  1717. logger.debug("Start to process object, bucket: {0}, key: {1}, process: {2}".format(
  1718. self.bucket_name, to_string(key), process))
  1719. process_data = "%s=%s" % (Bucket.PROCESS, process)
  1720. resp = self.__do_object('POST', key, params={Bucket.PROCESS: ''}, headers=headers, data=process_data)
  1721. logger.debug("Process object done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1722. return ProcessObjectResult(resp)
  1723. def put_object_tagging(self, key, tagging, headers=None, params=None):
  1724. """
  1725. :param str key: 上传tagging的对象名称,不能为空。
  1726. :param tagging: tag 标签内容
  1727. :type tagging: :class:`Tagging <oss2.models.Tagging>` 对象
  1728. :param headers: HTTP头部
  1729. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  1730. :param dict params: HTTP请求参数
  1731. :return: :class:`RequestResult <oss2.models.RequestResult>`
  1732. """
  1733. logger.debug("Start to put object tagging, bucket: {0}, key: {1}, tagging: {2}".format(
  1734. self.bucket_name, to_string(key), tagging))
  1735. if headers is not None:
  1736. headers = http.CaseInsensitiveDict(headers)
  1737. if params is None:
  1738. params = dict()
  1739. params[Bucket.TAGGING] = ""
  1740. data = self.__convert_data(Tagging, xml_utils.to_put_tagging, tagging)
  1741. resp = self.__do_object('PUT', key, data=data, params=params, headers=headers)
  1742. return RequestResult(resp)
  1743. def get_object_tagging(self, key, params=None, headers=None):
  1744. """
  1745. :param str key: 要获取tagging的对象名称
  1746. :param dict params: 请求参数
  1747. :param headers: HTTP头部
  1748. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  1749. :return: :class:`GetTaggingResult <oss2.models.GetTaggingResult>`
  1750. """
  1751. logger.debug("Start to get object tagging, bucket: {0}, key: {1} params: {2}".format(
  1752. self.bucket_name, to_string(key), str(params)))
  1753. headers = http.CaseInsensitiveDict(headers)
  1754. if params is None:
  1755. params = dict()
  1756. params[Bucket.TAGGING] = ""
  1757. resp = self.__do_object('GET', key, params=params, headers=headers)
  1758. return self._parse_result(resp, xml_utils.parse_get_tagging, GetTaggingResult)
  1759. def delete_object_tagging(self, key, params=None, headers=None):
  1760. """
  1761. :param str key: 要删除tagging的对象名称
  1762. :param dict params: 请求参数
  1763. :param headers: HTTP头部
  1764. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  1765. :return: :class:`RequestResult <oss2.models.RequestResult>`
  1766. """
  1767. logger.debug("Start to delete object tagging, bucket: {0}, key: {1}".format(
  1768. self.bucket_name, to_string(key)))
  1769. headers = http.CaseInsensitiveDict(headers)
  1770. if params is None:
  1771. params = dict()
  1772. params[Bucket.TAGGING] = ""
  1773. resp = self.__do_object('DELETE', key, params=params, headers=headers)
  1774. logger.debug("Delete object tagging done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1775. return RequestResult(resp)
  1776. def put_bucket_encryption(self, rule):
  1777. """设置bucket加密配置。
  1778. :param rule: :class:` ServerSideEncryptionRule<oss2.models.ServerSideEncryptionRule>` 对象
  1779. """
  1780. data = self.__convert_data(ServerSideEncryptionRule, xml_utils.to_put_bucket_encryption, rule)
  1781. logger.debug("Start to put bucket encryption, bucket: {0}, rule: {1}".format(self.bucket_name, data))
  1782. resp = self.__do_bucket('PUT', data=data, params={Bucket.ENCRYPTION: ""})
  1783. logger.debug("Put bucket encryption done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1784. return RequestResult(resp)
  1785. def get_bucket_encryption(self):
  1786. """获取bucket加密配置。
  1787. :return: :class:`GetServerSideEncryptionResult <oss2.models.GetServerSideEncryptionResult>`
  1788. :raises: 如果没有设置Bucket encryption,则抛出 :class:`NoSuchServerSideEncryptionRule <oss2.exceptions.NoSuchServerSideEncryptionRule>`
  1789. """
  1790. logger.debug("Start to get bucket encryption, bucket: {0}".format(self.bucket_name))
  1791. resp = self.__do_bucket('GET', params={Bucket.ENCRYPTION: ''})
  1792. logger.debug("Get bucket encryption done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1793. return self._parse_result(resp, xml_utils.parse_get_bucket_encryption, GetServerSideEncryptionResult)
  1794. def delete_bucket_encryption(self):
  1795. """删除Bucket加密配置。如果Bucket加密没有设置,也返回成功。"""
  1796. logger.debug("Start to delete bucket encryption, bucket: {0}".format(self.bucket_name))
  1797. resp = self.__do_bucket('DELETE', params={Bucket.ENCRYPTION: ''})
  1798. logger.debug("Delete bucket encryption done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1799. return RequestResult(resp)
  1800. def put_bucket_tagging(self, tagging, headers=None):
  1801. """
  1802. :param str key: 上传tagging的对象名称,不能为空。
  1803. :param tagging: tag 标签内容
  1804. :type tagging: :class:`Tagging <oss2.models.Tagging>` 对象
  1805. :return: :class:`RequestResult <oss2.models.RequestResult>`
  1806. """
  1807. logger.debug("Start to put object tagging, bucket: {0} tagging: {1}".format(
  1808. self.bucket_name, tagging))
  1809. headers = http.CaseInsensitiveDict(headers)
  1810. data = self.__convert_data(Tagging, xml_utils.to_put_tagging, tagging)
  1811. resp = self.__do_bucket('PUT', data=data, params={Bucket.TAGGING: ''}, headers=headers)
  1812. logger.debug("Put bucket tagging done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1813. return RequestResult(resp)
  1814. def get_bucket_tagging(self):
  1815. """
  1816. :param str key: 要获取tagging的对象名称
  1817. :param dict params: 请求参数
  1818. :return: :class:`GetTaggingResult<oss2.models.GetTaggingResult>`
  1819. """
  1820. logger.debug("Start to get bucket tagging, bucket: {0}".format(
  1821. self.bucket_name))
  1822. resp = self.__do_bucket('GET', params={Bucket.TAGGING: ''})
  1823. logger.debug("Get bucket tagging done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1824. return self._parse_result(resp, xml_utils.parse_get_tagging, GetTaggingResult)
  1825. def delete_bucket_tagging(self, params=None):
  1826. """
  1827. :return: :class:`RequestResult <oss2.models.RequestResult>`
  1828. """
  1829. logger.debug("Start to delete bucket tagging, bucket: {0}".format(
  1830. self.bucket_name))
  1831. if params is None:
  1832. params = dict()
  1833. if Bucket.TAGGING not in params:
  1834. params[Bucket.TAGGING] = ''
  1835. resp = self.__do_bucket('DELETE', params=params)
  1836. logger.debug("Delete bucket tagging done, req_id: {0}, status_code: {1}".format(
  1837. resp.request_id, resp.status))
  1838. return RequestResult(resp)
  1839. def list_object_versions(self, prefix='', delimiter='', key_marker='',
  1840. max_keys=100, versionid_marker='', headers=None):
  1841. """根据前缀罗列Bucket里的文件的版本。
  1842. :param str prefix: 只罗列文件名为该前缀的文件
  1843. :param str delimiter: 分隔符。可以用来模拟目录
  1844. :param str key_marker: 分页标志。首次调用传空串,后续使用返回值的next_marker
  1845. :param int max_keys: 最多返回文件的个数,文件和目录的和不能超过该值
  1846. :param str versionid_marker: 设定结果从key-marker对象的
  1847. versionid-marker之后按新旧版本排序开始返回,该版本不会在返回的结果当中。
  1848. :param headers: HTTP头部
  1849. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  1850. :return: :class:`ListObjectVersionsResult <oss2.models.ListObjectVersionsResult>`
  1851. """
  1852. logger.debug(
  1853. "Start to List object versions, bucket: {0}, prefix: {1}, delimiter: {2},"
  1854. +"key_marker: {3}, versionid_marker: {4}, max-keys: {5}".format(
  1855. self.bucket_name, to_string(prefix), delimiter, to_string(key_marker),
  1856. to_string(versionid_marker), max_keys))
  1857. headers = http.CaseInsensitiveDict(headers)
  1858. resp = self.__do_bucket('GET',
  1859. params={'prefix': prefix,
  1860. 'delimiter': delimiter,
  1861. 'key-marker': key_marker,
  1862. 'version-id-marker': versionid_marker,
  1863. 'max-keys': str(max_keys),
  1864. 'encoding-type': 'url',
  1865. Bucket.VERSIONS: ''},
  1866. headers=headers)
  1867. logger.debug("List object versions done, req_id: {0}, status_code: {1}"
  1868. .format(resp.request_id, resp.status))
  1869. return self._parse_result(resp, xml_utils.parse_list_object_versions, ListObjectVersionsResult)
  1870. def put_bucket_versioning(self, config, headers=None):
  1871. """
  1872. :param str operation: 设置bucket是否开启多版本特性,可取值为:[Enabled,Suspend]
  1873. :return: :class:`RequestResult <oss2.models.RequestResult>`
  1874. """
  1875. logger.debug("Start to put object versioning, bucket: {0}".format(self.bucket_name))
  1876. data = self.__convert_data(BucketVersioningConfig, xml_utils.to_put_bucket_versioning, config)
  1877. headers = http.CaseInsensitiveDict(headers)
  1878. headers['Content-MD5'] = utils.content_md5(data)
  1879. resp = self.__do_bucket('PUT', data=data, params={Bucket.VERSIONING: ''}, headers=headers)
  1880. logger.debug("Put bucket versiong done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1881. return RequestResult(resp)
  1882. def get_bucket_versioning(self):
  1883. """
  1884. :return: :class:`GetBucketVersioningResult<oss2.models.GetBucketVersioningResult>`
  1885. """
  1886. logger.debug("Start to get bucket versioning, bucket: {0}".format(self.bucket_name))
  1887. resp = self.__do_bucket('GET', params={Bucket.VERSIONING: ''})
  1888. logger.debug("Get bucket versiong done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1889. return self._parse_result(resp, xml_utils.parse_get_bucket_versioning, GetBucketVersioningResult)
  1890. def put_bucket_policy(self, policy):
  1891. """设置bucket授权策略, 具体policy书写规则请参考官方文档
  1892. :param str policy: 授权策略
  1893. """
  1894. logger.debug("Start to put bucket policy, bucket: {0}, policy: {1}".format(self.bucket_name, policy))
  1895. resp = self.__do_bucket('PUT', data=policy, params={Bucket.POLICY: ''}, headers={'Content-MD5': utils.content_md5(policy)})
  1896. logger.debug("Put bucket policy done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1897. return RequestResult(resp)
  1898. def get_bucket_policy(self):
  1899. """获取bucket授权策略
  1900. :return: :class:`GetBucketPolicyResult <oss2.models.GetBucketPolicyResult>`
  1901. """
  1902. logger.debug("Start to get bucket policy, bucket: {0}".format(self.bucket_name))
  1903. resp = self.__do_bucket('GET', params={Bucket.POLICY:''})
  1904. logger.debug("Get bucket policy done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1905. return GetBucketPolicyResult(resp)
  1906. def delete_bucket_policy(self):
  1907. """删除bucket授权策略
  1908. :return: :class:`RequestResult <oss2.models.RequestResult>`
  1909. """
  1910. logger.debug("Start to delete bucket policy, bucket: {0}".format(self.bucket_name))
  1911. resp = self.__do_bucket('DELETE', params={Bucket.POLICY: ''})
  1912. logger.debug("Delete bucket policy done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1913. return RequestResult(resp)
  1914. def put_bucket_request_payment(self, payer):
  1915. """设置付费者。
  1916. :param input: :class: str
  1917. """
  1918. data = xml_utils.to_put_bucket_request_payment(payer)
  1919. logger.debug("Start to put bucket request payment, bucket: {0}, payer: {1}".format(self.bucket_name, payer))
  1920. resp = self.__do_bucket('PUT', data=data, params={Bucket.REQUESTPAYMENT: ''}, headers={'Content-MD5': utils.content_md5(data)})
  1921. logger.debug("Put bucket request payment done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1922. return RequestResult(resp)
  1923. def get_bucket_request_payment(self):
  1924. """获取付费者设置。
  1925. :return: :class:`GetBucketRequestPaymentResult <oss2.models.GetBucketRequestPaymentResult>`
  1926. """
  1927. logger.debug("Start to get bucket request payment, bucket: {0}.".format(self.bucket_name))
  1928. resp = self.__do_bucket('GET', params={Bucket.REQUESTPAYMENT: ''})
  1929. logger.debug("Get bucket request payment done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1930. return self._parse_result(resp, xml_utils.parse_get_bucket_request_payment, GetBucketRequestPaymentResult)
  1931. def put_bucket_qos_info(self, bucket_qos_info):
  1932. """配置bucket的QoSInfo
  1933. :param bucket_qos_info :class:`BucketQosInfo <oss2.models.BucketQosInfo>`
  1934. :return: :class:`RequestResult <oss2.models.RequestResult>`
  1935. """
  1936. logger.debug("Start to put bucket qos info, bucket: {0}".format(self.bucket_name))
  1937. data = self.__convert_data(BucketQosInfo, xml_utils.to_put_qos_info, bucket_qos_info)
  1938. headers = http.CaseInsensitiveDict()
  1939. headers['Content-MD5'] = utils.content_md5(data)
  1940. resp = self.__do_bucket('PUT', data=data, params={Bucket.QOS_INFO: ''}, headers=headers)
  1941. logger.debug("Get bucket qos info done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1942. return RequestResult(resp)
  1943. def get_bucket_qos_info(self):
  1944. """获取bucket的QoSInfo
  1945. :return: :class:`GetBucketQosInfoResult <oss2.models.GetBucketQosInfoResult>`
  1946. """
  1947. logger.debug("Start to get bucket qos info, bucket: {0}".format(self.bucket_name))
  1948. resp = self.__do_bucket('GET', params={Bucket.QOS_INFO: ''})
  1949. logger.debug("Get bucket qos info, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1950. return self._parse_result(resp, xml_utils.parse_get_qos_info, GetBucketQosInfoResult)
  1951. def delete_bucket_qos_info(self):
  1952. """删除bucket的QoSInfo
  1953. :return: :class:`RequestResult <oss2.models.RequestResult>`
  1954. """
  1955. logger.debug("Start to delete bucket qos info, bucket: {0}".format(self.bucket_name))
  1956. resp = self.__do_bucket('DELETE', params={Bucket.QOS_INFO: ''})
  1957. logger.debug("Delete bucket qos info done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1958. return RequestResult(resp)
  1959. def set_bucket_storage_capacity(self, user_qos):
  1960. """设置Bucket的容量,单位GB
  1961. :param user_qos :class:`BucketUserQos <oss2.models.BucketUserQos>`
  1962. """
  1963. logger.debug("Start to set bucket storage capacity: {0}".format(self.bucket_name))
  1964. data = xml_utils.to_put_bucket_user_qos(user_qos)
  1965. resp = self.__do_bucket('PUT', data=data, params={Bucket.USER_QOS: ''})
  1966. logger.debug("Set bucket storage capacity done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1967. return RequestResult(resp)
  1968. def get_bucket_storage_capacity(self):
  1969. """获取bucket的容量信息。
  1970. :return: :class:`GetBucketUserQosResult <oss2.models.GetBucketUserQosResult>`
  1971. """
  1972. logger.debug("Start to get bucket storage capacity, bucket:{0}".format(self.bucket_name))
  1973. resp = self._Bucket__do_bucket('GET', params={Bucket.USER_QOS: ''})
  1974. logger.debug("Get bucket storage capacity done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1975. return self._parse_result(resp, xml_utils.parse_get_bucket_user_qos, GetBucketUserQosResult)
  1976. def put_async_fetch_task(self, task_config):
  1977. """创建一个异步获取文件到bucket的任务。
  1978. :param task_config: 任务配置
  1979. :type task_config: class:`AsyncFetchTaskConfiguration <oss2.models.AsyncFetchTaskConfiguration>`
  1980. :return: :class:`PutAsyncFetchTaskResult <oss2.models.PutAsyncFetchTaskResult>`
  1981. """
  1982. logger.debug("Start to put async fetch task, bucket:{0}".format(self.bucket_name))
  1983. data = xml_utils.to_put_async_fetch_task(task_config)
  1984. headers = http.CaseInsensitiveDict()
  1985. headers['Content-MD5'] = utils.content_md5(data)
  1986. resp = self._Bucket__do_bucket('POST', data=data, params={Bucket.ASYNC_FETCH: ''}, headers=headers)
  1987. logger.debug("Put async fetch task done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1988. return self._parse_result(resp, xml_utils.parse_put_async_fetch_task_result, PutAsyncFetchTaskResult)
  1989. def get_async_fetch_task(self, task_id):
  1990. """获取一个异步获取文件到bucket的任务信息。
  1991. :param str task_id: 任务id
  1992. :return: :class:`GetAsyncFetchTaskResult <oss2.models.GetAsyncFetchTaskResult>`
  1993. """
  1994. logger.debug("Start to get async fetch task, bucket:{0}, task_id:{1}".format(self.bucket_name, task_id))
  1995. resp = self._Bucket__do_bucket('GET', headers={OSS_TASK_ID: task_id}, params={Bucket.ASYNC_FETCH: ''})
  1996. logger.debug("Put async fetch task done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  1997. return self._parse_result(resp, xml_utils.parse_get_async_fetch_task_result, GetAsyncFetchTaskResult)
  1998. def put_bucket_inventory_configuration(self, inventory_configuration):
  1999. """设置bucket清单配置
  2000. :param inventory_configuration :class:`InventoryConfiguration <oss2.models.InventoryConfiguration>`
  2001. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2002. """
  2003. logger.debug("Start to put bucket inventory configuration, bucket: {0}".format(self.bucket_name))
  2004. data = self.__convert_data(InventoryConfiguration, xml_utils.to_put_inventory_configuration, inventory_configuration)
  2005. headers = http.CaseInsensitiveDict()
  2006. headers['Content-MD5'] = utils.content_md5(data)
  2007. resp = self.__do_bucket('PUT', data=data, params={Bucket.INVENTORY: '', Bucket.INVENTORY_CONFIG_ID:inventory_configuration.inventory_id}, headers=headers)
  2008. logger.debug("Put bucket inventory configuration done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2009. return RequestResult(resp)
  2010. def get_bucket_inventory_configuration(self, inventory_id):
  2011. """获取指定的清单配置。
  2012. :param str inventory_id : 清单配置id
  2013. :return: :class:`GetInventoryConfigurationResult <oss2.models.GetInventoryConfigurationResult>`
  2014. """
  2015. logger.debug("Start to get bucket inventory configuration, bucket: {0}".format(self.bucket_name))
  2016. resp = self.__do_bucket('GET', params={Bucket.INVENTORY: '', Bucket.INVENTORY_CONFIG_ID:inventory_id})
  2017. logger.debug("Get bucket inventory cinfguration done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2018. return self._parse_result(resp, xml_utils.parse_get_bucket_inventory_configuration, GetInventoryConfigurationResult)
  2019. def list_bucket_inventory_configurations(self, continuation_token=None):
  2020. """罗列清单配置,默认单次最大返回100条配置,如果存在超过100条配置,罗列结果将会分页,
  2021. 分页信息保存在 class:`ListInventoryConfigurationResult <oss2.models.ListInventoryConfigurationResult>`中。
  2022. :param str continuation_token: 分页标识, 默认值为None, 如果上次罗列不完整,这里设置为上次罗列结果中的next_continuation_token值。
  2023. :return: :class:`ListInventoryConfigurationResult <oss2.models.ListInventoryConfigurationResult>`
  2024. """
  2025. logger.debug("Start to list bucket inventory configuration, bucket: {0}".format(self.bucket_name))
  2026. params = {Bucket.INVENTORY:''}
  2027. if continuation_token is not None:
  2028. params[Bucket.CONTINUATION_TOKEN] = continuation_token
  2029. resp = self.__do_bucket('GET', params=params)
  2030. logger.debug("List bucket inventory configuration done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2031. return self._parse_result(resp, xml_utils.parse_list_bucket_inventory_configurations, ListInventoryConfigurationsResult)
  2032. def delete_bucket_inventory_configuration(self, inventory_id):
  2033. """删除指定的清单配置
  2034. :param str inventory_id : 清单配置id
  2035. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2036. """
  2037. logger.debug("Start to delete bucket inventory configuration, bucket: {0}, configuration id: {1}.".format(self.bucket_name, inventory_id))
  2038. resp = self.__do_bucket('DELETE', params={Bucket.INVENTORY:'', Bucket.INVENTORY_CONFIG_ID:inventory_id})
  2039. logger.debug("Delete bucket inventory configuration, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2040. return RequestResult(resp)
  2041. def init_bucket_worm(self, retention_period_days=None):
  2042. """创建一条合规保留策略
  2043. :param int retention_period_days : 指定object的保留天数
  2044. :return: :class:`InitBucketWormResult <oss2.models.InitBucketWormResult>`
  2045. """
  2046. logger.debug("Start to init bucket worm, bucket: {0}, retention_period_days: {1}."
  2047. .format(self.bucket_name, retention_period_days))
  2048. data = xml_utils.to_put_init_bucket_worm(retention_period_days)
  2049. headers = http.CaseInsensitiveDict()
  2050. headers['Content-MD5'] = utils.content_md5(data)
  2051. resp = self.__do_bucket('POST', data=data, params={Bucket.WORM: ''}, headers=headers)
  2052. logger.debug("init bucket worm done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2053. result = InitBucketWormResult(resp)
  2054. result.worm_id = resp.headers.get("x-oss-worm-id")
  2055. return result
  2056. def abort_bucket_worm(self):
  2057. """删除一条合规保留策略
  2058. 只有未锁定保留策略的状态下才能删除,一旦锁定bucket数据将处于保护状态。
  2059. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2060. """
  2061. logger.debug("Start to abort bucket worm, bucket: {0}.".format(self.bucket_name))
  2062. resp = self.__do_bucket('DELETE', params={Bucket.WORM: ''})
  2063. logger.debug("abort bucket worm done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2064. return RequestResult(resp)
  2065. def complete_bucket_worm(self, worm_id=None):
  2066. """锁定一条合规保留策略
  2067. :param str worm_id : 合规保留策略的id。
  2068. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2069. """
  2070. logger.debug("Start to complete bucket worm, bucket: {0}, worm_id: {1}.".format(self.bucket_name, worm_id))
  2071. resp = self.__do_bucket('POST', params={Bucket.WORM_ID: worm_id})
  2072. logger.debug("complete bucket worm done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2073. return RequestResult(resp)
  2074. def extend_bucket_worm(self, worm_id=None, retention_period_days=None):
  2075. """延长已经锁定的合规保留策略的object保护天数。
  2076. :param str worm_id : 合规保留策略的id。
  2077. :param int retention_period_days : 指定object的保留天数
  2078. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2079. """
  2080. data = xml_utils.to_put_extend_bucket_worm(retention_period_days)
  2081. headers = http.CaseInsensitiveDict()
  2082. headers['Content-MD5'] = utils.content_md5(data)
  2083. logger.debug("Start to extend bucket worm, bucket: {0}, worm_id: {1}, retention_period_days."
  2084. .format(self.bucket_name, worm_id, retention_period_days))
  2085. resp = self.__do_bucket('POST', data=data, params={Bucket.WORM_ID: worm_id, Bucket.WORM_EXTEND: ''}, headers=headers)
  2086. logger.debug("extend bucket worm done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2087. return RequestResult(resp)
  2088. def get_bucket_worm(self):
  2089. """获取合规保留策略
  2090. :return: :class:`GetBucketWormResult <oss2.models.GetBucketWormResult>`
  2091. """
  2092. logger.debug("Start to get bucket worm, bucket: {0}.".format(self.bucket_name))
  2093. resp = self.__do_bucket('GET', params={Bucket.WORM: ''})
  2094. logger.debug("get bucket worm done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2095. return self._parse_result(resp, xml_utils.parse_get_bucket_worm_result, GetBucketWormResult)
  2096. def put_bucket_replication(self, rule):
  2097. """设置bucket跨区域复制规则
  2098. :param rule :class:`ReplicationRule <oss2.models.ReplicationRule>`
  2099. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2100. """
  2101. logger.debug("Start to put bucket replication: {0}".format(self.bucket_name))
  2102. data = xml_utils.to_put_bucket_replication(rule)
  2103. headers = http.CaseInsensitiveDict()
  2104. headers['Content-MD5'] = utils.content_md5(data)
  2105. resp = self.__do_bucket('POST', data=data, params={Bucket.REPLICATION: '', 'comp': 'add'}, headers=headers)
  2106. logger.debug("Put bucket replication done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2107. return RequestResult(resp)
  2108. def get_bucket_replication(self):
  2109. """获取bucket跨区域复制规则
  2110. :return: :class:`GetBucketReplicationResult <oss2.models.GetBucketReplicationResult>`
  2111. """
  2112. logger.debug("Start to get bucket replication: {0}".format(self.bucket_name))
  2113. resp = self.__do_bucket('GET', params={Bucket.REPLICATION: ''})
  2114. logger.debug("Get bucket replication done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2115. return self._parse_result(resp, xml_utils.parse_get_bucket_replication_result, GetBucketReplicationResult)
  2116. def delete_bucket_replication(self, rule_id):
  2117. """停止Bucket的跨区域复制并删除Bucket的复制配置
  2118. :param str rule_id: Bucket跨区域复制规则的id。
  2119. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2120. """
  2121. logger.debug("Start to delete bucket replication: {0}".format(self.bucket_name))
  2122. data = xml_utils.to_delete_bucket_replication(rule_id)
  2123. headers = http.CaseInsensitiveDict()
  2124. headers['Content-MD5'] = utils.content_md5(data)
  2125. resp = self.__do_bucket('POST', data=data, params={Bucket.REPLICATION: '', 'comp': 'delete'}, headers=headers)
  2126. logger.debug("Delete bucket replication done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2127. return RequestResult(resp)
  2128. def get_bucket_replication_location(self):
  2129. """获取可复制到的Bucket所在的地域
  2130. :return: :class:`ReplicationLocation <oss2.models.GetBucketReplicationLocationResult>`
  2131. """
  2132. logger.debug("Start to get bucket replication location: {0}".format(self.bucket_name))
  2133. resp = self.__do_bucket('GET', params={Bucket.REPLICATION_LOCATION: ''})
  2134. logger.debug("Get bucket replication location done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2135. return self._parse_result(resp, xml_utils.parse_get_bucket_replication_location_result, GetBucketReplicationLocationResult)
  2136. def get_bucket_replication_progress(self, rule_id):
  2137. """获取获取某个Bucket的跨区域复制进度
  2138. :param str rule_id: Bucket跨区域复制规则的id。
  2139. :return: :class:`GetBucketReplicationProgressResult <oss2.models.GetBucketReplicationProgressResult>`
  2140. """
  2141. logger.debug("Start to get bucket replication progress: {0}".format(self.bucket_name))
  2142. resp = self.__do_bucket('GET', params={Bucket.REPLICATION_PROGRESS: '', 'rule-id': rule_id})
  2143. logger.debug("Get bucket replication progress done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2144. return self._parse_result(resp, xml_utils.parse_get_bucket_replication_progress_result, GetBucketReplicationProgressResult)
  2145. def _get_bucket_config(self, config):
  2146. """获得Bucket某项配置,具体哪种配置由 `config` 指定。该接口直接返回 `RequestResult` 对象。
  2147. 通过read()接口可以获得XML字符串。不建议使用。
  2148. :param str config: 可以是 `Bucket.ACL` 、 `Bucket.LOGGING` 等。
  2149. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2150. """
  2151. logger.debug("Start to get bucket config, bucket: {0}".format(self.bucket_name))
  2152. resp = self.__do_bucket('GET', params={config: ''})
  2153. logger.debug("Get bucket config done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2154. return resp
  2155. def put_bucket_transfer_acceleration(self, enabled):
  2156. """为存储空间(Bucket)配置传输加速
  2157. :param str enabled : 是否开启传输加速。true:开启传输加速; false:关闭传输加速.
  2158. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2159. """
  2160. logger.debug("Start to bucket transfer acceleration, bucket: {0}, enabled: {1}."
  2161. .format(self.bucket_name, enabled))
  2162. data = xml_utils.to_put_bucket_transfer_acceleration(enabled)
  2163. headers = http.CaseInsensitiveDict()
  2164. headers['Content-MD5'] = utils.content_md5(data)
  2165. resp = self.__do_bucket('PUT', data=data, params={Bucket.TRANSFER_ACCELERATION: ''}, headers=headers)
  2166. logger.debug("bucket transfer acceleration done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2167. return RequestResult(resp)
  2168. def get_bucket_transfer_acceleration(self):
  2169. """获取目标存储空间(Bucket)的传输加速配置
  2170. :return: :class:`GetBucketTransferAccelerationResult <oss2.models.GetBucketTransferAccelerationResult>`
  2171. """
  2172. logger.debug("Start to get bucket transfer acceleration: {0}".format(self.bucket_name))
  2173. resp = self.__do_bucket('GET', params={Bucket.TRANSFER_ACCELERATION: ''})
  2174. logger.debug("Get bucket transfer acceleration done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2175. return self._parse_result(resp, xml_utils.parse_get_bucket_transfer_acceleration_result, GetBucketTransferAccelerationResult)
  2176. def create_bucket_cname_token(self, domain):
  2177. """创建域名所有权验证所需的CnameToken。
  2178. :param str domain : 绑定的Cname名称。
  2179. :return: :class:`CreateBucketCnameTokenResult <oss2.models.CreateBucketCnameTokenResult>`
  2180. """
  2181. logger.debug("Start to create bucket cname token, bucket: {0}.".format(self.bucket_name))
  2182. data = xml_utils.to_bucket_cname_configuration(domain)
  2183. resp = self.__do_bucket('POST', data=data, params={Bucket.CNAME: '', Bucket.COMP: 'token'})
  2184. logger.debug("bucket cname token done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2185. return self._parse_result(resp, xml_utils.parse_create_bucket_cname_token, CreateBucketCnameTokenResult)
  2186. def get_bucket_cname_token(self, domain):
  2187. """获取已创建的CnameToken。
  2188. :param str domain : 绑定的Cname名称。
  2189. :return: :class:`GetBucketCnameTokenResult <oss2.models.GetBucketCnameTokenResult>`
  2190. """
  2191. logger.debug("Start to get bucket cname: {0}".format(self.bucket_name))
  2192. resp = self.__do_bucket('GET', params={Bucket.CNAME: domain, Bucket.COMP: 'token'})
  2193. logger.debug("Get bucket cname done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2194. return self._parse_result(resp, xml_utils.parse_get_bucket_cname_token, GetBucketCnameTokenResult)
  2195. def put_bucket_cname(self, input):
  2196. """为某个存储空间(Bucket)绑定自定义域名。
  2197. :param input: PutBucketCnameRequest类型,包含了证书和自定义域名信息
  2198. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2199. """
  2200. logger.debug("Start to add bucket cname, bucket: {0}.".format(self.bucket_name))
  2201. data = xml_utils.to_bucket_cname_configuration(input.domain, input.cert)
  2202. resp = self.__do_bucket('POST', data=data, params={Bucket.CNAME: '', Bucket.COMP: 'add'})
  2203. logger.debug("bucket cname done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2204. return RequestResult(resp)
  2205. def list_bucket_cname(self):
  2206. """查询某个存储空间(Bucket)下绑定的所有Cname列表。
  2207. :return: :class:`ListBucketCnameResult <oss2.models.ListBucketCnameResult>`
  2208. """
  2209. logger.debug("Start to do query list bucket cname: {0}".format(self.bucket_name))
  2210. resp = self.__do_bucket('GET', params={Bucket.CNAME: ''})
  2211. logger.debug("query list bucket cname done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2212. return self._parse_result(resp, xml_utils.parse_list_bucket_cname, ListBucketCnameResult)
  2213. def delete_bucket_cname(self, domain):
  2214. """删除某个存储空间(Bucket)已绑定的Cname
  2215. :param str domain : 绑定的Cname名称。
  2216. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2217. """
  2218. logger.debug("Start to delete bucket cname: {0}".format(self.bucket_name))
  2219. data = xml_utils.to_bucket_cname_configuration(domain)
  2220. resp = self.__do_bucket('POST', data=data, params={Bucket.CNAME: '', Bucket.COMP: 'delete'})
  2221. logger.debug("delete bucket cname done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2222. return RequestResult(resp)
  2223. def open_bucket_meta_query(self):
  2224. """为存储空间(Bucket)开启元数据管理功能
  2225. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2226. """
  2227. logger.debug("Start to bucket meta query, bucket: {0}.".format(self.bucket_name))
  2228. resp = self.__do_bucket('POST', params={Bucket.META_QUERY: '', 'comp': 'add'})
  2229. logger.debug("bucket meta query done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2230. return RequestResult(resp)
  2231. def get_bucket_meta_query_status(self):
  2232. """获取指定存储空间(Bucket)的元数据索引库信息。
  2233. :return: :class:`GetBucketMetaQueryResult <oss2.models.GetBucketMetaQueryResult>`
  2234. """
  2235. logger.debug("Start to get bucket meta query: {0}".format(self.bucket_name))
  2236. resp = self.__do_bucket('GET', params={Bucket.META_QUERY: ''})
  2237. logger.debug("Get bucket meta query done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2238. return self._parse_result(resp, xml_utils.parse_get_bucket_meta_query_result, GetBucketMetaQueryResult)
  2239. def do_bucket_meta_query(self, do_meta_query_request):
  2240. """查询满足指定条件的文件(Object),并按照指定字段和排序方式列出文件信息。
  2241. :param do_meta_query_request :class:`MetaQuery <oss2.models.MetaQuery>`
  2242. :return: :class:`DoBucketMetaQueryResult <oss2.models.DoBucketMetaQueryResult>`
  2243. """
  2244. logger.debug("Start to do bucket meta query: {0}".format(self.bucket_name))
  2245. data = self.__convert_data(MetaQuery, xml_utils.to_do_bucket_meta_query_request, do_meta_query_request)
  2246. resp = self.__do_bucket('POST', data=data, params={Bucket.META_QUERY: '', Bucket.COMP: 'query'})
  2247. logger.debug("do bucket meta query done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2248. return self._parse_result(resp, xml_utils.parse_do_bucket_meta_query_result, DoBucketMetaQueryResult)
  2249. def close_bucket_meta_query(self):
  2250. """关闭存储空间(Bucket)的元数据管理功能
  2251. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2252. """
  2253. logger.debug("Start to close bucket meta query: {0}".format(self.bucket_name))
  2254. resp = self.__do_bucket('POST', params={Bucket.META_QUERY: '', Bucket.COMP: 'delete'})
  2255. logger.debug("bucket meta query done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2256. return RequestResult(resp)
  2257. def put_bucket_access_monitor(self, status):
  2258. """更新 Bucket 访问跟踪状态。
  2259. :param str status : bucket访问跟踪的开启状态
  2260. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2261. """
  2262. logger.debug("Start to put bucket access monitor, bucket: {0}.".format(self.bucket_name))
  2263. data = xml_utils.to_put_bucket_access_monitor(status)
  2264. resp = self.__do_bucket('PUT', data=data, params={Bucket.ACCESS_MONITOR: ''})
  2265. logger.debug("bucket access monitor done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2266. return RequestResult(resp)
  2267. def get_bucket_access_monitor(self):
  2268. """获取当前Bucket的访问跟踪的状态。
  2269. :return: :class:`GetBucketAccessMonitorResult <oss2.models.GetBucketAccessMonitorResult>`
  2270. """
  2271. logger.debug("Start to get bucket access monitor: {0}".format(self.bucket_name))
  2272. resp = self.__do_bucket('GET', params={Bucket.ACCESS_MONITOR: ''})
  2273. logger.debug("query list bucket cname done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2274. return self._parse_result(resp, xml_utils.parse_get_bucket_access_monitor_result, GetBucketAccessMonitorResult)
  2275. def get_bucket_resource_group(self):
  2276. """查询存储空间(Bucket)的资源组ID。
  2277. :return: :class:`GetBucketResourceGroupResult <oss2.models.GetBucketResourceGroupResult>`
  2278. """
  2279. logger.debug("Start to get bucket resource group: {0}".format(self.bucket_name))
  2280. resp = self.__do_bucket('GET', params={Bucket.RESOURCE_GROUP: ''})
  2281. logger.debug("Get bucket resource group done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2282. return self._parse_result(resp, xml_utils.parse_get_bucket_resource_group_result, GetBucketResourceGroupResult)
  2283. def put_bucket_resource_group(self, resourceGroupId):
  2284. """为存储空间(Bucket)配置所属资源组。
  2285. :param str resourceGroupId : Bucket所属的资源组ID。
  2286. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2287. """
  2288. logger.debug("Start to put bucket resource group, bucket: {0}.".format(self.bucket_name))
  2289. data = xml_utils.to_put_bucket_resource_group(resourceGroupId)
  2290. resp = self.__do_bucket('PUT', data=data, params={Bucket.RESOURCE_GROUP: ''})
  2291. logger.debug("bucket resource group done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2292. return RequestResult(resp)
  2293. def put_bucket_style(self, styleName, content):
  2294. """新增图片样式。
  2295. :param str styleName : 样式名称。
  2296. :param str content : 图片样式内容,图片样式可以包含一个或多个图片处理操作。
  2297. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2298. """
  2299. logger.debug("Start to put bucket style, bucket: {0}.".format(self.bucket_name))
  2300. data = xml_utils.to_put_bucket_style(content)
  2301. resp = self.__do_bucket('PUT', data=data, params={Bucket.STYLE: '', Bucket.STYLE_NAME: styleName})
  2302. logger.debug("bucket style done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2303. return RequestResult(resp)
  2304. def get_bucket_style(self, styleName):
  2305. """查询某个Bucket下指定的图片样式信息。
  2306. :param str styleName : 样式名称。
  2307. :return: :class:`GetBucketStyleResult <oss2.models.GetBucketStyleResult>`
  2308. """
  2309. logger.debug("Start to get bucket style: {0}".format(self.bucket_name))
  2310. resp = self.__do_bucket('GET', params={Bucket.STYLE: '', Bucket.STYLE_NAME: styleName})
  2311. logger.debug("Get bucket style done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2312. return self._parse_result(resp, xml_utils.parse_get_bucket_style_result, GetBucketStyleResult)
  2313. def list_bucket_style(self):
  2314. """查询某个Bucket下已创建的所有图片样式。
  2315. :return: :class:`ListBucketStyleResult <oss2.models.ListBucketStyleResult>`
  2316. """
  2317. logger.debug("Start to list bucket style: {0}".format(self.bucket_name))
  2318. resp = self.__do_bucket('GET', params={Bucket.STYLE: ''})
  2319. logger.debug("query list bucket style done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2320. return self._parse_result(resp, xml_utils.parse_list_bucket_style, ListBucketStyleResult)
  2321. def delete_bucket_style(self, styleName):
  2322. """删除某个Bucket下指定的图片样式。
  2323. :param str styleName : 样式名称。
  2324. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2325. """
  2326. logger.debug("Start to delete bucket style: {0}".format(self.bucket_name))
  2327. resp = self.__do_bucket('DELETE', params={Bucket.STYLE: '', Bucket.STYLE_NAME: styleName})
  2328. logger.debug("delete bucket style done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2329. return RequestResult(resp)
  2330. def async_process_object(self, key, process, headers=None):
  2331. """异步处理多媒体接口。
  2332. :param str key: 处理的多媒体的对象名称
  2333. :param str process: 处理的字符串,例如"video/convert,f_mp4,vcodec_h265,s_1920x1080,vb_2000000,fps_30,acodec_aac,ab_100000,sn_1|sys/saveas,o_dGVzdC5qcGc,b_dGVzdA"
  2334. :param headers: HTTP头部
  2335. :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
  2336. """
  2337. headers = http.CaseInsensitiveDict(headers)
  2338. logger.debug("Start to async process object, bucket: {0}, key: {1}, process: {2}".format(
  2339. self.bucket_name, to_string(key), process))
  2340. process_data = "%s=%s" % (Bucket.ASYNC_PROCESS, process)
  2341. resp = self.__do_object('POST', key, params={Bucket.ASYNC_PROCESS: ''}, headers=headers, data=process_data)
  2342. logger.debug("Async process object done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2343. return self._parse_result(resp, xml_utils.parse_async_process_object, AsyncProcessObject)
  2344. def put_bucket_callback_policy(self, callbackPolicy):
  2345. """设置bucket回调策略
  2346. :param str callbackPolicy: 回调策略
  2347. """
  2348. logger.debug("Start to put bucket callback policy, bucket: {0}, callback policy: {1}".format(self.bucket_name, callbackPolicy))
  2349. data = xml_utils.to_do_bucket_callback_policy_request(callbackPolicy)
  2350. resp = self.__do_bucket('PUT', data=data, params={Bucket.POLICY: '', Bucket.COMP: Bucket.CALLBACK})
  2351. logger.debug("Put bucket callback policy done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2352. return RequestResult(resp)
  2353. def get_bucket_callback_policy(self):
  2354. """获取bucket回调策略
  2355. :return: :class:`GetBucketPolicyResult <oss2.models.CallbackPolicyResult>`
  2356. """
  2357. logger.debug("Start to get bucket callback policy, bucket: {0}".format(self.bucket_name))
  2358. resp = self.__do_bucket('GET', params={Bucket.POLICY: '', Bucket.COMP: Bucket.CALLBACK})
  2359. logger.debug("Get bucket callback policy done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2360. return self._parse_result(resp, xml_utils.parse_callback_policy_result, CallbackPolicyResult)
  2361. def delete_bucket_callback_policy(self):
  2362. """删除bucket回调策略
  2363. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2364. """
  2365. logger.debug("Start to delete bucket callback policy, bucket: {0}".format(self.bucket_name))
  2366. resp = self.__do_bucket('DELETE', params={Bucket.POLICY: '', Bucket.COMP: Bucket.CALLBACK})
  2367. logger.debug("Delete bucket callback policy done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2368. return RequestResult(resp)
  2369. def put_bucket_archive_direct_read(self, enabled=False):
  2370. """设置归档直读
  2371. :param boolean enabled: Bucket是否开启归档直读
  2372. """
  2373. logger.debug("Start to put bucket archive direct read, bucket: {0}, enabled: {1}".format(self.bucket_name, enabled))
  2374. data = xml_utils.to_put_bucket_archive_direct_read(enabled)
  2375. resp = self.__do_bucket('PUT', data=data, params={Bucket.ARCHIVE_DIRECT_READ: ''})
  2376. logger.debug("bucket archive direct read done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2377. return RequestResult(resp)
  2378. def get_bucket_archive_direct_read(self):
  2379. """获取归档直读
  2380. :return: :class:`GetBucketArchiveDirectReadResult <oss2.models.GetBucketArchiveDirectReadResult>`
  2381. """
  2382. logger.debug("Start to get bucket archive direct read, bucket: {0}".format(self.bucket_name))
  2383. resp = self.__do_bucket('GET', params={Bucket.ARCHIVE_DIRECT_READ: ''})
  2384. logger.debug("Get bucket archive direct read done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2385. return self._parse_result(resp, xml_utils.parse_get_bucket_archive_direct_read, GetBucketArchiveDirectReadResult)
  2386. def put_bucket_https_config(self, httpsConfig):
  2387. """Bucket开启或关闭TLS版本设置。
  2388. :param httpsConfig: TLS版本信息设置
  2389. """
  2390. logger.debug("Start to put bucket https config, bucket: {0}, https config: {1}".format(self.bucket_name, httpsConfig))
  2391. data = xml_utils.to_do_bucket_https_config_request(httpsConfig)
  2392. resp = self.__do_bucket('PUT', data=data, params={Bucket.HTTPS_CONFIG: ''})
  2393. logger.debug("Put bucket https config done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2394. return RequestResult(resp)
  2395. def create_bucket_data_redundancy_transition(self, targetType):
  2396. """为Bucket创建存储冗余转换任务。
  2397. :param str targetType: 目标存储冗余类型
  2398. """
  2399. logger.debug("Start to create bucket data redundancy transition, bucket: {0}, target type: {1}".format(self.bucket_name, targetType))
  2400. resp = self.__do_bucket('POST', params={Bucket.REDUNDANCY_TRANSITION: '', Bucket.TARGET_REDUNDANCY_TYPE: targetType})
  2401. logger.debug("Create bucket data redundancy transition done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2402. return self._parse_result(resp, xml_utils.parse_create_data_redundancy_transition_result, CreateDataRedundancyTransitionResult)
  2403. def get_bucket_data_redundancy_transition(self, taskId):
  2404. """获取存储冗余转换任务。
  2405. :return: :class:`DataRedundancyTransitionInfoResult <oss2.models.DataRedundancyTransitionInfoResult>`
  2406. """
  2407. logger.debug("Start to get bucket data redundancy transition, bucket: {0}".format(self.bucket_name))
  2408. resp = self.__do_bucket('GET', params={Bucket.REDUNDANCY_TRANSITION: '', Bucket.REDUNDANCY_TRANSITION_TASK_ID: taskId})
  2409. logger.debug("Get bucket data redundancy transition done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2410. return self._parse_result(resp, xml_utils.parse_get_bucket_data_redundancy_transition, DataRedundancyTransitionInfoResult)
  2411. def delete_bucket_data_redundancy_transition(self, taskId):
  2412. """删除存储冗余转换任务。
  2413. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2414. """
  2415. logger.debug("Start to delete bucket data redundancy transition, bucket: {0}".format(self.bucket_name))
  2416. resp = self.__do_bucket('DELETE', params={Bucket.REDUNDANCY_TRANSITION: '', Bucket.REDUNDANCY_TRANSITION_TASK_ID: taskId})
  2417. logger.debug("Delete bucket data redundancy transition done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2418. return RequestResult(resp)
  2419. def get_bucket_https_config(self):
  2420. """查看Bucket的TLS版本设置。
  2421. :return: :class:`HttpsConfigResult <oss2.models.HttpsConfigResult>`
  2422. """
  2423. logger.debug("Start to get bucket https config, bucket: {0}".format(self.bucket_name))
  2424. resp = self.__do_bucket('GET', params={Bucket.HTTPS_CONFIG: ''})
  2425. logger.debug("Get bucket https config done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2426. return self._parse_result(resp, xml_utils.parse_get_bucket_https_config, HttpsConfigResult)
  2427. def list_bucket_data_redundancy_transition(self):
  2428. """列举某个Bucket下所有的存储冗余转换任务。
  2429. :return: :class:`ListBucketDataRedundancyTransitionResult <oss2.models.ListBucketDataRedundancyTransitionResult>`
  2430. """
  2431. logger.debug("Start to do query list bucket data redundancy transition: {0}".format(self.bucket_name))
  2432. resp = self.__do_bucket('GET', params={Bucket.REDUNDANCY_TRANSITION: ''})
  2433. logger.debug("query list bucket data redundancy transition done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2434. return self._parse_result(resp, xml_utils.parse_list_bucket_data_redundancy_transition, ListBucketDataRedundancyTransitionResult)
  2435. def create_access_point(self, accessPoint):
  2436. """创建接入点
  2437. :param accessPoint :class:`CreateAccessPointRequest <oss2.models.CreateAccessPointRequest>`
  2438. :return: :class:`CreateAccessPointResult <oss2.models.CreateAccessPointResult>`
  2439. """
  2440. logger.debug("Start to create access point, bucket: {0}".format(self.bucket_name))
  2441. data = xml_utils.to_do_create_access_point_request(accessPoint)
  2442. resp = self.__do_bucket('PUT', data=data, params={Bucket.ACCESS_POINT: ''})
  2443. logger.debug("Create access point done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2444. return self._parse_result(resp, xml_utils.parse_create_access_point_result, CreateAccessPointResult)
  2445. def get_access_point(self, accessPointName):
  2446. """获取接入点信息
  2447. :param str accessPointName: 接入点名称
  2448. :return: :class:`GetAccessPointResult <oss2.models.GetAccessPointResult>`
  2449. """
  2450. logger.debug("Start to get access point, bucket: {0}".format(self.bucket_name))
  2451. headers = http.CaseInsensitiveDict()
  2452. headers['x-oss-access-point-name'] = accessPointName
  2453. resp = self.__do_bucket('GET', params={Bucket.ACCESS_POINT: ''}, headers=headers)
  2454. logger.debug("Get access point done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2455. return self._parse_result(resp, xml_utils.parse_get_access_point_result, GetAccessPointResult)
  2456. def delete_access_point(self, accessPointName):
  2457. """删除接入点
  2458. :param str accessPointName: 接入点名称
  2459. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2460. """
  2461. logger.debug("Start to delete access point, bucket: {0}".format(self.bucket_name))
  2462. headers = http.CaseInsensitiveDict()
  2463. headers['x-oss-access-point-name'] = accessPointName
  2464. resp = self.__do_bucket('DELETE', params={Bucket.ACCESS_POINT: ''}, headers=headers)
  2465. logger.debug("Delete access point done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2466. return RequestResult(resp)
  2467. def list_bucket_access_points(self, max_keys=100, continuation_token=''):
  2468. """查询某个Bucket下所有接入点。
  2469. param: int max_keys: 本次list返回access point的最大个数
  2470. param: str continuation_token: list时指定的起始标记
  2471. :return: :class:`ListAccessPointResult <oss2.models.ListAccessPointResult>`
  2472. """
  2473. logger.debug("Start to list bucket access point: {0}".format(self.bucket_name))
  2474. resp = self.__do_bucket('GET', params={Bucket.ACCESS_POINT: '', 'max-keys': str(max_keys), 'continuation-token': continuation_token})
  2475. logger.debug("query list bucket access point done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2476. return self._parse_result(resp, xml_utils.parse_list_access_point_result, ListAccessPointResult)
  2477. def put_access_point_policy(self, accessPointName, accessPointPolicy):
  2478. """设置接入点策略
  2479. :param str accessPointName: 接入点名称
  2480. :param str accessPointPolicy : 接入点策略
  2481. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2482. """
  2483. logger.debug("Start to put access point policy, bucket: {0}, accessPointPolicy: {1}".format(self.bucket_name, accessPointPolicy))
  2484. headers = http.CaseInsensitiveDict()
  2485. headers['x-oss-access-point-name'] = accessPointName
  2486. resp = self.__do_bucket('PUT', data=accessPointPolicy, params={Bucket.ACCESS_POINT_POLICY: ''}, headers=headers)
  2487. logger.debug("Create access point policy done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2488. return RequestResult(resp)
  2489. def get_access_point_policy(self, accessPointName):
  2490. """获取接入点策略
  2491. :param str accessPointName: 接入点名称
  2492. :return: :class:`GetAccessPointPolicyResult <oss2.models.GetAccessPointPolicyResult>`
  2493. """
  2494. logger.debug("Start to get access point policy, bucket: {0}".format(self.bucket_name))
  2495. headers = http.CaseInsensitiveDict()
  2496. headers['x-oss-access-point-name'] = accessPointName
  2497. resp = self.__do_bucket('GET', params={Bucket.ACCESS_POINT_POLICY: ''}, headers=headers)
  2498. logger.debug("Get access point policy done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2499. return GetAccessPointPolicyResult(resp)
  2500. def delete_access_point_policy(self, accessPointName):
  2501. """删除接入点策略
  2502. :param str accessPointName: 接入点名称
  2503. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2504. """
  2505. logger.debug("Start to delete access point policy, bucket: {0}".format(self.bucket_name))
  2506. headers = http.CaseInsensitiveDict()
  2507. headers['x-oss-access-point-name'] = accessPointName
  2508. resp = self.__do_bucket('DELETE', params={Bucket.ACCESS_POINT_POLICY: ''}, headers=headers)
  2509. logger.debug("Delete access point policy done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2510. return RequestResult(resp)
  2511. def put_bucket_public_access_block(self, block_public_access=False):
  2512. """为Bucket开启阻止公共访问。
  2513. :param bool block_public_access : 是否开启阻止公共访问。
  2514. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2515. """
  2516. logger.debug("Start to bucket put public access block, bucket: {0}, enabled: {1}."
  2517. .format(self.bucket_name, block_public_access))
  2518. data = xml_utils.to_put_public_access_block_request(block_public_access)
  2519. resp = self.__do_bucket('PUT', data=data, params={Bucket.PUBLIC_ACCESS_BLOCK: ''})
  2520. logger.debug("bucket public access block done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2521. return RequestResult(resp)
  2522. def get_bucket_public_access_block(self):
  2523. """获取指定Bucket的阻止公共访问配置信息。
  2524. :return: :class:`GetBucketPublicAccessBlockResult <oss2.models.GetBucketPublicAccessBlockResult>`
  2525. """
  2526. logger.debug("Start to get bucket public access block: {0}".format(self.bucket_name))
  2527. resp = self.__do_bucket('GET', params={Bucket.PUBLIC_ACCESS_BLOCK: ''})
  2528. logger.debug("Get bucket public access block done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2529. return self._parse_result(resp, xml_utils.parse_get_public_access_block_result, GetBucketPublicAccessBlockResult)
  2530. def delete_bucket_public_access_block(self):
  2531. """删除指定Bucket的阻止公共访问配置信息。
  2532. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2533. """
  2534. logger.debug("Start to delete bucket public access block, bucket: {0}".format(self.bucket_name))
  2535. resp = self.__do_bucket('DELETE', params={Bucket.PUBLIC_ACCESS_BLOCK: ''})
  2536. logger.debug("Delete bucket public access block done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2537. return RequestResult(resp)
  2538. def put_access_point_public_access_block(self, access_point_name, block_public_access=False):
  2539. """为接入点开启阻止公共访问。
  2540. :param bool block_public_access : 是否开启阻止公共访问。
  2541. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2542. """
  2543. logger.debug("Start to put access point public access block, bucket: {0}, access point name: {1}, block public access: {2}."
  2544. .format(self.bucket_name, access_point_name, block_public_access))
  2545. data = xml_utils.to_put_public_access_block_request(block_public_access)
  2546. resp = self.__do_bucket('PUT', data=data, params={Bucket.PUBLIC_ACCESS_BLOCK: '', Bucket.OSS_ACCESS_POINT_NAME: access_point_name})
  2547. logger.debug("access point public access block done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2548. return RequestResult(resp)
  2549. def get_access_point_public_access_block(self, access_point_name):
  2550. """获取指定接入点的阻止公共访问配置信息。
  2551. :return: :class:`GetBucketPublicAccessBlockResult <oss2.models.GetBucketPublicAccessBlockResult>`
  2552. """
  2553. logger.debug("Start to get access point public access block: {0}, access point name: {1}.".format(self.bucket_name, access_point_name))
  2554. resp = self.__do_bucket('GET', params={Bucket.PUBLIC_ACCESS_BLOCK: '', Bucket.OSS_ACCESS_POINT_NAME: access_point_name})
  2555. logger.debug("Get access point public access block done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2556. return self._parse_result(resp, xml_utils.parse_get_public_access_block_result, GetBucketPublicAccessBlockResult)
  2557. def delete_access_point_public_access_block(self, access_point_name):
  2558. """删除指定接入点的阻止公共访问配置信息。
  2559. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2560. """
  2561. logger.debug("Start to delete access point public access block, bucket: {0}, access point name: {1}.".format(self.bucket_name, access_point_name))
  2562. resp = self.__do_bucket('DELETE', params={Bucket.PUBLIC_ACCESS_BLOCK: '', Bucket.OSS_ACCESS_POINT_NAME: access_point_name})
  2563. logger.debug("Delete access point public access block done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2564. return RequestResult(resp)
  2565. def put_bucket_requester_qos_info(self, uid, qos_configuration):
  2566. """修改请求者在Bucket上的流控配置。
  2567. :param str uid: 请求者UID
  2568. :param qos_configuration :class:`QoSConfiguration <oss2.models.QoSConfiguration>`
  2569. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2570. """
  2571. logger.debug("Start to put bucket requester qos info, bucket: {0}, uid: {1}, qos_configuration: {2}."
  2572. .format(self.bucket_name, uid, qos_configuration))
  2573. if not uid:
  2574. raise ClientError('uid should not be empty')
  2575. data = xml_utils.to_put_qos_info(qos_configuration)
  2576. resp = self.__do_bucket('PUT', data=data, params={Bucket.REQUESTER_QOS_INFO: '', Bucket.QOS_REQUESTER: uid})
  2577. logger.debug("put bucket requester qos info done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2578. return RequestResult(resp)
  2579. def get_bucket_requester_qos_info(self, uid):
  2580. """获取请求者在Bucket上的流控配置。
  2581. :return: :class:`RequesterQoSInfoResult <oss2.models.RequesterQoSInfoResult>`
  2582. """
  2583. logger.debug("Start to get bucket requester qos info: {0}, uid: {1}.".format(self.bucket_name, uid))
  2584. if not uid:
  2585. raise ClientError('uid should not be empty')
  2586. resp = self.__do_bucket('GET', params={Bucket.REQUESTER_QOS_INFO: '', Bucket.QOS_REQUESTER: uid})
  2587. logger.debug("Get bucket requester qos info, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2588. return self._parse_result(resp, xml_utils.parse_get_requester_qos_info, RequesterQoSInfoResult)
  2589. def list_bucket_requester_qos_infos(self, continuation_token='', max_keys=100):
  2590. """列举所有对该Bucket的请求者流控配置。
  2591. :param str continuation_token: 分页标志,首次调用传空串
  2592. :param int max_keys: 最多返回数目
  2593. :return: :class:`ListBucketRequesterQoSInfosResult <oss2.models.ListBucketRequesterQoSInfosResult>`
  2594. """
  2595. logger.debug("Start to do query list bucket requester qos infos: {0}".format(self.bucket_name))
  2596. resp = self.__do_bucket('GET', params={Bucket.REQUESTER_QOS_INFO: '', 'continuation-token': continuation_token, 'max-keys': str(max_keys)})
  2597. logger.debug("query list bucket requester qos infos done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2598. return self._parse_result(resp, xml_utils.parse_list_bucket_requester_qos_infos, ListBucketRequesterQoSInfosResult)
  2599. def delete_bucket_requester_qos_info(self, uid):
  2600. """删除在Bucket上的请求者流控配置。
  2601. :return: :class:`RequestResult <oss2.models.RequestResult>`
  2602. """
  2603. logger.debug("Start to delete bucket requester qos info, bucket: {0}, uid: {1}.".format(self.bucket_name, uid))
  2604. if not uid:
  2605. raise ClientError('uid should not be empty')
  2606. resp = self.__do_bucket('DELETE', params={Bucket.REQUESTER_QOS_INFO: '', Bucket.QOS_REQUESTER: uid})
  2607. logger.debug("Delete bucket requester qos info done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
  2608. return RequestResult(resp)
  2609. def __do_object(self, method, key, **kwargs):
  2610. if not self.bucket_name:
  2611. raise ClientError("Bucket name should not be null or empty.")
  2612. if not key:
  2613. raise ClientError("key should not be null or empty.")
  2614. return self._do(method, self.bucket_name, key, **kwargs)
  2615. def __do_bucket(self, method, **kwargs):
  2616. return self._do(method, self.bucket_name, '', **kwargs)
  2617. def __convert_data(self, klass, converter, data):
  2618. if isinstance(data, klass):
  2619. return converter(data)
  2620. else:
  2621. return data
  2622. def _normalize_endpoint(endpoint):
  2623. url = endpoint
  2624. if not endpoint.startswith('http://') and not endpoint.startswith('https://'):
  2625. url = 'http://' + endpoint
  2626. p = urlparse(url)
  2627. if p.port is not None:
  2628. return p.scheme + '://' + p.hostname + ':' + str(p.port)
  2629. else:
  2630. return p.scheme + '://' + p.hostname
  2631. _ENDPOINT_TYPE_ALIYUN = 0
  2632. _ENDPOINT_TYPE_CNAME = 1
  2633. _ENDPOINT_TYPE_IP = 2
  2634. _ENDPOINT_TYPE_PATH_STYLE = 3
  2635. def _make_range_string(range):
  2636. if range is None:
  2637. return ''
  2638. start = range[0]
  2639. last = range[1]
  2640. if start is None and last is None:
  2641. return ''
  2642. return 'bytes=' + _range(start, last)
  2643. def _range(start, last):
  2644. def to_str(pos):
  2645. if pos is None:
  2646. return ''
  2647. else:
  2648. return str(pos)
  2649. return to_str(start) + '-' + to_str(last)
  2650. def _determine_endpoint_type(netloc, is_cname, bucket_name, is_path_style):
  2651. if utils.is_ip_or_localhost(netloc):
  2652. return _ENDPOINT_TYPE_IP
  2653. if is_cname:
  2654. return _ENDPOINT_TYPE_CNAME
  2655. if is_path_style:
  2656. return _ENDPOINT_TYPE_PATH_STYLE
  2657. if utils.is_valid_bucket_name(bucket_name):
  2658. return _ENDPOINT_TYPE_ALIYUN
  2659. else:
  2660. return _ENDPOINT_TYPE_IP
  2661. class _UrlMaker(object):
  2662. def __init__(self, endpoint, is_cname, is_path_style):
  2663. p = urlparse(endpoint)
  2664. self.scheme = p.scheme
  2665. self.netloc = p.netloc
  2666. self.is_cname = is_cname
  2667. self.is_path_style = is_path_style
  2668. def __call__(self, bucket_name, key, slash_safe=False):
  2669. self.type = _determine_endpoint_type(self.netloc, self.is_cname, bucket_name, self.is_path_style)
  2670. safe = '/' if slash_safe is True else ''
  2671. key = urlquote(key, safe=safe)
  2672. if self.type == _ENDPOINT_TYPE_CNAME:
  2673. return '{0}://{1}/{2}'.format(self.scheme, self.netloc, key)
  2674. if self.type == _ENDPOINT_TYPE_IP or self.type == _ENDPOINT_TYPE_PATH_STYLE:
  2675. if bucket_name:
  2676. return '{0}://{1}/{2}/{3}'.format(self.scheme, self.netloc, bucket_name, key)
  2677. else:
  2678. return '{0}://{1}/{2}'.format(self.scheme, self.netloc, key)
  2679. if not bucket_name:
  2680. assert not key
  2681. return '{0}://{1}'.format(self.scheme, self.netloc)
  2682. return '{0}://{1}.{2}/{3}'.format(self.scheme, bucket_name, self.netloc, key)