Hello, first thing to say -> Great work !
I have tried to setup a demo ftpd server using the library and everything works as I want (I know the sample code here is missing a few things, but I have tried to track it down):
import os
import sys
import time
import threading
import logging.handlers
from pyftpdlib.log import logger, LogFormatter
from pyftpdlib._compat import b, unicode
from pyftpdlib.filesystems import AbstractedFS
from pyftpdlib.servers import ThreadedFTPServer
from pyftpdlib.handlers import FTPHandler, TLS_FTPHandler
from pyftpdlib.authorizers import DummyAuthorizer, AuthenticationFailed
class MyHandler(FTPHandler):
  def on_disconnect(self):
    pass
class MyTLSHandler(TLS_FTPHandler):
  def on_disconnect(self):
    pass
class test_ftpd(threading.Thread):
  handler = None
  server_class = ThreadedFTPServer
  def __init__(self):
    threading.Thread.__init__(self)
    self.__serving = False
    self.__lock = threading.Lock()
    self.__flag = threading.Event()
    channel = logging.handlers.RotatingFileHandler('./test_ftpd.log', maxBytes=1024, backupCount=6)
    channel.setFormatter(LogFormatter())
    logger = logging.getLogger('pyftpdlib')
    logger.addHandler(channel)
    logger.setLevel(logging.INFO)
    ftpd_usetls = 0
    authorizer = DummyAuthorizer()
    if not ftpd_usetls:
      self.handler = MyHandler
    else:
      self.handler = MyTLSHandler
      self.handler.certfile = './test_ftpd.pem'
    self.handler.authorizer = authorizer
    self.handler.abstracted_fs = AbstractedFS
    self.handler.banner = "test ftpd ready."
    self.server = self.server_class(('0.0.0.0', 21), self.handler)
  @property
  def running(self):
    return self.__serving
  def start(self, timeout=0.001):
    if self.__serving:
      raise RuntimeError("Server already started")
    self.__timeout = timeout
    threading.Thread.start(self)
    self.__flag.wait()
  def run(self):
    self.__serving = True
    self.__flag.set()
    self.server._log_start()
    while self.__serving:
      self.__lock.acquire()
      self.server.serve_forever(timeout=self.__timeout, blocking=False)
      self.__lock.release()
   Â
logger.info(">>> shutting down FTP server (%s active fds) <<<", self.server._map_len())
    self.server.close_all()
  def stop(self):
    if not self.__serving:
      raise RuntimeError("Server not started yet")
    self.__serving = False
    self.join(timeout=10)
    if threading.activeCount() > 1:
     Â
logger.info('FTP server thread is still running')
def main(argv):
  server = test_ftpd()
  server.start()
  while server.running:
    try:
      time.sleep(1.0)
    except KeyboardInterrupt:
      server.stop()
if __name__ == '__main__':
  main(sys.argv[1:])
Then I tried to compile with py2exe:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from distutils.core import setup
import py2exe
class Target(object):
  '''Target is the baseclass for all executables that are created.
  It defines properties that are shared by all of them.
  '''
  def __init__(self, **kw):
    self.__dict__.update(kw)
    # the VersionInfo resource, uncomment and fill in those items
    # that make sense:
    Â
    # The 'version' attribute MUST be defined, otherwise no versioninfo will be built:
    # self.version = "1.0"
    Â
    self.company_name = "Test"
    self.copyright = "Copyright Test © 2014"
    # self.legal_copyright = "Copyright Company Name © 2013"
    # self.legal_trademark = ""
    # self.product_version = "1.0.0.0"
    self.product_name = "test FTP server"
    # self.private_build = "foo"
    # self.special_build = "bar"
  def copy(self):
    return Target(**self.__dict__)
  def __setitem__(self, name, value):
    self.__dict__[name] = value
test_ftpd = Target(
  # We can extend or override the VersionInfo of the base class:
  version = "1.0",
  # file_description = "File Description",
  # comments = "Some Comments",
  # internal_name = "spam",
  script="test.py", # path of the main script
  # Allows to specify the basename of the executable, if different from 'test'
  # dest_base = "test",
  # Icon resources:[(resource_id, path to .ico file), ...]
  # icon_resources=[(1, r"test.ico")]
  )
py2exe_options = dict(
  packages = [],
## Â Â excludes = "tof_specials Tkinter".split(),
## Â Â ignores = "dotblas gnosis.xml.pickle.parsers._cexpat mx.DateTime".split(),
## Â Â dll_excludes = "MSVCP90.dll mswsock.dll powrprof.dll".split(),
  optimize=2,
  compressed=True, # uncompressed may or may not have a faster startup
  bundle_files=0,
  dist_dir='dist_test',
  )
setup(name="name",
   # console based executables
   console=[test_ftpd],
   # py2exe options
   zipfile=None,
   options={"py2exe": py2exe_options},
   )
The compile is ok and I get the exe, but when I try to start it I get the following error:
Traceback (most recent call last):
 File "test.py", line 13, in <module>
ImportError: cannot import name 'TLS_FTPHandler'
What is going wrong here ?
My System:
Windows 7 64 Bit
Python 3.4.1 64 Bit
py2exe for python 3