Skip to content
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
10 changes: 10 additions & 0 deletions .github/dependabot.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Set update schedule for GitHub Actions

version: 2
updates:

- package-ecosystem: "github-actions"
directory: "/"
schedule:
# Check for updates to GitHub Actions every week
interval: "weekly"
31 changes: 31 additions & 0 deletions .github/workflows/precommit.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: "Run pre-commit checks"

on:
push:
pull_request:

jobs:
run-linters:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Configure caching
uses: actions/cache@v4
with:
path: ~/.cache/pre-commit
key: precommit-${{ runner.os }}-${{ hashFiles('.pre-commit-config.yaml') }}

- name: Install pre-commit
run: |
pip install pre-commit

- name: Run linters
run: |
pre-commit run --all-files
4 changes: 1 addition & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: python-esileapclient
name: Run unit tests

on: [push, pull_request]

Expand All @@ -20,7 +20,5 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install tox
- name: Lint
run: tox -epep8
- name: Unit Tests
run: tox -epy3
27 changes: 27 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: check-merge-conflict
- id: end-of-file-fixer
- id: check-added-large-files
- id: check-case-conflict
- id: check-json
- id: check-symlinks
- id: detect-private-key
- id: check-executables-have-shebangs

- repo: https://github.com/adrienverge/yamllint.git
rev: v1.37.0
hooks:
- id: yamllint
files: \.(yaml|yml)$
types: [file, yaml]
entry: yamllint --strict

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.2
hooks:
- id: ruff
- id: ruff-format
10 changes: 10 additions & 0 deletions .yamllint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
extends: default
rules:
line-length: disable
document-start: disable
indentation:
indent-sequences: whatever
hyphens:
max-spaces-after: 4
truthy:
check-keys: false
27 changes: 15 additions & 12 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,27 @@


def pytest_addoption(parser):
parser.addoption('--run-slow',
action='store_true',
default=False,
help='run tests marked as slow')
parser.addoption(
"--run-slow",
action="store_true",
default=False,
help="run tests marked as slow",
)


def pytest_configure(config):
slow_info = 'slow: mark test as slow to run'
neg_info = 'negative: marks tests that test invalid input'
config.addinivalue_line('markers', slow_info)
config.addinivalue_line('markers', neg_info)
slow_info = "slow: mark test as slow to run"
neg_info = "negative: marks tests that test invalid input"
config.addinivalue_line("markers", slow_info)
config.addinivalue_line("markers", neg_info)


def pytest_collection_modifyitems(config, items):
if config.getoption('--run-slow'):
if config.getoption("--run-slow"):
return
skipped = pytest.mark.skip(reason='slow tests are skipped by default; '
'to run, call pytest with --run-slow.')
skipped = pytest.mark.skip(
reason="slow tests are skipped by default; to run, call pytest with --run-slow."
)
for item in items:
if 'slow' in item.keywords:
if "slow" in item.keywords:
item.add_marker(skipped)
3 changes: 1 addition & 2 deletions esileapclient/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
Expand All @@ -14,4 +13,4 @@
import pbr.version


__version__ = pbr.version.VersionInfo('python-esileapclient').version_string()
__version__ = pbr.version.VersionInfo("python-esileapclient").version_string()
98 changes: 53 additions & 45 deletions esileapclient/common/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,12 @@ class Manager(object):
@property
@abc.abstractmethod
def resource_class(self):
"""The resource class
"""
"""The resource class"""

@property
@abc.abstractmethod
def _resource_name(self):
"""The resource name.
"""
"""The resource name."""

def __init__(self, api):
self.api = api
Expand All @@ -50,17 +48,20 @@ def _path(self, resource_id=None):
path.
"""

return ('/v1/%s/%s' % (self._resource_name, resource_id)
if resource_id else '/v1/%s' % self._resource_name)
return (
"/v1/%s/%s" % (self._resource_name, resource_id)
if resource_id
else "/v1/%s" % self._resource_name
)

@staticmethod
def _url_variables(variables):
"""Returns a url with variables set"""

url_variables = '?'
url_variables = "?"
for k, v in variables.items():
if v is not None:
url_variables += k + '=' + v + '&'
url_variables += k + "=" + v + "&"
return url_variables[:-1]

def _create(self, os_esileap_api_version=None, **kwargs):
Expand All @@ -71,30 +72,32 @@ def _create(self, os_esileap_api_version=None, **kwargs):

new = {}
invalid = []
for (key, value) in kwargs.items():
for key, value in kwargs.items():
if key in self.resource_class._creation_attributes:
new[key] = value
else:
invalid.append(key)
if invalid:
raise Exception('The attribute(s) "%(attrs)s" '
'are invalid; they are not '
'needed to create %(resource)s.' %
{'resource': self._resource_name,
'attrs': '","'.join(invalid)})
raise Exception(
'The attribute(s) "%(attrs)s" '
"are invalid; they are not "
"needed to create %(resource)s."
% {"resource": self._resource_name, "attrs": '","'.join(invalid)}
)

headers = {}
if os_esileap_api_version is not None:
headers['headers'] = {'X-OpenStack-ESI-Leap-API-Version':
os_esileap_api_version}
headers["headers"] = {
"X-OpenStack-ESI-Leap-API-Version": os_esileap_api_version
}

url = self._path()
resp, body = self.api.json_request('POST', url, body=new, **headers)
resp, body = self.api.json_request("POST", url, body=new, **headers)

if resp.status_code == 201:
return self.resource_class(self, body)
else:
raise exceptions.CommandError(json.loads(resp.text)['faultstring'])
raise exceptions.CommandError(json.loads(resp.text)["faultstring"])

def _update(self, resource_id, os_esileap_api_version=None, **kwargs):
"""Update a resource based on a kwargs dictionary of attributes.
Expand All @@ -104,30 +107,32 @@ def _update(self, resource_id, os_esileap_api_version=None, **kwargs):

new = {}
invalid = []
for (key, value) in kwargs.items():
for key, value in kwargs.items():
if key in self.resource_class._update_attributes:
new[key] = value
else:
invalid.append(key)
if invalid:
raise Exception('The attribute(s) "%(attrs)s" '
'are invalid; they are not '
'needed to update %(resource)s.' %
{'resource': self._resource_name,
'attrs': '","'.join(invalid)})
raise Exception(
'The attribute(s) "%(attrs)s" '
"are invalid; they are not "
"needed to update %(resource)s."
% {"resource": self._resource_name, "attrs": '","'.join(invalid)}
)

headers = {}
if os_esileap_api_version is not None:
headers['headers'] = {'X-OpenStack-ESI-Leap-API-Version':
os_esileap_api_version}
headers["headers"] = {
"X-OpenStack-ESI-Leap-API-Version": os_esileap_api_version
}

url = self._path(resource_id)
resp, body = self.api.json_request('PATCH', url, body=new, **headers)
resp, body = self.api.json_request("PATCH", url, body=new, **headers)

if resp.status_code == 200:
return self.resource_class(self, body)
else:
raise exceptions.CommandError(json.loads(resp.text)['faultstring'])
raise exceptions.CommandError(json.loads(resp.text)["faultstring"])

def _list(self, url, obj_class=None, os_esileap_api_version=None):
if obj_class is None:
Expand All @@ -136,17 +141,18 @@ def _list(self, url, obj_class=None, os_esileap_api_version=None):
kwargs = {}

if os_esileap_api_version is not None:
kwargs['headers'] = {'X-OpenStack-ESI-Leap-API-Version':
os_esileap_api_version}
kwargs["headers"] = {
"X-OpenStack-ESI-Leap-API-Version": os_esileap_api_version
}

resp, body = self.api.json_request('GET', url, **kwargs)
resp, body = self.api.json_request("GET", url, **kwargs)

if resp.status_code == 200:
body = body[self._resource_name]

return [obj_class(self, res) for res in body if res]
else:
raise exceptions.CommandError(json.loads(resp.text)['faultstring'])
raise exceptions.CommandError(json.loads(resp.text)["faultstring"])

def _get(self, resource_id, obj_class=None, os_esileap_api_version=None):
"""Retrieve a resource.
Expand All @@ -162,16 +168,17 @@ def _get(self, resource_id, obj_class=None, os_esileap_api_version=None):
kwargs = {}

if os_esileap_api_version is not None:
kwargs['headers'] = {'X-OpenStack-ESI-Leap-API-Version':
os_esileap_api_version}
kwargs["headers"] = {
"X-OpenStack-ESI-Leap-API-Version": os_esileap_api_version
}

resp, body = self.api.json_request('GET', url, **kwargs)
resp, body = self.api.json_request("GET", url, **kwargs)

if resp.status_code == 200:
return obj_class(self, body)

else:
raise exceptions.CommandError(json.loads(resp.text)['faultstring'])
raise exceptions.CommandError(json.loads(resp.text)["faultstring"])

def _delete(self, resource_id, os_esileap_api_version=None):
"""Delete a resource.
Expand All @@ -184,13 +191,14 @@ def _delete(self, resource_id, os_esileap_api_version=None):
kwargs = {}

if os_esileap_api_version is not None:
kwargs['headers'] = {'X-OpenStack-ESI-Leap-API-Version':
os_esileap_api_version}
kwargs["headers"] = {
"X-OpenStack-ESI-Leap-API-Version": os_esileap_api_version
}

resp, _ = self.api.json_request('DELETE', url, **kwargs)
resp, _ = self.api.json_request("DELETE", url, **kwargs)

if resp.status_code != 200:
raise exceptions.CommandError(json.loads(resp.text)['faultstring'])
raise exceptions.CommandError(json.loads(resp.text)["faultstring"])


@six.add_metaclass(abc.ABCMeta)
Expand All @@ -214,8 +222,7 @@ def detailed_fields(self):
@property
@abc.abstractmethod
def _creation_attributes(self):
"""A list of required creation attributes for a resource type.
"""
"""A list of required creation attributes for a resource type."""

def __init__(self, manager, info):
"""Populate and bind to a manager.
Expand All @@ -224,12 +231,13 @@ def __init__(self, manager, info):
"""

self.manager = manager
self._info = {k: v for (k, v) in info.items() if k
in self.detailed_fields.keys()}
self._info = {
k: v for (k, v) in info.items() if k in self.detailed_fields.keys()
}
self._add_details(self._info)

def _add_details(self, info):
for (k, v) in info.items():
for k, v in info.items():
try:
setattr(self, k, v)
except AttributeError:
Expand Down
Loading
Loading