8
\$\begingroup\$

For web-uploading of Cyrillic-named images, I've written the script below:

#!/usr/bin/python
# coding=utf-8
import os
import argparse
import shutil
class Error: pass
class FolderError(Error): pass
def copytranstree (src, dst):
 names = os.listdir( src )
 try:
 os.makedirs( dst )
 except WindowsError:
 pass
 errors = []
 for name in names:
 srcname = os.path.join( src, name )
 dstname = os.path.join( dst, ''.join([translit.get(x, x) for x in name.decode( input_parametres.encoding ).lower()]).encode( input_parametres.encoding ) )
 try:
 if os.path.isdir( srcname ):
 copytranstree( srcname, dstname )
 else:
 shutil.copy2( srcname, dstname )
 except (IOError, os.error), why:
 errors.append( ( srcname, dstname, str( why ) ))
 except Error, err:
 errors.extend( err.args[0] )
 try:
 shutil.copystat( src, dst )
 except WindowsError:
 pass
 except OSError, why:
 errors.extend( (src, dst, str(why) ) )
 if errors:
 raise Error( errors )
parser = argparse.ArgumentParser(description='Copy directory tree with transliterated pathnames')
parser.add_argument('-e','--encoding', help='File system encoding', default='utf-8')
parser.add_argument('-s','--src', help='Source folder name', default='./' )
parser.add_argument('-d','--dst', help='Destination folder name', default='./')
input_parametres = parser.parse_args()
translit = dict(zip(u"абвгдеёзийклмнопрстуфхьъ", "abvgdeeziyklmnoprstufh'~"))
translit.update({u'ц': 'tz', u'ч': 'ch', u'ш': 'sh', u'ы': 'yi',
 u'э': 'ye', u'ю': 'ju', u'я': 'ja', u' ': '_'})
src = os.path.abspath( input_parametres.src )
dst = os.path.abspath( input_parametres.dst )
if not os.path.exists( dst ):
 dstname = ''.join([translit.get(x, x) for x in dst.decode( input_parametres.encoding ).lower()]).encode( input_parametres.encoding ).lower()
 os.makedirs( dstname )
 dst = os.path.abspath( dstname )
if not os.path.exists( src ) or os.path.isfile( dst ):
 raise FolderError()
copytranstree( src, dst )

The script transliterates and copies a tree of files from a source folder to destination, considering encoding passed to the script (UTF for Ubuntu, CP121 for Windows).

Any ideas for common improvement of structure for Linux OS?

200_success
145k22 gold badges190 silver badges478 bronze badges
asked Apr 21, 2011 at 1:54
\$\endgroup\$

1 Answer 1

8
\$\begingroup\$
  1. All exceptions in python should inherit from an Exception class.
  2. WindowsError only works on Windows, its better to use the more general OSError
  3. You twice have a very long line to transliterate a string. Put it in a function and call it
  4. You should put any code that is part of the script proper in a main function.
  5. You shouldn't throw exceptions that you know won't be caught.
  6. The way you collect errors by throwing them up the stack is ugly.
  7. If you split the walking logic from the file operation logic the code will be clearer.

My updates (completely untested and probably wrong):

#!/usr/bin/python
# coding=utf-8
import os
import argparse
import shutil
class CommandError(Exception):
 """
 Thrown when the user has made a mistake in the command line
 """
def transliterated_walk(encoding, src, dst):
 """
 A generator which will walk over src producing them
 along with the transliterated versions in dst
 """
 files = []
 for filename in os.listdir(src):
 src_path = os.path.join(src, filename)
 dest_path = os.path.join(dest, transliterated(encoding, filename))
 if os.path.isdir(path):
 for entry in transliterated_walk(encoding, src_path, dest_path):
 yield entry
 else:
 files.append( (src_path, dest_path) )
 yield src, dest, files
def copytranstree (encoding, src, dst):
 errors = []
 for src_path, dest_path, filenames in transliterated_walk(encoding, src, dest):
 try:
 os.makedirs( dest_path )
 except WindowsError:
 pass
 for src_filename, dest_filename in filenames:
 try:
 shutil.copy2( src_filename, dst_filename )
 except (IOError, os.error) as why:
 errors.append( (src_filename, dest_filename, str(why) )
 try:
 shutil.copystat( src, dst )
 except OSError as why:
 errors.append( (src_path, dst_path, str(why) ) )
TRANSLIT = dict(zip(u"абвгдеёзийклмнопрстуфхьъ", "abvgdeeziyklmnoprstufh'~"))
TRANSLIT.update({u'ц': 'tz', u'ч': 'ch', u'ш': 'sh', u'ы': 'yi',
 u'э': 'ye', u'ю': 'ju', u'я': 'ja', u' ': '_'})
def transliterate(encoding, string):
 decoded = string.decode(encoding).lower()
 transliterated = ''.join(translit.get(x, x) for x in decoded)
 return transliterated.encode(encoding).lower()
def main():
 try:
 parser = argparse.ArgumentParser(description='Copy directory tree with transliterated pathnames')
 parser.add_argument('-e','--encoding', help='File system encoding', default='utf-8')
 parser.add_argument('-s','--src', help='Source folder name', default='./' )
 parser.add_argument('-d','--dst', help='Destination folder name', default='./')
 input_parametres = parser.parse_args()
 src = os.path.abspath( input_parametres.src )
 dst = os.path.abspath( input_parametres.dst )
 if not os.path.exists( dst ):
 dstname = transliterate(dst)
 os.makedirs( dstname )
 dst = os.path.abspath( dstname )
 if not os.path.exists( src ):
 raise CommandError('%s does not exist' % src)
 if os.path.isfile( dst ):
 raise CommandError('%s is a file' % dest)
 copytranstree( encoding, src, dst )
 except CommandError as error:
 print error
if __name__ == '__main__':
 main()
answered Apr 21, 2011 at 4:27
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.