Browse code

* s3cmd, S3/S3.py, S3/Utils.py, S3/S3Uri.py, S3/Exceptions.py: Yet anoter Unicode round. Unicodised all command line arguments before processing.

git-svn-id: https://s3tools.svn.sourceforge.net/svnroot/s3tools/s3cmd/trunk@238 830e0280-6d2a-0410-9c65-932aecc39d9d

Michal Ludvig authored on 2008/09/15 20:04:02
Showing 5 changed files
... ...
@@ -1,5 +1,11 @@
1 1
 2008-09-15  Michal Ludvig  <michal@logix.cz>
2 2
 
3
+	* s3cmd, S3/S3.py, S3/Utils.py, S3/S3Uri.py, S3/Exceptions.py:
4
+	  Yet anoter Unicode round. Unicodised all command line arguments 
5
+	  before processing.
6
+
7
+2008-09-15  Michal Ludvig  <michal@logix.cz>
8
+
3 9
 	* S3/S3.py: "s3cmd mb" can create upper-case buckets again
4 10
 	  in US. Non-US (e.g. EU) bucket names must conform to strict
5 11
 	  DNS-rules.
... ...
@@ -10,7 +10,15 @@ try:
10 10
 except ImportError:
11 11
 	import elementtree.ElementTree as ET
12 12
 
13
-class S3Error (Exception):
13
+class S3Exception(Exception):
14
+	def __str__(self):
15
+		## Is this legal?
16
+		return unicode(self)
17
+
18
+	def __unicode__(self):
19
+		return self.message
20
+
21
+class S3Error (S3Exception):
14 22
 	def __init__(self, response):
15 23
 		self.status = response["status"]
16 24
 		self.reason = response["reason"]
... ...
@@ -26,7 +34,7 @@ class S3Error (Exception):
26 26
 					debug("ErrorXML: " + child.tag + ": " + repr(child.text))
27 27
 					self.info[child.tag] = child.text
28 28
 
29
-	def __str__(self):
29
+	def __unicode__(self):
30 30
 		retval = "%d (%s)" % (self.status, self.reason)
31 31
 		try:
32 32
 			retval += (": %s" % self.info["Code"])
... ...
@@ -34,13 +42,11 @@ class S3Error (Exception):
34 34
 			pass
35 35
 		return retval
36 36
 
37
-class S3UploadError(Exception):
37
+class S3UploadError(S3Exception):
38 38
 	pass
39 39
 
40
-class S3DownloadError(Exception):
40
+class S3DownloadError(S3Exception):
41 41
 	pass
42 42
 
43
-class ParameterError(Exception):
43
+class ParameterError(S3Exception):
44 44
 	pass
45
-
46
-
... ...
@@ -8,6 +8,7 @@ import sys
8 8
 from BidirMap import BidirMap
9 9
 from logging import debug
10 10
 from S3 import S3
11
+from Utils import unicodise
11 12
 
12 13
 class S3Uri(object):
13 14
 	type = None
... ...
@@ -41,18 +42,6 @@ class S3Uri(object):
41 41
 	def public_url(self):
42 42
 		raise ValueError("This S3 URI does not have Anonymous URL representation")
43 43
 
44
-	def _unicodise(self, string):
45
-		"""
46
-		Convert 'string' to Unicode or raise an exception.
47
-		"""
48
-		debug("Unicodising %r" % string)
49
-		if type(string) == unicode:
50
-			return string
51
-		try:
52
-			return string.decode("utf-8")
53
-		except UnicodeDecodeError:
54
-			raise UnicodeDecodeError("Conversion to unicode failed: %r" % string)
55
-
56 44
 class S3UriS3(S3Uri):
57 45
 	type = "s3"
58 46
 	_re = re.compile("^s3://([^/]+)/?(.*)", re.IGNORECASE)
... ...
@@ -62,7 +51,7 @@ class S3UriS3(S3Uri):
62 62
 			raise ValueError("%s: not a S3 URI" % string)
63 63
 		groups = match.groups()
64 64
 		self._bucket = groups[0]
65
-		self._object = self._unicodise(groups[1])
65
+		self._object = unicodise(groups[1])
66 66
 
67 67
 	def bucket(self):
68 68
 		return self._bucket
... ...
@@ -98,7 +87,7 @@ class S3UriS3FS(S3Uri):
98 98
 			raise ValueError("%s: not a S3fs URI" % string)
99 99
 		groups = match.groups()
100 100
 		self._fsname = groups[0]
101
-		self._path = self._unicodise(groups[1]).split("/")
101
+		self._path = unicodise(groups[1]).split("/")
102 102
 
103 103
 	def fsname(self):
104 104
 		return self._fsname
... ...
@@ -117,7 +106,7 @@ class S3UriFile(S3Uri):
117 117
 		groups = match.groups()
118 118
 		if groups[0] not in (None, "file://"):
119 119
 			raise ValueError("%s: not a file:// URI" % string)
120
-		self._path = self._unicodise(groups[1]).split("/")
120
+		self._path = unicodise(groups[1]).split("/")
121 121
 
122 122
 	def path(self):
123 123
 		return "/".join(self._path)
... ...
@@ -173,3 +173,22 @@ def mkdir_with_parents(dir_name):
173 173
 			warning("%s: %s" % (cur_dir, e))
174 174
 			return False
175 175
 	return True
176
+
177
+def unicodise(string):
178
+	"""
179
+	Convert 'string' to Unicode or raise an exception.
180
+	"""
181
+	debug("Unicodising %r" % string)
182
+	if type(string) == unicode:
183
+		return string
184
+	try:
185
+		return string.decode("utf-8")
186
+	except UnicodeDecodeError:
187
+		raise UnicodeDecodeError("Conversion to unicode failed: %r" % string)
188
+
189
+def try_unicodise(string):
190
+	try:
191
+		return unicodise(string)
192
+	except UnicodeDecodeError:
193
+		return string
194
+
... ...
@@ -21,12 +21,14 @@ from optparse import OptionParser, Option, OptionValueError, IndentedHelpFormatt
21 21
 from logging import debug, info, warning, error
22 22
 from distutils.spawn import find_executable
23 23
 
24
-## Output UTF-8 in all cases, even on output redirects
25
-_unicode_stdout = codecs.getwriter("utf-8")(sys.stdout)
26
-_unicode_stderr = codecs.getwriter("utf-8")(sys.stderr)
24
+## Output native on TTY, UTF-8 otherwise (redirects)
25
+_stdout = sys.stdout.isatty() and sys.stdout or codecs.getwriter("utf-8")(sys.stdout)
26
+_stderr = sys.stderr.isatty() and sys.stderr or codecs.getwriter("utf-8")(sys.stderr)
27
+#_stdout = codecs.getwriter("utf-8")(sys.stdout)
28
+#_stderr = codecs.getwriter("utf-8")(sys.stderr)
27 29
 
28 30
 def output(message):
29
-	_unicode_stdout.write(message + "\n")
31
+	_stdout.write(message + "\n")
30 32
 
31 33
 def check_args_type(args, type, verbose_type):
32 34
 	for arg in args:
... ...
@@ -963,7 +965,7 @@ def main():
963 963
 	## debugging/verbose output for config file parser on request
964 964
 	logging.basicConfig(level=options.verbosity,
965 965
 	                    format='%(levelname)s: %(message)s',
966
-	                    stream = _unicode_stderr)
966
+	                    stream = _stderr)
967 967
 	
968 968
 	if options.show_version:
969 969
 		output("s3cmd version %s" % PkgInfo.version)
... ...
@@ -1052,9 +1054,12 @@ def main():
1052 1052
 		error("Missing command. Please run with --help for more information.")
1053 1053
 		sys.exit(1)
1054 1054
 
1055
+	## Unicodise all remaining arguments:
1056
+	args = [unicodise(arg) for arg in args]
1057
+
1055 1058
 	command = args.pop(0)
1056 1059
 	try:
1057
-		debug("Command: " + commands[command]["cmd"])
1060
+		debug("Command: %s" % commands[command]["cmd"])
1058 1061
 		## We must do this lookup in extra step to 
1059 1062
 		## avoid catching all KeyError exceptions
1060 1063
 		## from inner functions.
... ...
@@ -1070,10 +1075,10 @@ def main():
1070 1070
 	try:
1071 1071
 		cmd_func(args)
1072 1072
 	except S3Error, e:
1073
-		error("S3 error: " + str(e))
1073
+		error("S3 error: %s" % e)
1074 1074
 		sys.exit(1)
1075 1075
 	except ParameterError, e:
1076
-		error("Parameter problem: " + str(e))
1076
+		error("Parameter problem: %s" % e)
1077 1077
 		sys.exit(1)
1078 1078
 
1079 1079
 if __name__ == '__main__':
... ...
@@ -1087,6 +1092,7 @@ if __name__ == '__main__':
1087 1087
 		from S3.S3Uri import *
1088 1088
 		from S3 import Utils
1089 1089
 		from S3.Exceptions import *
1090
+		from S3.Utils import unicodise
1090 1091
 
1091 1092
 		main()
1092 1093
 		sys.exit(0)