Revision: 1239
Author: g.rodola
Date: Sun Dec 8 21:40:25 2013 UTC
Log: pep8ify
http://code.google.com/p/pyftpdlib/source/detail?r=1239
Modified:
/trunk/demo/anti_flood_ftpd.py
/trunk/demo/tls_ftpd.py
/trunk/demo/unix_daemon.py
/trunk/demo/unix_ftpd.py
/trunk/demo/winnt_ftpd.py
/trunk/pyftpdlib/__init__.py
/trunk/pyftpdlib/__main__.py
/trunk/pyftpdlib/authorizers.py
/trunk/pyftpdlib/filesystems.py
/trunk/pyftpdlib/ftpserver.py
/trunk/pyftpdlib/handlers.py
/trunk/pyftpdlib/ioloop.py
/trunk/pyftpdlib/log.py
/trunk/pyftpdlib/servers.py
/trunk/setup.py
/trunk/test/bench.py
/trunk/test/test_contrib.py
/trunk/test/test_ftpd.py
=======================================
--- /trunk/demo/anti_flood_ftpd.py Tue Feb 19 11:25:49 2013 UTC
+++ /trunk/demo/anti_flood_ftpd.py Sun Dec 8 21:40:25 2013 UTC
@@ -51,7 +51,8 @@
def __init__(self, *args, **kwargs):
FTPHandler.__init__(self, *args, **kwargs)
self.processed_cmds = 0
- self.pcmds_callback = self.ioloop.call_every(1,
self.check_processed_cmds)
+ self.pcmds_callback = \
+ self.ioloop.call_every(1, self.check_processed_cmds)
def on_connect(self):
# called when client connects.
=======================================
--- /trunk/demo/tls_ftpd.py Tue Feb 19 11:25:49 2013 UTC
+++ /trunk/demo/tls_ftpd.py Sun Dec 8 21:40:25 2013 UTC
@@ -41,9 +41,11 @@
from pyftpdlib.handlers import TLS_FTPHandler
from pyftpdlib.servers import FTPServer
+
CERTFILE = os.path.abspath(os.path.join(os.path.dirname(__file__),
"keycert.pem"))
+
def main():
authorizer = DummyAuthorizer()
authorizer.add_user('user', '12345', '.', perm='elradfmw')
=======================================
--- /trunk/demo/unix_daemon.py Tue Feb 19 11:25:49 2013 UTC
+++ /trunk/demo/unix_daemon.py Sun Dec 8 21:40:25 2013 UTC
@@ -79,11 +79,13 @@
LOG_FILE = "/var/log/pyftpdlib.log"
WORKDIR = os.getcwd()
UMASK = 0
-
+
+
def print_(s):
sys.stdout.write(s + '\n')
sys.stdout.flush()
+
def pid_exists(pid):
"""Return True if a process with the given PID is currently running."""
try:
@@ -94,6 +96,7 @@
else:
return True
+
def get_pid():
"""Return the PID saved in the pid file if possible, else None."""
try:
@@ -104,6 +107,7 @@
if err.errno != errno.ENOENT:
raise
+
def stop():
"""Keep attempting to stop the daemon for 5 seconds, first using
SIGTERM, then using SIGKILL.
@@ -132,6 +136,7 @@
sys.exit("\ncould not kill daemon (pid %s)" % pid)
time.sleep(0.1)
+
def status():
"""Print daemon status and exit."""
pid = get_pid()
@@ -141,6 +146,7 @@
print_("daemon running with pid %s" % pid)
sys.exit(0)
+
def get_server():
"""Return a pre-configured FTP server instance."""
handler = FTPHandler
@@ -149,25 +155,26 @@
server = FTPServer((HOST, PORT), handler)
return server
+
def daemonize():
"""A wrapper around python-daemonize context manager."""
def _daemonize():
- pid = os.fork()
+ pid = os.fork()
if pid > 0:
# exit first parent
- sys.exit(0)
-
+ sys.exit(0)
+
# decouple from parent environment
- os.chdir(WORKDIR)
- os.setsid()
- os.umask(0)
-
- # do second fork
- pid = os.fork()
+ os.chdir(WORKDIR)
+ os.setsid()
+ os.umask(0)
+
+ # do second fork
+ pid = os.fork()
if pid > 0:
# exit from second parent
- sys.exit(0)
-
+ sys.exit(0)
+
# redirect standard file descriptors
sys.stdout.flush()
sys.stderr.flush()
@@ -177,10 +184,10 @@
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
-
+
# write pidfile
pid = str(os.getpid())
- f = open(PID_FILE,'w')
+ f = open(PID_FILE, 'w')
f.write("%s\n" % pid)
f.close()
atexit.register(lambda: os.remove(PID_FILE))
@@ -190,7 +197,7 @@
sys.exit('daemon already running (pid %s)' % pid)
# instance FTPd before daemonizing, so that in case of problems we
# get an exception here and exit immediately
- server = get_server()
+ server = get_server()
_daemonize()
server.serve_forever()
=======================================
--- /trunk/demo/unix_ftpd.py Tue Feb 19 11:25:49 2013 UTC
+++ /trunk/demo/unix_ftpd.py Sun Dec 8 21:40:25 2013 UTC
@@ -43,7 +43,8 @@
def main():
- authorizer = UnixAuthorizer(rejected_users=["root"],
require_valid_shell=True)
+ authorizer = UnixAuthorizer(rejected_users=["root"],
+ require_valid_shell=True)
handler = FTPHandler
handler.authorizer = authorizer
handler.abstracted_fs = UnixFilesystem
=======================================
--- /trunk/demo/winnt_ftpd.py Tue Feb 19 11:25:49 2013 UTC
+++ /trunk/demo/winnt_ftpd.py Sun Dec 8 21:40:25 2013 UTC
@@ -47,7 +47,8 @@
# Use Guest user with empty password to handle anonymous sessions.
# Guest user must be enabled first, empty password set and profile
# directory specified.
- #authorizer = WindowsAuthorizer(anonymous_user="Guest",
anonymous_password="")
+ # authorizer = WindowsAuthorizer(anonymous_user="Guest",
+ # anonymous_password="")
handler = FTPHandler
handler.authorizer = authorizer
ftpd = FTPServer(('', 21), handler)
=======================================
--- /trunk/pyftpdlib/__init__.py Thu Nov 7 22:17:19 2013 UTC
+++ /trunk/pyftpdlib/__init__.py Sun Dec 8 21:40:25 2013 UTC
@@ -88,15 +88,16 @@
[I 13-02-19 10:55:42] use sendfile(2): True
[I 13-02-19 10:55:45] 127.0.0.1:34178-[] FTP session opened (connect)
[I 13-02-19 10:55:48] 127.0.0.1:34178-[user] USER 'user' logged in.
-[I 13-02-19 10:56:27] 127.0.0.1:34179-[user] RETR /home/giampaolo/.vimrc
completed=1 bytes=1700 seconds=0.001
+[I 13-02-19 10:56:27] 127.0.0.1:34179-[user] RETR /home/giampaolo/.vimrc
+ completed=1 bytes=1700 seconds=0.001
[I 13-02-19 10:56:39] 127.0.0.1:34179-[user] FTP session closed
(disconnect).
"""
-import logging
+
+__ver__ = '1.3.0'
+__author__ = "Giampaolo Rodola' <
g.ro...@gmail.com>"
+__web__ = '
http://code.google.com/p/pyftpdlib/'
-__ver__ = '1.3.0'
-__author__ = "Giampaolo Rodola' <
g.ro...@gmail.com>"
-__web__ = '
http://code.google.com/p/pyftpdlib/'
def _depwarn(msg):
"""
=======================================
--- /trunk/pyftpdlib/__main__.py Sat Aug 24 17:48:45 2013 UTC
+++ /trunk/pyftpdlib/__main__.py Sun Dec 8 21:40:25 2013 UTC
@@ -57,6 +57,7 @@
result.append(help_text)
return ''.join(result)
+
def main():
"""Start a stand alone anonymous FTP server."""
usage = "python -m pyftpdlib.ftpserver [options]"
=======================================
--- /trunk/pyftpdlib/authorizers.py Tue Nov 26 15:27:59 2013 UTC
+++ /trunk/pyftpdlib/authorizers.py Sun Dec 8 21:40:25 2013 UTC
@@ -303,8 +303,8 @@
def __init__(self):
"""Check for errors in the constructor."""
if self.rejected_users and self.allowed_users:
- raise AuthorizerError("rejected_users and allowed_users
options are "
- "mutually exclusive")
+ raise AuthorizerError("rejected_users and allowed_users
options "
+ "are mutually exclusive")
users = self._get_system_users()
for user in (self.allowed_users or self.rejected_users):
@@ -584,8 +584,8 @@
raise AuthorizerError("user %s has not a valid
shell"
% username)
- def override_user(self, username, password=None, homedir=None,
perm=None,
- msg_login=None, msg_quit=None):
+ def override_user(self, username, password=None, homedir=None,
+ perm=None, msg_login=None, msg_quit=None):
"""Overrides the options specified in the class constructor
for a specific user.
"""
@@ -613,7 +613,8 @@
password,
handler)
if self.require_valid_shell and username != 'anonymous':
if not self._has_valid_shell(username):
- raise AuthenticationFailed(self.msg_invalid_shell %
username)
+ raise AuthenticationFailed(
+ self.msg_invalid_shell % username)
@replace_anonymous
def has_user(self, username):
@@ -713,9 +714,10 @@
@replace_anonymous
def impersonate_user(self, username, password):
"""Impersonate the security context of another user."""
- handler = win32security.LogonUser(username, None, password,
-
win32con.LOGON32_LOGON_INTERACTIVE,
-
win32con.LOGON32_PROVIDER_DEFAULT)
+ handler = win32security.LogonUser(
+ username, None, password,
+ win32con.LOGON32_LOGON_INTERACTIVE,
+ win32con.LOGON32_PROVIDER_DEFAULT)
win32security.ImpersonateLoggedOnUser(handler)
handler.Close()
@@ -738,13 +740,13 @@
except pywintypes.error:
err = sys.exc_info()[1]
raise AuthorizerError(err)
- path = r"SOFTWARE\Microsoft\Windows
NT\CurrentVersion\ProfileList" + \
- "\\" + sid
+ path = r"SOFTWARE\Microsoft\Windows NT" \
+ r"\CurrentVersion\ProfileList" + "\\" + sid
try:
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path)
except WindowsError:
- raise AuthorizerError("No profile directory defined for
user %s"
- % username)
+ raise AuthorizerError(
+ "No profile directory defined for user %s" % username)
value = winreg.QueryValueEx(key, "ProfileImagePath")[0]
home = win32api.ExpandEnvironmentStrings(value)
if not PY3 and not isinstance(home, unicode):
@@ -756,7 +758,8 @@
"""Return all users defined on the Windows system."""
# XXX - Does Windows allow usernames with chars outside of
# ASCII set? In that case we need to convert this to unicode.
- return [entry['name'] for entry in win32net.NetUserEnum(None,
0)[0]]
+ return [entry['name'] for entry in
+ win32net.NetUserEnum(None, 0)[0]]
def get_msg_login(self, username):
return "Login successful."
@@ -852,8 +855,8 @@
self.anonymous_password)
self.terminate_impersonation(None)
- def override_user(self, username, password=None, homedir=None,
perm=None,
- msg_login=None, msg_quit=None):
+ def override_user(self, username, password=None, homedir=None,
+ perm=None, msg_login=None, msg_quit=None):
"""Overrides the options specified in the class constructor
for a specific user.
"""
@@ -880,8 +883,8 @@
if overridden_password != password:
raise AuthenticationFailed(self.msg_wrong_password)
else:
- BaseWindowsAuthorizer.validate_authentication(self,
username,
- password,
handler)
+ BaseWindowsAuthorizer.validate_authentication(
+ self, username, password, handler)
def impersonate_user(self, username, password):
"""Impersonate the security context of another user."""
=======================================
--- /trunk/pyftpdlib/filesystems.py Tue Feb 19 10:13:09 2013 UTC
+++ /trunk/pyftpdlib/filesystems.py Sun Dec 8 21:40:25 2013 UTC
@@ -49,8 +49,8 @@
__all__ = ['FilesystemError', 'AbstractedFS']
-_months_map = {1:'Jan', 2:'Feb', 3:'Mar', 4:'Apr', 5:'May', 6:'Jun',
7:'Jul',
- 8:'Aug', 9:'Sep', 10:'Oct', 11:'Nov', 12:'Dec'}
+_months_map = {1: 'Jan', 2: 'Feb', 3: 'Mar', 4: 'Apr', 5: 'May', 6: 'Jun',
+ 7: 'Jul', 8: 'Aug', 9: 'Sep', 10: 'Oct', 11: 'Nov',
12: 'Dec'}
# ===================================================================
@@ -63,6 +63,7 @@
send a customized error string to the client.
"""
+
# ===================================================================
# --- base class
# ===================================================================
@@ -239,6 +240,7 @@
def __init__(self, fd, name):
self.file = fd
self.name = name
+
def __getattr__(self, attr):
return getattr(self.file, attr)
@@ -496,8 +498,8 @@
raise
# formatting is matched with proftpd ls output
- line = "%s %3s %-8s %-8s %8s %s %s\r\n" % (perms, nlinks,
uname, gname,
- size, mtimestr,
basename)
+ line = "%s %3s %-8s %-8s %8s %s %s\r\n" % (
+ perms, nlinks, uname, gname, size, mtimestr, basename)
yield line.encode('utf8', self.cmd_channel.unicode_errors)
def format_mlsx(self, basedir, listing, perms, facts, ignore_err=True):
@@ -522,9 +524,9 @@
This is how output could appear to the client issuing
a MLSD request:
- type=file;size=156;perm=r;modify=20071029155301;unique=801cd2;
music.mp3
+ type=file;size=156;perm=r;modify=20071029155301;unique=8012;
music.mp3
type=dir;size=0;perm=el;modify=20071127230206;unique=801e33; ebooks
- type=file;size=211;perm=r;modify=20071103093626;unique=801e32;
module.py
+ type=file;size=211;perm=r;modify=20071103093626;unique=192;
module.py
"""
assert isinstance(basedir, unicode), basedir
if listing:
@@ -629,7 +631,7 @@
retfacts['unique'] = "%xg%x" % (st.st_dev, st.st_ino)
# facts can be in any order but we sort them by name
- factstring = "".join(["%s=%s;" % (x, retfacts[x]) \
+ factstring = "".join(["%s=%s;" % (x, retfacts[x])
for x in sorted(retfacts.keys())])
line = "%s %s\r\n" % (factstring, basename)
yield line.encode('utf8', self.cmd_channel.unicode_errors)
=======================================
--- /trunk/pyftpdlib/ftpserver.py Tue Feb 19 10:13:09 2013 UTC
+++ /trunk/pyftpdlib/ftpserver.py Sun Dec 8 21:40:25 2013 UTC
@@ -46,10 +46,10 @@
from pyftpdlib import _depwarn, __ver__
-__all__ =
['proto_cmds', 'Error', 'log', 'logline', 'logerror', 'DummyAuthorizer',
- 'AuthorizerError', 'FTPHandler', 'FTPServer', 'PassiveDTP',
- 'ActiveDTP', 'DTPHandler', 'ThrottledDTPHandler', 'FileProducer',
- 'BufferedIteratorProducer', 'AbstractedFS']
+__all__ = ['proto_cmds', 'Error', 'log', 'logline', 'logerror',
+ 'DummyAuthorizer', 'AuthorizerError', 'FTPHandler', 'FTPServer',
+ 'PassiveDTP', 'ActiveDTP', 'DTPHandler', 'ThrottledDTPHandler',
+ 'FileProducer', 'BufferedIteratorProducer', 'AbstractedFS']
_depwarn("pyftpdlib.ftpserver module is deprecated")
@@ -57,29 +57,34 @@
class CallLater(object):
def __init__(self, *args, **kwargs):
_depwarn("CallLater is deprecated; use "
- "pyftpdlib.ioloop.IOLoop.instance().call_later() instead")
+ "pyftpdlib.ioloop.IOLoop.instance().call_later() instead")
from pyftpdlib.ioloop import IOLoop
IOLoop.instance().call_later(*args, **kwargs)
+
class CallEvery(object):
def __init__(self, *args, **kwargs):
_depwarn("CallEvery is deprecated; use "
- "pyftpdlib.ioloop.IOLoop.instance().call_every() instead")
+ "pyftpdlib.ioloop.IOLoop.instance().call_every() instead")
from pyftpdlib.ioloop import IOLoop
IOLoop.instance().call_every(*args, **kwargs)
+
def log(msg):
_depwarn("pyftpdlib.ftpserver.log() is deprecated")
logger.info(msg)
+
def logline(msg):
_depwarn("pyftpdlib.ftpserver.logline() is deprecated")
logger.debug(msg)
+
def logerror(msg):
_depwarn("pyftpdlib.ftpserver.logline() is deprecated")
logger.error(msg)
+
if __name__ == '__main__':
from pyftpdlib import main
main()
=======================================
--- /trunk/pyftpdlib/handlers.py Tue Nov 26 15:27:59 2013 UTC
+++ /trunk/pyftpdlib/handlers.py Sun Dec 8 21:40:25 2013 UTC
@@ -51,7 +51,8 @@
AuthorizerError)
from pyftpdlib._compat import PY3, b, u, getcwdu, unicode, xrange, next
from pyftpdlib.filesystems import FilesystemError, AbstractedFS
-from pyftpdlib.ioloop import AsyncChat, Connector, Acceptor, timer,
_DISCONNECTED
+from pyftpdlib.ioloop import (AsyncChat, Connector, Acceptor, timer,
+ _DISCONNECTED)
from pyftpdlib.log import logger
@@ -77,104 +78,144 @@
proto_cmds = {
- 'ABOR': dict(perm=None, auth=True, arg=False,
- help='Syntax: ABOR (abort transfer).'),
- 'ALLO': dict(perm=None, auth=True, arg=True,
- help='Syntax: ALLO <SP> bytes (noop; allocate storage).'),
- 'APPE': dict(perm='a', auth=True, arg=True,
- help='Syntax: APPE <SP> file-name (append data to
file).'),
- 'CDUP': dict(perm='e', auth=True, arg=False,
- help='Syntax: CDUP (go to parent directory).'),
- 'CWD': dict(perm='e', auth=True, arg=None,
- help='Syntax: CWD [<SP> dir-name] (change working
directory).'),
- 'DELE': dict(perm='d', auth=True, arg=True,
- help='Syntax: DELE <SP> file-name (delete file).'),
- 'EPRT': dict(perm=None, auth=True, arg=True,
- help='Syntax: EPRT <SP> |proto|ip|port| (extended active
mode).'),
- 'EPSV': dict(perm=None, auth=True, arg=None,
- help='Syntax: EPSV [<SP> proto/"ALL"] (extended passive
mode).'),
- 'FEAT': dict(perm=None, auth=False, arg=False,
- help='Syntax: FEAT (list all new features supported).'),
- 'HELP': dict(perm=None, auth=False, arg=None,
- help='Syntax: HELP [<SP> cmd] (show help).'),
- 'LIST': dict(perm='l', auth=True, arg=None,
- help='Syntax: LIST [<SP> path] (list files).'),
- 'MDTM': dict(perm='l', auth=True, arg=True,
- help='Syntax: MDTM [<SP> path] (file last modification
time).'),
- 'MLSD': dict(perm='l', auth=True, arg=None,
- help='Syntax: MLSD [<SP> path] (list directory).'),
- 'MLST': dict(perm='l', auth=True, arg=None,
- help='Syntax: MLST [<SP> path] (show information about
path).'),
- 'MODE': dict(perm=None, auth=True, arg=True,
- help='Syntax: MODE <SP> mode (noop; set data transfer
mode).'),
- 'MKD': dict(perm='m', auth=True, arg=True,
- help='Syntax: MKD <SP> path (create directory).'),
- 'NLST': dict(perm='l', auth=True, arg=None,
- help='Syntax: NLST [<SP> path] (list path in a compact
form).'),
- 'NOOP': dict(perm=None, auth=False, arg=False,
- help='Syntax: NOOP (just do nothing).'),
- 'OPTS': dict(perm=None, auth=True, arg=True,
- help='Syntax: OPTS <SP> cmd [<SP> option] (set option
for '
- 'command).'),
- 'PASS': dict(perm=None, auth=False, arg=None,
- help='Syntax: PASS [<SP> password] (set user password).'),
- 'PASV': dict(perm=None, auth=True, arg=False,
- help='Syntax: PASV (open passive data connection).'),
- 'PORT': dict(perm=None, auth=True, arg=True,
- help='Syntax: PORT <sp> h1,h2,h3,h4,p1,p2 (open active
data '
- 'connection).'),
- 'PWD': dict(perm=None, auth=True, arg=False,
- help='Syntax: PWD (get current working directory).'),
- 'QUIT': dict(perm=None, auth=False, arg=False,
- help='Syntax: QUIT (quit current session).'),
- 'REIN': dict(perm=None, auth=True, arg=False,
- help='Syntax: REIN (flush account).'),
- 'REST': dict(perm=None, auth=True, arg=True,
- help='Syntax: REST <SP> offset (set file offset).'),
- 'RETR': dict(perm='r', auth=True, arg=True,
- help='Syntax: RETR <SP> file-name (retrieve a file).'),
- 'RMD': dict(perm='d', auth=True, arg=True,
- help='Syntax: RMD <SP> dir-name (remove directory).'),
- 'RNFR': dict(perm='f', auth=True, arg=True,
- help='Syntax: RNFR <SP> file-name (rename (source
name)).'),
- 'RNTO': dict(perm='f', auth=True, arg=True,
- help='Syntax: RNTO <SP> file-name (rename (destination
name)).'),
- 'SITE': dict(perm=None, auth=False, arg=True,
- help='Syntax: SITE <SP> site-command (execute SITE
command).'),
- 'SITE HELP': dict(perm=None, auth=False, arg=None,
- help='Syntax: SITE HELP [<SP> site-command] (show
SITE '
- 'command help).'),
- 'SITE CHMOD': dict(perm='M', auth=True, arg=True,
- help='Syntax: SITE CHMOD <SP> mode path (change
file '
- 'mode).'),
- 'SIZE': dict(perm='l', auth=True, arg=True,
- help='Syntax: SIZE <SP> file-name (get file size).'),
- 'STAT': dict(perm='l', auth=False, arg=None,
- help='Syntax: STAT [<SP> path name] (server stats [list '
- 'files]).'),
- 'STOR': dict(perm='w', auth=True, arg=True,
- help='Syntax: STOR <SP> file-name (store a file).'),
- 'STOU': dict(perm='w', auth=True, arg=None,
- help='Syntax: STOU [<SP> file-name] (store a file with a '
- 'unique name).'),
- 'STRU': dict(perm=None, auth=True, arg=True,
- help='Syntax: STRU <SP> type (noop; set file
structure).'),
- 'SYST': dict(perm=None, auth=False, arg=False,
- help='Syntax: SYST (get operating system type).'),
- 'TYPE': dict(perm=None, auth=True, arg=True,
- help='Syntax: TYPE <SP> [A | I] (set transfer type).'),
- 'USER': dict(perm=None, auth=False, arg=True,
- help='Syntax: USER <SP> user-name (set username).'),
- 'XCUP': dict(perm='e', auth=True, arg=False,
- help='Syntax: XCUP (obsolete; go to parent directory).'),
- 'XCWD': dict(perm='e', auth=True, arg=None,
- help='Syntax: XCWD [<SP> dir-name] (obsolete; change
directory).'),
- 'XMKD': dict(perm='m', auth=True, arg=True,
- help='Syntax: XMKD <SP> dir-name (obsolete; create
directory).'),
- 'XPWD': dict(perm=None, auth=True, arg=False,
- help='Syntax: XPWD (obsolete; get current dir).'),
- 'XRMD': dict(perm='d', auth=True, arg=True,
- help='Syntax: XRMD <SP> dir-name (obsolete; remove
directory).'),
+ 'ABOR': dict(
+ perm=None, auth=True, arg=False,
+ help='Syntax: ABOR (abort transfer).'),
+ 'ALLO': dict(
+ perm=None, auth=True, arg=True,
+ help='Syntax: ALLO <SP> bytes (noop; allocate storage).'),
+ 'APPE': dict(
+ perm='a', auth=True, arg=True,
+ help='Syntax: APPE <SP> file-name (append data to file).'),
+ 'CDUP': dict(
+ perm='e', auth=True, arg=False,
+ help='Syntax: CDUP (go to parent directory).'),
+ 'CWD': dict(
+ perm='e', auth=True, arg=None,
+ help='Syntax: CWD [<SP> dir-name] (change working directory).'),
+ 'DELE': dict(
+ perm='d', auth=True, arg=True,
+ help='Syntax: DELE <SP> file-name (delete file).'),
+ 'EPRT': dict(
+ perm=None, auth=True, arg=True,
+ help='Syntax: EPRT <SP> |proto|ip|port| (extended active mode).'),
+ 'EPSV': dict(
+ perm=None, auth=True, arg=None,
+ help='Syntax: EPSV [<SP> proto/"ALL"] (extended passive mode).'),
+ 'FEAT': dict(
+ perm=None, auth=False, arg=False,
+ help='Syntax: FEAT (list all new features supported).'),
+ 'HELP': dict(
+ perm=None, auth=False, arg=None,
+ help='Syntax: HELP [<SP> cmd] (show help).'),
+ 'LIST': dict(
+ perm='l', auth=True, arg=None,
+ help='Syntax: LIST [<SP> path] (list files).'),
+ 'MDTM': dict(
+ perm='l', auth=True, arg=True,
+ help='Syntax: MDTM [<SP> path] (file last modification time).'),
+ 'MLSD': dict(
+ perm='l', auth=True, arg=None,
+ help='Syntax: MLSD [<SP> path] (list directory).'),
+ 'MLST': dict(
+ perm='l', auth=True, arg=None,
+ help='Syntax: MLST [<SP> path] (show information about path).'),
+ 'MODE': dict(
+ perm=None, auth=True, arg=True,
+ help='Syntax: MODE <SP> mode (noop; set data transfer mode).'),
+ 'MKD': dict(
+ perm='m', auth=True, arg=True,
+ help='Syntax: MKD <SP> path (create directory).'),
+ 'NLST': dict(
+ perm='l', auth=True, arg=None,
+ help='Syntax: NLST [<SP> path] (list path in a compact form).'),
+ 'NOOP': dict(
+ perm=None, auth=False, arg=False,
+ help='Syntax: NOOP (just do nothing).'),
+ 'OPTS': dict(
+ perm=None, auth=True, arg=True,
+ help='Syntax: OPTS <SP> cmd [<SP> option] (set option for
command).'),
+ 'PASS': dict(
+ perm=None, auth=False, arg=None,
+ help='Syntax: PASS [<SP> password] (set user password).'),
+ 'PASV': dict(
+ perm=None, auth=True, arg=False,
+ help='Syntax: PASV (open passive data connection).'),
+ 'PORT': dict(
+ perm=None, auth=True, arg=True,
+ help='Syntax: PORT <sp> h,h,h,h,p,p (open active data
connection).'),
+ 'PWD': dict(
+ perm=None, auth=True, arg=False,
+ help='Syntax: PWD (get current working directory).'),
+ 'QUIT': dict(
+ perm=None, auth=False, arg=False,
+ help='Syntax: QUIT (quit current session).'),
+ 'REIN': dict(
+ perm=None, auth=True, arg=False,
+ help='Syntax: REIN (flush account).'),
+ 'REST': dict(
+ perm=None, auth=True, arg=True,
+ help='Syntax: REST <SP> offset (set file offset).'),
+ 'RETR': dict(
+ perm='r', auth=True, arg=True,
+ help='Syntax: RETR <SP> file-name (retrieve a file).'),
+ 'RMD': dict(
+ perm='d', auth=True, arg=True,
+ help='Syntax: RMD <SP> dir-name (remove directory).'),
+ 'RNFR': dict(
+ perm='f', auth=True, arg=True,
+ help='Syntax: RNFR <SP> file-name (rename (source name)).'),
+ 'RNTO': dict(
+ perm='f', auth=True, arg=True,
+ help='Syntax: RNTO <SP> file-name (rename (destination name)).'),
+ 'SITE': dict(
+ perm=None, auth=False, arg=True,
+ help='Syntax: SITE <SP> site-command (execute SITE command).'),
+ 'SITE HELP': dict(
+ perm=None, auth=False, arg=None,
+ help='Syntax: SITE HELP [<SP> cmd] (show SITE command help).'),
+ 'SITE CHMOD': dict(
+ perm='M', auth=True, arg=True,
+ help='Syntax: SITE CHMOD <SP> mode path (change file mode).'),
+ 'SIZE': dict(
+ perm='l', auth=True, arg=True,
+ help='Syntax: SIZE <SP> file-name (get file size).'),
+ 'STAT': dict(
+ perm='l', auth=False, arg=None,
+ help='Syntax: STAT [<SP> path name] (server stats [list files]).'),
+ 'STOR': dict(
+ perm='w', auth=True, arg=True,
+ help='Syntax: STOR <SP> file-name (store a file).'),
+ 'STOU': dict(
+ perm='w', auth=True, arg=None,
+ help='Syntax: STOU [<SP> name] (store a file with a unique
name).'),
+ 'STRU': dict(
+ perm=None, auth=True, arg=True,
+ help='Syntax: STRU <SP> type (noop; set file structure).'),
+ 'SYST': dict(
+ perm=None, auth=False, arg=False,
+ help='Syntax: SYST (get operating system type).'),
+ 'TYPE': dict(
+ perm=None, auth=True, arg=True,
+ help='Syntax: TYPE <SP> [A | I] (set transfer type).'),
+ 'USER': dict(
+ perm=None, auth=False, arg=True,
+ help='Syntax: USER <SP> user-name (set username).'),
+ 'XCUP': dict(
+ perm='e', auth=True, arg=False,
+ help='Syntax: XCUP (obsolete; go to parent directory).'),
+ 'XCWD': dict(
+ perm='e', auth=True, arg=None,
+ help='Syntax: XCWD [<SP> dir-name] (obsolete; change directory).'),
+ 'XMKD': dict(
+ perm='m', auth=True, arg=True,
+ help='Syntax: XMKD <SP> dir-name (obsolete; create directory).'),
+ 'XPWD': dict(
+ perm=None, auth=True, arg=False,
+ help='Syntax: XPWD (obsolete; get current dir).'),
+ 'XRMD': dict(
+ perm='d', auth=True, arg=True,
+ help='Syntax: XRMD <SP> dir-name (obsolete; remove directory).'),
}
if not hasattr(os, 'chmod'):
@@ -316,8 +357,9 @@
ip = ip[7:]
# The format of 227 response in not standardized.
# This is the most expected:
- self.cmd_channel.respond('227 Entering passive mode
(%s,%d,%d).' % (
- ip.replace('.', ','), port // 256, port % 256))
+ resp = '227 Entering passive mode (%s,%d,%d).' % (
+ ip.replace('.', ','), port // 256, port % 256)
+ self.cmd_channel.respond(resp)
else:
self.cmd_channel.respond('229 Entering extended passive mode '
'(|||%d|).' % port)
@@ -342,15 +384,15 @@
sock.close()
except socket.error:
pass
- msg = '425 Rejected data connection from foreign
address %s:%s.' \
- % (addr[0], addr[1])
+ msg = '425 Rejected data connection from foreign address '
\
+ '%s:%s.' % (addr[0], addr[1])
self.cmd_channel.respond_w_warning(msg)
# do not close listening socket: it couldn't be client's
blame
return
else:
# site-to-site FTP allowed
- msg = 'Established data connection with foreign
address %s:%s.'\
- % (addr[0], addr[1])
+ msg = 'Established data connection with foreign address ' \
+ '%s:%s.' % (addr[0], addr[1])
self.cmd_channel.log(msg, logfun=logger.warning)
# Immediately close the current channel (we accept only one
# connection at time) and avoid running out of max connections
@@ -467,7 +509,8 @@
if self.cmd_channel.connected:
msg = "Active data channel timed out."
self.cmd_channel.respond("421 " + msg, logfun=
logger.info)
- self.cmd_channel.log_cmd(self._cmd, self._normalized_addr,
421, msg)
+ self.cmd_channel.log_cmd(
+ self._cmd, self._normalized_addr, 421, msg)
self.close()
def handle_close(self):
@@ -558,7 +601,8 @@
# if we get an exception here we want the dispatcher
# instance to set socket attribute before closing, see:
#
http://code.google.com/p/pyftpdlib/issues/detail?id=188
- AsyncChat.__init__(self, socket.socket(),
ioloop=cmd_channel.ioloop)
+ AsyncChat.__init__(
+ self, socket.socket(), ioloop=cmd_channel.ioloop)
#
http://code.google.com/p/pyftpdlib/issues/detail?id=143
self.close()
if err.args[0] == errno.EINVAL:
@@ -589,7 +633,7 @@
__str__ = __repr__
def _use_sendfile(self, producer):
- return (Uself.cmd_channel.use_sendfile
+ return (self.cmd_channel.use_sendfile
and isinstance(producer, FileProducer)
and producer.type == 'i')
@@ -835,12 +879,13 @@
if self.file_obj is not None:
filename =
self.file_obj.name
elapsed_time = round(self.get_elapsed_time(), 3)
- self.cmd_channel.log_transfer(cmd=self.cmd,
- filename=
self.file_obj.name,
- receive=self.receive,
-
completed=self.transfer_finished,
- elapsed=elapsed_time,
-
bytes=self.get_transmitted_bytes())
+ self.cmd_channel.log_transfer(
+ cmd=self.cmd,
+ filename=
self.file_obj.name,
+ receive=self.receive,
+ completed=self.transfer_finished,
+ elapsed=elapsed_time,
+ bytes=self.get_transmitted_bytes())
if self.transfer_finished:
if self.receive:
self.cmd_channel.on_file_received(filename)
@@ -942,8 +987,8 @@
self.del_channel()
self._cancel_throttler()
- self._throttler = self.ioloop.call_later(sleepfor, unsleep,
-
_errback=self.handle_error)
+ self._throttler = self.ioloop.call_later(
+ sleepfor, unsleep, _errback=self.handle_error)
self._timenext = now + 1
def close(self):
@@ -1231,8 +1276,8 @@
return
if self.timeout:
- self._idler = self.ioloop.call_later(self.timeout,
self.handle_timeout,
-
_errback=self.handle_error)
+ self._idler = self.ioloop.call_later(
+ self.timeout, self.handle_timeout,
_errback=self.handle_error)
def __repr__(self):
status = [self.__class__.__module__ + "." +
self.__class__.__name__]
@@ -1421,7 +1466,7 @@
if not self.fs.validpath(arg):
line = self.fs.fs2ftp(arg)
- msg = '"%s" points to a path which is outside '
+ msg = '"%s" points to a path which is outside ' \
"the user's root directory" % line
self.respond("550 %s." % msg)
self.log_cmd(cmd, arg, 550, msg)
@@ -1624,9 +1669,8 @@
# data transfer finished, restart the idle timer
if self._idler is not None and not self._idler.cancelled:
self._idler.cancel()
- self._idler = self.ioloop.call_later(self.timeout,
- self.handle_timeout,
-
_errback=self.handle_error)
+ self._idler = self.ioloop.call_later(
+ self.timeout, self.handle_timeout,
_errback=self.handle_error)
# --- utility
@@ -1660,7 +1704,8 @@
- (file) file: the file[-like] object to send (if any).
"""
if self.data_channel is not None:
- self.respond("125 Data connection already open. Transfer
starting.")
+ self.respond(
+ "125 Data connection already open. Transfer starting.")
if file:
self.data_channel.file_obj = file
try:
@@ -1675,7 +1720,8 @@
# dealing with this exception is up to DTP (see bug #84)
self.data_channel.handle_error()
else:
- self.respond("150 File status okay. About to open data
connection.")
+ self.respond(
+ "150 File status okay. About to open data connection.")
self._out_dtp_queue = (data, isproducer, file, cmd)
def flush_account(self):
@@ -1990,7 +2036,8 @@
self._make_epasv(extmode=True)
elif line.lower() == 'all':
self._epsvall = True
- self.respond('220 Other commands other than EPSV are now
disabled.')
+ self.respond(
+ '220 Other commands other than EPSV are now disabled.')
else:
if self._af == socket.AF_INET:
self.respond('501 Unknown network protocol (use 1).')
@@ -2096,8 +2143,9 @@
basedir, basename = os.path.split(path)
perms = self.authorizer.get_perms(self.username)
try:
- iterator = self.run_as_current_user(self.fs.format_mlsx,
basedir,
- [basename], perms,
self._current_facts, ignore_err=False)
+ iterator = self.run_as_current_user(
+ self.fs.format_mlsx, basedir, [basename], perms,
+ self._current_facts, ignore_err=False)
data = b('').join(iterator)
except (OSError, FilesystemError):
err = sys.exc_info()[1]
@@ -2329,7 +2377,8 @@
return
else:
# a PASV or PORT was received but connection wasn't made yet
- if self._dtp_acceptor is not None or self._dtp_connector is
not None:
+ if (self._dtp_acceptor is not None
+ or self._dtp_connector is not None):
self._shutdown_connecting_dtp()
resp = "225 ABOR command successful; data channel closed."
@@ -2425,7 +2474,8 @@
else:
warnings.warn(
'%s.get_home_dir returned a non-unicode string;
now '
- 'casting to unicode' %
self.authorizer.__class__.__name__,
+ 'casting to unicode' % (
+ self.authorizer.__class__.__name__),
RuntimeWarning)
home = home.decode('utf8')
@@ -2579,7 +2629,8 @@
# The 257 response is supposed to include the directory
# name and in case it contains embedded double-quotes
# they must be doubled (see RFC-959, chapter 7, appendix 2).
- self.respond('257 "%s" directory created.' %
line.replace('"', '""'))
+ self.respond(
+ '257 "%s" directory created.' % line.replace('"', '""'))
return path
def ftp_RMD(self, path):
@@ -2790,7 +2841,8 @@
self.respond('501 %s.' % err)
else:
facts = [x.lower() for x in arg.split(';')]
- self._current_facts = [x for x in facts if x in
self._available_facts]
+ self._current_facts = \
+ [x for x in facts if x in self._available_facts]
f = ''.join([x + ';' for x in self._current_facts])
self.respond('200 MLST OPTS ' + f)
@@ -2892,23 +2944,23 @@
# ftp.exe) still use them.
def ftp_XCUP(self, line):
- """Change to the parent directory. Synonym for CDUP. Deprecated."""
+ "Change to the parent directory. Synonym for CDUP. Deprecated."
return self.ftp_CDUP(line)
def ftp_XCWD(self, line):
- """Change the current working directory. Synonym for CWD.
Deprecated."""
+ "Change the current working directory. Synonym for CWD.
Deprecated."
return self.ftp_CWD(line)
def ftp_XMKD(self, line):
- """Create the specified directory. Synonym for MKD. Deprecated."""
+ "Create the specified directory. Synonym for MKD. Deprecated."
return self.ftp_MKD(line)
def ftp_XPWD(self, line):
- """Return the current working directory. Synonym for PWD.
Deprecated."""
+ "Return the current working directory. Synonym for PWD.
Deprecated."
return self.ftp_PWD(line)
def ftp_XRMD(self, line):
- """Remove the specified directory. Synonym for RMD. Deprecated."""
+ "Remove the specified directory. Synonym for RMD. Deprecated."
return self.ftp_RMD(line)
@@ -2923,12 +2975,15 @@
else:
_ssl_proto_cmds = proto_cmds.copy()
_ssl_proto_cmds.update({
- 'AUTH': dict(perm=None, auth=False, arg=True,
- help='Syntax: AUTH <SP> TLS|SSL (set up secure
control channel).'),
- 'PBSZ': dict(perm=None, auth=False, arg=True,
- help='Syntax: PBSZ <SP> 0 (negotiate TLS buffer).'),
- 'PROT': dict(perm=None, auth=False, arg=True,
- help='Syntax: PROT <SP> [C|P] (set up un/secure data
channel).'),
+ 'AUTH': dict(
+ perm=None, auth=False, arg=True,
+ help='Syntax: AUTH <SP> TLS|SSL (set up secure control
channel).'),
+ 'PBSZ': dict(
+ perm=None, auth=False, arg=True,
+ help='Syntax: PBSZ <SP> 0 (negotiate TLS buffer).'),
+ 'PROT': dict(
+ perm=None, auth=False, arg=True,
+ help='Syntax: PROT <SP> [C|P] (set up un/secure data
channel).'),
})
class SSLConnection(_AsyncChatNewStyle):
@@ -3071,7 +3126,8 @@
os.write(self.socket.fileno(), b(''))
except (OSError, socket.error):
err = sys.exc_info()[1]
- if err.args[0] in (errno.EINTR, errno.EWOULDBLOCK,
errno.ENOBUFS):
+ if err.args[0] in (errno.EINTR, errno.EWOULDBLOCK,
+ errno.ENOBUFS):
return
elif err.args[0] in _DISCONNECTED:
return super(SSLConnection, self).close()
@@ -3289,7 +3345,8 @@
self.respond('234 AUTH %s successful.' % arg)
self.secure_connection(self.ssl_context)
else:
- self.respond("502 Unrecognized encryption type (use TLS or
SSL).")
+ self.respond(
+ "502 Unrecognized encryption type (use TLS or SSL).")
def ftp_PBSZ(self, line):
"""Negotiate size of buffer for secure data transfer.
@@ -3310,7 +3367,8 @@
self.respond(
"503 PROT not allowed on insecure control connection.")
elif not self._pbsz:
- self.respond("503 You must issue the PBSZ command prior to
PROT.")
+ self.respond(
+ "503 You must issue the PBSZ command prior to PROT.")
elif arg == 'C':
self.respond('200 Protection set to Clear')
self._prot = False
=======================================
--- /trunk/pyftpdlib/ioloop.py Wed Nov 6 20:25:02 2013 UTC
+++ /trunk/pyftpdlib/ioloop.py Sun Dec 8 21:40:25 2013 UTC
@@ -83,17 +83,17 @@
IOLoop.instance().loop()
"""
+import asynchat
import asyncore
-import asynchat
import errno
+import heapq
+import logging
+import os
import select
-import os
+import socket
import sys
-import traceback
import time
-import heapq
-import socket
-import logging
+import traceback
try:
import threading
except ImportError:
@@ -148,8 +148,8 @@
# remove cancelled tasks and re-heapify the queue if the
# number of cancelled tasks is more than the half of the
# entire queue
- if self._cancellations > 512 \
- and self._cancellations > (len(self._tasks) >> 1):
+ if (self._cancellations > 512
+ and self._cancellations > (len(self._tasks) >> 1)):
self.reheapify()
try:
@@ -210,9 +210,9 @@
sig = object.__repr__(self)
else:
sig = repr(self._target)
- sig += ' args=%s, kwargs=%s, cancelled=%s, secs=%s' \
- % (self._args or '[]', self._kwargs or '{}',
self.cancelled,
- self._delay)
+ sig += ' args=%s, kwargs=%s, cancelled=%s, secs=%s' % (
+ self._args or '[]', self._kwargs or '{}', self.cancelled,
+ self._delay)
return '<%s>' % sig
__str__ = __repr__
@@ -612,11 +612,11 @@
kevents = []
if events & self.WRITE:
kevents.append(select.kevent(
- fd, filter=select.KQ_FILTER_WRITE, flags=flags))
+ fd, filter=select.KQ_FILTER_WRITE, flags=flags))
if events & self.READ or not kevents:
# always read when there is not a write
kevents.append(select.kevent(
- fd, filter=select.KQ_FILTER_READ, flags=flags))
+ fd, filter=select.KQ_FILTER_READ, flags=flags))
# even though control() takes a list, it seems to return
# EINVAL on Mac OS X (10.6) when there is more than one
# event in the list
@@ -624,12 +624,13 @@
self._kqueue.control([kevent], 0)
# localize variable access to minimize overhead
- def poll(self, timeout,
- _len=len,
- _READ=select.KQ_FILTER_READ,
- _WRITE=select.KQ_FILTER_WRITE,
- _EOF=select.KQ_EV_EOF,
- _ERROR=select.KQ_EV_ERROR):
+ def poll(self,
+ timeout,
+ _len=len,
+ _READ=select.KQ_FILTER_READ,
+ _WRITE=select.KQ_FILTER_WRITE,
+ _EOF=select.KQ_EV_EOF,
+ _ERROR=select.KQ_EV_ERROR):
try:
kevents = self._kqueue.control(None, _len(self.socket_map),
timeout)
@@ -687,6 +688,7 @@
errno.ECONNABORTED, errno.EPIPE, errno.EBADF))
_RETRY = frozenset((errno.EAGAIN, errno.EWOULDBLOCK))
+
class Acceptor(asyncore.dispatcher):
"""Same as base asyncore.dispatcher and supposed to be used to
accept new connections.
@@ -800,7 +802,8 @@
# the remote client is using IPv4 and its address
is
# represented as an IPv4-mapped IPv6 address which
# looks like this ::ffff:151.12.5.65, see:
- #
http://en.wikipedia.org/wiki/IPv6#IPv4-mapped_addresses
+ #
http://en.wikipedia.org/wiki/IPv6\
+ # IPv4-mapped_addresses
#
http://tools.ietf.org/html/rfc3493.html#section-3.7
# We truncate the first bytes to make it look like
a
# common IPv4 address.
=======================================
--- /trunk/pyftpdlib/log.py Tue Feb 19 10:13:09 2013 UTC
+++ /trunk/pyftpdlib/log.py Sun Dec 8 21:40:25 2013 UTC
@@ -43,13 +43,14 @@
import curses
except ImportError:
curses = None
-
+
from pyftpdlib._compat import unicode
+
# default logger
-
logger = logging.getLogger('pyftpdlib')
+
def _stderr_supports_color():
color = False
if curses is not None and sys.stderr.isatty():
@@ -89,14 +90,19 @@
# works with unicode strings. The explicit calls to
# unicode() below are harmless in python2 but will do the
# right conversion in python 3.
- fg_color = (curses.tigetstr("setaf") or
curses.tigetstr("setf") or "")
+ fg_color = (curses.tigetstr("setaf") or curses.tigetstr("setf")
+ or "")
if (3, 0) < sys.version_info < (3, 2, 3):
fg_color = unicode(fg_color, "ascii")
self._colors = {
- logging.DEBUG: unicode(curses.tparm(fg_color,
4), "ascii"), # blue
- logging.INFO: unicode(curses.tparm(fg_color,
2), "ascii"), # green
- logging.WARNING: unicode(curses.tparm(fg_color,
3), "ascii"), # yellow
- logging.ERROR: unicode(curses.tparm(fg_color,
1), "ascii") # red
+ # blues
+ logging.DEBUG: unicode(curses.tparm(fg_color, 4), "ascii"),
+ # green
+ logging.INFO: unicode(curses.tparm(fg_color, 2), "ascii"),
+ # yellow
+ logging.WARNING: unicode(curses.tparm(fg_color,
3), "ascii"),
+ # red
+ logging.ERROR: unicode(curses.tparm(fg_color, 1), "ascii")
}
self._normal = unicode(curses.tigetstr("sgr0"), "ascii")
@@ -143,6 +149,7 @@
formatted = formatted.rstrip() + "\n" + record.exc_text
return formatted.replace("\n", "\n ")
+
def _config_logging():
channel = logging.StreamHandler()
channel.setFormatter(LogFormatter())
=======================================
--- /trunk/pyftpdlib/servers.py Tue Jul 16 16:07:08 2013 UTC
+++ /trunk/pyftpdlib/servers.py Sun Dec 8 21:40:25 2013 UTC
@@ -77,6 +77,7 @@
__all__ = ['FTPServer']
_BSD = 'bsd' in sys.platform
+
# ===================================================================
# --- base class
# ===================================================================
@@ -199,7 +200,7 @@
Also, logs server start and stop.
"""
if handle_exit:
- log = handle_exit and blocking == True
+ log = handle_exit and blocking
if log:
self._log_start()
try:
@@ -208,8 +209,9 @@
pass
if blocking:
if log:
-
logger.info(">>> shutting down FTP server (%s active
fds) <<<",
- self._map_len())
+
logger.info(
+ ">>> shutting down FTP server (%s active fds) <<<",
+ self._map_len())
self.close_all()
else:
self.ioloop.loop(timeout, blocking)
@@ -328,8 +330,8 @@
poll_timeout = getattr(self, 'poll_timeout', None)
soonest_timeout = poll_timeout
- while (ioloop.socket_map or ioloop.sched._tasks) and not \
- self._exit.is_set():
+ while (ioloop.socket_map or ioloop.sched._tasks) and \
+ not self._exit.is_set():
try:
if ioloop.socket_map:
poll(timeout=soonest_timeout)
@@ -342,9 +344,11 @@
# functions are supposed to be cancel()ed on
close()
# but by using threads we can incur into
# synchronization issues such as this one.
- #
https://code.google.com/p/pyftpdlib/issues/detail?id=245
+ #
https://code.google.com/p/pyftpdlib/issues/
+ # detail?id=245
if not ioloop.socket_map:
- ioloop.sched.reheapify() # get rid of
cancel()led calls
+ # get rid of cancel()led calls
+ ioloop.sched.reheapify()
soonest_timeout = sched_poll()
if soonest_timeout:
time.sleep(min(soonest_timeout, 1))
@@ -374,8 +378,8 @@
raise
else:
if poll_timeout:
- if soonest_timeout is None \
- or soonest_timeout > poll_timeout:
+ if (soonest_timeout is None
+ or soonest_timeout > poll_timeout):
soonest_timeout = poll_timeout
finally:
ioloop.close()
@@ -413,7 +417,7 @@
def serve_forever(self, timeout=None, blocking=True, handle_exit=True):
self._exit.clear()
if handle_exit:
- log = handle_exit and blocking == True
+ log = handle_exit and blocking
if log:
self._log_start()
try:
@@ -422,8 +426,9 @@
pass
if blocking:
if log:
-
logger.info(">>> shutting down FTP server (%s active "
\
- "workers) <<<", self._map_len())
+
logger.info(
+ ">>> shutting down FTP server (%s active workers)
<<<",
+ self._map_len())
self.close_all()
else:
self.ioloop.loop(timeout, blocking)
=======================================
--- /trunk/setup.py Thu Nov 7 22:17:19 2013 UTC
+++ /trunk/setup.py Sun Dec 8 21:40:25 2013 UTC
@@ -43,6 +43,7 @@
except ImportError:
from distutils.core import setup
+
def get_version():
INIT = os.path.abspath(os.path.join(os.path.dirname(__file__),
'pyftpdlib', '__init__.py'))
@@ -59,10 +60,11 @@
finally:
f.close()
+
name = 'pyftpdlib'
version = get_version()
-download_url = "
http://pyftpdlib.googlecode.com/files/" + name + "-" + \
- version
+ ".tar.gz"
+download_url = ("
http://pyftpdlib.googlecode.com/files/" + name + "-" +
+ version + ".tar.gz")
if sys.version_info < (2, 4):
sys.exit('python version not supported (min 2.4)')
@@ -71,9 +73,9 @@
name=name,
version=version,
description='High-level asynchronous FTP server library',
- long_description="Python FTP server library provides an high-level
portable "
- "interface to easily write asynchronous FTP servers
with "
- "Python.",
+ long_description="Python FTP server library provides an high-level "
+ "portable interface to easily write asynchronous FTP "
+ "servers with Python.",
license='License :: OSI Approved :: MIT License',
platforms='Platform Independent',
author="Giampaolo Rodola'",
@@ -85,28 +87,28 @@
'sendfile', 'asynchronous', 'nonblocking', 'eventdriven',
'rfc959', 'rfc1123', 'rfc2228', 'rfc2428', 'rfc2640', 'rfc3659'],
classifiers=[
- 'Development Status :: 5 - Production/Stable',
- 'Environment :: Console',
- 'Intended Audience :: Developers',
- 'Intended Audience :: System Administrators',
- 'License :: OSI Approved :: MIT License',
- 'Operating System :: OS Independent',
- 'Programming Language :: Python',
- 'Topic :: Internet :: File Transfer Protocol (FTP)',
- 'Topic :: Software Development :: Libraries :: Python Modules',
- 'Topic :: System :: Filesystems',
- 'Programming Language :: Python',
- 'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.4',
- 'Programming Language :: Python :: 2.5',
- 'Programming Language :: Python :: 2.6',
- 'Programming Language :: Python :: 2.7',
- 'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.0',
- 'Programming Language :: Python :: 3.1',
- 'Programming Language :: Python :: 3.2',
- 'Programming Language :: Python :: 3.3',
- ],
+ 'Development Status :: 5 - Production/Stable',
+ 'Environment :: Console',
+ 'Intended Audience :: Developers',
+ 'Intended Audience :: System Administrators',
+ 'License :: OSI Approved :: MIT License',
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python',
+ 'Topic :: Internet :: File Transfer Protocol (FTP)',
+ 'Topic :: Software Development :: Libraries :: Python Modules',
+ 'Topic :: System :: Filesystems',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 2',
+ 'Programming Language :: Python :: 2.4',
+ 'Programming Language :: Python :: 2.5',
+ 'Programming Language :: Python :: 2.6',
+ 'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.0',
+ 'Programming Language :: Python :: 3.1',
+ 'Programming Language :: Python :: 3.2',
+ 'Programming Language :: Python :: 3.3',
+ ],
)
=======================================
--- /trunk/test/bench.py Wed Apr 24 21:43:31 2013 UTC
+++ /trunk/test/bench.py Sun Dec 8 21:40:25 2013 UTC
@@ -90,7 +90,6 @@
# 300 concurrent clients (QUIT) 0.00 secs
-
from __future__ import with_statement, division
import ftplib
import sys
@@ -111,6 +110,7 @@
except ImportError:
psutil = None
+
HOST = 'localhost'
PORT = 21
USER = None
@@ -135,6 +135,7 @@
def b(s):
return s
+
#
http://goo.gl/6V8Rm
def hilite(string, ok=True, bold=False):
"""Return an highlighted version of 'string'."""
@@ -155,14 +156,16 @@
server_memory = []
+
def print_bench(what, value, unit=""):
s = "%s %s %-8s" % (hilite("%-50s" % what, ok=None, bold=0),
- hilite("%8.2f" % value),
- unit)
+ hilite("%8.2f" % value),
+ unit)
if server_memory:
s += "%s" % hilite(server_memory.pop())
print_(s.strip())
+
#
http://goo.gl/zeJZl
def bytes2human(n, format="%(value).1f%(symbol)s"):
"""
@@ -181,6 +184,7 @@
return format % locals()
return format % dict(symbol=symbols[0], value=n)
+
#
http://goo.gl/zeJZl
def human2bytes(s):
"""
@@ -194,11 +198,12 @@
num = s[:-1]
assert num.isdigit() and letter in symbols, s
num = float(num)
- prefix = {symbols[0]:1}
+ prefix = {symbols[0]: 1}
for i, s in enumerate(symbols[1:]):
prefix[s] = 1 << (i+1)*10
return int(num * prefix[letter])
+
def register_memory():
"""Register an approximation of memory used by FTP server process
and all of its children.
@@ -223,6 +228,7 @@
mem += get_mem(child)
server_memory.append(bytes2human(mem))
+
def timethis(what):
""""Utility function for making simple benchmarks (calculates time
calls).
It can be used either as a context manager or as a decorator.
@@ -236,14 +242,15 @@
res = (stop - start)
print_bench(what, res, "secs")
- if hasattr(what,"__call__"):
- def timed(*args,**kwargs):
+ if hasattr(what, "__call__"):
+ def timed(*args, **kwargs):
with benchmark():
- return what(*args,**kwargs)
+ return what(*args, **kwargs)
return timed
else:
return benchmark()
+
def connect():
"""Connect to FTP server, login and return an ftplib.FTP instance."""
if sys.version_info >= (2, 6):
@@ -257,6 +264,7 @@
ftp.login(USER, PASSWORD)
return ftp
+
def retr(ftp):
"""Same as ftplib's retrbinary() but discard the received data."""
ftp.voidcmd('TYPE I')
@@ -270,6 +278,7 @@
conn.close()
ftp.voidresp()
+
def stor(ftp, size):
"""Same as ftplib's storbinary() but just sends dummy data
instead of reading it from a real file.
@@ -286,6 +295,7 @@
conn.close()
ftp.voidresp()
+
def bytes_per_second(ftp, retr=True):
"""Return the number of bytes transmitted in 1 second."""
bytes = 0
@@ -328,6 +338,7 @@
ftp.quit()
return bytes
+
def cleanup():
ftp = connect()
try:
@@ -357,6 +368,7 @@
def handle_error(self):
raise
+
class AsyncWriter(asynchat.async_chat):
"""Just write dummy data to a connected socket, asynchronously."""
class ChunkProducer:
@@ -379,6 +391,7 @@
def handle_error(self):
raise
+
class AsyncQuit(asynchat.async_chat):
def __init__(self, sock):
@@ -396,6 +409,7 @@
def handle_error(self):
raise
+
class OptFormatter(optparse.IndentedHelpFormatter):
def format_epilog(self, s):
@@ -410,31 +424,36 @@
result.append(help_text)
return ''.join(result)
+
def main():
global HOST, PORT, USER, PASSWORD, SERVER_PROC, TIMEOUT
- USAGE = "%s -u USERNAME -p PASSWORD [-H] [-P] [-b] [-n] [-s] [-k]" %
__file__
+ USAGE = "%s -u USERNAME -p PASSWORD [-H] [-P] [-b] [-n] [-s] [-k]" % (
+ __file__)
parser = optparse.OptionParser(usage=USAGE,
epilog=__doc__[__doc__.find('Example'):],
formatter=OptFormatter())
parser.add_option('-u', '--user', dest='user', help='username')
parser.add_option('-p', '--pass', dest='password', help='password')
- parser.add_option('-H', '--host', dest='host', default=HOST,
help='hostname')
+ parser.add_option('-H', '--host', dest='host', default=HOST,
+ help='hostname')
parser.add_option('-P', '--port', dest='port', default=PORT,
help='port',
type=int)
- parser.add_option('-b', '--benchmark', dest='benchmark',
default='transfer',
+ parser.add_option('-b', '--benchmark', dest='benchmark',
+ default='transfer',
help="benchmark type
('transfer', 'concurrence', 'all')")
- parser.add_option('-n', '--clients', dest='clients', default=200,
type="int",
- help="number of concurrent clients used
by 'concurrence' "
- "benchmark")
+ parser.add_option('-n', '--clients', dest='clients', default=200,
+ type="int",
+ help="number of concurrent clients used by "
+ "'concurrence' benchmark")
parser.add_option('-s', '--filesize', dest='filesize', default="10M",
help="file size used by 'concurrence' benchmark "
"(e.g. '10M')")
parser.add_option('-k', '--pid', dest='pid', default=None, type="int",
- help="the PID of the server process to bench memory
usage")
+ help="the PID of the server process to bench memory "
+ "usage")
parser.add_option('-t', '--timeout', dest='timeout',
default=TIMEOUT, type="int", help="the socket
timeout")
-
options, args = parser.parse_args()
if not options.user or not options.password:
sys.exit(USAGE)
@@ -481,8 +500,8 @@
def bench_multi_retr(clients):
stor(clients[0], FILE_SIZE)
- with timethis("%s concurrent clients (RETR %s file)" \
- % (howmany, bytes2human(FILE_SIZE))):
+ with timethis("%s concurrent clients (RETR %s file)" % (
+ howmany, bytes2human(FILE_SIZE))):
for ftp in clients:
ftp.voidcmd('TYPE I')
conn = ftp.transfercmd("RETR " + TESTFN)
@@ -493,8 +512,8 @@
ftp.voidresp()
def bench_multi_stor(clients):
- with timethis("%s concurrent clients (STOR %s file)" \
- % (howmany, bytes2human(FILE_SIZE))):
+ with timethis("%s concurrent clients (STOR %s file)" % (
+ howmany, bytes2human(FILE_SIZE))):
for ftp in clients:
ftp.voidcmd('TYPE I')
conn = ftp.transfercmd("STOR " + TESTFN)
@@ -529,8 +548,8 @@
# start benchmark
if SERVER_PROC is not None:
register_memory()
- print_("(starting with %s of memory being used)" \
- % hilite(server_memory.pop()))
+ print_("(starting with %s of memory being used)" % (
+ hilite(server_memory.pop())))
if options.benchmark == 'transfer':
bench_stor()
bench_retr()
=======================================
--- /trunk/test/test_contrib.py Tue Nov 26 15:27:59 2013 UTC
+++ /trunk/test/test_contrib.py Sun Dec 8 21:40:25 2013 UTC
@@ -66,8 +66,10 @@
from test_ftpd import *
-FTPS_SUPPORT = hasattr(ftplib, 'FTP_TLS') and
hasattr(handlers, 'TLS_FTPHandler')
-CERTFILE =
os.path.abspath(os.path.join(os.path.dirname(__file__), 'keycert.pem'))
+FTPS_SUPPORT = (hasattr(ftplib, 'FTP_TLS') and
+ hasattr(handlers, 'TLS_FTPHandler'))
+CERTFILE = os.path.abspath(os.path.join(os.path.dirname(__file__),
+ 'keycert.pem'))
MPROCESS_SUPPORT = hasattr(servers, 'MultiprocessFTPServer')
@@ -535,7 +537,8 @@
self.assertRaises(AuthenticationFailed(auth.validate_authentication,
user, 'bar', None))
# make sure other settings keep using default values
- self.assertEqual(auth.get_home_dir(user),
self.get_current_user_homedir())
+ self.assertEqual(auth.get_home_dir(user),
+ self.get_current_user_homedir())
self.assertEqual(auth.get_perms(user), "elradfmw")
self.assertEqual(auth.get_msg_login(user), "Login successful.")
self.assertEqual(auth.get_msg_quit(user), "Goodbye.")
@@ -547,7 +550,8 @@
auth.override_user(user, homedir=dir)
self.assertEqual(auth.get_home_dir(user), dir)
# make sure other settings keep using default values
- #self.assertEqual(auth.get_home_dir(user),
self.get_current_user_homedir())
+ # self.assertEqual(auth.get_home_dir(user),
+ # self.get_current_user_homedir())
self.assertEqual(auth.get_perms(user), "elradfmw")
self.assertEqual(auth.get_msg_login(user), "Login successful.")
self.assertEqual(auth.get_msg_quit(user), "Goodbye.")
@@ -558,7 +562,8 @@
auth.override_user(user, perm="elr")
self.assertEqual(auth.get_perms(user), "elr")
# make sure other settings keep using default values
- self.assertEqual(auth.get_home_dir(user),
self.get_current_user_homedir())
+ self.assertEqual(auth.get_home_dir(user),
+ self.get_current_user_homedir())
#self.assertEqual(auth.get_perms(user), "elradfmw")
self.assertEqual(auth.get_msg_login(user), "Login successful.")
self.assertEqual(auth.get_msg_quit(user), "Goodbye.")
@@ -570,7 +575,8 @@
self.assertEqual(auth.get_msg_login(user), "foo")
self.assertEqual(auth.get_msg_quit(user), "bar")
# make sure other settings keep using default values
- self.assertEqual(auth.get_home_dir(user),
self.get_current_user_homedir())
+ self.assertEqual(auth.get_home_dir(user),
+ self.get_current_user_homedir())
self.assertEqual(auth.get_perms(user), "elradfmw")
#self.assertEqual(auth.get_msg_login(user), "Login successful.")
#self.assertEqual(auth.get_msg_quit(user), "Goodbye.")
@@ -592,7 +598,8 @@
auth.override_user, this_user)
self.assertRaisesWithMsg(AuthorizerError,
'no such user %s' % nonexistent_user,
- auth.override_user, nonexistent_user,
perm='r')
+ auth.override_user, nonexistent_user,
+ perm='r')
if self.authorizer_class.__name__ == 'UnixAuthorizer':
auth = self.authorizer_class(allowed_users=[this_user],
require_valid_shell=False)
@@ -613,7 +620,8 @@
auth.override_user, this_user, perm='r')
self.assertRaisesWithMsg(AuthorizerError,
"can't assign password to anonymous user",
- auth.override_user, "anonymous",
password='foo')
+ auth.override_user, "anonymous",
+ password='foo')
# =====================================================================
@@ -626,8 +634,8 @@
authorizer_class = getattr(authorizers, "UnixAuthorizer", None)
def test_get_perms_anonymous(self):
- auth = authorizers.UnixAuthorizer(global_perm='elr',
-
anonymous_user=self.get_current_user())
+ auth = authorizers.UnixAuthorizer(
+ global_perm='elr', anonymous_user=self.get_current_user())
self.assertTrue('e' in auth.get_perms('anonymous'))
self.assertFalse('w' in auth.get_perms('anonymous'))
warnings.filterwarnings("ignore")
@@ -636,8 +644,8 @@
self.assertTrue('w' in auth.get_perms('anonymous'))
def test_has_perm_anonymous(self):
- auth = authorizers.UnixAuthorizer(global_perm='elr',
-
anonymous_user=self.get_current_user())
+ auth = authorizers.UnixAuthorizer(
+ global_perm='elr', anonymous_user=self.get_current_user())
self.assertTrue(auth.has_perm(self.get_current_user(), 'r'))
self.assertFalse(auth.has_perm(self.get_current_user(), 'w'))
self.assertTrue(auth.has_perm('anonymous', 'e'))
=======================================
--- /trunk/test/test_ftpd.py Tue Nov 26 15:27:59 2013 UTC
+++ /trunk/test/test_ftpd.py Sun Dec 8 21:40:25 2013 UTC
@@ -482,7 +482,8 @@
ae(fs.fs2ftp(root), u('/'))
ae(fs.fs2ftp(join(root, u('/'))), u('/'))
ae(fs.fs2ftp(join(root, u('.'))), u('/'))
- ae(fs.fs2ftp(join(root, u('..'))), u('/')) # can't escape
from root
+ # can't escape from root
+ ae(fs.fs2ftp(join(root, u('..'))), u('/'))
ae(fs.fs2ftp(join(root, u('a'))), u('/a'))
ae(fs.fs2ftp(join(root, u('a/'))), u('/a'))
ae(fs.fs2ftp(join(root, u('a/..'))), u('/'))
@@ -564,7 +565,8 @@
# temporarily change warnings to exceptions for the purposes of testing
def setUp(self):
self.tempdir = tempfile.mkdtemp(dir=HOME)
- self.subtempdir = tempfile.mkdtemp(dir=os.path.join(HOME,
self.tempdir))
+ self.subtempdir = tempfile.mkdtemp(
+ dir=os.path.join(HOME, self.tempdir))
self.tempfile = touch(os.path.join(self.tempdir, TESTFN))
self.subtempfile = touch(os.path.join(self.subtempdir, TESTFN))
warnings.filterwarnings("error")
@@ -619,15 +621,17 @@
auth.add_anonymous, HOME, perm='?')
# expect warning on write permissions assigned to anonymous user
for x in "adfmw":
- self.assertRaisesRegex(RuntimeWarning,
- "write permissions assigned to
anonymous user.",
- auth.add_anonymous, HOME, perm=x)
+ self.assertRaisesRegex(
+ RuntimeWarning,
+ "write permissions assigned to anonymous user.",
+ auth.add_anonymous, HOME, perm=x)
def test_override_perm_interface(self):
auth = DummyAuthorizer()
auth.add_user(USER, PASSWD, HOME, perm='elr')
# raise exc if user does not exists
- self.assertRaises(KeyError, auth.override_perm, USER + 'w',
HOME, 'elr')
+ self.assertRaises(KeyError, auth.override_perm, USER + 'w',
+ HOME, 'elr')
# raise exc if path does not exist or it's not a directory
self.assertRaisesRegex(ValueError,
'no such directory',
@@ -642,9 +646,10 @@
# expect warning on write permissions assigned to anonymous user
auth.add_anonymous(HOME)
for p in "adfmw":
- self.assertRaisesRegex(RuntimeWarning,
- "write permissions assigned to
anonymous user.",
- auth.override_perm, 'anonymous', HOME,
p)
+ self.assertRaisesRegex(
+ RuntimeWarning,
+ "write permissions assigned to anonymous user.",
+ auth.override_perm, 'anonymous', HOME, p)
# raise on attempt to override home directory permissions
self.assertRaisesRegex(ValueError,
"can't override home directory permissions",
@@ -672,11 +677,13 @@
self.assertEqual(auth.has_perm(USER, 'w', HOME + '@'), False)
self.assertEqual(auth.has_perm(USER, 'w', self.tempdir + '@'),
False)
- path = os.path.join(self.tempdir + '@',
os.path.basename(self.tempfile))
+ path = os.path.join(self.tempdir + '@',
+ os.path.basename(self.tempfile))
self.assertEqual(auth.has_perm(USER, 'w', path), False)
# test case-sensitiveness
if (
os.name in ('nt', 'ce')) or (sys.platform == 'cygwin'):
- self.assertEqual(auth.has_perm(USER, 'w',
self.tempdir.upper()), True)
+ self.assertEqual(auth.has_perm(USER, 'w',
+ self.tempdir.upper()), True)
def test_override_perm_not_recursive_paths(self):
auth = DummyAuthorizer()
@@ -691,11 +698,13 @@
self.assertEqual(auth.has_perm(USER, 'w', HOME + '@'), False)
self.assertEqual(auth.has_perm(USER, 'w', self.tempdir + '@'),
False)
- path = os.path.join(self.tempdir + '@',
os.path.basename(self.tempfile))
+ path = os.path.join(self.tempdir + '@',
+ os.path.basename(self.tempfile))
self.assertEqual(auth.has_perm(USER, 'w', path), False)
# test case-sensitiveness
if (
os.name in ('nt', 'ce')) or (sys.platform == 'cygwin'):
- self.assertEqual(auth.has_perm(USER, 'w',
self.tempdir.upper()), True)
+ self.assertEqual(auth.has_perm(USER, 'w',
self.tempdir.upper()),
+ True)
class TestCallLater(TestCase):
@@ -1081,13 +1090,16 @@
def test_site(self):
self.assertRaises(ftplib.error_perm, self.client.sendcmd, 'site')
self.assertRaises(ftplib.error_perm,
self.client.sendcmd, 'site ?!?')
- self.assertRaises(ftplib.error_perm, self.client.sendcmd, 'site
foo bar')
- self.assertRaises(ftplib.error_perm, self.client.sendcmd, 'sitefoo
bar')
+ self.assertRaises(ftplib.error_perm, self.client.sendcmd,
+ 'site foo bar')
+ self.assertRaises(ftplib.error_perm, self.client.sendcmd,
+ 'sitefoo bar')
def test_site_help(self):
self.client.sendcmd('site help')
self.client.sendcmd('site help help')
- self.assertRaises(ftplib.error_perm, self.client.sendcmd, 'site
help ?!?')
+ self.assertRaises(ftplib.error_perm, self.client.sendcmd,
+ 'site help ?!?')
def test_rest(self):
# Test error conditions only; resumed data transfers are
@@ -1112,7 +1124,8 @@
ftplib.error_perm, self.client.sendcmd, 'opts mlst bad_fact')
self.assertRaises(
ftplib.error_perm, self.client.sendcmd, 'opts mlst type ;')
- self.assertRaises(ftplib.error_perm, self.client.sendcmd, 'opts
not_mlst')
+ self.assertRaises(ftplib.error_perm, self.client.sendcmd,
+ 'opts not_mlst')
# utility function which used for extracting the MLST "facts"
# string from the FEAT response
@@ -1247,7 +1260,8 @@
self.client.cwd(self.tempdir)
self.assertEqual(self.client.pwd(), '/%s' % self.tempdir)
self.client.cwd(subfolder)
- self.assertEqual(self.client.pwd(), '/%s/%s' % (self.tempdir,
subfolder))
+ self.assertEqual(self.client.pwd(),
+ '/%s/%s' % (self.tempdir, subfolder))
self.client.sendcmd('cdup')
self.assertEqual(self.client.pwd(), '/%s' % self.tempdir)
self.client.sendcmd('cdup')
@@ -1277,7 +1291,8 @@
self.client.rmd(self.tempdir)
self.assertRaises(ftplib.error_perm, self.client.rmd,
self.tempfile)
# make sure we can't remove the root directory
- self.assertRaisesRegex(ftplib.error_perm, "Can't remove root
directory",
+ self.assertRaisesRegex(ftplib.error_perm,
+ "Can't remove root directory",
self.client.rmd, u('/'))
def test_dele(self):
@@ -1303,13 +1318,15 @@
'rnto ' + self.tempfile)
# make sure we can't rename root directory
- self.assertRaisesRegex(ftplib.error_perm, "Can't rename home
directory",
+ self.assertRaisesRegex(ftplib.error_perm,
+ "Can't rename home directory",
self.client.rename, '/', '/x')
def test_mdtm(self):
self.client.sendcmd('mdtm ' + self.tempfile)
bogus = os.path.basename(tempfile.mktemp(dir=HOME))
- self.assertRaises(ftplib.error_perm, self.client.sendcmd, 'mdtm '
+ bogus)
+ self.assertRaises(ftplib.error_perm, self.client.sendcmd,
+ 'mdtm ' + bogus)
# make sure we can't use mdtm against directories
try:
self.client.sendcmd('mdtm ' + self.tempdir)
@@ -1335,9 +1352,10 @@
_getmtime = AbstractedFS.getmtime
try:
AbstractedFS.getmtime = lambda x, y: -9000000000
- self.assertRaisesRegex(ftplib.error_perm,
- "550 Can't determine file's last
modification time",
- self.client.sendcmd, 'mdtm ' +
self.tempfile)
+ self.assertRaisesRegex(
+ ftplib.error_perm,
+ "550 Can't determine file's last modification time",
+ self.client.sendcmd, 'mdtm ' + self.tempfile)
# make sure client hasn't been disconnected
self.client.sendcmd('noop')
finally:
@@ -1547,7 +1565,8 @@
conn.close()
# transfer finished, a 226 response is expected
self.assertEqual('226', self.client.voidresp()[:3])
- self.client.retrbinary('retr ' + filename,
self.dummy_recvfile.write)
+ self.client.retrbinary('retr ' + filename,
+ self.dummy_recvfile.write)
self.dummy_recvfile.seek(0)
self.assertEqual(hash(data), hash(self.dummy_recvfile.read()))
finally:
@@ -1579,7 +1598,8 @@
# login as a limited user in order to make STOU fail
self.client.login('anonymous', '@nopasswd')
before = os.listdir(HOME)
- self.assertRaises(ftplib.error_perm, self.client.sendcmd, 'stou '
+ TESTFN)
+ self.assertRaises(ftplib.error_perm, self.client.sendcmd,
+ 'stou ' + TESTFN)
after = os.listdir(HOME)
if before != after:
for file in after:
@@ -1647,8 +1667,8 @@
file_size = self.client.size(TESTFN)
self.assertEqual(file_size, bytes_sent)
self.client.sendcmd('rest %s' % ((file_size + 1)))
- self.assertRaises(ftplib.error_perm, self.client.sendcmd, 'stor '
+ TESTFN)
-
+ self.assertRaises(ftplib.error_perm, self.client.sendcmd,
+ 'stor ' + TESTFN)
self.client.sendcmd('rest %s' % bytes_sent)
self.client.storbinary('stor ' + TESTFN, self.dummy_sendfile)
@@ -1690,7 +1710,8 @@
# socket.error (Windows) or EOFError (Linux) exception is supposed
# to be raised in such a case.
self.client.sock.settimeout(.1)
- self.assertRaises((socket.error, EOFError),
self.client.sendcmd, 'noop')
+ self.assertRaises((socket.error, EOFError),
+ self.client.sendcmd, 'noop')
def test_stor_empty_file(self):
self.client.storbinary('stor ' + TESTFN, self.dummy_sendfile)
@@ -1802,8 +1823,8 @@
# on retr (RFC-1123)
file_size = self.client.size(TESTFN)
self.client.sendcmd('rest %s' % ((file_size + 1)))
- self.assertRaises(ftplib.error_perm, self.client.sendcmd, 'retr '
+ TESTFN)
-
+ self.assertRaises(ftplib.error_perm, self.client.sendcmd,
+ 'retr ' + TESTFN)
# test resume
self.client.sendcmd('rest %s' % received_bytes)
self.client.retrbinary("retr " + TESTFN, self.dummyfile.write)
@@ -1907,7 +1928,8 @@
self.assertEqual(mlstline('mlst'), mlstline('mlst /'))
# non-existent path
bogus = os.path.basename(tempfile.mktemp(dir=HOME))
- self.assertRaises(ftplib.error_perm, self.client.sendcmd, 'mlst '
+ bogus)
+ self.assertRaises(ftplib.error_perm, self.client.sendcmd,
+ 'mlst ' + bogus)
# test file/dir notations
self.assertTrue('type=dir' in mlstline('mlst'))
self.assertTrue('type=file' in mlstline('mlst ' + TESTFN))
@@ -1968,7 +1990,8 @@
resp = self.client.getmultiline()
self.assertEqual(resp, '550 Globbing not supported.')
bogus = os.path.basename(tempfile.mktemp(dir=HOME))
- self.assertRaises(ftplib.error_perm, self.client.sendcmd, 'stat '
+ bogus)
+ self.assertRaises(ftplib.error_perm, self.client.sendcmd,
+ 'stat ' + bogus)
def test_unforeseen_time_event(self):
# Emulate a case where the file last modification time is prior
@@ -2100,7 +2123,8 @@
def _throttle_bandwidth(self, *args, **kwargs):
ThrottledDTPHandler._throttle_bandwidth(self, *args,
**kwargs)
- if self._throttler is not None and not
self._throttler.cancelled:
+ if (self._throttler is not None
+ and not self._throttler.cancelled):
self._throttler.call()
self._throttler = None
@@ -2194,7 +2218,8 @@
data = self.client.sock.recv(BUFSIZE)
self.assertEqual(data, b("421 Control connection timed out.\r\n"))
# ensure client has been kicked off
- self.assertRaises((socket.error, EOFError),
self.client.sendcmd, 'noop')
+ self.assertRaises((socket.error, EOFError), self.client.sendcmd,
+ 'noop')
def test_data_timeout(self):
# Test data channel timeout. The client which does not send
@@ -2210,7 +2235,8 @@
data = self.client.sock.recv(BUFSIZE)
self.assertEqual(data, b("421 Data connection timed out.\r\n"))
# ensure client has been kicked off
- self.assertRaises((socket.error, EOFError),
self.client.sendcmd, 'noop')
+ self.assertRaises((socket.error, EOFError), self.client.sendcmd,
+ 'noop')
s.close()
def test_data_timeout_not_reached(self):
@@ -2245,7 +2271,8 @@
data = self.client.sock.recv(BUFSIZE)
self.assertEqual(data, b("421 Data connection timed out.\r\n"))
# ensure client has been kicked off
- self.assertRaises((socket.error, EOFError),
self.client.sendcmd, 'noop')
+ self.assertRaises((socket.error, EOFError), self.client.sendcmd,
+ 'noop')
s.close()
def test_idle_data_timeout2(self):
@@ -2262,7 +2289,8 @@
data = self.client.sock.recv(BUFSIZE)
self.assertEqual(data, b("421 Control connection timed out.\r\n"))
# ensure client has been kicked off
- self.assertRaises((socket.error, EOFError),
self.client.sendcmd, 'noop')
+ self.assertRaises((socket.error, EOFError), self.client.sendcmd,
+ 'noop')
s.close()
def test_pasv_timeout(self):
@@ -2415,11 +2443,13 @@
# Test FTPHandler.max_login_attempts attribute.
self.server.handler.max_login_attempts = 1
self.server.handler._auth_failed_timeout = 0
- self.assertRaises(ftplib.error_perm,
self.client.login, 'wrong', 'wrong')
+ self.assertRaises(ftplib.error_perm, self.client.login, 'wrong',
+ 'wrong')
# socket.error (Windows) or EOFError (Linux) exceptions are
# supposed to be raised when attempting to send/recv some data
# using a disconnected socket
- self.assertRaises((socket.error, EOFError),
self.client.sendcmd, 'noop')
+ self.assertRaises((socket.error, EOFError), self.client.sendcmd,
+ 'noop')
def test_masquerade_address(self):
# Test FTPHandler.masquerade_address attribute
@@ -3032,7 +3062,8 @@
def test_epsv_all(self):
self.client.sendcmd('epsv all')
self.assertRaises(ftplib.error_perm, self.client.sendcmd, 'pasv')
- self.assertRaises(ftplib.error_perm, self.client.sendport,
self.HOST, 2000)
+ self.assertRaises(ftplib.error_perm, self.client.sendport,
self.HOST,
+ 2000)
self.assertRaises(ftplib.error_perm, self.client.sendcmd,
'eprt |%s|%s|%s|' % (self.proto, self.HOST,
2000))
@@ -3245,7 +3276,8 @@
class TestFS(AbstractedFS):
def mkstemp(self, *args, **kwargs):
- raise IOError(errno.EEXIST, "No usable temporary file name
found")
+ raise IOError(errno.EEXIST,
+ "No usable temporary file name found")
self.server.handler.abstracted_fs = TestFS
try:
@@ -3385,7 +3417,8 @@
resp = self.client.cwd(TESTFN_UNICODE)
self.assertTrue(TESTFN_UNICODE in resp)
else:
- self.assertRaises(ftplib.error_perm, self.client.cwd,
TESTFN_UNICODE)
+ self.assertRaises(ftplib.error_perm, self.client.cwd,
+ TESTFN_UNICODE)
def test_mkd(self):
if self.utf8fs:
@@ -3394,13 +3427,15 @@
self.assertEqual(dirname, '/' + TESTFN_UNICODE)
self.assertTrue(os.path.isdir(TESTFN_UNICODE))
else:
- self.assertRaises(ftplib.error_perm, self.client.mkd,
TESTFN_UNICODE)
+ self.assertRaises(ftplib.error_perm, self.client.mkd,
+ TESTFN_UNICODE)
def test_rmdir(self):
if self.utf8fs:
self.client.rmd(TESTFN_UNICODE)
else:
- self.assertRaises(ftplib.error_perm, self.client.rmd,
TESTFN_UNICODE)
+ self.assertRaises(ftplib.error_perm, self.client.rmd,
+ TESTFN_UNICODE)
def test_rnfr_rnto(self):
if self.utf8fs:
@@ -3492,7 +3527,8 @@
dummy.seek(0)
self.client.storbinary('stor ' + TESTFN_UNICODE_2, dummy)
dummy_recv = BytesIO()
- self.client.retrbinary('retr ' + TESTFN_UNICODE_2,
dummy_recv.write)
+ self.client.retrbinary('retr ' + TESTFN_UNICODE_2,
+ dummy_recv.write)
dummy_recv.seek(0)
self.assertEqual(dummy_recv.read(), data)
else: