__init__.py 106 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072
  1. """
  2. Package resource API
  3. --------------------
  4. A resource is a logical file contained within a package, or a logical
  5. subdirectory thereof. The package resource API expects resource names
  6. to have their path parts separated with ``/``, *not* whatever the local
  7. path separator is. Do not use os.path operations to manipulate resource
  8. names being passed into the API.
  9. The package resource API is designed to work with normal filesystem packages,
  10. .egg files, and unpacked .egg files. It can also work in a limited way with
  11. .zip files and with custom PEP 302 loaders that support the ``get_data()``
  12. method.
  13. """
  14. from __future__ import absolute_import
  15. import sys
  16. import os
  17. import io
  18. import time
  19. import re
  20. import imp
  21. import zipfile
  22. import zipimport
  23. import warnings
  24. import stat
  25. import functools
  26. import pkgutil
  27. import token
  28. import symbol
  29. import operator
  30. import platform
  31. import collections
  32. import plistlib
  33. import email.parser
  34. import tempfile
  35. import textwrap
  36. from pkgutil import get_importer
  37. PY3 = sys.version_info > (3,)
  38. PY2 = not PY3
  39. if PY3:
  40. from urllib.parse import urlparse, urlunparse
  41. if PY2:
  42. from urlparse import urlparse, urlunparse
  43. if PY3:
  44. string_types = str,
  45. else:
  46. string_types = str, eval('unicode')
  47. iteritems = (lambda i: i.items()) if PY3 else lambda i: i.iteritems()
  48. # capture these to bypass sandboxing
  49. from os import utime
  50. try:
  51. from os import mkdir, rename, unlink
  52. WRITE_SUPPORT = True
  53. except ImportError:
  54. # no write support, probably under GAE
  55. WRITE_SUPPORT = False
  56. from os import open as os_open
  57. from os.path import isdir, split
  58. # Avoid try/except due to potential problems with delayed import mechanisms.
  59. if sys.version_info >= (3, 3) and sys.implementation.name == "cpython":
  60. import importlib._bootstrap as importlib_bootstrap
  61. else:
  62. importlib_bootstrap = None
  63. try:
  64. import parser
  65. except ImportError:
  66. pass
  67. try:
  68. import pkg_resources._vendor.packaging.version
  69. import pkg_resources._vendor.packaging.specifiers
  70. packaging = pkg_resources._vendor.packaging
  71. except ImportError:
  72. # fallback to naturally-installed version; allows system packagers to
  73. # omit vendored packages.
  74. import packaging.version
  75. import packaging.specifiers
  76. class PEP440Warning(RuntimeWarning):
  77. """
  78. Used when there is an issue with a version or specifier not complying with
  79. PEP 440.
  80. """
  81. class _SetuptoolsVersionMixin(object):
  82. def __hash__(self):
  83. return super(_SetuptoolsVersionMixin, self).__hash__()
  84. def __lt__(self, other):
  85. if isinstance(other, tuple):
  86. return tuple(self) < other
  87. else:
  88. return super(_SetuptoolsVersionMixin, self).__lt__(other)
  89. def __le__(self, other):
  90. if isinstance(other, tuple):
  91. return tuple(self) <= other
  92. else:
  93. return super(_SetuptoolsVersionMixin, self).__le__(other)
  94. def __eq__(self, other):
  95. if isinstance(other, tuple):
  96. return tuple(self) == other
  97. else:
  98. return super(_SetuptoolsVersionMixin, self).__eq__(other)
  99. def __ge__(self, other):
  100. if isinstance(other, tuple):
  101. return tuple(self) >= other
  102. else:
  103. return super(_SetuptoolsVersionMixin, self).__ge__(other)
  104. def __gt__(self, other):
  105. if isinstance(other, tuple):
  106. return tuple(self) > other
  107. else:
  108. return super(_SetuptoolsVersionMixin, self).__gt__(other)
  109. def __ne__(self, other):
  110. if isinstance(other, tuple):
  111. return tuple(self) != other
  112. else:
  113. return super(_SetuptoolsVersionMixin, self).__ne__(other)
  114. def __getitem__(self, key):
  115. return tuple(self)[key]
  116. def __iter__(self):
  117. component_re = re.compile(r'(\d+ | [a-z]+ | \.| -)', re.VERBOSE)
  118. replace = {
  119. 'pre': 'c',
  120. 'preview': 'c',
  121. '-': 'final-',
  122. 'rc': 'c',
  123. 'dev': '@',
  124. }.get
  125. def _parse_version_parts(s):
  126. for part in component_re.split(s):
  127. part = replace(part, part)
  128. if not part or part == '.':
  129. continue
  130. if part[:1] in '0123456789':
  131. # pad for numeric comparison
  132. yield part.zfill(8)
  133. else:
  134. yield '*'+part
  135. # ensure that alpha/beta/candidate are before final
  136. yield '*final'
  137. def old_parse_version(s):
  138. parts = []
  139. for part in _parse_version_parts(s.lower()):
  140. if part.startswith('*'):
  141. # remove '-' before a prerelease tag
  142. if part < '*final':
  143. while parts and parts[-1] == '*final-':
  144. parts.pop()
  145. # remove trailing zeros from each series of numeric parts
  146. while parts and parts[-1] == '00000000':
  147. parts.pop()
  148. parts.append(part)
  149. return tuple(parts)
  150. # Warn for use of this function
  151. warnings.warn(
  152. "You have iterated over the result of "
  153. "pkg_resources.parse_version. This is a legacy behavior which is "
  154. "inconsistent with the new version class introduced in setuptools "
  155. "8.0. In most cases, conversion to a tuple is unnecessary. For "
  156. "comparison of versions, sort the Version instances directly. If "
  157. "you have another use case requiring the tuple, please file a "
  158. "bug with the setuptools project describing that need.",
  159. RuntimeWarning,
  160. stacklevel=1,
  161. )
  162. for part in old_parse_version(str(self)):
  163. yield part
  164. class SetuptoolsVersion(_SetuptoolsVersionMixin, packaging.version.Version):
  165. pass
  166. class SetuptoolsLegacyVersion(_SetuptoolsVersionMixin,
  167. packaging.version.LegacyVersion):
  168. pass
  169. def parse_version(v):
  170. try:
  171. return SetuptoolsVersion(v)
  172. except packaging.version.InvalidVersion:
  173. return SetuptoolsLegacyVersion(v)
  174. _state_vars = {}
  175. def _declare_state(vartype, **kw):
  176. globals().update(kw)
  177. _state_vars.update(dict.fromkeys(kw, vartype))
  178. def __getstate__():
  179. state = {}
  180. g = globals()
  181. for k, v in _state_vars.items():
  182. state[k] = g['_sget_'+v](g[k])
  183. return state
  184. def __setstate__(state):
  185. g = globals()
  186. for k, v in state.items():
  187. g['_sset_'+_state_vars[k]](k, g[k], v)
  188. return state
  189. def _sget_dict(val):
  190. return val.copy()
  191. def _sset_dict(key, ob, state):
  192. ob.clear()
  193. ob.update(state)
  194. def _sget_object(val):
  195. return val.__getstate__()
  196. def _sset_object(key, ob, state):
  197. ob.__setstate__(state)
  198. _sget_none = _sset_none = lambda *args: None
  199. def get_supported_platform():
  200. """Return this platform's maximum compatible version.
  201. distutils.util.get_platform() normally reports the minimum version
  202. of Mac OS X that would be required to *use* extensions produced by
  203. distutils. But what we want when checking compatibility is to know the
  204. version of Mac OS X that we are *running*. To allow usage of packages that
  205. explicitly require a newer version of Mac OS X, we must also know the
  206. current version of the OS.
  207. If this condition occurs for any other platform with a version in its
  208. platform strings, this function should be extended accordingly.
  209. """
  210. plat = get_build_platform()
  211. m = macosVersionString.match(plat)
  212. if m is not None and sys.platform == "darwin":
  213. try:
  214. plat = 'macosx-%s-%s' % ('.'.join(_macosx_vers()[:2]), m.group(3))
  215. except ValueError:
  216. # not Mac OS X
  217. pass
  218. return plat
  219. __all__ = [
  220. # Basic resource access and distribution/entry point discovery
  221. 'require', 'run_script', 'get_provider', 'get_distribution',
  222. 'load_entry_point', 'get_entry_map', 'get_entry_info',
  223. 'iter_entry_points',
  224. 'resource_string', 'resource_stream', 'resource_filename',
  225. 'resource_listdir', 'resource_exists', 'resource_isdir',
  226. # Environmental control
  227. 'declare_namespace', 'working_set', 'add_activation_listener',
  228. 'find_distributions', 'set_extraction_path', 'cleanup_resources',
  229. 'get_default_cache',
  230. # Primary implementation classes
  231. 'Environment', 'WorkingSet', 'ResourceManager',
  232. 'Distribution', 'Requirement', 'EntryPoint',
  233. # Exceptions
  234. 'ResolutionError', 'VersionConflict', 'DistributionNotFound',
  235. 'UnknownExtra', 'ExtractionError',
  236. # Warnings
  237. 'PEP440Warning',
  238. # Parsing functions and string utilities
  239. 'parse_requirements', 'parse_version', 'safe_name', 'safe_version',
  240. 'get_platform', 'compatible_platforms', 'yield_lines', 'split_sections',
  241. 'safe_extra', 'to_filename', 'invalid_marker', 'evaluate_marker',
  242. # filesystem utilities
  243. 'ensure_directory', 'normalize_path',
  244. # Distribution "precedence" constants
  245. 'EGG_DIST', 'BINARY_DIST', 'SOURCE_DIST', 'CHECKOUT_DIST', 'DEVELOP_DIST',
  246. # "Provider" interfaces, implementations, and registration/lookup APIs
  247. 'IMetadataProvider', 'IResourceProvider', 'FileMetadata',
  248. 'PathMetadata', 'EggMetadata', 'EmptyProvider', 'empty_provider',
  249. 'NullProvider', 'EggProvider', 'DefaultProvider', 'ZipProvider',
  250. 'register_finder', 'register_namespace_handler', 'register_loader_type',
  251. 'fixup_namespace_packages', 'get_importer',
  252. # Deprecated/backward compatibility only
  253. 'run_main', 'AvailableDistributions',
  254. ]
  255. class ResolutionError(Exception):
  256. """Abstract base for dependency resolution errors"""
  257. def __repr__(self):
  258. return self.__class__.__name__+repr(self.args)
  259. class VersionConflict(ResolutionError):
  260. """
  261. An already-installed version conflicts with the requested version.
  262. Should be initialized with the installed Distribution and the requested
  263. Requirement.
  264. """
  265. _template = "{self.dist} is installed but {self.req} is required"
  266. @property
  267. def dist(self):
  268. return self.args[0]
  269. @property
  270. def req(self):
  271. return self.args[1]
  272. def report(self):
  273. return self._template.format(**locals())
  274. def with_context(self, required_by):
  275. """
  276. If required_by is non-empty, return a version of self that is a
  277. ContextualVersionConflict.
  278. """
  279. if not required_by:
  280. return self
  281. args = self.args + (required_by,)
  282. return ContextualVersionConflict(*args)
  283. class ContextualVersionConflict(VersionConflict):
  284. """
  285. A VersionConflict that accepts a third parameter, the set of the
  286. requirements that required the installed Distribution.
  287. """
  288. _template = VersionConflict._template + ' by {self.required_by}'
  289. @property
  290. def required_by(self):
  291. return self.args[2]
  292. class DistributionNotFound(ResolutionError):
  293. """A requested distribution was not found"""
  294. _template = ("The '{self.req}' distribution was not found "
  295. "and is required by {self.requirers_str}")
  296. @property
  297. def req(self):
  298. return self.args[0]
  299. @property
  300. def requirers(self):
  301. return self.args[1]
  302. @property
  303. def requirers_str(self):
  304. if not self.requirers:
  305. return 'the application'
  306. return ', '.join(self.requirers)
  307. def report(self):
  308. return self._template.format(**locals())
  309. def __str__(self):
  310. return self.report()
  311. class UnknownExtra(ResolutionError):
  312. """Distribution doesn't have an "extra feature" of the given name"""
  313. _provider_factories = {}
  314. PY_MAJOR = sys.version[:3]
  315. EGG_DIST = 3
  316. BINARY_DIST = 2
  317. SOURCE_DIST = 1
  318. CHECKOUT_DIST = 0
  319. DEVELOP_DIST = -1
  320. def register_loader_type(loader_type, provider_factory):
  321. """Register `provider_factory` to make providers for `loader_type`
  322. `loader_type` is the type or class of a PEP 302 ``module.__loader__``,
  323. and `provider_factory` is a function that, passed a *module* object,
  324. returns an ``IResourceProvider`` for that module.
  325. """
  326. _provider_factories[loader_type] = provider_factory
  327. def get_provider(moduleOrReq):
  328. """Return an IResourceProvider for the named module or requirement"""
  329. if isinstance(moduleOrReq, Requirement):
  330. return working_set.find(moduleOrReq) or require(str(moduleOrReq))[0]
  331. try:
  332. module = sys.modules[moduleOrReq]
  333. except KeyError:
  334. __import__(moduleOrReq)
  335. module = sys.modules[moduleOrReq]
  336. loader = getattr(module, '__loader__', None)
  337. return _find_adapter(_provider_factories, loader)(module)
  338. def _macosx_vers(_cache=[]):
  339. if not _cache:
  340. version = platform.mac_ver()[0]
  341. # fallback for MacPorts
  342. if version == '':
  343. plist = '/System/Library/CoreServices/SystemVersion.plist'
  344. if os.path.exists(plist):
  345. if hasattr(plistlib, 'readPlist'):
  346. plist_content = plistlib.readPlist(plist)
  347. if 'ProductVersion' in plist_content:
  348. version = plist_content['ProductVersion']
  349. _cache.append(version.split('.'))
  350. return _cache[0]
  351. def _macosx_arch(machine):
  352. return {'PowerPC': 'ppc', 'Power_Macintosh': 'ppc'}.get(machine, machine)
  353. def get_build_platform():
  354. """Return this platform's string for platform-specific distributions
  355. XXX Currently this is the same as ``distutils.util.get_platform()``, but it
  356. needs some hacks for Linux and Mac OS X.
  357. """
  358. try:
  359. # Python 2.7 or >=3.2
  360. from sysconfig import get_platform
  361. except ImportError:
  362. from distutils.util import get_platform
  363. plat = get_platform()
  364. if sys.platform == "darwin" and not plat.startswith('macosx-'):
  365. try:
  366. version = _macosx_vers()
  367. machine = os.uname()[4].replace(" ", "_")
  368. return "macosx-%d.%d-%s" % (int(version[0]), int(version[1]),
  369. _macosx_arch(machine))
  370. except ValueError:
  371. # if someone is running a non-Mac darwin system, this will fall
  372. # through to the default implementation
  373. pass
  374. return plat
  375. macosVersionString = re.compile(r"macosx-(\d+)\.(\d+)-(.*)")
  376. darwinVersionString = re.compile(r"darwin-(\d+)\.(\d+)\.(\d+)-(.*)")
  377. # XXX backward compat
  378. get_platform = get_build_platform
  379. def compatible_platforms(provided, required):
  380. """Can code for the `provided` platform run on the `required` platform?
  381. Returns true if either platform is ``None``, or the platforms are equal.
  382. XXX Needs compatibility checks for Linux and other unixy OSes.
  383. """
  384. if provided is None or required is None or provided==required:
  385. # easy case
  386. return True
  387. # Mac OS X special cases
  388. reqMac = macosVersionString.match(required)
  389. if reqMac:
  390. provMac = macosVersionString.match(provided)
  391. # is this a Mac package?
  392. if not provMac:
  393. # this is backwards compatibility for packages built before
  394. # setuptools 0.6. All packages built after this point will
  395. # use the new macosx designation.
  396. provDarwin = darwinVersionString.match(provided)
  397. if provDarwin:
  398. dversion = int(provDarwin.group(1))
  399. macosversion = "%s.%s" % (reqMac.group(1), reqMac.group(2))
  400. if dversion == 7 and macosversion >= "10.3" or \
  401. dversion == 8 and macosversion >= "10.4":
  402. return True
  403. # egg isn't macosx or legacy darwin
  404. return False
  405. # are they the same major version and machine type?
  406. if provMac.group(1) != reqMac.group(1) or \
  407. provMac.group(3) != reqMac.group(3):
  408. return False
  409. # is the required OS major update >= the provided one?
  410. if int(provMac.group(2)) > int(reqMac.group(2)):
  411. return False
  412. return True
  413. # XXX Linux and other platforms' special cases should go here
  414. return False
  415. def run_script(dist_spec, script_name):
  416. """Locate distribution `dist_spec` and run its `script_name` script"""
  417. ns = sys._getframe(1).f_globals
  418. name = ns['__name__']
  419. ns.clear()
  420. ns['__name__'] = name
  421. require(dist_spec)[0].run_script(script_name, ns)
  422. # backward compatibility
  423. run_main = run_script
  424. def get_distribution(dist):
  425. """Return a current distribution object for a Requirement or string"""
  426. if isinstance(dist, string_types):
  427. dist = Requirement.parse(dist)
  428. if isinstance(dist, Requirement):
  429. dist = get_provider(dist)
  430. if not isinstance(dist, Distribution):
  431. raise TypeError("Expected string, Requirement, or Distribution", dist)
  432. return dist
  433. def load_entry_point(dist, group, name):
  434. """Return `name` entry point of `group` for `dist` or raise ImportError"""
  435. return get_distribution(dist).load_entry_point(group, name)
  436. def get_entry_map(dist, group=None):
  437. """Return the entry point map for `group`, or the full entry map"""
  438. return get_distribution(dist).get_entry_map(group)
  439. def get_entry_info(dist, group, name):
  440. """Return the EntryPoint object for `group`+`name`, or ``None``"""
  441. return get_distribution(dist).get_entry_info(group, name)
  442. class IMetadataProvider:
  443. def has_metadata(name):
  444. """Does the package's distribution contain the named metadata?"""
  445. def get_metadata(name):
  446. """The named metadata resource as a string"""
  447. def get_metadata_lines(name):
  448. """Yield named metadata resource as list of non-blank non-comment lines
  449. Leading and trailing whitespace is stripped from each line, and lines
  450. with ``#`` as the first non-blank character are omitted."""
  451. def metadata_isdir(name):
  452. """Is the named metadata a directory? (like ``os.path.isdir()``)"""
  453. def metadata_listdir(name):
  454. """List of metadata names in the directory (like ``os.listdir()``)"""
  455. def run_script(script_name, namespace):
  456. """Execute the named script in the supplied namespace dictionary"""
  457. class IResourceProvider(IMetadataProvider):
  458. """An object that provides access to package resources"""
  459. def get_resource_filename(manager, resource_name):
  460. """Return a true filesystem path for `resource_name`
  461. `manager` must be an ``IResourceManager``"""
  462. def get_resource_stream(manager, resource_name):
  463. """Return a readable file-like object for `resource_name`
  464. `manager` must be an ``IResourceManager``"""
  465. def get_resource_string(manager, resource_name):
  466. """Return a string containing the contents of `resource_name`
  467. `manager` must be an ``IResourceManager``"""
  468. def has_resource(resource_name):
  469. """Does the package contain the named resource?"""
  470. def resource_isdir(resource_name):
  471. """Is the named resource a directory? (like ``os.path.isdir()``)"""
  472. def resource_listdir(resource_name):
  473. """List of resource names in the directory (like ``os.listdir()``)"""
  474. class WorkingSet(object):
  475. """A collection of active distributions on sys.path (or a similar list)"""
  476. def __init__(self, entries=None):
  477. """Create working set from list of path entries (default=sys.path)"""
  478. self.entries = []
  479. self.entry_keys = {}
  480. self.by_key = {}
  481. self.callbacks = []
  482. if entries is None:
  483. entries = sys.path
  484. for entry in entries:
  485. self.add_entry(entry)
  486. @classmethod
  487. def _build_master(cls):
  488. """
  489. Prepare the master working set.
  490. """
  491. ws = cls()
  492. try:
  493. from __main__ import __requires__
  494. except ImportError:
  495. # The main program does not list any requirements
  496. return ws
  497. # ensure the requirements are met
  498. try:
  499. ws.require(__requires__)
  500. except VersionConflict:
  501. return cls._build_from_requirements(__requires__)
  502. return ws
  503. @classmethod
  504. def _build_from_requirements(cls, req_spec):
  505. """
  506. Build a working set from a requirement spec. Rewrites sys.path.
  507. """
  508. # try it without defaults already on sys.path
  509. # by starting with an empty path
  510. ws = cls([])
  511. reqs = parse_requirements(req_spec)
  512. dists = ws.resolve(reqs, Environment())
  513. for dist in dists:
  514. ws.add(dist)
  515. # add any missing entries from sys.path
  516. for entry in sys.path:
  517. if entry not in ws.entries:
  518. ws.add_entry(entry)
  519. # then copy back to sys.path
  520. sys.path[:] = ws.entries
  521. return ws
  522. def add_entry(self, entry):
  523. """Add a path item to ``.entries``, finding any distributions on it
  524. ``find_distributions(entry, True)`` is used to find distributions
  525. corresponding to the path entry, and they are added. `entry` is
  526. always appended to ``.entries``, even if it is already present.
  527. (This is because ``sys.path`` can contain the same value more than
  528. once, and the ``.entries`` of the ``sys.path`` WorkingSet should always
  529. equal ``sys.path``.)
  530. """
  531. self.entry_keys.setdefault(entry, [])
  532. self.entries.append(entry)
  533. for dist in find_distributions(entry, True):
  534. self.add(dist, entry, False)
  535. def __contains__(self, dist):
  536. """True if `dist` is the active distribution for its project"""
  537. return self.by_key.get(dist.key) == dist
  538. def find(self, req):
  539. """Find a distribution matching requirement `req`
  540. If there is an active distribution for the requested project, this
  541. returns it as long as it meets the version requirement specified by
  542. `req`. But, if there is an active distribution for the project and it
  543. does *not* meet the `req` requirement, ``VersionConflict`` is raised.
  544. If there is no active distribution for the requested project, ``None``
  545. is returned.
  546. """
  547. dist = self.by_key.get(req.key)
  548. if dist is not None and dist not in req:
  549. # XXX add more info
  550. raise VersionConflict(dist, req)
  551. return dist
  552. def iter_entry_points(self, group, name=None):
  553. """Yield entry point objects from `group` matching `name`
  554. If `name` is None, yields all entry points in `group` from all
  555. distributions in the working set, otherwise only ones matching
  556. both `group` and `name` are yielded (in distribution order).
  557. """
  558. for dist in self:
  559. entries = dist.get_entry_map(group)
  560. if name is None:
  561. for ep in entries.values():
  562. yield ep
  563. elif name in entries:
  564. yield entries[name]
  565. def run_script(self, requires, script_name):
  566. """Locate distribution for `requires` and run `script_name` script"""
  567. ns = sys._getframe(1).f_globals
  568. name = ns['__name__']
  569. ns.clear()
  570. ns['__name__'] = name
  571. self.require(requires)[0].run_script(script_name, ns)
  572. def __iter__(self):
  573. """Yield distributions for non-duplicate projects in the working set
  574. The yield order is the order in which the items' path entries were
  575. added to the working set.
  576. """
  577. seen = {}
  578. for item in self.entries:
  579. if item not in self.entry_keys:
  580. # workaround a cache issue
  581. continue
  582. for key in self.entry_keys[item]:
  583. if key not in seen:
  584. seen[key]=1
  585. yield self.by_key[key]
  586. def add(self, dist, entry=None, insert=True, replace=False):
  587. """Add `dist` to working set, associated with `entry`
  588. If `entry` is unspecified, it defaults to the ``.location`` of `dist`.
  589. On exit from this routine, `entry` is added to the end of the working
  590. set's ``.entries`` (if it wasn't already present).
  591. `dist` is only added to the working set if it's for a project that
  592. doesn't already have a distribution in the set, unless `replace=True`.
  593. If it's added, any callbacks registered with the ``subscribe()`` method
  594. will be called.
  595. """
  596. if insert:
  597. dist.insert_on(self.entries, entry)
  598. if entry is None:
  599. entry = dist.location
  600. keys = self.entry_keys.setdefault(entry,[])
  601. keys2 = self.entry_keys.setdefault(dist.location,[])
  602. if not replace and dist.key in self.by_key:
  603. # ignore hidden distros
  604. return
  605. self.by_key[dist.key] = dist
  606. if dist.key not in keys:
  607. keys.append(dist.key)
  608. if dist.key not in keys2:
  609. keys2.append(dist.key)
  610. self._added_new(dist)
  611. def resolve(self, requirements, env=None, installer=None,
  612. replace_conflicting=False):
  613. """List all distributions needed to (recursively) meet `requirements`
  614. `requirements` must be a sequence of ``Requirement`` objects. `env`,
  615. if supplied, should be an ``Environment`` instance. If
  616. not supplied, it defaults to all distributions available within any
  617. entry or distribution in the working set. `installer`, if supplied,
  618. will be invoked with each requirement that cannot be met by an
  619. already-installed distribution; it should return a ``Distribution`` or
  620. ``None``.
  621. Unless `replace_conflicting=True`, raises a VersionConflict exception if
  622. any requirements are found on the path that have the correct name but
  623. the wrong version. Otherwise, if an `installer` is supplied it will be
  624. invoked to obtain the correct version of the requirement and activate
  625. it.
  626. """
  627. # set up the stack
  628. requirements = list(requirements)[::-1]
  629. # set of processed requirements
  630. processed = {}
  631. # key -> dist
  632. best = {}
  633. to_activate = []
  634. # Mapping of requirement to set of distributions that required it;
  635. # useful for reporting info about conflicts.
  636. required_by = collections.defaultdict(set)
  637. while requirements:
  638. # process dependencies breadth-first
  639. req = requirements.pop(0)
  640. if req in processed:
  641. # Ignore cyclic or redundant dependencies
  642. continue
  643. dist = best.get(req.key)
  644. if dist is None:
  645. # Find the best distribution and add it to the map
  646. dist = self.by_key.get(req.key)
  647. if dist is None or (dist not in req and replace_conflicting):
  648. ws = self
  649. if env is None:
  650. if dist is None:
  651. env = Environment(self.entries)
  652. else:
  653. # Use an empty environment and workingset to avoid
  654. # any further conflicts with the conflicting
  655. # distribution
  656. env = Environment([])
  657. ws = WorkingSet([])
  658. dist = best[req.key] = env.best_match(req, ws, installer)
  659. if dist is None:
  660. requirers = required_by.get(req, None)
  661. raise DistributionNotFound(req, requirers)
  662. to_activate.append(dist)
  663. if dist not in req:
  664. # Oops, the "best" so far conflicts with a dependency
  665. dependent_req = required_by[req]
  666. raise VersionConflict(dist, req).with_context(dependent_req)
  667. # push the new requirements onto the stack
  668. new_requirements = dist.requires(req.extras)[::-1]
  669. requirements.extend(new_requirements)
  670. # Register the new requirements needed by req
  671. for new_requirement in new_requirements:
  672. required_by[new_requirement].add(req.project_name)
  673. processed[req] = True
  674. # return list of distros to activate
  675. return to_activate
  676. def find_plugins(self, plugin_env, full_env=None, installer=None,
  677. fallback=True):
  678. """Find all activatable distributions in `plugin_env`
  679. Example usage::
  680. distributions, errors = working_set.find_plugins(
  681. Environment(plugin_dirlist)
  682. )
  683. # add plugins+libs to sys.path
  684. map(working_set.add, distributions)
  685. # display errors
  686. print('Could not load', errors)
  687. The `plugin_env` should be an ``Environment`` instance that contains
  688. only distributions that are in the project's "plugin directory" or
  689. directories. The `full_env`, if supplied, should be an ``Environment``
  690. contains all currently-available distributions. If `full_env` is not
  691. supplied, one is created automatically from the ``WorkingSet`` this
  692. method is called on, which will typically mean that every directory on
  693. ``sys.path`` will be scanned for distributions.
  694. `installer` is a standard installer callback as used by the
  695. ``resolve()`` method. The `fallback` flag indicates whether we should
  696. attempt to resolve older versions of a plugin if the newest version
  697. cannot be resolved.
  698. This method returns a 2-tuple: (`distributions`, `error_info`), where
  699. `distributions` is a list of the distributions found in `plugin_env`
  700. that were loadable, along with any other distributions that are needed
  701. to resolve their dependencies. `error_info` is a dictionary mapping
  702. unloadable plugin distributions to an exception instance describing the
  703. error that occurred. Usually this will be a ``DistributionNotFound`` or
  704. ``VersionConflict`` instance.
  705. """
  706. plugin_projects = list(plugin_env)
  707. # scan project names in alphabetic order
  708. plugin_projects.sort()
  709. error_info = {}
  710. distributions = {}
  711. if full_env is None:
  712. env = Environment(self.entries)
  713. env += plugin_env
  714. else:
  715. env = full_env + plugin_env
  716. shadow_set = self.__class__([])
  717. # put all our entries in shadow_set
  718. list(map(shadow_set.add, self))
  719. for project_name in plugin_projects:
  720. for dist in plugin_env[project_name]:
  721. req = [dist.as_requirement()]
  722. try:
  723. resolvees = shadow_set.resolve(req, env, installer)
  724. except ResolutionError as v:
  725. # save error info
  726. error_info[dist] = v
  727. if fallback:
  728. # try the next older version of project
  729. continue
  730. else:
  731. # give up on this project, keep going
  732. break
  733. else:
  734. list(map(shadow_set.add, resolvees))
  735. distributions.update(dict.fromkeys(resolvees))
  736. # success, no need to try any more versions of this project
  737. break
  738. distributions = list(distributions)
  739. distributions.sort()
  740. return distributions, error_info
  741. def require(self, *requirements):
  742. """Ensure that distributions matching `requirements` are activated
  743. `requirements` must be a string or a (possibly-nested) sequence
  744. thereof, specifying the distributions and versions required. The
  745. return value is a sequence of the distributions that needed to be
  746. activated to fulfill the requirements; all relevant distributions are
  747. included, even if they were already activated in this working set.
  748. """
  749. needed = self.resolve(parse_requirements(requirements))
  750. for dist in needed:
  751. self.add(dist)
  752. return needed
  753. def subscribe(self, callback):
  754. """Invoke `callback` for all distributions (including existing ones)"""
  755. if callback in self.callbacks:
  756. return
  757. self.callbacks.append(callback)
  758. for dist in self:
  759. callback(dist)
  760. def _added_new(self, dist):
  761. for callback in self.callbacks:
  762. callback(dist)
  763. def __getstate__(self):
  764. return (
  765. self.entries[:], self.entry_keys.copy(), self.by_key.copy(),
  766. self.callbacks[:]
  767. )
  768. def __setstate__(self, e_k_b_c):
  769. entries, keys, by_key, callbacks = e_k_b_c
  770. self.entries = entries[:]
  771. self.entry_keys = keys.copy()
  772. self.by_key = by_key.copy()
  773. self.callbacks = callbacks[:]
  774. class Environment(object):
  775. """Searchable snapshot of distributions on a search path"""
  776. def __init__(self, search_path=None, platform=get_supported_platform(),
  777. python=PY_MAJOR):
  778. """Snapshot distributions available on a search path
  779. Any distributions found on `search_path` are added to the environment.
  780. `search_path` should be a sequence of ``sys.path`` items. If not
  781. supplied, ``sys.path`` is used.
  782. `platform` is an optional string specifying the name of the platform
  783. that platform-specific distributions must be compatible with. If
  784. unspecified, it defaults to the current platform. `python` is an
  785. optional string naming the desired version of Python (e.g. ``'3.3'``);
  786. it defaults to the current version.
  787. You may explicitly set `platform` (and/or `python`) to ``None`` if you
  788. wish to map *all* distributions, not just those compatible with the
  789. running platform or Python version.
  790. """
  791. self._distmap = {}
  792. self.platform = platform
  793. self.python = python
  794. self.scan(search_path)
  795. def can_add(self, dist):
  796. """Is distribution `dist` acceptable for this environment?
  797. The distribution must match the platform and python version
  798. requirements specified when this environment was created, or False
  799. is returned.
  800. """
  801. return (self.python is None or dist.py_version is None
  802. or dist.py_version==self.python) \
  803. and compatible_platforms(dist.platform, self.platform)
  804. def remove(self, dist):
  805. """Remove `dist` from the environment"""
  806. self._distmap[dist.key].remove(dist)
  807. def scan(self, search_path=None):
  808. """Scan `search_path` for distributions usable in this environment
  809. Any distributions found are added to the environment.
  810. `search_path` should be a sequence of ``sys.path`` items. If not
  811. supplied, ``sys.path`` is used. Only distributions conforming to
  812. the platform/python version defined at initialization are added.
  813. """
  814. if search_path is None:
  815. search_path = sys.path
  816. for item in search_path:
  817. for dist in find_distributions(item):
  818. self.add(dist)
  819. def __getitem__(self, project_name):
  820. """Return a newest-to-oldest list of distributions for `project_name`
  821. Uses case-insensitive `project_name` comparison, assuming all the
  822. project's distributions use their project's name converted to all
  823. lowercase as their key.
  824. """
  825. distribution_key = project_name.lower()
  826. return self._distmap.get(distribution_key, [])
  827. def add(self, dist):
  828. """Add `dist` if we ``can_add()`` it and it has not already been added
  829. """
  830. if self.can_add(dist) and dist.has_version():
  831. dists = self._distmap.setdefault(dist.key, [])
  832. if dist not in dists:
  833. dists.append(dist)
  834. dists.sort(key=operator.attrgetter('hashcmp'), reverse=True)
  835. def best_match(self, req, working_set, installer=None):
  836. """Find distribution best matching `req` and usable on `working_set`
  837. This calls the ``find(req)`` method of the `working_set` to see if a
  838. suitable distribution is already active. (This may raise
  839. ``VersionConflict`` if an unsuitable version of the project is already
  840. active in the specified `working_set`.) If a suitable distribution
  841. isn't active, this method returns the newest distribution in the
  842. environment that meets the ``Requirement`` in `req`. If no suitable
  843. distribution is found, and `installer` is supplied, then the result of
  844. calling the environment's ``obtain(req, installer)`` method will be
  845. returned.
  846. """
  847. dist = working_set.find(req)
  848. if dist is not None:
  849. return dist
  850. for dist in self[req.key]:
  851. if dist in req:
  852. return dist
  853. # try to download/install
  854. return self.obtain(req, installer)
  855. def obtain(self, requirement, installer=None):
  856. """Obtain a distribution matching `requirement` (e.g. via download)
  857. Obtain a distro that matches requirement (e.g. via download). In the
  858. base ``Environment`` class, this routine just returns
  859. ``installer(requirement)``, unless `installer` is None, in which case
  860. None is returned instead. This method is a hook that allows subclasses
  861. to attempt other ways of obtaining a distribution before falling back
  862. to the `installer` argument."""
  863. if installer is not None:
  864. return installer(requirement)
  865. def __iter__(self):
  866. """Yield the unique project names of the available distributions"""
  867. for key in self._distmap.keys():
  868. if self[key]:
  869. yield key
  870. def __iadd__(self, other):
  871. """In-place addition of a distribution or environment"""
  872. if isinstance(other, Distribution):
  873. self.add(other)
  874. elif isinstance(other, Environment):
  875. for project in other:
  876. for dist in other[project]:
  877. self.add(dist)
  878. else:
  879. raise TypeError("Can't add %r to environment" % (other,))
  880. return self
  881. def __add__(self, other):
  882. """Add an environment or distribution to an environment"""
  883. new = self.__class__([], platform=None, python=None)
  884. for env in self, other:
  885. new += env
  886. return new
  887. # XXX backward compatibility
  888. AvailableDistributions = Environment
  889. class ExtractionError(RuntimeError):
  890. """An error occurred extracting a resource
  891. The following attributes are available from instances of this exception:
  892. manager
  893. The resource manager that raised this exception
  894. cache_path
  895. The base directory for resource extraction
  896. original_error
  897. The exception instance that caused extraction to fail
  898. """
  899. class ResourceManager:
  900. """Manage resource extraction and packages"""
  901. extraction_path = None
  902. def __init__(self):
  903. self.cached_files = {}
  904. def resource_exists(self, package_or_requirement, resource_name):
  905. """Does the named resource exist?"""
  906. return get_provider(package_or_requirement).has_resource(resource_name)
  907. def resource_isdir(self, package_or_requirement, resource_name):
  908. """Is the named resource an existing directory?"""
  909. return get_provider(package_or_requirement).resource_isdir(
  910. resource_name
  911. )
  912. def resource_filename(self, package_or_requirement, resource_name):
  913. """Return a true filesystem path for specified resource"""
  914. return get_provider(package_or_requirement).get_resource_filename(
  915. self, resource_name
  916. )
  917. def resource_stream(self, package_or_requirement, resource_name):
  918. """Return a readable file-like object for specified resource"""
  919. return get_provider(package_or_requirement).get_resource_stream(
  920. self, resource_name
  921. )
  922. def resource_string(self, package_or_requirement, resource_name):
  923. """Return specified resource as a string"""
  924. return get_provider(package_or_requirement).get_resource_string(
  925. self, resource_name
  926. )
  927. def resource_listdir(self, package_or_requirement, resource_name):
  928. """List the contents of the named resource directory"""
  929. return get_provider(package_or_requirement).resource_listdir(
  930. resource_name
  931. )
  932. def extraction_error(self):
  933. """Give an error message for problems extracting file(s)"""
  934. old_exc = sys.exc_info()[1]
  935. cache_path = self.extraction_path or get_default_cache()
  936. err = ExtractionError("""Can't extract file(s) to egg cache
  937. The following error occurred while trying to extract file(s) to the Python egg
  938. cache:
  939. %s
  940. The Python egg cache directory is currently set to:
  941. %s
  942. Perhaps your account does not have write access to this directory? You can
  943. change the cache directory by setting the PYTHON_EGG_CACHE environment
  944. variable to point to an accessible directory.
  945. """ % (old_exc, cache_path)
  946. )
  947. err.manager = self
  948. err.cache_path = cache_path
  949. err.original_error = old_exc
  950. raise err
  951. def get_cache_path(self, archive_name, names=()):
  952. """Return absolute location in cache for `archive_name` and `names`
  953. The parent directory of the resulting path will be created if it does
  954. not already exist. `archive_name` should be the base filename of the
  955. enclosing egg (which may not be the name of the enclosing zipfile!),
  956. including its ".egg" extension. `names`, if provided, should be a
  957. sequence of path name parts "under" the egg's extraction location.
  958. This method should only be called by resource providers that need to
  959. obtain an extraction location, and only for names they intend to
  960. extract, as it tracks the generated names for possible cleanup later.
  961. """
  962. extract_path = self.extraction_path or get_default_cache()
  963. target_path = os.path.join(extract_path, archive_name+'-tmp', *names)
  964. try:
  965. _bypass_ensure_directory(target_path)
  966. except:
  967. self.extraction_error()
  968. self._warn_unsafe_extraction_path(extract_path)
  969. self.cached_files[target_path] = 1
  970. return target_path
  971. @staticmethod
  972. def _warn_unsafe_extraction_path(path):
  973. """
  974. If the default extraction path is overridden and set to an insecure
  975. location, such as /tmp, it opens up an opportunity for an attacker to
  976. replace an extracted file with an unauthorized payload. Warn the user
  977. if a known insecure location is used.
  978. See Distribute #375 for more details.
  979. """
  980. if os.name == 'nt' and not path.startswith(os.environ['windir']):
  981. # On Windows, permissions are generally restrictive by default
  982. # and temp directories are not writable by other users, so
  983. # bypass the warning.
  984. return
  985. mode = os.stat(path).st_mode
  986. if mode & stat.S_IWOTH or mode & stat.S_IWGRP:
  987. msg = ("%s is writable by group/others and vulnerable to attack "
  988. "when "
  989. "used with get_resource_filename. Consider a more secure "
  990. "location (set with .set_extraction_path or the "
  991. "PYTHON_EGG_CACHE environment variable)." % path)
  992. warnings.warn(msg, UserWarning)
  993. def postprocess(self, tempname, filename):
  994. """Perform any platform-specific postprocessing of `tempname`
  995. This is where Mac header rewrites should be done; other platforms don't
  996. have anything special they should do.
  997. Resource providers should call this method ONLY after successfully
  998. extracting a compressed resource. They must NOT call it on resources
  999. that are already in the filesystem.
  1000. `tempname` is the current (temporary) name of the file, and `filename`
  1001. is the name it will be renamed to by the caller after this routine
  1002. returns.
  1003. """
  1004. if os.name == 'posix':
  1005. # Make the resource executable
  1006. mode = ((os.stat(tempname).st_mode) | 0o555) & 0o7777
  1007. os.chmod(tempname, mode)
  1008. def set_extraction_path(self, path):
  1009. """Set the base path where resources will be extracted to, if needed.
  1010. If you do not call this routine before any extractions take place, the
  1011. path defaults to the return value of ``get_default_cache()``. (Which
  1012. is based on the ``PYTHON_EGG_CACHE`` environment variable, with various
  1013. platform-specific fallbacks. See that routine's documentation for more
  1014. details.)
  1015. Resources are extracted to subdirectories of this path based upon
  1016. information given by the ``IResourceProvider``. You may set this to a
  1017. temporary directory, but then you must call ``cleanup_resources()`` to
  1018. delete the extracted files when done. There is no guarantee that
  1019. ``cleanup_resources()`` will be able to remove all extracted files.
  1020. (Note: you may not change the extraction path for a given resource
  1021. manager once resources have been extracted, unless you first call
  1022. ``cleanup_resources()``.)
  1023. """
  1024. if self.cached_files:
  1025. raise ValueError(
  1026. "Can't change extraction path, files already extracted"
  1027. )
  1028. self.extraction_path = path
  1029. def cleanup_resources(self, force=False):
  1030. """
  1031. Delete all extracted resource files and directories, returning a list
  1032. of the file and directory names that could not be successfully removed.
  1033. This function does not have any concurrency protection, so it should
  1034. generally only be called when the extraction path is a temporary
  1035. directory exclusive to a single process. This method is not
  1036. automatically called; you must call it explicitly or register it as an
  1037. ``atexit`` function if you wish to ensure cleanup of a temporary
  1038. directory used for extractions.
  1039. """
  1040. # XXX
  1041. def get_default_cache():
  1042. """Determine the default cache location
  1043. This returns the ``PYTHON_EGG_CACHE`` environment variable, if set.
  1044. Otherwise, on Windows, it returns a "Python-Eggs" subdirectory of the
  1045. "Application Data" directory. On all other systems, it's "~/.python-eggs".
  1046. """
  1047. try:
  1048. return os.environ['PYTHON_EGG_CACHE']
  1049. except KeyError:
  1050. pass
  1051. if os.name!='nt':
  1052. return os.path.expanduser('~/.python-eggs')
  1053. # XXX this may be locale-specific!
  1054. app_data = 'Application Data'
  1055. app_homes = [
  1056. # best option, should be locale-safe
  1057. (('APPDATA',), None),
  1058. (('USERPROFILE',), app_data),
  1059. (('HOMEDRIVE','HOMEPATH'), app_data),
  1060. (('HOMEPATH',), app_data),
  1061. (('HOME',), None),
  1062. # 95/98/ME
  1063. (('WINDIR',), app_data),
  1064. ]
  1065. for keys, subdir in app_homes:
  1066. dirname = ''
  1067. for key in keys:
  1068. if key in os.environ:
  1069. dirname = os.path.join(dirname, os.environ[key])
  1070. else:
  1071. break
  1072. else:
  1073. if subdir:
  1074. dirname = os.path.join(dirname, subdir)
  1075. return os.path.join(dirname, 'Python-Eggs')
  1076. else:
  1077. raise RuntimeError(
  1078. "Please set the PYTHON_EGG_CACHE enviroment variable"
  1079. )
  1080. def safe_name(name):
  1081. """Convert an arbitrary string to a standard distribution name
  1082. Any runs of non-alphanumeric/. characters are replaced with a single '-'.
  1083. """
  1084. return re.sub('[^A-Za-z0-9.]+', '-', name)
  1085. def safe_version(version):
  1086. """
  1087. Convert an arbitrary string to a standard version string
  1088. """
  1089. try:
  1090. # normalize the version
  1091. return str(packaging.version.Version(version))
  1092. except packaging.version.InvalidVersion:
  1093. version = version.replace(' ','.')
  1094. return re.sub('[^A-Za-z0-9.]+', '-', version)
  1095. def safe_extra(extra):
  1096. """Convert an arbitrary string to a standard 'extra' name
  1097. Any runs of non-alphanumeric characters are replaced with a single '_',
  1098. and the result is always lowercased.
  1099. """
  1100. return re.sub('[^A-Za-z0-9.]+', '_', extra).lower()
  1101. def to_filename(name):
  1102. """Convert a project or version name to its filename-escaped form
  1103. Any '-' characters are currently replaced with '_'.
  1104. """
  1105. return name.replace('-','_')
  1106. class MarkerEvaluation(object):
  1107. values = {
  1108. 'os_name': lambda: os.name,
  1109. 'sys_platform': lambda: sys.platform,
  1110. 'python_full_version': platform.python_version,
  1111. 'python_version': lambda: platform.python_version()[:3],
  1112. 'platform_version': platform.version,
  1113. 'platform_machine': platform.machine,
  1114. 'python_implementation': platform.python_implementation,
  1115. }
  1116. @classmethod
  1117. def is_invalid_marker(cls, text):
  1118. """
  1119. Validate text as a PEP 426 environment marker; return an exception
  1120. if invalid or False otherwise.
  1121. """
  1122. try:
  1123. cls.evaluate_marker(text)
  1124. except SyntaxError as e:
  1125. return cls.normalize_exception(e)
  1126. return False
  1127. @staticmethod
  1128. def normalize_exception(exc):
  1129. """
  1130. Given a SyntaxError from a marker evaluation, normalize the error
  1131. message:
  1132. - Remove indications of filename and line number.
  1133. - Replace platform-specific error messages with standard error
  1134. messages.
  1135. """
  1136. subs = {
  1137. 'unexpected EOF while parsing': 'invalid syntax',
  1138. 'parenthesis is never closed': 'invalid syntax',
  1139. }
  1140. exc.filename = None
  1141. exc.lineno = None
  1142. exc.msg = subs.get(exc.msg, exc.msg)
  1143. return exc
  1144. @classmethod
  1145. def and_test(cls, nodelist):
  1146. # MUST NOT short-circuit evaluation, or invalid syntax can be skipped!
  1147. items = [
  1148. cls.interpret(nodelist[i])
  1149. for i in range(1, len(nodelist), 2)
  1150. ]
  1151. return functools.reduce(operator.and_, items)
  1152. @classmethod
  1153. def test(cls, nodelist):
  1154. # MUST NOT short-circuit evaluation, or invalid syntax can be skipped!
  1155. items = [
  1156. cls.interpret(nodelist[i])
  1157. for i in range(1, len(nodelist), 2)
  1158. ]
  1159. return functools.reduce(operator.or_, items)
  1160. @classmethod
  1161. def atom(cls, nodelist):
  1162. t = nodelist[1][0]
  1163. if t == token.LPAR:
  1164. if nodelist[2][0] == token.RPAR:
  1165. raise SyntaxError("Empty parentheses")
  1166. return cls.interpret(nodelist[2])
  1167. msg = "Language feature not supported in environment markers"
  1168. raise SyntaxError(msg)
  1169. @classmethod
  1170. def comparison(cls, nodelist):
  1171. if len(nodelist) > 4:
  1172. msg = "Chained comparison not allowed in environment markers"
  1173. raise SyntaxError(msg)
  1174. comp = nodelist[2][1]
  1175. cop = comp[1]
  1176. if comp[0] == token.NAME:
  1177. if len(nodelist[2]) == 3:
  1178. if cop == 'not':
  1179. cop = 'not in'
  1180. else:
  1181. cop = 'is not'
  1182. try:
  1183. cop = cls.get_op(cop)
  1184. except KeyError:
  1185. msg = repr(cop) + " operator not allowed in environment markers"
  1186. raise SyntaxError(msg)
  1187. return cop(cls.evaluate(nodelist[1]), cls.evaluate(nodelist[3]))
  1188. @classmethod
  1189. def get_op(cls, op):
  1190. ops = {
  1191. symbol.test: cls.test,
  1192. symbol.and_test: cls.and_test,
  1193. symbol.atom: cls.atom,
  1194. symbol.comparison: cls.comparison,
  1195. 'not in': lambda x, y: x not in y,
  1196. 'in': lambda x, y: x in y,
  1197. '==': operator.eq,
  1198. '!=': operator.ne,
  1199. }
  1200. if hasattr(symbol, 'or_test'):
  1201. ops[symbol.or_test] = cls.test
  1202. return ops[op]
  1203. @classmethod
  1204. def evaluate_marker(cls, text, extra=None):
  1205. """
  1206. Evaluate a PEP 426 environment marker on CPython 2.4+.
  1207. Return a boolean indicating the marker result in this environment.
  1208. Raise SyntaxError if marker is invalid.
  1209. This implementation uses the 'parser' module, which is not implemented
  1210. on
  1211. Jython and has been superseded by the 'ast' module in Python 2.6 and
  1212. later.
  1213. """
  1214. return cls.interpret(parser.expr(text).totuple(1)[1])
  1215. @classmethod
  1216. def _markerlib_evaluate(cls, text):
  1217. """
  1218. Evaluate a PEP 426 environment marker using markerlib.
  1219. Return a boolean indicating the marker result in this environment.
  1220. Raise SyntaxError if marker is invalid.
  1221. """
  1222. import _markerlib
  1223. # markerlib implements Metadata 1.2 (PEP 345) environment markers.
  1224. # Translate the variables to Metadata 2.0 (PEP 426).
  1225. env = _markerlib.default_environment()
  1226. for key in env.keys():
  1227. new_key = key.replace('.', '_')
  1228. env[new_key] = env.pop(key)
  1229. try:
  1230. result = _markerlib.interpret(text, env)
  1231. except NameError as e:
  1232. raise SyntaxError(e.args[0])
  1233. return result
  1234. if 'parser' not in globals():
  1235. # Fall back to less-complete _markerlib implementation if 'parser' module
  1236. # is not available.
  1237. evaluate_marker = _markerlib_evaluate
  1238. @classmethod
  1239. def interpret(cls, nodelist):
  1240. while len(nodelist)==2: nodelist = nodelist[1]
  1241. try:
  1242. op = cls.get_op(nodelist[0])
  1243. except KeyError:
  1244. raise SyntaxError("Comparison or logical expression expected")
  1245. return op(nodelist)
  1246. @classmethod
  1247. def evaluate(cls, nodelist):
  1248. while len(nodelist)==2: nodelist = nodelist[1]
  1249. kind = nodelist[0]
  1250. name = nodelist[1]
  1251. if kind==token.NAME:
  1252. try:
  1253. op = cls.values[name]
  1254. except KeyError:
  1255. raise SyntaxError("Unknown name %r" % name)
  1256. return op()
  1257. if kind==token.STRING:
  1258. s = nodelist[1]
  1259. if not cls._safe_string(s):
  1260. raise SyntaxError(
  1261. "Only plain strings allowed in environment markers")
  1262. return s[1:-1]
  1263. msg = "Language feature not supported in environment markers"
  1264. raise SyntaxError(msg)
  1265. @staticmethod
  1266. def _safe_string(cand):
  1267. return (
  1268. cand[:1] in "'\"" and
  1269. not cand.startswith('"""') and
  1270. not cand.startswith("'''") and
  1271. '\\' not in cand
  1272. )
  1273. invalid_marker = MarkerEvaluation.is_invalid_marker
  1274. evaluate_marker = MarkerEvaluation.evaluate_marker
  1275. class NullProvider:
  1276. """Try to implement resources and metadata for arbitrary PEP 302 loaders"""
  1277. egg_name = None
  1278. egg_info = None
  1279. loader = None
  1280. def __init__(self, module):
  1281. self.loader = getattr(module, '__loader__', None)
  1282. self.module_path = os.path.dirname(getattr(module, '__file__', ''))
  1283. def get_resource_filename(self, manager, resource_name):
  1284. return self._fn(self.module_path, resource_name)
  1285. def get_resource_stream(self, manager, resource_name):
  1286. return io.BytesIO(self.get_resource_string(manager, resource_name))
  1287. def get_resource_string(self, manager, resource_name):
  1288. return self._get(self._fn(self.module_path, resource_name))
  1289. def has_resource(self, resource_name):
  1290. return self._has(self._fn(self.module_path, resource_name))
  1291. def has_metadata(self, name):
  1292. return self.egg_info and self._has(self._fn(self.egg_info, name))
  1293. if sys.version_info <= (3,):
  1294. def get_metadata(self, name):
  1295. if not self.egg_info:
  1296. return ""
  1297. return self._get(self._fn(self.egg_info, name))
  1298. else:
  1299. def get_metadata(self, name):
  1300. if not self.egg_info:
  1301. return ""
  1302. return self._get(self._fn(self.egg_info, name)).decode("utf-8")
  1303. def get_metadata_lines(self, name):
  1304. return yield_lines(self.get_metadata(name))
  1305. def resource_isdir(self, resource_name):
  1306. return self._isdir(self._fn(self.module_path, resource_name))
  1307. def metadata_isdir(self, name):
  1308. return self.egg_info and self._isdir(self._fn(self.egg_info, name))
  1309. def resource_listdir(self, resource_name):
  1310. return self._listdir(self._fn(self.module_path, resource_name))
  1311. def metadata_listdir(self, name):
  1312. if self.egg_info:
  1313. return self._listdir(self._fn(self.egg_info, name))
  1314. return []
  1315. def run_script(self, script_name, namespace):
  1316. script = 'scripts/'+script_name
  1317. if not self.has_metadata(script):
  1318. raise ResolutionError("No script named %r" % script_name)
  1319. script_text = self.get_metadata(script).replace('\r\n', '\n')
  1320. script_text = script_text.replace('\r', '\n')
  1321. script_filename = self._fn(self.egg_info, script)
  1322. namespace['__file__'] = script_filename
  1323. if os.path.exists(script_filename):
  1324. source = open(script_filename).read()
  1325. code = compile(source, script_filename, 'exec')
  1326. exec(code, namespace, namespace)
  1327. else:
  1328. from linecache import cache
  1329. cache[script_filename] = (
  1330. len(script_text), 0, script_text.split('\n'), script_filename
  1331. )
  1332. script_code = compile(script_text, script_filename,'exec')
  1333. exec(script_code, namespace, namespace)
  1334. def _has(self, path):
  1335. raise NotImplementedError(
  1336. "Can't perform this operation for unregistered loader type"
  1337. )
  1338. def _isdir(self, path):
  1339. raise NotImplementedError(
  1340. "Can't perform this operation for unregistered loader type"
  1341. )
  1342. def _listdir(self, path):
  1343. raise NotImplementedError(
  1344. "Can't perform this operation for unregistered loader type"
  1345. )
  1346. def _fn(self, base, resource_name):
  1347. if resource_name:
  1348. return os.path.join(base, *resource_name.split('/'))
  1349. return base
  1350. def _get(self, path):
  1351. if hasattr(self.loader, 'get_data'):
  1352. return self.loader.get_data(path)
  1353. raise NotImplementedError(
  1354. "Can't perform this operation for loaders without 'get_data()'"
  1355. )
  1356. register_loader_type(object, NullProvider)
  1357. class EggProvider(NullProvider):
  1358. """Provider based on a virtual filesystem"""
  1359. def __init__(self, module):
  1360. NullProvider.__init__(self, module)
  1361. self._setup_prefix()
  1362. def _setup_prefix(self):
  1363. # we assume here that our metadata may be nested inside a "basket"
  1364. # of multiple eggs; that's why we use module_path instead of .archive
  1365. path = self.module_path
  1366. old = None
  1367. while path!=old:
  1368. if path.lower().endswith('.egg'):
  1369. self.egg_name = os.path.basename(path)
  1370. self.egg_info = os.path.join(path, 'EGG-INFO')
  1371. self.egg_root = path
  1372. break
  1373. old = path
  1374. path, base = os.path.split(path)
  1375. class DefaultProvider(EggProvider):
  1376. """Provides access to package resources in the filesystem"""
  1377. def _has(self, path):
  1378. return os.path.exists(path)
  1379. def _isdir(self, path):
  1380. return os.path.isdir(path)
  1381. def _listdir(self, path):
  1382. return os.listdir(path)
  1383. def get_resource_stream(self, manager, resource_name):
  1384. return open(self._fn(self.module_path, resource_name), 'rb')
  1385. def _get(self, path):
  1386. with open(path, 'rb') as stream:
  1387. return stream.read()
  1388. register_loader_type(type(None), DefaultProvider)
  1389. if importlib_bootstrap is not None:
  1390. register_loader_type(importlib_bootstrap.SourceFileLoader, DefaultProvider)
  1391. class EmptyProvider(NullProvider):
  1392. """Provider that returns nothing for all requests"""
  1393. _isdir = _has = lambda self, path: False
  1394. _get = lambda self, path: ''
  1395. _listdir = lambda self, path: []
  1396. module_path = None
  1397. def __init__(self):
  1398. pass
  1399. empty_provider = EmptyProvider()
  1400. class ZipManifests(dict):
  1401. """
  1402. zip manifest builder
  1403. """
  1404. @classmethod
  1405. def build(cls, path):
  1406. """
  1407. Build a dictionary similar to the zipimport directory
  1408. caches, except instead of tuples, store ZipInfo objects.
  1409. Use a platform-specific path separator (os.sep) for the path keys
  1410. for compatibility with pypy on Windows.
  1411. """
  1412. with ContextualZipFile(path) as zfile:
  1413. items = (
  1414. (
  1415. name.replace('/', os.sep),
  1416. zfile.getinfo(name),
  1417. )
  1418. for name in zfile.namelist()
  1419. )
  1420. return dict(items)
  1421. load = build
  1422. class MemoizedZipManifests(ZipManifests):
  1423. """
  1424. Memoized zipfile manifests.
  1425. """
  1426. manifest_mod = collections.namedtuple('manifest_mod', 'manifest mtime')
  1427. def load(self, path):
  1428. """
  1429. Load a manifest at path or return a suitable manifest already loaded.
  1430. """
  1431. path = os.path.normpath(path)
  1432. mtime = os.stat(path).st_mtime
  1433. if path not in self or self[path].mtime != mtime:
  1434. manifest = self.build(path)
  1435. self[path] = self.manifest_mod(manifest, mtime)
  1436. return self[path].manifest
  1437. class ContextualZipFile(zipfile.ZipFile):
  1438. """
  1439. Supplement ZipFile class to support context manager for Python 2.6
  1440. """
  1441. def __enter__(self):
  1442. return self
  1443. def __exit__(self, type, value, traceback):
  1444. self.close()
  1445. def __new__(cls, *args, **kwargs):
  1446. """
  1447. Construct a ZipFile or ContextualZipFile as appropriate
  1448. """
  1449. if hasattr(zipfile.ZipFile, '__exit__'):
  1450. return zipfile.ZipFile(*args, **kwargs)
  1451. return super(ContextualZipFile, cls).__new__(cls)
  1452. class ZipProvider(EggProvider):
  1453. """Resource support for zips and eggs"""
  1454. eagers = None
  1455. _zip_manifests = MemoizedZipManifests()
  1456. def __init__(self, module):
  1457. EggProvider.__init__(self, module)
  1458. self.zip_pre = self.loader.archive+os.sep
  1459. def _zipinfo_name(self, fspath):
  1460. # Convert a virtual filename (full path to file) into a zipfile subpath
  1461. # usable with the zipimport directory cache for our target archive
  1462. if fspath.startswith(self.zip_pre):
  1463. return fspath[len(self.zip_pre):]
  1464. raise AssertionError(
  1465. "%s is not a subpath of %s" % (fspath, self.zip_pre)
  1466. )
  1467. def _parts(self, zip_path):
  1468. # Convert a zipfile subpath into an egg-relative path part list.
  1469. # pseudo-fs path
  1470. fspath = self.zip_pre+zip_path
  1471. if fspath.startswith(self.egg_root+os.sep):
  1472. return fspath[len(self.egg_root)+1:].split(os.sep)
  1473. raise AssertionError(
  1474. "%s is not a subpath of %s" % (fspath, self.egg_root)
  1475. )
  1476. @property
  1477. def zipinfo(self):
  1478. return self._zip_manifests.load(self.loader.archive)
  1479. def get_resource_filename(self, manager, resource_name):
  1480. if not self.egg_name:
  1481. raise NotImplementedError(
  1482. "resource_filename() only supported for .egg, not .zip"
  1483. )
  1484. # no need to lock for extraction, since we use temp names
  1485. zip_path = self._resource_to_zip(resource_name)
  1486. eagers = self._get_eager_resources()
  1487. if '/'.join(self._parts(zip_path)) in eagers:
  1488. for name in eagers:
  1489. self._extract_resource(manager, self._eager_to_zip(name))
  1490. return self._extract_resource(manager, zip_path)
  1491. @staticmethod
  1492. def _get_date_and_size(zip_stat):
  1493. size = zip_stat.file_size
  1494. # ymdhms+wday, yday, dst
  1495. date_time = zip_stat.date_time + (0, 0, -1)
  1496. # 1980 offset already done
  1497. timestamp = time.mktime(date_time)
  1498. return timestamp, size
  1499. def _extract_resource(self, manager, zip_path):
  1500. if zip_path in self._index():
  1501. for name in self._index()[zip_path]:
  1502. last = self._extract_resource(
  1503. manager, os.path.join(zip_path, name)
  1504. )
  1505. # return the extracted directory name
  1506. return os.path.dirname(last)
  1507. timestamp, size = self._get_date_and_size(self.zipinfo[zip_path])
  1508. if not WRITE_SUPPORT:
  1509. raise IOError('"os.rename" and "os.unlink" are not supported '
  1510. 'on this platform')
  1511. try:
  1512. real_path = manager.get_cache_path(
  1513. self.egg_name, self._parts(zip_path)
  1514. )
  1515. if self._is_current(real_path, zip_path):
  1516. return real_path
  1517. outf, tmpnam = _mkstemp(".$extract", dir=os.path.dirname(real_path))
  1518. os.write(outf, self.loader.get_data(zip_path))
  1519. os.close(outf)
  1520. utime(tmpnam, (timestamp, timestamp))
  1521. manager.postprocess(tmpnam, real_path)
  1522. try:
  1523. rename(tmpnam, real_path)
  1524. except os.error:
  1525. if os.path.isfile(real_path):
  1526. if self._is_current(real_path, zip_path):
  1527. # the file became current since it was checked above,
  1528. # so proceed.
  1529. return real_path
  1530. # Windows, del old file and retry
  1531. elif os.name=='nt':
  1532. unlink(real_path)
  1533. rename(tmpnam, real_path)
  1534. return real_path
  1535. raise
  1536. except os.error:
  1537. # report a user-friendly error
  1538. manager.extraction_error()
  1539. return real_path
  1540. def _is_current(self, file_path, zip_path):
  1541. """
  1542. Return True if the file_path is current for this zip_path
  1543. """
  1544. timestamp, size = self._get_date_and_size(self.zipinfo[zip_path])
  1545. if not os.path.isfile(file_path):
  1546. return False
  1547. stat = os.stat(file_path)
  1548. if stat.st_size!=size or stat.st_mtime!=timestamp:
  1549. return False
  1550. # check that the contents match
  1551. zip_contents = self.loader.get_data(zip_path)
  1552. with open(file_path, 'rb') as f:
  1553. file_contents = f.read()
  1554. return zip_contents == file_contents
  1555. def _get_eager_resources(self):
  1556. if self.eagers is None:
  1557. eagers = []
  1558. for name in ('native_libs.txt', 'eager_resources.txt'):
  1559. if self.has_metadata(name):
  1560. eagers.extend(self.get_metadata_lines(name))
  1561. self.eagers = eagers
  1562. return self.eagers
  1563. def _index(self):
  1564. try:
  1565. return self._dirindex
  1566. except AttributeError:
  1567. ind = {}
  1568. for path in self.zipinfo:
  1569. parts = path.split(os.sep)
  1570. while parts:
  1571. parent = os.sep.join(parts[:-1])
  1572. if parent in ind:
  1573. ind[parent].append(parts[-1])
  1574. break
  1575. else:
  1576. ind[parent] = [parts.pop()]
  1577. self._dirindex = ind
  1578. return ind
  1579. def _has(self, fspath):
  1580. zip_path = self._zipinfo_name(fspath)
  1581. return zip_path in self.zipinfo or zip_path in self._index()
  1582. def _isdir(self, fspath):
  1583. return self._zipinfo_name(fspath) in self._index()
  1584. def _listdir(self, fspath):
  1585. return list(self._index().get(self._zipinfo_name(fspath), ()))
  1586. def _eager_to_zip(self, resource_name):
  1587. return self._zipinfo_name(self._fn(self.egg_root, resource_name))
  1588. def _resource_to_zip(self, resource_name):
  1589. return self._zipinfo_name(self._fn(self.module_path, resource_name))
  1590. register_loader_type(zipimport.zipimporter, ZipProvider)
  1591. class FileMetadata(EmptyProvider):
  1592. """Metadata handler for standalone PKG-INFO files
  1593. Usage::
  1594. metadata = FileMetadata("/path/to/PKG-INFO")
  1595. This provider rejects all data and metadata requests except for PKG-INFO,
  1596. which is treated as existing, and will be the contents of the file at
  1597. the provided location.
  1598. """
  1599. def __init__(self, path):
  1600. self.path = path
  1601. def has_metadata(self, name):
  1602. return name=='PKG-INFO'
  1603. def get_metadata(self, name):
  1604. if name=='PKG-INFO':
  1605. with open(self.path,'rU') as f:
  1606. metadata = f.read()
  1607. return metadata
  1608. raise KeyError("No metadata except PKG-INFO is available")
  1609. def get_metadata_lines(self, name):
  1610. return yield_lines(self.get_metadata(name))
  1611. class PathMetadata(DefaultProvider):
  1612. """Metadata provider for egg directories
  1613. Usage::
  1614. # Development eggs:
  1615. egg_info = "/path/to/PackageName.egg-info"
  1616. base_dir = os.path.dirname(egg_info)
  1617. metadata = PathMetadata(base_dir, egg_info)
  1618. dist_name = os.path.splitext(os.path.basename(egg_info))[0]
  1619. dist = Distribution(basedir, project_name=dist_name, metadata=metadata)
  1620. # Unpacked egg directories:
  1621. egg_path = "/path/to/PackageName-ver-pyver-etc.egg"
  1622. metadata = PathMetadata(egg_path, os.path.join(egg_path,'EGG-INFO'))
  1623. dist = Distribution.from_filename(egg_path, metadata=metadata)
  1624. """
  1625. def __init__(self, path, egg_info):
  1626. self.module_path = path
  1627. self.egg_info = egg_info
  1628. class EggMetadata(ZipProvider):
  1629. """Metadata provider for .egg files"""
  1630. def __init__(self, importer):
  1631. """Create a metadata provider from a zipimporter"""
  1632. self.zip_pre = importer.archive+os.sep
  1633. self.loader = importer
  1634. if importer.prefix:
  1635. self.module_path = os.path.join(importer.archive, importer.prefix)
  1636. else:
  1637. self.module_path = importer.archive
  1638. self._setup_prefix()
  1639. _declare_state('dict', _distribution_finders = {})
  1640. def register_finder(importer_type, distribution_finder):
  1641. """Register `distribution_finder` to find distributions in sys.path items
  1642. `importer_type` is the type or class of a PEP 302 "Importer" (sys.path item
  1643. handler), and `distribution_finder` is a callable that, passed a path
  1644. item and the importer instance, yields ``Distribution`` instances found on
  1645. that path item. See ``pkg_resources.find_on_path`` for an example."""
  1646. _distribution_finders[importer_type] = distribution_finder
  1647. def find_distributions(path_item, only=False):
  1648. """Yield distributions accessible via `path_item`"""
  1649. importer = get_importer(path_item)
  1650. finder = _find_adapter(_distribution_finders, importer)
  1651. return finder(importer, path_item, only)
  1652. def find_eggs_in_zip(importer, path_item, only=False):
  1653. """
  1654. Find eggs in zip files; possibly multiple nested eggs.
  1655. """
  1656. if importer.archive.endswith('.whl'):
  1657. # wheels are not supported with this finder
  1658. # they don't have PKG-INFO metadata, and won't ever contain eggs
  1659. return
  1660. metadata = EggMetadata(importer)
  1661. if metadata.has_metadata('PKG-INFO'):
  1662. yield Distribution.from_filename(path_item, metadata=metadata)
  1663. if only:
  1664. # don't yield nested distros
  1665. return
  1666. for subitem in metadata.resource_listdir('/'):
  1667. if subitem.endswith('.egg'):
  1668. subpath = os.path.join(path_item, subitem)
  1669. for dist in find_eggs_in_zip(zipimport.zipimporter(subpath), subpath):
  1670. yield dist
  1671. register_finder(zipimport.zipimporter, find_eggs_in_zip)
  1672. def find_nothing(importer, path_item, only=False):
  1673. return ()
  1674. register_finder(object, find_nothing)
  1675. def find_on_path(importer, path_item, only=False):
  1676. """Yield distributions accessible on a sys.path directory"""
  1677. path_item = _normalize_cached(path_item)
  1678. if os.path.isdir(path_item) and os.access(path_item, os.R_OK):
  1679. if path_item.lower().endswith('.egg'):
  1680. # unpacked egg
  1681. yield Distribution.from_filename(
  1682. path_item, metadata=PathMetadata(
  1683. path_item, os.path.join(path_item,'EGG-INFO')
  1684. )
  1685. )
  1686. else:
  1687. # scan for .egg and .egg-info in directory
  1688. for entry in os.listdir(path_item):
  1689. lower = entry.lower()
  1690. if lower.endswith('.egg-info') or lower.endswith('.dist-info'):
  1691. fullpath = os.path.join(path_item, entry)
  1692. if os.path.isdir(fullpath):
  1693. # egg-info directory, allow getting metadata
  1694. metadata = PathMetadata(path_item, fullpath)
  1695. else:
  1696. metadata = FileMetadata(fullpath)
  1697. yield Distribution.from_location(
  1698. path_item, entry, metadata, precedence=DEVELOP_DIST
  1699. )
  1700. elif not only and lower.endswith('.egg'):
  1701. dists = find_distributions(os.path.join(path_item, entry))
  1702. for dist in dists:
  1703. yield dist
  1704. elif not only and lower.endswith('.egg-link'):
  1705. with open(os.path.join(path_item, entry)) as entry_file:
  1706. entry_lines = entry_file.readlines()
  1707. for line in entry_lines:
  1708. if not line.strip():
  1709. continue
  1710. path = os.path.join(path_item, line.rstrip())
  1711. dists = find_distributions(path)
  1712. for item in dists:
  1713. yield item
  1714. break
  1715. register_finder(pkgutil.ImpImporter, find_on_path)
  1716. if importlib_bootstrap is not None:
  1717. register_finder(importlib_bootstrap.FileFinder, find_on_path)
  1718. _declare_state('dict', _namespace_handlers={})
  1719. _declare_state('dict', _namespace_packages={})
  1720. def register_namespace_handler(importer_type, namespace_handler):
  1721. """Register `namespace_handler` to declare namespace packages
  1722. `importer_type` is the type or class of a PEP 302 "Importer" (sys.path item
  1723. handler), and `namespace_handler` is a callable like this::
  1724. def namespace_handler(importer, path_entry, moduleName, module):
  1725. # return a path_entry to use for child packages
  1726. Namespace handlers are only called if the importer object has already
  1727. agreed that it can handle the relevant path item, and they should only
  1728. return a subpath if the module __path__ does not already contain an
  1729. equivalent subpath. For an example namespace handler, see
  1730. ``pkg_resources.file_ns_handler``.
  1731. """
  1732. _namespace_handlers[importer_type] = namespace_handler
  1733. def _handle_ns(packageName, path_item):
  1734. """Ensure that named package includes a subpath of path_item (if needed)"""
  1735. importer = get_importer(path_item)
  1736. if importer is None:
  1737. return None
  1738. loader = importer.find_module(packageName)
  1739. if loader is None:
  1740. return None
  1741. module = sys.modules.get(packageName)
  1742. if module is None:
  1743. module = sys.modules[packageName] = imp.new_module(packageName)
  1744. module.__path__ = []
  1745. _set_parent_ns(packageName)
  1746. elif not hasattr(module,'__path__'):
  1747. raise TypeError("Not a package:", packageName)
  1748. handler = _find_adapter(_namespace_handlers, importer)
  1749. subpath = handler(importer, path_item, packageName, module)
  1750. if subpath is not None:
  1751. path = module.__path__
  1752. path.append(subpath)
  1753. loader.load_module(packageName)
  1754. for path_item in path:
  1755. if path_item not in module.__path__:
  1756. module.__path__.append(path_item)
  1757. return subpath
  1758. def declare_namespace(packageName):
  1759. """Declare that package 'packageName' is a namespace package"""
  1760. imp.acquire_lock()
  1761. try:
  1762. if packageName in _namespace_packages:
  1763. return
  1764. path, parent = sys.path, None
  1765. if '.' in packageName:
  1766. parent = '.'.join(packageName.split('.')[:-1])
  1767. declare_namespace(parent)
  1768. if parent not in _namespace_packages:
  1769. __import__(parent)
  1770. try:
  1771. path = sys.modules[parent].__path__
  1772. except AttributeError:
  1773. raise TypeError("Not a package:", parent)
  1774. # Track what packages are namespaces, so when new path items are added,
  1775. # they can be updated
  1776. _namespace_packages.setdefault(parent,[]).append(packageName)
  1777. _namespace_packages.setdefault(packageName,[])
  1778. for path_item in path:
  1779. # Ensure all the parent's path items are reflected in the child,
  1780. # if they apply
  1781. _handle_ns(packageName, path_item)
  1782. finally:
  1783. imp.release_lock()
  1784. def fixup_namespace_packages(path_item, parent=None):
  1785. """Ensure that previously-declared namespace packages include path_item"""
  1786. imp.acquire_lock()
  1787. try:
  1788. for package in _namespace_packages.get(parent,()):
  1789. subpath = _handle_ns(package, path_item)
  1790. if subpath:
  1791. fixup_namespace_packages(subpath, package)
  1792. finally:
  1793. imp.release_lock()
  1794. def file_ns_handler(importer, path_item, packageName, module):
  1795. """Compute an ns-package subpath for a filesystem or zipfile importer"""
  1796. subpath = os.path.join(path_item, packageName.split('.')[-1])
  1797. normalized = _normalize_cached(subpath)
  1798. for item in module.__path__:
  1799. if _normalize_cached(item)==normalized:
  1800. break
  1801. else:
  1802. # Only return the path if it's not already there
  1803. return subpath
  1804. register_namespace_handler(pkgutil.ImpImporter, file_ns_handler)
  1805. register_namespace_handler(zipimport.zipimporter, file_ns_handler)
  1806. if importlib_bootstrap is not None:
  1807. register_namespace_handler(importlib_bootstrap.FileFinder, file_ns_handler)
  1808. def null_ns_handler(importer, path_item, packageName, module):
  1809. return None
  1810. register_namespace_handler(object, null_ns_handler)
  1811. def normalize_path(filename):
  1812. """Normalize a file/dir name for comparison purposes"""
  1813. return os.path.normcase(os.path.realpath(filename))
  1814. def _normalize_cached(filename, _cache={}):
  1815. try:
  1816. return _cache[filename]
  1817. except KeyError:
  1818. _cache[filename] = result = normalize_path(filename)
  1819. return result
  1820. def _set_parent_ns(packageName):
  1821. parts = packageName.split('.')
  1822. name = parts.pop()
  1823. if parts:
  1824. parent = '.'.join(parts)
  1825. setattr(sys.modules[parent], name, sys.modules[packageName])
  1826. def yield_lines(strs):
  1827. """Yield non-empty/non-comment lines of a string or sequence"""
  1828. if isinstance(strs, string_types):
  1829. for s in strs.splitlines():
  1830. s = s.strip()
  1831. # skip blank lines/comments
  1832. if s and not s.startswith('#'):
  1833. yield s
  1834. else:
  1835. for ss in strs:
  1836. for s in yield_lines(ss):
  1837. yield s
  1838. # whitespace and comment
  1839. LINE_END = re.compile(r"\s*(#.*)?$").match
  1840. # line continuation
  1841. CONTINUE = re.compile(r"\s*\\\s*(#.*)?$").match
  1842. # Distribution or extra
  1843. DISTRO = re.compile(r"\s*((\w|[-.])+)").match
  1844. # ver. info
  1845. VERSION = re.compile(r"\s*(<=?|>=?|===?|!=|~=)\s*((\w|[-.*_!+])+)").match
  1846. # comma between items
  1847. COMMA = re.compile(r"\s*,").match
  1848. OBRACKET = re.compile(r"\s*\[").match
  1849. CBRACKET = re.compile(r"\s*\]").match
  1850. MODULE = re.compile(r"\w+(\.\w+)*$").match
  1851. EGG_NAME = re.compile(
  1852. r"""
  1853. (?P<name>[^-]+) (
  1854. -(?P<ver>[^-]+) (
  1855. -py(?P<pyver>[^-]+) (
  1856. -(?P<plat>.+)
  1857. )?
  1858. )?
  1859. )?
  1860. """,
  1861. re.VERBOSE | re.IGNORECASE,
  1862. ).match
  1863. class EntryPoint(object):
  1864. """Object representing an advertised importable object"""
  1865. def __init__(self, name, module_name, attrs=(), extras=(), dist=None):
  1866. if not MODULE(module_name):
  1867. raise ValueError("Invalid module name", module_name)
  1868. self.name = name
  1869. self.module_name = module_name
  1870. self.attrs = tuple(attrs)
  1871. self.extras = Requirement.parse(("x[%s]" % ','.join(extras))).extras
  1872. self.dist = dist
  1873. def __str__(self):
  1874. s = "%s = %s" % (self.name, self.module_name)
  1875. if self.attrs:
  1876. s += ':' + '.'.join(self.attrs)
  1877. if self.extras:
  1878. s += ' [%s]' % ','.join(self.extras)
  1879. return s
  1880. def __repr__(self):
  1881. return "EntryPoint.parse(%r)" % str(self)
  1882. def load(self, require=True, *args, **kwargs):
  1883. """
  1884. Require packages for this EntryPoint, then resolve it.
  1885. """
  1886. if not require or args or kwargs:
  1887. warnings.warn(
  1888. "Parameters to load are deprecated. Call .resolve and "
  1889. ".require separately.",
  1890. DeprecationWarning,
  1891. stacklevel=2,
  1892. )
  1893. if require:
  1894. self.require(*args, **kwargs)
  1895. return self.resolve()
  1896. def resolve(self):
  1897. """
  1898. Resolve the entry point from its module and attrs.
  1899. """
  1900. module = __import__(self.module_name, fromlist=['__name__'], level=0)
  1901. try:
  1902. return functools.reduce(getattr, self.attrs, module)
  1903. except AttributeError as exc:
  1904. raise ImportError(str(exc))
  1905. def require(self, env=None, installer=None):
  1906. if self.extras and not self.dist:
  1907. raise UnknownExtra("Can't require() without a distribution", self)
  1908. reqs = self.dist.requires(self.extras)
  1909. items = working_set.resolve(reqs, env, installer)
  1910. list(map(working_set.add, items))
  1911. pattern = re.compile(
  1912. r'\s*'
  1913. r'(?P<name>.+?)\s*'
  1914. r'=\s*'
  1915. r'(?P<module>[\w.]+)\s*'
  1916. r'(:\s*(?P<attr>[\w.]+))?\s*'
  1917. r'(?P<extras>\[.*\])?\s*$'
  1918. )
  1919. @classmethod
  1920. def parse(cls, src, dist=None):
  1921. """Parse a single entry point from string `src`
  1922. Entry point syntax follows the form::
  1923. name = some.module:some.attr [extra1, extra2]
  1924. The entry name and module name are required, but the ``:attrs`` and
  1925. ``[extras]`` parts are optional
  1926. """
  1927. m = cls.pattern.match(src)
  1928. if not m:
  1929. msg = "EntryPoint must be in 'name=module:attrs [extras]' format"
  1930. raise ValueError(msg, src)
  1931. res = m.groupdict()
  1932. extras = cls._parse_extras(res['extras'])
  1933. attrs = res['attr'].split('.') if res['attr'] else ()
  1934. return cls(res['name'], res['module'], attrs, extras, dist)
  1935. @classmethod
  1936. def _parse_extras(cls, extras_spec):
  1937. if not extras_spec:
  1938. return ()
  1939. req = Requirement.parse('x' + extras_spec)
  1940. if req.specs:
  1941. raise ValueError()
  1942. return req.extras
  1943. @classmethod
  1944. def parse_group(cls, group, lines, dist=None):
  1945. """Parse an entry point group"""
  1946. if not MODULE(group):
  1947. raise ValueError("Invalid group name", group)
  1948. this = {}
  1949. for line in yield_lines(lines):
  1950. ep = cls.parse(line, dist)
  1951. if ep.name in this:
  1952. raise ValueError("Duplicate entry point", group, ep.name)
  1953. this[ep.name]=ep
  1954. return this
  1955. @classmethod
  1956. def parse_map(cls, data, dist=None):
  1957. """Parse a map of entry point groups"""
  1958. if isinstance(data, dict):
  1959. data = data.items()
  1960. else:
  1961. data = split_sections(data)
  1962. maps = {}
  1963. for group, lines in data:
  1964. if group is None:
  1965. if not lines:
  1966. continue
  1967. raise ValueError("Entry points must be listed in groups")
  1968. group = group.strip()
  1969. if group in maps:
  1970. raise ValueError("Duplicate group name", group)
  1971. maps[group] = cls.parse_group(group, lines, dist)
  1972. return maps
  1973. def _remove_md5_fragment(location):
  1974. if not location:
  1975. return ''
  1976. parsed = urlparse(location)
  1977. if parsed[-1].startswith('md5='):
  1978. return urlunparse(parsed[:-1] + ('',))
  1979. return location
  1980. class Distribution(object):
  1981. """Wrap an actual or potential sys.path entry w/metadata"""
  1982. PKG_INFO = 'PKG-INFO'
  1983. def __init__(self, location=None, metadata=None, project_name=None,
  1984. version=None, py_version=PY_MAJOR, platform=None,
  1985. precedence=EGG_DIST):
  1986. self.project_name = safe_name(project_name or 'Unknown')
  1987. if version is not None:
  1988. self._version = safe_version(version)
  1989. self.py_version = py_version
  1990. self.platform = platform
  1991. self.location = location
  1992. self.precedence = precedence
  1993. self._provider = metadata or empty_provider
  1994. @classmethod
  1995. def from_location(cls, location, basename, metadata=None,**kw):
  1996. project_name, version, py_version, platform = [None]*4
  1997. basename, ext = os.path.splitext(basename)
  1998. if ext.lower() in _distributionImpl:
  1999. # .dist-info gets much metadata differently
  2000. match = EGG_NAME(basename)
  2001. if match:
  2002. project_name, version, py_version, platform = match.group(
  2003. 'name','ver','pyver','plat'
  2004. )
  2005. cls = _distributionImpl[ext.lower()]
  2006. return cls(
  2007. location, metadata, project_name=project_name, version=version,
  2008. py_version=py_version, platform=platform, **kw
  2009. )
  2010. @property
  2011. def hashcmp(self):
  2012. return (
  2013. self.parsed_version,
  2014. self.precedence,
  2015. self.key,
  2016. _remove_md5_fragment(self.location),
  2017. self.py_version or '',
  2018. self.platform or '',
  2019. )
  2020. def __hash__(self):
  2021. return hash(self.hashcmp)
  2022. def __lt__(self, other):
  2023. return self.hashcmp < other.hashcmp
  2024. def __le__(self, other):
  2025. return self.hashcmp <= other.hashcmp
  2026. def __gt__(self, other):
  2027. return self.hashcmp > other.hashcmp
  2028. def __ge__(self, other):
  2029. return self.hashcmp >= other.hashcmp
  2030. def __eq__(self, other):
  2031. if not isinstance(other, self.__class__):
  2032. # It's not a Distribution, so they are not equal
  2033. return False
  2034. return self.hashcmp == other.hashcmp
  2035. def __ne__(self, other):
  2036. return not self == other
  2037. # These properties have to be lazy so that we don't have to load any
  2038. # metadata until/unless it's actually needed. (i.e., some distributions
  2039. # may not know their name or version without loading PKG-INFO)
  2040. @property
  2041. def key(self):
  2042. try:
  2043. return self._key
  2044. except AttributeError:
  2045. self._key = key = self.project_name.lower()
  2046. return key
  2047. @property
  2048. def parsed_version(self):
  2049. if not hasattr(self, "_parsed_version"):
  2050. self._parsed_version = parse_version(self.version)
  2051. return self._parsed_version
  2052. def _warn_legacy_version(self):
  2053. LV = packaging.version.LegacyVersion
  2054. is_legacy = isinstance(self._parsed_version, LV)
  2055. if not is_legacy:
  2056. return
  2057. # While an empty version is techincally a legacy version and
  2058. # is not a valid PEP 440 version, it's also unlikely to
  2059. # actually come from someone and instead it is more likely that
  2060. # it comes from setuptools attempting to parse a filename and
  2061. # including it in the list. So for that we'll gate this warning
  2062. # on if the version is anything at all or not.
  2063. if not self.version:
  2064. return
  2065. tmpl = textwrap.dedent("""
  2066. '{project_name} ({version})' is being parsed as a legacy,
  2067. non PEP 440,
  2068. version. You may find odd behavior and sort order.
  2069. In particular it will be sorted as less than 0.0. It
  2070. is recommend to migrate to PEP 440 compatible
  2071. versions.
  2072. """).strip().replace('\n', ' ')
  2073. warnings.warn(tmpl.format(**vars(self)), PEP440Warning)
  2074. @property
  2075. def version(self):
  2076. try:
  2077. return self._version
  2078. except AttributeError:
  2079. for line in self._get_metadata(self.PKG_INFO):
  2080. if line.lower().startswith('version:'):
  2081. self._version = safe_version(line.split(':',1)[1].strip())
  2082. return self._version
  2083. else:
  2084. tmpl = "Missing 'Version:' header and/or %s file"
  2085. raise ValueError(tmpl % self.PKG_INFO, self)
  2086. @property
  2087. def _dep_map(self):
  2088. try:
  2089. return self.__dep_map
  2090. except AttributeError:
  2091. dm = self.__dep_map = {None: []}
  2092. for name in 'requires.txt', 'depends.txt':
  2093. for extra, reqs in split_sections(self._get_metadata(name)):
  2094. if extra:
  2095. if ':' in extra:
  2096. extra, marker = extra.split(':', 1)
  2097. if invalid_marker(marker):
  2098. # XXX warn
  2099. reqs=[]
  2100. elif not evaluate_marker(marker):
  2101. reqs=[]
  2102. extra = safe_extra(extra) or None
  2103. dm.setdefault(extra,[]).extend(parse_requirements(reqs))
  2104. return dm
  2105. def requires(self, extras=()):
  2106. """List of Requirements needed for this distro if `extras` are used"""
  2107. dm = self._dep_map
  2108. deps = []
  2109. deps.extend(dm.get(None, ()))
  2110. for ext in extras:
  2111. try:
  2112. deps.extend(dm[safe_extra(ext)])
  2113. except KeyError:
  2114. raise UnknownExtra(
  2115. "%s has no such extra feature %r" % (self, ext)
  2116. )
  2117. return deps
  2118. def _get_metadata(self, name):
  2119. if self.has_metadata(name):
  2120. for line in self.get_metadata_lines(name):
  2121. yield line
  2122. def activate(self, path=None):
  2123. """Ensure distribution is importable on `path` (default=sys.path)"""
  2124. if path is None:
  2125. path = sys.path
  2126. self.insert_on(path)
  2127. if path is sys.path:
  2128. fixup_namespace_packages(self.location)
  2129. for pkg in self._get_metadata('namespace_packages.txt'):
  2130. if pkg in sys.modules:
  2131. declare_namespace(pkg)
  2132. def egg_name(self):
  2133. """Return what this distribution's standard .egg filename should be"""
  2134. filename = "%s-%s-py%s" % (
  2135. to_filename(self.project_name), to_filename(self.version),
  2136. self.py_version or PY_MAJOR
  2137. )
  2138. if self.platform:
  2139. filename += '-' + self.platform
  2140. return filename
  2141. def __repr__(self):
  2142. if self.location:
  2143. return "%s (%s)" % (self, self.location)
  2144. else:
  2145. return str(self)
  2146. def __str__(self):
  2147. try:
  2148. version = getattr(self, 'version', None)
  2149. except ValueError:
  2150. version = None
  2151. version = version or "[unknown version]"
  2152. return "%s %s" % (self.project_name, version)
  2153. def __getattr__(self, attr):
  2154. """Delegate all unrecognized public attributes to .metadata provider"""
  2155. if attr.startswith('_'):
  2156. raise AttributeError(attr)
  2157. return getattr(self._provider, attr)
  2158. @classmethod
  2159. def from_filename(cls, filename, metadata=None, **kw):
  2160. return cls.from_location(
  2161. _normalize_cached(filename), os.path.basename(filename), metadata,
  2162. **kw
  2163. )
  2164. def as_requirement(self):
  2165. """Return a ``Requirement`` that matches this distribution exactly"""
  2166. if isinstance(self.parsed_version, packaging.version.Version):
  2167. spec = "%s==%s" % (self.project_name, self.parsed_version)
  2168. else:
  2169. spec = "%s===%s" % (self.project_name, self.parsed_version)
  2170. return Requirement.parse(spec)
  2171. def load_entry_point(self, group, name):
  2172. """Return the `name` entry point of `group` or raise ImportError"""
  2173. ep = self.get_entry_info(group, name)
  2174. if ep is None:
  2175. raise ImportError("Entry point %r not found" % ((group, name),))
  2176. return ep.load()
  2177. def get_entry_map(self, group=None):
  2178. """Return the entry point map for `group`, or the full entry map"""
  2179. try:
  2180. ep_map = self._ep_map
  2181. except AttributeError:
  2182. ep_map = self._ep_map = EntryPoint.parse_map(
  2183. self._get_metadata('entry_points.txt'), self
  2184. )
  2185. if group is not None:
  2186. return ep_map.get(group,{})
  2187. return ep_map
  2188. def get_entry_info(self, group, name):
  2189. """Return the EntryPoint object for `group`+`name`, or ``None``"""
  2190. return self.get_entry_map(group).get(name)
  2191. def insert_on(self, path, loc = None):
  2192. """Insert self.location in path before its nearest parent directory"""
  2193. loc = loc or self.location
  2194. if not loc:
  2195. return
  2196. nloc = _normalize_cached(loc)
  2197. bdir = os.path.dirname(nloc)
  2198. npath= [(p and _normalize_cached(p) or p) for p in path]
  2199. for p, item in enumerate(npath):
  2200. if item == nloc:
  2201. break
  2202. elif item == bdir and self.precedence == EGG_DIST:
  2203. # if it's an .egg, give it precedence over its directory
  2204. if path is sys.path:
  2205. self.check_version_conflict()
  2206. path.insert(p, loc)
  2207. npath.insert(p, nloc)
  2208. break
  2209. else:
  2210. if path is sys.path:
  2211. self.check_version_conflict()
  2212. path.append(loc)
  2213. return
  2214. # p is the spot where we found or inserted loc; now remove duplicates
  2215. while True:
  2216. try:
  2217. np = npath.index(nloc, p+1)
  2218. except ValueError:
  2219. break
  2220. else:
  2221. del npath[np], path[np]
  2222. # ha!
  2223. p = np
  2224. return
  2225. def check_version_conflict(self):
  2226. if self.key == 'setuptools':
  2227. # ignore the inevitable setuptools self-conflicts :(
  2228. return
  2229. nsp = dict.fromkeys(self._get_metadata('namespace_packages.txt'))
  2230. loc = normalize_path(self.location)
  2231. for modname in self._get_metadata('top_level.txt'):
  2232. if (modname not in sys.modules or modname in nsp
  2233. or modname in _namespace_packages):
  2234. continue
  2235. if modname in ('pkg_resources', 'setuptools', 'site'):
  2236. continue
  2237. fn = getattr(sys.modules[modname], '__file__', None)
  2238. if fn and (normalize_path(fn).startswith(loc) or
  2239. fn.startswith(self.location)):
  2240. continue
  2241. issue_warning(
  2242. "Module %s was already imported from %s, but %s is being added"
  2243. " to sys.path" % (modname, fn, self.location),
  2244. )
  2245. def has_version(self):
  2246. try:
  2247. self.version
  2248. except ValueError:
  2249. issue_warning("Unbuilt egg for " + repr(self))
  2250. return False
  2251. return True
  2252. def clone(self,**kw):
  2253. """Copy this distribution, substituting in any changed keyword args"""
  2254. names = 'project_name version py_version platform location precedence'
  2255. for attr in names.split():
  2256. kw.setdefault(attr, getattr(self, attr, None))
  2257. kw.setdefault('metadata', self._provider)
  2258. return self.__class__(**kw)
  2259. @property
  2260. def extras(self):
  2261. return [dep for dep in self._dep_map if dep]
  2262. class DistInfoDistribution(Distribution):
  2263. """Wrap an actual or potential sys.path entry w/metadata, .dist-info style"""
  2264. PKG_INFO = 'METADATA'
  2265. EQEQ = re.compile(r"([\(,])\s*(\d.*?)\s*([,\)])")
  2266. @property
  2267. def _parsed_pkg_info(self):
  2268. """Parse and cache metadata"""
  2269. try:
  2270. return self._pkg_info
  2271. except AttributeError:
  2272. metadata = self.get_metadata(self.PKG_INFO)
  2273. self._pkg_info = email.parser.Parser().parsestr(metadata)
  2274. return self._pkg_info
  2275. @property
  2276. def _dep_map(self):
  2277. try:
  2278. return self.__dep_map
  2279. except AttributeError:
  2280. self.__dep_map = self._compute_dependencies()
  2281. return self.__dep_map
  2282. def _preparse_requirement(self, requires_dist):
  2283. """Convert 'Foobar (1); baz' to ('Foobar ==1', 'baz')
  2284. Split environment marker, add == prefix to version specifiers as
  2285. necessary, and remove parenthesis.
  2286. """
  2287. parts = requires_dist.split(';', 1) + ['']
  2288. distvers = parts[0].strip()
  2289. mark = parts[1].strip()
  2290. distvers = re.sub(self.EQEQ, r"\1==\2\3", distvers)
  2291. distvers = distvers.replace('(', '').replace(')', '')
  2292. return (distvers, mark)
  2293. def _compute_dependencies(self):
  2294. """Recompute this distribution's dependencies."""
  2295. from _markerlib import compile as compile_marker
  2296. dm = self.__dep_map = {None: []}
  2297. reqs = []
  2298. # Including any condition expressions
  2299. for req in self._parsed_pkg_info.get_all('Requires-Dist') or []:
  2300. distvers, mark = self._preparse_requirement(req)
  2301. parsed = next(parse_requirements(distvers))
  2302. parsed.marker_fn = compile_marker(mark)
  2303. reqs.append(parsed)
  2304. def reqs_for_extra(extra):
  2305. for req in reqs:
  2306. if req.marker_fn(override={'extra':extra}):
  2307. yield req
  2308. common = frozenset(reqs_for_extra(None))
  2309. dm[None].extend(common)
  2310. for extra in self._parsed_pkg_info.get_all('Provides-Extra') or []:
  2311. extra = safe_extra(extra.strip())
  2312. dm[extra] = list(frozenset(reqs_for_extra(extra)) - common)
  2313. return dm
  2314. _distributionImpl = {
  2315. '.egg': Distribution,
  2316. '.egg-info': Distribution,
  2317. '.dist-info': DistInfoDistribution,
  2318. }
  2319. def issue_warning(*args,**kw):
  2320. level = 1
  2321. g = globals()
  2322. try:
  2323. # find the first stack frame that is *not* code in
  2324. # the pkg_resources module, to use for the warning
  2325. while sys._getframe(level).f_globals is g:
  2326. level += 1
  2327. except ValueError:
  2328. pass
  2329. warnings.warn(stacklevel=level + 1, *args, **kw)
  2330. def parse_requirements(strs):
  2331. """Yield ``Requirement`` objects for each specification in `strs`
  2332. `strs` must be a string, or a (possibly-nested) iterable thereof.
  2333. """
  2334. # create a steppable iterator, so we can handle \-continuations
  2335. lines = iter(yield_lines(strs))
  2336. def scan_list(ITEM, TERMINATOR, line, p, groups, item_name):
  2337. items = []
  2338. while not TERMINATOR(line, p):
  2339. if CONTINUE(line, p):
  2340. try:
  2341. line = next(lines)
  2342. p = 0
  2343. except StopIteration:
  2344. raise ValueError(
  2345. "\\ must not appear on the last nonblank line"
  2346. )
  2347. match = ITEM(line, p)
  2348. if not match:
  2349. msg = "Expected " + item_name + " in"
  2350. raise ValueError(msg, line, "at", line[p:])
  2351. items.append(match.group(*groups))
  2352. p = match.end()
  2353. match = COMMA(line, p)
  2354. if match:
  2355. # skip the comma
  2356. p = match.end()
  2357. elif not TERMINATOR(line, p):
  2358. msg = "Expected ',' or end-of-list in"
  2359. raise ValueError(msg, line, "at", line[p:])
  2360. match = TERMINATOR(line, p)
  2361. # skip the terminator, if any
  2362. if match:
  2363. p = match.end()
  2364. return line, p, items
  2365. for line in lines:
  2366. match = DISTRO(line)
  2367. if not match:
  2368. raise ValueError("Missing distribution spec", line)
  2369. project_name = match.group(1)
  2370. p = match.end()
  2371. extras = []
  2372. match = OBRACKET(line, p)
  2373. if match:
  2374. p = match.end()
  2375. line, p, extras = scan_list(
  2376. DISTRO, CBRACKET, line, p, (1,), "'extra' name"
  2377. )
  2378. line, p, specs = scan_list(VERSION, LINE_END, line, p, (1, 2),
  2379. "version spec")
  2380. specs = [(op, val) for op, val in specs]
  2381. yield Requirement(project_name, specs, extras)
  2382. class Requirement:
  2383. def __init__(self, project_name, specs, extras):
  2384. """DO NOT CALL THIS UNDOCUMENTED METHOD; use Requirement.parse()!"""
  2385. self.unsafe_name, project_name = project_name, safe_name(project_name)
  2386. self.project_name, self.key = project_name, project_name.lower()
  2387. self.specifier = packaging.specifiers.SpecifierSet(
  2388. ",".join(["".join([x, y]) for x, y in specs])
  2389. )
  2390. self.specs = specs
  2391. self.extras = tuple(map(safe_extra, extras))
  2392. self.hashCmp = (
  2393. self.key,
  2394. self.specifier,
  2395. frozenset(self.extras),
  2396. )
  2397. self.__hash = hash(self.hashCmp)
  2398. def __str__(self):
  2399. extras = ','.join(self.extras)
  2400. if extras:
  2401. extras = '[%s]' % extras
  2402. return '%s%s%s' % (self.project_name, extras, self.specifier)
  2403. def __eq__(self, other):
  2404. return (
  2405. isinstance(other, Requirement) and
  2406. self.hashCmp == other.hashCmp
  2407. )
  2408. def __ne__(self, other):
  2409. return not self == other
  2410. def __contains__(self, item):
  2411. if isinstance(item, Distribution):
  2412. if item.key != self.key:
  2413. return False
  2414. item = item.version
  2415. # Allow prereleases always in order to match the previous behavior of
  2416. # this method. In the future this should be smarter and follow PEP 440
  2417. # more accurately.
  2418. return self.specifier.contains(item, prereleases=True)
  2419. def __hash__(self):
  2420. return self.__hash
  2421. def __repr__(self): return "Requirement.parse(%r)" % str(self)
  2422. @staticmethod
  2423. def parse(s):
  2424. reqs = list(parse_requirements(s))
  2425. if reqs:
  2426. if len(reqs) == 1:
  2427. return reqs[0]
  2428. raise ValueError("Expected only one requirement", s)
  2429. raise ValueError("No requirements found", s)
  2430. def _get_mro(cls):
  2431. """Get an mro for a type or classic class"""
  2432. if not isinstance(cls, type):
  2433. class cls(cls, object): pass
  2434. return cls.__mro__[1:]
  2435. return cls.__mro__
  2436. def _find_adapter(registry, ob):
  2437. """Return an adapter factory for `ob` from `registry`"""
  2438. for t in _get_mro(getattr(ob, '__class__', type(ob))):
  2439. if t in registry:
  2440. return registry[t]
  2441. def ensure_directory(path):
  2442. """Ensure that the parent directory of `path` exists"""
  2443. dirname = os.path.dirname(path)
  2444. if not os.path.isdir(dirname):
  2445. os.makedirs(dirname)
  2446. def _bypass_ensure_directory(path):
  2447. """Sandbox-bypassing version of ensure_directory()"""
  2448. if not WRITE_SUPPORT:
  2449. raise IOError('"os.mkdir" not supported on this platform.')
  2450. dirname, filename = split(path)
  2451. if dirname and filename and not isdir(dirname):
  2452. _bypass_ensure_directory(dirname)
  2453. mkdir(dirname, 0o755)
  2454. def split_sections(s):
  2455. """Split a string or iterable thereof into (section, content) pairs
  2456. Each ``section`` is a stripped version of the section header ("[section]")
  2457. and each ``content`` is a list of stripped lines excluding blank lines and
  2458. comment-only lines. If there are any such lines before the first section
  2459. header, they're returned in a first ``section`` of ``None``.
  2460. """
  2461. section = None
  2462. content = []
  2463. for line in yield_lines(s):
  2464. if line.startswith("["):
  2465. if line.endswith("]"):
  2466. if section or content:
  2467. yield section, content
  2468. section = line[1:-1].strip()
  2469. content = []
  2470. else:
  2471. raise ValueError("Invalid section heading", line)
  2472. else:
  2473. content.append(line)
  2474. # wrap up last segment
  2475. yield section, content
  2476. def _mkstemp(*args,**kw):
  2477. old_open = os.open
  2478. try:
  2479. # temporarily bypass sandboxing
  2480. os.open = os_open
  2481. return tempfile.mkstemp(*args,**kw)
  2482. finally:
  2483. # and then put it back
  2484. os.open = old_open
  2485. # Silence the PEP440Warning by default, so that end users don't get hit by it
  2486. # randomly just because they use pkg_resources. We want to append the rule
  2487. # because we want earlier uses of filterwarnings to take precedence over this
  2488. # one.
  2489. warnings.filterwarnings("ignore", category=PEP440Warning, append=True)
  2490. # Set up global resource manager (deliberately not state-saved)
  2491. _manager = ResourceManager()
  2492. def _initialize(g):
  2493. for name in dir(_manager):
  2494. if not name.startswith('_'):
  2495. g[name] = getattr(_manager, name)
  2496. _initialize(globals())
  2497. # Prepare the master working set and make the ``require()`` API available
  2498. working_set = WorkingSet._build_master()
  2499. _declare_state('object', working_set=working_set)
  2500. require = working_set.require
  2501. iter_entry_points = working_set.iter_entry_points
  2502. add_activation_listener = working_set.subscribe
  2503. run_script = working_set.run_script
  2504. # backward compatibility
  2505. run_main = run_script
  2506. # Activate all distributions already on sys.path, and ensure that
  2507. # all distributions added to the working set in the future (e.g. by
  2508. # calling ``require()``) will get activated as well.
  2509. add_activation_listener(lambda dist: dist.activate())
  2510. working_set.entries=[]
  2511. # match order
  2512. list(map(working_set.add_entry, sys.path))