| Benjamin Peterson | 90f5ba5 | 2010-03-11 22:53:45 +0000 | [diff] [blame] | 1 | #! /usr/bin/env python3 | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 2 | # -*- coding: iso-8859-1 -*- | 
| Barry Warsaw | 63ce5af | 2001-07-27 16:47:18 +0000 | [diff] [blame] | 3 | # Originally written by Barry Warsaw <barry@zope.com> | 
| Barry Warsaw | c8f0892 | 2000-02-26 20:56:47 +0000 | [diff] [blame] | 4 | # | 
| Barry Warsaw | e04ee70 | 2003-04-16 18:08:23 +0000 | [diff] [blame] | 5 | # Minimally patched to make it even more xgettext compatible | 
| Barry Warsaw | c8f0892 | 2000-02-26 20:56:47 +0000 | [diff] [blame] | 6 | # by Peter Funk <pf@artcom-gmbh.de> | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 7 | # | 
 | 8 | # 2002-11-22 Jürgen Hermann <jh@web.de> | 
 | 9 | # Added checks that _() only contains string literals, and | 
 | 10 | # command line args are resolved to module lists, i.e. you | 
 | 11 | # can now pass a filename, a module or package name, or a | 
 | 12 | # directory (including globbing chars, important for Win32). | 
 | 13 | # Made docstring fit in 80 chars wide displays using pydoc. | 
 | 14 | # | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 15 |  | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 16 | # for selftesting | 
 | 17 | try: | 
 | 18 |     import fintl | 
 | 19 |     _ = fintl.gettext | 
 | 20 | except ImportError: | 
 | 21 |     _ = lambda s: s | 
 | 22 |  | 
 | 23 | __doc__ = _("""pygettext -- Python equivalent of xgettext(1) | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 24 |  | 
 | 25 | Many systems (Solaris, Linux, Gnu) provide extensive tools that ease the | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 26 | internationalization of C programs. Most of these tools are independent of | 
 | 27 | the programming language and can be used from within Python programs. | 
| Barry Warsaw | e04ee70 | 2003-04-16 18:08:23 +0000 | [diff] [blame] | 28 | Martin von Loewis' work[1] helps considerably in this regard. | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 29 |  | 
| Barry Warsaw | 5dbf526 | 1999-11-03 18:47:52 +0000 | [diff] [blame] | 30 | There's one problem though; xgettext is the program that scans source code | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 31 | looking for message strings, but it groks only C (or C++). Python | 
 | 32 | introduces a few wrinkles, such as dual quoting characters, triple quoted | 
| Barry Warsaw | e04ee70 | 2003-04-16 18:08:23 +0000 | [diff] [blame] | 33 | strings, and raw strings. xgettext understands none of this. | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 34 |  | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 35 | Enter pygettext, which uses Python's standard tokenize module to scan | 
 | 36 | Python source code, generating .pot files identical to what GNU xgettext[2] | 
 | 37 | generates for C and C++ code. From there, the standard GNU tools can be | 
| Barry Warsaw | e04ee70 | 2003-04-16 18:08:23 +0000 | [diff] [blame] | 38 | used. | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 39 |  | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 40 | A word about marking Python strings as candidates for translation. GNU | 
 | 41 | xgettext recognizes the following keywords: gettext, dgettext, dcgettext, | 
 | 42 | and gettext_noop. But those can be a lot of text to include all over your | 
 | 43 | code. C and C++ have a trick: they use the C preprocessor. Most | 
 | 44 | internationalized C source includes a #define for gettext() to _() so that | 
 | 45 | what has to be written in the source is much less. Thus these are both | 
| Barry Warsaw | e04ee70 | 2003-04-16 18:08:23 +0000 | [diff] [blame] | 46 | translatable strings: | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 47 |  | 
 | 48 |     gettext("Translatable String") | 
 | 49 |     _("Translatable String") | 
 | 50 |  | 
 | 51 | Python of course has no preprocessor so this doesn't work so well.  Thus, | 
 | 52 | pygettext searches only for _() by default, but see the -k/--keyword flag | 
 | 53 | below for how to augment this. | 
 | 54 |  | 
 | 55 |  [1] http://www.python.org/workshops/1997-10/proceedings/loewis.html | 
 | 56 |  [2] http://www.gnu.org/software/gettext/gettext.html | 
 | 57 |  | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 58 | NOTE: pygettext attempts to be option and feature compatible with GNU | 
 | 59 | xgettext where ever possible. However some options are still missing or are | 
 | 60 | not fully implemented. Also, xgettext's use of command line switches with | 
 | 61 | option arguments is broken, and in these cases, pygettext just defines | 
| Barry Warsaw | e04ee70 | 2003-04-16 18:08:23 +0000 | [diff] [blame] | 62 | additional switches. | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 63 |  | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 64 | Usage: pygettext [options] inputfile ... | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 65 |  | 
 | 66 | Options: | 
 | 67 |  | 
 | 68 |     -a | 
 | 69 |     --extract-all | 
| Barry Warsaw | 63ce5af | 2001-07-27 16:47:18 +0000 | [diff] [blame] | 70 |         Extract all strings. | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 71 |  | 
| Barry Warsaw | c8f0892 | 2000-02-26 20:56:47 +0000 | [diff] [blame] | 72 |     -d name | 
 | 73 |     --default-domain=name | 
| Barry Warsaw | 63ce5af | 2001-07-27 16:47:18 +0000 | [diff] [blame] | 74 |         Rename the default output file from messages.pot to name.pot. | 
| Barry Warsaw | c8f0892 | 2000-02-26 20:56:47 +0000 | [diff] [blame] | 75 |  | 
 | 76 |     -E | 
 | 77 |     --escape | 
| Barry Warsaw | 08a8a35 | 2000-10-27 04:56:28 +0000 | [diff] [blame] | 78 |         Replace non-ASCII characters with octal escape sequences. | 
 | 79 |  | 
 | 80 |     -D | 
 | 81 |     --docstrings | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 82 |         Extract module, class, method, and function docstrings.  These do | 
 | 83 |         not need to be wrapped in _() markers, and in fact cannot be for | 
 | 84 |         Python to consider them docstrings. (See also the -X option). | 
| Barry Warsaw | c8f0892 | 2000-02-26 20:56:47 +0000 | [diff] [blame] | 85 |  | 
 | 86 |     -h | 
 | 87 |     --help | 
| Barry Warsaw | 63ce5af | 2001-07-27 16:47:18 +0000 | [diff] [blame] | 88 |         Print this help message and exit. | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 89 |  | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 90 |     -k word | 
 | 91 |     --keyword=word | 
 | 92 |         Keywords to look for in addition to the default set, which are: | 
 | 93 |         %(DEFAULTKEYWORDS)s | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 94 |  | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 95 |         You can have multiple -k flags on the command line. | 
 | 96 |  | 
 | 97 |     -K | 
 | 98 |     --no-default-keywords | 
 | 99 |         Disable the default set of keywords (see above).  Any keywords | 
 | 100 |         explicitly added with the -k/--keyword option are still recognized. | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 101 |  | 
 | 102 |     --no-location | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 103 |         Do not write filename/lineno location comments. | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 104 |  | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 105 |     -n | 
 | 106 |     --add-location | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 107 |         Write filename/lineno location comments indicating where each | 
 | 108 |         extracted string is found in the source.  These lines appear before | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 109 |         each msgid.  The style of comments is controlled by the -S/--style | 
 | 110 |         option.  This is the default. | 
 | 111 |  | 
| Barry Warsaw | 08a8a35 | 2000-10-27 04:56:28 +0000 | [diff] [blame] | 112 |     -o filename | 
 | 113 |     --output=filename | 
 | 114 |         Rename the default output file from messages.pot to filename.  If | 
 | 115 |         filename is `-' then the output is sent to standard out. | 
 | 116 |  | 
 | 117 |     -p dir | 
 | 118 |     --output-dir=dir | 
 | 119 |         Output files will be placed in directory dir. | 
 | 120 |  | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 121 |     -S stylename | 
 | 122 |     --style stylename | 
 | 123 |         Specify which style to use for location comments.  Two styles are | 
 | 124 |         supported: | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 125 |  | 
 | 126 |         Solaris  # File: filename, line: line-number | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 127 |         GNU      #: filename:line | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 128 |  | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 129 |         The style name is case insensitive.  GNU style is the default. | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 130 |  | 
| Barry Warsaw | 5dbf526 | 1999-11-03 18:47:52 +0000 | [diff] [blame] | 131 |     -v | 
 | 132 |     --verbose | 
 | 133 |         Print the names of the files being processed. | 
 | 134 |  | 
| Barry Warsaw | c8f0892 | 2000-02-26 20:56:47 +0000 | [diff] [blame] | 135 |     -V | 
 | 136 |     --version | 
 | 137 |         Print the version of pygettext and exit. | 
 | 138 |  | 
 | 139 |     -w columns | 
 | 140 |     --width=columns | 
 | 141 |         Set width of output to columns. | 
 | 142 |  | 
 | 143 |     -x filename | 
 | 144 |     --exclude-file=filename | 
 | 145 |         Specify a file that contains a list of strings that are not be | 
 | 146 |         extracted from the input files.  Each string to be excluded must | 
 | 147 |         appear on a line by itself in the file. | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 148 |  | 
| Barry Warsaw | 63ce5af | 2001-07-27 16:47:18 +0000 | [diff] [blame] | 149 |     -X filename | 
 | 150 |     --no-docstrings=filename | 
 | 151 |         Specify a file that contains a list of files (one per line) that | 
 | 152 |         should not have their docstrings extracted.  This is only useful in | 
 | 153 |         conjunction with the -D option above. | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 154 |  | 
| Barry Warsaw | 63ce5af | 2001-07-27 16:47:18 +0000 | [diff] [blame] | 155 | If `inputfile' is -, standard input is read. | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 156 | """) | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 157 |  | 
 | 158 | import os | 
| Barry Warsaw | e04ee70 | 2003-04-16 18:08:23 +0000 | [diff] [blame] | 159 | import imp | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 160 | import sys | 
| Barry Warsaw | e04ee70 | 2003-04-16 18:08:23 +0000 | [diff] [blame] | 161 | import glob | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 162 | import time | 
 | 163 | import getopt | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 164 | import token | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 165 | import tokenize | 
 | 166 |  | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 167 | __version__ = '1.5' | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 168 |  | 
 | 169 | default_keywords = ['_'] | 
 | 170 | DEFAULTKEYWORDS = ', '.join(default_keywords) | 
 | 171 |  | 
 | 172 | EMPTYSTRING = '' | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 173 |  | 
 | 174 |  | 
 | 175 |  | 
| Barry Warsaw | 63ce5af | 2001-07-27 16:47:18 +0000 | [diff] [blame] | 176 | # The normal pot-file header. msgmerge and Emacs's po-mode work better if it's | 
 | 177 | # there. | 
| Barry Warsaw | 5dbf526 | 1999-11-03 18:47:52 +0000 | [diff] [blame] | 178 | pot_header = _('''\ | 
 | 179 | # SOME DESCRIPTIVE TITLE. | 
 | 180 | # Copyright (C) YEAR ORGANIZATION | 
 | 181 | # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. | 
 | 182 | # | 
 | 183 | msgid "" | 
 | 184 | msgstr "" | 
 | 185 | "Project-Id-Version: PACKAGE VERSION\\n" | 
| Martin v. Löwis | 0f6b383 | 2001-03-01 22:56:17 +0000 | [diff] [blame] | 186 | "POT-Creation-Date: %(time)s\\n" | 
 | 187 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n" | 
| Barry Warsaw | 5dbf526 | 1999-11-03 18:47:52 +0000 | [diff] [blame] | 188 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n" | 
 | 189 | "Language-Team: LANGUAGE <LL@li.org>\\n" | 
 | 190 | "MIME-Version: 1.0\\n" | 
 | 191 | "Content-Type: text/plain; charset=CHARSET\\n" | 
 | 192 | "Content-Transfer-Encoding: ENCODING\\n" | 
 | 193 | "Generated-By: pygettext.py %(version)s\\n" | 
 | 194 |  | 
 | 195 | ''') | 
 | 196 |  | 
 | 197 |  | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 198 | def usage(code, msg=''): | 
| Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 199 |     print(__doc__ % globals(), file=sys.stderr) | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 200 |     if msg: | 
| Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 201 |         print(msg, file=sys.stderr) | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 202 |     sys.exit(code) | 
 | 203 |  | 
| Barry Warsaw | c8f0892 | 2000-02-26 20:56:47 +0000 | [diff] [blame] | 204 |  | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 205 |  | 
| Barry Warsaw | 5dbf526 | 1999-11-03 18:47:52 +0000 | [diff] [blame] | 206 | escapes = [] | 
| Barry Warsaw | 5dbf526 | 1999-11-03 18:47:52 +0000 | [diff] [blame] | 207 |  | 
| Barry Warsaw | c8f0892 | 2000-02-26 20:56:47 +0000 | [diff] [blame] | 208 | def make_escapes(pass_iso8859): | 
 | 209 |     global escapes | 
| Barry Warsaw | 7733e12 | 2000-02-27 14:30:48 +0000 | [diff] [blame] | 210 |     if pass_iso8859: | 
 | 211 |         # Allow iso-8859 characters to pass through so that e.g. 'msgid | 
 | 212 |         # "Höhe"' would result not result in 'msgid "H\366he"'.  Otherwise we | 
 | 213 |         # escape any character outside the 32..126 range. | 
 | 214 |         mod = 128 | 
 | 215 |     else: | 
 | 216 |         mod = 256 | 
| Barry Warsaw | c8f0892 | 2000-02-26 20:56:47 +0000 | [diff] [blame] | 217 |     for i in range(256): | 
| Barry Warsaw | 7733e12 | 2000-02-27 14:30:48 +0000 | [diff] [blame] | 218 |         if 32 <= (i % mod) <= 126: | 
| Barry Warsaw | c8f0892 | 2000-02-26 20:56:47 +0000 | [diff] [blame] | 219 |             escapes.append(chr(i)) | 
 | 220 |         else: | 
 | 221 |             escapes.append("\\%03o" % i) | 
 | 222 |     escapes[ord('\\')] = '\\\\' | 
 | 223 |     escapes[ord('\t')] = '\\t' | 
 | 224 |     escapes[ord('\r')] = '\\r' | 
 | 225 |     escapes[ord('\n')] = '\\n' | 
 | 226 |     escapes[ord('\"')] = '\\"' | 
 | 227 |  | 
| Barry Warsaw | 5dbf526 | 1999-11-03 18:47:52 +0000 | [diff] [blame] | 228 |  | 
 | 229 | def escape(s): | 
| Barry Warsaw | c8f0892 | 2000-02-26 20:56:47 +0000 | [diff] [blame] | 230 |     global escapes | 
| Barry Warsaw | 5dbf526 | 1999-11-03 18:47:52 +0000 | [diff] [blame] | 231 |     s = list(s) | 
 | 232 |     for i in range(len(s)): | 
 | 233 |         s[i] = escapes[ord(s[i])] | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 234 |     return EMPTYSTRING.join(s) | 
| Barry Warsaw | 5dbf526 | 1999-11-03 18:47:52 +0000 | [diff] [blame] | 235 |  | 
 | 236 |  | 
 | 237 | def safe_eval(s): | 
 | 238 |     # unwrap quotes, safely | 
 | 239 |     return eval(s, {'__builtins__':{}}, {}) | 
 | 240 |  | 
 | 241 |  | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 242 | def normalize(s): | 
 | 243 |     # This converts the various Python string types into a format that is | 
 | 244 |     # appropriate for .po files, namely much closer to C style. | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 245 |     lines = s.split('\n') | 
| Barry Warsaw | 5dbf526 | 1999-11-03 18:47:52 +0000 | [diff] [blame] | 246 |     if len(lines) == 1: | 
 | 247 |         s = '"' + escape(s) + '"' | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 248 |     else: | 
| Barry Warsaw | 5dbf526 | 1999-11-03 18:47:52 +0000 | [diff] [blame] | 249 |         if not lines[-1]: | 
 | 250 |             del lines[-1] | 
 | 251 |             lines[-1] = lines[-1] + '\n' | 
 | 252 |         for i in range(len(lines)): | 
 | 253 |             lines[i] = escape(lines[i]) | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 254 |         lineterm = '\\n"\n"' | 
 | 255 |         s = '""\n"' + lineterm.join(lines) + '"' | 
| Barry Warsaw | 5dbf526 | 1999-11-03 18:47:52 +0000 | [diff] [blame] | 256 |     return s | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 257 |  | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 258 |  | 
 | 259 | def containsAny(str, set): | 
| Barry Warsaw | e04ee70 | 2003-04-16 18:08:23 +0000 | [diff] [blame] | 260 |     """Check whether 'str' contains ANY of the chars in 'set'""" | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 261 |     return 1 in [c in str for c in set] | 
 | 262 |  | 
 | 263 |  | 
 | 264 | def _visit_pyfiles(list, dirname, names): | 
| Barry Warsaw | e04ee70 | 2003-04-16 18:08:23 +0000 | [diff] [blame] | 265 |     """Helper for getFilesForName().""" | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 266 |     # get extension for python source files | 
| Georg Brandl | bf82e37 | 2008-05-16 17:02:34 +0000 | [diff] [blame] | 267 |     if '_py_ext' not in globals(): | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 268 |         global _py_ext | 
| Barry Warsaw | e04ee70 | 2003-04-16 18:08:23 +0000 | [diff] [blame] | 269 |         _py_ext = [triple[0] for triple in imp.get_suffixes() | 
 | 270 |                    if triple[2] == imp.PY_SOURCE][0] | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 271 |  | 
 | 272 |     # don't recurse into CVS directories | 
 | 273 |     if 'CVS' in names: | 
 | 274 |         names.remove('CVS') | 
 | 275 |  | 
 | 276 |     # add all *.py files to list | 
 | 277 |     list.extend( | 
| Barry Warsaw | e04ee70 | 2003-04-16 18:08:23 +0000 | [diff] [blame] | 278 |         [os.path.join(dirname, file) for file in names | 
 | 279 |          if os.path.splitext(file)[1] == _py_ext] | 
 | 280 |         ) | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 281 |  | 
 | 282 |  | 
 | 283 | def _get_modpkg_path(dotted_name, pathlist=None): | 
| Barry Warsaw | e04ee70 | 2003-04-16 18:08:23 +0000 | [diff] [blame] | 284 |     """Get the filesystem path for a module or a package. | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 285 |  | 
| Barry Warsaw | e04ee70 | 2003-04-16 18:08:23 +0000 | [diff] [blame] | 286 |     Return the file system path to a file for a module, and to a directory for | 
 | 287 |     a package. Return None if the name is not found, or is a builtin or | 
 | 288 |     extension module. | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 289 |     """ | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 290 |     # split off top-most name | 
 | 291 |     parts = dotted_name.split('.', 1) | 
 | 292 |  | 
 | 293 |     if len(parts) > 1: | 
 | 294 |         # we have a dotted path, import top-level package | 
 | 295 |         try: | 
 | 296 |             file, pathname, description = imp.find_module(parts[0], pathlist) | 
 | 297 |             if file: file.close() | 
 | 298 |         except ImportError: | 
 | 299 |             return None | 
 | 300 |  | 
 | 301 |         # check if it's indeed a package | 
 | 302 |         if description[2] == imp.PKG_DIRECTORY: | 
 | 303 |             # recursively handle the remaining name parts | 
 | 304 |             pathname = _get_modpkg_path(parts[1], [pathname]) | 
 | 305 |         else: | 
 | 306 |             pathname = None | 
 | 307 |     else: | 
 | 308 |         # plain name | 
 | 309 |         try: | 
| Barry Warsaw | e04ee70 | 2003-04-16 18:08:23 +0000 | [diff] [blame] | 310 |             file, pathname, description = imp.find_module( | 
 | 311 |                 dotted_name, pathlist) | 
 | 312 |             if file: | 
 | 313 |                 file.close() | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 314 |             if description[2] not in [imp.PY_SOURCE, imp.PKG_DIRECTORY]: | 
 | 315 |                 pathname = None | 
 | 316 |         except ImportError: | 
 | 317 |             pathname = None | 
 | 318 |  | 
 | 319 |     return pathname | 
 | 320 |  | 
 | 321 |  | 
 | 322 | def getFilesForName(name): | 
| Barry Warsaw | e04ee70 | 2003-04-16 18:08:23 +0000 | [diff] [blame] | 323 |     """Get a list of module files for a filename, a module or package name, | 
 | 324 |     or a directory. | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 325 |     """ | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 326 |     if not os.path.exists(name): | 
 | 327 |         # check for glob chars | 
 | 328 |         if containsAny(name, "*?[]"): | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 329 |             files = glob.glob(name) | 
 | 330 |             list = [] | 
 | 331 |             for file in files: | 
 | 332 |                 list.extend(getFilesForName(file)) | 
 | 333 |             return list | 
 | 334 |  | 
 | 335 |         # try to find module or package | 
 | 336 |         name = _get_modpkg_path(name) | 
 | 337 |         if not name: | 
 | 338 |             return [] | 
 | 339 |  | 
 | 340 |     if os.path.isdir(name): | 
 | 341 |         # find all python files in directory | 
 | 342 |         list = [] | 
| Alexandre Vassalotti | 4e6531e | 2008-05-09 20:00:17 +0000 | [diff] [blame] | 343 |         os.walk(name, _visit_pyfiles, list) | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 344 |         return list | 
 | 345 |     elif os.path.exists(name): | 
 | 346 |         # a single file | 
 | 347 |         return [name] | 
 | 348 |  | 
 | 349 |     return [] | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 350 |  | 
 | 351 |  | 
 | 352 | class TokenEater: | 
 | 353 |     def __init__(self, options): | 
 | 354 |         self.__options = options | 
 | 355 |         self.__messages = {} | 
 | 356 |         self.__state = self.__waiting | 
 | 357 |         self.__data = [] | 
 | 358 |         self.__lineno = -1 | 
| Barry Warsaw | 08a8a35 | 2000-10-27 04:56:28 +0000 | [diff] [blame] | 359 |         self.__freshmodule = 1 | 
| Barry Warsaw | 63ce5af | 2001-07-27 16:47:18 +0000 | [diff] [blame] | 360 |         self.__curfile = None | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 361 |  | 
 | 362 |     def __call__(self, ttype, tstring, stup, etup, line): | 
 | 363 |         # dispatch | 
| Barry Warsaw | 08a8a35 | 2000-10-27 04:56:28 +0000 | [diff] [blame] | 364 | ##        import token | 
 | 365 | ##        print >> sys.stderr, 'ttype:', token.tok_name[ttype], \ | 
 | 366 | ##              'tstring:', tstring | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 367 |         self.__state(ttype, tstring, stup[0]) | 
 | 368 |  | 
 | 369 |     def __waiting(self, ttype, tstring, lineno): | 
| Barry Warsaw | 63ce5af | 2001-07-27 16:47:18 +0000 | [diff] [blame] | 370 |         opts = self.__options | 
| Barry Warsaw | 08a8a35 | 2000-10-27 04:56:28 +0000 | [diff] [blame] | 371 |         # Do docstring extractions, if enabled | 
| Barry Warsaw | 63ce5af | 2001-07-27 16:47:18 +0000 | [diff] [blame] | 372 |         if opts.docstrings and not opts.nodocstrings.get(self.__curfile): | 
| Barry Warsaw | 08a8a35 | 2000-10-27 04:56:28 +0000 | [diff] [blame] | 373 |             # module docstring? | 
 | 374 |             if self.__freshmodule: | 
 | 375 |                 if ttype == tokenize.STRING: | 
| Barry Warsaw | 16b62c1 | 2001-05-21 19:51:26 +0000 | [diff] [blame] | 376 |                     self.__addentry(safe_eval(tstring), lineno, isdocstring=1) | 
| Barry Warsaw | 08a8a35 | 2000-10-27 04:56:28 +0000 | [diff] [blame] | 377 |                     self.__freshmodule = 0 | 
 | 378 |                 elif ttype not in (tokenize.COMMENT, tokenize.NL): | 
 | 379 |                     self.__freshmodule = 0 | 
 | 380 |                 return | 
 | 381 |             # class docstring? | 
 | 382 |             if ttype == tokenize.NAME and tstring in ('class', 'def'): | 
 | 383 |                 self.__state = self.__suiteseen | 
 | 384 |                 return | 
| Barry Warsaw | 63ce5af | 2001-07-27 16:47:18 +0000 | [diff] [blame] | 385 |         if ttype == tokenize.NAME and tstring in opts.keywords: | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 386 |             self.__state = self.__keywordseen | 
 | 387 |  | 
| Barry Warsaw | 08a8a35 | 2000-10-27 04:56:28 +0000 | [diff] [blame] | 388 |     def __suiteseen(self, ttype, tstring, lineno): | 
 | 389 |         # ignore anything until we see the colon | 
 | 390 |         if ttype == tokenize.OP and tstring == ':': | 
 | 391 |             self.__state = self.__suitedocstring | 
 | 392 |  | 
 | 393 |     def __suitedocstring(self, ttype, tstring, lineno): | 
 | 394 |         # ignore any intervening noise | 
 | 395 |         if ttype == tokenize.STRING: | 
| Barry Warsaw | 16b62c1 | 2001-05-21 19:51:26 +0000 | [diff] [blame] | 396 |             self.__addentry(safe_eval(tstring), lineno, isdocstring=1) | 
| Barry Warsaw | 08a8a35 | 2000-10-27 04:56:28 +0000 | [diff] [blame] | 397 |             self.__state = self.__waiting | 
 | 398 |         elif ttype not in (tokenize.NEWLINE, tokenize.INDENT, | 
 | 399 |                            tokenize.COMMENT): | 
 | 400 |             # there was no class docstring | 
 | 401 |             self.__state = self.__waiting | 
 | 402 |  | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 403 |     def __keywordseen(self, ttype, tstring, lineno): | 
 | 404 |         if ttype == tokenize.OP and tstring == '(': | 
 | 405 |             self.__data = [] | 
 | 406 |             self.__lineno = lineno | 
 | 407 |             self.__state = self.__openseen | 
 | 408 |         else: | 
 | 409 |             self.__state = self.__waiting | 
 | 410 |  | 
 | 411 |     def __openseen(self, ttype, tstring, lineno): | 
 | 412 |         if ttype == tokenize.OP and tstring == ')': | 
 | 413 |             # We've seen the last of the translatable strings.  Record the | 
| Barry Warsaw | e04ee70 | 2003-04-16 18:08:23 +0000 | [diff] [blame] | 414 |             # line number of the first line of the strings and update the list | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 415 |             # of messages seen.  Reset state for the next batch.  If there | 
 | 416 |             # were no strings inside _(), then just ignore this entry. | 
 | 417 |             if self.__data: | 
| Barry Warsaw | 08a8a35 | 2000-10-27 04:56:28 +0000 | [diff] [blame] | 418 |                 self.__addentry(EMPTYSTRING.join(self.__data)) | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 419 |             self.__state = self.__waiting | 
 | 420 |         elif ttype == tokenize.STRING: | 
| Barry Warsaw | 5dbf526 | 1999-11-03 18:47:52 +0000 | [diff] [blame] | 421 |             self.__data.append(safe_eval(tstring)) | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 422 |         elif ttype not in [tokenize.COMMENT, token.INDENT, token.DEDENT, | 
 | 423 |                            token.NEWLINE, tokenize.NL]: | 
 | 424 |             # warn if we see anything else than STRING or whitespace | 
| Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 425 |             print(_( | 
| Barry Warsaw | e04ee70 | 2003-04-16 18:08:23 +0000 | [diff] [blame] | 426 |                 '*** %(file)s:%(lineno)s: Seen unexpected token "%(token)s"' | 
 | 427 |                 ) % { | 
 | 428 |                 'token': tstring, | 
 | 429 |                 'file': self.__curfile, | 
 | 430 |                 'lineno': self.__lineno | 
| Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 431 |                 }, file=sys.stderr) | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 432 |             self.__state = self.__waiting | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 433 |  | 
| Barry Warsaw | 16b62c1 | 2001-05-21 19:51:26 +0000 | [diff] [blame] | 434 |     def __addentry(self, msg, lineno=None, isdocstring=0): | 
| Barry Warsaw | 08a8a35 | 2000-10-27 04:56:28 +0000 | [diff] [blame] | 435 |         if lineno is None: | 
 | 436 |             lineno = self.__lineno | 
 | 437 |         if not msg in self.__options.toexclude: | 
 | 438 |             entry = (self.__curfile, lineno) | 
| Barry Warsaw | 16b62c1 | 2001-05-21 19:51:26 +0000 | [diff] [blame] | 439 |             self.__messages.setdefault(msg, {})[entry] = isdocstring | 
| Barry Warsaw | 08a8a35 | 2000-10-27 04:56:28 +0000 | [diff] [blame] | 440 |  | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 441 |     def set_filename(self, filename): | 
 | 442 |         self.__curfile = filename | 
| Barry Warsaw | 63ce5af | 2001-07-27 16:47:18 +0000 | [diff] [blame] | 443 |         self.__freshmodule = 1 | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 444 |  | 
 | 445 |     def write(self, fp): | 
 | 446 |         options = self.__options | 
| Matthias Klose | 2443d4a | 2004-08-16 12:10:12 +0000 | [diff] [blame] | 447 |         timestamp = time.strftime('%Y-%m-%d %H:%M+%Z') | 
| Barry Warsaw | 08a8a35 | 2000-10-27 04:56:28 +0000 | [diff] [blame] | 448 |         # The time stamp in the header doesn't have the same format as that | 
 | 449 |         # generated by xgettext... | 
| Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 450 |         print(pot_header % {'time': timestamp, 'version': __version__}, file=fp) | 
| Barry Warsaw | 128c77d | 2001-05-23 16:59:45 +0000 | [diff] [blame] | 451 |         # Sort the entries.  First sort each particular entry's keys, then | 
 | 452 |         # sort all the entries by their first item. | 
 | 453 |         reverse = {} | 
| Fred Drake | 33e2c3e | 2000-10-26 03:49:15 +0000 | [diff] [blame] | 454 |         for k, v in self.__messages.items(): | 
| Guido van Rossum | f7bd964 | 2008-01-15 17:41:38 +0000 | [diff] [blame] | 455 |             keys = sorted(v.keys()) | 
| Barry Warsaw | 50cf706 | 2001-05-24 23:06:13 +0000 | [diff] [blame] | 456 |             reverse.setdefault(tuple(keys), []).append((k, v)) | 
| Guido van Rossum | f7bd964 | 2008-01-15 17:41:38 +0000 | [diff] [blame] | 457 |         rkeys = sorted(reverse.keys()) | 
| Barry Warsaw | 128c77d | 2001-05-23 16:59:45 +0000 | [diff] [blame] | 458 |         for rkey in rkeys: | 
| Barry Warsaw | 50cf706 | 2001-05-24 23:06:13 +0000 | [diff] [blame] | 459 |             rentries = reverse[rkey] | 
 | 460 |             rentries.sort() | 
 | 461 |             for k, v in rentries: | 
 | 462 |                 # If the entry was gleaned out of a docstring, then add a | 
 | 463 |                 # comment stating so.  This is to aid translators who may wish | 
 | 464 |                 # to skip translating some unimportant docstrings. | 
| Guido van Rossum | 89da5d7 | 2006-08-22 00:21:25 +0000 | [diff] [blame] | 465 |                 isdocstring = any(v.values()) | 
| Barry Warsaw | 50cf706 | 2001-05-24 23:06:13 +0000 | [diff] [blame] | 466 |                 # k is the message string, v is a dictionary-set of (filename, | 
 | 467 |                 # lineno) tuples.  We want to sort the entries in v first by | 
 | 468 |                 # file name and then by line number. | 
| Guido van Rossum | f7bd964 | 2008-01-15 17:41:38 +0000 | [diff] [blame] | 469 |                 v = sorted(v.keys()) | 
| Barry Warsaw | 50cf706 | 2001-05-24 23:06:13 +0000 | [diff] [blame] | 470 |                 if not options.writelocations: | 
 | 471 |                     pass | 
 | 472 |                 # location comments are different b/w Solaris and GNU: | 
 | 473 |                 elif options.locationstyle == options.SOLARIS: | 
 | 474 |                     for filename, lineno in v: | 
 | 475 |                         d = {'filename': filename, 'lineno': lineno} | 
| Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 476 |                         print(_( | 
 | 477 |                             '# File: %(filename)s, line: %(lineno)d') % d, file=fp) | 
| Barry Warsaw | 50cf706 | 2001-05-24 23:06:13 +0000 | [diff] [blame] | 478 |                 elif options.locationstyle == options.GNU: | 
 | 479 |                     # fit as many locations on one line, as long as the | 
 | 480 |                     # resulting line length doesn't exceeds 'options.width' | 
 | 481 |                     locline = '#:' | 
 | 482 |                     for filename, lineno in v: | 
 | 483 |                         d = {'filename': filename, 'lineno': lineno} | 
 | 484 |                         s = _(' %(filename)s:%(lineno)d') % d | 
 | 485 |                         if len(locline) + len(s) <= options.width: | 
 | 486 |                             locline = locline + s | 
 | 487 |                         else: | 
| Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 488 |                             print(locline, file=fp) | 
| Barry Warsaw | 50cf706 | 2001-05-24 23:06:13 +0000 | [diff] [blame] | 489 |                             locline = "#:" + s | 
 | 490 |                     if len(locline) > 2: | 
| Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 491 |                         print(locline, file=fp) | 
| Barry Warsaw | 5c94ce5 | 2001-06-20 19:41:40 +0000 | [diff] [blame] | 492 |                 if isdocstring: | 
| Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 493 |                     print('#, docstring', file=fp) | 
 | 494 |                 print('msgid', normalize(k), file=fp) | 
 | 495 |                 print('msgstr ""\n', file=fp) | 
| Barry Warsaw | 08a8a35 | 2000-10-27 04:56:28 +0000 | [diff] [blame] | 496 |  | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 497 |  | 
 | 498 |  | 
 | 499 | def main(): | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 500 |     global default_keywords | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 501 |     try: | 
 | 502 |         opts, args = getopt.getopt( | 
 | 503 |             sys.argv[1:], | 
| Barry Warsaw | 63ce5af | 2001-07-27 16:47:18 +0000 | [diff] [blame] | 504 |             'ad:DEhk:Kno:p:S:Vvw:x:X:', | 
| Barry Warsaw | 2b63969 | 2001-05-21 19:58:23 +0000 | [diff] [blame] | 505 |             ['extract-all', 'default-domain=', 'escape', 'help', | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 506 |              'keyword=', 'no-default-keywords', | 
| Barry Warsaw | c8f0892 | 2000-02-26 20:56:47 +0000 | [diff] [blame] | 507 |              'add-location', 'no-location', 'output=', 'output-dir=', | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 508 |              'style=', 'verbose', 'version', 'width=', 'exclude-file=', | 
| Barry Warsaw | 63ce5af | 2001-07-27 16:47:18 +0000 | [diff] [blame] | 509 |              'docstrings', 'no-docstrings', | 
| Barry Warsaw | c8f0892 | 2000-02-26 20:56:47 +0000 | [diff] [blame] | 510 |              ]) | 
| Guido van Rossum | b940e11 | 2007-01-10 16:19:56 +0000 | [diff] [blame] | 511 |     except getopt.error as msg: | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 512 |         usage(1, msg) | 
 | 513 |  | 
 | 514 |     # for holding option values | 
 | 515 |     class Options: | 
 | 516 |         # constants | 
 | 517 |         GNU = 1 | 
 | 518 |         SOLARIS = 2 | 
 | 519 |         # defaults | 
| Barry Warsaw | c8f0892 | 2000-02-26 20:56:47 +0000 | [diff] [blame] | 520 |         extractall = 0 # FIXME: currently this option has no effect at all. | 
 | 521 |         escape = 0 | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 522 |         keywords = [] | 
| Barry Warsaw | c8f0892 | 2000-02-26 20:56:47 +0000 | [diff] [blame] | 523 |         outpath = '' | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 524 |         outfile = 'messages.pot' | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 525 |         writelocations = 1 | 
 | 526 |         locationstyle = GNU | 
| Barry Warsaw | 5dbf526 | 1999-11-03 18:47:52 +0000 | [diff] [blame] | 527 |         verbose = 0 | 
| Barry Warsaw | c8f0892 | 2000-02-26 20:56:47 +0000 | [diff] [blame] | 528 |         width = 78 | 
 | 529 |         excludefilename = '' | 
| Barry Warsaw | 08a8a35 | 2000-10-27 04:56:28 +0000 | [diff] [blame] | 530 |         docstrings = 0 | 
| Barry Warsaw | 63ce5af | 2001-07-27 16:47:18 +0000 | [diff] [blame] | 531 |         nodocstrings = {} | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 532 |  | 
 | 533 |     options = Options() | 
 | 534 |     locations = {'gnu' : options.GNU, | 
 | 535 |                  'solaris' : options.SOLARIS, | 
 | 536 |                  } | 
 | 537 |  | 
 | 538 |     # parse options | 
 | 539 |     for opt, arg in opts: | 
 | 540 |         if opt in ('-h', '--help'): | 
 | 541 |             usage(0) | 
| Barry Warsaw | c8f0892 | 2000-02-26 20:56:47 +0000 | [diff] [blame] | 542 |         elif opt in ('-a', '--extract-all'): | 
 | 543 |             options.extractall = 1 | 
 | 544 |         elif opt in ('-d', '--default-domain'): | 
 | 545 |             options.outfile = arg + '.pot' | 
 | 546 |         elif opt in ('-E', '--escape'): | 
 | 547 |             options.escape = 1 | 
| Barry Warsaw | 08a8a35 | 2000-10-27 04:56:28 +0000 | [diff] [blame] | 548 |         elif opt in ('-D', '--docstrings'): | 
 | 549 |             options.docstrings = 1 | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 550 |         elif opt in ('-k', '--keyword'): | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 551 |             options.keywords.append(arg) | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 552 |         elif opt in ('-K', '--no-default-keywords'): | 
 | 553 |             default_keywords = [] | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 554 |         elif opt in ('-n', '--add-location'): | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 555 |             options.writelocations = 1 | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 556 |         elif opt in ('--no-location',): | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 557 |             options.writelocations = 0 | 
 | 558 |         elif opt in ('-S', '--style'): | 
 | 559 |             options.locationstyle = locations.get(arg.lower()) | 
 | 560 |             if options.locationstyle is None: | 
 | 561 |                 usage(1, _('Invalid value for --style: %s') % arg) | 
| Barry Warsaw | c8f0892 | 2000-02-26 20:56:47 +0000 | [diff] [blame] | 562 |         elif opt in ('-o', '--output'): | 
 | 563 |             options.outfile = arg | 
 | 564 |         elif opt in ('-p', '--output-dir'): | 
 | 565 |             options.outpath = arg | 
| Barry Warsaw | 5dbf526 | 1999-11-03 18:47:52 +0000 | [diff] [blame] | 566 |         elif opt in ('-v', '--verbose'): | 
 | 567 |             options.verbose = 1 | 
| Barry Warsaw | c8f0892 | 2000-02-26 20:56:47 +0000 | [diff] [blame] | 568 |         elif opt in ('-V', '--version'): | 
| Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 569 |             print(_('pygettext.py (xgettext for Python) %s') % __version__) | 
| Barry Warsaw | c8f0892 | 2000-02-26 20:56:47 +0000 | [diff] [blame] | 570 |             sys.exit(0) | 
 | 571 |         elif opt in ('-w', '--width'): | 
 | 572 |             try: | 
 | 573 |                 options.width = int(arg) | 
 | 574 |             except ValueError: | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 575 |                 usage(1, _('--width argument must be an integer: %s') % arg) | 
| Barry Warsaw | c8f0892 | 2000-02-26 20:56:47 +0000 | [diff] [blame] | 576 |         elif opt in ('-x', '--exclude-file'): | 
 | 577 |             options.excludefilename = arg | 
| Barry Warsaw | 63ce5af | 2001-07-27 16:47:18 +0000 | [diff] [blame] | 578 |         elif opt in ('-X', '--no-docstrings'): | 
 | 579 |             fp = open(arg) | 
 | 580 |             try: | 
 | 581 |                 while 1: | 
 | 582 |                     line = fp.readline() | 
 | 583 |                     if not line: | 
 | 584 |                         break | 
 | 585 |                     options.nodocstrings[line[:-1]] = 1 | 
 | 586 |             finally: | 
 | 587 |                 fp.close() | 
| Barry Warsaw | c8f0892 | 2000-02-26 20:56:47 +0000 | [diff] [blame] | 588 |  | 
 | 589 |     # calculate escapes | 
| Barry Warsaw | 7733e12 | 2000-02-27 14:30:48 +0000 | [diff] [blame] | 590 |     make_escapes(options.escape) | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 591 |  | 
 | 592 |     # calculate all keywords | 
 | 593 |     options.keywords.extend(default_keywords) | 
 | 594 |  | 
| Barry Warsaw | c8f0892 | 2000-02-26 20:56:47 +0000 | [diff] [blame] | 595 |     # initialize list of strings to exclude | 
 | 596 |     if options.excludefilename: | 
 | 597 |         try: | 
 | 598 |             fp = open(options.excludefilename) | 
 | 599 |             options.toexclude = fp.readlines() | 
 | 600 |             fp.close() | 
 | 601 |         except IOError: | 
| Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 602 |             print(_( | 
 | 603 |                 "Can't read --exclude-file: %s") % options.excludefilename, file=sys.stderr) | 
| Barry Warsaw | c8f0892 | 2000-02-26 20:56:47 +0000 | [diff] [blame] | 604 |             sys.exit(1) | 
 | 605 |     else: | 
 | 606 |         options.toexclude = [] | 
 | 607 |  | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 608 |     # resolve args to module lists | 
 | 609 |     expanded = [] | 
 | 610 |     for arg in args: | 
 | 611 |         if arg == '-': | 
 | 612 |             expanded.append(arg) | 
 | 613 |         else: | 
 | 614 |             expanded.extend(getFilesForName(arg)) | 
 | 615 |     args = expanded | 
 | 616 |  | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 617 |     # slurp through all the files | 
 | 618 |     eater = TokenEater(options) | 
 | 619 |     for filename in args: | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 620 |         if filename == '-': | 
 | 621 |             if options.verbose: | 
| Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 622 |                 print(_('Reading standard input')) | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 623 |             fp = sys.stdin | 
 | 624 |             closep = 0 | 
 | 625 |         else: | 
 | 626 |             if options.verbose: | 
| Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 627 |                 print(_('Working on %s') % filename) | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 628 |             fp = open(filename) | 
 | 629 |             closep = 1 | 
 | 630 |         try: | 
 | 631 |             eater.set_filename(filename) | 
| Barry Warsaw | 75ee8f5 | 2001-02-26 04:46:53 +0000 | [diff] [blame] | 632 |             try: | 
| Trent Nelson | 428de65 | 2008-03-18 22:41:35 +0000 | [diff] [blame] | 633 |                 tokens = tokenize.generate_tokens(fp.readline) | 
 | 634 |                 for _token in tokens: | 
 | 635 |                     eater(*_token) | 
| Guido van Rossum | b940e11 | 2007-01-10 16:19:56 +0000 | [diff] [blame] | 636 |             except tokenize.TokenError as e: | 
| Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 637 |                 print('%s: %s, line %d, column %d' % ( | 
| Georg Brandl | 6464d47 | 2007-10-22 16:16:13 +0000 | [diff] [blame] | 638 |                     e.args[0], filename, e.args[1][0], e.args[1][1]), | 
 | 639 |                     file=sys.stderr) | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 640 |         finally: | 
 | 641 |             if closep: | 
 | 642 |                 fp.close() | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 643 |  | 
| Barry Warsaw | a17e0f1 | 2000-03-08 15:18:35 +0000 | [diff] [blame] | 644 |     # write the output | 
 | 645 |     if options.outfile == '-': | 
 | 646 |         fp = sys.stdout | 
 | 647 |         closep = 0 | 
 | 648 |     else: | 
 | 649 |         if options.outpath: | 
 | 650 |             options.outfile = os.path.join(options.outpath, options.outfile) | 
 | 651 |         fp = open(options.outfile, 'w') | 
 | 652 |         closep = 1 | 
 | 653 |     try: | 
 | 654 |         eater.write(fp) | 
 | 655 |     finally: | 
 | 656 |         if closep: | 
 | 657 |             fp.close() | 
| Barry Warsaw | e27db5a | 1999-08-13 20:59:48 +0000 | [diff] [blame] | 658 |  | 
 | 659 |  | 
 | 660 | if __name__ == '__main__': | 
 | 661 |     main() | 
| Barry Warsaw | 75a6e67 | 2000-05-02 19:28:30 +0000 | [diff] [blame] | 662 |     # some more test strings | 
| Barry Warsaw | e04ee70 | 2003-04-16 18:08:23 +0000 | [diff] [blame] | 663 |     # this one creates a warning | 
 | 664 |     _('*** Seen unexpected token "%(token)s"') % {'token': 'test'} | 
| Martin v. Löwis | 0d1fdea | 2002-11-22 08:36:54 +0000 | [diff] [blame] | 665 |     _('more' 'than' 'one' 'string') |