/usr/lib/python3/dist-packages/pyramid/path.py is in python3-pyramid 1.6+dfsg-1.1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 | import os
import pkg_resources
import sys
import imp
from zope.interface import implementer
from pyramid.interfaces import IAssetDescriptor
from pyramid.compat import string_types
ignore_types = [ imp.C_EXTENSION, imp.C_BUILTIN ]
init_names = [ '__init__%s' % x[0] for x in imp.get_suffixes() if
x[0] and x[2] not in ignore_types ]
def caller_path(path, level=2):
if not os.path.isabs(path):
module = caller_module(level+1)
prefix = package_path(module)
path = os.path.join(prefix, path)
return path
def caller_module(level=2, sys=sys):
module_globals = sys._getframe(level).f_globals
module_name = module_globals.get('__name__') or '__main__'
module = sys.modules[module_name]
return module
def package_name(pkg_or_module):
""" If this function is passed a module, return the dotted Python
package name of the package in which the module lives. If this
function is passed a package, return the dotted Python package
name of the package itself."""
if pkg_or_module is None or pkg_or_module.__name__ == '__main__':
return '__main__'
pkg_name = pkg_or_module.__name__
pkg_filename = getattr(pkg_or_module, '__file__', None)
if pkg_filename is None:
# Namespace packages do not have __init__.py* files,
# and so have no __file__ attribute
return pkg_name
splitted = os.path.split(pkg_filename)
if splitted[-1] in init_names:
# it's a package
return pkg_name
return pkg_name.rsplit('.', 1)[0]
def package_of(pkg_or_module):
""" Return the package of a module or return the package itself """
pkg_name = package_name(pkg_or_module)
__import__(pkg_name)
return sys.modules[pkg_name]
def caller_package(level=2, caller_module=caller_module):
# caller_module in arglist for tests
module = caller_module(level+1)
f = getattr(module, '__file__', '')
if (('__init__.py' in f) or ('__init__$py' in f)): # empty at >>>
# Module is a package
return module
# Go up one level to get package
package_name = module.__name__.rsplit('.', 1)[0]
return sys.modules[package_name]
def package_path(package):
# computing the abspath is actually kinda expensive so we memoize
# the result
prefix = getattr(package, '__abspath__', None)
if prefix is None:
prefix = pkg_resources.resource_filename(package.__name__, '')
# pkg_resources doesn't care whether we feed it a package
# name or a module name within the package, the result
# will be the same: a directory name to the package itself
try:
package.__abspath__ = prefix
except:
# this is only an optimization, ignore any error
pass
return prefix
class _CALLER_PACKAGE(object):
def __repr__(self): # pragma: no cover (for docs)
return 'pyramid.path.CALLER_PACKAGE'
CALLER_PACKAGE = _CALLER_PACKAGE()
class Resolver(object):
def __init__(self, package=CALLER_PACKAGE):
if package in (None, CALLER_PACKAGE):
self.package = package
else:
if isinstance(package, string_types):
try:
__import__(package)
except ImportError:
raise ValueError(
'The dotted name %r cannot be imported' % (package,)
)
package = sys.modules[package]
self.package = package_of(package)
def get_package_name(self):
if self.package is CALLER_PACKAGE:
package_name = caller_package().__name__
else:
package_name = self.package.__name__
return package_name
def get_package(self):
if self.package is CALLER_PACKAGE:
package = caller_package()
else:
package = self.package
return package
class AssetResolver(Resolver):
""" A class used to resolve an :term:`asset specification` to an
:term:`asset descriptor`.
.. versionadded:: 1.3
The constructor accepts a single argument named ``package`` which may be
any of:
- A fully qualified (not relative) dotted name to a module or package
- a Python module or package object
- The value ``None``
- The constant value :attr:`pyramid.path.CALLER_PACKAGE`.
The default value is :attr:`pyramid.path.CALLER_PACKAGE`.
The ``package`` is used when a relative asset specification is supplied
to the :meth:`~pyramid.path.AssetResolver.resolve` method. An asset
specification without a colon in it is treated as relative.
If ``package`` is ``None``, the resolver will
only be able to resolve fully qualified (not relative) asset
specifications. Any attempt to resolve a relative asset specification
will result in an :exc:`ValueError` exception.
If ``package`` is :attr:`pyramid.path.CALLER_PACKAGE`,
the resolver will treat relative asset specifications as
relative to the caller of the :meth:`~pyramid.path.AssetResolver.resolve`
method.
If ``package`` is a *module* or *module name* (as opposed to a package or
package name), its containing package is computed and this
package is used to derive the package name (all names are resolved relative
to packages, never to modules). For example, if the ``package`` argument
to this type was passed the string ``xml.dom.expatbuilder``, and
``template.pt`` is supplied to the
:meth:`~pyramid.path.AssetResolver.resolve` method, the resulting absolute
asset spec would be ``xml.minidom:template.pt``, because
``xml.dom.expatbuilder`` is a module object, not a package object.
If ``package`` is a *package* or *package name* (as opposed to a module or
module name), this package will be used to compute relative
asset specifications. For example, if the ``package`` argument to this
type was passed the string ``xml.dom``, and ``template.pt`` is supplied
to the :meth:`~pyramid.path.AssetResolver.resolve` method, the resulting
absolute asset spec would be ``xml.minidom:template.pt``.
"""
def resolve(self, spec):
"""
Resolve the asset spec named as ``spec`` to an object that has the
attributes and methods described in
:class:`pyramid.interfaces.IAssetDescriptor`.
If ``spec`` is an absolute filename
(e.g. ``/path/to/myproject/templates/foo.pt``) or an absolute asset
spec (e.g. ``myproject:templates.foo.pt``), an asset descriptor is
returned without taking into account the ``package`` passed to this
class' constructor.
If ``spec`` is a *relative* asset specification (an asset
specification without a ``:`` in it, e.g. ``templates/foo.pt``), the
``package`` argument of the constructor is used as the package
portion of the asset spec. For example:
.. code-block:: python
a = AssetResolver('myproject')
resolver = a.resolve('templates/foo.pt')
print(resolver.abspath())
# -> /path/to/myproject/templates/foo.pt
If the AssetResolver is constructed without a ``package`` argument of
``None``, and a relative asset specification is passed to
``resolve``, an :exc:`ValueError` exception is raised.
"""
if os.path.isabs(spec):
return FSAssetDescriptor(spec)
path = spec
if ':' in path:
package_name, path = spec.split(':', 1)
else:
if self.package is CALLER_PACKAGE:
package_name = caller_package().__name__
else:
package_name = getattr(self.package, '__name__', None)
if package_name is None:
raise ValueError(
'relative spec %r irresolveable without package' % (spec,)
)
return PkgResourcesAssetDescriptor(package_name, path)
class DottedNameResolver(Resolver):
""" A class used to resolve a :term:`dotted Python name` to a package or
module object.
.. versionadded:: 1.3
The constructor accepts a single argument named ``package`` which may be
any of:
- A fully qualified (not relative) dotted name to a module or package
- a Python module or package object
- The value ``None``
- The constant value :attr:`pyramid.path.CALLER_PACKAGE`.
The default value is :attr:`pyramid.path.CALLER_PACKAGE`.
The ``package`` is used when a relative dotted name is supplied to the
:meth:`~pyramid.path.DottedNameResolver.resolve` method. A dotted name
which has a ``.`` (dot) or ``:`` (colon) as its first character is
treated as relative.
If ``package`` is ``None``, the resolver will only be able to resolve
fully qualified (not relative) names. Any attempt to resolve a
relative name will result in an :exc:`ValueError` exception.
If ``package`` is :attr:`pyramid.path.CALLER_PACKAGE`,
the resolver will treat relative dotted names as relative to
the caller of the :meth:`~pyramid.path.DottedNameResolver.resolve`
method.
If ``package`` is a *module* or *module name* (as opposed to a package or
package name), its containing package is computed and this
package used to derive the package name (all names are resolved relative
to packages, never to modules). For example, if the ``package`` argument
to this type was passed the string ``xml.dom.expatbuilder``, and
``.mindom`` is supplied to the
:meth:`~pyramid.path.DottedNameResolver.resolve` method, the resulting
import would be for ``xml.minidom``, because ``xml.dom.expatbuilder`` is
a module object, not a package object.
If ``package`` is a *package* or *package name* (as opposed to a module or
module name), this package will be used to relative compute
dotted names. For example, if the ``package`` argument to this type was
passed the string ``xml.dom``, and ``.minidom`` is supplied to the
:meth:`~pyramid.path.DottedNameResolver.resolve` method, the resulting
import would be for ``xml.minidom``.
"""
def resolve(self, dotted):
"""
This method resolves a dotted name reference to a global Python
object (an object which can be imported) to the object itself.
Two dotted name styles are supported:
- ``pkg_resources``-style dotted names where non-module attributes
of a package are separated from the rest of the path using a ``:``
e.g. ``package.module:attr``.
- ``zope.dottedname``-style dotted names where non-module
attributes of a package are separated from the rest of the path
using a ``.`` e.g. ``package.module.attr``.
These styles can be used interchangeably. If the supplied name
contains a ``:`` (colon), the ``pkg_resources`` resolution
mechanism will be chosen, otherwise the ``zope.dottedname``
resolution mechanism will be chosen.
If the ``dotted`` argument passed to this method is not a string, a
:exc:`ValueError` will be raised.
When a dotted name cannot be resolved, a :exc:`ValueError` error is
raised.
Example:
.. code-block:: python
r = DottedNameResolver()
v = r.resolve('xml') # v is the xml module
"""
if not isinstance(dotted, string_types):
raise ValueError('%r is not a string' % (dotted,))
package = self.package
if package is CALLER_PACKAGE:
package = caller_package()
return self._resolve(dotted, package)
def maybe_resolve(self, dotted):
"""
This method behaves just like
:meth:`~pyramid.path.DottedNameResolver.resolve`, except if the
``dotted`` value passed is not a string, it is simply returned. For
example:
.. code-block:: python
import xml
r = DottedNameResolver()
v = r.maybe_resolve(xml)
# v is the xml module; no exception raised
"""
if isinstance(dotted, string_types):
package = self.package
if package is CALLER_PACKAGE:
package = caller_package()
return self._resolve(dotted, package)
return dotted
def _resolve(self, dotted, package):
if ':' in dotted:
return self._pkg_resources_style(dotted, package)
else:
return self._zope_dottedname_style(dotted, package)
def _pkg_resources_style(self, value, package):
""" package.module:attr style """
if value.startswith(('.', ':')):
if not package:
raise ValueError(
'relative name %r irresolveable without package' % (value,)
)
if value in ['.', ':']:
value = package.__name__
else:
value = package.__name__ + value
# Calling EntryPoint.load with an argument is deprecated.
# See https://pythonhosted.org/setuptools/history.html#id8
ep = pkg_resources.EntryPoint.parse('x=%s' % value)
if hasattr(ep, 'resolve'):
# setuptools>=10.2
return ep.resolve() # pragma: NO COVER
else:
return ep.load(False) # pragma: NO COVER
def _zope_dottedname_style(self, value, package):
""" package.module.attr style """
module = getattr(package, '__name__', None) # package may be None
if not module:
module = None
if value == '.':
if module is None:
raise ValueError(
'relative name %r irresolveable without package' % (value,)
)
name = module.split('.')
else:
name = value.split('.')
if not name[0]:
if module is None:
raise ValueError(
'relative name %r irresolveable without '
'package' % (value,)
)
module = module.split('.')
name.pop(0)
while not name[0]:
module.pop()
name.pop(0)
name = module + name
used = name.pop(0)
found = __import__(used)
for n in name:
used += '.' + n
try:
found = getattr(found, n)
except AttributeError:
__import__(used)
found = getattr(found, n) # pragma: no cover
return found
@implementer(IAssetDescriptor)
class PkgResourcesAssetDescriptor(object):
pkg_resources = pkg_resources
def __init__(self, pkg_name, path):
self.pkg_name = pkg_name
self.path = path
def absspec(self):
return '%s:%s' % (self.pkg_name, self.path)
def abspath(self):
return os.path.abspath(
self.pkg_resources.resource_filename(self.pkg_name, self.path))
def stream(self):
return self.pkg_resources.resource_stream(self.pkg_name, self.path)
def isdir(self):
return self.pkg_resources.resource_isdir(self.pkg_name, self.path)
def listdir(self):
return self.pkg_resources.resource_listdir(self.pkg_name, self.path)
def exists(self):
return self.pkg_resources.resource_exists(self.pkg_name, self.path)
@implementer(IAssetDescriptor)
class FSAssetDescriptor(object):
def __init__(self, path):
self.path = os.path.abspath(path)
def absspec(self):
raise NotImplementedError
def abspath(self):
return self.path
def stream(self):
return open(self.path, 'rb')
def isdir(self):
return os.path.isdir(self.path)
def listdir(self):
return os.listdir(self.path)
def exists(self):
return os.path.exists(self.path)
|