def publish(self, repository_name, username, password): if repository_name: self._io.writeln( 'Publishing <info>{}</info> (<comment>{}</comment>) ' 'to <fg=cyan>{}</>'.format(self._package.pretty_name, self._package.pretty_version, repository_name)) else: self._io.writeln( 'Publishing <info>{}</info> (<comment>{}</comment>) ' 'to <fg=cyan>PyPI</>'.format(self._package.pretty_name, self._package.pretty_version)) if not repository_name: url = 'https://upload.pypi.org/legacy/' repository_name = 'pypi' else: # Retrieving config information config_file = Path(CONFIG_DIR) / 'config.toml' if not config_file.exists(): raise RuntimeError('Config file does not exist. ' 'Unable to get repository information') with config_file.open() as f: config = toml.loads(f.read()) if ('repositories' not in config or repository_name not in config['repositories']): raise RuntimeError( 'Repository {} is not defined'.format(repository_name)) url = config['repositories'][repository_name]['url'] if not (username and password): auth_file = Path(CONFIG_DIR) / 'auth.toml' if auth_file.exists(): with auth_file.open() as f: auth_config = toml.loads(f.read()) if 'http-basic' in auth_config and repository_name in auth_config[ 'http-basic']: config = auth_config['http-basic'][repository_name] username = config.get('username') password = config.get('password') # Requesting missing credentials if not username: username = self._io.ask('Username:'******'Password:') # TODO: handle certificates self._uploader.auth(username, password) return self._uploader.upload(url)
def test_executor_should_delete_incomplete_downloads(config, io, tmp_dir, mocker, pool, mock_file_downloads): fixture = Path(__file__).parent.parent.joinpath( "fixtures/distributions/demo-0.1.0-py2.py3-none-any.whl") destination_fixture = Path(tmp_dir) / "tomlkit-0.5.3-py2.py3-none-any.whl" shutil.copyfile(str(fixture), str(destination_fixture)) mocker.patch( "poetry.installation.executor.Executor._download_archive", side_effect=Exception("Download error"), ) mocker.patch( "poetry.installation.chef.Chef.get_cached_archive_for_link", side_effect=lambda link: link, ) mocker.patch( "poetry.installation.chef.Chef.get_cache_directory_for_link", return_value=Path(tmp_dir), ) config = Config() config.merge({"cache-dir": tmp_dir}) env = MockEnv(path=Path(tmp_dir)) executor = Executor(env, pool, config, io) with pytest.raises(Exception, match="Download error"): executor._download(Install(Package("tomlkit", "0.5.3"))) assert not destination_fixture.exists()
def test_remove_keeps_dir_if_not_deleteable(tmp_dir, manager, poetry, config, mocker): # Ensure we empty rather than delete folder if its is an active mount point. # See https://github.com/python-poetry/poetry/pull/2064 config.merge({"virtualenvs": {"path": str(tmp_dir)}}) venv_name = manager.generate_env_name("simple-project", str(poetry.file.parent)) venv_path = Path(tmp_dir) / "{}-py3.6".format(venv_name) venv_path.mkdir() folder1_path = venv_path / "folder1" folder1_path.mkdir() file1_path = folder1_path / "file1" file1_path.touch(exist_ok=False) file2_path = venv_path / "file2" file2_path.touch(exist_ok=False) mocker.patch( "poetry.utils._compat.subprocess.check_output", side_effect=check_output_wrapper(Version.parse("3.6.6")), ) original_rmtree = shutil.rmtree def err_on_rm_venv_only(path, *args, **kwargs): print(path) if path == str(venv_path): raise OSError(16, "Test error") # ERRNO 16: Device or resource busy else: original_rmtree(path) m = mocker.patch("shutil.rmtree", side_effect=err_on_rm_venv_only) venv = manager.remove("{}-py3.6".format(venv_name)) m.assert_any_call(str(venv_path)) assert venv_path == venv.path assert venv_path.exists() assert not folder1_path.exists() assert not file1_path.exists() assert not file2_path.exists() m.side_effect = original_rmtree # Avoid teardown using `err_on_rm_venv_only`
def update(self, release): from poetry.utils._compat import Path from poetry.utils.helpers import temporary_directory version = release.version self.line('Updating to <info>{}</info>'.format(version)) prefix = sys.prefix base_prefix = getattr(sys, 'base_prefix', None) real_prefix = getattr(sys, 'real_prefix', None) prefix_poetry = Path(prefix) / 'bin' / 'poetry' if prefix_poetry.exists(): pip = (prefix_poetry.parent / 'pip').resolve() elif (base_prefix and base_prefix != prefix and (Path(base_prefix) / 'bin' / 'poetry').exists()): pip = Path(base_prefix) / 'bin' / 'pip' elif real_prefix: pip = Path(real_prefix) / 'bin' / 'pip' else: pip = Path(prefix) / 'bin' / 'pip' if not pip.exists(): raise RuntimeError('Unable to determine poetry\'s path') with temporary_directory(prefix='poetry-update-') as temp_dir: temp_dir = Path(temp_dir) dist = temp_dir / 'dist' self.line(' - Getting dependencies') self.process(str(pip), 'install', '-U', 'poetry=={}'.format(release.version), '--target', str(dist)) self.line(' - Vendorizing dependencies') poetry_dir = dist / 'poetry' vendor_dir = poetry_dir / '_vendor' # Everything, except poetry itself, should # be put in the _vendor directory for file in dist.glob('*'): if file.name.startswith('poetry'): continue dest = vendor_dir / file.name if file.is_dir(): shutil.copytree(str(file), str(dest)) shutil.rmtree(str(file)) else: shutil.copy(str(file), str(dest)) os.unlink(str(file)) wheel_data = dist / 'poetry-{}.dist-info'.format(version) / 'WHEEL' with wheel_data.open() as f: wheel_data = Parser().parsestr(f.read()) tag = wheel_data['Tag'] # Repack everything and install self.line(' - Updating <info>poetry</info>') shutil.make_archive(str(temp_dir / 'poetry-{}-{}'.format(version, tag)), format='zip', root_dir=str(dist)) os.rename( str(temp_dir / 'poetry-{}-{}.zip'.format(version, tag)), str(temp_dir / 'poetry-{}-{}.whl'.format(version, tag)), ) self.process( str(pip), 'install', '--upgrade', '--no-deps', str(temp_dir / 'poetry-{}-{}.whl'.format(version, tag))) self.line('') self.line('<info>poetry</> (<comment>{}</>) ' 'successfully installed!'.format(version))
def update(self, release): from poetry.utils._compat import Path from poetry.utils.helpers import temporary_directory version = release.version self.line("Updating to <info>{}</info>".format(version)) prefix = sys.prefix base_prefix = getattr(sys, "base_prefix", None) real_prefix = getattr(sys, "real_prefix", None) prefix_poetry = Path(prefix) / "bin" / "poetry" if prefix_poetry.exists(): pip = (prefix_poetry.parent / "pip").resolve() elif (base_prefix and base_prefix != prefix and (Path(base_prefix) / "bin" / "poetry").exists()): pip = Path(base_prefix) / "bin" / "pip" elif real_prefix: pip = Path(real_prefix) / "bin" / "pip" else: pip = Path(prefix) / "bin" / "pip" if not pip.exists(): raise RuntimeError("Unable to determine poetry's path") with temporary_directory(prefix="poetry-update-") as temp_dir: temp_dir = Path(temp_dir) dist = temp_dir / "dist" self.line(" - Getting dependencies") self.process( str(pip), "install", "-U", "poetry=={}".format(release.version), "--target", str(dist), ) self.line(" - Vendorizing dependencies") poetry_dir = dist / "poetry" vendor_dir = poetry_dir / "_vendor" # Everything, except poetry itself, should # be put in the _vendor directory for file in dist.glob("*"): if file.name.startswith("poetry"): continue dest = vendor_dir / file.name if file.is_dir(): shutil.copytree(str(file), str(dest)) shutil.rmtree(str(file)) else: shutil.copy(str(file), str(dest)) os.unlink(str(file)) wheel_data = dist / "poetry-{}.dist-info".format(version) / "WHEEL" with wheel_data.open() as f: wheel_data = Parser().parsestr(f.read()) tag = wheel_data["Tag"] # Repack everything and install self.line(" - Updating <info>poetry</info>") shutil.make_archive( str(temp_dir / "poetry-{}-{}".format(version, tag)), format="zip", root_dir=str(dist), ) os.rename( str(temp_dir / "poetry-{}-{}.zip".format(version, tag)), str(temp_dir / "poetry-{}-{}.whl".format(version, tag)), ) self.process( str(pip), "install", "--upgrade", "--no-deps", str(temp_dir / "poetry-{}-{}.whl".format(version, tag)), ) self.line("") self.line("<info>poetry</> (<comment>{}</>) " "successfully installed!".format(version))
def test_self_update_should_install_all_necessary_elements( app, http, mocker, environ, tmp_dir ): os.environ["POETRY_HOME"] = tmp_dir command = app.find("self update") version = Version.parse(__version__).next_minor.text mocker.patch( "poetry.repositories.pypi_repository.PyPiRepository.find_packages", return_value=[Package("poetry", version)], ) mocker.patch.object(command, "_check_recommended_installation", return_value=None) mocker.patch.object( command, "_get_release_name", return_value="poetry-{}-darwin".format(version) ) mocker.patch("subprocess.check_output", return_value=b"Python 3.8.2") http.register_uri( "GET", command.BASE_URL + "/{}/poetry-{}-darwin.sha256sum".format(version, version), body=FIXTURES.joinpath("poetry-1.0.5-darwin.sha256sum").read_bytes(), ) http.register_uri( "GET", command.BASE_URL + "/{}/poetry-{}-darwin.tar.gz".format(version, version), body=FIXTURES.joinpath("poetry-1.0.5-darwin.tar.gz").read_bytes(), ) tester = CommandTester(command) tester.execute() bin_ = Path(tmp_dir).joinpath("bin") lib = Path(tmp_dir).joinpath("lib") assert bin_.exists() script = bin_.joinpath("poetry") assert script.exists() expected_script = """\ # -*- coding: utf-8 -*- import glob import sys import os lib = os.path.normpath(os.path.join(os.path.realpath(__file__), "../..", "lib")) vendors = os.path.join(lib, "poetry", "_vendor") current_vendors = os.path.join( vendors, "py{}".format(".".join(str(v) for v in sys.version_info[:2])) ) sys.path.insert(0, lib) sys.path.insert(0, current_vendors) if __name__ == "__main__": from poetry.console import main main() """ if not WINDOWS: expected_script = "#!/usr/bin/env python\n" + expected_script assert expected_script == script.read_text() if WINDOWS: bat = bin_.joinpath("poetry.bat") expected_bat = '@echo off\r\npython "{}" %*\r\n'.format( str(script).replace(os.environ.get("USERPROFILE", ""), "%USERPROFILE%") ) assert bat.exists() with bat.open(newline="") as f: assert expected_bat == f.read() assert lib.exists() assert lib.joinpath("poetry").exists()
def publish(self, repository_name, username, password): if repository_name: self._io.writeln( "Publishing <info>{}</info> (<comment>{}</comment>) " "to <fg=cyan>{}</>".format( self._package.pretty_name, self._package.pretty_version, repository_name, )) else: self._io.writeln( "Publishing <info>{}</info> (<comment>{}</comment>) " "to <fg=cyan>PyPI</>".format(self._package.pretty_name, self._package.pretty_version)) if not repository_name: url = "https://upload.pypi.org/legacy/" repository_name = "pypi" else: # Retrieving config information config_file = Path(CONFIG_DIR) / "config.toml" if not config_file.exists(): raise RuntimeError("Config file does not exist. " "Unable to get repository information") with config_file.open() as f: config = toml.loads(f.read()) if ("repositories" not in config or repository_name not in config["repositories"]): raise RuntimeError( "Repository {} is not defined".format(repository_name)) url = config["repositories"][repository_name]["url"] if not (username and password): auth_file = Path(CONFIG_DIR) / "auth.toml" if auth_file.exists(): with auth_file.open() as f: auth_config = toml.loads(f.read()) if ("http-basic" in auth_config and repository_name in auth_config["http-basic"]): config = auth_config["http-basic"][repository_name] username = config.get("username") password = config.get("password") # Requesting missing credentials if not username: username = self._io.ask("Username:"******"Password:") # TODO: handle certificates self._uploader.auth(username, password) return self._uploader.upload(url)
def create(cls, path=None): path = path or os.getcwd() pyproject_file = Path(path) if pyproject_file.name != "pyproject.toml": pyproject_file = pyproject_file / "pyproject.toml" if not pyproject_file.exists(): raise RuntimeError( "Jetty could not find a pyproject.toml file in {}".format( path)) local_config = TomlFile(pyproject_file.as_posix()).read() tool = local_config.setdefault('tool', {}) if 'jetty' not in tool and 'poetry' not in tool: raise RuntimeError("[tool.jetty] section not found in {}".format( pyproject_file.name)) local_config = merge(tool.get('jetty', {}), tool.get('poetry', {})) # Checking validity cls.check(local_config) # Load package name = local_config.get('name', pyproject_file.parent.name) version = local_config.get('version', '0') package = ProjectPackage(name, version, version) if 'dependencies' in local_config: for name, constraint in local_config['dependencies'].items(): if name.lower() == 'python': package.python_versions = constraint continue if isinstance(constraint, list): for _constraint in constraint: package.add_dependency(name, _constraint) continue package.add_dependency(name, constraint) if 'dev-dependencies' in local_config: for name, constraint in local_config['dev-dependencies'].items(): if isinstance(constraint, list): for _constraint in constraint: package.add_dependency(name, _constraint, category='dev') continue package.add_dependency(name, constraint, category='dev') extras = local_config.get("extras", {}) for extra_name, requirements in extras.items(): package.extras[extra_name] = [] # Checking for dependency for req in requirements: req = Dependency(req, "*") for dep in package.requires: if dep.name == req.name: dep.in_extras.append(extra_name) package.extras[extra_name].append(dep) break lock = pyproject_file.parent / "poetry.lock" locker = Locker(lock, local_config) return cls(pyproject_file, local_config, package, locker)