def test_first_word(): assert setupmeta.relative_path(None) is None assert setupmeta.relative_path("") == "" assert setupmeta.relative_path("foo") == "foo" assert setupmeta.first_word(None) is None assert setupmeta.first_word("") is None assert setupmeta.first_word(" \n \t ") is None assert setupmeta.first_word(" \n \t foo[bar]") == "foo" assert setupmeta.first_word("FOO bar") == "foo" assert setupmeta.first_word(" FOO, bar") == "foo" assert setupmeta.first_word("123") == "123"
def auto_fill_entry_points(self, key="entry_points"): if self.pkg_info.entry_points_txt: self.add_definition(key, load_contents(self.pkg_info.entry_points_txt), relative_path(self.pkg_info.entry_points_txt)) path = "%s.ini" % key self.add_definition(key, load_contents(path), path)
def delete(self, full_path): if os.path.isdir(full_path): shutil.rmtree(full_path) print("deleted %s" % setupmeta.relative_path(full_path)) else: os.unlink(full_path) self.by_ext[full_path.rpartition(".")[2]] += 1 self.deleted += 1
def __init__(self, path): self.source = relative_path(path) self.reqs = load_list(path) self.links = None if any(self.is_complex_requirement(line) for line in self.reqs): reqs, links = self.parse_requirements(path) if reqs: self.reqs = reqs self.links = links
def __init__(self, path, abstract=False): """ :param str path: Path to req file :param bool abstract: If True, abstract away simple pinning (applicable to install_requires only) """ self.source = relative_path(path) self.notes = {} self.reqs = [] self.abstracted = [] self.untouched = [] self.ignored = [] self.links = None if abstract: self.parse_with_comments() else: reqs, links = parse_requirements(path) if reqs: self.reqs = reqs self.links = links
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
def __init__(self, path, abstract=False): """ :param str path: Path to req file :param bool abstract: If True, abstract away simple pinning (applicable to install_requires only) """ self.source = relative_path(path) current_section = None self.notes = {} self.reqs = [] self.abstracted = [] self.untouched = [] self.ignored = [] for line in load_list(path, comment=None): if not abstract: # Not abstracting, just trim away comments if line.startswith("#"): continue if "# " in line: i = line.index("# ") line = line[:i].strip() if line: self.reqs.append(line) continue # We're abstracting, allow comments to tweak how we do that if line.startswith("#"): # Lines containing only a comment can start a "section", all requirements below this will respect that section word = first_word(line[1:]) if word in KNOWN_SECTIONS: current_section = word continue line_section = current_section note = None if "# " in line: # Trailing comments can direct us to treat that particular line in a certain way regarding pinning i = line.index("# ") word = first_word(line[i + 2:]) line = line[:i].strip() if word in KNOWN_SECTIONS: line_section = word note = "'%s' stated on line" % word if line_section == "indirect": # 'indirect' means the pinning was done to satisfy some indirect dependency, # but should not be considered as our project's dep self.ignored.append("%s # %s" % (line, note or "indirect section")) continue if (not line_section or line_section == "abstract") and "==" in line: # By default (or if in explicit 'abstract' section), trim away simple '==' pinning i = line.index("==") line = line[:i].strip() if not note: if line_section: note = "in '%s' section" % line_section else: note = "abstracted by default" self.abstracted.append("%s # %s" % (line, note)) elif line and (line[0].isalnum() or line.startswith("-e")): # Count as untouched only actual deps (ignore flags such as -i) if note: self.untouched.append("%s # %s" % (line, note)) else: self.untouched.append(line) if note: self.notes[line] = note or "abstract by default" self.reqs.append(line) self.links = None if any(is_complex_requirement(line) for line in self.reqs): reqs, links = parse_requirements(self.reqs) if reqs: self.reqs = reqs self.links = links