Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature/pre commit updates #102

Merged
merged 3 commits into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 16 additions & 25 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,38 +1,29 @@
exclude: ".all-contributorsrc|.tributors"
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
rev: v4.4.0
hooks:
- id: check-added-large-files
- id: check-case-conflict
- id: check-docstring-first
- id: end-of-file-fixer
- id: trailing-whitespace
- id: mixed-line-ending

- repo: local
- repo: https://github.com/pycqa/isort
rev: 5.12.0
hooks:
- id: black
name: black
language: python
types: [python]
entry: black

- id: isort
name: isort
args: [--filter-files]
language: python
types: [python]
entry: isort

- id: mypy
name: mypy
language: python
types: [python]
entry: mypy

- repo: https://github.com/psf/black
rev: 23.9.1
hooks:
- id: black
language_version: python3.11
- repo: https://github.com/pycqa/flake8
rev: 6.1.0
hooks:
- id: flake8
name: flake8
language: python
types: [python]
entry: flake8
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.5.1
hooks:
- id: mypy
additional_dependencies: ["types-requests"]
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and **Merged pull requests**. Critical items to know are:
The versions coincide with releases on pip. Only major versions will be released as tags on Github.

## [0.0.x](https://github.com/oras-project/oras-py/tree/main) (0.0.x)
- refactor tests using fixtures and rework pre-commit configuration (0.1.25)
- eliminate the additional subdirectory creation while pulling an image to a custom output directory (0.1.24)
- updating the exclude string in the pyproject.toml file to match the [data type black expects](https://black.readthedocs.io/en/stable/usage_and_configuration/the_basics.html#configuration-format)
- patch fix for pulling artifacts by digest (0.1.23)
Expand Down
2 changes: 1 addition & 1 deletion oras/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ def exit(self, msg: str, return_code: int = 1):
self.handler({"level": "error", "msg": msg})
sys.exit(return_code)

def progress(self, done: int = None, total: int = None):
def progress(self, done: int, total: int):
"""
Show piece of a progress bar

Expand Down
2 changes: 1 addition & 1 deletion oras/oci.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ def NewLayer(


def ManifestConfig(
path: str = None, media_type: str = None
path: Optional[str] = None, media_type: Optional[str] = None
) -> Tuple[Dict[str, object], str]:
"""
Write an empty config, if one is not provided
Expand Down
8 changes: 4 additions & 4 deletions oras/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -816,7 +816,7 @@ def pull(self, *args, **kwargs) -> List[str]:

@decorator.ensure_container
def get_manifest(
self, container: container_type, allowed_media_type: list = None
self, container: container_type, allowed_media_type: Optional[list] = None
) -> dict:
"""
Retrieve a manifest for a package.
Expand All @@ -842,9 +842,9 @@ def do_request(
self,
url: str,
method: str = "GET",
data: Union[dict, bytes] = None,
headers: dict = None,
json: dict = None,
data: Optional[Union[dict, bytes]] = None,
headers: Optional[dict] = None,
json: Optional[dict] = None,
stream: bool = False,
):
"""
Expand Down
58 changes: 58 additions & 0 deletions oras/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import os
from dataclasses import dataclass

import pytest


@dataclass
class TestCredentials:
with_auth: bool
user: str
password: str


@pytest.fixture
def registry():
host = os.environ.get("ORAS_HOST")
port = os.environ.get("ORAS_PORT")

if not host or not port:
pytest.skip(
"You must export ORAS_HOST and ORAS_PORT"
" for a running registry before running tests."
)

return f"{host}:{port}"


@pytest.fixture
def credentials(request):
with_auth = os.environ.get("ORAS_AUTH") == "true"
user = os.environ.get("ORAS_USER", "myuser")
pwd = os.environ.get("ORAS_PASS", "mypass")

if with_auth and not user or not pwd:
pytest.skip("To test auth you need to export ORAS_USER and ORAS_PASS")

marks = [m.name for m in request.node.iter_markers()]
if request.node.parent:
marks += [m.name for m in request.node.parent.iter_markers()]

if request.node.get_closest_marker("with_auth"):
if request.node.get_closest_marker("with_auth").args[0] != with_auth:
if with_auth:
pytest.skip("test requires un-authenticated access to registry")
else:
pytest.skip("test requires authenticated access to registry")

return TestCredentials(with_auth, user, pwd)


@pytest.fixture
def target(registry):
return f"{registry}/dinosaur/artifact:v1"


@pytest.fixture
def target_dir(registry):
return f"{registry}/dinosaur/directory:v1"
47 changes: 13 additions & 34 deletions oras/tests/test_oras.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,61 +4,40 @@

import os
import shutil
import sys

import pytest

import oras.client

here = os.path.abspath(os.path.dirname(__file__))

registry_host = os.environ.get("ORAS_HOST")
registry_port = os.environ.get("ORAS_PORT")
with_auth = os.environ.get("ORAS_AUTH") == "true"
oras_user = os.environ.get("ORAS_USER", "myuser")
oras_pass = os.environ.get("ORAS_PASS", "mypass")


def setup_module(module):
"""
Ensure the registry port and host is in the environment.
"""
if not registry_host or not registry_port:
sys.exit(
"You must export ORAS_HOST and ORAS_PORT for a running registry before running tests."
)
if with_auth and not oras_user or not oras_pass:
sys.exit("To test auth you need to export ORAS_USER and ORAS_PASS")


registry = f"{registry_host}:{registry_port}"
target = f"{registry}/dinosaur/artifact:v1"
target_dir = f"{registry}/dinosaur/directory:v1"


def test_basic_oras():
def test_basic_oras(registry):
"""
Basic tests for oras (without authentication)
"""
client = oras.client.OrasClient(hostname=registry, insecure=True)
assert "Python version" in client.version()


@pytest.mark.skipif(not with_auth, reason="basic auth is needed for login/logout")
def test_login_logout():
@pytest.mark.with_auth(True)
def test_login_logout(registry, credentials):
"""
Login and logout are all we can test with basic auth!
"""
client = oras.client.OrasClient(hostname=registry, insecure=True)
res = client.login(
hostname=registry, username=oras_user, password=oras_pass, insecure=True
hostname=registry,
username=credentials.user,
password=credentials.password,
insecure=True,
)
assert res["Status"] == "Login Succeeded"
client.logout(registry)


@pytest.mark.skipif(with_auth, reason="token auth is needed for push and pull")
def test_basic_push_pull(tmp_path):
@pytest.mark.with_auth(False)
def test_basic_push_pull(tmp_path, registry, credentials, target):
"""
Basic tests for oras (without authentication)
"""
Expand Down Expand Up @@ -88,8 +67,8 @@ def test_basic_push_pull(tmp_path):
assert res.status_code == 201


@pytest.mark.skipif(with_auth, reason="token auth is needed for push and pull")
def test_get_delete_tags(tmp_path):
@pytest.mark.with_auth(False)
def test_get_delete_tags(tmp_path, registry, credentials, target):
"""
Test creationg, getting, and deleting tags.
"""
Expand Down Expand Up @@ -139,8 +118,8 @@ def test_get_many_tags():
assert len(tags) == 10


@pytest.mark.skipif(with_auth, reason="token auth is needed for push and pull")
def test_directory_push_pull(tmp_path):
@pytest.mark.with_auth(False)
def test_directory_push_pull(tmp_path, registry, credentials, target_dir):
"""
Test push and pull for directory
"""
Expand Down
31 changes: 4 additions & 27 deletions oras/tests/test_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
__license__ = "Apache-2.0"

import os
import sys
from pathlib import Path

import pytest
Expand All @@ -15,35 +14,13 @@

here = os.path.abspath(os.path.dirname(__file__))

registry_host = os.environ.get("ORAS_HOST")
registry_port = os.environ.get("ORAS_PORT")
with_auth = os.environ.get("ORAS_AUTH") == "true"
oras_user = os.environ.get("ORAS_USER", "myuser")
oras_pass = os.environ.get("ORAS_PASS", "mypass")


def setup_module(module):
"""
Ensure the registry port and host is in the environment.
"""
if not registry_host or not registry_port:
sys.exit(
"You must export ORAS_HOST and ORAS_PORT for a running registry before running tests."
)
if with_auth and not oras_user or not oras_pass:
sys.exit("To test auth you need to export ORAS_USER and ORAS_PASS")


registry = f"{registry_host}:{registry_port}"
target = f"{registry}/dinosaur/artifact:v1"
target_dir = f"{registry}/dinosaur/directory:v1"


@pytest.mark.skipif(with_auth, reason="token auth is needed for push and pull")
def test_annotated_registry_push(tmp_path):
@pytest.mark.with_auth(False)
def test_annotated_registry_push(tmp_path, registry, credentials, target):
"""
Basic tests for oras push with annotations
"""

# Direct access to registry functions
remote = oras.provider.Registry(hostname=registry, insecure=True)
client = oras.client.OrasClient(hostname=registry, insecure=True)
Expand Down Expand Up @@ -84,7 +61,7 @@ def test_annotated_registry_push(tmp_path):
)


def test_parse_manifest():
def test_parse_manifest(registry):
"""
Test parse manifest function.

Expand Down
2 changes: 1 addition & 1 deletion oras/utils/fileio.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ def get_tmpdir(
return tmpdir


def recursive_find(base: str, pattern: str = None) -> Generator:
def recursive_find(base: str, pattern: Optional[str] = None) -> Generator:
"""
Find filenames that match a particular pattern, and yield them.

Expand Down
11 changes: 2 additions & 9 deletions oras/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
__copyright__ = "Copyright The ORAS Authors."
__license__ = "Apache-2.0"

__version__ = "0.1.24"
__version__ = "0.1.25"
AUTHOR = "Vanessa Sochat"
EMAIL = "[email protected]"
NAME = "oras"
Expand All @@ -19,14 +19,7 @@
("requests", {"min_version": None}),
)

TESTS_REQUIRES = (
("pytest", {"min_version": "4.6.2"}),
("mypy", {"min_version": None}),
("pyflakes", {"min_version": None}),
("black", {"min_version": None}),
("types-requests", {"min_version": None}),
("isort", {"min_version": None}),
)
TESTS_REQUIRES = (("pytest", {"min_version": "4.6.2"}),)

DOCKER_REQUIRES = (("docker", {"exact_version": "5.0.1"}),)

Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ skip = []

[tool.mypy]
mypy_path = ["oras", "examples"]

[tool.pytest.ini_options]
markers = ["with_auth: mark for tests requiring authenticated registry access (or not)"]