def test_unsupported_twine(*_): with setupmeta.temp_resource() as temp: copy_to(setupmeta.project_path("examples", "single", "setup.py"), temp) copy_to(setupmeta.project_path("examples", "single", "single.py"), temp) run_setup_py(["twine"], "twine command not supported on pypy", folder=temp)
def get_requirements(*relative_paths): """ Read old-school requirements.txt type file """ for path in relative_paths: path = project_path(path) if os.path.isfile(path): trace("found requirements: %s" % path) return RequirementsEntry(path)
def load_readme(relative_path, limit=0): """ Loader for README files """ content = [] try: full_path = setupmeta.project_path(relative_path) with io.open(full_path, encoding='utf-8') as fh: for line in fh.readlines(): m = RE_README_TOKEN.search(line) if not m: content.append(line) continue pre, post = m.group(1), m.group(4) pre = pre and pre.strip() post = post and post.strip() if pre or post: content.append(line) continue # Not beginning/end, or no spaces around action = m.group(2) param = m.group(3) if action == 'end' and param == 'long_description': break if action == 'include': included = load_readme(param, limit=limit) if included: content.append(included) return ''.join(content).strip() except IOError: return None
def run(self): if platform.python_implementation() != "CPython": abort("twine command not supported on %s" % platform.python_implementation()) if not self.egg and not self.sdist and not self.wheel: abort("Specify at least one of: --egg, --dist or --wheel") twine = setupmeta.which('twine') if not twine: abort("twine is not installed") if not self.commit: print("Dryrun, use --commit to effectively build/publish") dist = setupmeta.project_path('dist') self.clean('dist', 'build') try: if self.should_run(self.egg): self.run_command("build egg distribution", sys.executable, 'setup.py', 'bdist_egg') if self.should_run(self.sdist): self.run_command("build source distribution", sys.executable, 'setup.py', 'sdist') if self.should_run(self.wheel): self.run_command("build wheel distribution", sys.executable, 'setup.py', 'bdist_wheel', '--universal') if self.commit and not os.path.exists(dist): abort("No files found in %s" % dist) files = [os.path.join(dist, name) for name in sorted(os.listdir(dist))] if self.commit else ['dist/*'] self.run_command("upload to PyPi via twine", twine, 'upload', *files) finally: self.clean('build')
def test_find_scm_in_parent(): meta = new_meta("post") versioning = meta.versioning assert versioning.enabled assert not versioning.problem assert setupmeta.project_path() == conftest.TESTS assert versioning.scm.root == conftest.PROJECT_DIR
def __init__(self, *relative_paths): """ :param list(str) relative_paths: Relative path to scan for definitions """ Settings.__init__(self) self.relative_path = os.path.join(*relative_paths) self.full_path = project_path(*relative_paths) self.exists = os.path.isfile(self.full_path) if self.exists: with io.open(self.full_path, "rt") as fh: docstring_marker = None docstring_start = None docstring = [] line_number = 0 for line in fh: line_number += 1 line = line.rstrip() if docstring_marker: if line.endswith(docstring_marker): docstring_marker = None if docstring: self.scan_docstring(docstring, line_number=docstring_start - 1) else: docstring.append(line) continue if line.startswith('"""') or line.startswith("'''"): docstring_marker = line[:3] if len(line) > 3 and line.endswith(docstring_marker): # Single docstring line edge case docstring_marker = None continue docstring_start = line_number docstring.append(line[3:]) continue self.scan_line(line, RE_PY_VALUE, line_number)
def bump(self, what, commit=False, simulate_branch=None): if self.problem: setupmeta.abort(self.problem) branch = simulate_branch or self.scm.get_branch() if branch not in self.strategy.branches: setupmeta.abort("Can't bump branch '%s', need one of %s" % (branch, self.strategy.branches)) gv = self.scm.get_version() if gv and gv.dirty: if commit: setupmeta.abort("You have pending changes, can't bump") print("Note: you have pending changes, commit (or stash) them before using --commit") next_version = self.strategy.bumped(what, gv) if not commit: print("Not committing bump, use --commit to commit") vdefs = self.meta.definitions.get("version") if vdefs: self.update_sources(next_version, commit, vdefs) self.scm.apply_tag(commit, next_version) if not self.strategy.hook: return hook = setupmeta.project_path(self.strategy.hook) if setupmeta.is_executable(hook): setupmeta.run_program(hook, self.meta.name, branch, next_version, fatal=True, dryrun=not commit, cwd=setupmeta.project_path())
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 find_venv(): venv = os.environ.get("VIRTUAL_ENV") if venv: return venv for folder in (".venv", "venv"): fpath = setupmeta.project_path(folder) if os.path.isdir(fpath): return fpath
def find_packages(name, subfolder=None): """ Find packages for 'name' (if any), 'subfolder' is like "src" """ result = set() if subfolder: path = project_path(subfolder, name) trace("looking for packages in '%s/%s'" % (subfolder, name)) else: path = project_path(name) trace("looking for packages in '%s'" % name) init_py = os.path.join(path, '__init__.py') if os.path.isfile(init_py): result.add(name) trace("found package '%s'" % name) for subpackage in setuptools.find_packages(where=path): result.add("%s.%s" % (name, subpackage)) trace("found subpackage '%s.%s'" % (name, subpackage)) return result
def run_setup_py(folder, *args): if folder == setupmeta.project_path() or not os.path.isabs(folder): return cleaned_output( setupmeta.run_program(sys.executable, os.path.join(folder, 'setup.py'), *args, capture='all', fatal=True)) return run_internal_setup_py(folder, *args)
def run_setup_py(folder, *args): if folder == setupmeta.project_path() or not os.path.isabs(folder): output = run_program(sys.executable, os.path.join(folder, "setup.py"), "-q", *args, capture="all") return cleaned_output(output) return run_internal_setup_py(folder, *args)
def clean(self, *relative_paths): for relative_path in relative_paths: path = setupmeta.project_path(relative_path) if not os.path.exists(path): continue if self.commit: print("Deleting %s..." % path) shutil.rmtree(path) else: print("Would delete %s" % path)
def run(self): if not self.setupmeta: return if platform.python_implementation() != "CPython": abort("twine command not supported on %s" % platform.python_implementation()) if not self.egg and not self.sdist and not self.wheel: abort("Specify at least one of: --egg, --dist or --wheel") # Env var SETUPMETA_TWINE primarily used to allow for flexible testing # Can be set to instruct setupmeta to use a particular twine executable as well # Use absolute path, of filename (for example: "my-twine-wrapper") twine = setupmeta.which(os.environ.get("SETUPMETA_TWINE", "twine")) if not twine: abort("twine is not installed") if not self.commit: print("Dryrun, use --commit to effectively build/publish") dist = setupmeta.project_path("dist") self.clean("dist", "build") try: if self.should_run(self.egg): self.run_command("build egg distribution", sys.executable, "setup.py", "bdist_egg") if self.should_run(self.sdist): self.run_command("build source distribution", sys.executable, "setup.py", "sdist") if self.should_run(self.wheel): self.run_command("build wheel distribution", sys.executable, "setup.py", "bdist_wheel", "--universal") if self.commit and not os.path.exists(dist): abort("No files found in %s" % dist) files = [ os.path.join(dist, name) for name in sorted(os.listdir(dist)) ] if self.commit else ["dist/*"] self.run_command("upload to PyPi via twine", twine, "upload", *files) finally: self.clean("build")
def resolved_paths(relative_paths): """ :param list(str) relative_paths: Ex: "README.rst", "README*" :return str|None: Contents of the first non-empty file found """ candidates = [] for path in relative_paths: # De-dupe and respect order (especially for globbed paths) if '*' in path: full_path = setupmeta.project_path(path) for expanded in glob.glob(full_path): relative_path = os.path.basename(expanded) if relative_path not in candidates: candidates.append(relative_path) continue if path not in candidates: candidates.append(path) return candidates
def update_sources(self, next_version, commit, push, vdefs): modified = [] for vdef in vdefs.sources: if ".py:" not in vdef.source: continue relative_path, _, target_line = vdef.source.partition(":") full_path = setupmeta.project_path(relative_path) target_line = setupmeta.to_int(target_line, default=0) lines = [] changed = 0 line_number = 0 revised = None with io.open(full_path, "rt") as fh: for line in fh.readlines(): line_number += 1 if line_number == target_line: revised = updated_line(line, next_version, vdef) if revised and revised != line: changed += 1 line = revised lines.append(line) if not changed: print("%s already has the right version" % vdef.source) else: modified.append(relative_path) if commit: with io.open(full_path, "wt") as fh: fh.writelines(lines) else: print("Would update %s with: %s" % (vdef.source, revised.strip())) if not modified: return self.scm.commit_files(commit, push, modified, next_version)
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') 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: warnings.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) rendered = self.strategy.rendered(gv) if cv and rendered and not rendered.startswith(cv): source = vdef.sources[0].source expected = rendered[:len(cv)] msg = "In %s version should be %s, not %s" % (source, expected, cv) warnings.warn(msg) self.meta.auto_fill('version', rendered, self.scm.name, override=True)
def load_contents(relative_path, limit=0): """ Return contents of file with 'relative_path' :param str relative_path: Relative path to file :param int limit: Max number of lines to load :return str|None: Contents, if any """ try: full_path = setupmeta.project_path(relative_path) with io.open(full_path, encoding='utf-8') as fh: lines = [] for line in fh: limit -= 1 if limit == 0: break lines.append(line) return ''.join(lines).strip() except IOError: pass
def __init__(self, upstream): """ :param upstream: Either a dict or Distribution """ Settings.__init__(self) self.attrs = 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(): 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, setupmeta.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) 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"), ) scm = scm or setupmeta.versioning.project_scm(MetaDefs.project_dir) self.versioning = setupmeta.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", "install_requires") self.auto_fill_requires("test", "tests_require") if self.requirements.links: self.auto_fill("dependency_links", self.requirements.links, self.requirements.links_source) self.auto_fill_classifiers() self.auto_fill_entry_points() self.auto_fill_license() self.auto_fill_long_description() self.sort_classifiers()
def test_twine(): temp = tempfile.mkdtemp() try: copy_to(setupmeta.project_path('examples', 'single', 'setup.py'), temp) copy_to(setupmeta.project_path('examples', 'single', 'single.py'), temp) if platform.python_implementation() != "CPython": run_setup_py(['twine'], "twine command not supported on ", folder=temp) return run_setup_py(['twine'], "Specify at least one of: --egg, --dist or --wheel", folder=temp) run_setup_py(['twine', '--egg=all'], "twine is not installed", folder=temp) copy_to(setupmeta.project_path('tests', 'mock-twine'), temp, basename='twine') run_setup_py( ['twine', '--egg=all'], """ Dryrun, use --commit to effectively build/publish Would build egg distribution: .*python.* setup.py bdist_egg Would upload to PyPi via twine """, folder=temp ) run_setup_py( ['twine', '--commit', '--egg=all', '--wheel=1.0'], """ python.* setup.py bdist_egg Uploading to PyPi via twine Running: <target>/twine upload <target>/dist/single-0.1.0-.+.egg Deleting <target>/build """, folder=temp ) run_setup_py( ['twine', '--egg=all'], """ Would delete .*/dist Would build egg distribution: .*python.* setup.py bdist_egg Would upload to PyPi via twine """, folder=temp ) run_setup_py( ['twine', '--commit', '--rebuild', '--egg=all', '--sdist=all', '--wheel=all'], """ Deleting <target>/dist python.* setup.py bdist_egg python.* setup.py sdist python.* setup.py bdist_wheel Uploading to PyPi via twine Running: <target>/twine upload <target>/dist Deleting <target>/build """, folder=temp ) run_setup_py( ['twine', '--commit', '--rebuild', '--egg=1.0'], """ Deleting <target>/dist No files found in <target>/dist """, folder=temp ) finally: shutil.rmtree(temp)
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): trace("looking for src packages in %s" % src_folder) packages = setuptools.find_packages(where=src_folder) if not packages and 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() if os.path.isdir(src_folder): trace("looking for direct packages in %s" % src_folder) with current_folder(src_folder): raw_packages = setuptools.find_packages() if raw_packages: # Keep only packages that start with the expected name # For any other use-case, user must explicitly list their packages packages = [ p for p in raw_packages if p.startswith(name) ] if packages != raw_packages: trace("all packages found: %s" % raw_packages) if not packages and 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_entry_points() self.auto_fill_license() self.auto_fill_long_description() self.auto_fill_include_package_data() return self
def test_twine(sample_project): with patch.dict(os.environ, {"SETUPMETA_TWINE": "/dev/null/no-twine"}): run_setup_py(["twine"], "Specify at least one of: --egg, --dist or --wheel") run_setup_py(["twine", "--egg=all"], "twine is not installed") mocked_twine = os.path.join(sample_project, "mocked-twine") shutil.copy2(setupmeta.project_path("tests", "mock-twine"), mocked_twine) with patch.dict(os.environ, {"SETUPMETA_TWINE": "mocked-twine"}): run_setup_py( ["twine", "--egg=all"], """ Dryrun, use --commit to effectively build/publish Would build egg distribution: .*python.* setup.py bdist_egg Would upload to PyPi via twine """, ) run_setup_py( ["twine", "--commit", "--egg=all", "--wheel=1.0"], """ python.* setup.py bdist_egg Uploading to PyPi via twine Running: <target>/mocked-twine upload <target>/dist/sample-0.1.0-.+.egg Deleting <target>/build """, ) run_setup_py( ["twine", "--egg=all"], """ Would delete .*/dist Would build egg distribution: .*python.* setup.py bdist_egg Would upload to PyPi via twine """, ) run_setup_py( [ "twine", "--commit", "--rebuild", "--egg=all", "--sdist=all", "--wheel=all" ], """ Deleting <target>/dist python.* setup.py bdist_egg python.* setup.py sdist python.* setup.py bdist_wheel Uploading to PyPi via twine Running: <target>/mocked-twine upload <target>/dist Deleting <target>/build """, ) run_setup_py( ["twine", "--commit", "--rebuild", "--egg=1.0"], """ Deleting <target>/dist No files found in <target>/dist """, )
def clean_direct(self): for target in self.direct: full_path = setupmeta.project_path(target) if os.path.exists(full_path): self.delete(full_path)
def __init__(self, upstream): """ :param upstream: Either a dict or Distribution """ Settings.__init__(self) self.attrs = 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(): self.add_definition(key, value, EXPLICIT) # 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) 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' direct_packages = find_packages(self.name) src_packages = find_packages(self.name, subfolder='src') packages = sorted(direct_packages | src_packages) if src_packages: self.auto_fill('package_dir', {'': 'src'}) if packages: self.auto_fill('packages', packages) if os.path.isfile(project_path('%s.py' % self.name)): py_modules = [self.name] 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'), ) scm = scm or setupmeta.versioning.project_scm(MetaDefs.project_dir) self.versioning = setupmeta.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.auto_fill_requires('install', 'install_requires') self.auto_fill_requires('test', 'tests_require') if self.requirements.links: self.auto_fill('dependency_links', self.requirements.links, self.requirements.links_source) self.auto_fill_classifiers() self.auto_fill_entry_points() self.auto_fill_license() self.auto_fill_long_description() self.sort_classifiers()
def test_twine(): with setupmeta.temp_resource() as temp: copy_to(setupmeta.project_path("examples", "single", "setup.py"), temp) copy_to(setupmeta.project_path("examples", "single", "single.py"), temp) run_setup_py(["twine"], "Specify at least one of: --egg, --dist or --wheel", folder=temp) run_setup_py(["twine", "--egg=all"], "twine is not installed", folder=temp) copy_to(setupmeta.project_path("tests", "mock-twine"), temp, basename="twine") run_setup_py( ["twine", "--egg=all"], """ Dryrun, use --commit to effectively build/publish Would build egg distribution: .*python.* setup.py bdist_egg Would upload to PyPi via twine """, folder=temp, ) run_setup_py( ["twine", "--commit", "--egg=all", "--wheel=1.0"], """ python.* setup.py bdist_egg Uploading to PyPi via twine Running: <target>/twine upload <target>/dist/single-0.1.0-.+.egg Deleting <target>/build """, folder=temp, ) run_setup_py( ["twine", "--egg=all"], """ Would delete .*/dist Would build egg distribution: .*python.* setup.py bdist_egg Would upload to PyPi via twine """, folder=temp, ) run_setup_py( [ "twine", "--commit", "--rebuild", "--egg=all", "--sdist=all", "--wheel=all" ], """ Deleting <target>/dist python.* setup.py bdist_egg python.* setup.py sdist python.* setup.py bdist_wheel Uploading to PyPi via twine Running: <target>/twine upload <target>/dist Deleting <target>/build """, folder=temp, ) run_setup_py( ["twine", "--commit", "--rebuild", "--egg=1.0"], """ Deleting <target>/dist No files found in <target>/dist """, folder=temp, )