Compare commits

...

2 commits

Author SHA1 Message Date
95654e9e3e Switch from Woodpecker CI to Forgejo Actions
All checks were successful
Run tests / tests (push) Successful in 3m5s
2024-03-15 10:23:48 +01:00
85caf81ac2 Introduce some new pre-commit hooks 2024-03-15 10:23:21 +01:00
24 changed files with 296 additions and 177 deletions

View file

@ -0,0 +1,84 @@
---
name: Build and publish Debian & Python packages
on: ["create"]
jobs:
build:
runs-on: docker
container:
image: docker.io/brenard/debian-python-deb:latest
steps:
- name: Check out repository code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build Debian & Python package
env:
MAINTAINER_NAME: ${{ vars.MAINTAINER_NAME }}
MAINTAINER_EMAIL: ${{ vars.MAINTAINER_EMAIL }}
DEBIAN_CODENAME: ${{ vars.DEBIAN_CODENAME }}
run: |
echo "${{ secrets.GPG_KEY }}"|base64 -d|gpg --import
./build.sh
rm -fr deb_dist/mylib-*
- name: Upload Debian & Python package files
uses: actions/upload-artifact@v3
with:
name: dist
path: |
dist
deb_dist
publish-forgejo:
runs-on: docker
container:
image: docker.io/brenard/debian-python-deb:latest
steps:
- name: Download Debian & Python packages files
uses: actions/download-artifact@v3
with:
name: dist
- name: Create the release
id: create-release
shell: bash
run: |
mkdir release
mv dist/*.whl release/
mv deb_dist/*.deb release/
md5sum release/* > md5sum.txt
sha512sum release/* > sha512sum.txt
mv md5sum.txt sha512sum.txt release/
{
echo 'release_note<<EOF'
cat dist/release_notes.md
echo 'EOF'
} >> "$GITHUB_OUTPUT"
- name: Publish release on Forgejo
uses: actions/forgejo-release@v1
with:
direction: upload
url: https://gitea.zionetrix.net
token: ${{ secrets.forgejo_token }}
release-dir: release
release-notes: ${{ steps.create-release.outputs.release_note }}
publish-aptly:
runs-on: docker
container:
image: docker.io/brenard/aptly-publish:latest
steps:
- name: "Download Debian package files"
uses: actions/download-artifact@v3
with:
name: dist
- name: "Publish Debian package on Aptly repository"
uses: https://gitea.zionetrix.net/bn8/aptly-publish@master
with:
api_url: ${{ vars.apt_api_url }}
api_username: ${{ vars.apt_api_username }}
api_password: ${{ secrets.apt_api_password }}
repo_name: ${{ vars.apt_repo_name }}
path: "deb_dist"
source_name: ${{ vars.apt_source_name }}

View file

@ -0,0 +1,30 @@
---
name: Run tests
on: [push]
jobs:
tests:
runs-on: docker
container:
image: docker.io/brenard/python-pre-commit:latest
steps:
- name: Check out repository code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install dependencies
env:
DEBIAN_FRONTEND: noninteractive
run: |
apt-get -qq update
apt-get -qq -y install --no-install-recommends \
build-essential \
python3 \
python3-dev \
libldap2-dev \
libsasl2-dev \
pkg-config \
libsystemd-dev \
libpq-dev \
libmariadb-dev
- name: Run tests.sh
run: ./tests.sh

View file

@ -1,31 +1,58 @@
# Pre-commit hooks to run tests and ensure code is cleaned. # Pre-commit hooks to run tests and ensure code is cleaned.
# See https://pre-commit.com for more information # See https://pre-commit.com for more information
---
repos: repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.6
hooks:
- id: ruff
args: ["--fix"]
- repo: https://github.com/asottile/pyupgrade - repo: https://github.com/asottile/pyupgrade
rev: v3.3.1 rev: v3.15.0
hooks: hooks:
- id: pyupgrade - id: pyupgrade
args: ['--keep-percent-format', '--py37-plus'] args: ["--keep-percent-format", "--py37-plus"]
- repo: https://github.com/psf/black - repo: https://github.com/psf/black
rev: 22.12.0 rev: 23.11.0
hooks: hooks:
- id: black - id: black
args: ['--target-version', 'py37', '--line-length', '100'] args: ["--target-version", "py37", "--line-length", "100"]
- repo: https://github.com/PyCQA/isort - repo: https://github.com/PyCQA/isort
rev: 5.11.5 rev: 5.12.0
hooks: hooks:
- id: isort - id: isort
args: ['--profile', 'black', '--line-length', '100'] args: ["--profile", "black", "--line-length", "100"]
- repo: https://github.com/PyCQA/flake8 - repo: https://github.com/PyCQA/flake8
rev: 6.0.0 rev: 6.1.0
hooks: hooks:
- id: flake8 - id: flake8
args: ['--max-line-length=100'] args: ["--max-line-length=100"]
- repo: https://github.com/codespell-project/codespell
rev: v2.2.2
hooks:
- id: codespell
args:
- --ignore-words-list=exten
- --skip="./.*,*.csv,*.json,*.ini,*.subject,*.txt,*.html,*.log,*.conf"
- --quiet-level=2
- --ignore-regex=.*codespell-ignore$
# - --write-changes # Uncomment to write changes
exclude_types: [csv, json]
- repo: https://github.com/adrienverge/yamllint
rev: v1.32.0
hooks:
- id: yamllint
ignore: .github/
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v2.7.1
hooks:
- id: prettier
args: ["--print-width", "100"]
- repo: local - repo: local
hooks: hooks:
- id: pylint - id: pylint
name: pylint name: pylint
entry: pylint --extension-pkg-whitelist=cx_Oracle entry: ./.pre-commit-pylint --extension-pkg-whitelist=cx_Oracle
language: system language: system
types: [python] types: [python]
require_serial: true require_serial: true
@ -38,7 +65,7 @@ repos:
hooks: hooks:
- id: pytest - id: pytest
name: pytest name: pytest
entry: python3 -m pytest tests entry: ./.pre-commit-pytest tests
language: system language: system
types: [python] types: [python]
pass_filenames: false pass_filenames: false

21
.pre-commit-pylint Executable file
View file

@ -0,0 +1,21 @@
#!/bin/bash
PWD=`pwd`
if [ -d "$PWD/venv" ]
then
echo "Run pylint inside venv ($PWD/venv)..."
[ ! -e "$PWD/venv/bin/pylint" ] && $PWD/venv/bin/python -m pip install pylint
$PWD/venv/bin/pylint "$@"
exit $?
elif [ -e "$PWD/pyproject.toml" ]
then
echo "Run pylint using poetry..."
poetry run pylint --version > /dev/null 2>&1 || poetry run python -m pip install pylint
poetry run pylint "$@"
exit $?
else
echo "Run pylint at system scope..."
pylint "$@"
exit $?
fi

21
.pre-commit-pytest Executable file
View file

@ -0,0 +1,21 @@
#!/bin/bash
PWD=`pwd`
if [ -d "$PWD/venv" ]
then
echo "Run pytest inside venv ($PWD/venv)..."
[ ! -e "$PWD/venv/bin/pytest" ] && $PWD/venv/bin/python -m pip install pytest
$PWD/venv/bin/pytest "$@"
exit $?
elif [ -e "$PWD/pyproject.toml" ]
then
echo "Run pytest using poetry..."
poetry run pytest --version > /dev/null 2>&1 || poetry run python -m pip install pytest
poetry run pytest "$@"
exit $?
else
echo "Run pytest at system scope..."
pytest "$@"
exit $?
fi

View file

@ -1,63 +0,0 @@
clone:
git:
image: woodpeckerci/plugin-git
tags: true
pipeline:
test:
image: brenard/mylib:dev-master
commands:
- ./tests.sh --no-venv
build:
image: brenard/debian-python-deb
when:
event: tag
commands:
- echo "$GPG_KEY"|base64 -d|gpg --import
- ./build.sh --quiet
- rm -fr deb_dist/mylib-*
secrets: [ maintainer_name, maintainer_email, gpg_key, debian_codename ]
publish-dryrun:
group: publish
image: alpine
when:
event: tag
commands:
- ls dist/*
- ls deb_dist/*
publish-gitea:
group: publish
image: plugins/gitea-release
when:
event: tag
settings:
api_key:
from_secret: gitea_token
base_url: https://gitea.zionetrix.net
note: dist/release_notes.md
files:
- dist/*
- deb_dist/*.deb
checksum:
- md5
- sha512
publish-apt:
group: publish
image: brenard/aptly-publish
when:
event: tag
settings:
api_url:
from_secret: apt_api_url
api_username:
from_secret: apt_api_username
api_password:
from_secret: apt_api_password
repo_name:
from_secret: apt_repo_name
path: deb_dist
source_name: mylib

View file

@ -35,35 +35,35 @@ Just run `pip install git+https://gitea.zionetrix.net/bn8/python-mylib.git`
Just run `python setup.py install` Just run `python setup.py install`
**Note:** This project could previously use as independent python files (not as module). This old version is keep in *legacy* git branch (not maintained). **Note:** This project could previously use as independent python files (not as module). This old version is keep in _legacy_ git branch (not maintained).
## Include libs ## Include libs
* **mylib.email.EmailClient:** An email client to forge (eventually using template) and send email via a SMTP server - **mylib.email.EmailClient:** An email client to forge (eventually using template) and send email via a SMTP server
* **mylib.ldap.LdapServer:** A small lib to make requesting LDAP server easier. It's also provide some helper functions to deal with LDAP date string. - **mylib.ldap.LdapServer:** A small lib to make requesting LDAP server easier. It's also provide some helper functions to deal with LDAP date string.
* **mylib.mysql.MyDB:** An extra small lib to remember me how to interact with MySQL/MariaDB database - **mylib.mysql.MyDB:** An extra small lib to remember me how to interact with MySQL/MariaDB database
* **mylib.pgsql.PgDB:** An small lib to remember me how to interact with PostgreSQL database. **Warning:** The insert/update/delete/select methods demonstrate how to forge raw SQL request, but **it's a bad idea**: Prefer using prepared query. - **mylib.pgsql.PgDB:** An small lib to remember me how to interact with PostgreSQL database. **Warning:** The insert/update/delete/select methods demonstrate how to forge raw SQL request, but **it's a bad idea**: Prefer using prepared query.
* **mylib.opening_hours:** A set of helper functions to deal with french opening hours (including normal opening hours, exceptional closure and nonworking public holidays). - **mylib.opening_hours:** A set of helper functions to deal with french opening hours (including normal opening hours, exceptional closure and nonworking public holidays).
* **mylib.pbar.Pbar:** A small lib for progress bar - **mylib.pbar.Pbar:** A small lib for progress bar
* **mylib.report.Report:** A small lib to implement logging based email report send at exit - **mylib.report.Report:** A small lib to implement logging based email report send at exit
To know how to use these libs, you can take a look on *mylib.scripts* content or in *tests* directory. To know how to use these libs, you can take a look on _mylib.scripts_ content or in _tests_ directory.
## Code Style ## Code Style
[pylint](https://pypi.org/project/pylint/) is used to check for errors and enforces a coding standard, using thoses parameters: [pylint](https://pypi.org/project/pylint/) is used to check for errors and enforces a coding standard, using those parameters:
```bash ```bash
pylint --extension-pkg-whitelist=cx_Oracle pylint --extension-pkg-whitelist=cx_Oracle
``` ```
[flake8](https://pypi.org/project/flake8/) is also used to check for errors and enforces a coding standard, using thoses parameters: [flake8](https://pypi.org/project/flake8/) is also used to check for errors and enforces a coding standard, using those parameters:
```bash ```bash
flake8 --max-line-length=100 flake8 --max-line-length=100
``` ```
[black](https://pypi.org/project/black/) is used to format the code, using thoses parameters: [black](https://pypi.org/project/black/) is used to format the code, using those parameters:
```bash ```bash
black --target-version py37 --line-length 100 black --target-version py37 --line-length 100
@ -83,7 +83,6 @@ pyupgrade --keep-percent-format --py37-plus
**Note:** There is `.pre-commit-config.yaml` to use [pre-commit](https://pre-commit.com/) to automatically run these tools before commits. After cloning the repository, execute `pre-commit install` to install the git hook. **Note:** There is `.pre-commit-config.yaml` to use [pre-commit](https://pre-commit.com/) to automatically run these tools before commits. After cloning the repository, execute `pre-commit install` to install the git hook.
## Copyright ## Copyright
Copyright (c) 2013-2021 Benjamin Renard <brenard@zionetrix.net> Copyright (c) 2013-2021 Benjamin Renard <brenard@zionetrix.net>

View file

@ -81,7 +81,7 @@ cd deb_dist/mylib-$VERSION
if [ -z "$DEBIAN_CODENAME" ] if [ -z "$DEBIAN_CODENAME" ]
then then
echo "Retreive debian codename using lsb_release..." echo "Retrieve debian codename using lsb_release..."
DEBIAN_CODENAME=$( lsb_release -c -s ) DEBIAN_CODENAME=$( lsb_release -c -s )
[ $( lsb_release -r -s ) -ge 9 ] && DEBIAN_CODENAME="${DEBIAN_CODENAME}-ee" [ $( lsb_release -r -s ) -ge 9 ] && DEBIAN_CODENAME="${DEBIAN_CODENAME}-ee"
else else

View file

@ -1,7 +1,7 @@
""" Some really common helper functions """ """ Some really common helper functions """
# #
# Pretty formating helpers # Pretty formatting helpers
# #
@ -11,7 +11,7 @@ def increment_prefix(prefix):
def pretty_format_value(value, encoding="utf8", prefix=None): def pretty_format_value(value, encoding="utf8", prefix=None):
"""Returned pretty formated value to display""" """Returned pretty formatted value to display"""
if isinstance(value, dict): if isinstance(value, dict):
return pretty_format_dict(value, encoding=encoding, prefix=prefix) return pretty_format_dict(value, encoding=encoding, prefix=prefix)
if isinstance(value, list): if isinstance(value, list):
@ -27,10 +27,10 @@ def pretty_format_value(value, encoding="utf8", prefix=None):
def pretty_format_value_in_list(value, encoding="utf8", prefix=None): def pretty_format_value_in_list(value, encoding="utf8", prefix=None):
""" """
Returned pretty formated value to display in list Returned pretty formatted value to display in list
That method will prefix value with line return and incremented prefix That method will prefix value with line return and incremented prefix
if pretty formated value contains line return. if pretty formatted value contains line return.
""" """
prefix = prefix if prefix else "" prefix = prefix if prefix else ""
value = pretty_format_value(value, encoding, prefix) value = pretty_format_value(value, encoding, prefix)
@ -41,7 +41,7 @@ def pretty_format_value_in_list(value, encoding="utf8", prefix=None):
def pretty_format_dict(value, encoding="utf8", prefix=None): def pretty_format_dict(value, encoding="utf8", prefix=None):
"""Returned pretty formated dict to display""" """Returned pretty formatted dict to display"""
prefix = prefix if prefix else "" prefix = prefix if prefix else ""
result = [] result = []
for key in sorted(value.keys()): for key in sorted(value.keys()):
@ -53,7 +53,7 @@ def pretty_format_dict(value, encoding="utf8", prefix=None):
def pretty_format_list(row, encoding="utf8", prefix=None): def pretty_format_list(row, encoding="utf8", prefix=None):
"""Returned pretty formated list to display""" """Returned pretty formatted list to display"""
prefix = prefix if prefix else "" prefix = prefix if prefix else ""
result = [] result = []
for idx, values in enumerate(row): for idx, values in enumerate(row):

View file

@ -465,7 +465,7 @@ class PasswordOption(StringOption):
service_name = self._keyring_service_name service_name = self._keyring_service_name
username = self._keyring_username username = self._keyring_username
log.debug("Retreive password %s for username=%s from keyring", service_name, username) log.debug("Retrieve password %s for username=%s from keyring", service_name, username)
value = keyring.get_password(service_name, username) value = keyring.get_password(service_name, username)
if value is None: if value is None:
@ -757,7 +757,7 @@ class Config: # pylint: disable=too-many-instance-attributes
self.sections[name] = ConfigSection(self, name, **kwargs) self.sections[name] = ConfigSection(self, name, **kwargs)
if loaded_callback: if loaded_callback:
self._loaded_callbacks.append(loaded_callback) self._loaded_callbacks.append(loaded_callback)
# If configuration is already loaded, execute callback immediatly # If configuration is already loaded, execute callback immediately
if self._filepath or self.options: if self._filepath or self.options:
self._loaded() self._loaded()
return self.sections[name] return self.sections[name]
@ -1155,7 +1155,7 @@ class Config: # pylint: disable=too-many-instance-attributes
dest="validate", dest="validate",
help=( help=(
"Validate configuration: initialize application to test if provided parameters" "Validate configuration: initialize application to test if provided parameters"
" works.\n\nNote: Validation will occured after configuration file creation or" " works.\n\nNote: Validation will occurred after configuration file creation or"
" update. On error, re-run with -O/--overwrite parameter to fix it." " update. On error, re-run with -O/--overwrite parameter to fix it."
), ),
) )
@ -1197,7 +1197,7 @@ class Config: # pylint: disable=too-many-instance-attributes
if options.validate: if options.validate:
validate() validate()
else: else:
print(f"Error occured creating configuration file {options.config}") print(f"Error occurred creating configuration file {options.config}")
sys.exit(1) sys.exit(1)
sys.exit(0) sys.exit(0)
@ -1282,7 +1282,7 @@ class ConfigurableObject:
raise ConfigException(f"No configuration name defined for {__name__}") raise ConfigException(f"No configuration name defined for {__name__}")
def _get_option(self, option, default=None, required=False): def _get_option(self, option, default=None, required=False):
"""Retreive option value""" """Retrieve option value"""
if self._kwargs and option in self._kwargs: if self._kwargs and option in self._kwargs:
return self._kwargs[option] return self._kwargs[option]
@ -1302,7 +1302,7 @@ class ConfigurableObject:
def set_default(self, option, default_value): def set_default(self, option, default_value):
"""Set option default value""" """Set option default value"""
assert option in self._defaults, f"Unkown option {option}" assert option in self._defaults, f"Unknown option {option}"
self._defaults[option] = default_value self._defaults[option] = default_value
def set_defaults(self, **default_values): def set_defaults(self, **default_values):
@ -1394,7 +1394,7 @@ class ConfigurableObject:
return True return True
# If Config provided, use it's get_option() method to obtain a global just_try parameter # If Config provided, use it's get_option() method to obtain a global just_try parameter
# value with a defaut to False, otherwise always false # value with a default to False, otherwise always false
return self._config.get_option("just_try", default=False) if self._config else False return self._config.get_option("just_try", default=False) if self._config else False

View file

@ -38,7 +38,7 @@ class DBFailToConnect(DBException, RuntimeError):
""" """
def __init__(self, uri): def __init__(self, uri):
super().__init__("An error occured during database connection ({uri})", uri=uri) super().__init__("An error occurred during database connection ({uri})", uri=uri)
class DBDuplicatedSQLParameter(DBException, KeyError): class DBDuplicatedSQLParameter(DBException, KeyError):

View file

@ -239,7 +239,7 @@ class EmailClient(
msg["Date"] = email.utils.formatdate(None, True) msg["Date"] = email.utils.formatdate(None, True)
encoding = encoding if encoding else self._get_option("encoding") encoding = encoding if encoding else self._get_option("encoding")
if template: if template:
assert template in self.templates, f"Unknwon template {template}" assert template in self.templates, f"Unknown template {template}"
# Handle subject from template # Handle subject from template
if not subject: if not subject:
assert self.templates[template].get( assert self.templates[template].get(
@ -251,7 +251,7 @@ class EmailClient(
else self.templates[template]["subject"].format(**template_vars) else self.templates[template]["subject"].format(**template_vars)
) )
# Put HTML part in last one to prefered it # Put HTML part in last one to preferred it
parts = [] parts = []
if self.templates[template].get("text"): if self.templates[template].get("text"):
if isinstance(self.templates[template]["text"], MakoTemplate): if isinstance(self.templates[template]["text"], MakoTemplate):
@ -322,7 +322,7 @@ class EmailClient(
catch_addr = self._get_option("catch_all_addr") catch_addr = self._get_option("catch_all_addr")
if catch_addr: if catch_addr:
log.debug( log.debug(
"Catch email originaly send to %s (CC:%s, BCC:%s) to %s", "Catch email originally send to %s (CC:%s, BCC:%s) to %s",
", ".join(recipients), ", ".join(recipients),
", ".join(cc) if isinstance(cc, list) else cc, ", ".join(cc) if isinstance(cc, list) else cc,
", ".join(bcc) if isinstance(bcc, list) else bcc, ", ".join(bcc) if isinstance(bcc, list) else bcc,

View file

@ -211,7 +211,7 @@ class LdapServer:
result_page_control = rctrl result_page_control = rctrl
break break
# If PagedResultsControl answer not detected, paged serach # If PagedResultsControl answer not detected, paged search
if not result_page_control: if not result_page_control:
self._error( self._error(
"LdapServer - Server ignores RFC2696 control, paged search can not works", "LdapServer - Server ignores RFC2696 control, paged search can not works",
@ -238,7 +238,7 @@ class LdapServer:
page_control.cookie = result_page_control.cookie page_control.cookie = result_page_control.cookie
self.logger.debug( self.logger.debug(
"LdapServer - Paged search end: %d object(s) retreived in %d page(s) of %d object(s)", "LdapServer - Paged search end: %d object(s) retrieved in %d page(s) of %d object(s)",
len(ret), len(ret),
pages_count, pages_count,
pagesize, pagesize,
@ -379,12 +379,12 @@ class LdapServer:
@staticmethod @staticmethod
def get_dn(obj): def get_dn(obj):
"""Retreive an on object DN from its entry in LDAP search result""" """Retrieve an on object DN from its entry in LDAP search result"""
return obj[0][0] return obj[0][0]
@staticmethod @staticmethod
def get_attr(obj, attr, all_values=None, default=None, decode=False): def get_attr(obj, attr, all_values=None, default=None, decode=False):
"""Retreive an on object attribute value(s) from the object entry in LDAP search result""" """Retrieve an on object attribute value(s) from the object entry in LDAP search result"""
if attr not in obj: if attr not in obj:
for k in obj: for k in obj:
if k.lower() == attr.lower(): if k.lower() == attr.lower():
@ -437,7 +437,7 @@ class LdapClient:
self.initialize() self.initialize()
def _get_option(self, option, default=None, required=False): def _get_option(self, option, default=None, required=False):
"""Retreive option value""" """Retrieve option value"""
if self._options and hasattr(self._options, self._options_prefix + option): if self._options and hasattr(self._options, self._options_prefix + option):
return getattr(self._options, self._options_prefix + option) return getattr(self._options, self._options_prefix + option)
@ -500,7 +500,7 @@ class LdapClient:
self.config = loaded_config self.config = loaded_config
uri = self._get_option("uri", required=True) uri = self._get_option("uri", required=True)
binddn = self._get_option("binddn") binddn = self._get_option("binddn")
log.info("Connect to LDAP server %s as %s", uri, binddn if binddn else "annonymous") log.info("Connect to LDAP server %s as %s", uri, binddn if binddn else "anonymous")
self._conn = LdapServer( self._conn = LdapServer(
uri, uri,
dn=binddn, dn=binddn,
@ -553,7 +553,7 @@ class LdapClient:
:param attr: The attribute name :param attr: The attribute name
:param all_values: If True, all values of the attribute will be :param all_values: If True, all values of the attribute will be
returned instead of the first value only returned instead of the first value only
(optinal, default: False) (optional, default: False)
""" """
if attr not in obj: if attr not in obj:
for k in obj: for k in obj:
@ -582,7 +582,7 @@ class LdapClient:
:param name: The object type name :param name: The object type name
:param filterstr: The LDAP filter to use to search objects on LDAP directory :param filterstr: The LDAP filter to use to search objects on LDAP directory
:param basedn: The base DN of the search :param basedn: The base DN of the search
:param attrs: The list of attribute names to retreive :param attrs: The list of attribute names to retrieve
:param key_attr: The attribute name or 'dn' to use as key in result :param key_attr: The attribute name or 'dn' to use as key in result
(optional, if leave to None, the result will be a list) (optional, if leave to None, the result will be a list)
:param warn: If True, a warning message will be logged if no object is found :param warn: If True, a warning message will be logged if no object is found
@ -594,7 +594,7 @@ class LdapClient:
(optional, default: see LdapServer.paged_search) (optional, default: see LdapServer.paged_search)
""" """
if name in self._cached_objects: if name in self._cached_objects:
log.debug("Retreived %s objects from cache", name) log.debug("Retrieved %s objects from cache", name)
else: else:
assert self._conn or self.initialize() assert self._conn or self.initialize()
log.debug( log.debug(
@ -643,7 +643,7 @@ class LdapClient:
:param object_name: The object name (only use in log messages) :param object_name: The object name (only use in log messages)
:param filterstr: The LDAP filter to use to search the object on LDAP directory :param filterstr: The LDAP filter to use to search the object on LDAP directory
:param basedn: The base DN of the search :param basedn: The base DN of the search
:param attrs: The list of attribute names to retreive :param attrs: The list of attribute names to retrieve
:param warn: If True, a warning message will be logged if no object is found :param warn: If True, a warning message will be logged if no object is found
in LDAP directory (otherwise, it will be just a debug message) in LDAP directory (otherwise, it will be just a debug message)
(optional, default: True) (optional, default: True)
@ -855,7 +855,7 @@ class LdapClient:
Update an object Update an object
:param ldap_obj: The original LDAP object :param ldap_obj: The original LDAP object
:param changes: The changes to make on LDAP object (as formated by get_changes() method) :param changes: The changes to make on LDAP object (as formatted by get_changes() method)
:param protected_attrs: An optional list of protected attributes :param protected_attrs: An optional list of protected attributes
:param rdn_attr: The LDAP object RDN attribute (to detect renaming, default: auto-detected) :param rdn_attr: The LDAP object RDN attribute (to detect renaming, default: auto-detected)
:param rdn_attr: Enable relax modification server control (optional, default: false) :param rdn_attr: Enable relax modification server control (optional, default: false)
@ -915,7 +915,7 @@ class LdapClient:
# Otherwise, update object DN # Otherwise, update object DN
ldap_obj["dn"] = new_dn ldap_obj["dn"] = new_dn
else: else:
log.debug("%s: No change detected on RDN attibute %s", ldap_obj["dn"], rdn_attr) log.debug("%s: No change detected on RDN attribute %s", ldap_obj["dn"], rdn_attr)
try: try:
if self._just_try: if self._just_try:
@ -1103,7 +1103,7 @@ def format_date(value, from_timezone=None, to_timezone=None, naive=True):
(optional, default : server local timezone) (optional, default : server local timezone)
:param to_timezone: The timezone used in LDAP (optional, default : UTC) :param to_timezone: The timezone used in LDAP (optional, default : UTC)
:param naive: Use naive datetime : do not handle timezone conversion before :param naive: Use naive datetime : do not handle timezone conversion before
formating and return datetime as UTC (because LDAP required a formatting and return datetime as UTC (because LDAP required a
timezone) timezone)
""" """
assert isinstance( assert isinstance(

View file

@ -29,7 +29,7 @@ Mapping configuration
'join': '[glue]', # If present, sources values will be join using the "glue" 'join': '[glue]', # If present, sources values will be join using the "glue"
# Alternative mapping # Alternative mapping
'or': { [map configuration] } # If this mapping case does not retreive any value, try to 'or': { [map configuration] } # If this mapping case does not retrieve any value, try to
# get value(s) with this other mapping configuration # get value(s) with this other mapping configuration
}, },
'[dst key 2]': { '[dst key 2]': {

View file

@ -41,7 +41,7 @@ class MyDB(DB):
) )
except Error as err: except Error as err:
log.fatal( log.fatal(
"An error occured during MySQL database connection (%s@%s:%s).", "An error occurred during MySQL database connection (%s@%s:%s).",
self._user, self._user,
self._host, self._host,
self._db, self._db,

View file

@ -31,7 +31,7 @@ class OracleDB(DB):
self._conn = cx_Oracle.connect(user=self._user, password=self._pwd, dsn=self._dsn) self._conn = cx_Oracle.connect(user=self._user, password=self._pwd, dsn=self._dsn)
except cx_Oracle.Error as err: except cx_Oracle.Error as err:
log.fatal( log.fatal(
"An error occured during Oracle database connection (%s@%s).", "An error occurred during Oracle database connection (%s@%s).",
self._user, self._user,
self._dsn, self._dsn,
exc_info=1, exc_info=1,

View file

@ -45,7 +45,7 @@ class PgDB(DB):
) )
except psycopg2.Error as err: except psycopg2.Error as err:
log.fatal( log.fatal(
"An error occured during Postgresql database connection (%s@%s, database=%s).", "An error occurred during Postgresql database connection (%s@%s, database=%s).",
self._user, self._user,
self._host, self._host,
self._db, self._db,
@ -71,7 +71,7 @@ class PgDB(DB):
return True return True
except psycopg2.Error: except psycopg2.Error:
log.error( log.error(
'An error occured setting Postgresql database connection encoding to "%s"', 'An error occurred setting Postgresql database connection encoding to "%s"',
enc, enc,
exc_info=1, exc_info=1,
) )
@ -126,7 +126,7 @@ class PgDB(DB):
return False return False
# #
# Depreated helpers # Deprecated helpers
# #
@classmethod @classmethod

View file

@ -96,7 +96,7 @@ class Report(ConfigurableObject): # pylint: disable=useless-object-inheritance
self.send_at_exit() self.send_at_exit()
def get_handler(self): def get_handler(self):
"""Retreive logging handler""" """Retrieve logging handler"""
return self.handler return self.handler
def write(self, msg): def write(self, msg):

View file

@ -31,7 +31,7 @@ def init_logging(options, name, report=None):
def get_default_opt_value(config, default_config, key): def get_default_opt_value(config, default_config, key):
"""Retreive default option value from config or default config dictionaries""" """Retrieve default option value from config or default config dictionaries"""
if config and key in config: if config and key in config:
return config[key] return config[key]
return default_config.get(key) return default_config.get(key)

View file

@ -47,7 +47,7 @@ def main(argv=None): # pylint: disable=too-many-locals,too-many-statements
sftp.connect() sftp.connect()
atexit.register(sftp.close) atexit.register(sftp.close)
log.debug("Create tempory file") log.debug("Create temporary file")
test_content = b"Juste un test." test_content = b"Juste un test."
tmp_dir = tempfile.TemporaryDirectory() # pylint: disable=consider-using-with tmp_dir = tempfile.TemporaryDirectory() # pylint: disable=consider-using-with
tmp_file = os.path.join( tmp_file = os.path.join(

View file

@ -116,13 +116,13 @@ class SFTPClient(ConfigurableObject):
if self.initial_directory: if self.initial_directory:
log.debug("Initial remote directory: '%s'", self.initial_directory) log.debug("Initial remote directory: '%s'", self.initial_directory)
else: else:
log.debug("Fail to retreive remote directory, use empty string instead") log.debug("Fail to retrieve remote directory, use empty string instead")
self.initial_directory = "" self.initial_directory = ""
def get_file(self, remote_filepath, local_filepath): def get_file(self, remote_filepath, local_filepath):
"""Retrieve a file from SFTP server""" """Retrieve a file from SFTP server"""
self.connect() self.connect()
log.debug("Retreive file '%s' to '%s'", remote_filepath, local_filepath) log.debug("Retrieve file '%s' to '%s'", remote_filepath, local_filepath)
return self.sftp_client.get(remote_filepath, local_filepath) is None return self.sftp_client.get(remote_filepath, local_filepath) is None
def open_file(self, remote_filepath, mode="r"): def open_file(self, remote_filepath, mode="r"):

View file

@ -35,7 +35,7 @@ class TelltaleFile:
@property @property
def last_update(self): def last_update(self):
"""Retreive last update datetime of the telltall file""" """Retrieve last update datetime of the telltall file"""
try: try:
return datetime.datetime.fromtimestamp(os.stat(self.filepath).st_mtime) return datetime.datetime.fromtimestamp(os.stat(self.filepath).st_mtime)
except FileNotFoundError: except FileNotFoundError:

View file

@ -32,7 +32,7 @@ do
set -x set -x
;; ;;
*) *)
usage "Unkown parameter '$OPT'" usage "Unknown parameter '$OPT'"
esac esac
let idx=idx+1 let idx=idx+1
done done

View file

@ -10,7 +10,7 @@ import pytest
from mylib.config import BooleanOption, Config, ConfigSection, StringOption from mylib.config import BooleanOption, Config, ConfigSection, StringOption
runned = {} tested = {}
def test_config_init_default_args(): def test_config_init_default_args():
@ -58,24 +58,24 @@ def test_add_section_with_callback():
config = Config("Test app") config = Config("Test app")
name = "test_section" name = "test_section"
global runned global tested
runned["test_add_section_with_callback"] = False tested["test_add_section_with_callback"] = False
def test_callback(loaded_config): def test_callback(loaded_config):
global runned global tested
assert loaded_config == config assert loaded_config == config
assert runned["test_add_section_with_callback"] is False assert tested["test_add_section_with_callback"] is False
runned["test_add_section_with_callback"] = True tested["test_add_section_with_callback"] = True
section = config.add_section(name, loaded_callback=test_callback) section = config.add_section(name, loaded_callback=test_callback)
assert isinstance(section, ConfigSection) assert isinstance(section, ConfigSection)
assert test_callback in config._loaded_callbacks assert test_callback in config._loaded_callbacks
assert runned["test_add_section_with_callback"] is False assert tested["test_add_section_with_callback"] is False
config.parse_arguments_options(argv=[], create=False) config.parse_arguments_options(argv=[], create=False)
assert runned["test_add_section_with_callback"] is True assert tested["test_add_section_with_callback"] is True
assert test_callback in config._loaded_callbacks_executed assert test_callback in config._loaded_callbacks_executed
# Try to execute again to verify callback is not runned again # Try to execute again to verify callback is not tested again
config._loaded() config._loaded()
@ -84,21 +84,21 @@ def test_add_section_with_callback_already_loaded():
name = "test_section" name = "test_section"
config.parse_arguments_options(argv=[], create=False) config.parse_arguments_options(argv=[], create=False)
global runned global tested
runned["test_add_section_with_callback_already_loaded"] = False tested["test_add_section_with_callback_already_loaded"] = False
def test_callback(loaded_config): def test_callback(loaded_config):
global runned global tested
assert loaded_config == config assert loaded_config == config
assert runned["test_add_section_with_callback_already_loaded"] is False assert tested["test_add_section_with_callback_already_loaded"] is False
runned["test_add_section_with_callback_already_loaded"] = True tested["test_add_section_with_callback_already_loaded"] = True
section = config.add_section(name, loaded_callback=test_callback) section = config.add_section(name, loaded_callback=test_callback)
assert isinstance(section, ConfigSection) assert isinstance(section, ConfigSection)
assert runned["test_add_section_with_callback_already_loaded"] is True assert tested["test_add_section_with_callback_already_loaded"] is True
assert test_callback in config._loaded_callbacks assert test_callback in config._loaded_callbacks
assert test_callback in config._loaded_callbacks_executed assert test_callback in config._loaded_callbacks_executed
# Try to execute again to verify callback is not runned again # Try to execute again to verify callback is not tested again
config._loaded() config._loaded()