Code cleaning

This commit is contained in:
Benjamin Renard 2021-05-19 19:19:57 +02:00
parent ad31ddc699
commit 6bbacce38a
15 changed files with 186 additions and 124 deletions

6
.pylintrc Normal file
View File

@ -0,0 +1,6 @@
[MESSAGES CONTROL]
disable=invalid-name,
locally-disabled,
too-many-arguments,
too-many-branches,
line-too-long,

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" Email helpers """ """ Email client to forge and send emails """
import logging import logging
import os import os

View File

@ -1,4 +1,6 @@
#!/usr/bin/env python3 # -*- coding: utf-8 -*-
""" LDAP server connection helper """
import copy import copy
import datetime import datetime
@ -12,7 +14,9 @@ from ldap.controls.simple import RelaxRulesControl
import ldap.modlist as modlist import ldap.modlist as modlist
import pytz import pytz
class LdapServer(object): # pylint: disable=useless-object-inheritance
class LdapServer:
""" LDAP server connection helper """ # pylint: disable=useless-object-inheritance
uri = None uri = None
dn = None dn = None
@ -21,24 +25,25 @@ class LdapServer(object): # pylint: disable=useless-object-inheritance
con = 0 con = 0
def __init__(self,uri,dn=None,pwd=None,v2=None,raiseOnError=False, logger=False): def __init__(self, uri, dn=None, pwd=None, v2=None, raiseOnError=False, logger=False):
self.uri = uri self.uri = uri
self.dn = dn self.dn = dn
self.pwd = pwd self.pwd = pwd
self.raiseOnError = raiseOnError self.raiseOnError = raiseOnError
if v2: if v2:
self.v2=True self.v2 = True
if logger: if logger:
self.logger = logger self.logger = logger
else: else:
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
def _error(self,error,level=logging.WARNING): def _error(self, error, level=logging.WARNING):
if self.raiseOnError: if self.raiseOnError:
raise LdapServerException(error) raise LdapServerException(error)
self.logger.log(level, error) self.logger.log(level, error)
def connect(self): def connect(self):
""" Start connection to LDAP server """
if self.con == 0: if self.con == 0:
try: try:
con = ldap.initialize(self.uri) con = ldap.initialize(self.uri)
@ -48,19 +53,20 @@ class LdapServer(object): # pylint: disable=useless-object-inheritance
con.protocol_version = ldap.VERSION3 # pylint: disable=no-member con.protocol_version = ldap.VERSION3 # pylint: disable=no-member
if self.dn: if self.dn:
con.simple_bind_s(self.dn,self.pwd) con.simple_bind_s(self.dn, self.pwd)
elif self.uri.startswith('ldapi://'): elif self.uri.startswith('ldapi://'):
con.sasl_interactive_bind_s("", ldap.sasl.external()) con.sasl_interactive_bind_s("", ldap.sasl.external())
self.con = con self.con = con
return True return True
except ldap.LDAPError as e: # pylint: disable=no-member except ldap.LDAPError as e: # pylint: disable=no-member
self._error('LdapServer - Error connecting and binding to LDAP server : %s' % e,logging.CRITICAL) self._error('LdapServer - Error connecting and binding to LDAP server : %s' % e, logging.CRITICAL)
return False return False
return True return True
@staticmethod @staticmethod
def get_scope(scope): def get_scope(scope):
""" Map scope parameter to python-ldap value """
if scope == 'base': if scope == 'base':
return ldap.SCOPE_BASE # pylint: disable=no-member return ldap.SCOPE_BASE # pylint: disable=no-member
if scope == 'one': if scope == 'one':
@ -70,6 +76,7 @@ class LdapServer(object): # pylint: disable=useless-object-inheritance
raise Exception("Unknown LDAP scope '%s'" % scope) raise Exception("Unknown LDAP scope '%s'" % scope)
def search(self, basedn, filterstr=None, attrs=None, sizelimit=0, scope=None): def search(self, basedn, filterstr=None, attrs=None, sizelimit=0, scope=None):
""" Run a search on LDAP server """
res_id = self.con.search( res_id = self.con.search(
basedn, basedn,
self.get_scope(scope if scope else 'sub'), self.get_scope(scope if scope else 'sub'),
@ -79,7 +86,7 @@ class LdapServer(object): # pylint: disable=useless-object-inheritance
ret = {} ret = {}
c = 0 c = 0
while True: while True:
res_type, res_data = self.con.result(res_id,0) res_type, res_data = self.con.result(res_id, 0)
if res_data == [] or (sizelimit and c > sizelimit): if res_data == [] or (sizelimit and c > sizelimit):
break break
if res_type == ldap.RES_SEARCH_ENTRY: # pylint: disable=no-member if res_type == ldap.RES_SEARCH_ENTRY: # pylint: disable=no-member
@ -88,10 +95,12 @@ class LdapServer(object): # pylint: disable=useless-object-inheritance
return ret return ret
def get_object(self, dn, filterstr=None, attrs=None): def get_object(self, dn, filterstr=None, attrs=None):
""" Retrieve a LDAP object specified by its DN """
result = self.search(dn, filterstr=filterstr, scope='base', attrs=attrs) result = self.search(dn, filterstr=filterstr, scope='base', attrs=attrs)
return result[dn] if dn in result else None return result[dn] if dn in result else None
def paged_search(self, basedn, filterstr, attrs, scope='sub', pagesize=500): def paged_search(self, basedn, filterstr, attrs, scope='sub', pagesize=500):
""" Run a paged search on LDAP server """
assert not self.v2, "Paged search is not available on LDAP version 2" assert not self.v2, "Paged search is not available on LDAP version 2"
# Initialize SimplePagedResultsControl object # Initialize SimplePagedResultsControl object
page_control = SimplePagedResultsControl( page_control = SimplePagedResultsControl(
@ -161,18 +170,20 @@ class LdapServer(object): # pylint: disable=useless-object-inheritance
self.logger.debug("LdapServer - Paged search end: %d object(s) retreived in %d page(s) of %d object(s)", len(ret), pages_count, pagesize) self.logger.debug("LdapServer - Paged search end: %d object(s) retreived in %d page(s) of %d object(s)", len(ret), pages_count, pagesize)
return ret return ret
def add_object(self,dn,attrs): def add_object(self, dn, attrs):
""" Add an object in LDAP directory """
ldif = modlist.addModlist(attrs) ldif = modlist.addModlist(attrs)
try: try:
self.logger.debug("LdapServer - Add %s", dn) self.logger.debug("LdapServer - Add %s", dn)
self.con.add_s(dn,ldif) self.con.add_s(dn, ldif)
return True return True
except ldap.LDAPError as e: # pylint: disable=no-member except ldap.LDAPError as e: # pylint: disable=no-member
self._error("LdapServer - Error adding %s : %s" % (dn,e), logging.ERROR) self._error("LdapServer - Error adding %s : %s" % (dn, e), logging.ERROR)
return False return False
def update_object(self, dn, old, new, ignore_attrs=None, relax=False): def update_object(self, dn, old, new, ignore_attrs=None, relax=False):
""" Update an object in LDAP directory """
assert not relax or not self.v2, "Relax modification is not available on LDAP version 2" assert not relax or not self.v2, "Relax modification is not available on LDAP version 2"
ldif = modlist.modifyModlist( ldif = modlist.modifyModlist(
old, new, old, new,
@ -192,6 +203,7 @@ class LdapServer(object): # pylint: disable=useless-object-inheritance
@staticmethod @staticmethod
def update_need(old, new, ignore_attrs=None): def update_need(old, new, ignore_attrs=None):
""" Check if an update is need on a LDAP object based on its old and new attributes values """
ldif = modlist.modifyModlist( ldif = modlist.modifyModlist(
old, new, old, new,
ignore_attr_types=ignore_attrs if ignore_attrs else [] ignore_attr_types=ignore_attrs if ignore_attrs else []
@ -202,6 +214,7 @@ class LdapServer(object): # pylint: disable=useless-object-inheritance
@staticmethod @staticmethod
def get_changes(old, new, ignore_attrs=None): def get_changes(old, new, ignore_attrs=None):
""" Retrieve changes (as modlist) on an object based on its old and new attributes values """
return modlist.modifyModlist( return modlist.modifyModlist(
old, new, old, new,
ignore_attr_types=ignore_attrs if ignore_attrs else [] ignore_attr_types=ignore_attrs if ignore_attrs else []
@ -209,6 +222,7 @@ class LdapServer(object): # pylint: disable=useless-object-inheritance
@staticmethod @staticmethod
def format_changes(old, new, ignore_attrs=None, prefix=None): def format_changes(old, new, ignore_attrs=None, prefix=None):
""" Format changes (modlist) on an object based on its old and new attributes values to display/log it """
msg = [] msg = []
for (op, attr, val) in modlist.modifyModlist(old, new, ignore_attr_types=ignore_attrs if ignore_attrs else []): for (op, attr, val) in modlist.modifyModlist(old, new, ignore_attr_types=ignore_attrs if ignore_attrs else []):
if op == ldap.MOD_ADD: # pylint: disable=no-member if op == ldap.MOD_ADD: # pylint: disable=no-member
@ -226,6 +240,7 @@ class LdapServer(object): # pylint: disable=useless-object-inheritance
return '\n'.join(msg) return '\n'.join(msg)
def rename_object(self, dn, new_rdn, new_sup=None, delete_old=True): def rename_object(self, dn, new_rdn, new_sup=None, delete_old=True):
""" Rename an object in LDAP directory """
# If new_rdn is a complete DN, split new RDN and new superior DN # If new_rdn is a complete DN, split new RDN and new superior DN
if len(new_rdn.split(',')) > 1: if len(new_rdn.split(',')) > 1:
self.logger.debug( self.logger.debug(
@ -261,21 +276,24 @@ class LdapServer(object): # pylint: disable=useless-object-inheritance
return False return False
def drop_object(self, dn): def drop_object(self, dn):
""" Drop an object in LDAP directory """
try: try:
self.logger.debug("LdapServer - Delete %s", dn) self.logger.debug("LdapServer - Delete %s", dn)
self.con.delete_s(dn) self.con.delete_s(dn)
return True return True
except ldap.LDAPError as e: # pylint: disable=no-member except ldap.LDAPError as e: # pylint: disable=no-member
self._error("LdapServer - Error deleting %s : %s" % (dn,e), logging.ERROR) self._error("LdapServer - Error deleting %s : %s" % (dn, e), logging.ERROR)
return False return False
@staticmethod @staticmethod
def get_dn(obj): def get_dn(obj):
""" Retreive 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=None, default=None): def get_attr(obj, attr, all=None, default=None):
""" Retreive 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():
@ -289,13 +307,18 @@ class LdapServer(object): # pylint: disable=useless-object-inheritance
return obj[attr][0] return obj[attr][0]
return default return default
class LdapServerException(BaseException): class LdapServerException(BaseException):
def __init__(self,msg): """ Generic exception raised by LdapServer """
def __init__(self, msg):
BaseException.__init__(self, msg) BaseException.__init__(self, msg)
# #
# Helpers # LDAP date string helpers
# #
def parse_datetime(value, to_timezone=None, default_timezone=None, naive=None): def parse_datetime(value, to_timezone=None, default_timezone=None, naive=None):
""" """
Convert LDAP date string to datetime.datetime object Convert LDAP date string to datetime.datetime object
@ -335,6 +358,7 @@ def parse_datetime(value, to_timezone=None, default_timezone=None, naive=None):
return date.astimezone(to_timezone) return date.astimezone(to_timezone)
return date return date
def parse_date(value, to_timezone=None, default_timezone=None, naive=None): def parse_date(value, to_timezone=None, default_timezone=None, naive=None):
""" """
Convert LDAP date string to datetime.date object Convert LDAP date string to datetime.date object
@ -348,6 +372,7 @@ def parse_date(value, to_timezone=None, default_timezone=None, naive=None):
""" """
return parse_datetime(value, to_timezone, default_timezone, naive).date() return parse_datetime(value, to_timezone, default_timezone, naive).date()
def format_datetime(value, from_timezone=None, to_timezone=None, naive=None): def format_datetime(value, from_timezone=None, to_timezone=None, naive=None):
""" """
Convert datetime.datetime object to LDAP date string Convert datetime.datetime object to LDAP date string
@ -388,6 +413,7 @@ def format_datetime(value, from_timezone=None, to_timezone=None, naive=None):
datestring = datestring.replace('+0000', 'Z') datestring = datestring.replace('+0000', 'Z')
return datestring return datestring
def format_date(value, from_timezone=None, to_timezone=None, naive=None): def format_date(value, from_timezone=None, to_timezone=None, naive=None):
""" """
Convert datetime.date object to LDAP date string Convert datetime.date object to LDAP date string

View File

@ -9,21 +9,22 @@ import MySQLdb
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class MyDB: class MyDB:
""" MySQL client """ """ MySQL client """
host = "" host = ""
user = "" user = ""
pwd = "" pwd = ""
db = "" db = ""
con = 0 con = 0
def __init__(self, host, user, pwd, db): def __init__(self, host, user, pwd, db):
self.host = host self.host = host
self.user = user self.user = user
self.pwd = pwd self.pwd = pwd
self.db = db self.db = db
def connect(self): def connect(self):
""" Connect to MySQL server """ """ Connect to MySQL server """
@ -35,7 +36,7 @@ class MyDB:
log.fatal('Error connecting to MySQL server', exc_info=True) log.fatal('Error connecting to MySQL server', exc_info=True)
sys.exit(1) sys.exit(1)
def doSQL(self,sql): def doSQL(self, sql):
""" Run INSERT/UPDATE/DELETE/... SQL query """ """ Run INSERT/UPDATE/DELETE/... SQL query """
cursor = self.con.cursor() cursor = self.con.cursor()
try: try:

View File

@ -1,3 +1,7 @@
# -*- coding: utf-8 -*-
""" Opening hours helpers """
import datetime import datetime
import re import re
import time import time
@ -10,37 +14,39 @@ date_format = '%d/%m/%Y'
date_pattern = re.compile('^([0-9]{2})/([0-9]{2})/([0-9]{4})$') date_pattern = re.compile('^([0-9]{2})/([0-9]{2})/([0-9]{4})$')
time_pattern = re.compile('^([0-9]{1,2})h([0-9]{2})?$') time_pattern = re.compile('^([0-9]{1,2})h([0-9]{2})?$')
def easter_date(year): def easter_date(year):
a = year//100 a = year // 100
b = year%100 b = year % 100
c = (3*(a+25))//4 c = (3 * (a + 25)) // 4
d = (3*(a+25))%4 d = (3 * (a + 25)) % 4
e = (8*(a+11))//25 e = (8 * (a + 11)) // 25
f = (5*a+b)%19 f = (5 * a + b) % 19
g = (19*f+c-e)%30 g = (19 * f + c - e) % 30
h = (f+11*g)//319 h = (f + 11 * g) // 319
j = (60*(5-d)+b)//4 j = (60 * (5 - d) + b) // 4
k = (60*(5-d)+b)%4 k = (60 * (5 - d) + b) % 4
m = (2*j-k-g+h)%7 m = (2 * j - k - g + h) % 7
n = (g-h+m+114)//31 n = (g - h + m + 114) // 31
p = (g-h+m+114)%31 p = (g - h + m + 114) % 31
day = p+1 day = p + 1
month = n month = n
return datetime.date(year, month, day) return datetime.date(year, month, day)
def nonworking_french_public_days_of_the_year(year=None): def nonworking_french_public_days_of_the_year(year=None):
if year is None: if year is None:
year=datetime.date.today().year year = datetime.date.today().year
dp=easter_date(year) dp = easter_date(year)
return { return {
'1janvier': datetime.date(year, 1, 1), '1janvier': datetime.date(year, 1, 1),
'paques': dp, 'paques': dp,
'lundi_paques': (dp+datetime.timedelta(1)), 'lundi_paques': (dp + datetime.timedelta(1)),
'1mai': datetime.date(year, 5, 1), '1mai': datetime.date(year, 5, 1),
'8mai': datetime.date(year, 5, 8), '8mai': datetime.date(year, 5, 8),
'jeudi_ascension': (dp+datetime.timedelta(39)), 'jeudi_ascension': (dp + datetime.timedelta(39)),
'pentecote': (dp+datetime.timedelta(49)), 'pentecote': (dp + datetime.timedelta(49)),
'lundi_pentecote': (dp+datetime.timedelta(50)), 'lundi_pentecote': (dp + datetime.timedelta(50)),
'14juillet': datetime.date(year, 7, 14), '14juillet': datetime.date(year, 7, 14),
'15aout': datetime.date(year, 8, 15), '15aout': datetime.date(year, 8, 15),
'1novembre': datetime.date(year, 11, 1), '1novembre': datetime.date(year, 11, 1),
@ -49,8 +55,9 @@ def nonworking_french_public_days_of_the_year(year=None):
'saint_etienne': datetime.date(year, 12, 26), 'saint_etienne': datetime.date(year, 12, 26),
} }
def parse_exceptional_closures(values): def parse_exceptional_closures(values):
exceptional_closures=[] exceptional_closures = []
for value in values: for value in values:
days = [] days = []
hours_periods = [] hours_periods = []
@ -60,15 +67,15 @@ def parse_exceptional_closures(values):
continue continue
parts = word.split('-') parts = word.split('-')
if len(parts) == 1: if len(parts) == 1:
# ex : 31/02/2017 # ex: 31/02/2017
ptime = time.strptime(word, date_format) ptime = time.strptime(word, date_format)
date = datetime.date(ptime.tm_year, ptime.tm_mon, ptime.tm_mday) date = datetime.date(ptime.tm_year, ptime.tm_mon, ptime.tm_mday)
if date not in days: if date not in days:
days.append(date) days.append(date)
elif len(parts) == 2: elif len(parts) == 2:
# ex : 18/12/2017-20/12/2017 ou 9h-10h30 # ex: 18/12/2017-20/12/2017 ou 9h-10h30
if date_pattern.match(parts[0]) and date_pattern.match(parts[1]): if date_pattern.match(parts[0]) and date_pattern.match(parts[1]):
# ex : 18/12/2017-20/12/2017 # ex: 18/12/2017-20/12/2017
pstart = time.strptime(parts[0], date_format) pstart = time.strptime(parts[0], date_format)
pstop = time.strptime(parts[1], date_format) pstop = time.strptime(parts[1], date_format)
if pstop <= pstart: if pstop <= pstart:
@ -81,7 +88,7 @@ def parse_exceptional_closures(values):
days.append(date) days.append(date)
date += datetime.timedelta(days=1) date += datetime.timedelta(days=1)
else: else:
# ex : 9h-10h30 # ex: 9h-10h30
mstart = time_pattern.match(parts[0]) mstart = time_pattern.match(parts[0])
mstop = time_pattern.match(parts[1]) mstop = time_pattern.match(parts[1])
if not mstart or not mstop: if not mstart or not mstop:
@ -92,7 +99,7 @@ def parse_exceptional_closures(values):
raise ValueError('Time %s <= %s' % (parts[1], parts[0])) raise ValueError('Time %s <= %s' % (parts[1], parts[0]))
hours_periods.append({'start': hstart, 'stop': hstop}) hours_periods.append({'start': hstart, 'stop': hstop})
else: else:
raise ValueError('Invalid number of part in this word : "%s"' % word) raise ValueError('Invalid number of part in this word: "%s"' % word)
if not days: if not days:
raise ValueError('No days found in value "%s"' % value) raise ValueError('No days found in value "%s"' % value)
exceptional_closures.append({'days': days, 'hours_periods': hours_periods}) exceptional_closures.append({'days': days, 'hours_periods': hours_periods})
@ -100,82 +107,85 @@ def parse_exceptional_closures(values):
def parse_normal_opening_hours(values): def parse_normal_opening_hours(values):
normal_opening_hours=[] normal_opening_hours = []
for value in values: for value in values:
days=[] days = []
hours_periods=[] hours_periods = []
words=value.strip().split() words = value.strip().split()
for word in words: for word in words:
if word=='': if not word:
continue continue
parts=word.split('-') parts = word.split('-')
if len(parts)==1: if len(parts) == 1:
# ex : jeudi # ex: jeudi
if word not in week_days: if word not in week_days:
raise ValueError('"%s" is not a valid week day' % word) raise ValueError('"%s" is not a valid week day' % word)
if word not in days: if word not in days:
days.append(word) days.append(word)
elif len(parts)==2: elif len(parts) == 2:
# ex : lundi-jeudi ou 9h-10h30 # ex: lundi-jeudi ou 9h-10h30
if parts[0] in week_days and parts[1] in week_days: if parts[0] in week_days and parts[1] in week_days:
# ex : lundi-jeudi # ex: lundi-jeudi
if week_days.index(parts[1]) <= week_days.index(parts[0]): if week_days.index(parts[1]) <= week_days.index(parts[0]):
raise ValueError('"%s" is before "%s"' % (parts[1],parts[0])) raise ValueError('"%s" is before "%s"' % (parts[1], parts[0]))
started=False started = False
for d in week_days: for d in week_days:
if not started and d!=parts[0]: if not started and d != parts[0]:
continue continue
started=True started = True
if d not in days: if d not in days:
days.append(d) days.append(d)
if d==parts[1]: if d == parts[1]:
break break
else: else:
#ex : 9h-10h30 # ex: 9h-10h30
mstart=time_pattern.match(parts[0]) mstart = time_pattern.match(parts[0])
mstop=time_pattern.match(parts[1]) mstop = time_pattern.match(parts[1])
if not mstart or not mstop: if not mstart or not mstop:
raise ValueError('"%s" is not a valid time period' % word) raise ValueError('"%s" is not a valid time period' % word)
hstart=datetime.time(int(mstart.group(1)), int(mstart.group(2) or 0)) hstart = datetime.time(int(mstart.group(1)), int(mstart.group(2) or 0))
hstop=datetime.time(int(mstop.group(1)), int(mstop.group(2) or 0)) hstop = datetime.time(int(mstop.group(1)), int(mstop.group(2) or 0))
if hstop<=hstart: if hstop <= hstart:
raise ValueError('Time %s <= %s' % (parts[1],parts[0])) raise ValueError('Time %s <= %s' % (parts[1], parts[0]))
hours_periods.append({'start': hstart, 'stop': hstop}) hours_periods.append({'start': hstart, 'stop': hstop})
else: else:
raise ValueError('Invalid number of part in this word : "%s"' % word) raise ValueError('Invalid number of part in this word: "%s"' % word)
if not days and not hours_periods: if not days and not hours_periods:
raise ValueError('No days or hours period found in this value : "%s"' % value) raise ValueError('No days or hours period found in this value: "%s"' % value)
normal_opening_hours.append({'days': days, 'hours_periods': hours_periods}) normal_opening_hours.append({'days': days, 'hours_periods': hours_periods})
return normal_opening_hours return normal_opening_hours
def is_closed(normal_opening_hours_values=None, exceptional_closures_values=None,
nonworking_public_holidays_values=None, exceptional_closure_on_nonworking_public_days=False, def is_closed(
when=None, on_error='raise'): normal_opening_hours_values=None, exceptional_closures_values=None,
nonworking_public_holidays_values=None, exceptional_closure_on_nonworking_public_days=False,
when=None, on_error='raise'
):
if not when: if not when:
when = datetime.datetime.now() when = datetime.datetime.now()
when_date=when.date() when_date = when.date()
when_time=when.time() when_time = when.time()
when_weekday=week_days[when.timetuple().tm_wday] when_weekday = week_days[when.timetuple().tm_wday]
on_error_result=None on_error_result = None
if on_error=='closed': if on_error == 'closed':
on_error_result={'closed': True, 'exceptional_closure': False, 'exceptional_closure_all_day': False} on_error_result = {'closed': True, 'exceptional_closure': False, 'exceptional_closure_all_day': False}
elif on_error=='opened': elif on_error == 'opened':
on_error_result={'closed': False, 'exceptional_closure': False, 'exceptional_closure_all_day': False} on_error_result = {'closed': False, 'exceptional_closure': False, 'exceptional_closure_all_day': False}
log.debug("When = %s => date = %s / time = %s / week day = %s", when, when_date, when_time, when_weekday) log.debug("When = %s => date = %s / time = %s / week day = %s", when, when_date, when_time, when_weekday)
if nonworking_public_holidays_values: if nonworking_public_holidays_values:
log.debug("Nonworking public holidays: %s", nonworking_public_holidays_values) log.debug("Nonworking public holidays: %s", nonworking_public_holidays_values)
nonworking_days=nonworking_french_public_days_of_the_year() nonworking_days = nonworking_french_public_days_of_the_year()
for day in nonworking_public_holidays_values: for day in nonworking_public_holidays_values:
if day in nonworking_days and when_date==nonworking_days[day]: if day in nonworking_days and when_date == nonworking_days[day]:
log.debug("Non working day: %s", day) log.debug("Non working day: %s", day)
return {'closed': True, 'exceptional_closure': exceptional_closure_on_nonworking_public_days, 'exceptional_closure_all_day': exceptional_closure_on_nonworking_public_days} return {'closed': True, 'exceptional_closure': exceptional_closure_on_nonworking_public_days, 'exceptional_closure_all_day': exceptional_closure_on_nonworking_public_days}
if len(exceptional_closures_values)>0: if exceptional_closures_values:
try: try:
exceptional_closures=parse_exceptional_closures(exceptional_closures_values) exceptional_closures = parse_exceptional_closures(exceptional_closures_values)
log.debug('Exceptional closures: %s', exceptional_closures) log.debug('Exceptional closures: %s', exceptional_closures)
except Exception as e: except ValueError as e:
log.error("Fail to parse exceptional closures, consider as closed", exc_info=True) log.error("Fail to parse exceptional closures, consider as closed", exc_info=True)
if on_error_result is None: if on_error_result is None:
raise e from e raise e from e
@ -193,9 +203,9 @@ def is_closed(normal_opening_hours_values=None, exceptional_closures_values=None
if normal_opening_hours_values: if normal_opening_hours_values:
try: try:
normal_opening_hours=parse_normal_opening_hours(normal_opening_hours_values) normal_opening_hours = parse_normal_opening_hours(normal_opening_hours_values)
log.debug('Normal opening hours: %s', normal_opening_hours) log.debug('Normal opening hours: %s', normal_opening_hours)
except Exception: except ValueError as e: # pylint: disable=broad-except
log.error("Fail to parse normal opening hours, consider as closed", exc_info=True) log.error("Fail to parse normal opening hours, consider as closed", exc_info=True)
if on_error_result is None: if on_error_result is None:
raise e from e raise e from e

View File

@ -8,7 +8,8 @@ import progressbar
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class Pbar(object): # pylint: disable=useless-object-inheritance
class Pbar: # pylint: disable=useless-object-inheritance
""" """
Progress bar Progress bar

View File

@ -10,13 +10,14 @@ import psycopg2
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class PgDB: class PgDB:
""" PostgreSQL client """ """ PostgreSQL client """
host = "" host = ""
user = "" user = ""
pwd = "" pwd = ""
db = "" db = ""
con = 0 con = 0
@ -34,7 +35,11 @@ class PgDB:
""" Connect to PostgreSQL server """ """ Connect to PostgreSQL server """
if self.con == 0: if self.con == 0:
try: try:
con = psycopg2.connect("dbname='%s' user='%s' host='%s' password='%s'" % (self.db,self.user,self.host,self.pwd)) con = psycopg2.connect(
"dbname='%s' user='%s' host='%s' password='%s'" % (
self.db, self.user, self.host, self.pwd
)
)
self.con = con self.con = con
except Exception: except Exception:
log.fatal('An error occured during Postgresql database connection.', exc_info=1) log.fatal('An error occured during Postgresql database connection.', exc_info=1)
@ -131,7 +136,7 @@ class PgDB:
def insert(self, table, values, just_try=False): def insert(self, table, values, just_try=False):
""" Run INSERT SQL query """ """ Run INSERT SQL query """
sql=u"INSERT INTO %s (%s) VALUES (%s)" % (table, u', '.join(values.keys()), u", ".join(map(lambda x: self._quote_value(values[x]), values))) sql = u"INSERT INTO %s (%s) VALUES (%s)" % (table, u', '.join(values.keys()), u", ".join(map(lambda x: self._quote_value(values[x]), values)))
if just_try: if just_try:
log.debug(u"Just-try mode : execute INSERT query : %s", sql) log.debug(u"Just-try mode : execute INSERT query : %s", sql)
@ -145,11 +150,11 @@ class PgDB:
def update(self, table, values, where_clauses, where_op=u'AND', just_try=False): def update(self, table, values, where_clauses, where_op=u'AND', just_try=False):
""" Run UPDATE SQL query """ """ Run UPDATE SQL query """
where=self._format_where_clauses(where_clauses, where_op=where_op) where = self._format_where_clauses(where_clauses, where_op=where_op)
if not where: if not where:
return False return False
sql=u"UPDATE %s SET %s WHERE %s" % (table, u", ".join(map(lambda x: "%s=%s" % (x, self._quote_value(values[x])), values)), where) sql = u"UPDATE %s SET %s WHERE %s" % (table, u", ".join(map(lambda x: "%s=%s" % (x, self._quote_value(values[x])), values)), where)
if just_try: if just_try:
log.debug(u"Just-try mode : execute UPDATE query : %s", sql) log.debug(u"Just-try mode : execute UPDATE query : %s", sql)
@ -163,11 +168,11 @@ class PgDB:
def delete(self, table, where_clauses, where_op=u'AND', just_try=False): def delete(self, table, where_clauses, where_op=u'AND', just_try=False):
""" Run DELETE SQL query """ """ Run DELETE SQL query """
where=self._format_where_clauses(where_clauses, where_op=where_op) where = self._format_where_clauses(where_clauses, where_op=where_op)
if not where: if not where:
return False return False
sql=u"DELETE FROM %s WHERE %s" % (table, where) sql = u"DELETE FROM %s WHERE %s" % (table, where)
if just_try: if just_try:
log.debug(u"Just-try mode : execute DELETE query : %s", sql) log.debug(u"Just-try mode : execute DELETE query : %s", sql)
@ -191,7 +196,7 @@ class PgDB:
sql += u" FROM " + table sql += u" FROM " + table
if where_clauses: if where_clauses:
where=self._format_where_clauses(where_clauses, where_op=where_op) where = self._format_where_clauses(where_clauses, where_op=where_op)
if not where: if not where:
return False return False

View File

@ -8,7 +8,8 @@ import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class Report(object): # pylint: disable=useless-object-inheritance
class Report: # pylint: disable=useless-object-inheritance
""" Logging report """ """ Logging report """
content = [] content = []

View File

@ -5,8 +5,8 @@ import datetime
import logging import logging
import sys import sys
import argparse
import getpass import getpass
from mako.template import Template as MakoTemplate
from mylib.scripts.helpers import get_opts_parser, add_email_opts from mylib.scripts.helpers import get_opts_parser, add_email_opts
from mylib.scripts.helpers import init_logging, init_email_client from mylib.scripts.helpers import init_logging, init_email_client
@ -14,7 +14,8 @@ from mylib.scripts.helpers import init_logging, init_email_client
log = logging.getLogger('mylib.scripts.email_test') log = logging.getLogger('mylib.scripts.email_test')
def main(argv=None): #pylint: disable=too-many-locals,too-many-statements
def main(argv=None): # pylint: disable=too-many-locals,too-many-statements
""" Script main """ """ Script main """
if argv is None: if argv is None:
argv = sys.argv[1:] argv = sys.argv[1:]

View File

@ -9,8 +9,9 @@ from mylib.email import EmailClient
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
def init_logging(options, name, report=None): def init_logging(options, name, report=None):
""" Initialize logs """ """ Initialize logging from calling script options """
logformat = '%(asctime)s - ' + name + ' - %(levelname)s - %(message)s' logformat = '%(asctime)s - ' + name + ' - %(levelname)s - %(message)s'
if options.debug: if options.debug:
loglevel = logging.DEBUG loglevel = logging.DEBUG
@ -172,6 +173,7 @@ def add_email_opts(parser):
def init_email_client(options, **kwargs): def init_email_client(options, **kwargs):
""" Initialize email client from calling script options """
log.info('Initialize Email client') log.info('Initialize Email client')
return EmailClient( return EmailClient(
smtp_host=options.email_smtp_host, smtp_host=options.email_smtp_host,

View File

@ -8,14 +8,15 @@ import sys
import dateutil.tz import dateutil.tz
import pytz import pytz
from mylib.ldap import format_datetime,format_date, parse_datetime, parse_date from mylib.ldap import format_datetime, format_date, parse_datetime, parse_date
from mylib.scripts.helpers import get_opts_parser from mylib.scripts.helpers import get_opts_parser
from mylib.scripts.helpers import init_logging from mylib.scripts.helpers import init_logging
log = logging.getLogger('mylib.scripts.ldap_test') log = logging.getLogger('mylib.scripts.ldap_test')
def main(argv=None): #pylint: disable=too-many-locals,too-many-statements
def main(argv=None): # pylint: disable=too-many-locals,too-many-statements
""" Script main """ """ Script main """
if argv is None: if argv is None:
argv = sys.argv[1:] argv = sys.argv[1:]
@ -24,6 +25,9 @@ def main(argv=None): #pylint: disable=too-many-locals,too-many-statements
parser = get_opts_parser(just_try=True) parser = get_opts_parser(just_try=True)
options = parser.parse_args() options = parser.parse_args()
# Initialize logs
init_logging(options, 'Test LDAP helpers')
now = datetime.datetime.now().replace(tzinfo=dateutil.tz.tzlocal()) now = datetime.datetime.now().replace(tzinfo=dateutil.tz.tzlocal())
print("Now = %s" % now) print("Now = %s" % now)
@ -50,7 +54,6 @@ def main(argv=None): #pylint: disable=too-many-locals,too-many-statements
print("format_date (to_timezone=Tokyo) : %s" % format_date(now, to_timezone='Asia/Tokyo')) print("format_date (to_timezone=Tokyo) : %s" % format_date(now, to_timezone='Asia/Tokyo'))
print("format_date (naive=True) : %s" % format_date(now, naive=True)) print("format_date (naive=True) : %s" % format_date(now, naive=True))
print("parse_datetime : %s" % parse_datetime(datestring_now)) print("parse_datetime : %s" % parse_datetime(datestring_now))
print("parse_datetime (default_timezone=utc) : %s" % parse_datetime(datestring_now[0:-1], default_timezone=pytz.utc)) print("parse_datetime (default_timezone=utc) : %s" % parse_datetime(datestring_now[0:-1], default_timezone=pytz.utc))
print("parse_datetime (default_timezone=local) : %s" % parse_datetime(datestring_now[0:-1], default_timezone=dateutil.tz.tzlocal())) print("parse_datetime (default_timezone=local) : %s" % parse_datetime(datestring_now[0:-1], default_timezone=dateutil.tz.tzlocal()))

View File

@ -12,7 +12,8 @@ from mylib.scripts.helpers import init_logging
log = logging.getLogger('mylib.scripts.pbar_test') log = logging.getLogger('mylib.scripts.pbar_test')
def main(argv=None): #pylint: disable=too-many-locals,too-many-statements
def main(argv=None): # pylint: disable=too-many-locals,too-many-statements
""" Script main """ """ Script main """
if argv is None: if argv is None:
argv = sys.argv[1:] argv = sys.argv[1:]

View File

@ -11,7 +11,8 @@ from mylib.scripts.helpers import init_logging, init_email_client
log = logging.getLogger('mylib.scripts.report_test') log = logging.getLogger('mylib.scripts.report_test')
def main(argv=None): #pylint: disable=too-many-locals,too-many-statements
def main(argv=None): # pylint: disable=too-many-locals,too-many-statements
""" Script main """ """ Script main """
if argv is None: if argv is None:
argv = sys.argv[1:] argv = sys.argv[1:]

2
setup.cfg Normal file
View File

@ -0,0 +1,2 @@
[flake8]
ignore = E501

View File

@ -43,6 +43,7 @@ def test_parse_exceptional_closures_full_days_period():
} }
] ]
def test_parse_exceptional_closures_invalid_days_period(): def test_parse_exceptional_closures_invalid_days_period():
with pytest.raises(ValueError): with pytest.raises(ValueError):
opening_hours.parse_exceptional_closures(["22/09/2017-21/09/2017"]) opening_hours.parse_exceptional_closures(["22/09/2017-21/09/2017"])
@ -156,21 +157,22 @@ def test_parse_normal_opening_hours_multiple_periods():
# Tests on is_closed # Tests on is_closed
# #
exceptional_closures = ["22/09/2017", "20/09/2017-22/09/2017", "20/09/2017-22/09/2017 18/09/2017", "25/11/2017", "26/11/2017 9h30-12h30"] exceptional_closures = ["22/09/2017", "20/09/2017-22/09/2017", "20/09/2017-22/09/2017 18/09/2017", "25/11/2017", "26/11/2017 9h30-12h30"]
normal_opening_hours = ["lundi-mardi jeudi 9h30-12h30 14h-16h30", "mercredi vendredi 9h30-12h30 14h-17h"] normal_opening_hours = ["lundi-mardi jeudi 9h30-12h30 14h-16h30", "mercredi vendredi 9h30-12h30 14h-17h"]
nonworking_public_holidays = [ nonworking_public_holidays = [
'1janvier', '1janvier',
'paques', 'paques',
'lundi_paques', 'lundi_paques',
'1mai', '1mai',
'8mai', '8mai',
'jeudi_ascension', 'jeudi_ascension',
'lundi_pentecote', 'lundi_pentecote',
'14juillet', '14juillet',
'15aout', '15aout',
'1novembre', '1novembre',
'11novembre', '11novembre',
'noel', 'noel',
] ]