``ftputil`` - высокоуровневая библиотека для клиента FTP протокола
==================================================================

:Версия:                   2.1 beta
:Дата:                     2006-02-18
:Резюме:                   высокоуровневая Python библиотека для клиента FTP протокола
:Ключевые слова:           FTP, замена ``ftplib``, виртуальная файловая система
:Автор:                    Stefan Schwarzer <sschwarzer@sschwarzer.net>
:Русский перевод:  	   Степанов Антон <antymail@mail.ru>


.. contents:: Содержание

Введение
--------

Модуль ``ftputil`` является высокоуровневым интерфейсом для
ftplib_ модуля.Объекты FTPHost позволяют производить
большое количество операций, аналогичных операциям в модулях os_ и `os.path`_.

.. _ftplib: http://www.python.org/doc/current/lib/module-ftplib.html
.. _os: http://www.python.org/doc/current/lib/module-os.html
.. _`os.path`: http://www.python.org/doc/current/lib/module-os.path.html

Примеры:
  ::

    import ftputil

    # download some files from the login directory
    host = ftputil.FTPHost('ftp.domain.com', 'user', 'password')
    names = host.listdir(host.curdir)
    for name in names:
        if host.path.isfile(name):
            host.download(name, name, 'b')  # remote, local, binary mode

    # make a new directory and copy a remote file into it
    host.mkdir('newdir')
    source = host.file('index.html', 'r')  # file-like object
    target = host.file('newdir/index.html', 'w')  # file-like object
    host.copyfileobj(source, target)  # similar to shutil.copyfileobj
    source.close()
    target.close()

Такие методы как `FTPHost.lstat`_ и `FTPHost.stat`_ позволяют узнать размер
и время изменения файла. Последний может следовать по ссылкам аналогичным
`os.stat`_. Даже, такая функция как `FTPHost.path.walk`_ работает
в этой библиотеке.

.. _`os.stat`: http://www.python.org/doc/current/lib/os-file-dir.html#l2h-1455

Дистрибутив содержит модуль ``UserTuple``, который обеспечивает
совместимость результатов модуля stat_ с версиями Python 2.0 и 2.1.

.. _stat: http://www.python.org/doc/current/lib/module-stat.html

Иерархия исключений
-------------------

Исключения находятся в пространстве имен пакета ``ftputil``
(например: ``ftputil.TemporaryError``). Они организованы следующим образом

  ::

    FTPError
        FTPOSError(FTPError, OSError)
            TemporaryError(FTPOSError)
            PermanentError(FTPOSError)
            ParserError(FTPOSError)
        FTPIOError(FTPError)
        InternalError(FTPError)
            RootDirError(InternalError)
            InaccessibleLoginDirError(InternalError)
        TimeShiftError(FTPError)

ниже приведено описание каждого исключения:

- ``FTPError``

  является корнем иерархии исключений модуля.


- ``FTPOSError``

  потомок ``OSError``. Создан для подобия объектов модуля
  os и объектов модуля ``FTPHost``. Сравните

  ::

    try:
        os.chdir('nonexisting_directory')
    except OSError:
        ...

  с

  ::

    host = ftputil.FTPHost('host', 'user', 'password')
    try:
        host.chdir('nonexisting_directory')
    except OSError:
        ...

  Представим функцию,


  ::

    def func(path, file):
        ...

  которая работает в локальной файловой системе и получает  ошибки
  ``OSErrors``.  Если вы измените список параметров на

  ::

    def func(path, file, os=os):
        ...

  где параметр ``os`` означает ``os`` модуль, то вызывая функцию
  как

  ::

    host = ftputil.FTPHost('host', 'user', 'password')
    func(path, file, os=host)

  Вы сможете использовать тот же самый код как для локальной
  файловой системы так и для удаленной.
  Другое подобие между ``OSError`` и ``FTPOSError`` залючается в том,
  что последний возвращает FTP серверу код ошибки ``errno`` в
  свойстве объекта-исключения и текст ошибки ``strerror``.

- ``TemporaryError``

  это исключение вызывается в том случае, если код ошибки
  полученной от FTP сервера находится в диапазоне от 400 до 499. Это
  исключение соответствует исключению ``ftplib.error_temp`` (хотя
  ``TemporaryError`` и ``ftplib.error_temp`` *не являются* идентичными).

- ``PermanentError``


  это исключение вызывается в том случае, если код ошибки
  полученной от FTP сервера находится в диапазоне от 500 до 599
  (снова, это исключение подобно, но *не* идентично исключению
  ``ftplib.error_perm``).

- ``ParserError``

  ошибка, которая возникает в течение анализа списка каталогов
  из сервера. Это исключение используется такими методами объекта
  ``FTPHost`` как: ``stat``, ``lstat``, и ``listdir``.

- ``FTPIOError``

  это исключение обозначает ошибку ввода/вывода на удаленном
  компьютере. Эта ошибка, главным образом, связана с файл-подобными
  объектами которые были использованы при вызове функции
  ``FTPHost.file`` (``FTPHost.open`` - псевдоним). Сравните:

  ::

    >>> try:
    ...     f = open('notthere')
    ... except IOError, obj:
    ...     print obj.errno
    ...     print obj.strerror
    ...
    2
    No such file or directory

  с

  ::

    >>> host = ftputil.FTPHost('host', 'user', 'password')
    >>> try:
    ...     f = host.open('notthere')
    ... except IOError, obj:
    ...     print obj.errno
    ...     print obj.strerror
    ...
    550
    550 notthere: No such file or directory.

  Как вы можете видеть, отрывки кода подобны. (Однако,
  коды ошибок не являются одинаковыми.)

- ``InternalError``

  относится к классу исключений которое вызывается из-за наличия
  ограничений FTP протокола или в следствие непосредственного выполнения модуля
  ``ftputil``.

- ``RootDirError``

  при выполнении ``lstat`` - метода невозможно выполнить
  ``stat``- запрос к корневому каталогу /.
  Если Вы знаете *способ* как это сделать, пожайлуста, сообщите
  мне. :-)

- ``InaccessibleLoginDirError``

  Это исключение вызывается только в том случае, если выполнятся
  *одно* из следующих условий:

  - Каталог, в который «Вы» помещаетесь при входе в систему не
    доступен, тогда запрос ``chdir`` будет прерван.

  - Ваш путь содержит одни пробелы.

- ``TimeShiftError``
  используется, чтобы обозначить ошибки, которые касаются метода
  `time shift`_, например, попытка установить значение, которое не является
  кратным 1 часу


``FTPHost`` - объекты
---------------------

.. _`FTPHost construction`:

Конструкция
~~~~~~~~~~~

``FTPHost`` запрос может быть произведен с использованием следующего вызова:

  ::

    host = ftputil.FTPHost(host, user, password, account,
                           session_factory=ftplib.FTP)

Первые четыре параметра - строки с тем же самым значением,
что и у FTP класса в ``ftplib`` модуле. Параметр
``session_factory`` may используется для того, чтобы произвести FTP
подключение через другие фабрики, чем установленное по умолчанию значение
``ftplib.FTP``. Например, M2Crypto распределение использует безопасный FTP
класс, который получен из ``ftplib.FTP``.

Фактически, все позиционные и ключевые аргументы отличные от
``session_factory`` проходят на фабрику, чтобы выполнить новый
фоновый сеанс (который выполняется для каждого открытого удаленного файла;
см. ниже).

Эти функциональные возможности конструктора также позволяют "оборачивать"
``ftplib.FTP`` объекты, чтобы делать то, что невозможно сделать 
с использованием одного ``ftplib.FTP`` конструктора.

Например, предположите, что Вы хотите произвести соединение с другим портом,
отличным от заданного по умолчанию, но ``ftplib.FTP`` предлагает это сделать
только с использованием метода ``connect``, но через другой конструктор.
Решение состоит в создании "класса обертки":

  ::

    import ftplib
    import ftputil

    EXAMPLE_PORT = 50001

    class MySession(ftplib.FTP):
        def __init__(self, host, userid, password, port):
            """Act like ftplib.FTP's constructor but connect to other port."""
            ftplib.FTP.__init__(self)
            self.connect(host, port)
            self.login(userid, password)

    # try not to use MySession() as factory, - use the class itself
    host = ftputil.FTPHost(host, userid, password,
                           port=EXAMPLE_PORT, session_factory=MySession)
    # use `host` as usual

При входе в систему, формат списка каталогов (необходимый для
применения stat - методов к файлам и каталогам) определяется
автоматически. Если нет, то Вы можете использовать метод
`set_directory_format`_ , чтобы установить формат "вручную".

``FTPHost`` - свойства и методы
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Свойства
````````

- ``curdir``, ``pardir``, ``sep``

  являются строками, которые обозначают текущий и родительский каталог на 
  на отдаленном сервере. Sep опознает разделитель пути. Хотя 
  `RFC 959`_ (Протокол передачи файлов) обращает внимание на то, что эти
  значения могут зависеть от сервера. Unix машины , кажется, хорошо работают
  даже для не - Unix серверов.

.. _`RFC 959`: `RFC 959 - File Transfer Protocol (FTP)`_

.. _`time shift`:

Коррекция времени часового пояса
````````````````````````````````

.. _`set_time_shift`:

- ``set_time_shift(time_shift)``

  устанавливает так называемое значение сдвига времени (измеряемое в секундах). 
  Сдвиг времени - различие между местным временем сервера и
  местным временем клиента в данный момент, т.е. по определению:

  ::

    time_shift = server_time - client_time

  Установка этого значения важна, если `upload_if_newer`_ и
  `download_if_newer`_ работали правильно, даже если часовой пояс 
  FTP сервера отличается от часового пояса клиента (где 
  библиотека ``ftputil`` запущена). Обратите внимание на то, что значение
  сдвига времени *может быть* отрицательным.

  Если значение сдвига времени является неправльным, например не является кратным 1 часу,
  или абсолютное зачение больше чем 24 часа, то вызывется исключение: ``TimeShiftError``.

  См. также `synchronize_times`_ как простой способ установки сдвига времени.

- ``time_shift()``

  возвращает установленное текущее значение сдвига времени. См. 
  ``set_time_shift`` (выше) для его определения.

.. _`synchronize_times`:

- ``synchronize_times()``

  синхронизирует локальное время сервера и клиента, так,
  чтобы методы `upload_if_newer`_ и `download_if_newer`_ правильно работали,
  даже если клиент и сервер находятся в различных часовых поясах. Для
  того, чтобы *все* это работало должны выполняться следующие условия:

  - Должно быть установлено подключение между сервером и клиентом.

  - Клиент должен иметь доступ к каталогу, который является текущим, когда 
    ``synchronize_times`` вызывается.

  - Каталог, к которому обращаются *не* должен быть корневым каталогом (т.е. /)
    FTP сервера.

  Если Вы не можете выполнить эти условия, Вы можете установить
  значение сдвига времени вручную с использованием `set_time_shift`_. Попытка вызова
  ``synchronize_times``, если вышеупомянутые условия не выполняются приведет к генерации
  ``TimeShiftError`` исключения.

Файлы и каталоги
````````````````

- ``file(path, mode='r')``

  возвращает файл-подобный объект, который связан с путем на отдаленном
  главном компьютере. Этот путь может быть абсолютным, или относительным
  для текущего каталога на отдаленном главном компьютере (этот каталог может быть определен
  с помощью getcwd метода). Также как и для локальных файлов задается по умолчанию режим - "r",
  т. е. чтение текстовых файлов. Допустимые режимы - "r",
  "rb", "w", и "wb".

- ``open(path, mode='r')``

  является псевдонимом для ``file`` (см. выше).

- ``copyfileobj(source, target, length=64*1024)``

  копирует содержимое из файл-подобного объекта-источника
  в файл-подобный объект-адресат. Единственное различие с
  ``shutil.copyfileobj`` - есть заданный по умолчанию размер буфера.

- ``close()``

  закрывает соединение с отдаленным компьютером. После этого,
  взаимодействие с FTP сервером невозможно без создания нового объекта
  ``FTPHost``.

- ``getcwd()``

  возвращает абсолютный путь текущего каталога на отдаленном компьютере. Этот
  метод действует подобно методу ``os.getcwd``.

- ``chdir(directory)``

  устанавливает текущий каталог на FTP сервере. Это метод похож на метод
  ``os.chdir``, а Вы что ожидали.:-)

- ``mkdir(path, [mode])``

  создаёт каталог на отдаленном компьютере. При своём выполнении,
  не создает  "промежуточные" каталоги, которые уже существуют.
  При этом параметр ``mode`` игнорируется. Создан
  для совместимости с ``os.mkdir``,если объект ``FTPHost``
  вставляется в функцию вместо os модуля (см. подраздел
  исключений Питона выше).

- ``makedirs(path, [mode])``
  работает аналогично команде ``mkdir`` (см. выше, но, также, создаёт "промежуточные"
  каталоги (также как и команда ``os.makedirs``). Параметр ``mode`` введен
  только для совместимости с командой ``os.makedirs`` и в данном случае
  игнорируется.

- ``rmdir(path)``

  удаляет заданный удаленный каталог.

  В предыдущих версиях ``ftputil``, эта функция зависела от отдаленного
  сервера, были эти каталоги пустыми или нет. ``ftputil``
  версии 2.0 по умолчанию позволяет удалять только пустые
  каталоги.

  Если Вы хотите установить ``ftputil`` 2.0, но при этом произвести
  минимальные изменения в исходном тексте, добавьте дполнительный параметр
  ``_remove_only_empty=False``. Обратите внимание, что это метод осуждается и,
  вероятно, не будет поддерживаться в следующих версиях ``ftputil``.

- ``remove(path)``

  удаляет файл на отдаленном компьютере (подобен методу ``os.remove``).

- ``unlink(path)``

  является псевдонимом для ``remove``.

- ``rename(source, target)``

  переименовывает исходный файл (или каталог) на FTP сервере.


- ``listdir(path)``

  возвращает список, содержащий имена файлов и каталогов
  по заданном пути; подобен методу ``os.listdir``.

- ``walk(top, topdown=True, onerror=None)``

  команда обхода дерева каталогов, аналогична команде `os.walk`_ в версии Python 2.3.
  Фактически, ``FTPHost.walk`` использует код из Python системы с введением
  необходимых модификаций, см. документацию по языку.

  Если остальные команды библиотеки ftputil могут работать с любой версией Python,
  то начиная с версии 2.0 и выше, метод ``walk`` требует наличие генераторов 
  и будет работать с версией Python 2.2 и выше.

.. _`os.walk`: http://docs.python.org/lib/os-file-dir.html#l2h-1638

Отправка и загрузка файлов
``````````````````````````

- ``upload(source, target, mode='')``

  копирует локальный файл (с заданным именем, например, в виде строки)
  на отдаленный компьютер по соответствующему адресу. Как источник, так и адресат
  могут иметь абсолютные или относительные пути текущего каталога
  (на локальном или отдаленного компьютере, соответственно).
  Режим отправки может быть " " или "@" для ASCII, или "b" для двоичного кода.
  Режим ASCII задан по умолчанию.

- ``download(source, target, mode='')``

  выполняет загрузку из удаленного источника в конечный файл.
  И источник и адресат являются параметрами задаваемыми в виде строки.
  Дополнительное описание применения метода загрузки см. ниже

.. _`upload_if_newer`:

- ``upload_if_newer(source, target, mode='')``

  подобен методу копирования. Единственное отличие - то,
  что файл отправляется, если время последней модификации
  для исходного файла более современное чем конечного файла,
  или адресат не существует вообще. Если отправка фактически происходит,
  то возвращается истинное значение, иначе - ложь.

  Обратите внимание, что этот метод только проверяет существование и/или
  время модификации источника и конечного файла;
  что не может привести замене в режиме передачи, например:

  ::

    # transfer in ASCII mode
    host.upload_if_newer('source_file', 'target_file', 'a')
    # won't transfer the file again
    host.upload_if_newer('source_file', 'target_file', 'b')

  точно так же, если передача прервана, а
  отдаленный файл будет иметь более новую модификацию
  чем локальный файл, то передача не будет повторена,
  даже если будет использоваться ``upload_if_newer`` второй раз.
  Имеются (по крайней мере) две возможности после того, как отправка завершилась неудачей:

  - используйте ``upload`` вместо ``upload_if_newer``, или

  - удалите конечный файл используя ``FTPHost.remove``,
    затем используте ``upload`` или ``upload_if_newer``, чтобы передать файл снова.

  Если кажется, что файл отправлен "напрасно", то читайте подраздел настройки
  `time shift`_.

.. _`download_if_newer`:

- ``download_if_newer(source, target, mode='')``

  соответствует ``upload_if_newer``, но выполняет загрузку
  с сервера на локальный компьютер. Читайте описание процесса загрузки
  с использованием метода ``upload_if_newer``  для того, чтобы узнать больше.
  Если загрузка фактически произошла, то возвращается истинное значение, иначе - ложь.

  Если кажется, что файл отправлен напрасно, то читайте подраздел настройки
  `time shift`_.


Stat - методы для файлов и каталогов
````````````````````````````````````

Методы ``lstat`` и ``stat`` (и другие) основываются
на формате  каталога, используемого FTP сервером. При соединении
с  компьютером, конструктор  ``FTPHost`` выбирает  формат, который, как он считает,
является правильным. Однако, если Вы получите странные результаты
(или исключения), следует установить формат каталога
"вручную". Установка форамата произойдет незамедлительно после вызова функции:

.. _`set_directory_format`:

- ``set_directory_format(server_format)``

  ``server_format`` - представляет собой строку "unix", либо -  "ms". Чтобы
   выбрать правильный формат, Вы должны запустить из командной строки FTP клиент
   и вызвать функцию  листинга каталога (большинство клиентов выполняют данную
   операцию с использованием команды ``DIR``).

  Если результирующие строки  имеют вид:

  ::

      drwxr-sr-x   2 45854    200           512 Jul 30 17:14 image
      -rw-r--r--   1 45854    200          4604 Jan 19 23:11 index.html

  используйте строку "unix" как аргумент.

  Если вывод имеет вид таких строк:

  ::

      12-07-01  02:05PM       <DIR>          XPLaunch
      07-17-00  02:08PM             12266720 digidash.exe

  тогда используте "ms" для установки значения ``server_format``.

  Если ни один из вышеупомянутых параметров настройки не поможет,
  тогда свяжитесь со мной. Был бы очень хорошо, если Вы смогли бы  выслать
  листинг ошибочного вывода (вывод с использованием команды ``DIR``).

Если, при запросе, ``lstat`` или ``stat`` методы выдают неправильное время изменения файла,
или  неправильно выдают дату, используйте методы, которые работают с учётом разницы во времени
(`time shift`_).

.. _`FTPHost.lstat`:

- ``lstat(path)``

  возвращает объект, аналогичный объекту ``os.lstat`` (кортеж с
  дополнительными параметрами;  смотрите документацию по  ``os``
  модулю). Однако, учитывая характер приложения,
  следует обратить внимание на следующие аспекты:

  - Результат получается вследствие анализа вывода команды ``DIR``
    на сервере. Поэтому, результат команды  ``FTPHost.lstat`` не
    может содержать больше информации чем полученный текст.
    В особенности:

  - Пользователь и группа пользователей могут  быть определены толоко через строки, но не
    как числа, и только  сервер выдает эти строки. Это
    Это обычно относится к самим  Unix серверами, но никак не относится к
    FTP программам сервера.

  - Значения  времени последней модификации  файла могут быть неточными,
    все зависит от информации полученной от сервера. Если файл
    был изменен раньше чем год назад , то точность значения времени
    изменения файла не будет больше одного дня. Для более новых
    файлов, точность времени модификации файла  может  быть равной одной минуте.

  - Ссылки могут  быть явными только на тех серверах,
    которые получают информацию из вывода команды ``DIR``.

  - Пункты, которые не могут быть определены принимают значение ``None``.

  - Также существует  проблема с применением stat - метода к корневому каталогу. В
    этом случае вызывается ошибка ``RootDirError``. Проблема имеет отношение к
    алгоритму, используемому в методе ``(l)stat``, и я не знаю ни одного способа, который
    помог бы её решить.

.. update for other servers

..

  В настоящее время, библиотека ``ftputil`` поддерживает формат MS Robin FTP сервера.
  Формат который в основном используется Unix серверами также поддерживается. Если
  Вы нуждаетесь в поддержке других форматов, пожалуйста, свяжитесь со мной
  по электронной почте. Адрес приведён в конце этого текста.

.. implement and document support for setting the directory parser
   "manually"

.. _`FTPHost.stat`:

- ``stat(path)``
  возвращает ``stat`` информацию для файлов, которые указаны по ссылке.
  Этот метод следует по множеству ссылок, пока регулярный файл или каталог
  не будут найдены. Если цепочка ссылок зациклена то вызывается исключение:
  ``PermanentError``.

``FTPHost.path``
~~~~~~~~~~~~~~~~

``FTPHost`` объекты имеют такое свойство как: ``path``, подобное
`os.path`_. Приведенные ниже методы могут прменяться
к отдаленному компьютеру с семантикой кода аналогичной семантике кода методов ``os.path``:

.. _`FTPHost.path.walk`:

::

    abspath(path)
    basename(path)
    commonprefix(path_list)
    dirname(path)
    exists(path)
    getmtime(path)
    getsize(path)
    isabs(path)
    isdir(path)
    isfile(path)
    islink(path)
    join(path1, path2, ...)
    normcase(path)
    normpath(path)
    split(path)
    splitdrive(path)
    splitext(path)
    walk(path, func, arg)

``FTPFile`` - объекты
---------------------

``FTPFile`` объекты создаются при вызове конструкций ``FTPHost.file`` (или
``FTPHost.open``) и имеют аналогичные методы, (с теми же параметрами, и с той же семантикой)
что и методы, работающие с локальными файлами:

  ::

    close()
    read([count])
    readline([count])
    readlines()
    write(data)
    writelines(string_sequence)
    xreadlines()

и атрибут ``closed``. Для получения детальной информации смотрите раздел  `File
objects`_ в справочнике по библиотеке.

.. _`file objects`:
   http://www.python.org/doc/current/lib/bltin-file-objects.html

Обратите внимание на то, что ``ftputil`` поддерживает и двоичный и текстовый режимы
работы со строкой завершающей преобразования.

Советы и подсказки / FAQ
------------------------

Где я могу получить самую последнюю версию?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Смотрите http://www.sschwarzer.net/python/python_software.html#ftputil.
Объявления относительно новых версий будут рассылаться списку адресатов (см. вопрос ниже).
Объявления относительно появления главных модификаций отправляются в
службу новостей `comp.lang.python`_ .

.. _`comp.lang.python`: news:comp.lang.python

Имеется ли почтовый ящик на ``ftputil``?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Да, вы можете подписаться на
http://codespeak.net/mailman/listinfo/ftputil
или прочитать архивы на http://codespeak.net/pipermail/ftputil/.

Я нашел ошибку! Что теперь?
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Перед сообщением об ошибке, удостоверьтесь в том, что Вы пользовались самой последней версией
``ftputil``. Эта ошибка уже могла быть устранена.

Пожалуйста отправьте  отчёт об ошибке (на английском языке) на почтовый ящик  ``ftputil``
или вышлите его прямо мне (адрес электронного почтового ящика приведен в начале этого файла).
В *любом* случае Вы *не должны* включать конфиденциальную информацию
(логин пользователя, пароль, имена файлов, и т.п.) в Ваше письмо.


В сообщении об ошибке, пожалуйста, введите следующую информацию:

- версия ``ftputil``

- версия Python

- тип и версия  FTP сервера (отображается в "сообщении приветствия")

- операционные системы и их версии на сервере и клиенте
  (выводятся при вводе командной строки ``uname -a`` на Unix)

- описание ошибки

- если возможно, то краткий пример кода, который приводит к ошибке

- если возможно, то идеи, которые бы помогли найти причину ошибки

Соединение по другому порту
~~~~~~~~~~~~~~~~~~~~~~~~~~~

По умолчанию, ``FTPHost`` объект соединяется по обычному  FTP порту.
Если Вы хотите использовать другой порт, то просмотрите раздел `FTPHost construction`_.

Вы можете использовать тот же самый подход  как при подключении в активном режиме,
так и при подключении в пассивном режиме, как Вам нравится.

Использование активных или пассивных подключений
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Используйте оберточный класс для ``ftplib.FTP``, как описано в разделе
`FTPHost construction`_::

    import ftplib

    class ActiveFTPSession(ftplib.FTP):
        def __init__(self, host, userid, password):
            """
            Act like ftplib.FTP's constructor but use active mode
            explicitly.
            """
            ftplib.FTP.__init__(self)
            self.connect(host, port)
            self.login(userid, password)
            # see http://docs.python.org/lib/ftp-objects.html
            self.set_pasv(False)

Используйте этот класс как аргумент``session_factory`` в конструкторе``FTPHost``.


Условная отправка/загрузка с/на сервер(а) в различных часовых поясах
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Вы можете заметить, что ``ftputil`` отправляет или загружает лишние файлы,
когда это не требуется. Это может случаться тогда, когда FTP сервер и клиент,
на котором запущена библиотека ``ftputil``, находятся в различных часовых поясах.
Смотрите раздел по установке `time shift`_.
Может быть, достаточно вызвать метод `synchronize_times`_.

Выдаются неправильные даты или время при выполнении  stat - методов на сервере
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

См. предыдущий и следующий советы.

Файл - связанные методы-запросы (например: listdir) возвращают неожиданные результаты
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Если, например, ``listdir`` или ``lstat`` возвращают неправильное значение
или вызывают исключение, то это может происходить из-за неправильно
определенного формата каталога. См. `set_directory_format`_.

Я не нахожу ответ на мою проблему в этом документе
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Пожалуйста, вышлите мне на электронный почтовый ящик Ваш вопрос, и я посмотрю,
что смогу для Вас сделать. :-) Вероятно лучший способ заключается в том,
чтобы выслать ваш вопрос по адресу  ftputil@codespeak.net;
потенциально, гораздо большее число людей сможет помочь Вам.

Ошибки и ограничения
--------------------

- ``ftputil`` нуждается в версии Python 2.0 или выше.

- При выполнении  ``lstat`` метода возвращается неправильное значение для корневого каталога
  ``/``. Если Вы знаете как решить эту проблему, пожалуйста, сообщите мне.
  Корневой каталог может использоваться в таких методах, соответственно:
  ``FTPHost.path.exists/isfile/isdir/islink``,
  хотя...

- Блокировка времени исполнения индивидуальных дочерних процессов.
  Эта проблема возникает в том случае, если ``FTPHost`` объект, или
  генерированные ``FTPFile`` объекты не используются в течение 10 минут и более.

- До сих пор, я не обращал внимание на безопасность потока.
  В принципе, по крайней мере, различные ``FTPFile``
  объекты должны работать в различных потоках.

- ``FTPFile`` объекты в текстовом режиме  *не поддерживают символы*
  размером больше одного байта. Пожалуйста, отправьте мне письмо,
  если вы работатете с мультибайтовыми потоками текста в ваших  FTP сеансах.

- В данной версии невозможно прервать процесс отправки и загрузки файлов.
  Свяжитесь со мной, если у Вас возникли с этим проблемы.

- ``UserTuple`` класс в модуле  ``UserTuple.py``, пока полностью не проверен.
  Если у вас возникла проблема при работе с этим классом, сообщите мне.

Файлы
-----

Если не изменены опции инсталляции, то ``ftputil`` файлы
будут размещены в `ftputil`` пакете. Документация (в
`reStructured Text`_ и в формате HTML ) находится в той же самой директории.

.. _`reStructured Text`: http://docutils.sourceforge.net/rst.html

Файлы ``_test_*.py`` и ``_mock_ftplib.py`` служат для тестирования модуля.
Если Вы  *используете* библиотеку ftputil (т.е. *не модифицируете* её),
Вы можете удалить эти файлы.

Справочники
-----------

- Mackinnon T, Freeman S, Craig P. 2000. `Endo-Testing:
  Unit Testing with Mock Objects`_.

- Postel J, Reynolds J. 1985. `RFC 959 - File Transfer Protocol (FTP)`_.

- Van Rossum G, Drake Jr FL. 2003. `Python Library Reference`_.

.. _`Endo-Testing: Unit Testing with Mock Objects`:
   http://www.connextra.com/aboutUs/mockobjects.pdf
.. _`RFC 959 - File Transfer Protocol (FTP)`: http://www.ietf.org/rfc/rfc959.txt
.. _`Python Library Reference`: http://www.python.org/doc/current/lib/lib.html

Автор
-----

Библиотека ``ftputil`` написана Стефаном Шварцером (Stefan Schwarzer)
<sschwarzer@sschwarzer.net>.

Обратная связь учтена. :-)

