com.googler.python 1.0.7 → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (354) hide show
  1. package/package.json +4 -2
  2. package/python3.4.2/lib/python3.4/site-packages/pip/__init__.py +1 -277
  3. package/python3.4.2/lib/python3.4/site-packages/pip/__main__.py +19 -7
  4. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/__init__.py +246 -0
  5. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/basecommand.py +373 -0
  6. package/python3.4.2/lib/python3.4/site-packages/pip/{baseparser.py → _internal/baseparser.py} +240 -224
  7. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/build_env.py +92 -0
  8. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/cache.py +202 -0
  9. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/cmdoptions.py +609 -0
  10. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/commands/__init__.py +79 -0
  11. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/commands/check.py +42 -0
  12. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/commands/completion.py +94 -0
  13. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/commands/configuration.py +227 -0
  14. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/commands/download.py +233 -0
  15. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/commands/freeze.py +96 -0
  16. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/commands/hash.py +57 -0
  17. package/python3.4.2/lib/python3.4/site-packages/pip/{commands → _internal/commands}/help.py +36 -33
  18. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/commands/install.py +477 -0
  19. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/commands/list.py +343 -0
  20. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/commands/search.py +135 -0
  21. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/commands/show.py +164 -0
  22. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/commands/uninstall.py +71 -0
  23. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/commands/wheel.py +179 -0
  24. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/compat.py +235 -0
  25. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/configuration.py +378 -0
  26. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/download.py +922 -0
  27. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/exceptions.py +249 -0
  28. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/index.py +1117 -0
  29. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/locations.py +194 -0
  30. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/models/__init__.py +4 -0
  31. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/models/index.py +15 -0
  32. package/python3.4.2/lib/python3.4/site-packages/pip/{_vendor/requests/packages/urllib3/contrib → _internal/operations}/__init__.py +0 -0
  33. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/operations/check.py +106 -0
  34. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/operations/freeze.py +252 -0
  35. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/operations/prepare.py +378 -0
  36. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/pep425tags.py +317 -0
  37. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/req/__init__.py +69 -0
  38. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/req/req_file.py +338 -0
  39. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/req/req_install.py +1115 -0
  40. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/req/req_set.py +164 -0
  41. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/req/req_uninstall.py +455 -0
  42. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/resolve.py +354 -0
  43. package/python3.4.2/lib/python3.4/site-packages/pip/{status_codes.py → _internal/status_codes.py} +8 -6
  44. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/utils/__init__.py +0 -0
  45. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/utils/appdirs.py +258 -0
  46. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/utils/deprecation.py +77 -0
  47. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/utils/encoding.py +33 -0
  48. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/utils/filesystem.py +28 -0
  49. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/utils/glibc.py +84 -0
  50. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/utils/hashes.py +94 -0
  51. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/utils/logging.py +132 -0
  52. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/utils/misc.py +851 -0
  53. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/utils/outdated.py +163 -0
  54. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/utils/packaging.py +70 -0
  55. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/utils/setuptools_build.py +8 -0
  56. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/utils/temp_dir.py +82 -0
  57. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/utils/typing.py +29 -0
  58. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/utils/ui.py +421 -0
  59. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/vcs/__init__.py +471 -0
  60. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/vcs/bazaar.py +113 -0
  61. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/vcs/git.py +311 -0
  62. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/vcs/mercurial.py +105 -0
  63. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/vcs/subversion.py +271 -0
  64. package/python3.4.2/lib/python3.4/site-packages/pip/_internal/wheel.py +817 -0
  65. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/__init__.py +109 -8
  66. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/appdirs.py +604 -0
  67. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/cachecontrol/__init__.py +11 -0
  68. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/cachecontrol/_cmd.py +60 -0
  69. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/cachecontrol/adapter.py +134 -0
  70. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/cachecontrol/cache.py +39 -0
  71. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/cachecontrol/caches/__init__.py +2 -0
  72. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/cachecontrol/caches/file_cache.py +133 -0
  73. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/cachecontrol/caches/redis_cache.py +43 -0
  74. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/cachecontrol/compat.py +29 -0
  75. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/cachecontrol/controller.py +373 -0
  76. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/cachecontrol/filewrapper.py +78 -0
  77. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/cachecontrol/heuristics.py +138 -0
  78. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/cachecontrol/serialize.py +194 -0
  79. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/cachecontrol/wrapper.py +27 -0
  80. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/certifi/__init__.py +3 -0
  81. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/certifi/__main__.py +2 -0
  82. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests → certifi}/cacert.pem +1765 -2358
  83. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/certifi/core.py +37 -0
  84. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/chardet → chardet}/__init__.py +39 -32
  85. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/chardet/big5freq.py +386 -0
  86. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/chardet → chardet}/big5prober.py +47 -42
  87. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/chardet → chardet}/chardistribution.py +233 -231
  88. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/chardet/charsetgroupprober.py +106 -0
  89. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/chardet/charsetprober.py +145 -0
  90. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/chardet/cli/__init__.py +1 -0
  91. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/chardet/cli/chardetect.py +85 -0
  92. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/chardet/codingstatemachine.py +88 -0
  93. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/chardet → chardet}/compat.py +34 -34
  94. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/chardet → chardet}/cp949prober.py +49 -44
  95. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/chardet/enums.py +76 -0
  96. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/chardet/escprober.py +101 -0
  97. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/chardet/escsm.py +246 -0
  98. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/chardet/eucjpprober.py +92 -0
  99. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/chardet/euckrfreq.py +195 -0
  100. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/chardet → chardet}/euckrprober.py +47 -42
  101. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/chardet → chardet}/euctwfreq.py +387 -428
  102. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/chardet → chardet}/euctwprober.py +46 -41
  103. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/chardet → chardet}/gb2312freq.py +283 -472
  104. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/chardet → chardet}/gb2312prober.py +46 -41
  105. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/chardet → chardet}/hebrewprober.py +292 -283
  106. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/chardet → chardet}/jisfreq.py +325 -569
  107. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/chardet → chardet}/jpcntx.py +233 -219
  108. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/chardet → chardet}/langbulgarianmodel.py +228 -229
  109. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/chardet → chardet}/langcyrillicmodel.py +333 -329
  110. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/chardet → chardet}/langgreekmodel.py +225 -225
  111. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/chardet → chardet}/langhebrewmodel.py +200 -201
  112. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/chardet → chardet}/langhungarianmodel.py +225 -225
  113. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/chardet → chardet}/langthaimodel.py +199 -200
  114. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/chardet/langturkishmodel.py +193 -0
  115. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/chardet → chardet}/latin1prober.py +145 -139
  116. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/chardet/mbcharsetprober.py +91 -0
  117. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/chardet → chardet}/mbcsgroupprober.py +54 -54
  118. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/chardet/mbcssm.py +572 -0
  119. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/chardet/sbcharsetprober.py +132 -0
  120. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/chardet → chardet}/sbcsgroupprober.py +73 -69
  121. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/chardet/sjisprober.py +92 -0
  122. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/chardet/universaldetector.py +286 -0
  123. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/chardet → chardet}/utf8prober.py +82 -76
  124. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/chardet/version.py +9 -0
  125. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/colorama/__init__.py +7 -7
  126. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/colorama/ansi.py +102 -50
  127. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/colorama/ansitowin32.py +236 -190
  128. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/colorama/initialise.py +82 -56
  129. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/colorama/win32.py +156 -137
  130. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/colorama/winterm.py +162 -120
  131. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/distlib/__init__.py +23 -23
  132. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/distlib/_backport/__init__.py +6 -6
  133. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/distlib/_backport/misc.py +41 -41
  134. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/distlib/_backport/shutil.py +761 -761
  135. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/distlib/_backport/sysconfig.cfg +84 -84
  136. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/distlib/_backport/sysconfig.py +788 -788
  137. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/distlib/_backport/tarfile.py +2607 -2607
  138. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/distlib/compat.py +1117 -1064
  139. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/distlib/database.py +1318 -1301
  140. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/distlib/index.py +516 -488
  141. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/distlib/locators.py +1292 -1194
  142. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/distlib/manifest.py +393 -364
  143. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/distlib/markers.py +131 -190
  144. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/distlib/metadata.py +1068 -1026
  145. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/distlib/resources.py +355 -317
  146. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/distlib/scripts.py +415 -323
  147. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/distlib/t32.exe +0 -0
  148. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/distlib/t64.exe +0 -0
  149. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/distlib/util.py +1755 -1575
  150. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/distlib/version.py +736 -721
  151. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/distlib/w32.exe +0 -0
  152. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/distlib/w64.exe +0 -0
  153. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/distlib/wheel.py +984 -958
  154. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/distro.py +1104 -0
  155. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/__init__.py +35 -23
  156. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/{ihatexml.py → _ihatexml.py} +288 -285
  157. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/{inputstream.py → _inputstream.py} +923 -881
  158. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/{tokenizer.py → _tokenizer.py} +1721 -1731
  159. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/{trie → _trie}/__init__.py +14 -12
  160. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/{trie → _trie}/_base.py +37 -37
  161. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/{trie → _trie}/datrie.py +44 -44
  162. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/{trie → _trie}/py.py +67 -67
  163. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/{utils.py → _utils.py} +124 -82
  164. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/constants.py +2947 -3104
  165. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/filters/alphabeticalattributes.py +29 -20
  166. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/filters/{_base.py → base.py} +12 -12
  167. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/filters/inject_meta_charset.py +73 -65
  168. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/filters/lint.py +93 -93
  169. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/filters/optionaltags.py +207 -205
  170. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/filters/sanitizer.py +896 -12
  171. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/filters/whitespace.py +38 -38
  172. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/html5parser.py +2791 -2713
  173. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/serializer.py +409 -0
  174. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/treeadapters/__init__.py +30 -0
  175. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/treeadapters/genshi.py +54 -0
  176. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/treeadapters/sax.py +50 -44
  177. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/treebuilders/__init__.py +88 -76
  178. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/treebuilders/{_base.py → base.py} +417 -377
  179. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/treebuilders/dom.py +236 -227
  180. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/treebuilders/etree.py +340 -337
  181. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/treebuilders/etree_lxml.py +366 -369
  182. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/treewalkers/__init__.py +154 -57
  183. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/treewalkers/{_base.py → base.py} +252 -200
  184. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/treewalkers/dom.py +43 -46
  185. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/treewalkers/etree.py +130 -138
  186. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/treewalkers/{lxmletree.py → etree_lxml.py} +213 -208
  187. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/treewalkers/{genshistream.py → genshi.py} +69 -69
  188. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/idna/__init__.py +2 -0
  189. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/idna/codec.py +118 -0
  190. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/idna/compat.py +12 -0
  191. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/idna/core.py +387 -0
  192. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/idna/idnadata.py +1585 -0
  193. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/idna/intranges.py +53 -0
  194. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/idna/package_data.py +2 -0
  195. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/idna/uts46data.py +7634 -0
  196. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/ipaddress.py +2419 -0
  197. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/lockfile/__init__.py +347 -0
  198. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/lockfile/linklockfile.py +73 -0
  199. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/lockfile/mkdirlockfile.py +84 -0
  200. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/lockfile/pidlockfile.py +190 -0
  201. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/lockfile/sqlitelockfile.py +156 -0
  202. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/lockfile/symlinklockfile.py +70 -0
  203. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/msgpack/__init__.py +66 -0
  204. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/msgpack/_version.py +1 -0
  205. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/msgpack/exceptions.py +41 -0
  206. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/msgpack/fallback.py +971 -0
  207. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/packaging/__about__.py +21 -0
  208. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/packaging/__init__.py +14 -0
  209. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/packaging/_compat.py +30 -0
  210. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/packaging/_structures.py +70 -0
  211. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/packaging/markers.py +301 -0
  212. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/packaging/requirements.py +130 -0
  213. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/packaging/specifiers.py +774 -0
  214. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/packaging/utils.py +63 -0
  215. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/packaging/version.py +441 -0
  216. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{pkg_resources.py → pkg_resources/__init__.py} +3125 -2762
  217. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/pkg_resources/py31compat.py +22 -0
  218. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/progress/__init__.py +127 -0
  219. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/progress/bar.py +88 -0
  220. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/progress/counter.py +48 -0
  221. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/progress/helpers.py +91 -0
  222. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/progress/spinner.py +44 -0
  223. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/pyparsing.py +5720 -0
  224. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/pytoml/__init__.py +3 -0
  225. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/pytoml/core.py +13 -0
  226. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/pytoml/parser.py +374 -0
  227. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/pytoml/writer.py +127 -0
  228. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/__init__.py +123 -77
  229. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/__version__.py +14 -0
  230. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/_internal_utils.py +42 -0
  231. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/adapters.py +525 -388
  232. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/api.py +152 -120
  233. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/auth.py +293 -193
  234. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/certs.py +18 -24
  235. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/compat.py +73 -115
  236. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/cookies.py +542 -454
  237. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/exceptions.py +122 -75
  238. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/help.py +120 -0
  239. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/hooks.py +34 -45
  240. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/models.py +948 -803
  241. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages.py +16 -0
  242. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/sessions.py +737 -637
  243. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/status_codes.py +91 -88
  244. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/structures.py +105 -127
  245. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/utils.py +904 -673
  246. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/retrying.py +267 -0
  247. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/six.py +891 -646
  248. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/__init__.py +97 -0
  249. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/_collections.py +319 -0
  250. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/connection.py +373 -0
  251. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/urllib3 → urllib3}/connectionpool.py +905 -710
  252. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/contrib/__init__.py +0 -0
  253. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__init__.py +0 -0
  254. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py +593 -0
  255. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py +343 -0
  256. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/contrib/appengine.py +296 -0
  257. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/urllib3 → urllib3}/contrib/ntlmpool.py +112 -120
  258. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py +455 -0
  259. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/contrib/securetransport.py +810 -0
  260. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/contrib/socks.py +188 -0
  261. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/exceptions.py +246 -0
  262. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/urllib3 → urllib3}/fields.py +178 -177
  263. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/urllib3 → urllib3}/filepost.py +94 -100
  264. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/urllib3 → urllib3}/packages/__init__.py +5 -4
  265. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/packages/backports/__init__.py +0 -0
  266. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py +53 -0
  267. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/urllib3 → urllib3}/packages/ordered_dict.py +259 -260
  268. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/packages/six.py +868 -0
  269. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/urllib3 → urllib3}/packages/ssl_match_hostname/__init__.py +19 -13
  270. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/urllib3 → urllib3}/packages/ssl_match_hostname/_implementation.py +157 -105
  271. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/poolmanager.py +440 -0
  272. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/urllib3 → urllib3}/request.py +148 -141
  273. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/response.py +626 -0
  274. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/util/__init__.py +54 -0
  275. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/util/connection.py +130 -0
  276. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/util/request.py +118 -0
  277. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/util/response.py +81 -0
  278. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/util/retry.py +401 -0
  279. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/util/selectors.py +581 -0
  280. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/util/ssl_.py +341 -0
  281. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/urllib3 → urllib3}/util/timeout.py +242 -234
  282. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/{requests/packages/urllib3 → urllib3}/util/url.py +230 -162
  283. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/urllib3/util/wait.py +40 -0
  284. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/webencodings/__init__.py +342 -0
  285. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/webencodings/labels.py +231 -0
  286. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/webencodings/mklabels.py +59 -0
  287. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/webencodings/tests.py +153 -0
  288. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/webencodings/x_user_defined.py +325 -0
  289. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/_markerlib/__init__.py +0 -16
  290. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/_markerlib/markers.py +0 -119
  291. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/sanitizer.py +0 -271
  292. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/serializer/__init__.py +0 -16
  293. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/serializer/htmlserializer.py +0 -320
  294. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/html5lib/treewalkers/pulldom.py +0 -63
  295. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/re-vendor.py +0 -34
  296. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/__init__.py +0 -3
  297. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/chardet/big5freq.py +0 -925
  298. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/chardet/chardetect.py +0 -46
  299. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/chardet/charsetgroupprober.py +0 -106
  300. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/chardet/charsetprober.py +0 -62
  301. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/chardet/codingstatemachine.py +0 -61
  302. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/chardet/constants.py +0 -39
  303. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/chardet/escprober.py +0 -86
  304. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/chardet/escsm.py +0 -242
  305. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/chardet/eucjpprober.py +0 -90
  306. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/chardet/euckrfreq.py +0 -596
  307. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/chardet/mbcharsetprober.py +0 -86
  308. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/chardet/mbcssm.py +0 -575
  309. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/chardet/sbcharsetprober.py +0 -120
  310. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/chardet/sjisprober.py +0 -91
  311. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/chardet/universaldetector.py +0 -170
  312. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/urllib3/__init__.py +0 -58
  313. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/urllib3/_collections.py +0 -205
  314. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/urllib3/connection.py +0 -204
  315. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/urllib3/contrib/pyopenssl.py +0 -422
  316. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/urllib3/exceptions.py +0 -126
  317. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/urllib3/packages/six.py +0 -385
  318. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/urllib3/poolmanager.py +0 -258
  319. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/urllib3/response.py +0 -308
  320. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/urllib3/util/__init__.py +0 -27
  321. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/urllib3/util/connection.py +0 -45
  322. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/urllib3/util/request.py +0 -68
  323. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/urllib3/util/response.py +0 -13
  324. package/python3.4.2/lib/python3.4/site-packages/pip/_vendor/requests/packages/urllib3/util/ssl_.py +0 -133
  325. package/python3.4.2/lib/python3.4/site-packages/pip/backwardcompat/__init__.py +0 -138
  326. package/python3.4.2/lib/python3.4/site-packages/pip/basecommand.py +0 -201
  327. package/python3.4.2/lib/python3.4/site-packages/pip/cmdoptions.py +0 -371
  328. package/python3.4.2/lib/python3.4/site-packages/pip/commands/__init__.py +0 -88
  329. package/python3.4.2/lib/python3.4/site-packages/pip/commands/bundle.py +0 -42
  330. package/python3.4.2/lib/python3.4/site-packages/pip/commands/completion.py +0 -59
  331. package/python3.4.2/lib/python3.4/site-packages/pip/commands/freeze.py +0 -114
  332. package/python3.4.2/lib/python3.4/site-packages/pip/commands/install.py +0 -314
  333. package/python3.4.2/lib/python3.4/site-packages/pip/commands/list.py +0 -162
  334. package/python3.4.2/lib/python3.4/site-packages/pip/commands/search.py +0 -132
  335. package/python3.4.2/lib/python3.4/site-packages/pip/commands/show.py +0 -80
  336. package/python3.4.2/lib/python3.4/site-packages/pip/commands/uninstall.py +0 -59
  337. package/python3.4.2/lib/python3.4/site-packages/pip/commands/unzip.py +0 -7
  338. package/python3.4.2/lib/python3.4/site-packages/pip/commands/wheel.py +0 -195
  339. package/python3.4.2/lib/python3.4/site-packages/pip/commands/zip.py +0 -351
  340. package/python3.4.2/lib/python3.4/site-packages/pip/download.py +0 -644
  341. package/python3.4.2/lib/python3.4/site-packages/pip/exceptions.py +0 -46
  342. package/python3.4.2/lib/python3.4/site-packages/pip/index.py +0 -990
  343. package/python3.4.2/lib/python3.4/site-packages/pip/locations.py +0 -171
  344. package/python3.4.2/lib/python3.4/site-packages/pip/log.py +0 -276
  345. package/python3.4.2/lib/python3.4/site-packages/pip/pep425tags.py +0 -102
  346. package/python3.4.2/lib/python3.4/site-packages/pip/req.py +0 -1931
  347. package/python3.4.2/lib/python3.4/site-packages/pip/runner.py +0 -18
  348. package/python3.4.2/lib/python3.4/site-packages/pip/util.py +0 -720
  349. package/python3.4.2/lib/python3.4/site-packages/pip/vcs/__init__.py +0 -251
  350. package/python3.4.2/lib/python3.4/site-packages/pip/vcs/bazaar.py +0 -131
  351. package/python3.4.2/lib/python3.4/site-packages/pip/vcs/git.py +0 -194
  352. package/python3.4.2/lib/python3.4/site-packages/pip/vcs/mercurial.py +0 -151
  353. package/python3.4.2/lib/python3.4/site-packages/pip/vcs/subversion.py +0 -273
  354. package/python3.4.2/lib/python3.4/site-packages/pip/wheel.py +0 -560
@@ -1,1575 +1,1755 @@
1
- #
2
- # Copyright (C) 2012-2013 The Python Software Foundation.
3
- # See LICENSE.txt and CONTRIBUTORS.txt.
4
- #
5
- import codecs
6
- from collections import deque
7
- import contextlib
8
- import csv
9
- from glob import iglob as std_iglob
10
- import io
11
- import json
12
- import logging
13
- import os
14
- import py_compile
15
- import re
16
- import shutil
17
- import socket
18
- import ssl
19
- import subprocess
20
- import sys
21
- import tarfile
22
- import tempfile
23
- try:
24
- import threading
25
- except ImportError:
26
- import dummy_threading as threading
27
- import time
28
-
29
- from . import DistlibException
30
- from .compat import (string_types, text_type, shutil, raw_input, StringIO,
31
- cache_from_source, urlopen, httplib, xmlrpclib, splittype,
32
- HTTPHandler, HTTPSHandler as BaseHTTPSHandler,
33
- BaseConfigurator, valid_ident, Container, configparser,
34
- URLError, match_hostname, CertificateError, ZipFile)
35
-
36
- logger = logging.getLogger(__name__)
37
-
38
- #
39
- # Requirement parsing code for name + optional constraints + optional extras
40
- #
41
- # e.g. 'foo >= 1.2, < 2.0 [bar, baz]'
42
- #
43
- # The regex can seem a bit hairy, so we build it up out of smaller pieces
44
- # which are manageable.
45
- #
46
-
47
- COMMA = r'\s*,\s*'
48
- COMMA_RE = re.compile(COMMA)
49
-
50
- IDENT = r'(\w|[.-])+'
51
- EXTRA_IDENT = r'(\*|:(\*|\w+):|' + IDENT + ')'
52
- VERSPEC = IDENT + r'\*?'
53
-
54
- RELOP = '([<>=!~]=)|[<>]'
55
-
56
- #
57
- # The first relop is optional - if absent, will be taken as '~='
58
- #
59
- BARE_CONSTRAINTS = ('(' + RELOP + r')?\s*(' + VERSPEC + ')(' + COMMA + '(' +
60
- RELOP + r')\s*(' + VERSPEC + '))*')
61
-
62
- DIRECT_REF = '(from\s+(?P<diref>.*))'
63
-
64
- #
65
- # Either the bare constraints or the bare constraints in parentheses
66
- #
67
- CONSTRAINTS = (r'\(\s*(?P<c1>' + BARE_CONSTRAINTS + '|' + DIRECT_REF +
68
- r')\s*\)|(?P<c2>' + BARE_CONSTRAINTS + '\s*)')
69
-
70
- EXTRA_LIST = EXTRA_IDENT + '(' + COMMA + EXTRA_IDENT + ')*'
71
- EXTRAS = r'\[\s*(?P<ex>' + EXTRA_LIST + r')?\s*\]'
72
- REQUIREMENT = ('(?P<dn>' + IDENT + r')\s*(' + EXTRAS + r'\s*)?(\s*' +
73
- CONSTRAINTS + ')?$')
74
- REQUIREMENT_RE = re.compile(REQUIREMENT)
75
-
76
- #
77
- # Used to scan through the constraints
78
- #
79
- RELOP_IDENT = '(?P<op>' + RELOP + r')\s*(?P<vn>' + VERSPEC + ')'
80
- RELOP_IDENT_RE = re.compile(RELOP_IDENT)
81
-
82
- def parse_requirement(s):
83
-
84
- def get_constraint(m):
85
- d = m.groupdict()
86
- return d['op'], d['vn']
87
-
88
- result = None
89
- m = REQUIREMENT_RE.match(s)
90
- if m:
91
- d = m.groupdict()
92
- name = d['dn']
93
- cons = d['c1'] or d['c2']
94
- if not d['diref']:
95
- url = None
96
- else:
97
- # direct reference
98
- cons = None
99
- url = d['diref'].strip()
100
- if not cons:
101
- cons = None
102
- constr = ''
103
- rs = d['dn']
104
- else:
105
- if cons[0] not in '<>!=':
106
- cons = '~=' + cons
107
- iterator = RELOP_IDENT_RE.finditer(cons)
108
- cons = [get_constraint(m) for m in iterator]
109
- rs = '%s (%s)' % (name, ', '.join(['%s %s' % con for con in cons]))
110
- if not d['ex']:
111
- extras = None
112
- else:
113
- extras = COMMA_RE.split(d['ex'])
114
- result = Container(name=name, constraints=cons, extras=extras,
115
- requirement=rs, source=s, url=url)
116
- return result
117
-
118
-
119
- def get_resources_dests(resources_root, rules):
120
- """Find destinations for resources files"""
121
-
122
- def get_rel_path(base, path):
123
- # normalizes and returns a lstripped-/-separated path
124
- base = base.replace(os.path.sep, '/')
125
- path = path.replace(os.path.sep, '/')
126
- assert path.startswith(base)
127
- return path[len(base):].lstrip('/')
128
-
129
-
130
- destinations = {}
131
- for base, suffix, dest in rules:
132
- prefix = os.path.join(resources_root, base)
133
- for abs_base in iglob(prefix):
134
- abs_glob = os.path.join(abs_base, suffix)
135
- for abs_path in iglob(abs_glob):
136
- resource_file = get_rel_path(resources_root, abs_path)
137
- if dest is None: # remove the entry if it was here
138
- destinations.pop(resource_file, None)
139
- else:
140
- rel_path = get_rel_path(abs_base, abs_path)
141
- rel_dest = dest.replace(os.path.sep, '/').rstrip('/')
142
- destinations[resource_file] = rel_dest + '/' + rel_path
143
- return destinations
144
-
145
-
146
- def in_venv():
147
- if hasattr(sys, 'real_prefix'):
148
- # virtualenv venvs
149
- result = True
150
- else:
151
- # PEP 405 venvs
152
- result = sys.prefix != getattr(sys, 'base_prefix', sys.prefix)
153
- return result
154
-
155
-
156
- def get_executable():
157
- if sys.platform == 'darwin' and ('__PYVENV_LAUNCHER__'
158
- in os.environ):
159
- result = os.environ['__PYVENV_LAUNCHER__']
160
- else:
161
- result = sys.executable
162
- return result
163
-
164
-
165
- def proceed(prompt, allowed_chars, error_prompt=None, default=None):
166
- p = prompt
167
- while True:
168
- s = raw_input(p)
169
- p = prompt
170
- if not s and default:
171
- s = default
172
- if s:
173
- c = s[0].lower()
174
- if c in allowed_chars:
175
- break
176
- if error_prompt:
177
- p = '%c: %s\n%s' % (c, error_prompt, prompt)
178
- return c
179
-
180
-
181
- def extract_by_key(d, keys):
182
- if isinstance(keys, string_types):
183
- keys = keys.split()
184
- result = {}
185
- for key in keys:
186
- if key in d:
187
- result[key] = d[key]
188
- return result
189
-
190
- def read_exports(stream):
191
- if sys.version_info[0] >= 3:
192
- # needs to be a text stream
193
- stream = codecs.getreader('utf-8')(stream)
194
- # Try to load as JSON, falling back on legacy format
195
- data = stream.read()
196
- stream = StringIO(data)
197
- try:
198
- data = json.load(stream)
199
- result = data['exports']
200
- for group, entries in result.items():
201
- for k, v in entries.items():
202
- s = '%s = %s' % (k, v)
203
- entry = get_export_entry(s)
204
- assert entry is not None
205
- entries[k] = entry
206
- return result
207
- except Exception:
208
- stream.seek(0, 0)
209
- cp = configparser.ConfigParser()
210
- if hasattr(cp, 'read_file'):
211
- cp.read_file(stream)
212
- else:
213
- cp.readfp(stream)
214
- result = {}
215
- for key in cp.sections():
216
- result[key] = entries = {}
217
- for name, value in cp.items(key):
218
- s = '%s = %s' % (name, value)
219
- entry = get_export_entry(s)
220
- assert entry is not None
221
- #entry.dist = self
222
- entries[name] = entry
223
- return result
224
-
225
-
226
- def write_exports(exports, stream):
227
- if sys.version_info[0] >= 3:
228
- # needs to be a text stream
229
- stream = codecs.getwriter('utf-8')(stream)
230
- cp = configparser.ConfigParser()
231
- for k, v in exports.items():
232
- # TODO check k, v for valid values
233
- cp.add_section(k)
234
- for entry in v.values():
235
- if entry.suffix is None:
236
- s = entry.prefix
237
- else:
238
- s = '%s:%s' % (entry.prefix, entry.suffix)
239
- if entry.flags:
240
- s = '%s [%s]' % (s, ', '.join(entry.flags))
241
- cp.set(k, entry.name, s)
242
- cp.write(stream)
243
-
244
-
245
- @contextlib.contextmanager
246
- def tempdir():
247
- td = tempfile.mkdtemp()
248
- try:
249
- yield td
250
- finally:
251
- shutil.rmtree(td)
252
-
253
- @contextlib.contextmanager
254
- def chdir(d):
255
- cwd = os.getcwd()
256
- try:
257
- os.chdir(d)
258
- yield
259
- finally:
260
- os.chdir(cwd)
261
-
262
-
263
- @contextlib.contextmanager
264
- def socket_timeout(seconds=15):
265
- cto = socket.getdefaulttimeout()
266
- try:
267
- socket.setdefaulttimeout(seconds)
268
- yield
269
- finally:
270
- socket.setdefaulttimeout(cto)
271
-
272
-
273
- class cached_property(object):
274
- def __init__(self, func):
275
- self.func = func
276
- #for attr in ('__name__', '__module__', '__doc__'):
277
- # setattr(self, attr, getattr(func, attr, None))
278
-
279
- def __get__(self, obj, cls=None):
280
- if obj is None:
281
- return self
282
- value = self.func(obj)
283
- object.__setattr__(obj, self.func.__name__, value)
284
- #obj.__dict__[self.func.__name__] = value = self.func(obj)
285
- return value
286
-
287
- def convert_path(pathname):
288
- """Return 'pathname' as a name that will work on the native filesystem.
289
-
290
- The path is split on '/' and put back together again using the current
291
- directory separator. Needed because filenames in the setup script are
292
- always supplied in Unix style, and have to be converted to the local
293
- convention before we can actually use them in the filesystem. Raises
294
- ValueError on non-Unix-ish systems if 'pathname' either starts or
295
- ends with a slash.
296
- """
297
- if os.sep == '/':
298
- return pathname
299
- if not pathname:
300
- return pathname
301
- if pathname[0] == '/':
302
- raise ValueError("path '%s' cannot be absolute" % pathname)
303
- if pathname[-1] == '/':
304
- raise ValueError("path '%s' cannot end with '/'" % pathname)
305
-
306
- paths = pathname.split('/')
307
- while os.curdir in paths:
308
- paths.remove(os.curdir)
309
- if not paths:
310
- return os.curdir
311
- return os.path.join(*paths)
312
-
313
-
314
- class FileOperator(object):
315
- def __init__(self, dry_run=False):
316
- self.dry_run = dry_run
317
- self.ensured = set()
318
- self._init_record()
319
-
320
- def _init_record(self):
321
- self.record = False
322
- self.files_written = set()
323
- self.dirs_created = set()
324
-
325
- def record_as_written(self, path):
326
- if self.record:
327
- self.files_written.add(path)
328
-
329
- def newer(self, source, target):
330
- """Tell if the target is newer than the source.
331
-
332
- Returns true if 'source' exists and is more recently modified than
333
- 'target', or if 'source' exists and 'target' doesn't.
334
-
335
- Returns false if both exist and 'target' is the same age or younger
336
- than 'source'. Raise PackagingFileError if 'source' does not exist.
337
-
338
- Note that this test is not very accurate: files created in the same
339
- second will have the same "age".
340
- """
341
- if not os.path.exists(source):
342
- raise DistlibException("file '%r' does not exist" %
343
- os.path.abspath(source))
344
- if not os.path.exists(target):
345
- return True
346
-
347
- return os.stat(source).st_mtime > os.stat(target).st_mtime
348
-
349
- def copy_file(self, infile, outfile, check=True):
350
- """Copy a file respecting dry-run and force flags.
351
- """
352
- self.ensure_dir(os.path.dirname(outfile))
353
- logger.info('Copying %s to %s', infile, outfile)
354
- if not self.dry_run:
355
- msg = None
356
- if check:
357
- if os.path.islink(outfile):
358
- msg = '%s is a symlink' % outfile
359
- elif os.path.exists(outfile) and not os.path.isfile(outfile):
360
- msg = '%s is a non-regular file' % outfile
361
- if msg:
362
- raise ValueError(msg + ' which would be overwritten')
363
- shutil.copyfile(infile, outfile)
364
- self.record_as_written(outfile)
365
-
366
- def copy_stream(self, instream, outfile, encoding=None):
367
- assert not os.path.isdir(outfile)
368
- self.ensure_dir(os.path.dirname(outfile))
369
- logger.info('Copying stream %s to %s', instream, outfile)
370
- if not self.dry_run:
371
- if encoding is None:
372
- outstream = open(outfile, 'wb')
373
- else:
374
- outstream = codecs.open(outfile, 'w', encoding=encoding)
375
- try:
376
- shutil.copyfileobj(instream, outstream)
377
- finally:
378
- outstream.close()
379
- self.record_as_written(outfile)
380
-
381
- def write_binary_file(self, path, data):
382
- self.ensure_dir(os.path.dirname(path))
383
- if not self.dry_run:
384
- with open(path, 'wb') as f:
385
- f.write(data)
386
- self.record_as_written(path)
387
-
388
- def write_text_file(self, path, data, encoding):
389
- self.ensure_dir(os.path.dirname(path))
390
- if not self.dry_run:
391
- with open(path, 'wb') as f:
392
- f.write(data.encode(encoding))
393
- self.record_as_written(path)
394
-
395
- def set_mode(self, bits, mask, files):
396
- if os.name == 'posix':
397
- # Set the executable bits (owner, group, and world) on
398
- # all the files specified.
399
- for f in files:
400
- if self.dry_run:
401
- logger.info("changing mode of %s", f)
402
- else:
403
- mode = (os.stat(f).st_mode | bits) & mask
404
- logger.info("changing mode of %s to %o", f, mode)
405
- os.chmod(f, mode)
406
-
407
- set_executable_mode = lambda s, f: s.set_mode(0o555, 0o7777, f)
408
-
409
- def ensure_dir(self, path):
410
- path = os.path.abspath(path)
411
- if path not in self.ensured and not os.path.exists(path):
412
- self.ensured.add(path)
413
- d, f = os.path.split(path)
414
- self.ensure_dir(d)
415
- logger.info('Creating %s' % path)
416
- if not self.dry_run:
417
- os.mkdir(path)
418
- if self.record:
419
- self.dirs_created.add(path)
420
-
421
- def byte_compile(self, path, optimize=False, force=False, prefix=None):
422
- dpath = cache_from_source(path, not optimize)
423
- logger.info('Byte-compiling %s to %s', path, dpath)
424
- if not self.dry_run:
425
- if force or self.newer(path, dpath):
426
- if not prefix:
427
- diagpath = None
428
- else:
429
- assert path.startswith(prefix)
430
- diagpath = path[len(prefix):]
431
- py_compile.compile(path, dpath, diagpath, True) # raise error
432
- self.record_as_written(dpath)
433
- return dpath
434
-
435
- def ensure_removed(self, path):
436
- if os.path.exists(path):
437
- if os.path.isdir(path) and not os.path.islink(path):
438
- logger.debug('Removing directory tree at %s', path)
439
- if not self.dry_run:
440
- shutil.rmtree(path)
441
- if self.record:
442
- if path in self.dirs_created:
443
- self.dirs_created.remove(path)
444
- else:
445
- if os.path.islink(path):
446
- s = 'link'
447
- else:
448
- s = 'file'
449
- logger.debug('Removing %s %s', s, path)
450
- if not self.dry_run:
451
- os.remove(path)
452
- if self.record:
453
- if path in self.files_written:
454
- self.files_written.remove(path)
455
-
456
- def is_writable(self, path):
457
- result = False
458
- while not result:
459
- if os.path.exists(path):
460
- result = os.access(path, os.W_OK)
461
- break
462
- parent = os.path.dirname(path)
463
- if parent == path:
464
- break
465
- path = parent
466
- return result
467
-
468
- def commit(self):
469
- """
470
- Commit recorded changes, turn off recording, return
471
- changes.
472
- """
473
- assert self.record
474
- result = self.files_written, self.dirs_created
475
- self._init_record()
476
- return result
477
-
478
- def rollback(self):
479
- if not self.dry_run:
480
- for f in list(self.files_written):
481
- if os.path.exists(f):
482
- os.remove(f)
483
- # dirs should all be empty now, except perhaps for
484
- # __pycache__ subdirs
485
- # reverse so that subdirs appear before their parents
486
- dirs = sorted(self.dirs_created, reverse=True)
487
- for d in dirs:
488
- flist = os.listdir(d)
489
- if flist:
490
- assert flist == ['__pycache__']
491
- sd = os.path.join(d, flist[0])
492
- os.rmdir(sd)
493
- os.rmdir(d) # should fail if non-empty
494
- self._init_record()
495
-
496
- def resolve(module_name, dotted_path):
497
- if module_name in sys.modules:
498
- mod = sys.modules[module_name]
499
- else:
500
- mod = __import__(module_name)
501
- if dotted_path is None:
502
- result = mod
503
- else:
504
- parts = dotted_path.split('.')
505
- result = getattr(mod, parts.pop(0))
506
- for p in parts:
507
- result = getattr(result, p)
508
- return result
509
-
510
-
511
- class ExportEntry(object):
512
- def __init__(self, name, prefix, suffix, flags):
513
- self.name = name
514
- self.prefix = prefix
515
- self.suffix = suffix
516
- self.flags = flags
517
-
518
- @cached_property
519
- def value(self):
520
- return resolve(self.prefix, self.suffix)
521
-
522
- def __repr__(self):
523
- return '<ExportEntry %s = %s:%s %s>' % (self.name, self.prefix,
524
- self.suffix, self.flags)
525
-
526
- def __eq__(self, other):
527
- if not isinstance(other, ExportEntry):
528
- result = False
529
- else:
530
- result = (self.name == other.name and
531
- self.prefix == other.prefix and
532
- self.suffix == other.suffix and
533
- self.flags == other.flags)
534
- return result
535
-
536
- __hash__ = object.__hash__
537
-
538
-
539
- ENTRY_RE = re.compile(r'''(?P<name>(\w|[-.])+)
540
- \s*=\s*(?P<callable>(\w+)([:\.]\w+)*)
541
- \s*(\[\s*(?P<flags>\w+(=\w+)?(,\s*\w+(=\w+)?)*)\s*\])?
542
- ''', re.VERBOSE)
543
-
544
-
545
- def get_export_entry(specification):
546
- m = ENTRY_RE.search(specification)
547
- if not m:
548
- result = None
549
- if '[' in specification or ']' in specification:
550
- raise DistlibException('Invalid specification '
551
- '%r' % specification)
552
- else:
553
- d = m.groupdict()
554
- name = d['name']
555
- path = d['callable']
556
- colons = path.count(':')
557
- if colons == 0:
558
- prefix, suffix = path, None
559
- else:
560
- if colons != 1:
561
- raise DistlibException('Invalid specification '
562
- '%r' % specification)
563
- prefix, suffix = path.split(':')
564
- flags = d['flags']
565
- if flags is None:
566
- if '[' in specification or ']' in specification:
567
- raise DistlibException('Invalid specification '
568
- '%r' % specification)
569
- flags = []
570
- else:
571
- flags = [f.strip() for f in flags.split(',')]
572
- result = ExportEntry(name, prefix, suffix, flags)
573
- return result
574
-
575
-
576
- def get_cache_base(suffix=None):
577
- """
578
- Return the default base location for distlib caches. If the directory does
579
- not exist, it is created. Use the suffix provided for the base directory,
580
- and default to '.distlib' if it isn't provided.
581
-
582
- On Windows, if LOCALAPPDATA is defined in the environment, then it is
583
- assumed to be a directory, and will be the parent directory of the result.
584
- On POSIX, and on Windows if LOCALAPPDATA is not defined, the user's home
585
- directory - using os.expanduser('~') - will be the parent directory of
586
- the result.
587
-
588
- The result is just the directory '.distlib' in the parent directory as
589
- determined above, or with the name specified with ``suffix``.
590
- """
591
- if suffix is None:
592
- suffix = '.distlib'
593
- if os.name == 'nt' and 'LOCALAPPDATA' in os.environ:
594
- result = os.path.expandvars('$localappdata')
595
- else:
596
- # Assume posix, or old Windows
597
- result = os.path.expanduser('~')
598
- # we use 'isdir' instead of 'exists', because we want to
599
- # fail if there's a file with that name
600
- if os.path.isdir(result):
601
- usable = os.access(result, os.W_OK)
602
- if not usable:
603
- logger.warning('Directory exists but is not writable: %s', result)
604
- else:
605
- try:
606
- os.makedirs(result)
607
- usable = True
608
- except OSError:
609
- logger.warning('Unable to create %s', result, exc_info=True)
610
- usable = False
611
- if not usable:
612
- result = tempfile.mkdtemp()
613
- logger.warning('Default location unusable, using %s', result)
614
- return os.path.join(result, suffix)
615
-
616
-
617
- def path_to_cache_dir(path):
618
- """
619
- Convert an absolute path to a directory name for use in a cache.
620
-
621
- The algorithm used is:
622
-
623
- #. On Windows, any ``':'`` in the drive is replaced with ``'---'``.
624
- #. Any occurrence of ``os.sep`` is replaced with ``'--'``.
625
- #. ``'.cache'`` is appended.
626
- """
627
- d, p = os.path.splitdrive(os.path.abspath(path))
628
- if d:
629
- d = d.replace(':', '---')
630
- p = p.replace(os.sep, '--')
631
- return d + p + '.cache'
632
-
633
-
634
- def ensure_slash(s):
635
- if not s.endswith('/'):
636
- return s + '/'
637
- return s
638
-
639
-
640
- def parse_credentials(netloc):
641
- username = password = None
642
- if '@' in netloc:
643
- prefix, netloc = netloc.split('@', 1)
644
- if ':' not in prefix:
645
- username = prefix
646
- else:
647
- username, password = prefix.split(':', 1)
648
- return username, password, netloc
649
-
650
-
651
- def get_process_umask():
652
- result = os.umask(0o22)
653
- os.umask(result)
654
- return result
655
-
656
- def is_string_sequence(seq):
657
- result = True
658
- i = None
659
- for i, s in enumerate(seq):
660
- if not isinstance(s, string_types):
661
- result = False
662
- break
663
- assert i is not None
664
- return result
665
-
666
- PROJECT_NAME_AND_VERSION = re.compile('([a-z0-9_]+([.-][a-z_][a-z0-9_]*)*)-'
667
- '([a-z0-9_.+-]+)', re.I)
668
- PYTHON_VERSION = re.compile(r'-py(\d\.?\d?)')
669
-
670
-
671
- def split_filename(filename, project_name=None):
672
- """
673
- Extract name, version, python version from a filename (no extension)
674
-
675
- Return name, version, pyver or None
676
- """
677
- result = None
678
- pyver = None
679
- m = PYTHON_VERSION.search(filename)
680
- if m:
681
- pyver = m.group(1)
682
- filename = filename[:m.start()]
683
- if project_name and len(filename) > len(project_name) + 1:
684
- m = re.match(re.escape(project_name) + r'\b', filename)
685
- if m:
686
- n = m.end()
687
- result = filename[:n], filename[n + 1:], pyver
688
- if result is None:
689
- m = PROJECT_NAME_AND_VERSION.match(filename)
690
- if m:
691
- result = m.group(1), m.group(3), pyver
692
- return result
693
-
694
- # Allow spaces in name because of legacy dists like "Twisted Core"
695
- NAME_VERSION_RE = re.compile(r'(?P<name>[\w .-]+)\s*'
696
- r'\(\s*(?P<ver>[^\s)]+)\)$')
697
-
698
- def parse_name_and_version(p):
699
- """
700
- A utility method used to get name and version from a string.
701
-
702
- From e.g. a Provides-Dist value.
703
-
704
- :param p: A value in a form 'foo (1.0)'
705
- :return: The name and version as a tuple.
706
- """
707
- m = NAME_VERSION_RE.match(p)
708
- if not m:
709
- raise DistlibException('Ill-formed name/version string: \'%s\'' % p)
710
- d = m.groupdict()
711
- return d['name'].strip().lower(), d['ver']
712
-
713
- def get_extras(requested, available):
714
- result = set()
715
- requested = set(requested or [])
716
- available = set(available or [])
717
- if '*' in requested:
718
- requested.remove('*')
719
- result |= available
720
- for r in requested:
721
- if r == '-':
722
- result.add(r)
723
- elif r.startswith('-'):
724
- unwanted = r[1:]
725
- if unwanted not in available:
726
- logger.warning('undeclared extra: %s' % unwanted)
727
- if unwanted in result:
728
- result.remove(unwanted)
729
- else:
730
- if r not in available:
731
- logger.warning('undeclared extra: %s' % r)
732
- result.add(r)
733
- return result
734
- #
735
- # Extended metadata functionality
736
- #
737
-
738
- def _get_external_data(url):
739
- result = {}
740
- try:
741
- # urlopen might fail if it runs into redirections,
742
- # because of Python issue #13696. Fixed in locators
743
- # using a custom redirect handler.
744
- resp = urlopen(url)
745
- headers = resp.info()
746
- if headers.get('Content-Type') != 'application/json':
747
- logger.debug('Unexpected response for JSON request')
748
- else:
749
- reader = codecs.getreader('utf-8')(resp)
750
- #data = reader.read().decode('utf-8')
751
- #result = json.loads(data)
752
- result = json.load(reader)
753
- except Exception as e:
754
- logger.exception('Failed to get external data for %s: %s', url, e)
755
- return result
756
-
757
-
758
- def get_project_data(name):
759
- url = ('https://www.red-dove.com/pypi/projects/'
760
- '%s/%s/project.json' % (name[0].upper(), name))
761
- result = _get_external_data(url)
762
- return result
763
-
764
- def get_package_data(name, version):
765
- url = ('https://www.red-dove.com/pypi/projects/'
766
- '%s/%s/package-%s.json' % (name[0].upper(), name, version))
767
- return _get_external_data(url)
768
-
769
-
770
- class Cache(object):
771
- """
772
- A class implementing a cache for resources that need to live in the file system
773
- e.g. shared libraries. This class was moved from resources to here because it
774
- could be used by other modules, e.g. the wheel module.
775
- """
776
-
777
- def __init__(self, base):
778
- """
779
- Initialise an instance.
780
-
781
- :param base: The base directory where the cache should be located.
782
- """
783
- # we use 'isdir' instead of 'exists', because we want to
784
- # fail if there's a file with that name
785
- if not os.path.isdir(base):
786
- os.makedirs(base)
787
- if (os.stat(base).st_mode & 0o77) != 0:
788
- logger.warning('Directory \'%s\' is not private', base)
789
- self.base = os.path.abspath(os.path.normpath(base))
790
-
791
- def prefix_to_dir(self, prefix):
792
- """
793
- Converts a resource prefix to a directory name in the cache.
794
- """
795
- return path_to_cache_dir(prefix)
796
-
797
- def clear(self):
798
- """
799
- Clear the cache.
800
- """
801
- not_removed = []
802
- for fn in os.listdir(self.base):
803
- fn = os.path.join(self.base, fn)
804
- try:
805
- if os.path.islink(fn) or os.path.isfile(fn):
806
- os.remove(fn)
807
- elif os.path.isdir(fn):
808
- shutil.rmtree(fn)
809
- except Exception:
810
- not_removed.append(fn)
811
- return not_removed
812
-
813
-
814
- class EventMixin(object):
815
- """
816
- A very simple publish/subscribe system.
817
- """
818
- def __init__(self):
819
- self._subscribers = {}
820
-
821
- def add(self, event, subscriber, append=True):
822
- """
823
- Add a subscriber for an event.
824
-
825
- :param event: The name of an event.
826
- :param subscriber: The subscriber to be added (and called when the
827
- event is published).
828
- :param append: Whether to append or prepend the subscriber to an
829
- existing subscriber list for the event.
830
- """
831
- subs = self._subscribers
832
- if event not in subs:
833
- subs[event] = deque([subscriber])
834
- else:
835
- sq = subs[event]
836
- if append:
837
- sq.append(subscriber)
838
- else:
839
- sq.appendleft(subscriber)
840
-
841
- def remove(self, event, subscriber):
842
- """
843
- Remove a subscriber for an event.
844
-
845
- :param event: The name of an event.
846
- :param subscriber: The subscriber to be removed.
847
- """
848
- subs = self._subscribers
849
- if event not in subs:
850
- raise ValueError('No subscribers: %r' % event)
851
- subs[event].remove(subscriber)
852
-
853
- def get_subscribers(self, event):
854
- """
855
- Return an iterator for the subscribers for an event.
856
- :param event: The event to return subscribers for.
857
- """
858
- return iter(self._subscribers.get(event, ()))
859
-
860
- def publish(self, event, *args, **kwargs):
861
- """
862
- Publish a event and return a list of values returned by its
863
- subscribers.
864
-
865
- :param event: The event to publish.
866
- :param args: The positional arguments to pass to the event's
867
- subscribers.
868
- :param kwargs: The keyword arguments to pass to the event's
869
- subscribers.
870
- """
871
- result = []
872
- for subscriber in self.get_subscribers(event):
873
- try:
874
- value = subscriber(event, *args, **kwargs)
875
- except Exception:
876
- logger.exception('Exception during event publication')
877
- value = None
878
- result.append(value)
879
- logger.debug('publish %s: args = %s, kwargs = %s, result = %s',
880
- event, args, kwargs, result)
881
- return result
882
-
883
- #
884
- # Simple sequencing
885
- #
886
- class Sequencer(object):
887
- def __init__(self):
888
- self._preds = {}
889
- self._succs = {}
890
- self._nodes = set() # nodes with no preds/succs
891
-
892
- def add_node(self, node):
893
- self._nodes.add(node)
894
-
895
- def remove_node(self, node, edges=False):
896
- if node in self._nodes:
897
- self._nodes.remove(node)
898
- if edges:
899
- for p in set(self._preds.get(node, ())):
900
- self.remove(p, node)
901
- for s in set(self._succs.get(node, ())):
902
- self.remove(node, s)
903
- # Remove empties
904
- for k, v in list(self._preds.items()):
905
- if not v:
906
- del self._preds[k]
907
- for k, v in list(self._succs.items()):
908
- if not v:
909
- del self._succs[k]
910
-
911
- def add(self, pred, succ):
912
- assert pred != succ
913
- self._preds.setdefault(succ, set()).add(pred)
914
- self._succs.setdefault(pred, set()).add(succ)
915
-
916
- def remove(self, pred, succ):
917
- assert pred != succ
918
- try:
919
- preds = self._preds[succ]
920
- succs = self._succs[pred]
921
- except KeyError:
922
- raise ValueError('%r not a successor of anything' % succ)
923
- try:
924
- preds.remove(pred)
925
- succs.remove(succ)
926
- except KeyError:
927
- raise ValueError('%r not a successor of %r' % (succ, pred))
928
-
929
- def is_step(self, step):
930
- return (step in self._preds or step in self._succs or
931
- step in self._nodes)
932
-
933
- def get_steps(self, final):
934
- if not self.is_step(final):
935
- raise ValueError('Unknown: %r' % final)
936
- result = []
937
- todo = []
938
- seen = set()
939
- todo.append(final)
940
- while todo:
941
- step = todo.pop(0)
942
- if step in seen:
943
- # if a step was already seen,
944
- # move it to the end (so it will appear earlier
945
- # when reversed on return) ... but not for the
946
- # final step, as that would be confusing for
947
- # users
948
- if step != final:
949
- result.remove(step)
950
- result.append(step)
951
- else:
952
- seen.add(step)
953
- result.append(step)
954
- preds = self._preds.get(step, ())
955
- todo.extend(preds)
956
- return reversed(result)
957
-
958
- @property
959
- def strong_connections(self):
960
- #http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
961
- index_counter = [0]
962
- stack = []
963
- lowlinks = {}
964
- index = {}
965
- result = []
966
-
967
- graph = self._succs
968
-
969
- def strongconnect(node):
970
- # set the depth index for this node to the smallest unused index
971
- index[node] = index_counter[0]
972
- lowlinks[node] = index_counter[0]
973
- index_counter[0] += 1
974
- stack.append(node)
975
-
976
- # Consider successors
977
- try:
978
- successors = graph[node]
979
- except Exception:
980
- successors = []
981
- for successor in successors:
982
- if successor not in lowlinks:
983
- # Successor has not yet been visited
984
- strongconnect(successor)
985
- lowlinks[node] = min(lowlinks[node],lowlinks[successor])
986
- elif successor in stack:
987
- # the successor is in the stack and hence in the current
988
- # strongly connected component (SCC)
989
- lowlinks[node] = min(lowlinks[node],index[successor])
990
-
991
- # If `node` is a root node, pop the stack and generate an SCC
992
- if lowlinks[node] == index[node]:
993
- connected_component = []
994
-
995
- while True:
996
- successor = stack.pop()
997
- connected_component.append(successor)
998
- if successor == node: break
999
- component = tuple(connected_component)
1000
- # storing the result
1001
- result.append(component)
1002
-
1003
- for node in graph:
1004
- if node not in lowlinks:
1005
- strongconnect(node)
1006
-
1007
- return result
1008
-
1009
- @property
1010
- def dot(self):
1011
- result = ['digraph G {']
1012
- for succ in self._preds:
1013
- preds = self._preds[succ]
1014
- for pred in preds:
1015
- result.append(' %s -> %s;' % (pred, succ))
1016
- for node in self._nodes:
1017
- result.append(' %s;' % node)
1018
- result.append('}')
1019
- return '\n'.join(result)
1020
-
1021
- #
1022
- # Unarchiving functionality for zip, tar, tgz, tbz, whl
1023
- #
1024
-
1025
- ARCHIVE_EXTENSIONS = ('.tar.gz', '.tar.bz2', '.tar', '.zip',
1026
- '.tgz', '.tbz', '.whl')
1027
-
1028
- def unarchive(archive_filename, dest_dir, format=None, check=True):
1029
-
1030
- def check_path(path):
1031
- if not isinstance(path, text_type):
1032
- path = path.decode('utf-8')
1033
- p = os.path.abspath(os.path.join(dest_dir, path))
1034
- if not p.startswith(dest_dir) or p[plen] != os.sep:
1035
- raise ValueError('path outside destination: %r' % p)
1036
-
1037
- dest_dir = os.path.abspath(dest_dir)
1038
- plen = len(dest_dir)
1039
- archive = None
1040
- if format is None:
1041
- if archive_filename.endswith(('.zip', '.whl')):
1042
- format = 'zip'
1043
- elif archive_filename.endswith(('.tar.gz', '.tgz')):
1044
- format = 'tgz'
1045
- mode = 'r:gz'
1046
- elif archive_filename.endswith(('.tar.bz2', '.tbz')):
1047
- format = 'tbz'
1048
- mode = 'r:bz2'
1049
- elif archive_filename.endswith('.tar'):
1050
- format = 'tar'
1051
- mode = 'r'
1052
- else:
1053
- raise ValueError('Unknown format for %r' % archive_filename)
1054
- try:
1055
- if format == 'zip':
1056
- archive = ZipFile(archive_filename, 'r')
1057
- if check:
1058
- names = archive.namelist()
1059
- for name in names:
1060
- check_path(name)
1061
- else:
1062
- archive = tarfile.open(archive_filename, mode)
1063
- if check:
1064
- names = archive.getnames()
1065
- for name in names:
1066
- check_path(name)
1067
- if format != 'zip' and sys.version_info[0] < 3:
1068
- # See Python issue 17153. If the dest path contains Unicode,
1069
- # tarfile extraction fails on Python 2.x if a member path name
1070
- # contains non-ASCII characters - it leads to an implicit
1071
- # bytes -> unicode conversion using ASCII to decode.
1072
- for tarinfo in archive.getmembers():
1073
- if not isinstance(tarinfo.name, text_type):
1074
- tarinfo.name = tarinfo.name.decode('utf-8')
1075
- archive.extractall(dest_dir)
1076
-
1077
- finally:
1078
- if archive:
1079
- archive.close()
1080
-
1081
-
1082
- def zip_dir(directory):
1083
- """zip a directory tree into a BytesIO object"""
1084
- result = io.BytesIO()
1085
- dlen = len(directory)
1086
- with ZipFile(result, "w") as zf:
1087
- for root, dirs, files in os.walk(directory):
1088
- for name in files:
1089
- full = os.path.join(root, name)
1090
- rel = root[dlen:]
1091
- dest = os.path.join(rel, name)
1092
- zf.write(full, dest)
1093
- return result
1094
-
1095
- #
1096
- # Simple progress bar
1097
- #
1098
-
1099
- UNITS = ('', 'K', 'M', 'G','T','P')
1100
-
1101
-
1102
- class Progress(object):
1103
- unknown = 'UNKNOWN'
1104
-
1105
- def __init__(self, minval=0, maxval=100):
1106
- assert maxval is None or maxval >= minval
1107
- self.min = self.cur = minval
1108
- self.max = maxval
1109
- self.started = None
1110
- self.elapsed = 0
1111
- self.done = False
1112
-
1113
- def update(self, curval):
1114
- assert self.min <= curval
1115
- assert self.max is None or curval <= self.max
1116
- self.cur = curval
1117
- now = time.time()
1118
- if self.started is None:
1119
- self.started = now
1120
- else:
1121
- self.elapsed = now - self.started
1122
-
1123
- def increment(self, incr):
1124
- assert incr >= 0
1125
- self.update(self.cur + incr)
1126
-
1127
- def start(self):
1128
- self.update(self.min)
1129
- return self
1130
-
1131
- def stop(self):
1132
- if self.max is not None:
1133
- self.update(self.max)
1134
- self.done = True
1135
-
1136
- @property
1137
- def maximum(self):
1138
- return self.unknown if self.max is None else self.max
1139
-
1140
- @property
1141
- def percentage(self):
1142
- if self.done:
1143
- result = '100 %'
1144
- elif self.max is None:
1145
- result = ' ?? %'
1146
- else:
1147
- v = 100.0 * (self.cur - self.min) / (self.max - self.min)
1148
- result = '%3d %%' % v
1149
- return result
1150
-
1151
- def format_duration(self, duration):
1152
- if (duration <= 0) and self.max is None or self.cur == self.min:
1153
- result = '??:??:??'
1154
- #elif duration < 1:
1155
- # result = '--:--:--'
1156
- else:
1157
- result = time.strftime('%H:%M:%S', time.gmtime(duration))
1158
- return result
1159
-
1160
- @property
1161
- def ETA(self):
1162
- if self.done:
1163
- prefix = 'Done'
1164
- t = self.elapsed
1165
- #import pdb; pdb.set_trace()
1166
- else:
1167
- prefix = 'ETA '
1168
- if self.max is None:
1169
- t = -1
1170
- elif self.elapsed == 0 or (self.cur == self.min):
1171
- t = 0
1172
- else:
1173
- #import pdb; pdb.set_trace()
1174
- t = float(self.max - self.min)
1175
- t /= self.cur - self.min
1176
- t = (t - 1) * self.elapsed
1177
- return '%s: %s' % (prefix, self.format_duration(t))
1178
-
1179
- @property
1180
- def speed(self):
1181
- if self.elapsed == 0:
1182
- result = 0.0
1183
- else:
1184
- result = (self.cur - self.min) / self.elapsed
1185
- for unit in UNITS:
1186
- if result < 1000:
1187
- break
1188
- result /= 1000.0
1189
- return '%d %sB/s' % (result, unit)
1190
-
1191
- #
1192
- # Glob functionality
1193
- #
1194
-
1195
- RICH_GLOB = re.compile(r'\{([^}]*)\}')
1196
- _CHECK_RECURSIVE_GLOB = re.compile(r'[^/\\,{]\*\*|\*\*[^/\\,}]')
1197
- _CHECK_MISMATCH_SET = re.compile(r'^[^{]*\}|\{[^}]*$')
1198
-
1199
-
1200
- def iglob(path_glob):
1201
- """Extended globbing function that supports ** and {opt1,opt2,opt3}."""
1202
- if _CHECK_RECURSIVE_GLOB.search(path_glob):
1203
- msg = """invalid glob %r: recursive glob "**" must be used alone"""
1204
- raise ValueError(msg % path_glob)
1205
- if _CHECK_MISMATCH_SET.search(path_glob):
1206
- msg = """invalid glob %r: mismatching set marker '{' or '}'"""
1207
- raise ValueError(msg % path_glob)
1208
- return _iglob(path_glob)
1209
-
1210
-
1211
- def _iglob(path_glob):
1212
- rich_path_glob = RICH_GLOB.split(path_glob, 1)
1213
- if len(rich_path_glob) > 1:
1214
- assert len(rich_path_glob) == 3, rich_path_glob
1215
- prefix, set, suffix = rich_path_glob
1216
- for item in set.split(','):
1217
- for path in _iglob(''.join((prefix, item, suffix))):
1218
- yield path
1219
- else:
1220
- if '**' not in path_glob:
1221
- for item in std_iglob(path_glob):
1222
- yield item
1223
- else:
1224
- prefix, radical = path_glob.split('**', 1)
1225
- if prefix == '':
1226
- prefix = '.'
1227
- if radical == '':
1228
- radical = '*'
1229
- else:
1230
- # we support both
1231
- radical = radical.lstrip('/')
1232
- radical = radical.lstrip('\\')
1233
- for path, dir, files in os.walk(prefix):
1234
- path = os.path.normpath(path)
1235
- for fn in _iglob(os.path.join(path, radical)):
1236
- yield fn
1237
-
1238
-
1239
-
1240
- #
1241
- # HTTPSConnection which verifies certificates/matches domains
1242
- #
1243
-
1244
- class HTTPSConnection(httplib.HTTPSConnection):
1245
- ca_certs = None # set this to the path to the certs file (.pem)
1246
- check_domain = True # only used if ca_certs is not None
1247
-
1248
- # noinspection PyPropertyAccess
1249
- def connect(self):
1250
- sock = socket.create_connection((self.host, self.port), self.timeout)
1251
- if getattr(self, '_tunnel_host', False):
1252
- self.sock = sock
1253
- self._tunnel()
1254
-
1255
- if not hasattr(ssl, 'SSLContext'):
1256
- # For 2.x
1257
- if self.ca_certs:
1258
- cert_reqs = ssl.CERT_REQUIRED
1259
- else:
1260
- cert_reqs = ssl.CERT_NONE
1261
- self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
1262
- cert_reqs=cert_reqs,
1263
- ssl_version=ssl.PROTOCOL_SSLv23,
1264
- ca_certs=self.ca_certs)
1265
- else:
1266
- context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1267
- context.options |= ssl.OP_NO_SSLv2
1268
- if self.cert_file:
1269
- context.load_cert_chain(self.cert_file, self.key_file)
1270
- kwargs = {}
1271
- if self.ca_certs:
1272
- context.verify_mode = ssl.CERT_REQUIRED
1273
- context.load_verify_locations(cafile=self.ca_certs)
1274
- if getattr(ssl, 'HAS_SNI', False):
1275
- kwargs['server_hostname'] = self.host
1276
- self.sock = context.wrap_socket(sock, **kwargs)
1277
- if self.ca_certs and self.check_domain:
1278
- try:
1279
- match_hostname(self.sock.getpeercert(), self.host)
1280
- logger.debug('Host verified: %s', self.host)
1281
- except CertificateError:
1282
- self.sock.shutdown(socket.SHUT_RDWR)
1283
- self.sock.close()
1284
- raise
1285
-
1286
- class HTTPSHandler(BaseHTTPSHandler):
1287
- def __init__(self, ca_certs, check_domain=True):
1288
- BaseHTTPSHandler.__init__(self)
1289
- self.ca_certs = ca_certs
1290
- self.check_domain = check_domain
1291
-
1292
- def _conn_maker(self, *args, **kwargs):
1293
- """
1294
- This is called to create a connection instance. Normally you'd
1295
- pass a connection class to do_open, but it doesn't actually check for
1296
- a class, and just expects a callable. As long as we behave just as a
1297
- constructor would have, we should be OK. If it ever changes so that
1298
- we *must* pass a class, we'll create an UnsafeHTTPSConnection class
1299
- which just sets check_domain to False in the class definition, and
1300
- choose which one to pass to do_open.
1301
- """
1302
- result = HTTPSConnection(*args, **kwargs)
1303
- if self.ca_certs:
1304
- result.ca_certs = self.ca_certs
1305
- result.check_domain = self.check_domain
1306
- return result
1307
-
1308
- def https_open(self, req):
1309
- try:
1310
- return self.do_open(self._conn_maker, req)
1311
- except URLError as e:
1312
- if 'certificate verify failed' in str(e.reason):
1313
- raise CertificateError('Unable to verify server certificate '
1314
- 'for %s' % req.host)
1315
- else:
1316
- raise
1317
-
1318
- #
1319
- # To prevent against mixing HTTP traffic with HTTPS (examples: A Man-In-The-
1320
- # Middle proxy using HTTP listens on port 443, or an index mistakenly serves
1321
- # HTML containing a http://xyz link when it should be https://xyz),
1322
- # you can use the following handler class, which does not allow HTTP traffic.
1323
- #
1324
- # It works by inheriting from HTTPHandler - so build_opener won't add a
1325
- # handler for HTTP itself.
1326
- #
1327
- class HTTPSOnlyHandler(HTTPSHandler, HTTPHandler):
1328
- def http_open(self, req):
1329
- raise URLError('Unexpected HTTP request on what should be a secure '
1330
- 'connection: %s' % req)
1331
-
1332
- #
1333
- # XML-RPC with timeouts
1334
- #
1335
-
1336
- _ver_info = sys.version_info[:2]
1337
-
1338
- if _ver_info == (2, 6):
1339
- class HTTP(httplib.HTTP):
1340
- def __init__(self, host='', port=None, **kwargs):
1341
- if port == 0: # 0 means use port 0, not the default port
1342
- port = None
1343
- self._setup(self._connection_class(host, port, **kwargs))
1344
-
1345
-
1346
- class HTTPS(httplib.HTTPS):
1347
- def __init__(self, host='', port=None, **kwargs):
1348
- if port == 0: # 0 means use port 0, not the default port
1349
- port = None
1350
- self._setup(self._connection_class(host, port, **kwargs))
1351
-
1352
-
1353
- class Transport(xmlrpclib.Transport):
1354
- def __init__(self, timeout, use_datetime=0):
1355
- self.timeout = timeout
1356
- xmlrpclib.Transport.__init__(self, use_datetime)
1357
-
1358
- def make_connection(self, host):
1359
- h, eh, x509 = self.get_host_info(host)
1360
- if _ver_info == (2, 6):
1361
- result = HTTP(h, timeout=self.timeout)
1362
- else:
1363
- if not self._connection or host != self._connection[0]:
1364
- self._extra_headers = eh
1365
- self._connection = host, httplib.HTTPConnection(h)
1366
- result = self._connection[1]
1367
- return result
1368
-
1369
- class SafeTransport(xmlrpclib.SafeTransport):
1370
- def __init__(self, timeout, use_datetime=0):
1371
- self.timeout = timeout
1372
- xmlrpclib.SafeTransport.__init__(self, use_datetime)
1373
-
1374
- def make_connection(self, host):
1375
- h, eh, kwargs = self.get_host_info(host)
1376
- if not kwargs:
1377
- kwargs = {}
1378
- kwargs['timeout'] = self.timeout
1379
- if _ver_info == (2, 6):
1380
- result = HTTPS(host, None, **kwargs)
1381
- else:
1382
- if not self._connection or host != self._connection[0]:
1383
- self._extra_headers = eh
1384
- self._connection = host, httplib.HTTPSConnection(h, None,
1385
- **kwargs)
1386
- result = self._connection[1]
1387
- return result
1388
-
1389
-
1390
- class ServerProxy(xmlrpclib.ServerProxy):
1391
- def __init__(self, uri, **kwargs):
1392
- self.timeout = timeout = kwargs.pop('timeout', None)
1393
- # The above classes only come into play if a timeout
1394
- # is specified
1395
- if timeout is not None:
1396
- scheme, _ = splittype(uri)
1397
- use_datetime = kwargs.get('use_datetime', 0)
1398
- if scheme == 'https':
1399
- tcls = SafeTransport
1400
- else:
1401
- tcls = Transport
1402
- kwargs['transport'] = t = tcls(timeout, use_datetime=use_datetime)
1403
- self.transport = t
1404
- xmlrpclib.ServerProxy.__init__(self, uri, **kwargs)
1405
-
1406
- #
1407
- # CSV functionality. This is provided because on 2.x, the csv module can't
1408
- # handle Unicode. However, we need to deal with Unicode in e.g. RECORD files.
1409
- #
1410
-
1411
- def _csv_open(fn, mode, **kwargs):
1412
- if sys.version_info[0] < 3:
1413
- mode += 'b'
1414
- else:
1415
- kwargs['newline'] = ''
1416
- return open(fn, mode, **kwargs)
1417
-
1418
-
1419
- class CSVBase(object):
1420
- defaults = {
1421
- 'delimiter': str(','), # The strs are used because we need native
1422
- 'quotechar': str('"'), # str in the csv API (2.x won't take
1423
- 'lineterminator': str('\n') # Unicode)
1424
- }
1425
-
1426
- def __enter__(self):
1427
- return self
1428
-
1429
- def __exit__(self, *exc_info):
1430
- self.stream.close()
1431
-
1432
-
1433
- class CSVReader(CSVBase):
1434
- def __init__(self, **kwargs):
1435
- if 'stream' in kwargs:
1436
- stream = kwargs['stream']
1437
- if sys.version_info[0] >= 3:
1438
- # needs to be a text stream
1439
- stream = codecs.getreader('utf-8')(stream)
1440
- self.stream = stream
1441
- else:
1442
- self.stream = _csv_open(kwargs['path'], 'r')
1443
- self.reader = csv.reader(self.stream, **self.defaults)
1444
-
1445
- def __iter__(self):
1446
- return self
1447
-
1448
- def next(self):
1449
- result = next(self.reader)
1450
- if sys.version_info[0] < 3:
1451
- for i, item in enumerate(result):
1452
- if not isinstance(item, text_type):
1453
- result[i] = item.decode('utf-8')
1454
- return result
1455
-
1456
- __next__ = next
1457
-
1458
- class CSVWriter(CSVBase):
1459
- def __init__(self, fn, **kwargs):
1460
- self.stream = _csv_open(fn, 'w')
1461
- self.writer = csv.writer(self.stream, **self.defaults)
1462
-
1463
- def writerow(self, row):
1464
- if sys.version_info[0] < 3:
1465
- r = []
1466
- for item in row:
1467
- if isinstance(item, text_type):
1468
- item = item.encode('utf-8')
1469
- r.append(item)
1470
- row = r
1471
- self.writer.writerow(row)
1472
-
1473
- #
1474
- # Configurator functionality
1475
- #
1476
-
1477
- class Configurator(BaseConfigurator):
1478
-
1479
- value_converters = dict(BaseConfigurator.value_converters)
1480
- value_converters['inc'] = 'inc_convert'
1481
-
1482
- def __init__(self, config, base=None):
1483
- super(Configurator, self).__init__(config)
1484
- self.base = base or os.getcwd()
1485
-
1486
- def configure_custom(self, config):
1487
- def convert(o):
1488
- if isinstance(o, (list, tuple)):
1489
- result = type(o)([convert(i) for i in o])
1490
- elif isinstance(o, dict):
1491
- if '()' in o:
1492
- result = self.configure_custom(o)
1493
- else:
1494
- result = {}
1495
- for k in o:
1496
- result[k] = convert(o[k])
1497
- else:
1498
- result = self.convert(o)
1499
- return result
1500
-
1501
- c = config.pop('()')
1502
- if not callable(c):
1503
- c = self.resolve(c)
1504
- props = config.pop('.', None)
1505
- # Check for valid identifiers
1506
- args = config.pop('[]', ())
1507
- if args:
1508
- args = tuple([convert(o) for o in args])
1509
- items = [(k, convert(config[k])) for k in config if valid_ident(k)]
1510
- kwargs = dict(items)
1511
- result = c(*args, **kwargs)
1512
- if props:
1513
- for n, v in props.items():
1514
- setattr(result, n, convert(v))
1515
- return result
1516
-
1517
- def __getitem__(self, key):
1518
- result = self.config[key]
1519
- if isinstance(result, dict) and '()' in result:
1520
- self.config[key] = result = self.configure_custom(result)
1521
- return result
1522
-
1523
- def inc_convert(self, value):
1524
- """Default converter for the inc:// protocol."""
1525
- if not os.path.isabs(value):
1526
- value = os.path.join(self.base, value)
1527
- with codecs.open(value, 'r', encoding='utf-8') as f:
1528
- result = json.load(f)
1529
- return result
1530
-
1531
- #
1532
- # Mixin for running subprocesses and capturing their output
1533
- #
1534
-
1535
- class SubprocessMixin(object):
1536
- def __init__(self, verbose=False, progress=None):
1537
- self.verbose = verbose
1538
- self.progress = progress
1539
-
1540
- def reader(self, stream, context):
1541
- """
1542
- Read lines from a subprocess' output stream and either pass to a progress
1543
- callable (if specified) or write progress information to sys.stderr.
1544
- """
1545
- progress = self.progress
1546
- verbose = self.verbose
1547
- while True:
1548
- s = stream.readline()
1549
- if not s:
1550
- break
1551
- if progress is not None:
1552
- progress(s, context)
1553
- else:
1554
- if not verbose:
1555
- sys.stderr.write('.')
1556
- else:
1557
- sys.stderr.write(s.decode('utf-8'))
1558
- sys.stderr.flush()
1559
- stream.close()
1560
-
1561
- def run_command(self, cmd, **kwargs):
1562
- p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
1563
- stderr=subprocess.PIPE, **kwargs)
1564
- t1 = threading.Thread(target=self.reader, args=(p.stdout, 'stdout'))
1565
- t1.start()
1566
- t2 = threading.Thread(target=self.reader, args=(p.stderr, 'stderr'))
1567
- t2.start()
1568
- p.wait()
1569
- t1.join()
1570
- t2.join()
1571
- if self.progress is not None:
1572
- self.progress('done.', 'main')
1573
- elif self.verbose:
1574
- sys.stderr.write('done.\n')
1575
- return p
1
+ #
2
+ # Copyright (C) 2012-2017 The Python Software Foundation.
3
+ # See LICENSE.txt and CONTRIBUTORS.txt.
4
+ #
5
+ import codecs
6
+ from collections import deque
7
+ import contextlib
8
+ import csv
9
+ from glob import iglob as std_iglob
10
+ import io
11
+ import json
12
+ import logging
13
+ import os
14
+ import py_compile
15
+ import re
16
+ import socket
17
+ try:
18
+ import ssl
19
+ except ImportError: # pragma: no cover
20
+ ssl = None
21
+ import subprocess
22
+ import sys
23
+ import tarfile
24
+ import tempfile
25
+ import textwrap
26
+
27
+ try:
28
+ import threading
29
+ except ImportError: # pragma: no cover
30
+ import dummy_threading as threading
31
+ import time
32
+
33
+ from . import DistlibException
34
+ from .compat import (string_types, text_type, shutil, raw_input, StringIO,
35
+ cache_from_source, urlopen, urljoin, httplib, xmlrpclib,
36
+ splittype, HTTPHandler, BaseConfigurator, valid_ident,
37
+ Container, configparser, URLError, ZipFile, fsdecode,
38
+ unquote, urlparse)
39
+
40
+ logger = logging.getLogger(__name__)
41
+
42
+ #
43
+ # Requirement parsing code as per PEP 508
44
+ #
45
+
46
+ IDENTIFIER = re.compile(r'^([\w\.-]+)\s*')
47
+ VERSION_IDENTIFIER = re.compile(r'^([\w\.*+-]+)\s*')
48
+ COMPARE_OP = re.compile(r'^(<=?|>=?|={2,3}|[~!]=)\s*')
49
+ MARKER_OP = re.compile(r'^((<=?)|(>=?)|={2,3}|[~!]=|in|not\s+in)\s*')
50
+ OR = re.compile(r'^or\b\s*')
51
+ AND = re.compile(r'^and\b\s*')
52
+ NON_SPACE = re.compile(r'(\S+)\s*')
53
+ STRING_CHUNK = re.compile(r'([\s\w\.{}()*+#:;,/?!~`@$%^&=|<>\[\]-]+)')
54
+
55
+
56
+ def parse_marker(marker_string):
57
+ """
58
+ Parse a marker string and return a dictionary containing a marker expression.
59
+
60
+ The dictionary will contain keys "op", "lhs" and "rhs" for non-terminals in
61
+ the expression grammar, or strings. A string contained in quotes is to be
62
+ interpreted as a literal string, and a string not contained in quotes is a
63
+ variable (such as os_name).
64
+ """
65
+ def marker_var(remaining):
66
+ # either identifier, or literal string
67
+ m = IDENTIFIER.match(remaining)
68
+ if m:
69
+ result = m.groups()[0]
70
+ remaining = remaining[m.end():]
71
+ elif not remaining:
72
+ raise SyntaxError('unexpected end of input')
73
+ else:
74
+ q = remaining[0]
75
+ if q not in '\'"':
76
+ raise SyntaxError('invalid expression: %s' % remaining)
77
+ oq = '\'"'.replace(q, '')
78
+ remaining = remaining[1:]
79
+ parts = [q]
80
+ while remaining:
81
+ # either a string chunk, or oq, or q to terminate
82
+ if remaining[0] == q:
83
+ break
84
+ elif remaining[0] == oq:
85
+ parts.append(oq)
86
+ remaining = remaining[1:]
87
+ else:
88
+ m = STRING_CHUNK.match(remaining)
89
+ if not m:
90
+ raise SyntaxError('error in string literal: %s' % remaining)
91
+ parts.append(m.groups()[0])
92
+ remaining = remaining[m.end():]
93
+ else:
94
+ s = ''.join(parts)
95
+ raise SyntaxError('unterminated string: %s' % s)
96
+ parts.append(q)
97
+ result = ''.join(parts)
98
+ remaining = remaining[1:].lstrip() # skip past closing quote
99
+ return result, remaining
100
+
101
+ def marker_expr(remaining):
102
+ if remaining and remaining[0] == '(':
103
+ result, remaining = marker(remaining[1:].lstrip())
104
+ if remaining[0] != ')':
105
+ raise SyntaxError('unterminated parenthesis: %s' % remaining)
106
+ remaining = remaining[1:].lstrip()
107
+ else:
108
+ lhs, remaining = marker_var(remaining)
109
+ while remaining:
110
+ m = MARKER_OP.match(remaining)
111
+ if not m:
112
+ break
113
+ op = m.groups()[0]
114
+ remaining = remaining[m.end():]
115
+ rhs, remaining = marker_var(remaining)
116
+ lhs = {'op': op, 'lhs': lhs, 'rhs': rhs}
117
+ result = lhs
118
+ return result, remaining
119
+
120
+ def marker_and(remaining):
121
+ lhs, remaining = marker_expr(remaining)
122
+ while remaining:
123
+ m = AND.match(remaining)
124
+ if not m:
125
+ break
126
+ remaining = remaining[m.end():]
127
+ rhs, remaining = marker_expr(remaining)
128
+ lhs = {'op': 'and', 'lhs': lhs, 'rhs': rhs}
129
+ return lhs, remaining
130
+
131
+ def marker(remaining):
132
+ lhs, remaining = marker_and(remaining)
133
+ while remaining:
134
+ m = OR.match(remaining)
135
+ if not m:
136
+ break
137
+ remaining = remaining[m.end():]
138
+ rhs, remaining = marker_and(remaining)
139
+ lhs = {'op': 'or', 'lhs': lhs, 'rhs': rhs}
140
+ return lhs, remaining
141
+
142
+ return marker(marker_string)
143
+
144
+
145
+ def parse_requirement(req):
146
+ """
147
+ Parse a requirement passed in as a string. Return a Container
148
+ whose attributes contain the various parts of the requirement.
149
+ """
150
+ remaining = req.strip()
151
+ if not remaining or remaining.startswith('#'):
152
+ return None
153
+ m = IDENTIFIER.match(remaining)
154
+ if not m:
155
+ raise SyntaxError('name expected: %s' % remaining)
156
+ distname = m.groups()[0]
157
+ remaining = remaining[m.end():]
158
+ extras = mark_expr = versions = uri = None
159
+ if remaining and remaining[0] == '[':
160
+ i = remaining.find(']', 1)
161
+ if i < 0:
162
+ raise SyntaxError('unterminated extra: %s' % remaining)
163
+ s = remaining[1:i]
164
+ remaining = remaining[i + 1:].lstrip()
165
+ extras = []
166
+ while s:
167
+ m = IDENTIFIER.match(s)
168
+ if not m:
169
+ raise SyntaxError('malformed extra: %s' % s)
170
+ extras.append(m.groups()[0])
171
+ s = s[m.end():]
172
+ if not s:
173
+ break
174
+ if s[0] != ',':
175
+ raise SyntaxError('comma expected in extras: %s' % s)
176
+ s = s[1:].lstrip()
177
+ if not extras:
178
+ extras = None
179
+ if remaining:
180
+ if remaining[0] == '@':
181
+ # it's a URI
182
+ remaining = remaining[1:].lstrip()
183
+ m = NON_SPACE.match(remaining)
184
+ if not m:
185
+ raise SyntaxError('invalid URI: %s' % remaining)
186
+ uri = m.groups()[0]
187
+ t = urlparse(uri)
188
+ # there are issues with Python and URL parsing, so this test
189
+ # is a bit crude. See bpo-20271, bpo-23505. Python doesn't
190
+ # always parse invalid URLs correctly - it should raise
191
+ # exceptions for malformed URLs
192
+ if not (t.scheme and t.netloc):
193
+ raise SyntaxError('Invalid URL: %s' % uri)
194
+ remaining = remaining[m.end():].lstrip()
195
+ else:
196
+
197
+ def get_versions(ver_remaining):
198
+ """
199
+ Return a list of operator, version tuples if any are
200
+ specified, else None.
201
+ """
202
+ m = COMPARE_OP.match(ver_remaining)
203
+ versions = None
204
+ if m:
205
+ versions = []
206
+ while True:
207
+ op = m.groups()[0]
208
+ ver_remaining = ver_remaining[m.end():]
209
+ m = VERSION_IDENTIFIER.match(ver_remaining)
210
+ if not m:
211
+ raise SyntaxError('invalid version: %s' % ver_remaining)
212
+ v = m.groups()[0]
213
+ versions.append((op, v))
214
+ ver_remaining = ver_remaining[m.end():]
215
+ if not ver_remaining or ver_remaining[0] != ',':
216
+ break
217
+ ver_remaining = ver_remaining[1:].lstrip()
218
+ m = COMPARE_OP.match(ver_remaining)
219
+ if not m:
220
+ raise SyntaxError('invalid constraint: %s' % ver_remaining)
221
+ if not versions:
222
+ versions = None
223
+ return versions, ver_remaining
224
+
225
+ if remaining[0] != '(':
226
+ versions, remaining = get_versions(remaining)
227
+ else:
228
+ i = remaining.find(')', 1)
229
+ if i < 0:
230
+ raise SyntaxError('unterminated parenthesis: %s' % remaining)
231
+ s = remaining[1:i]
232
+ remaining = remaining[i + 1:].lstrip()
233
+ # As a special diversion from PEP 508, allow a version number
234
+ # a.b.c in parentheses as a synonym for ~= a.b.c (because this
235
+ # is allowed in earlier PEPs)
236
+ if COMPARE_OP.match(s):
237
+ versions, _ = get_versions(s)
238
+ else:
239
+ m = VERSION_IDENTIFIER.match(s)
240
+ if not m:
241
+ raise SyntaxError('invalid constraint: %s' % s)
242
+ v = m.groups()[0]
243
+ s = s[m.end():].lstrip()
244
+ if s:
245
+ raise SyntaxError('invalid constraint: %s' % s)
246
+ versions = [('~=', v)]
247
+
248
+ if remaining:
249
+ if remaining[0] != ';':
250
+ raise SyntaxError('invalid requirement: %s' % remaining)
251
+ remaining = remaining[1:].lstrip()
252
+
253
+ mark_expr, remaining = parse_marker(remaining)
254
+
255
+ if remaining and remaining[0] != '#':
256
+ raise SyntaxError('unexpected trailing data: %s' % remaining)
257
+
258
+ if not versions:
259
+ rs = distname
260
+ else:
261
+ rs = '%s %s' % (distname, ', '.join(['%s %s' % con for con in versions]))
262
+ return Container(name=distname, extras=extras, constraints=versions,
263
+ marker=mark_expr, url=uri, requirement=rs)
264
+
265
+
266
+ def get_resources_dests(resources_root, rules):
267
+ """Find destinations for resources files"""
268
+
269
+ def get_rel_path(root, path):
270
+ # normalizes and returns a lstripped-/-separated path
271
+ root = root.replace(os.path.sep, '/')
272
+ path = path.replace(os.path.sep, '/')
273
+ assert path.startswith(root)
274
+ return path[len(root):].lstrip('/')
275
+
276
+ destinations = {}
277
+ for base, suffix, dest in rules:
278
+ prefix = os.path.join(resources_root, base)
279
+ for abs_base in iglob(prefix):
280
+ abs_glob = os.path.join(abs_base, suffix)
281
+ for abs_path in iglob(abs_glob):
282
+ resource_file = get_rel_path(resources_root, abs_path)
283
+ if dest is None: # remove the entry if it was here
284
+ destinations.pop(resource_file, None)
285
+ else:
286
+ rel_path = get_rel_path(abs_base, abs_path)
287
+ rel_dest = dest.replace(os.path.sep, '/').rstrip('/')
288
+ destinations[resource_file] = rel_dest + '/' + rel_path
289
+ return destinations
290
+
291
+
292
+ def in_venv():
293
+ if hasattr(sys, 'real_prefix'):
294
+ # virtualenv venvs
295
+ result = True
296
+ else:
297
+ # PEP 405 venvs
298
+ result = sys.prefix != getattr(sys, 'base_prefix', sys.prefix)
299
+ return result
300
+
301
+
302
+ def get_executable():
303
+ # The __PYVENV_LAUNCHER__ dance is apparently no longer needed, as
304
+ # changes to the stub launcher mean that sys.executable always points
305
+ # to the stub on OS X
306
+ # if sys.platform == 'darwin' and ('__PYVENV_LAUNCHER__'
307
+ # in os.environ):
308
+ # result = os.environ['__PYVENV_LAUNCHER__']
309
+ # else:
310
+ # result = sys.executable
311
+ # return result
312
+ result = os.path.normcase(sys.executable)
313
+ if not isinstance(result, text_type):
314
+ result = fsdecode(result)
315
+ return result
316
+
317
+
318
+ def proceed(prompt, allowed_chars, error_prompt=None, default=None):
319
+ p = prompt
320
+ while True:
321
+ s = raw_input(p)
322
+ p = prompt
323
+ if not s and default:
324
+ s = default
325
+ if s:
326
+ c = s[0].lower()
327
+ if c in allowed_chars:
328
+ break
329
+ if error_prompt:
330
+ p = '%c: %s\n%s' % (c, error_prompt, prompt)
331
+ return c
332
+
333
+
334
+ def extract_by_key(d, keys):
335
+ if isinstance(keys, string_types):
336
+ keys = keys.split()
337
+ result = {}
338
+ for key in keys:
339
+ if key in d:
340
+ result[key] = d[key]
341
+ return result
342
+
343
+ def read_exports(stream):
344
+ if sys.version_info[0] >= 3:
345
+ # needs to be a text stream
346
+ stream = codecs.getreader('utf-8')(stream)
347
+ # Try to load as JSON, falling back on legacy format
348
+ data = stream.read()
349
+ stream = StringIO(data)
350
+ try:
351
+ jdata = json.load(stream)
352
+ result = jdata['extensions']['python.exports']['exports']
353
+ for group, entries in result.items():
354
+ for k, v in entries.items():
355
+ s = '%s = %s' % (k, v)
356
+ entry = get_export_entry(s)
357
+ assert entry is not None
358
+ entries[k] = entry
359
+ return result
360
+ except Exception:
361
+ stream.seek(0, 0)
362
+
363
+ def read_stream(cp, stream):
364
+ if hasattr(cp, 'read_file'):
365
+ cp.read_file(stream)
366
+ else:
367
+ cp.readfp(stream)
368
+
369
+ cp = configparser.ConfigParser()
370
+ try:
371
+ read_stream(cp, stream)
372
+ except configparser.MissingSectionHeaderError:
373
+ stream.close()
374
+ data = textwrap.dedent(data)
375
+ stream = StringIO(data)
376
+ read_stream(cp, stream)
377
+
378
+ result = {}
379
+ for key in cp.sections():
380
+ result[key] = entries = {}
381
+ for name, value in cp.items(key):
382
+ s = '%s = %s' % (name, value)
383
+ entry = get_export_entry(s)
384
+ assert entry is not None
385
+ #entry.dist = self
386
+ entries[name] = entry
387
+ return result
388
+
389
+
390
+ def write_exports(exports, stream):
391
+ if sys.version_info[0] >= 3:
392
+ # needs to be a text stream
393
+ stream = codecs.getwriter('utf-8')(stream)
394
+ cp = configparser.ConfigParser()
395
+ for k, v in exports.items():
396
+ # TODO check k, v for valid values
397
+ cp.add_section(k)
398
+ for entry in v.values():
399
+ if entry.suffix is None:
400
+ s = entry.prefix
401
+ else:
402
+ s = '%s:%s' % (entry.prefix, entry.suffix)
403
+ if entry.flags:
404
+ s = '%s [%s]' % (s, ', '.join(entry.flags))
405
+ cp.set(k, entry.name, s)
406
+ cp.write(stream)
407
+
408
+
409
+ @contextlib.contextmanager
410
+ def tempdir():
411
+ td = tempfile.mkdtemp()
412
+ try:
413
+ yield td
414
+ finally:
415
+ shutil.rmtree(td)
416
+
417
+ @contextlib.contextmanager
418
+ def chdir(d):
419
+ cwd = os.getcwd()
420
+ try:
421
+ os.chdir(d)
422
+ yield
423
+ finally:
424
+ os.chdir(cwd)
425
+
426
+
427
+ @contextlib.contextmanager
428
+ def socket_timeout(seconds=15):
429
+ cto = socket.getdefaulttimeout()
430
+ try:
431
+ socket.setdefaulttimeout(seconds)
432
+ yield
433
+ finally:
434
+ socket.setdefaulttimeout(cto)
435
+
436
+
437
+ class cached_property(object):
438
+ def __init__(self, func):
439
+ self.func = func
440
+ #for attr in ('__name__', '__module__', '__doc__'):
441
+ # setattr(self, attr, getattr(func, attr, None))
442
+
443
+ def __get__(self, obj, cls=None):
444
+ if obj is None:
445
+ return self
446
+ value = self.func(obj)
447
+ object.__setattr__(obj, self.func.__name__, value)
448
+ #obj.__dict__[self.func.__name__] = value = self.func(obj)
449
+ return value
450
+
451
+ def convert_path(pathname):
452
+ """Return 'pathname' as a name that will work on the native filesystem.
453
+
454
+ The path is split on '/' and put back together again using the current
455
+ directory separator. Needed because filenames in the setup script are
456
+ always supplied in Unix style, and have to be converted to the local
457
+ convention before we can actually use them in the filesystem. Raises
458
+ ValueError on non-Unix-ish systems if 'pathname' either starts or
459
+ ends with a slash.
460
+ """
461
+ if os.sep == '/':
462
+ return pathname
463
+ if not pathname:
464
+ return pathname
465
+ if pathname[0] == '/':
466
+ raise ValueError("path '%s' cannot be absolute" % pathname)
467
+ if pathname[-1] == '/':
468
+ raise ValueError("path '%s' cannot end with '/'" % pathname)
469
+
470
+ paths = pathname.split('/')
471
+ while os.curdir in paths:
472
+ paths.remove(os.curdir)
473
+ if not paths:
474
+ return os.curdir
475
+ return os.path.join(*paths)
476
+
477
+
478
+ class FileOperator(object):
479
+ def __init__(self, dry_run=False):
480
+ self.dry_run = dry_run
481
+ self.ensured = set()
482
+ self._init_record()
483
+
484
+ def _init_record(self):
485
+ self.record = False
486
+ self.files_written = set()
487
+ self.dirs_created = set()
488
+
489
+ def record_as_written(self, path):
490
+ if self.record:
491
+ self.files_written.add(path)
492
+
493
+ def newer(self, source, target):
494
+ """Tell if the target is newer than the source.
495
+
496
+ Returns true if 'source' exists and is more recently modified than
497
+ 'target', or if 'source' exists and 'target' doesn't.
498
+
499
+ Returns false if both exist and 'target' is the same age or younger
500
+ than 'source'. Raise PackagingFileError if 'source' does not exist.
501
+
502
+ Note that this test is not very accurate: files created in the same
503
+ second will have the same "age".
504
+ """
505
+ if not os.path.exists(source):
506
+ raise DistlibException("file '%r' does not exist" %
507
+ os.path.abspath(source))
508
+ if not os.path.exists(target):
509
+ return True
510
+
511
+ return os.stat(source).st_mtime > os.stat(target).st_mtime
512
+
513
+ def copy_file(self, infile, outfile, check=True):
514
+ """Copy a file respecting dry-run and force flags.
515
+ """
516
+ self.ensure_dir(os.path.dirname(outfile))
517
+ logger.info('Copying %s to %s', infile, outfile)
518
+ if not self.dry_run:
519
+ msg = None
520
+ if check:
521
+ if os.path.islink(outfile):
522
+ msg = '%s is a symlink' % outfile
523
+ elif os.path.exists(outfile) and not os.path.isfile(outfile):
524
+ msg = '%s is a non-regular file' % outfile
525
+ if msg:
526
+ raise ValueError(msg + ' which would be overwritten')
527
+ shutil.copyfile(infile, outfile)
528
+ self.record_as_written(outfile)
529
+
530
+ def copy_stream(self, instream, outfile, encoding=None):
531
+ assert not os.path.isdir(outfile)
532
+ self.ensure_dir(os.path.dirname(outfile))
533
+ logger.info('Copying stream %s to %s', instream, outfile)
534
+ if not self.dry_run:
535
+ if encoding is None:
536
+ outstream = open(outfile, 'wb')
537
+ else:
538
+ outstream = codecs.open(outfile, 'w', encoding=encoding)
539
+ try:
540
+ shutil.copyfileobj(instream, outstream)
541
+ finally:
542
+ outstream.close()
543
+ self.record_as_written(outfile)
544
+
545
+ def write_binary_file(self, path, data):
546
+ self.ensure_dir(os.path.dirname(path))
547
+ if not self.dry_run:
548
+ with open(path, 'wb') as f:
549
+ f.write(data)
550
+ self.record_as_written(path)
551
+
552
+ def write_text_file(self, path, data, encoding):
553
+ self.ensure_dir(os.path.dirname(path))
554
+ if not self.dry_run:
555
+ with open(path, 'wb') as f:
556
+ f.write(data.encode(encoding))
557
+ self.record_as_written(path)
558
+
559
+ def set_mode(self, bits, mask, files):
560
+ if os.name == 'posix' or (os.name == 'java' and os._name == 'posix'):
561
+ # Set the executable bits (owner, group, and world) on
562
+ # all the files specified.
563
+ for f in files:
564
+ if self.dry_run:
565
+ logger.info("changing mode of %s", f)
566
+ else:
567
+ mode = (os.stat(f).st_mode | bits) & mask
568
+ logger.info("changing mode of %s to %o", f, mode)
569
+ os.chmod(f, mode)
570
+
571
+ set_executable_mode = lambda s, f: s.set_mode(0o555, 0o7777, f)
572
+
573
+ def ensure_dir(self, path):
574
+ path = os.path.abspath(path)
575
+ if path not in self.ensured and not os.path.exists(path):
576
+ self.ensured.add(path)
577
+ d, f = os.path.split(path)
578
+ self.ensure_dir(d)
579
+ logger.info('Creating %s' % path)
580
+ if not self.dry_run:
581
+ os.mkdir(path)
582
+ if self.record:
583
+ self.dirs_created.add(path)
584
+
585
+ def byte_compile(self, path, optimize=False, force=False, prefix=None):
586
+ dpath = cache_from_source(path, not optimize)
587
+ logger.info('Byte-compiling %s to %s', path, dpath)
588
+ if not self.dry_run:
589
+ if force or self.newer(path, dpath):
590
+ if not prefix:
591
+ diagpath = None
592
+ else:
593
+ assert path.startswith(prefix)
594
+ diagpath = path[len(prefix):]
595
+ py_compile.compile(path, dpath, diagpath, True) # raise error
596
+ self.record_as_written(dpath)
597
+ return dpath
598
+
599
+ def ensure_removed(self, path):
600
+ if os.path.exists(path):
601
+ if os.path.isdir(path) and not os.path.islink(path):
602
+ logger.debug('Removing directory tree at %s', path)
603
+ if not self.dry_run:
604
+ shutil.rmtree(path)
605
+ if self.record:
606
+ if path in self.dirs_created:
607
+ self.dirs_created.remove(path)
608
+ else:
609
+ if os.path.islink(path):
610
+ s = 'link'
611
+ else:
612
+ s = 'file'
613
+ logger.debug('Removing %s %s', s, path)
614
+ if not self.dry_run:
615
+ os.remove(path)
616
+ if self.record:
617
+ if path in self.files_written:
618
+ self.files_written.remove(path)
619
+
620
+ def is_writable(self, path):
621
+ result = False
622
+ while not result:
623
+ if os.path.exists(path):
624
+ result = os.access(path, os.W_OK)
625
+ break
626
+ parent = os.path.dirname(path)
627
+ if parent == path:
628
+ break
629
+ path = parent
630
+ return result
631
+
632
+ def commit(self):
633
+ """
634
+ Commit recorded changes, turn off recording, return
635
+ changes.
636
+ """
637
+ assert self.record
638
+ result = self.files_written, self.dirs_created
639
+ self._init_record()
640
+ return result
641
+
642
+ def rollback(self):
643
+ if not self.dry_run:
644
+ for f in list(self.files_written):
645
+ if os.path.exists(f):
646
+ os.remove(f)
647
+ # dirs should all be empty now, except perhaps for
648
+ # __pycache__ subdirs
649
+ # reverse so that subdirs appear before their parents
650
+ dirs = sorted(self.dirs_created, reverse=True)
651
+ for d in dirs:
652
+ flist = os.listdir(d)
653
+ if flist:
654
+ assert flist == ['__pycache__']
655
+ sd = os.path.join(d, flist[0])
656
+ os.rmdir(sd)
657
+ os.rmdir(d) # should fail if non-empty
658
+ self._init_record()
659
+
660
+ def resolve(module_name, dotted_path):
661
+ if module_name in sys.modules:
662
+ mod = sys.modules[module_name]
663
+ else:
664
+ mod = __import__(module_name)
665
+ if dotted_path is None:
666
+ result = mod
667
+ else:
668
+ parts = dotted_path.split('.')
669
+ result = getattr(mod, parts.pop(0))
670
+ for p in parts:
671
+ result = getattr(result, p)
672
+ return result
673
+
674
+
675
+ class ExportEntry(object):
676
+ def __init__(self, name, prefix, suffix, flags):
677
+ self.name = name
678
+ self.prefix = prefix
679
+ self.suffix = suffix
680
+ self.flags = flags
681
+
682
+ @cached_property
683
+ def value(self):
684
+ return resolve(self.prefix, self.suffix)
685
+
686
+ def __repr__(self): # pragma: no cover
687
+ return '<ExportEntry %s = %s:%s %s>' % (self.name, self.prefix,
688
+ self.suffix, self.flags)
689
+
690
+ def __eq__(self, other):
691
+ if not isinstance(other, ExportEntry):
692
+ result = False
693
+ else:
694
+ result = (self.name == other.name and
695
+ self.prefix == other.prefix and
696
+ self.suffix == other.suffix and
697
+ self.flags == other.flags)
698
+ return result
699
+
700
+ __hash__ = object.__hash__
701
+
702
+
703
+ ENTRY_RE = re.compile(r'''(?P<name>(\w|[-.+])+)
704
+ \s*=\s*(?P<callable>(\w+)([:\.]\w+)*)
705
+ \s*(\[\s*(?P<flags>\w+(=\w+)?(,\s*\w+(=\w+)?)*)\s*\])?
706
+ ''', re.VERBOSE)
707
+
708
+ def get_export_entry(specification):
709
+ m = ENTRY_RE.search(specification)
710
+ if not m:
711
+ result = None
712
+ if '[' in specification or ']' in specification:
713
+ raise DistlibException("Invalid specification "
714
+ "'%s'" % specification)
715
+ else:
716
+ d = m.groupdict()
717
+ name = d['name']
718
+ path = d['callable']
719
+ colons = path.count(':')
720
+ if colons == 0:
721
+ prefix, suffix = path, None
722
+ else:
723
+ if colons != 1:
724
+ raise DistlibException("Invalid specification "
725
+ "'%s'" % specification)
726
+ prefix, suffix = path.split(':')
727
+ flags = d['flags']
728
+ if flags is None:
729
+ if '[' in specification or ']' in specification:
730
+ raise DistlibException("Invalid specification "
731
+ "'%s'" % specification)
732
+ flags = []
733
+ else:
734
+ flags = [f.strip() for f in flags.split(',')]
735
+ result = ExportEntry(name, prefix, suffix, flags)
736
+ return result
737
+
738
+
739
+ def get_cache_base(suffix=None):
740
+ """
741
+ Return the default base location for distlib caches. If the directory does
742
+ not exist, it is created. Use the suffix provided for the base directory,
743
+ and default to '.distlib' if it isn't provided.
744
+
745
+ On Windows, if LOCALAPPDATA is defined in the environment, then it is
746
+ assumed to be a directory, and will be the parent directory of the result.
747
+ On POSIX, and on Windows if LOCALAPPDATA is not defined, the user's home
748
+ directory - using os.expanduser('~') - will be the parent directory of
749
+ the result.
750
+
751
+ The result is just the directory '.distlib' in the parent directory as
752
+ determined above, or with the name specified with ``suffix``.
753
+ """
754
+ if suffix is None:
755
+ suffix = '.distlib'
756
+ if os.name == 'nt' and 'LOCALAPPDATA' in os.environ:
757
+ result = os.path.expandvars('$localappdata')
758
+ else:
759
+ # Assume posix, or old Windows
760
+ result = os.path.expanduser('~')
761
+ # we use 'isdir' instead of 'exists', because we want to
762
+ # fail if there's a file with that name
763
+ if os.path.isdir(result):
764
+ usable = os.access(result, os.W_OK)
765
+ if not usable:
766
+ logger.warning('Directory exists but is not writable: %s', result)
767
+ else:
768
+ try:
769
+ os.makedirs(result)
770
+ usable = True
771
+ except OSError:
772
+ logger.warning('Unable to create %s', result, exc_info=True)
773
+ usable = False
774
+ if not usable:
775
+ result = tempfile.mkdtemp()
776
+ logger.warning('Default location unusable, using %s', result)
777
+ return os.path.join(result, suffix)
778
+
779
+
780
+ def path_to_cache_dir(path):
781
+ """
782
+ Convert an absolute path to a directory name for use in a cache.
783
+
784
+ The algorithm used is:
785
+
786
+ #. On Windows, any ``':'`` in the drive is replaced with ``'---'``.
787
+ #. Any occurrence of ``os.sep`` is replaced with ``'--'``.
788
+ #. ``'.cache'`` is appended.
789
+ """
790
+ d, p = os.path.splitdrive(os.path.abspath(path))
791
+ if d:
792
+ d = d.replace(':', '---')
793
+ p = p.replace(os.sep, '--')
794
+ return d + p + '.cache'
795
+
796
+
797
+ def ensure_slash(s):
798
+ if not s.endswith('/'):
799
+ return s + '/'
800
+ return s
801
+
802
+
803
+ def parse_credentials(netloc):
804
+ username = password = None
805
+ if '@' in netloc:
806
+ prefix, netloc = netloc.split('@', 1)
807
+ if ':' not in prefix:
808
+ username = prefix
809
+ else:
810
+ username, password = prefix.split(':', 1)
811
+ return username, password, netloc
812
+
813
+
814
+ def get_process_umask():
815
+ result = os.umask(0o22)
816
+ os.umask(result)
817
+ return result
818
+
819
+ def is_string_sequence(seq):
820
+ result = True
821
+ i = None
822
+ for i, s in enumerate(seq):
823
+ if not isinstance(s, string_types):
824
+ result = False
825
+ break
826
+ assert i is not None
827
+ return result
828
+
829
+ PROJECT_NAME_AND_VERSION = re.compile('([a-z0-9_]+([.-][a-z_][a-z0-9_]*)*)-'
830
+ '([a-z0-9_.+-]+)', re.I)
831
+ PYTHON_VERSION = re.compile(r'-py(\d\.?\d?)')
832
+
833
+
834
+ def split_filename(filename, project_name=None):
835
+ """
836
+ Extract name, version, python version from a filename (no extension)
837
+
838
+ Return name, version, pyver or None
839
+ """
840
+ result = None
841
+ pyver = None
842
+ filename = unquote(filename).replace(' ', '-')
843
+ m = PYTHON_VERSION.search(filename)
844
+ if m:
845
+ pyver = m.group(1)
846
+ filename = filename[:m.start()]
847
+ if project_name and len(filename) > len(project_name) + 1:
848
+ m = re.match(re.escape(project_name) + r'\b', filename)
849
+ if m:
850
+ n = m.end()
851
+ result = filename[:n], filename[n + 1:], pyver
852
+ if result is None:
853
+ m = PROJECT_NAME_AND_VERSION.match(filename)
854
+ if m:
855
+ result = m.group(1), m.group(3), pyver
856
+ return result
857
+
858
+ # Allow spaces in name because of legacy dists like "Twisted Core"
859
+ NAME_VERSION_RE = re.compile(r'(?P<name>[\w .-]+)\s*'
860
+ r'\(\s*(?P<ver>[^\s)]+)\)$')
861
+
862
+ def parse_name_and_version(p):
863
+ """
864
+ A utility method used to get name and version from a string.
865
+
866
+ From e.g. a Provides-Dist value.
867
+
868
+ :param p: A value in a form 'foo (1.0)'
869
+ :return: The name and version as a tuple.
870
+ """
871
+ m = NAME_VERSION_RE.match(p)
872
+ if not m:
873
+ raise DistlibException('Ill-formed name/version string: \'%s\'' % p)
874
+ d = m.groupdict()
875
+ return d['name'].strip().lower(), d['ver']
876
+
877
+ def get_extras(requested, available):
878
+ result = set()
879
+ requested = set(requested or [])
880
+ available = set(available or [])
881
+ if '*' in requested:
882
+ requested.remove('*')
883
+ result |= available
884
+ for r in requested:
885
+ if r == '-':
886
+ result.add(r)
887
+ elif r.startswith('-'):
888
+ unwanted = r[1:]
889
+ if unwanted not in available:
890
+ logger.warning('undeclared extra: %s' % unwanted)
891
+ if unwanted in result:
892
+ result.remove(unwanted)
893
+ else:
894
+ if r not in available:
895
+ logger.warning('undeclared extra: %s' % r)
896
+ result.add(r)
897
+ return result
898
+ #
899
+ # Extended metadata functionality
900
+ #
901
+
902
+ def _get_external_data(url):
903
+ result = {}
904
+ try:
905
+ # urlopen might fail if it runs into redirections,
906
+ # because of Python issue #13696. Fixed in locators
907
+ # using a custom redirect handler.
908
+ resp = urlopen(url)
909
+ headers = resp.info()
910
+ ct = headers.get('Content-Type')
911
+ if not ct.startswith('application/json'):
912
+ logger.debug('Unexpected response for JSON request: %s', ct)
913
+ else:
914
+ reader = codecs.getreader('utf-8')(resp)
915
+ #data = reader.read().decode('utf-8')
916
+ #result = json.loads(data)
917
+ result = json.load(reader)
918
+ except Exception as e:
919
+ logger.exception('Failed to get external data for %s: %s', url, e)
920
+ return result
921
+
922
+ _external_data_base_url = 'https://www.red-dove.com/pypi/projects/'
923
+
924
+ def get_project_data(name):
925
+ url = '%s/%s/project.json' % (name[0].upper(), name)
926
+ url = urljoin(_external_data_base_url, url)
927
+ result = _get_external_data(url)
928
+ return result
929
+
930
+ def get_package_data(name, version):
931
+ url = '%s/%s/package-%s.json' % (name[0].upper(), name, version)
932
+ url = urljoin(_external_data_base_url, url)
933
+ return _get_external_data(url)
934
+
935
+
936
+ class Cache(object):
937
+ """
938
+ A class implementing a cache for resources that need to live in the file system
939
+ e.g. shared libraries. This class was moved from resources to here because it
940
+ could be used by other modules, e.g. the wheel module.
941
+ """
942
+
943
+ def __init__(self, base):
944
+ """
945
+ Initialise an instance.
946
+
947
+ :param base: The base directory where the cache should be located.
948
+ """
949
+ # we use 'isdir' instead of 'exists', because we want to
950
+ # fail if there's a file with that name
951
+ if not os.path.isdir(base): # pragma: no cover
952
+ os.makedirs(base)
953
+ if (os.stat(base).st_mode & 0o77) != 0:
954
+ logger.warning('Directory \'%s\' is not private', base)
955
+ self.base = os.path.abspath(os.path.normpath(base))
956
+
957
+ def prefix_to_dir(self, prefix):
958
+ """
959
+ Converts a resource prefix to a directory name in the cache.
960
+ """
961
+ return path_to_cache_dir(prefix)
962
+
963
+ def clear(self):
964
+ """
965
+ Clear the cache.
966
+ """
967
+ not_removed = []
968
+ for fn in os.listdir(self.base):
969
+ fn = os.path.join(self.base, fn)
970
+ try:
971
+ if os.path.islink(fn) or os.path.isfile(fn):
972
+ os.remove(fn)
973
+ elif os.path.isdir(fn):
974
+ shutil.rmtree(fn)
975
+ except Exception:
976
+ not_removed.append(fn)
977
+ return not_removed
978
+
979
+
980
+ class EventMixin(object):
981
+ """
982
+ A very simple publish/subscribe system.
983
+ """
984
+ def __init__(self):
985
+ self._subscribers = {}
986
+
987
+ def add(self, event, subscriber, append=True):
988
+ """
989
+ Add a subscriber for an event.
990
+
991
+ :param event: The name of an event.
992
+ :param subscriber: The subscriber to be added (and called when the
993
+ event is published).
994
+ :param append: Whether to append or prepend the subscriber to an
995
+ existing subscriber list for the event.
996
+ """
997
+ subs = self._subscribers
998
+ if event not in subs:
999
+ subs[event] = deque([subscriber])
1000
+ else:
1001
+ sq = subs[event]
1002
+ if append:
1003
+ sq.append(subscriber)
1004
+ else:
1005
+ sq.appendleft(subscriber)
1006
+
1007
+ def remove(self, event, subscriber):
1008
+ """
1009
+ Remove a subscriber for an event.
1010
+
1011
+ :param event: The name of an event.
1012
+ :param subscriber: The subscriber to be removed.
1013
+ """
1014
+ subs = self._subscribers
1015
+ if event not in subs:
1016
+ raise ValueError('No subscribers: %r' % event)
1017
+ subs[event].remove(subscriber)
1018
+
1019
+ def get_subscribers(self, event):
1020
+ """
1021
+ Return an iterator for the subscribers for an event.
1022
+ :param event: The event to return subscribers for.
1023
+ """
1024
+ return iter(self._subscribers.get(event, ()))
1025
+
1026
+ def publish(self, event, *args, **kwargs):
1027
+ """
1028
+ Publish a event and return a list of values returned by its
1029
+ subscribers.
1030
+
1031
+ :param event: The event to publish.
1032
+ :param args: The positional arguments to pass to the event's
1033
+ subscribers.
1034
+ :param kwargs: The keyword arguments to pass to the event's
1035
+ subscribers.
1036
+ """
1037
+ result = []
1038
+ for subscriber in self.get_subscribers(event):
1039
+ try:
1040
+ value = subscriber(event, *args, **kwargs)
1041
+ except Exception:
1042
+ logger.exception('Exception during event publication')
1043
+ value = None
1044
+ result.append(value)
1045
+ logger.debug('publish %s: args = %s, kwargs = %s, result = %s',
1046
+ event, args, kwargs, result)
1047
+ return result
1048
+
1049
+ #
1050
+ # Simple sequencing
1051
+ #
1052
+ class Sequencer(object):
1053
+ def __init__(self):
1054
+ self._preds = {}
1055
+ self._succs = {}
1056
+ self._nodes = set() # nodes with no preds/succs
1057
+
1058
+ def add_node(self, node):
1059
+ self._nodes.add(node)
1060
+
1061
+ def remove_node(self, node, edges=False):
1062
+ if node in self._nodes:
1063
+ self._nodes.remove(node)
1064
+ if edges:
1065
+ for p in set(self._preds.get(node, ())):
1066
+ self.remove(p, node)
1067
+ for s in set(self._succs.get(node, ())):
1068
+ self.remove(node, s)
1069
+ # Remove empties
1070
+ for k, v in list(self._preds.items()):
1071
+ if not v:
1072
+ del self._preds[k]
1073
+ for k, v in list(self._succs.items()):
1074
+ if not v:
1075
+ del self._succs[k]
1076
+
1077
+ def add(self, pred, succ):
1078
+ assert pred != succ
1079
+ self._preds.setdefault(succ, set()).add(pred)
1080
+ self._succs.setdefault(pred, set()).add(succ)
1081
+
1082
+ def remove(self, pred, succ):
1083
+ assert pred != succ
1084
+ try:
1085
+ preds = self._preds[succ]
1086
+ succs = self._succs[pred]
1087
+ except KeyError: # pragma: no cover
1088
+ raise ValueError('%r not a successor of anything' % succ)
1089
+ try:
1090
+ preds.remove(pred)
1091
+ succs.remove(succ)
1092
+ except KeyError: # pragma: no cover
1093
+ raise ValueError('%r not a successor of %r' % (succ, pred))
1094
+
1095
+ def is_step(self, step):
1096
+ return (step in self._preds or step in self._succs or
1097
+ step in self._nodes)
1098
+
1099
+ def get_steps(self, final):
1100
+ if not self.is_step(final):
1101
+ raise ValueError('Unknown: %r' % final)
1102
+ result = []
1103
+ todo = []
1104
+ seen = set()
1105
+ todo.append(final)
1106
+ while todo:
1107
+ step = todo.pop(0)
1108
+ if step in seen:
1109
+ # if a step was already seen,
1110
+ # move it to the end (so it will appear earlier
1111
+ # when reversed on return) ... but not for the
1112
+ # final step, as that would be confusing for
1113
+ # users
1114
+ if step != final:
1115
+ result.remove(step)
1116
+ result.append(step)
1117
+ else:
1118
+ seen.add(step)
1119
+ result.append(step)
1120
+ preds = self._preds.get(step, ())
1121
+ todo.extend(preds)
1122
+ return reversed(result)
1123
+
1124
+ @property
1125
+ def strong_connections(self):
1126
+ #http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
1127
+ index_counter = [0]
1128
+ stack = []
1129
+ lowlinks = {}
1130
+ index = {}
1131
+ result = []
1132
+
1133
+ graph = self._succs
1134
+
1135
+ def strongconnect(node):
1136
+ # set the depth index for this node to the smallest unused index
1137
+ index[node] = index_counter[0]
1138
+ lowlinks[node] = index_counter[0]
1139
+ index_counter[0] += 1
1140
+ stack.append(node)
1141
+
1142
+ # Consider successors
1143
+ try:
1144
+ successors = graph[node]
1145
+ except Exception:
1146
+ successors = []
1147
+ for successor in successors:
1148
+ if successor not in lowlinks:
1149
+ # Successor has not yet been visited
1150
+ strongconnect(successor)
1151
+ lowlinks[node] = min(lowlinks[node],lowlinks[successor])
1152
+ elif successor in stack:
1153
+ # the successor is in the stack and hence in the current
1154
+ # strongly connected component (SCC)
1155
+ lowlinks[node] = min(lowlinks[node],index[successor])
1156
+
1157
+ # If `node` is a root node, pop the stack and generate an SCC
1158
+ if lowlinks[node] == index[node]:
1159
+ connected_component = []
1160
+
1161
+ while True:
1162
+ successor = stack.pop()
1163
+ connected_component.append(successor)
1164
+ if successor == node: break
1165
+ component = tuple(connected_component)
1166
+ # storing the result
1167
+ result.append(component)
1168
+
1169
+ for node in graph:
1170
+ if node not in lowlinks:
1171
+ strongconnect(node)
1172
+
1173
+ return result
1174
+
1175
+ @property
1176
+ def dot(self):
1177
+ result = ['digraph G {']
1178
+ for succ in self._preds:
1179
+ preds = self._preds[succ]
1180
+ for pred in preds:
1181
+ result.append(' %s -> %s;' % (pred, succ))
1182
+ for node in self._nodes:
1183
+ result.append(' %s;' % node)
1184
+ result.append('}')
1185
+ return '\n'.join(result)
1186
+
1187
+ #
1188
+ # Unarchiving functionality for zip, tar, tgz, tbz, whl
1189
+ #
1190
+
1191
+ ARCHIVE_EXTENSIONS = ('.tar.gz', '.tar.bz2', '.tar', '.zip',
1192
+ '.tgz', '.tbz', '.whl')
1193
+
1194
+ def unarchive(archive_filename, dest_dir, format=None, check=True):
1195
+
1196
+ def check_path(path):
1197
+ if not isinstance(path, text_type):
1198
+ path = path.decode('utf-8')
1199
+ p = os.path.abspath(os.path.join(dest_dir, path))
1200
+ if not p.startswith(dest_dir) or p[plen] != os.sep:
1201
+ raise ValueError('path outside destination: %r' % p)
1202
+
1203
+ dest_dir = os.path.abspath(dest_dir)
1204
+ plen = len(dest_dir)
1205
+ archive = None
1206
+ if format is None:
1207
+ if archive_filename.endswith(('.zip', '.whl')):
1208
+ format = 'zip'
1209
+ elif archive_filename.endswith(('.tar.gz', '.tgz')):
1210
+ format = 'tgz'
1211
+ mode = 'r:gz'
1212
+ elif archive_filename.endswith(('.tar.bz2', '.tbz')):
1213
+ format = 'tbz'
1214
+ mode = 'r:bz2'
1215
+ elif archive_filename.endswith('.tar'):
1216
+ format = 'tar'
1217
+ mode = 'r'
1218
+ else: # pragma: no cover
1219
+ raise ValueError('Unknown format for %r' % archive_filename)
1220
+ try:
1221
+ if format == 'zip':
1222
+ archive = ZipFile(archive_filename, 'r')
1223
+ if check:
1224
+ names = archive.namelist()
1225
+ for name in names:
1226
+ check_path(name)
1227
+ else:
1228
+ archive = tarfile.open(archive_filename, mode)
1229
+ if check:
1230
+ names = archive.getnames()
1231
+ for name in names:
1232
+ check_path(name)
1233
+ if format != 'zip' and sys.version_info[0] < 3:
1234
+ # See Python issue 17153. If the dest path contains Unicode,
1235
+ # tarfile extraction fails on Python 2.x if a member path name
1236
+ # contains non-ASCII characters - it leads to an implicit
1237
+ # bytes -> unicode conversion using ASCII to decode.
1238
+ for tarinfo in archive.getmembers():
1239
+ if not isinstance(tarinfo.name, text_type):
1240
+ tarinfo.name = tarinfo.name.decode('utf-8')
1241
+ archive.extractall(dest_dir)
1242
+
1243
+ finally:
1244
+ if archive:
1245
+ archive.close()
1246
+
1247
+
1248
+ def zip_dir(directory):
1249
+ """zip a directory tree into a BytesIO object"""
1250
+ result = io.BytesIO()
1251
+ dlen = len(directory)
1252
+ with ZipFile(result, "w") as zf:
1253
+ for root, dirs, files in os.walk(directory):
1254
+ for name in files:
1255
+ full = os.path.join(root, name)
1256
+ rel = root[dlen:]
1257
+ dest = os.path.join(rel, name)
1258
+ zf.write(full, dest)
1259
+ return result
1260
+
1261
+ #
1262
+ # Simple progress bar
1263
+ #
1264
+
1265
+ UNITS = ('', 'K', 'M', 'G','T','P')
1266
+
1267
+
1268
+ class Progress(object):
1269
+ unknown = 'UNKNOWN'
1270
+
1271
+ def __init__(self, minval=0, maxval=100):
1272
+ assert maxval is None or maxval >= minval
1273
+ self.min = self.cur = minval
1274
+ self.max = maxval
1275
+ self.started = None
1276
+ self.elapsed = 0
1277
+ self.done = False
1278
+
1279
+ def update(self, curval):
1280
+ assert self.min <= curval
1281
+ assert self.max is None or curval <= self.max
1282
+ self.cur = curval
1283
+ now = time.time()
1284
+ if self.started is None:
1285
+ self.started = now
1286
+ else:
1287
+ self.elapsed = now - self.started
1288
+
1289
+ def increment(self, incr):
1290
+ assert incr >= 0
1291
+ self.update(self.cur + incr)
1292
+
1293
+ def start(self):
1294
+ self.update(self.min)
1295
+ return self
1296
+
1297
+ def stop(self):
1298
+ if self.max is not None:
1299
+ self.update(self.max)
1300
+ self.done = True
1301
+
1302
+ @property
1303
+ def maximum(self):
1304
+ return self.unknown if self.max is None else self.max
1305
+
1306
+ @property
1307
+ def percentage(self):
1308
+ if self.done:
1309
+ result = '100 %'
1310
+ elif self.max is None:
1311
+ result = ' ?? %'
1312
+ else:
1313
+ v = 100.0 * (self.cur - self.min) / (self.max - self.min)
1314
+ result = '%3d %%' % v
1315
+ return result
1316
+
1317
+ def format_duration(self, duration):
1318
+ if (duration <= 0) and self.max is None or self.cur == self.min:
1319
+ result = '??:??:??'
1320
+ #elif duration < 1:
1321
+ # result = '--:--:--'
1322
+ else:
1323
+ result = time.strftime('%H:%M:%S', time.gmtime(duration))
1324
+ return result
1325
+
1326
+ @property
1327
+ def ETA(self):
1328
+ if self.done:
1329
+ prefix = 'Done'
1330
+ t = self.elapsed
1331
+ #import pdb; pdb.set_trace()
1332
+ else:
1333
+ prefix = 'ETA '
1334
+ if self.max is None:
1335
+ t = -1
1336
+ elif self.elapsed == 0 or (self.cur == self.min):
1337
+ t = 0
1338
+ else:
1339
+ #import pdb; pdb.set_trace()
1340
+ t = float(self.max - self.min)
1341
+ t /= self.cur - self.min
1342
+ t = (t - 1) * self.elapsed
1343
+ return '%s: %s' % (prefix, self.format_duration(t))
1344
+
1345
+ @property
1346
+ def speed(self):
1347
+ if self.elapsed == 0:
1348
+ result = 0.0
1349
+ else:
1350
+ result = (self.cur - self.min) / self.elapsed
1351
+ for unit in UNITS:
1352
+ if result < 1000:
1353
+ break
1354
+ result /= 1000.0
1355
+ return '%d %sB/s' % (result, unit)
1356
+
1357
+ #
1358
+ # Glob functionality
1359
+ #
1360
+
1361
+ RICH_GLOB = re.compile(r'\{([^}]*)\}')
1362
+ _CHECK_RECURSIVE_GLOB = re.compile(r'[^/\\,{]\*\*|\*\*[^/\\,}]')
1363
+ _CHECK_MISMATCH_SET = re.compile(r'^[^{]*\}|\{[^}]*$')
1364
+
1365
+
1366
+ def iglob(path_glob):
1367
+ """Extended globbing function that supports ** and {opt1,opt2,opt3}."""
1368
+ if _CHECK_RECURSIVE_GLOB.search(path_glob):
1369
+ msg = """invalid glob %r: recursive glob "**" must be used alone"""
1370
+ raise ValueError(msg % path_glob)
1371
+ if _CHECK_MISMATCH_SET.search(path_glob):
1372
+ msg = """invalid glob %r: mismatching set marker '{' or '}'"""
1373
+ raise ValueError(msg % path_glob)
1374
+ return _iglob(path_glob)
1375
+
1376
+
1377
+ def _iglob(path_glob):
1378
+ rich_path_glob = RICH_GLOB.split(path_glob, 1)
1379
+ if len(rich_path_glob) > 1:
1380
+ assert len(rich_path_glob) == 3, rich_path_glob
1381
+ prefix, set, suffix = rich_path_glob
1382
+ for item in set.split(','):
1383
+ for path in _iglob(''.join((prefix, item, suffix))):
1384
+ yield path
1385
+ else:
1386
+ if '**' not in path_glob:
1387
+ for item in std_iglob(path_glob):
1388
+ yield item
1389
+ else:
1390
+ prefix, radical = path_glob.split('**', 1)
1391
+ if prefix == '':
1392
+ prefix = '.'
1393
+ if radical == '':
1394
+ radical = '*'
1395
+ else:
1396
+ # we support both
1397
+ radical = radical.lstrip('/')
1398
+ radical = radical.lstrip('\\')
1399
+ for path, dir, files in os.walk(prefix):
1400
+ path = os.path.normpath(path)
1401
+ for fn in _iglob(os.path.join(path, radical)):
1402
+ yield fn
1403
+
1404
+ if ssl:
1405
+ from .compat import (HTTPSHandler as BaseHTTPSHandler, match_hostname,
1406
+ CertificateError)
1407
+
1408
+
1409
+ #
1410
+ # HTTPSConnection which verifies certificates/matches domains
1411
+ #
1412
+
1413
+ class HTTPSConnection(httplib.HTTPSConnection):
1414
+ ca_certs = None # set this to the path to the certs file (.pem)
1415
+ check_domain = True # only used if ca_certs is not None
1416
+
1417
+ # noinspection PyPropertyAccess
1418
+ def connect(self):
1419
+ sock = socket.create_connection((self.host, self.port), self.timeout)
1420
+ if getattr(self, '_tunnel_host', False):
1421
+ self.sock = sock
1422
+ self._tunnel()
1423
+
1424
+ if not hasattr(ssl, 'SSLContext'):
1425
+ # For 2.x
1426
+ if self.ca_certs:
1427
+ cert_reqs = ssl.CERT_REQUIRED
1428
+ else:
1429
+ cert_reqs = ssl.CERT_NONE
1430
+ self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
1431
+ cert_reqs=cert_reqs,
1432
+ ssl_version=ssl.PROTOCOL_SSLv23,
1433
+ ca_certs=self.ca_certs)
1434
+ else: # pragma: no cover
1435
+ context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1436
+ context.options |= ssl.OP_NO_SSLv2
1437
+ if self.cert_file:
1438
+ context.load_cert_chain(self.cert_file, self.key_file)
1439
+ kwargs = {}
1440
+ if self.ca_certs:
1441
+ context.verify_mode = ssl.CERT_REQUIRED
1442
+ context.load_verify_locations(cafile=self.ca_certs)
1443
+ if getattr(ssl, 'HAS_SNI', False):
1444
+ kwargs['server_hostname'] = self.host
1445
+ self.sock = context.wrap_socket(sock, **kwargs)
1446
+ if self.ca_certs and self.check_domain:
1447
+ try:
1448
+ match_hostname(self.sock.getpeercert(), self.host)
1449
+ logger.debug('Host verified: %s', self.host)
1450
+ except CertificateError: # pragma: no cover
1451
+ self.sock.shutdown(socket.SHUT_RDWR)
1452
+ self.sock.close()
1453
+ raise
1454
+
1455
+ class HTTPSHandler(BaseHTTPSHandler):
1456
+ def __init__(self, ca_certs, check_domain=True):
1457
+ BaseHTTPSHandler.__init__(self)
1458
+ self.ca_certs = ca_certs
1459
+ self.check_domain = check_domain
1460
+
1461
+ def _conn_maker(self, *args, **kwargs):
1462
+ """
1463
+ This is called to create a connection instance. Normally you'd
1464
+ pass a connection class to do_open, but it doesn't actually check for
1465
+ a class, and just expects a callable. As long as we behave just as a
1466
+ constructor would have, we should be OK. If it ever changes so that
1467
+ we *must* pass a class, we'll create an UnsafeHTTPSConnection class
1468
+ which just sets check_domain to False in the class definition, and
1469
+ choose which one to pass to do_open.
1470
+ """
1471
+ result = HTTPSConnection(*args, **kwargs)
1472
+ if self.ca_certs:
1473
+ result.ca_certs = self.ca_certs
1474
+ result.check_domain = self.check_domain
1475
+ return result
1476
+
1477
+ def https_open(self, req):
1478
+ try:
1479
+ return self.do_open(self._conn_maker, req)
1480
+ except URLError as e:
1481
+ if 'certificate verify failed' in str(e.reason):
1482
+ raise CertificateError('Unable to verify server certificate '
1483
+ 'for %s' % req.host)
1484
+ else:
1485
+ raise
1486
+
1487
+ #
1488
+ # To prevent against mixing HTTP traffic with HTTPS (examples: A Man-In-The-
1489
+ # Middle proxy using HTTP listens on port 443, or an index mistakenly serves
1490
+ # HTML containing a http://xyz link when it should be https://xyz),
1491
+ # you can use the following handler class, which does not allow HTTP traffic.
1492
+ #
1493
+ # It works by inheriting from HTTPHandler - so build_opener won't add a
1494
+ # handler for HTTP itself.
1495
+ #
1496
+ class HTTPSOnlyHandler(HTTPSHandler, HTTPHandler):
1497
+ def http_open(self, req):
1498
+ raise URLError('Unexpected HTTP request on what should be a secure '
1499
+ 'connection: %s' % req)
1500
+
1501
+ #
1502
+ # XML-RPC with timeouts
1503
+ #
1504
+
1505
+ _ver_info = sys.version_info[:2]
1506
+
1507
+ if _ver_info == (2, 6):
1508
+ class HTTP(httplib.HTTP):
1509
+ def __init__(self, host='', port=None, **kwargs):
1510
+ if port == 0: # 0 means use port 0, not the default port
1511
+ port = None
1512
+ self._setup(self._connection_class(host, port, **kwargs))
1513
+
1514
+
1515
+ if ssl:
1516
+ class HTTPS(httplib.HTTPS):
1517
+ def __init__(self, host='', port=None, **kwargs):
1518
+ if port == 0: # 0 means use port 0, not the default port
1519
+ port = None
1520
+ self._setup(self._connection_class(host, port, **kwargs))
1521
+
1522
+
1523
+ class Transport(xmlrpclib.Transport):
1524
+ def __init__(self, timeout, use_datetime=0):
1525
+ self.timeout = timeout
1526
+ xmlrpclib.Transport.__init__(self, use_datetime)
1527
+
1528
+ def make_connection(self, host):
1529
+ h, eh, x509 = self.get_host_info(host)
1530
+ if _ver_info == (2, 6):
1531
+ result = HTTP(h, timeout=self.timeout)
1532
+ else:
1533
+ if not self._connection or host != self._connection[0]:
1534
+ self._extra_headers = eh
1535
+ self._connection = host, httplib.HTTPConnection(h)
1536
+ result = self._connection[1]
1537
+ return result
1538
+
1539
+ if ssl:
1540
+ class SafeTransport(xmlrpclib.SafeTransport):
1541
+ def __init__(self, timeout, use_datetime=0):
1542
+ self.timeout = timeout
1543
+ xmlrpclib.SafeTransport.__init__(self, use_datetime)
1544
+
1545
+ def make_connection(self, host):
1546
+ h, eh, kwargs = self.get_host_info(host)
1547
+ if not kwargs:
1548
+ kwargs = {}
1549
+ kwargs['timeout'] = self.timeout
1550
+ if _ver_info == (2, 6):
1551
+ result = HTTPS(host, None, **kwargs)
1552
+ else:
1553
+ if not self._connection or host != self._connection[0]:
1554
+ self._extra_headers = eh
1555
+ self._connection = host, httplib.HTTPSConnection(h, None,
1556
+ **kwargs)
1557
+ result = self._connection[1]
1558
+ return result
1559
+
1560
+
1561
+ class ServerProxy(xmlrpclib.ServerProxy):
1562
+ def __init__(self, uri, **kwargs):
1563
+ self.timeout = timeout = kwargs.pop('timeout', None)
1564
+ # The above classes only come into play if a timeout
1565
+ # is specified
1566
+ if timeout is not None:
1567
+ scheme, _ = splittype(uri)
1568
+ use_datetime = kwargs.get('use_datetime', 0)
1569
+ if scheme == 'https':
1570
+ tcls = SafeTransport
1571
+ else:
1572
+ tcls = Transport
1573
+ kwargs['transport'] = t = tcls(timeout, use_datetime=use_datetime)
1574
+ self.transport = t
1575
+ xmlrpclib.ServerProxy.__init__(self, uri, **kwargs)
1576
+
1577
+ #
1578
+ # CSV functionality. This is provided because on 2.x, the csv module can't
1579
+ # handle Unicode. However, we need to deal with Unicode in e.g. RECORD files.
1580
+ #
1581
+
1582
+ def _csv_open(fn, mode, **kwargs):
1583
+ if sys.version_info[0] < 3:
1584
+ mode += 'b'
1585
+ else:
1586
+ kwargs['newline'] = ''
1587
+ # Python 3 determines encoding from locale. Force 'utf-8'
1588
+ # file encoding to match other forced utf-8 encoding
1589
+ kwargs['encoding'] = 'utf-8'
1590
+ return open(fn, mode, **kwargs)
1591
+
1592
+
1593
+ class CSVBase(object):
1594
+ defaults = {
1595
+ 'delimiter': str(','), # The strs are used because we need native
1596
+ 'quotechar': str('"'), # str in the csv API (2.x won't take
1597
+ 'lineterminator': str('\n') # Unicode)
1598
+ }
1599
+
1600
+ def __enter__(self):
1601
+ return self
1602
+
1603
+ def __exit__(self, *exc_info):
1604
+ self.stream.close()
1605
+
1606
+
1607
+ class CSVReader(CSVBase):
1608
+ def __init__(self, **kwargs):
1609
+ if 'stream' in kwargs:
1610
+ stream = kwargs['stream']
1611
+ if sys.version_info[0] >= 3:
1612
+ # needs to be a text stream
1613
+ stream = codecs.getreader('utf-8')(stream)
1614
+ self.stream = stream
1615
+ else:
1616
+ self.stream = _csv_open(kwargs['path'], 'r')
1617
+ self.reader = csv.reader(self.stream, **self.defaults)
1618
+
1619
+ def __iter__(self):
1620
+ return self
1621
+
1622
+ def next(self):
1623
+ result = next(self.reader)
1624
+ if sys.version_info[0] < 3:
1625
+ for i, item in enumerate(result):
1626
+ if not isinstance(item, text_type):
1627
+ result[i] = item.decode('utf-8')
1628
+ return result
1629
+
1630
+ __next__ = next
1631
+
1632
+ class CSVWriter(CSVBase):
1633
+ def __init__(self, fn, **kwargs):
1634
+ self.stream = _csv_open(fn, 'w')
1635
+ self.writer = csv.writer(self.stream, **self.defaults)
1636
+
1637
+ def writerow(self, row):
1638
+ if sys.version_info[0] < 3:
1639
+ r = []
1640
+ for item in row:
1641
+ if isinstance(item, text_type):
1642
+ item = item.encode('utf-8')
1643
+ r.append(item)
1644
+ row = r
1645
+ self.writer.writerow(row)
1646
+
1647
+ #
1648
+ # Configurator functionality
1649
+ #
1650
+
1651
+ class Configurator(BaseConfigurator):
1652
+
1653
+ value_converters = dict(BaseConfigurator.value_converters)
1654
+ value_converters['inc'] = 'inc_convert'
1655
+
1656
+ def __init__(self, config, base=None):
1657
+ super(Configurator, self).__init__(config)
1658
+ self.base = base or os.getcwd()
1659
+
1660
+ def configure_custom(self, config):
1661
+ def convert(o):
1662
+ if isinstance(o, (list, tuple)):
1663
+ result = type(o)([convert(i) for i in o])
1664
+ elif isinstance(o, dict):
1665
+ if '()' in o:
1666
+ result = self.configure_custom(o)
1667
+ else:
1668
+ result = {}
1669
+ for k in o:
1670
+ result[k] = convert(o[k])
1671
+ else:
1672
+ result = self.convert(o)
1673
+ return result
1674
+
1675
+ c = config.pop('()')
1676
+ if not callable(c):
1677
+ c = self.resolve(c)
1678
+ props = config.pop('.', None)
1679
+ # Check for valid identifiers
1680
+ args = config.pop('[]', ())
1681
+ if args:
1682
+ args = tuple([convert(o) for o in args])
1683
+ items = [(k, convert(config[k])) for k in config if valid_ident(k)]
1684
+ kwargs = dict(items)
1685
+ result = c(*args, **kwargs)
1686
+ if props:
1687
+ for n, v in props.items():
1688
+ setattr(result, n, convert(v))
1689
+ return result
1690
+
1691
+ def __getitem__(self, key):
1692
+ result = self.config[key]
1693
+ if isinstance(result, dict) and '()' in result:
1694
+ self.config[key] = result = self.configure_custom(result)
1695
+ return result
1696
+
1697
+ def inc_convert(self, value):
1698
+ """Default converter for the inc:// protocol."""
1699
+ if not os.path.isabs(value):
1700
+ value = os.path.join(self.base, value)
1701
+ with codecs.open(value, 'r', encoding='utf-8') as f:
1702
+ result = json.load(f)
1703
+ return result
1704
+
1705
+
1706
+ class SubprocessMixin(object):
1707
+ """
1708
+ Mixin for running subprocesses and capturing their output
1709
+ """
1710
+ def __init__(self, verbose=False, progress=None):
1711
+ self.verbose = verbose
1712
+ self.progress = progress
1713
+
1714
+ def reader(self, stream, context):
1715
+ """
1716
+ Read lines from a subprocess' output stream and either pass to a progress
1717
+ callable (if specified) or write progress information to sys.stderr.
1718
+ """
1719
+ progress = self.progress
1720
+ verbose = self.verbose
1721
+ while True:
1722
+ s = stream.readline()
1723
+ if not s:
1724
+ break
1725
+ if progress is not None:
1726
+ progress(s, context)
1727
+ else:
1728
+ if not verbose:
1729
+ sys.stderr.write('.')
1730
+ else:
1731
+ sys.stderr.write(s.decode('utf-8'))
1732
+ sys.stderr.flush()
1733
+ stream.close()
1734
+
1735
+ def run_command(self, cmd, **kwargs):
1736
+ p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
1737
+ stderr=subprocess.PIPE, **kwargs)
1738
+ t1 = threading.Thread(target=self.reader, args=(p.stdout, 'stdout'))
1739
+ t1.start()
1740
+ t2 = threading.Thread(target=self.reader, args=(p.stderr, 'stderr'))
1741
+ t2.start()
1742
+ p.wait()
1743
+ t1.join()
1744
+ t2.join()
1745
+ if self.progress is not None:
1746
+ self.progress('done.', 'main')
1747
+ elif self.verbose:
1748
+ sys.stderr.write('done.\n')
1749
+ return p
1750
+
1751
+
1752
+ def normalize_name(name):
1753
+ """Normalize a python package name a la PEP 503"""
1754
+ # https://www.python.org/dev/peps/pep-0503/#normalized-names
1755
+ return re.sub('[-_.]+', '-', name).lower()