Уведомления

Группа в Telegram: @pythonsu

#1 Апрель 20, 2015 20:23:36

l1nx
Зарегистрирован: 2015-04-12
Сообщения: 20
Репутация: +  0  -
Профиль   Отправить e-mail  

Покомментируйте код

Скрипт для копирования фото с телефона на nas и сортировкой по папкам с датой

#!/usr/bin/env python
import sys, os.path, shutil, re
from PIL import Image
from PIL.ExifTags import TAGS
# ./phone_photos_to_nas.py input_dir output_dir
inputdir  = sys.argv[1]
outputdir = sys.argv[2]
def main ():
    if os.path.isdir(inputdir):
        for root, dirs, files in os.walk(inputdir):
            for f in files:
                # if filename like 20141111_191402.jpg
                match_obj = re.match(r"\d{8}_\d{6}", f)
                if match_obj:
                    year  = f[0:4]
                    month = f[4:6]
                    day   = f[6:8]
                    date  = day + '.' + month + '.' + year
                else:
                    # get date from exif data
                    img_info = {}
                    i = Image.open(os.path.join(root, f))
                    info = i._getexif()
                    for tag, value in info.items():
                        decoded = TAGS.get(tag, tag)
                        img_info[decoded] = value
                    raw_date = img_info['DateTimeDigitized'] # 2014:11:11 19:14:02
                    year  = raw_date[0:4]
                    month = raw_date[5:7]
                    day   = raw_date[8:10]
                    date  = day + '.' + month + '.' + year
                dirs = os.walk(outputdir).next()[1]
                if date in dirs:
                    shutil.copy2(os.path.join(root, f), os.path.join(outputdir, date))
                else:
                    os.makedirs(os.path.join(outputdir, date))
                    shutil.copy2(os.path.join(root, f), os.path.join(outputdir, date))
    print "Done!"
main()

Офлайн

#2 Апрель 20, 2015 21:59:47

terabayt
От: Киев
Зарегистрирован: 2011-11-26
Сообщения: 1099
Репутация: +  103  -
Профиль   Отправить e-mail  

Покомментируйте код

сразу бросается

                match_obj = re.match(r"\d{8}_\d{6}", f)
                if match_obj:
                    year  = f[0:4]
                    month = f[4:6]
                    day   = f[6:8]
                    date  = day + '.' + month + '.' + year
                    year  = raw_date[0:4]
                    month = raw_date[5:7]
                    day   = raw_date[8:10]
                    date  = day + '.' + month + '.' + year
как миниму нужно вынести в отдельнуюю функцию, но лучше как-то сделать красивее!

if os.path.isdir(inputdir):
а что если будет передано что-то что не проходит условие?
выведет Done!
а нужно предупреждение или ошибку

import sys, os.path, shutil, re
os.makedirs(os.path.join(outputdir, date))
ну я думаю вы поняли



————————————————
-*- Simple is better than complex -*-

Офлайн

#3 Апрель 21, 2015 00:18:00

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10016
Репутация: +  857  -
Профиль   Отправить e-mail  

Покомментируйте код

l1nx
match_obj = re.match(r"\d{8}_\d{6}", f)
if match_obj:
    year  = f[0:4]
    month = f[4:6]
    day   = f[6:8]
    date  = day + '.' + month + '.' + year

>>> import re
>>> 
>>> s = '20141111_191402.jpg'
>>> 
>>> match = re.match(r'(\d{4})(\d{2})(\d{2})_\d{6}', s)
>>> day, month, year = match.groups()[::-1]
>>> date = '{}.{}.{}'.format(day, month, year)
>>> date
'11.11.2014'
>>>


l1nx
import sys, os.path, shutil, re
1) Это всё надо на разных строках писать. (прочитай PEP8 и PEP20 из списка)
2) os.path не надо импортировать, так как он доступен при импорте os.


Ещё код слишком большой. Нужно делать функции, где каждая функция целиком помещается на экране (25 строк) и выполняет только одну задачу.



Отредактировано py.user.next (Апрель 21, 2015 00:35:25)

Офлайн

#4 Апрель 22, 2015 17:43:27

l1nx
Зарегистрирован: 2015-04-12
Сообщения: 20
Репутация: +  0  -
Профиль   Отправить e-mail  

Покомментируйте код

Версия 2. Разбила функцию на функции и добавлена обработка ошибок

#!/usr/bin/env python
import os
import re
import shutil
import sys
from PIL import Image
from PIL.ExifTags import TAGS
# ./phone_photos_to_nas.py input_dir output_dir
if len(sys.argv) == 2 and (sys.argv[1] == '-h' or sys.argv[1] == 'help'):
    exit("Need 2 arguments: input_dir and output_dir")
elif len(sys.argv)!= 3:
    exit("Error: need 2 arguments: input_dir and output_dir")
inputdir = sys.argv[1]
outputdir = sys.argv[2]
date = ''
def main():
    if os.path.isdir(inputdir):
        for root, dirs, files in os.walk(inputdir):
            for f in files:
                # if filename like 20141111_191402.jpg
                match_obj = re.match(r"\d{8}_\d{6}", f)
                if match_obj:
                    format_date(f)
                else:
                    # get date from exif data
                    img_info = {}
                    i = Image.open(os.path.join(root, f))
                    info = i._getexif()
                    for tag, value in info.items():
                        decoded = TAGS.get(tag, tag)
                        img_info[decoded] = value
                    format_date(img_info['DateTimeDigitized']) # 2014:11:11 19:14:02
                copy_files(root, f, date)
    else:
        print inputdir +" is not dir"
def copy_files(root, f, date):
    if os.path.isdir(outputdir):
        dirs = os.walk(outputdir).next()[1]
        if date in dirs:
            shutil.copy2(os.path.join(root, f), os.path.join(outputdir, date))
        else:
            os.mkdir(os.path.join(outputdir, date))
            shutil.copy2(os.path.join(root, f), os.path.join(outputdir, date))
    else:
        print outputdir +" is not dir"
def format_date(s):
    match = re.match(r'(\d{4}):?(\d{2}):?(\d{2})[_|\s]\d{2}:?\d{2}:?\d{2}', s)
    day, month, year = match.groups()[::-1]
    global date
    date = '{}.{}.{}'.format(day, month, year)
    return date # '11.11.2014'
main()

Офлайн

#5 Апрель 22, 2015 19:03:21

terabayt
От: Киев
Зарегистрирован: 2011-11-26
Сообщения: 1099
Репутация: +  103  -
Профиль   Отправить e-mail  

Покомментируйте код

date = ''
global date
не нужно так делать
____________
def format_date(s):
    match = re.match(r'(\d{4}):?(\d{2}):?(\d{2})[_|\s]\d{2}:?\d{2}:?\d{2}', s)
    day, month, year = match.groups()[::-1]
    global date
    date = '{}.{}.{}'.format(day, month, year)
    return date # '11.11.2014'
очень большая, нужно воспользоваться функциями модуля datetime
_____________
                    i = Image.open(os.path.join(root, f))
                    info = i._getexif()
                    for tag, value in info.items():
                        decoded = TAGS.get(tag, tag)
                        img_info[decoded] = value
                    format_date(img_info['DateTimeDigitized']) # 2014:11:11 19:14:02
а попробуйте
                    i = Image.open(os.path.join(root, f))
                    info = i._getexif()
                    img_info = dict(info.items())
                    format_date(img_info['DateTimeDigitized']) # 2014:11:11 19:14:02
или же так как у меня
______________
вот мой вариант, не проверял
но думаю понятно что я хочу сказать :)
#!/usr/bin/env python
import os
import re
import shutil
import sys
from datetime import datetime
from PIL import Image
from PIL.ExifTags import TAGS
# ./phone_photos_to_nas.py input_dir output_dir
if len(sys.argv) == 2 and (sys.argv[1] == '-h' or sys.argv[1] == 'help'):
    exit("Need 2 arguments: input_dir and output_dir")
elif len(sys.argv)!= 3:
    exit("Error: need 2 arguments: input_dir and output_dir")
def main(inputdir, outputdir):
    if os.path.isdir(inputdir):
        for root, dirs, files in os.walk(inputdir):
            for f in files:
                # if filename like 20141111_191402.jpg
                match_obj = re.match(r"\d{8}_\d{6}", f)
                if match_obj:
                    date = format_date(f, "%Y%m%d_%H%M%S")
                else:
                    info = Image.open(os.path.join(root, f))._getexif()
                    for tag, value in info.items():
                        if TAGS.get(tag, tag) == 'DateTimeDigitized':
                            date = format_date(value, "%Y:%m:%d %H:%M:%S")
                            break
                copy_files(root, f, date, outputdir)
    else:
        print inputdir +" is not dir"
def copy_files(root, f, date, outputdir):
    if os.path.isdir(outputdir):
        dirs = os.walk(outputdir).next()[1]
        if date in dirs:
            shutil.copy2(os.path.join(root, f), os.path.join(outputdir, date))
        else:
            os.mkdir(os.path.join(outputdir, date))
            shutil.copy2(os.path.join(root, f), os.path.join(outputdir, date))
    else:
        print outputdir +" is not dir"
def format_date(s, r):
    return datetime.strftime(datetime.strptime(s, r), "%d.%m.%Y")
main(sys.argv[1], sys.argv[2])



————————————————
-*- Simple is better than complex -*-

Отредактировано terabayt (Апрель 22, 2015 19:04:27)

Офлайн

#6 Апрель 23, 2015 00:54:47

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10016
Репутация: +  857  -
Профиль   Отправить e-mail  

Покомментируйте код

terabayt
нужно воспользоваться функциями модуля datetime
Не, ей просто надо переставить символы в имени файла. С датой/временем она не работает никак.
Просто функцию надо назвать не format_date(), а translate_name() или около того.

l1nx
if len(sys.argv) == 2 and (sys.argv[1] == '-h' or sys.argv[1] == 'help'):
    exit("Need 2 arguments: input_dir and output_dir")
elif len(sys.argv)!= 3:
    exit("Error: need 2 arguments: input_dir and output_dir")
inputdir = sys.argv[1]
outputdir = sys.argv[2]
Вот это всё надо заменить на argparse; там всё красиво, удобно и компактно.
Посмотришь примеры, он простой.

l1nx
inputdir = sys.argv[1]
outputdir = sys.argv[2]
date = ''
Глобальных переменных и ссылок на них вообще не должно быть.
Функции должны зависеть только от себя самих, иначе они будут ломаться из-за изменений в других функциях.

l1nx
print outputdir +" is not dir"
Старайся делать функции такими, чтобы они ничего не выводили, а либо возвращали значение True/False, 0 (успех) / 1 2 3 4 … (ошибка), либо порождали исключение в случае ошибки, а в случае успеха не возвращали ничего.
А вывод уже основывается снаружи на этих значениях.



Отредактировано py.user.next (Апрель 23, 2015 01:00:15)

Офлайн

#7 Апрель 23, 2015 01:03:47

terabayt
От: Киев
Зарегистрирован: 2011-11-26
Сообщения: 1099
Репутация: +  103  -
Профиль   Отправить e-mail  

Покомментируйте код

py.user.next
Не, ей просто надо переставить символы в имени файла. С датой/временем она не работает никак.
Просто функцию надо назвать не format_date(), а translate_name() или около того.
img_info = {}
i = Image.open(os.path.join(root, f))
info = i._getexif()
for tag, value in info.items():
    decoded = TAGS.get(tag, tag)
    img_info[decoded] = value
format_date(img_info['DateTimeDigitized']) # 2014:11:11 19:14:02
а это? я сильно не вникал
строковое представление лучше же переделать через модуль datetime чем переставлять местами символы?!



————————————————
-*- Simple is better than complex -*-

Отредактировано terabayt (Апрель 23, 2015 01:04:18)

Офлайн

#8 Апрель 23, 2015 01:19:50

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10016
Репутация: +  857  -
Профиль   Отправить e-mail  

Покомментируйте код

terabayt
а это? я сильно не вникал
А, она, походу, слила две функции в одну.

l1nx
match = re.match(r'(\d{4}):?(\d{2}):?(\d{2})[_|\s]\d{2}:?\d{2}:?\d{2}', s)
А я ещё думаю, что это регулярка у неё такая странная с двоеточиями для имён файлов.

Значит надо две функции: одна переделывает имя, а другая метаданные изображения. И у них должны быть разные регулярки.

terabayt
строковое представление лучше же переделать через модуль datetime чем переставлять местами символы?!
Когда у тебя есть целые числа, обозначающие временные величины, и тебе нужно сформировать на их основе строку - тогда да. А когда у тебя строки, которые просто нужно переставить местами, - тогда нет.

Модуль datetime отвечает за пределы значений (не даёт им вылазить) и знает роль каждого значения (при формировании минуты не окажутся секундами).

Вот пример:
>>> s = '1.12.2015'
>>> 
>>> d, m, y = s.split('.')
>>> 
>>> out = '{}_{}_{}'.format(y, m, d)
>>> out
'2015_12_1'
>>>
Для того, чтобы просто переставить части, не нужно знать, что это - дата. А ты говоришь, что, раз это дата, то нужно использовать datetime. А зачем его тут использовать?



Отредактировано py.user.next (Апрель 23, 2015 01:31:00)

Офлайн

#9 Апрель 23, 2015 01:50:08

terabayt
От: Киев
Зарегистрирован: 2011-11-26
Сообщения: 1099
Репутация: +  103  -
Профиль   Отправить e-mail  

Покомментируйте код

py.user.next
А зачем его тут использовать?
для облегчения и универсальности
py.user.next
Вот пример
это хороший пример, все красиво, но
напишите как это
20141111_191402
2014:11:11 19:14:02
можно так же красиво обработать

py.user.next
А зачем его тут использовать?

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



————————————————
-*- Simple is better than complex -*-

Офлайн

#10 Апрель 23, 2015 03:47:36

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10016
Репутация: +  857  -
Профиль   Отправить e-mail  

Покомментируйте код

terabayt
для облегчения и универсальности
А если там вдруг появятся имена файлов/директорий, которые вообще ничего из даты/времени не содержат?

terabayt
напишите как это
20141111_191402
2014:11:11 19:14:02
можно так же красиво обработать
Это делается канонизация и всё:
>>> import re
>>> 
>>> def trans_name(s):
...     match = re.match(r'(\d{4})(\d{2})(\d{2})\d{6}', s)
...     day, month, year = match.groups()[::-1]
...     out = '{}.{}.{}'.format(day, month, year)
...     return out
... 
>>> def canon(s):
...     return re.sub(r'[ :_]', r'', s)
... 
>>> lst = ['20141111_191402',
...        '2014:11:11 19:14:02',
...        '2014_11_11_19_14_02.jpg']
>>> 
>>> out = [trans_name(canon(i)) for i in lst]
>>> out
['11.11.2014', '11.11.2014', '11.11.2014']
>>>

Но это не её случай всё равно, у неё как бы две части программы друг с другом не связаны, поэтому одну функцию тут лучше не юзать. Иначе если формат метаданных поменяется, то соответствующее изменение кода зацепит формат имени директории и наоборот.



Отредактировано py.user.next (Апрель 23, 2015 04:06:15)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version