From d4015d6566e15a005ad6fd6cdfb2c477bce5e946 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Thu, 23 Oct 2014 14:51:51 -0400 Subject: [PATCH 1/3] ENH: remove obsolete code for python < 2.6 (we support >= 2.6) --- fail2ban/server/asyncserver.py | 8 ++------ fail2ban/tests/samplestestcase.py | 6 +----- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/fail2ban/server/asyncserver.py b/fail2ban/server/asyncserver.py index 14673a99..6e71da77 100644 --- a/fail2ban/server/asyncserver.py +++ b/fail2ban/server/asyncserver.py @@ -149,12 +149,8 @@ class AsyncServer(asyncore.dispatcher): self.__init = True # TODO Add try..catch # There's a bug report for Python 2.6/3.0 that use_poll=True yields some 2.5 incompatibilities: - if sys.version_info >= (2, 6): # if python 2.6 or greater... - logSys.debug("Detected Python 2.6 or greater. asyncore.loop() not using poll") - asyncore.loop(use_poll = False) # fixes the "Unexpected communication problem" issue on Python 2.6 and 3.0 - else: # pragma: no cover - logSys.debug("NOT Python 2.6/3.* - asyncore.loop() using poll") - asyncore.loop(use_poll = True) + logSys.debug("Detected Python 2.6 or greater. asyncore.loop() not using poll") + asyncore.loop(use_poll=False) # fixes the "Unexpected communication problem" issue on Python 2.6 and 3.0 ## # Stops the communication server. diff --git a/fail2ban/tests/samplestestcase.py b/fail2ban/tests/samplestestcase.py index e0831184..2c18a504 100644 --- a/fail2ban/tests/samplestestcase.py +++ b/fail2ban/tests/samplestestcase.py @@ -24,11 +24,7 @@ __license__ = "GPL" import unittest, sys, os, fileinput, re, time, datetime, inspect -if sys.version_info >= (2, 6): - import json -else: - import simplejson as json - next = lambda x: x.next() +import json from ..server.filter import Filter from ..client.filterreader import FilterReader From caa6006a3179513962f960d57a8fca9e6199951b Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Sat, 25 Oct 2014 09:25:18 -0400 Subject: [PATCH 2/3] ENH: do use @staticmethod (we are well beyond support of 2.4 now) --- bin/fail2ban-client | 3 +-- fail2ban/client/csocket.py | 3 +-- fail2ban/client/jailreader.py | 3 +-- fail2ban/server/asyncserver.py | 3 +-- fail2ban/server/banmanager.py | 3 +-- fail2ban/server/filter.py | 21 +++++++-------------- fail2ban/server/mytime.py | 14 +++++--------- 7 files changed, 17 insertions(+), 33 deletions(-) diff --git a/bin/fail2ban-client b/bin/fail2ban-client index 0c6999c1..866a5287 100755 --- a/bin/fail2ban-client +++ b/bin/fail2ban-client @@ -419,12 +419,11 @@ class Fail2banClient: ret = False return ret - #@staticmethod + @staticmethod def dumpConfig(cmd): for c in cmd: print c return True - dumpConfig = staticmethod(dumpConfig) class ServerExecutionException(Exception): diff --git a/fail2ban/client/csocket.py b/fail2ban/client/csocket.py index 1d522f6c..921b0de5 100644 --- a/fail2ban/client/csocket.py +++ b/fail2ban/client/csocket.py @@ -57,7 +57,7 @@ class CSocket: self.__csock.close() return ret - #@staticmethod + @staticmethod def receive(sock): msg = EMPTY_BYTES while msg.rfind(CSocket.END_STRING) == -1: @@ -66,4 +66,3 @@ class CSocket: raise RuntimeError, "socket connection broken" msg = msg + chunk return loads(msg) - receive = staticmethod(receive) diff --git a/fail2ban/client/jailreader.py b/fail2ban/client/jailreader.py index ffdc5e26..84cc5e2a 100644 --- a/fail2ban/client/jailreader.py +++ b/fail2ban/client/jailreader.py @@ -220,7 +220,7 @@ class JailReader(ConfigReader): stream.insert(0, ["add", self.__name, backend]) return stream - #@staticmethod + @staticmethod def extractOptions(option): match = JailReader.optionCRE.match(option) if not match: @@ -235,4 +235,3 @@ class JailReader(ConfigReader): val for val in optmatch.group(2,3,4) if val is not None][0] option_opts[opt.strip()] = value.strip() return option_name, option_opts - extractOptions = staticmethod(extractOptions) diff --git a/fail2ban/server/asyncserver.py b/fail2ban/server/asyncserver.py index 6e71da77..a54d41a1 100644 --- a/fail2ban/server/asyncserver.py +++ b/fail2ban/server/asyncserver.py @@ -171,12 +171,11 @@ class AsyncServer(asyncore.dispatcher): # @param sock: socket file. - #@staticmethod + @staticmethod def __markCloseOnExec(sock): fd = sock.fileno() flags = fcntl.fcntl(fd, fcntl.F_GETFD) fcntl.fcntl(fd, fcntl.F_SETFD, flags|fcntl.FD_CLOEXEC) - __markCloseOnExec = staticmethod(__markCloseOnExec) ## # AsyncServerException is used to wrap communication exceptions. diff --git a/fail2ban/server/banmanager.py b/fail2ban/server/banmanager.py index b24fa9e5..c21cad45 100644 --- a/fail2ban/server/banmanager.py +++ b/fail2ban/server/banmanager.py @@ -126,7 +126,7 @@ class BanManager: # @param ticket the FailTicket # @return a BanTicket - #@staticmethod + @staticmethod def createBanTicket(ticket): ip = ticket.getIP() #lastTime = ticket.getTime() @@ -134,7 +134,6 @@ class BanManager: banTicket = BanTicket(ip, lastTime, ticket.getMatches()) banTicket.setAttempt(ticket.getAttempt()) return banTicket - createBanTicket = staticmethod(createBanTicket) ## # Add a ban ticket. diff --git a/fail2ban/server/filter.py b/fail2ban/server/filter.py index d1c9d2ad..c886bf35 100644 --- a/fail2ban/server/filter.py +++ b/fail2ban/server/filter.py @@ -838,7 +838,7 @@ class DNSUtils: IP_CRE = re.compile("^(?:\d{1,3}\.){3}\d{1,3}$") - #@staticmethod + @staticmethod def dnsToIp(dns): """ Convert a DNS into an IP address using the Python socket module. Thanks to Kevin Drapel. @@ -853,9 +853,8 @@ class DNSUtils: logSys.warning("Socket error raised trying to resolve hostname %s: %s" % (dns, e)) return list() - dnsToIp = staticmethod(dnsToIp) - #@staticmethod + @staticmethod def searchIP(text): """ Search if an IP address if directly available and return it. @@ -865,9 +864,8 @@ class DNSUtils: return match else: return None - searchIP = staticmethod(searchIP) - #@staticmethod + @staticmethod def isValidIP(string): """ Return true if str is a valid IP """ @@ -877,9 +875,8 @@ class DNSUtils: return True except socket.error: return False - isValidIP = staticmethod(isValidIP) - #@staticmethod + @staticmethod def textToIp(text, useDns): """ Return the IP of DNS found in a given text. """ @@ -901,9 +898,8 @@ class DNSUtils: text, ipList) return ipList - textToIp = staticmethod(textToIp) - #@staticmethod + @staticmethod def cidr(i, n): """ Convert an IP address string with a CIDR mask into a 32-bit integer. @@ -911,18 +907,15 @@ class DNSUtils: # 32-bit IPv4 address mask MASK = 0xFFFFFFFFL return ~(MASK >> n) & MASK & DNSUtils.addr2bin(i) - cidr = staticmethod(cidr) - #@staticmethod + @staticmethod def addr2bin(string): """ Convert a string IPv4 address into an unsigned integer. """ return struct.unpack("!L", socket.inet_aton(string))[0] - addr2bin = staticmethod(addr2bin) - #@staticmethod + @staticmethod def bin2addr(addr): """ Convert a numeric IPv4 address into string n.n.n.n form. """ return socket.inet_ntoa(struct.pack("!L", addr)) - bin2addr = staticmethod(bin2addr) diff --git a/fail2ban/server/mytime.py b/fail2ban/server/mytime.py index 96c7f8ab..a27f575b 100644 --- a/fail2ban/server/mytime.py +++ b/fail2ban/server/mytime.py @@ -43,48 +43,44 @@ class MyTime: # # @param t the time to set or None - #@staticmethod + @staticmethod def setTime(t): MyTime.myTime = t - setTime = staticmethod(setTime) ## # Equivalent to time.time() # # @return time.time() if setTime was called with None - #@staticmethod + @staticmethod def time(): if MyTime.myTime is None: return time.time() else: return MyTime.myTime - time = staticmethod(time) ## # Equivalent to time.gmtime() # # @return time.gmtime() if setTime was called with None - #@staticmethod + @staticmethod def gmtime(): if MyTime.myTime is None: return time.gmtime() else: return time.gmtime(MyTime.myTime) - gmtime = staticmethod(gmtime) - #@staticmethod + @staticmethod def now(): if MyTime.myTime is None: return datetime.datetime.now() else: return datetime.datetime.fromtimestamp(MyTime.myTime) - now = staticmethod(now) + @staticmethod def localtime(x=None): if MyTime.myTime is None or x is not None: return time.localtime(x) else: return time.localtime(MyTime.myTime) - localtime = staticmethod(localtime) From e1a5decc00a49bf24702b02de9f5ece81a1b84b9 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Sat, 25 Oct 2014 09:34:37 -0400 Subject: [PATCH 3/3] DOC: adjust docs in mytime to place docs into docstrings --- fail2ban/server/mytime.py | 62 +++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/fail2ban/server/mytime.py b/fail2ban/server/mytime.py index a27f575b..f284379e 100644 --- a/fail2ban/server/mytime.py +++ b/fail2ban/server/mytime.py @@ -26,46 +26,48 @@ import time, datetime ## # MyTime class. # -# This class is a wrapper around time.time() and time.gmtime(). When -# performing unit test, it is very useful to get a fixed value from these -# functions. -# Thus, time.time() and time.gmtime() should never be called directly. -# This wrapper should be called instead. The API are equivalent. class MyTime: - + """A wrapper around time module primarily for testing purposes + + This class is a wrapper around time.time() and time.gmtime(). When + performing unit test, it is very useful to get a fixed value from + these functions. Thus, time.time() and time.gmtime() should never + be called directly. This wrapper should be called instead. The API + are equivalent. + """ + myTime = None - - ## - # Sets the current time. - # - # Use None in order to always get the real current time. - # - # @param t the time to set or None - + @staticmethod def setTime(t): + """Set current time. + + Use None in order to always get the real current time. + + @param t the time to set or None + """ + MyTime.myTime = t - - ## - # Equivalent to time.time() - # - # @return time.time() if setTime was called with None - + @staticmethod def time(): + """Decorate time.time() for the purpose of testing mocking + + @return time.time() if setTime was called with None + """ + if MyTime.myTime is None: return time.time() else: return MyTime.myTime - - ## - # Equivalent to time.gmtime() - # - # @return time.gmtime() if setTime was called with None - + @staticmethod def gmtime(): + """Decorate time.gmtime() for the purpose of testing mocking + + @return time.gmtime() if setTime was called with None + """ if MyTime.myTime is None: return time.gmtime() else: @@ -73,6 +75,10 @@ class MyTime: @staticmethod def now(): + """Decorate datetime.now() for the purpose of testing mocking + + @return datetime.now() if setTime was called with None + """ if MyTime.myTime is None: return datetime.datetime.now() else: @@ -80,6 +86,10 @@ class MyTime: @staticmethod def localtime(x=None): + """Decorate time.localtime() for the purpose of testing mocking + + @return time.localtime() if setTime was called with None + """ if MyTime.myTime is None or x is not None: return time.localtime(x) else: