Skip to content

Commit

Permalink
Introduce new project code standards (#977)
Browse files Browse the repository at this point in the history
This change adds Ruff as the new linter and loosens Black's formatting
as well.
Due to this change, we can drop flake8 and old pre-commit hooks.
  • Loading branch information
JacobCallahan authored Aug 10, 2023
1 parent f62e367 commit 4e4026f
Show file tree
Hide file tree
Showing 21 changed files with 389 additions and 341 deletions.
5 changes: 0 additions & 5 deletions .coveragerc

This file was deleted.

6 changes: 0 additions & 6 deletions .flake8

This file was deleted.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ __pycache__/

# Common venv name
.nailgun/
venv*
20 changes: 5 additions & 15 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,27 +1,17 @@
# configuration for pre-commit git hooks

repos:
- repo: https://github.com/asottile/reorder_python_imports
rev: v3.0.1
hooks:
- id: reorder-python-imports
- repo: https://github.com/asottile/pyupgrade
rev: v2.32.0
hooks:
- id: pyupgrade
args: [--py36-plus]
- repo: https://github.com/psf/black
rev: 22.3.0
rev: 23.3.0
hooks:
- id: black
- repo: https://github.com/pycqa/flake8
rev: 3.9.2
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.0.277
hooks:
- id: flake8
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.2.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: debug-statements
1 change: 0 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

from packaging.version import Version


# Add the NailGun root directory to the system path. This allows references
# such as :mod:`nailgun.client` to be processed correctly.
ROOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))
Expand Down
7 changes: 2 additions & 5 deletions docs/create_user_nailgun.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,14 @@
from pprint import pprint

from nailgun.config import ServerConfig
from nailgun.entities import Organization
from nailgun.entities import User
from nailgun.entities import Organization, User


def main():
"""Create an identical user account on a pair of satellites."""
server_configs = ServerConfig.get('sat1'), ServerConfig.get('sat2')
for server_config in server_configs:
org = Organization(server_config).search(query={'search': 'name="Default_Organization"'})[
0
]
org = Organization(server_config).search(query={'search': 'name="Default_Organization"'})[0]
# The LDAP authentication source with an ID of 1 is internal. It is
# nearly guaranteed to exist and be functioning.
user = User(
Expand Down
5 changes: 3 additions & 2 deletions docs/create_user_plain.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"""
import json
from pprint import pprint
import sys

import requests

Expand Down Expand Up @@ -66,11 +67,11 @@ def get_organization_id(server_config, label):
response.raise_for_status()
decoded = response.json()
if decoded['subtotal'] != 1:
print(
pprint(
f'Expected to find one organization, but instead found {decoded["subtotal"]}. '
f'Search results: {decoded["results"]}'
)
exit(1)
sys.exit(1)
return decoded['results'][0]['id']


Expand Down
1 change: 0 additions & 1 deletion nailgun/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,4 @@
"""
from logging import basicConfig


basicConfig()
7 changes: 3 additions & 4 deletions nailgun/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,13 @@
http://docs.python-requests.org/en/latest/api/#main-interface
"""
import logging
from json import dumps
import logging
from warnings import simplefilter

import requests
import urllib3


logger = logging.getLogger(__name__)

# The urllib3 module (which requests uses) refuses to make insecure HTTPS
Expand Down Expand Up @@ -87,7 +86,7 @@ def _set_content_type(kwargs):

def _truncate_data(data, max_len=500):
"""Truncate data to a max length"""
if isinstance(data, (str, bytes)):
if isinstance(data, str | bytes):
if len(data) > max_len:
return f"{data[:max_len - 3]}..."
return data
Expand Down Expand Up @@ -127,7 +126,7 @@ def _log_response(response):
"""
message = f'Received HTTP {response.status_code} response: {response.text}'
if response.status_code >= 400: # pragma: no cover
if not response.ok:
logger.warning(message)
else:
logger.debug(message)
Expand Down
9 changes: 3 additions & 6 deletions nailgun/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
"""
import json
from os.path import isfile
from os.path import join
from os.path import isfile, join
from threading import Lock

from packaging.version import parse
Expand Down Expand Up @@ -114,7 +113,7 @@ def __repr__(self):
attrs = vars(self).copy()
if "version" in attrs:
attrs["version"] = str(attrs.pop("version"))
kv_pairs = ", ".join(f"{key}={repr(value)}" for key, value in attrs.items())
kv_pairs = ", ".join(f"{key}={value!r}" for key, value in attrs.items())
return f"{self.__module__}.{type(self).__name__}({kv_pairs})"

@classmethod
Expand Down Expand Up @@ -201,9 +200,7 @@ def save(self, label='default', path=None):

# Where is the file we're writing to?
if path is None:
path = join(
BaseDirectory.save_config_path(self._xdg_config_dir), self._xdg_config_file
)
path = join(BaseDirectory.save_config_path(self._xdg_config_dir), self._xdg_config_file)
self._file_lock.acquire()

try:
Expand Down
77 changes: 36 additions & 41 deletions nailgun/entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,29 @@
workings of entity classes.
"""
import hashlib
import os.path
from datetime import datetime
from functools import lru_cache
from http.client import ACCEPTED
from http.client import NO_CONTENT
from urllib.parse import urljoin # noqa:F0401,E0611
import hashlib
from http.client import ACCEPTED, NO_CONTENT
import os.path
from urllib.parse import urljoin

from fauxfactory import gen_alphanumeric
from fauxfactory import gen_choice
from fauxfactory import gen_alphanumeric, gen_choice
from packaging.version import Version

from nailgun import client
from nailgun import entity_fields
from nailgun.entity_mixins import _get_entity_ids
from nailgun.entity_mixins import _payload
from nailgun.entity_mixins import _poll_task
from nailgun.entity_mixins import Entity
from nailgun.entity_mixins import EntityCreateMixin
from nailgun.entity_mixins import EntityDeleteMixin
from nailgun.entity_mixins import EntityReadMixin
from nailgun.entity_mixins import EntitySearchMixin
from nailgun.entity_mixins import EntityUpdateMixin
from nailgun.entity_mixins import to_json_serializable # noqa: F401
from nailgun import client, entity_fields
from nailgun.entity_mixins import (
Entity,
EntityCreateMixin,
EntityDeleteMixin,
EntityReadMixin,
EntitySearchMixin,
EntityUpdateMixin,
_get_entity_ids,
_payload,
_poll_task,
to_json_serializable, # noqa: F401
)

# The size of this file is a direct reflection of the size of Satellite's API.
# This file's size has already been significantly cut down through the use of
Expand Down Expand Up @@ -195,7 +194,7 @@ def _get_version(server_config):
return getattr(server_config, 'version', Version('1!0'))


@lru_cache()
@lru_cache
def _feature_list(server_config, smart_proxy_id=1):
"""Get list of features enabled on capsule"""
smart_proxy = SmartProxy(server_config, id=smart_proxy_id).read_json()
Expand Down Expand Up @@ -1519,7 +1518,10 @@ def read(self, entity=None, attrs=None, ignore=None, params=None):
if attr not in ignore:
# We cannot call `self.update_json([])`, as an ID might not be
# present on self. However, `attrs` is guaranteed to have an ID.
attrs[attr] = DiscoveryRule(self._server_config, id=attrs['id'],).update_json(
attrs[attr] = DiscoveryRule(
self._server_config,
id=attrs['id'],
).update_json(
[]
)[attr]
return super().read(entity, attrs, ignore, params)
Expand Down Expand Up @@ -1943,7 +1945,7 @@ def read(self, entity=None, attrs=None, ignore=None, params=None):
)
for entity_id in _get_entity_ids('template_inputs', attrs)
]
setattr(entity, 'template_inputs', referenced_entities)
entity.template_inputs = referenced_entities
return entity


Expand Down Expand Up @@ -2521,9 +2523,7 @@ def read(self, entity=None, attrs=None, ignore=None, params=None):
if ignore is None:
ignore = set()
ignore.add('content_view_filter')
ignore.update(
[field_name for field_name in entity.get_fields().keys() if field_name not in attrs]
)
ignore.update([field_name for field_name in entity.get_fields() if field_name not in attrs])
return super().read(entity, attrs, ignore, params)

def create_payload(self):
Expand Down Expand Up @@ -2892,7 +2892,7 @@ def add(self, synchronous=True, timeout=None, **kwargs):
kwargs = kwargs.copy() # shadow the passed-in kwargs
if 'data' not in kwargs:
# data is required
kwargs['data'] = dict()
kwargs['data'] = {}
kwargs.update(self._server_config.get_client_kwargs())
response = client.put(self.path('add'), **kwargs)
return _handle_response(response, self._server_config, synchronous, timeout)
Expand All @@ -2914,7 +2914,7 @@ def remove(self, synchronous=True, timeout=None, **kwargs):
kwargs = kwargs.copy() # shadow the passed-in kwargs
if 'data' not in kwargs:
# data is required
kwargs['data'] = dict()
kwargs['data'] = {}
if 'data' in kwargs and 'component_ids' not in kwargs['data']:
kwargs['data']['component_ids'] = [self.id]
kwargs.update(self._server_config.get_client_kwargs())
Expand Down Expand Up @@ -4058,7 +4058,7 @@ def get_values(self):
attrs.pop('_owner_type')
return attrs

def create_missing(self):
def create_missing(self): # noqa: PLR0912, PLR0915 - TODO: Refactor this?
"""Create a bogus managed host.
The exact set of attributes that are required varies depending on
Expand Down Expand Up @@ -5104,7 +5104,7 @@ def read(self, entity=None, attrs=None, ignore=None, params=None):
if attrs['type'] != 'virtual':
ignore.add('attached_to')
ignore.add('tag')
if attrs['type'] != 'bridge' and attrs['type'] != 'bond':
if attrs['type'] not in ('bridge', 'bond'):
ignore.add('attached_devices')
return super().read(entity, attrs, ignore, params)

Expand Down Expand Up @@ -5882,9 +5882,7 @@ def __init__(self, server_config=None, **kwargs):
self._fields = {
'match': entity_fields.StringField(required=True),
'value': entity_fields.StringField(required=True),
'smart_class_parameter': entity_fields.OneToOneField(
SmartClassParameters, parent=True
),
'smart_class_parameter': entity_fields.OneToOneField(SmartClassParameters, parent=True),
'omit': entity_fields.BooleanField(),
}
super().__init__(server_config, **kwargs)
Expand Down Expand Up @@ -6308,10 +6306,7 @@ def search_normalize(self, results):
while Puppet Class entity returns dictionary with lists of subclasses
split by main puppet class.
"""
flattened_results = []
for key in results.keys():
for item in results[key]:
flattened_results.append(item)
flattened_results = [item for sublist in results.values() for item in sublist]
return super().search_normalize(flattened_results)

def path(self, which=None):
Expand Down Expand Up @@ -6827,8 +6822,8 @@ def import_uploads(
It expects either a list of uploads or upload_ids (but not both).
:param content_type: content type (deb’, ‘docker_manifest’, ‘file’, ‘ostree,
rpm’, ‘srpm)
:param content_type: content type (`deb`, `docker_manifest`, `file`, `ostree`,
`rpm`, `srpm`)
:param uploads: Array of uploads to be imported
:param upload_ids: Array of upload ids to be imported
:param synchronous: What should happen if the server returns an HTTP
Expand Down Expand Up @@ -6973,7 +6968,7 @@ def available_repositories(self, **kwargs):
"""
if 'data' not in kwargs:
kwargs['data'] = dict()
kwargs['data'] = {}
kwargs['data']['product_id'] = self.product.id
kwargs = kwargs.copy() # shadow the passed-in kwargs
kwargs.update(self._server_config.get_client_kwargs())
Expand All @@ -6997,7 +6992,7 @@ def enable(self, synchronous=True, timeout=None, **kwargs):
"""
if 'data' not in kwargs:
kwargs['data'] = dict()
kwargs['data'] = {}
kwargs['data']['product_id'] = self.product.id
kwargs = kwargs.copy() # shadow the passed-in kwargs
kwargs.update(self._server_config.get_client_kwargs())
Expand All @@ -7019,7 +7014,7 @@ def disable(self, synchronous=True, timeout=None, **kwargs):
"""
if 'data' not in kwargs:
kwargs['data'] = dict()
kwargs['data'] = {}
kwargs['data']['product_id'] = self.product.id
kwargs = kwargs.copy() # shadow the passed-in kwargs
kwargs.update(self._server_config.get_client_kwargs())
Expand Down
Loading

0 comments on commit 4e4026f

Please sign in to comment.