コード例 #1
0
def test_package_authors():
    package = Package("foo", "0.1.0")

    package.authors.append("Sébastien Eustace <*****@*****.**>")
    assert package.author_name == "Sébastien Eustace"
    assert package.author_email == "*****@*****.**"

    package.authors.insert(0, "John Doe")
    assert package.author_name == "John Doe"
    assert package.author_email is None
コード例 #2
0
def package_git():
    package = Package(
        "demo",
        "1.0.0",
        source_type="git",
        source_url="[email protected]:demo/demo.git",
        source_reference="master",
    )

    return package
コード例 #3
0
    def find_packages(self, dependency: Dependency) -> list[Package]:
        """
        Find packages on the remote server.
        """
        constraint, allow_prereleases = self._get_constraints_from_dependency(
            dependency
        )

        try:
            info = self.get_package_info(dependency.name)
        except PackageNotFound:
            self._log(
                f"No packages found for {dependency.name} {constraint!s}",
                level="debug",
            )
            return []

        packages = []
        ignored_pre_release_packages = []

        for version, release in info["releases"].items():
            if not release:
                # Bad release
                self._log(
                    f"No release information found for {dependency.name}-{version},"
                    " skipping",
                    level="debug",
                )
                continue

            try:
                package = Package(info["info"]["name"], version)
            except InvalidVersion:
                self._log(
                    f'Unable to parse version "{version}" for the'
                    f" {dependency.name} package, skipping",
                    level="debug",
                )
                continue

            if package.is_prerelease() and not allow_prereleases:
                if constraint.is_any():
                    # we need this when all versions of the package are pre-releases
                    ignored_pre_release_packages.append(package)
                continue

            if constraint.allows(package.version):
                packages.append(package)

        self._log(
            f"{len(packages)} packages found for {dependency.name} {constraint!s}",
            level="debug",
        )

        return packages or ignored_pre_release_packages
コード例 #4
0
ファイル: test_add.py プロジェクト: jottr/poetry
def test_adding_a_plugin_can_update_poetry_dependencies_if_needed(
        app, repo, tester, env, installed):
    poetry_package = Package("poetry", "1.2.0")
    poetry_package.add_dependency(
        Factory.create_dependency("tomlkit", "^0.7.0"))

    plugin_package = Package("poetry-plugin", "1.2.3")
    plugin_package.add_dependency(
        Factory.create_dependency("tomlkit", "^0.7.2"))

    installed.add_package(poetry_package)
    installed.add_package(Package("tomlkit", "0.7.1"))

    repo.add_package(plugin_package)
    repo.add_package(Package("tomlkit", "0.7.1"))
    repo.add_package(Package("tomlkit", "0.7.2"))

    tester.execute("poetry-plugin")

    expected = """\
Using version ^1.2.3 for poetry-plugin
Updating dependencies
Resolving dependencies...

Writing lock file

Package operations: 1 install, 1 update, 0 removals

  • Updating tomlkit (0.7.1 -> 0.7.2)
  • Installing poetry-plugin (1.2.3)
"""

    assert tester.io.fetch_output() == expected

    update_command = app.find("update")
    assert update_command.poetry.file.parent == env.path
    assert update_command.poetry.locker.lock.parent == env.path
    assert update_command.poetry.locker.lock.exists()

    content = update_command.poetry.file.read()["tool"]["poetry"]
    assert "poetry-plugin" in content["dependencies"]
    assert content["dependencies"]["poetry-plugin"] == "^1.2.3"
コード例 #5
0
ファイル: test_remove.py プロジェクト: python-poetry/poetry
def test_remove_does_not_live_empty_groups(
    tester: CommandTester,
    app: PoetryTestApplication,
    repo: TestRepository,
    command_tester_factory: CommandTesterFactory,
    installed: Repository,
):
    """
    Empty groups are automatically discarded after package removal.
    """
    installed.add_package(Package("foo", "2.0.0"))
    repo.add_package(Package("foo", "2.0.0"))
    repo.add_package(Package("baz", "1.0.0"))

    content = app.poetry.file.read()

    groups_content = tomlkit.parse("""\
[tool.poetry.group.bar.dependencies]
foo = "^2.0.0"
baz = "^1.0.0"

""")
    content["tool"]["poetry"]["dependencies"]["foo"] = "^2.0.0"
    content["tool"]["poetry"].value._insert_after(
        "dependencies", "group", groups_content["tool"]["poetry"]["group"])
    app.poetry.file.write(content)

    app.poetry.package.add_dependency(
        Factory.create_dependency("foo", "^2.0.0"))
    app.poetry.package.add_dependency(
        Factory.create_dependency("foo", "^2.0.0", groups=["bar"]))
    app.poetry.package.add_dependency(
        Factory.create_dependency("baz", "^1.0.0", groups=["bar"]))

    tester.execute("foo baz --group bar")

    content = app.poetry.file.read()["tool"]["poetry"]
    assert "foo" in content["dependencies"]
    assert "foo" not in content["group"]["bar"]["dependencies"]
    assert "baz" not in content["group"]["bar"]["dependencies"]
    assert "[tool.poetry.group.bar]" not in content.as_string()
    assert "[tool.poetry.group]" not in content.as_string()
コード例 #6
0
def test_requirement_source_type_url():
    installer = PipInstaller(NullEnv(), NullIO(), Pool())

    foo = Package("foo", "0.0.0")
    foo.source_type = "url"
    foo.source_url = "https://somehwere.com/releases/foo-1.0.0.tar.gz"

    result = installer.requirement(foo, formatted=True)
    expected = "{}#egg={}".format(foo.source_url, foo.name)

    assert expected == result
コード例 #7
0
def add_to_repo(repository, name, version, deps=None, python=None):
    package = Package(name, version)
    if python:
        package.python_versions = python

    if deps:
        for dep_name, dep_constraint in deps.items():
            package.add_dependency(
                Factory.create_dependency(dep_name, dep_constraint))

    repository.add_package(package)
コード例 #8
0
def test_package_authors_invalid():
    package = Package("foo", "0.1.0")

    package.authors.insert(0, "<John Doe")
    with pytest.raises(ValueError) as e:
        package.author_name

    assert (
        str(e.value) ==
        "Invalid author string. Must be in the format: John Smith <*****@*****.**>"
    )
コード例 #9
0
def test_package_add_dependency_vcs_groups(groups: list[str],
                                           f: Factory) -> None:
    package = Package("foo", "0.1.0")

    dependency = package.add_dependency(
        f.create_dependency(
            "poetry",
            {"git": "https://github.com/python-poetry/poetry.git"},
            groups=groups,
        ))
    assert dependency.groups == frozenset(groups)
コード例 #10
0
ファイル: test_executor.py プロジェクト: xantocoder/poetry-1
def test_execute_executes_a_batch_of_operations(config, pool, io, tmp_dir,
                                                mock_file_downloads):
    config = Config()
    config.merge({"cache-dir": tmp_dir})

    env = MockEnv(path=Path(tmp_dir))
    executor = Executor(env, pool, config, io)

    file_package = Package("demo", "0.1.0")
    file_package.source_type = "file"
    file_package.source_url = str(
        Path(__file__).parent.parent.joinpath(
            "fixtures/distributions/demo-0.1.0-py2.py3-none-any.whl").resolve(
            ))

    directory_package = Package("simple-project", "1.2.3")
    directory_package.source_type = "directory"
    directory_package.source_url = str(
        Path(__file__).parent.parent.joinpath(
            "fixtures/simple_project").resolve())

    git_package = Package("demo", "0.1.0")
    git_package.source_type = "git"
    git_package.source_reference = "master"
    git_package.source_url = "https://github.com/demo/demo.git"

    assert 0 == executor.execute([
        Install(Package("pytest", "3.5.2")),
        Uninstall(Package("attrs", "17.4.0")),
        Update(Package("requests", "2.18.3"), Package("requests", "2.18.4")),
        Uninstall(Package("clikit", "0.2.3")).skip("Not currently installed"),
        Install(file_package),
        Install(directory_package),
        Install(git_package),
    ])

    expected = """
Package operations: 4 installs, 1 update, 1 removal

  • Installing pytest (3.5.2)
  • Removing attrs (17.4.0)
  • Updating requests (2.18.3 -> 2.18.4)
  • Installing demo (0.1.0 {})
  • Installing simple-project (1.2.3 {})
  • Installing demo (0.1.0 master)
""".format(file_package.source_url, directory_package.source_url)

    expected = set(expected.splitlines())
    output = set(io.fetch_output().splitlines())
    assert expected == output
    assert 5 == len(env.executed)
コード例 #11
0
ファイル: test_chooser.py プロジェクト: yosmoc/poetry
def test_chooser_chooses_system_specific_wheel_link_if_available(
    mock_pypi, mock_legacy, source_type, pool
):
    env = MockEnv(
        supported_tags=[Tag("cp37", "cp37m", "win32"), Tag("py3", "none", "any")]
    )
    chooser = Chooser(pool, env)

    package = Package("pyyaml", "3.13.0")
    if source_type == "legacy":
        package = Package(
            package.name,
            package.version.text,
            source_type="legacy",
            source_reference="foo",
            source_url="https://foo.bar/simple/",
        )

    link = chooser.choose_for(package)

    assert "PyYAML-3.13-cp37-cp37m-win32.whl" == link.filename
コード例 #12
0
ファイル: test_package.py プロジェクト: jaharkes/poetry-core
def package_with_groups():
    package = Package("foo", "1.2.3")

    optional_group = DependencyGroup("optional", optional=True)
    optional_group.add_dependency(Factory.create_dependency("bam", "^3.0.0"))

    package.add_dependency(Factory.create_dependency("bar", "^1.0.0"))
    package.add_dependency(Factory.create_dependency("baz", "^1.1.0"))
    package.add_dependency(Factory.create_dependency("bim", "^2.0.0", groups=["dev"]))
    package.add_dependency_group(optional_group)

    return package
コード例 #13
0
def test_add_with_constraint(
    tester: CommandTester,
    repo: TestRepository,
):
    repo.add_package(Package("poetry-plugin", "0.1.0"))
    repo.add_package(Package("poetry-plugin", "0.2.0"))

    tester.execute("poetry-plugin@^0.2.0")

    expected = """
Updating dependencies
Resolving dependencies...

Writing lock file

Package operations: 1 install, 0 updates, 0 removals

  • Installing poetry-plugin (0.2.0)
"""

    assert_plugin_add_result(tester, expected, "^0.2.0")
コード例 #14
0
    def find_packages(self, dependency: Dependency) -> list[Package]:
        packages = []
        constraint, allow_prereleases = self._get_constraints_from_dependency(
            dependency)

        key = dependency.name
        if not constraint.is_any():
            key = f"{key}:{constraint!s}"

        ignored_pre_release_versions = []

        if self._cache.store("matches").has(key):
            versions = self._cache.store("matches").get(key)
        else:
            page = self._get_page(f"/{dependency.name.replace('.', '-')}/")
            if page is None:
                return []

            versions = []
            for version in page.versions(dependency.name):
                if version.is_unstable() and not allow_prereleases:
                    if constraint.is_any():
                        # we need this when all versions of the package are pre-releases
                        ignored_pre_release_versions.append(version)
                    continue

                if constraint.allows(version):
                    versions.append(version)

            self._cache.store("matches").put(key, versions, 5)

        for package_versions in (versions, ignored_pre_release_versions):
            for version in package_versions:
                package = Package(
                    dependency.name,
                    version,
                    source_type="legacy",
                    source_reference=self.name,
                    source_url=self._url,
                )

                packages.append(package)

            self._log(
                f"{len(packages)} packages found for {dependency.name} {constraint!s}",
                level="debug",
            )

            if packages or not constraint.is_any():
                # we have matching packages, or constraint is not (*)
                break

        return packages
コード例 #15
0
def test_package_resolved_reference_is_relevant_for_equality_only_if_present_for_both_packages(
):
    a1 = Package(
        "a",
        "0.1.0",
        source_type="git",
        source_url="https://foo.bar",
        source_reference="master",
        source_resolved_reference="c01b317af582501c5ba07b23d5bef3fbada2d4ef",
    )
    a2 = Package(
        a1.name,
        a1.version,
        source_type="git",
        source_url="https://foo.bar",
        source_reference="master",
        source_resolved_reference="a444731cd243cb5cd04e4d5fb81f86e1fecf8a00",
    )
    a3 = Package(
        a1.name,
        a1.version,
        source_type="git",
        source_url="https://foo.bar",
        source_reference="master",
        source_resolved_reference="c01b317af582501c5ba07b23d5bef3fbada2d4ef",
    )
    a4 = Package(
        a1.name,
        a1.version,
        source_type="git",
        source_url="https://foo.bar",
        source_reference="master",
    )

    assert a1 == a1
    assert a1 == a3
    assert a1 != a2
    assert a2 != a3
    assert a1 == a4
    assert a2 == a4
コード例 #16
0
ファイル: test_add.py プロジェクト: jottr/poetry
def test_add_existing_plugin_warns_about_no_operation(app, repo, tester, env,
                                                      installed):
    env.path.joinpath("pyproject.toml").write_text(
        """\
[tool.poetry]
name = "poetry"
version = "1.2.0"
description = "Python dependency management and packaging made easy."
authors = [
    "Sébastien Eustace <*****@*****.**>"
]

[tool.poetry.dependencies]
python = "^3.6"
poetry-plugin = "^1.2.3"
""",
        encoding="utf-8",
    )

    installed.add_package(Package("poetry-plugin", "1.2.3"))

    repo.add_package(Package("poetry-plugin", "1.2.3"))

    tester.execute("poetry-plugin")

    expected = """\
The following plugins are already present in the pyproject.toml file and will be skipped:

  • poetry-plugin

If you want to update it to the latest compatible version, you can use `poetry plugin update package`.
If you prefer to upgrade it to the latest available version, you can use `poetry plugin add package@latest`.

"""

    assert tester.io.fetch_output() == expected

    update_command = app.find("update")
    # The update command should not have been called
    assert update_command.poetry.file.parent != env.path
コード例 #17
0
def test_it_should_calculate_operations_in_correct_order():
    transaction = Transaction(
        [Package("a", "1.0.0"), Package("b", "2.0.0"), Package("c", "3.0.0")],
        [
            (Package("a", "1.0.0"), 1),
            (Package("b", "2.1.0"), 2),
            (Package("d", "4.0.0"), 0),
        ],
    )

    check_operations(
        transaction.calculate_operations(),
        [
            {"job": "install", "package": Package("b", "2.1.0")},
            {"job": "install", "package": Package("a", "1.0.0")},
            {"job": "install", "package": Package("d", "4.0.0")},
        ],
    )
コード例 #18
0
ファイル: test_remove.py プロジェクト: stjordanis/poetry
def test_remove_command_should_not_write_changes_upon_installer_errors(
        tester, app, repo, command_tester_factory, mocker):
    repo.add_package(Package("foo", "2.0.0"))

    command_tester_factory("add").execute("foo")

    mocker.patch("poetry.installation.installer.Installer.run", return_value=1)

    original_content = app.poetry.file.read().as_string()

    tester.execute("foo")

    assert app.poetry.file.read().as_string() == original_content
コード例 #19
0
ファイル: test_add.py プロジェクト: yannliepallotools/poetry
def test_add_existing_plugin_updates_if_requested(app, repo, tester, env,
                                                  installed, mocker):
    env.path.joinpath("pyproject.toml").write_text(
        """\
[tool.poetry]
name = "poetry"
version = "1.2.0"
description = "Python dependency management and packaging made easy."
authors = [
    "Sébastien Eustace <*****@*****.**>"
]

[tool.poetry.dependencies]
python = "^3.6"
poetry-plugin = "^1.2.3"
""",
        encoding="utf-8",
    )

    installed.add_package(Package("poetry-plugin", "1.2.3"))

    repo.add_package(Package("poetry-plugin", "1.2.3"))
    repo.add_package(Package("poetry-plugin", "2.3.4"))

    tester.execute("poetry-plugin@latest")

    expected = """\
Using version ^2.3.4 for poetry-plugin
Updating dependencies
Resolving dependencies...

Writing lock file

Package operations: 0 installs, 1 update, 0 removals

  • Updating poetry-plugin (1.2.3 -> 2.3.4)
"""

    assert_plugin_add_result(tester, app, env, expected, "^2.3.4")
コード例 #20
0
def test_chooser_chooses_sdist_if_no_compatible_wheel_link_is_available(
    env,
    mock_pypi,
    mock_legacy,
    source_type,
    pool,
):
    chooser = Chooser(pool, env)

    package = Package("pyyaml", "3.13.0")
    if source_type == "legacy":
        package = Package(
            package.name,
            package.version.text,
            source_type="legacy",
            source_reference="foo",
            source_url="https://foo.bar/simple/",
        )

    link = chooser.choose_for(package)

    assert "PyYAML-3.13.tar.gz" == link.filename
コード例 #21
0
def test_chooser_chooses_universal_wheel_link_if_available(
        env, mock_pypi, mock_legacy, source_type, pool):
    chooser = Chooser(pool, env)

    package = Package("pytest", "3.5.0")
    if source_type == "legacy":
        package.source_type = "legacy"
        package.source_reference = "foo"
        package.source_url = "https://foo.bar/simple/"

    link = chooser.choose_for(package)

    assert "pytest-3.5.0-py2.py3-none-any.whl" == link.filename
コード例 #22
0
ファイル: test_executor.py プロジェクト: bradsbrown/poetry
def test_executor_should_write_pep610_url_references_for_directories(
    tmp_venv, pool, config, io
):
    url = Path(__file__).parent.parent.joinpath("fixtures/simple_project").resolve()
    package = Package(
        "simple-project", "1.2.3", source_type="directory", source_url=url.as_posix()
    )

    executor = Executor(tmp_venv, pool, config, io)
    executor.execute([Install(package)])
    verify_installed_distribution(
        tmp_venv, package, {"dir_info": {}, "url": url.as_uri()}
    )
コード例 #23
0
    def create_package_from_pep610(cls, distribution: metadata.Distribution) -> Package:
        path = Path(str(distribution._path))  # type: ignore[attr-defined]
        source_type = None
        source_url = None
        source_reference = None
        source_resolved_reference = None
        develop = False

        url_reference = json.loads(
            path.joinpath("direct_url.json").read_text(encoding="utf-8")
        )
        if "archive_info" in url_reference:
            # File or URL distribution
            if url_reference["url"].startswith("file:"):
                # File distribution
                source_type = "file"
                source_url = url_to_path(url_reference["url"]).as_posix()
            else:
                # URL distribution
                source_type = "url"
                source_url = url_reference["url"]
        elif "dir_info" in url_reference:
            # Directory distribution
            source_type = "directory"
            source_url = url_to_path(url_reference["url"]).as_posix()
            develop = url_reference["dir_info"].get("editable", False)
        elif "vcs_info" in url_reference:
            # VCS distribution
            source_type = url_reference["vcs_info"]["vcs"]
            source_url = url_reference["url"]
            source_resolved_reference = url_reference["vcs_info"]["commit_id"]
            source_reference = url_reference["vcs_info"].get(
                "requested_revision", source_resolved_reference
            )

        package = Package(
            distribution.metadata["name"],
            distribution.metadata["version"],
            source_type=source_type,
            source_url=source_url,
            source_reference=source_reference,
            source_resolved_reference=source_resolved_reference,
            develop=develop,
        )

        package.description = distribution.metadata.get(  # type: ignore[attr-defined]
            "summary",
            "",
        )

        return package
コード例 #24
0
ファイル: test_add.py プロジェクト: tony/poetry
def test_adding_a_plugin_can_update_poetry_dependencies_if_needed(
    app: "PoetryTestApplication",
    repo: "TestRepository",
    tester: "CommandTester",
    env: "MockEnv",
    installed: "Repository",
):
    poetry_package = Package("poetry", "1.2.0")
    poetry_package.add_dependency(
        Factory.create_dependency("tomlkit", "^0.7.0"))

    plugin_package = Package("poetry-plugin", "1.2.3")
    plugin_package.add_dependency(
        Factory.create_dependency("tomlkit", "^0.7.2"))

    installed.add_package(poetry_package)
    installed.add_package(Package("tomlkit", "0.7.1"))

    repo.add_package(plugin_package)
    repo.add_package(Package("tomlkit", "0.7.1"))
    repo.add_package(Package("tomlkit", "0.7.2"))

    tester.execute("poetry-plugin")

    expected = """\
Using version ^1.2.3 for poetry-plugin
Updating dependencies
Resolving dependencies...

Writing lock file

Package operations: 1 install, 1 update, 0 removals

  • Updating tomlkit (0.7.1 -> 0.7.2)
  • Installing poetry-plugin (1.2.3)
"""

    assert_plugin_add_result(tester, app, env, expected, "^1.2.3")
コード例 #25
0
def test_self_update_can_update_from_recommended_installation(
    tester: CommandTester,
    repo: TestRepository,
    installed: TestRepository,
):
    new_version = Version.parse(__version__).next_minor().text

    old_poetry = Package("poetry", __version__)
    old_poetry.add_dependency(Factory.create_dependency("cleo", "^0.8.2"))

    new_poetry = Package("poetry", new_version)
    new_poetry.add_dependency(Factory.create_dependency("cleo", "^1.0.0"))

    installed.add_package(old_poetry)
    installed.add_package(Package("cleo", "0.8.2"))

    repo.add_package(new_poetry)
    repo.add_package(Package("cleo", "1.0.0"))

    tester.execute()

    expected_output = f"""\
Updating Poetry version ...

Using version ^{new_version} for poetry

Updating dependencies
Resolving dependencies...

Writing lock file

Package operations: 0 installs, 2 updates, 0 removals

  • Updating cleo (0.8.2 -> 1.0.0)
  • Updating poetry ({__version__} -> {new_version})
"""

    assert tester.io.fetch_output() == expected_output
コード例 #26
0
def test_add_existing_plugin_warns_about_no_operation(
    tester: CommandTester,
    repo: TestRepository,
    installed: TestRepository,
):
    SelfCommand.get_default_system_pyproject_file().write_text(
        f"""\
[tool.poetry]
name = "poetry-instance"
version = "1.2.0"
description = "Python dependency management and packaging made easy."
authors = []

[tool.poetry.dependencies]
python = "^3.6"

[tool.poetry.group.{SelfCommand.ADDITIONAL_PACKAGE_GROUP}.dependencies]
poetry-plugin = "^1.2.3"
""",
        encoding="utf-8",
    )

    installed.add_package(Package("poetry-plugin", "1.2.3"))

    repo.add_package(Package("poetry-plugin", "1.2.3"))

    tester.execute("poetry-plugin")

    expected = f"""\
The following packages are already present in the pyproject.toml and will be\
 skipped:

  • poetry-plugin
{tester.command._hint_update_packages}
Nothing to add.
"""

    assert tester.io.fetch_output() == expected
コード例 #27
0
def test_requirement_source_type_url():
    installer = PipInstaller(NullEnv(), NullIO(), Pool())

    foo = Package(
        "foo",
        "0.0.0",
        source_type="url",
        source_url="https://somewhere.com/releases/foo-1.0.0.tar.gz",
    )

    result = installer.requirement(foo, formatted=True)
    expected = f"{foo.source_url}#egg={foo.name}"

    assert result == expected
コード例 #28
0
ファイル: test_pip_installer.py プロジェクト: yosmoc/poetry
def test_install_with_non_pypi_default_repository(pool, installer):
    default = LegacyRepository("default", "https://default.com")
    another = LegacyRepository("another", "https://another.com")

    pool.add_repository(default, default=True)
    pool.add_repository(another)

    foo = Package(
        "foo",
        "0.0.0",
        source_type="legacy",
        source_reference=default.name,
        source_url=default.url,
    )
    bar = Package(
        "bar",
        "0.1.0",
        source_type="legacy",
        source_reference=another.name,
        source_url=another.url,
    )

    installer.install(foo)
    installer.install(bar)
コード例 #29
0
def test_executor_should_write_pep610_url_references_for_files(
        tmp_venv, pool, config, io):
    url = (Path(__file__).parent.parent.joinpath(
        "fixtures/distributions/demo-0.1.0-py2.py3-none-any.whl").resolve())
    package = Package("demo",
                      "0.1.0",
                      source_type="file",
                      source_url=url.as_posix())

    executor = Executor(tmp_venv, pool, config, io)
    executor.execute([Install(package)])
    verify_installed_distribution(tmp_venv, package, {
        "archive_info": {},
        "url": url.as_uri()
    })
コード例 #30
0
def test_throw_on_invalid_package():
    invalid = next(
        filter(
            lambda e: str(e._path).endswith("invalid-0.0.1.dist-info"),
            sorted(
                metadata.distributions(path=[str(SITE_PURELIB)]),
                key=lambda d: str(d._path),
            ),
        )
    )
    name = invalid.metadata["name"]
    version = invalid.metadata["version"]
    with pytest.raises(TypeError) as error:
        Package(name, version, version)
    assert str(error.value) == "expected string or bytes-like object"