def _parsed_extra(given, default): if not given: return default if given[0] not in "+!": setupmeta.warn( "PEP-440 allows only '+' as local version separator, please update your setup.py" ) given = given[1:] if not given: return given if given[0] == "!": setupmeta.warn( "'!' character in 'versioning' is now deprecated, please remove it" ) given = given[1:] if not given: return given if given == "devcommit": # Allow for convenience notation of the form "dev+devcommit" or "post+devcommit" etc return "{devcommit}{dirty}" if given == "build-id": # Allow for convenience notation of the form "dev+build-id" or "post+build-id" etc return "h{$*BUILD_ID:local}.{commitid}{dirty}" return given
def __init__(self, main, extra, branches, hook, **kwargs): self.main = main self.extra = extra if kwargs: setupmeta.warn("Ignored fields for 'versioning': %s" % kwargs) self.main_bits = self.bits(main) if isinstance(self.main_bits, list): self.bumpable = [ b.text for b in self.main_bits if b.text in BUMPABLE ] else: self.bumpable = [] self.extra_bits = self.bits(extra) self.branches = branches self.hook = hook if self.branches and hasattr(self.branches, "lstrip"): self.branches = self.branches.lstrip("(").rstrip(")") self.branches = setupmeta.listify(self.branches, separator=",") self.text = self.formatted(self.branches, self.main, self.extra) if not self.main_bits: self.problem = "No versioning format specified" return all_bits = self.main_bits if isinstance(self.main_bits, list) else [] if isinstance(self.extra_bits, list): all_bits = all_bits + self.extra_bits problems = [bit.problem for bit in all_bits if bit.problem] self.problem = "\n".join(problems) if problems else None
def auto_fill_version(self): """ Auto-fill version as defined by self.strategy :param setupmeta.model.SetupMeta meta: Parent meta object """ pygradle_version = os.environ.get("PYGRADLE_PROJECT_VERSION") if pygradle_version: # Minimal support for https://github.com/linkedin/pygradle self.meta.auto_fill("version", pygradle_version, "pygradle", override=True) return if not self.enabled: setupmeta.trace("not auto-filling version, versioning is disabled") return vdef = self.meta.definitions.get("version") if vdef and vdef.source and vdef.source.lower().endswith("-info"): # We already got version from PKG-INFO return cv = vdef.sources[0].value if vdef and vdef.sources else None if self.problem: if not cv: self.meta.auto_fill("version", "0.0.0", "missing") if self.strategy: setupmeta.warn(self.problem) setupmeta.trace("not auto-filling version due to problem: [%s]" % self.problem) return gv = self.scm.get_version() if self.generate_version_file: path = setupmeta.project_path(setupmeta.VERSION_FILE) with open(path, "w") as fh: fh.write("%s" % gv) if gv.patch and "patch" not in self.strategy.bumpable: msg = "patch version component should be .0 for versioning strategy '%s', " % self.strategy msg += "'.%s' from current version tag '%s' will be ignored" % ( gv.patch, gv) setupmeta.warn(msg) rendered = self.strategy.rendered(gv) if cv and gv: cvv = Version(main=cv, distance=gv.distance, commitid=gv.commitid, dirty=gv.dirty) if cvv.major != gv.major or cvv.minor != gv.minor or cvv.patch != gv.patch: source = vdef.sources[0].source expected = rendered[:len(cv)] msg = "In %s version should be %s, not %s" % (source, expected, cv) setupmeta.warn(msg) self.meta.auto_fill("version", rendered, self.scm.name, override=True)
def get_pip( ): # pragma: no cover, see https://github.com/pypa/setuptools/issues/2355 """ Deprecated, see https://github.com/zsimic/setupmeta/issues/49 Left around for a while because some callers import this, they will have to adapt to pip 20.1+ """ try: # pip >= 19.3 from pip._internal.req import parse_requirements from pip._internal.network.session import PipSession return parse_requirements, PipSession except ImportError: pass try: # pip >= 10.0 from pip._internal.req import parse_requirements from pip._internal.download import PipSession return parse_requirements, PipSession except ImportError: pass try: # pip < 10.0 from pip.req import parse_requirements from pip.download import PipSession return parse_requirements, PipSession except ImportError: from setupmeta import warn warn("Can't find PipSession, won't auto-fill requirements") return None, None
def _show_dependencies(definitions): """ Conveniently get dependency tree via ./setup.py check --dep, similar to https://pypi.org/project/pipdeptree """ if setupmeta.pkg_resources is None or not hasattr(setupmeta.pkg_resources, "WorkingSet"): setupmeta.warn("pkg_resources is not available, can't show dependencies") return 1 venv = find_venv() if not venv: setupmeta.warn("Could not find virtual environment to scan for dependencies") return 1 entries = list(find_subfolders(venv, ["site-packages"])) if not entries: setupmeta.warn("Could not find 'site-packages' subfolder in '%s'" % venv) return 1 tree = DepTree(setupmeta.pkg_resources.WorkingSet(entries), definitions) print(tree.rendered()) return len(tree.conflicts) + len(tree.cycles)
def finalize(self, upstream): self.attrs.update(MetaDefs.dist_to_dict(upstream)) self.find_project_dir(self.attrs.pop("_setup_py_path", None)) scm = self.attrs.pop("scm", None) # Add definitions from setup()'s attrs (highest priority) for key, value in self.attrs.items(): if key not in self.definitions: self.add_definition(key, value, EXPLICIT) # Add definitions from PKG-INFO, when available self.pkg_info = PackageInfo(MetaDefs.project_dir) for key, value in self.pkg_info.info.items(): if key in MetaDefs.all_fields: self.add_definition(key, value, relative_path(self.pkg_info.path)) # Allow to auto-fill 'name' from setup.py's __title__, if any self.merge(SimpleModule("setup.py")) title = self.definitions.get("title") if title: self.auto_fill("name", title.value, source=title.source) if "--name" in sys.argv[1:3]: # No need to waste time auto-filling anything if all we need to show is package name return self packages = self.attrs.get("packages", []) py_modules = self.attrs.get("py_modules", []) if not packages and not py_modules and self.name: # Try to auto-determine a good default from 'self.name' name = self.pythonified_name src_folder = project_path("src") if os.path.isdir(src_folder): packages = setuptools.find_packages(where=src_folder) if os.path.isfile(project_path("src", "%s.py" % name)): py_modules = [name] if packages or py_modules: self.auto_fill("package_dir", {"": "src"}) else: src_folder = project_path() packages = setuptools.find_packages(where=src_folder) if packages: # Take only found packages that start with the expected name # For any other use-case, user must explicitly list their packages packages = [p for p in packages if p.startswith(name)] if os.path.isfile(project_path("%s.py" % name)): py_modules = [name] if packages: self.auto_fill("packages", sorted(packages)) if py_modules: self.auto_fill("py_modules", py_modules) # Scan the usual/conventional places for py_module in py_modules: self.merge(SimpleModule("%s.py" % py_module)) for package in packages: if package and "." not in package: # Look at top level modules only self.merge( SimpleModule(package, "__about__.py"), SimpleModule(package, "__version__.py"), SimpleModule(package, "__init__.py"), SimpleModule("src", package, "__about__.py"), SimpleModule("src", package, "__version__.py"), SimpleModule("src", package, "__init__.py"), ) if not self.name: warn( "'name' not specified in setup.py, auto-fill will be incomplete" ) elif not self.definitions.get("packages") and not self.definitions.get( "py_modules"): warn( "No 'packages' or 'py_modules' defined, this is an empty python package" ) scm = scm or project_scm(MetaDefs.project_dir) self.versioning = Versioning(self, scm) self.versioning.auto_fill_version() self.fill_urls() self.auto_adjust("author", self.extract_email) self.auto_adjust("contact", self.extract_email) self.auto_adjust("maintainer", self.extract_email) self.requirements = Requirements(self.pkg_info) self.auto_fill_requires("install_requires") self.auto_fill_requires("tests_require") if self.requirements.dependency_links: self.auto_fill("dependency_links", self.requirements.dependency_links, self.requirements.links_source) self.auto_fill_classifiers() self.auto_fill_entry_points() self.auto_fill_license() self.auto_fill_long_description() self.auto_fill_include_package_data() self.sort_classifiers() return self