Source code for djangofloor.utils

"""Utility functions
=================

Define some utility functions like warning or walking through modules.

"""

import argparse
import os
import re
import zlib
from argparse import ArgumentParser
from importlib import import_module

import pkg_resources
from django.core.exceptions import ImproperlyConfigured
from django.utils.module_loading import import_string

__author__ = "Matthieu Gallet"


[docs]class RemovedInDjangoFloor110Warning(DeprecationWarning): """Used for displaying functions or modules that will be removed in a near future.""" pass
[docs]class RemovedInDjangoFloor200Warning(DeprecationWarning): """Used for displaying functions or modules that will be removed in a near future.""" pass
[docs]def is_package_present(package_name): """Return True is the `package_name` package is presend in your current Python environment.""" try: import_module(package_name) return True except ImportError: return False
[docs]def ensure_dir(path, parent=True): """Ensure that the given directory exists :param path: the path to check :param parent: only ensure the existence of the parent directory """ dirname = os.path.dirname(path) if parent else path if not os.path.isdir(dirname): os.makedirs(dirname) return path
[docs]def walk(module_name, dirname, topdown=True): """ Copy of :func:`os.walk`, please refer to its doc. The only difference is that we walk in a package_resource instead of a plain directory. :type module_name: basestring :param module_name: module to search in :type dirname: basestring :param dirname: base directory :type topdown: bool :param topdown: if True, perform a topdown search. """ def rec_walk(root): """ Recursively list subdirectories and filenames from the root. :param root: the root path :type root: basestring """ dirnames = [] filenames = [] for name in pkg_resources.resource_listdir(module_name, root): # noinspection PyUnresolvedReferences fullname = root + "/" + name isdir = pkg_resources.resource_isdir(module_name, fullname) if isdir: dirnames.append(name) if not topdown: rec_walk(fullname) else: filenames.append(name) yield root, dirnames, filenames if topdown: for name in dirnames: # noinspection PyUnresolvedReferences for values in rec_walk(root + "/" + name): yield values return rec_walk(dirname)
def _resolve_name(name, package, level): """Return the absolute name of the module to be imported.""" # noinspection PyTypeChecker if not hasattr(package, "rindex"): raise ValueError("'package' not set to a string") dot = len(package) for x in range(level, 1, -1): try: dot = package.rindex(".", 0, dot) except ValueError: raise ValueError("attempted relative import beyond top-level package") return "%s.%s" % (package[:dot], name)
[docs]def guess_version(defined_settings): """Guesss the project version. Expect an installed version (findable with pkg_resources) or __version__ in `your_project/__init__.py`. If not found :param defined_settings: all already defined settings (dict) :type defined_settings: :class:`dict` :return: should be something like `"1.2.3"` :rtype: :class:`str` """ try: project_distribution = pkg_resources.get_distribution( defined_settings["DF_MODULE_NAME"] ) return project_distribution.version except pkg_resources.DistributionNotFound: pass try: return import_string("%s.__version__" % defined_settings["DF_MODULE_NAME"]) except ImportError: return "1.0.0"
[docs]def get_view_from_string(view_as_str): try: view = import_string(view_as_str) except ImportError: raise ImproperlyConfigured("Unable to import %s" % view_as_str) if hasattr(view, "as_view") and callable(view.as_view): return view.as_view() elif callable(view): return view raise ImproperlyConfigured( '%s is not callabled and does not have an "as_view" attribute' )
[docs]def remove_arguments_from_help(parser, arguments): assert isinstance(parser, ArgumentParser) assert isinstance(arguments, set) # noinspection PyProtectedMember for action in parser._actions: if arguments & set(action.option_strings): action.help = argparse.SUPPRESS
[docs]def smart_pipfile_url(url: str) -> str: """ Given a `pip install URL`, return a valid PipFile line. >>> smart_pipfile_url('git://git.myproject.org/MyProject#egg=MyProject') "MyProject = { git = 'git://git.myproject.org/MyProject', editable = true }" >>> smart_pipfile_url('git+http://git.myproject.org/MyProject#egg=MyProject') "MyProject = { git = 'http://git.myproject.org/MyProject', editable = true }" >>> smart_pipfile_url('git+https://git.myproject.org/MyProject#egg=MyProject') "MyProject = { git = 'https://git.myproject.org/MyProject', editable = true }" >>> smart_pipfile_url('git+ssh://git.myproject.org/MyProject#egg=MyProject') "MyProject = { git = 'ssh://git.myproject.org/MyProject', editable = true }" >>> smart_pipfile_url('git+git://git.myproject.org/MyProject#egg=MyProject') "MyProject = { git = 'git://git.myproject.org/MyProject', editable = true }" >>> smart_pipfile_url('git+file://git.myproject.org/MyProject#egg=MyProject') "MyProject = { git = 'file://git.myproject.org/MyProject', editable = true }" >>> smart_pipfile_url('git+git@git.myproject.org:MyProject#egg=MyProject') "MyProject = { git = 'git://git@git.myproject.org/MyProject', editable = true }" >>> smart_pipfile_url('git://git.myproject.org/MyProject.git@master#egg=MyProject') "MyProject = { git = 'git://git.myproject.org/MyProject.git', ref = 'master', editable = true }" >>> smart_pipfile_url('git://git.myproject.org/MyProject.git@v1.0#egg=MyProject') "MyProject = { git = 'git://git.myproject.org/MyProject.git', ref = 'v1.0', editable = true }" >>> smart_pipfile_url('git://git.myproject.org/MyProject.git@da39a3ee5e6b4b0d3255bfef#egg=MyProject') "MyProject = { git = 'git://git.myproject.org/MyProject.git', ref = 'da39a3ee5e6b4b0d3255bfef', editable = true }" >>> smart_pipfile_url('hg+http://hg.myproject.org/MyProject#egg=MyProject') "MyProject = { hg = 'http://hg.myproject.org/MyProject', editable = true }" >>> smart_pipfile_url('hg+https://hg.myproject.org/MyProject#egg=MyProject') "MyProject = { hg = 'https://hg.myproject.org/MyProject', editable = true }" >>> smart_pipfile_url('hg+ssh://hg.myproject.org/MyProject#egg=MyProject') "MyProject = { hg = 'ssh://hg.myproject.org/MyProject', editable = true }" >>> smart_pipfile_url('hg+http://hg.myproject.org/MyProject@da39a3ee5e6b#egg=MyProject') "MyProject = { hg = 'http://hg.myproject.org/MyProject', ref = 'da39a3ee5e6b', editable = true }" >>> smart_pipfile_url('svn+svn://svn.myproject.org/svn/MyProject#egg=MyProject') "MyProject = { svn = 'svn://svn.myproject.org/svn/MyProject', editable = true }" >>> smart_pipfile_url('svn+http://svn.myproject.org/svn/MyProject/trunk@2019#egg=MyProject') "MyProject = { svn = 'http://svn.myproject.org/svn/MyProject/trunk', ref = '2019', editable = true }" >>> smart_pipfile_url('bzr+http://bzr.myproject.org/MyProject/trunk#egg=MyProject') "MyProject = { bzr = 'http://bzr.myproject.org/MyProject/trunk', editable = true }" >>> smart_pipfile_url('bzr+sftp://user@myproject.org/MyProject/trunk#egg=MyProject') "MyProject = { bzr = 'sftp://user@myproject.org/MyProject/trunk', editable = true }" >>> smart_pipfile_url('bzr+ssh://user@myproject.org/MyProject/trunk#egg=MyProject') "MyProject = { bzr = 'ssh://user@myproject.org/MyProject/trunk', editable = true }" >>> smart_pipfile_url('requests[socks]') "requests = { extras = ['socks'] }" >>> smart_pipfile_url('requests[socks,all]') "requests = { extras = ['socks', 'all'] }" >>> smart_pipfile_url('records>0.5.0') "records = '>0.5.0'" >>> smart_pipfile_url('git+https://github.com/django/django.git@1.11.4') "django = { git = 'https://github.com/django/django.git', ref = '1.11.4', editable = true }" >>> smart_pipfile_url('https://github.com/divio/django-cms/archive/release/3.4.x.zip') '"7377c666" = { file = \\'https://github.com/divio/django-cms/archive/release/3.4.x.zip\\' }' >>> smart_pipfile_url('pywinusb;python_version<"2.7"') "pywinusb = '*'" """ def pip_repr(value: dict): return "{ %s }" % ", ".join(["%s = %r" % (k, v) for (k, v) in value.items()]) class TRUE: def __repr__(self): return "true" url_matcher = re.match( r"^(svn\+|git\+|hg\+|bzr\+)?(([^:]+)://[^/]+/[^@#]+)(@[^#]+)?(#.+)?$", url ) git_matcher = re.match(r"^git\+([^@]+)@([^:]+):([^#]+)#egg=(.*)$", url) pkg_matcher = re.match( r"^([^\[;=<>~]+)(\[[^\]]+\])?((===|!=|<=|>=|<|>|==|~=)[^;]+)?(;.*)?$", url.replace(" ", ""), ) egg_name = None values = {} if url_matcher: versionning_protocol, url, scheme, tag, anchor = url_matcher.groups() if versionning_protocol is None: if scheme == "git": versionning_protocol = scheme else: versionning_protocol = "file" else: versionning_protocol = versionning_protocol[:-1] if url.endswith(".git"): egg_name = url.rpartition("/")[2].rpartition(".")[0] elif versionning_protocol == "git": egg_name = url.rpartition("/")[2] if anchor and anchor.startswith("#egg="): egg_name = anchor[5:] values[versionning_protocol] = url if tag: values["ref"] = tag[1:] if versionning_protocol != "file": values["editable"] = TRUE() if not egg_name: egg_name = ('"%X"' % zlib.crc32(url.encode())).lower() elif git_matcher: login, host, project, egg_name = git_matcher.groups() values["git"] = "git://%s@%s/%s" % (login, host, project) values["editable"] = TRUE() elif pkg_matcher: egg_name, extra, spec, __, markers = pkg_matcher.groups() if extra: values["extras"] = extra[1:-1].split(",") if spec: values["version"] = spec elif not values: values["version"] = "*" if len(values) == 1 and "version" in values: return "%s = %r" % (egg_name, values["version"]) return "%s = %s" % (egg_name, pip_repr(values))