Errno 22 с функцией Shutil Python и .move()

Итак, я отлаживал это большую часть дня, и я бросаю полотенце.

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

Тем не менее, это последний бит, который удерживает меня. Все работает прекрасно, пока я не перехожу к той части, где копирую папку, переданную в качестве аргумента, обратно на сервер.

Вот проблемный кусок кода:

print "Match Source: " + match_src

archive_folder_name = match_src.rsplit('/', 1)[1]

print "Archive Folder Name: " + archive_folder_name

if not (os.path.isdir(os.path.join(os.path.dirname(match_src), "Archive"))):
    os.mkdir(os.path.join(os.path.dirname(match_src), "Archive"))

archive_dst = os.path.join(os.path.join(os.path.dirname(match_src), "Archive"), archive_folder_name)

print "Archived Folder Destination: " + archive_dst

# okay, archive folder has been made. Now we need to move the old
# stuff to this folder.

shutil.move(match_src, archive_dst)

# okay, archive folder is filled. Now to move the new stuff there
print "Updated Source: " + updated_folder_path

print "Destination: " + os.path.dirname(match_src)

shutil.move(updated_folder_path, os.path.dirname(match_src))

А вот вывод этих операторов печати и код ошибки:

ServerReturn mwl36$ python serverreturn_main.py /Users/mwl36/Desktop/Week\ 1 
I'm on a Mac.
Path: /Users/mwl36/Desktop/Week 1
Folder: Week 1
Match Source: /Volumes/GCPSX Mac HD/ID/Marisa/Work for Student Workers/201315/SERVERTEST/Week 1
Archive Folder Name: Week 1
Archived Folder Destination: /Volumes/GCPSX Mac HD/ID/Marisa/Work for Student Workers/201315/SERVERTEST/Archive/Week 1
Updated Source: /Users/mwl36/Desktop/Week 1
Destination: /Volumes/GCPSX Mac HD/ID/Marisa/Work for Student Workers/201315/SERVERTEST
Traceback (most recent call last):
  File "serverreturn_main.py", line 124, in <module>
    main()
  File "serverreturn_main.py", line 117, in main
    shutil.move(updated_folder_path, os.path.dirname(match_src))
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/shutil.py", line 296, in move
    copytree(src, real_dst, symlinks=True)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/shutil.py", line 206, in copytree
    raise Error, errors
shutil.Error: [('/Users/mwl36/Desktop/Week 1/testfile.txt', '/Volumes/GCPSX Mac HD/ID/Marisa/Work for Student Workers/201315/SERVERTEST/Week 1/testfile.txt', "[Errno 22] Invalid argument: '/Volumes/GCPSX Mac HD/ID/Marisa/Work for Student Workers/201315/SERVERTEST/Week 1/testfile.txt'")]

Где я ошибаюсь? Если вызов do shutdown.move(src, dst) сработал в первый раз без проблем, почему здесь он рвет? Я пытался добавить задержку после первоначального вызова, но безрезультатно.

РЕДАКТИРОВАТЬ: Что еще более странно, так это то, что он действительно выполнит перемещение, но, похоже, никогда не удалит старую папку на рабочем столе. По сути, он копирует папку в папку DST, но не очищает ее после себя.

РЕДАКТИРОВАТЬ № 2: Вызов os.listdir показывает, что каталог исчез, и что единственное, что там было до второго вызова перемещения, - это «Архив». Я проверю copy() завтра, когда буду на работе, и у меня снова будет доступ к коду.


person Brynn Flynn    schedule 04.09.2013    source источник
comment
Кажется, он висит на копитри. Copytree не может находиться в месте, где dst уже существует, по крайней мере, это я понимаю из документации.   -  person Benjooster    schedule 04.09.2013
comment
Вопрос ко всем присутствующим: может ли shutil.move принимать аргумент с пробелом? Другими словами, не должно ли это привести к ошибке в следующем: /Volumes/GCPSX Mac HD/..., потому что это похоже на три аргумента?   -  person erewok    schedule 04.09.2013
comment
@erewok Он будет принимать пробелы, если он вводится как необработанная строка. Ошибка выглядит так, как будто она недовольна форматом, но это может быть просто из-за вставки в stackoverflow.   -  person Benjooster    schedule 04.09.2013
comment
@Benjooster Я так и думал, но я установил задержку в программе между двумя вызовами перемещения, что дало бы ей время для очистки (и я смотрел ее в каталоге файлов), и она все равно выдавала ошибку. Хм. Может быть, вызов listdir поможет вырваться из этого дерьма и проверить, что старая неделя 1 находится вне этого места?   -  person Brynn Flynn    schedule 05.09.2013
comment
@erewok Это возможно, но если бы это было так, это должно было бы дать сбой при первом вызове, а не при втором.   -  person Brynn Flynn    schedule 05.09.2013
comment
@BrynnFlynn Вы пробовали os.listdir? Каталог точно пропал? Я вижу вашу правку в исходном сообщении. Вы пытались использовать Shutil.copy для перезаписи каталога назначения?   -  person Benjooster    schedule 05.09.2013
comment
Если он все еще не очищается, вы можете вызвать Shutil.rmtree, прежде чем пытаться второй шаг.   -  person Benjooster    schedule 05.09.2013
comment
@Benjooster Извини, я шел домой с работы! Listdir показывает, что в DST нет других каталогов непосредственно перед вызовом move. Я попробую ваши предложения с копией и rmtree, чтобы посмотреть, поможет ли это мне.   -  person Brynn Flynn    schedule 05.09.2013
comment
Если ошибка в copystat, как ответ ниже shutil.copy, следует избегать этого, поскольку он исключает метаданные. Если вам нужны метаданные, вам придется выполнить отладку, как указано ниже. Если shutil.move все еще не работает, вы можете использовать shutil.copy2, который будет включать данные копистата. Однако, если ошибка связана с копистатом, я считаю, что это все равно не удастся.   -  person Benjooster    schedule 05.09.2013
comment
Я знаю, что это кажется глупым, но вы пробовали это без os.path.dirname? Вы должны получить сообщение об ошибке, что каталог уже существует, но вы не получаете эту ошибку при первом перемещении, и ясно, что папка Week 1 уже существует в папке архива.   -  person Benjooster    schedule 05.09.2013


Ответы (1)


shutil.move() скопирует источник в место назначения, а затем удалит источник, если «простое перемещение» невозможно. Это может произойти, например, когда источник и место назначения находятся в разных файловых системах.

В данном случае shutil.move() делает именно это: сначала копирует источник в место назначения, а затем выполняет rmtree() в источнике.

Во время копирования shutil скопирует байты исходных файлов, а затем скопирует «статистику» (разрешения, время модификации и т. д.). Итак, похоже, что [Errno 22] Invalid argument происходит либо от копирования байтов, либо от копирования данных статистики. Кажется очень маловероятным, что копирование байтов вызовет ошибку EINVAL, поэтому наиболее вероятным объяснением является то, что копирование данных "stat" вызывает эту ошибку.

Вы можете проверить это, добавив что-то вроде этого в начало основного скрипта:

import shutil
import sys
import traceback

orig_copystat = shutil.copystat
def my_copystat(src, dst):
    try:
        orig_copystat(src, dst)
    except Exception as e:
        sys.stdout.write('copystat failed: %s\n' % e)
        traceback.print_exc()

shutil.copystat = my_copystat

# Your script here...

Если мое предположение верно, вы увидите copystat failed: ... сообщений (и трассировку стека) при запуске скрипта, но в противном случае он должен "работать". Если вы видите сообщение об ошибке из приведенной выше функции, вы можете изменить указанную выше функцию, чтобы она молча игнорировала исключение и запускала свой скрипт. В противном случае попробуйте выполнить обезьянью исправление shutil.copyfile, как указано выше, и посмотрите, где именно в copyfile() возникает исключение.

person Alok--    schedule 05.09.2013