""" :copyright: 2010-2015 by Ronny Pfannschmidt :license: MIT """ import os import warnings from ._version_cls import NonNormalizedVersion from ._version_cls import Version from .config import Configuration from .config import DEFAULT_LOCAL_SCHEME from .config import DEFAULT_TAG_REGEX from .config import DEFAULT_VERSION_SCHEME from .discover import iter_matching_entrypoints from .utils import function_has_arg from .utils import trace from .version import format_version from .version import meta PRETEND_KEY = "SETUPTOOLS_SCM_PRETEND_VERSION" PRETEND_KEY_NAMED = PRETEND_KEY + "_FOR_{name}" TEMPLATES = { ".py": """\ # coding: utf-8 # file generated by setuptools_scm # don't change, don't track in version control version = {version!r} version_tuple = {version_tuple!r} """, ".txt": "{version}", } def version_from_scm(root): warnings.warn( "version_from_scm is deprecated please use get_version", category=DeprecationWarning, stacklevel=2, ) config = Configuration(root=root) # TODO: Is it API? return _version_from_entrypoints(config) def _call_entrypoint_fn(root, config, fn): if function_has_arg(fn, "config"): return fn(root, config=config) else: warnings.warn( f"parse function {fn.__module__}.{fn.__name__}" " are required to provide a named argument" " 'config', setuptools_scm>=8.0 will remove support.", category=DeprecationWarning, stacklevel=2, ) return fn(root) def _version_from_entrypoints(config: Configuration, fallback=False): if fallback: entrypoint = "setuptools_scm.parse_scm_fallback" root = config.fallback_root else: entrypoint = "setuptools_scm.parse_scm" root = config.absolute_root for ep in iter_matching_entrypoints(root, entrypoint, config): version = _call_entrypoint_fn(root, config, ep.load()) trace(ep, version) if version: return version def dump_version(root, version, write_to, template=None): assert isinstance(version, str) if not write_to: return target = os.path.normpath(os.path.join(root, write_to)) ext = os.path.splitext(target)[1] template = template or TEMPLATES.get(ext) if template is None: raise ValueError( "bad file format: '{}' (of {}) \nonly *.txt and *.py are supported".format( os.path.splitext(target)[1], target ) ) parsed_version = Version(version) version_fields = parsed_version.release if parsed_version.dev is not None: version_fields += (f"dev{parsed_version.dev}",) if parsed_version.local is not None: version_fields += (parsed_version.local,) with open(target, "w") as fp: fp.write(template.format(version=version, version_tuple=tuple(version_fields))) def _do_parse(config): trace("dist name:", config.dist_name) if config.dist_name is not None: pretended = os.environ.get( PRETEND_KEY_NAMED.format(name=config.dist_name.upper()) ) else: pretended = None if pretended is None: pretended = os.environ.get(PRETEND_KEY) if pretended: # we use meta here since the pretended version # must adhere to the pep to begin with return meta(tag=pretended, preformatted=True, config=config) if config.parse: parse_result = _call_entrypoint_fn(config.absolute_root, config, config.parse) if isinstance(parse_result, str): raise TypeError( "version parse result was a string\nplease return a parsed version" ) version = parse_result or _version_from_entrypoints(config, fallback=True) else: # include fallbacks after dropping them from the main entrypoint version = _version_from_entrypoints(config) or _version_from_entrypoints( config, fallback=True ) if version: return version raise LookupError( "setuptools-scm was unable to detect version for %r.\n\n" "Make sure you're either building from a fully intact git repository " "or PyPI tarballs. Most other sources (such as GitHub's tarballs, a " "git checkout without the .git folder) don't contain the necessary " "metadata and will not work.\n\n" "For example, if you're using pip, instead of " "https://github.com/user/proj/archive/master.zip " "use git+https://github.com/user/proj.git#egg=proj" % config.absolute_root ) def get_version( root=".", version_scheme=DEFAULT_VERSION_SCHEME, local_scheme=DEFAULT_LOCAL_SCHEME, write_to=None, write_to_template=None, relative_to=None, tag_regex=DEFAULT_TAG_REGEX, parentdir_prefix_version=None, fallback_version=None, fallback_root=".", parse=None, git_describe_command=None, dist_name=None, version_cls=None, normalize=True, search_parent_directories=False, ): """ If supplied, relative_to should be a file from which root may be resolved. Typically called by a script or module that is not in the root of the repository to direct setuptools_scm to the root of the repository by supplying ``__file__``. """ config = Configuration(**locals()) return _get_version(config) def _get_version(config): parsed_version = _do_parse(config) if parsed_version: version_string = format_version( parsed_version, version_scheme=config.version_scheme, local_scheme=config.local_scheme, ) dump_version( root=config.root, version=version_string, write_to=config.write_to, template=config.write_to_template, ) return version_string # Public API __all__ = [ "get_version", "dump_version", "version_from_scm", "Configuration", "DEFAULT_VERSION_SCHEME", "DEFAULT_LOCAL_SCHEME", "DEFAULT_TAG_REGEX", "Version", "NonNormalizedVersion", # TODO: are the symbols below part of public API ? "function_has_arg", "trace", "format_version", "meta", "iter_matching_entrypoints", ]