From 2ec2ed70dfae0edfb9c8df437cfa20b41e971fd1 Mon Sep 17 00:00:00 2001 From: strank Date: Mon, 28 Jul 2008 15:24:27 +0000 Subject: Merged trunk r5043:5619 to adjacent-citations branch. git-svn-id: http://svn.code.sf.net/p/docutils/code/branches/adjacent-citations@5621 929543f6-e4f2-0310-98a6-ba3bd3dd1d04 --- docutils/__init__.py | 2 +- docutils/core.py | 8 +- docutils/frontend.py | 17 +- docutils/languages/__init__.py | 2 +- docutils/languages/pt_br.py | 2 +- docutils/nodes.py | 83 +++++---- docutils/parsers/__init__.py | 2 +- docutils/parsers/rst/directives/__init__.py | 2 +- docutils/parsers/rst/directives/admonitions.py | 2 +- docutils/parsers/rst/directives/body.py | 2 +- docutils/parsers/rst/directives/images.py | 4 +- docutils/parsers/rst/directives/misc.py | 24 +-- docutils/parsers/rst/directives/parts.py | 4 +- docutils/parsers/rst/directives/tables.py | 24 +-- docutils/parsers/rst/languages/__init__.py | 2 +- docutils/parsers/rst/languages/de.py | 2 +- docutils/parsers/rst/roles.py | 12 +- docutils/parsers/rst/states.py | 11 +- docutils/readers/__init__.py | 2 +- docutils/readers/python/__init__.py | 2 +- docutils/readers/python/moduleparser.py | 64 +++---- docutils/statemachine.py | 10 +- docutils/transforms/frontmatter.py | 2 +- docutils/transforms/parts.py | 4 +- docutils/transforms/references.py | 30 +-- docutils/transforms/writer_aux.py | 2 +- docutils/utils.py | 8 +- docutils/writers/__init__.py | 2 +- docutils/writers/html4css1/__init__.py | 65 +++---- docutils/writers/html4css1/html4css1.css | 2 +- docutils/writers/latex2e/__init__.py | 247 +++++++++++++++---------- docutils/writers/newlatex2e/__init__.py | 4 +- docutils/writers/newlatex2e/unicode_map.py | 2 +- docutils/writers/s5_html/__init__.py | 2 +- 34 files changed, 371 insertions(+), 282 deletions(-) (limited to 'docutils') diff --git a/docutils/__init__.py b/docutils/__init__.py index 6991f3643..eca962fca 100644 --- a/docutils/__init__.py +++ b/docutils/__init__.py @@ -49,7 +49,7 @@ Subpackages: __docformat__ = 'reStructuredText' -__version__ = '0.5' +__version__ = '0.6' """``major.minor.micro`` version number. The micro number is bumped for API changes, for new functionality, and for interim project releases. The minor number is bumped whenever there is a significant project release. The major diff --git a/docutils/core.py b/docutils/core.py index f68f74cea..bf3b2a4f1 100644 --- a/docutils/core.py +++ b/docutils/core.py @@ -53,9 +53,11 @@ class Publisher: """A `docutils.writers.Writer` instance.""" for component in 'reader', 'parser', 'writer': - assert not isinstance(getattr(self, component), StringType), \ - ('passed string as "%s" parameter; use "%s_name" instead' - % (getattr(self, component), component, component)) + assert not isinstance(getattr(self, component), StringType), ( + 'passed string "%s" as "%s" parameter; pass an instance, ' + 'or use the "%s_name" parameter instead (in ' + 'docutils.core.publish_* convenience functions).' + % (getattr(self, component), component, component)) self.source = source """The source of input data, a `docutils.io.Input` instance.""" diff --git a/docutils/frontend.py b/docutils/frontend.py index 034e30769..c21bd2c2d 100644 --- a/docutils/frontend.py +++ b/docutils/frontend.py @@ -193,7 +193,7 @@ def make_paths_absolute(pathdict, keys, base_path=None): if base_path is None: base_path = os.getcwd() for key in keys: - if pathdict.has_key(key): + if key in pathdict: value = pathdict[key] if isinstance(value, types.ListType): value = [make_one_path_absolute(base_path, path) @@ -225,7 +225,7 @@ class Values(optparse.Values): other_dict = other_dict.__dict__ other_dict = other_dict.copy() for setting in option_parser.lists.keys(): - if (hasattr(self, setting) and other_dict.has_key(setting)): + if (hasattr(self, setting) and setting in other_dict): value = getattr(self, setting) if value: value += other_dict[setting] @@ -359,12 +359,14 @@ class OptionParser(optparse.OptionParser, docutils.SettingsSpec): ['--leave-comments'], {'action': 'store_false', 'dest': 'strip_comments'}), ('Remove all elements with classes="" from the document tree. ' + 'Warning: potentially dangerous; use with caution. ' '(Multiple-use option.)', ['--strip-elements-with-class'], {'action': 'append', 'dest': 'strip_elements_with_classes', 'metavar': '', 'validator': validate_strip_class}), ('Remove all classes="" attributes from elements in the ' - 'document tree. (Multiple-use option.)', + 'document tree. Warning: potentially dangerous; use with caution. ' + '(Multiple-use option.)', ['--strip-class'], {'action': 'append', 'dest': 'strip_classes', 'metavar': '', 'validator': validate_strip_class}), @@ -476,8 +478,9 @@ class OptionParser(optparse.OptionParser, docutils.SettingsSpec): config_section = 'general' - version_template = ('%%prog (Docutils %s [%s])' - % (docutils.__version__, docutils.__version_details__)) + version_template = ('%%prog (Docutils %s [%s], Python %s, on %s)' + % (docutils.__version__, docutils.__version_details__, + sys.version.split()[0], sys.platform)) """Default version message.""" def __init__(self, components=(), defaults=None, read_config_files=None, @@ -582,7 +585,7 @@ class OptionParser(optparse.OptionParser, docutils.SettingsSpec): continue for section in (tuple(component.config_section_dependencies or ()) + (component.config_section,)): - if applied.has_key(section): + if section in applied: continue applied[section] = 1 settings.update(parser.get_section(section), self) @@ -696,7 +699,7 @@ Skipping "%s" configuration file. if not self.has_section('general'): self.add_section('general') for key, value in options.items(): - if self.old_settings.has_key(key): + if key in self.old_settings: section, setting = self.old_settings[key] if not self.has_section(section): self.add_section(section) diff --git a/docutils/languages/__init__.py b/docutils/languages/__init__.py index c721c0210..7d6521fc1 100644 --- a/docutils/languages/__init__.py +++ b/docutils/languages/__init__.py @@ -14,7 +14,7 @@ __docformat__ = 'reStructuredText' _languages = {} def get_language(language_code): - if _languages.has_key(language_code): + if language_code in _languages: return _languages[language_code] module = __import__(language_code, globals(), locals()) _languages[language_code] = module diff --git a/docutils/languages/pt_br.py b/docutils/languages/pt_br.py index 92db002aa..f4adfbbf6 100644 --- a/docutils/languages/pt_br.py +++ b/docutils/languages/pt_br.py @@ -27,7 +27,7 @@ labels = { 'copyright': u'Copyright', 'dedication': u'Dedicat\u00F3ria', 'abstract': u'Resumo', - 'attention': u'Atten\u00E7\u00E3o!', + 'attention': u'Aten\u00E7\u00E3o!', 'caution': u'Cuidado!', 'danger': u'PERIGO!', 'error': u'Erro', diff --git a/docutils/nodes.py b/docutils/nodes.py index ffb679b17..816befd4d 100644 --- a/docutils/nodes.py +++ b/docutils/nodes.py @@ -27,7 +27,6 @@ import re import warnings from types import IntType, SliceType, StringType, UnicodeType, \ TupleType, ListType, ClassType, TypeType -from UserString import UserString # ============================== @@ -62,11 +61,7 @@ class Node: return 1 def __str__(self): - return self.__unicode__().encode('raw_unicode_escape') - - def __unicode__(self): - # Override in subclass. - raise NotImplementedError + return unicode(self).encode('raw_unicode_escape') def asdom(self, dom=None): """Return a DOM **fragment** representation of this Node.""" @@ -273,7 +268,15 @@ class Node: except IndexError: return None -class Text(Node, UserString): +class reprunicode(unicode): + """ + A class that removes the initial u from unicode's repr. + """ + + def __repr__(self): + return unicode.__repr__(self)[1:] + +class Text(Node, reprunicode): """ Instances are terminal nodes (leaves) containing text only; no child @@ -286,38 +289,44 @@ class Text(Node, UserString): children = () """Text nodes have no children, and cannot have children.""" + def __new__(cls, data, rawsource=None): + """Prevent the rawsource argument from propagating to str.""" + return reprunicode.__new__(cls, data) + def __init__(self, data, rawsource=''): - UserString.__init__(self, data) self.rawsource = rawsource """The raw text from which this element was constructed.""" def __repr__(self): - data = repr(self.data) + data = reprunicode.__repr__(self) if len(data) > 70: - data = repr(self.data[:64] + ' ...') + data = reprunicode.__repr__(self[:64] + ' ...') return '<%s: %s>' % (self.tagname, data) - def __len__(self): - return len(self.data) - def shortrepr(self): - data = repr(self.data) + data = reprunicode.__repr__(self) if len(data) > 20: - data = repr(self.data[:16] + ' ...') + data = reprunicode.__repr__(self[:16] + ' ...') return '<%s: %s>' % (self.tagname, data) def _dom_node(self, domroot): - return domroot.createTextNode(self.data) + return domroot.createTextNode(unicode(self)) def astext(self): - return self.data + return reprunicode(self) - def __unicode__(self): - return self.data + # Note about __unicode__: The implementation of __unicode__ here, + # and the one raising NotImplemented in the superclass Node had + # to be removed when changing Text to a subclass of unicode instead + # of UserString, since there is no way to delegate the __unicode__ + # call to the superclass unicode: + # unicode itself does not have __unicode__ method to delegate to + # and calling unicode(self) or unicode.__new__ directly creates + # an infinite loop def copy(self): - return self.__class__(self.data) + return self.__class__(reprunicode(self), rawsource=self.rawsource) def deepcopy(self): return self.copy() @@ -325,10 +334,19 @@ class Text(Node, UserString): def pformat(self, indent=' ', level=0): result = [] indent = indent * level - for line in self.data.splitlines(): + for line in self.splitlines(): result.append(indent + line + '\n') return ''.join(result) + # rstrip and lstrip are used by substitution definitions where + # they are expected to return a Text instance, this was formerly + # taken care of by UserString. Note that then and now the + # rawsource member is lost. + + def rstrip(self, chars=None): + return self.__class__(reprunicode.rstrip(self, chars)) + def lstrip(self, chars=None): + return self.__class__(reprunicode.lstrip(self, chars)) class Element(Node): @@ -539,10 +557,10 @@ class Element(Node): return self.attributes.get(key, failobj) def hasattr(self, attr): - return self.attributes.has_key(attr) + return attr in self.attributes def delattr(self, attr): - if self.attributes.has_key(attr): + if attr in self.attributes: del self.attributes[attr] def setdefault(self, key, failobj=None): @@ -550,6 +568,9 @@ class Element(Node): has_key = hasattr + # support operator in + __contains__ = hasattr + def append(self, item): self.setup_child(item) self.children.append(item) @@ -930,18 +951,18 @@ class document(Root, Structural, Element): def set_id(self, node, msgnode=None): for id in node['ids']: - if self.ids.has_key(id) and self.ids[id] is not node: + if id in self.ids and self.ids[id] is not node: msg = self.reporter.severe('Duplicate ID: "%s".' % id) if msgnode != None: msgnode += msg if not node['ids']: for name in node['names']: id = self.settings.id_prefix + make_id(name) - if id and not self.ids.has_key(id): + if id and id not in self.ids: break else: id = '' - while not id or self.ids.has_key(id): + while not id or id in self.ids: id = (self.settings.id_prefix + self.settings.auto_id_prefix + str(self.id_start)) self.id_start += 1 @@ -982,7 +1003,7 @@ class document(Root, Structural, Element): The new target is invalidated regardless. """ for name in node['names']: - if self.nameids.has_key(name): + if name in self.nameids: self.set_duplicate_name_id(node, id, name, msgnode, explicit) else: self.nameids[name] = id @@ -997,10 +1018,10 @@ class document(Root, Structural, Element): level = 2 if old_id is not None: old_node = self.ids[old_id] - if node.has_key('refuri'): + if 'refuri' in node: refuri = node['refuri'] if old_node['names'] \ - and old_node.has_key('refuri') \ + and 'refuri' in old_node \ and old_node['refuri'] == refuri: level = 1 # just inform if refuri's identical if level > 1: @@ -1031,7 +1052,7 @@ class document(Root, Structural, Element): msgnode += msg def has_name(self, name): - return self.nameids.has_key(name) + return name in self.nameids # "note" here is an imperative verb: "take note of". def note_implicit_target(self, target, msgnode=None): @@ -1091,7 +1112,7 @@ class document(Root, Structural, Element): def note_substitution_def(self, subdef, def_name, msgnode=None): name = whitespace_normalize_name(def_name) - if self.substitution_defs.has_key(name): + if name in self.substitution_defs: msg = self.reporter.error( 'Duplicate substitution definition name: "%s".' % name, base_node=subdef) diff --git a/docutils/parsers/__init__.py b/docutils/parsers/__init__.py index 125ab7674..2683376f9 100644 --- a/docutils/parsers/__init__.py +++ b/docutils/parsers/__init__.py @@ -41,7 +41,7 @@ _parser_aliases = { def get_parser_class(parser_name): """Return the Parser class from the `parser_name` module.""" parser_name = parser_name.lower() - if _parser_aliases.has_key(parser_name): + if parser_name in _parser_aliases: parser_name = _parser_aliases[parser_name] module = __import__(parser_name, globals(), locals()) return module.Parser diff --git a/docutils/parsers/rst/directives/__init__.py b/docutils/parsers/rst/directives/__init__.py index 14ac03a99..30da65ecd 100644 --- a/docutils/parsers/rst/directives/__init__.py +++ b/docutils/parsers/rst/directives/__init__.py @@ -76,7 +76,7 @@ def directive(directive_name, language_module, document): normname = directive_name.lower() messages = [] msg_text = [] - if _directives.has_key(normname): + if normname in _directives: return _directives[normname], messages canonicalname = None try: diff --git a/docutils/parsers/rst/directives/admonitions.py b/docutils/parsers/rst/directives/admonitions.py index bed3381b8..870b6659e 100644 --- a/docutils/parsers/rst/directives/admonitions.py +++ b/docutils/parsers/rst/directives/admonitions.py @@ -35,7 +35,7 @@ class BaseAdmonition(Directive): self.lineno) admonition_node += nodes.title(title_text, '', *textnodes) admonition_node += messages - if self.options.has_key('class'): + if 'class' in self.options: classes = self.options['class'] else: classes = ['admonition-' + nodes.make_id(title_text)] diff --git a/docutils/parsers/rst/directives/body.py b/docutils/parsers/rst/directives/body.py index 03c9c3fa6..0cc695726 100644 --- a/docutils/parsers/rst/directives/body.py +++ b/docutils/parsers/rst/directives/body.py @@ -39,7 +39,7 @@ class BasePseudoSection(Directive): textnodes, messages = self.state.inline_text(title_text, self.lineno) titles = [nodes.title(title_text, '', *textnodes)] # Sidebar uses this code. - if self.options.has_key('subtitle'): + if 'subtitle' in self.options: textnodes, more_messages = self.state.inline_text( self.options['subtitle'], self.lineno) titles.append(nodes.subtitle(self.options['subtitle'], '', diff --git a/docutils/parsers/rst/directives/images.py b/docutils/parsers/rst/directives/images.py index 96bdb3353..59323bba0 100644 --- a/docutils/parsers/rst/directives/images.py +++ b/docutils/parsers/rst/directives/images.py @@ -46,7 +46,7 @@ class Image(Directive): 'class': directives.class_option} def run(self): - if self.options.has_key('align'): + if 'align' in self.options: if isinstance(self.state, states.SubstitutionDef): # Check for align_v_values. if self.options['align'] not in self.align_v_values: @@ -66,7 +66,7 @@ class Image(Directive): reference = directives.uri(self.arguments[0]) self.options['uri'] = reference reference_node = None - if self.options.has_key('target'): + if 'target' in self.options: block = states.escape2null( self.options['target']).splitlines() block = [line for line in block] diff --git a/docutils/parsers/rst/directives/misc.py b/docutils/parsers/rst/directives/misc.py index 5d5d34729..89c8364c7 100644 --- a/docutils/parsers/rst/directives/misc.py +++ b/docutils/parsers/rst/directives/misc.py @@ -86,7 +86,7 @@ class Include(Directive): raise self.severe('Problem with "end-before" option of "%s" ' 'directive:\nText not found.' % self.name) include_text = include_text[:before_index] - if self.options.has_key('literal'): + if 'literal' in self.options: literal_block = nodes.literal_block(include_text, include_text, source=path) literal_block.line = 1 @@ -120,20 +120,20 @@ class Raw(Directive): def run(self): if (not self.state.document.settings.raw_enabled or (not self.state.document.settings.file_insertion_enabled - and (self.options.has_key('file') - or self.options.has_key('url')))): + and ('file' in self.options + or 'url' in self.options))): raise self.warning('"%s" directive disabled.' % self.name) attributes = {'format': ' '.join(self.arguments[0].lower().split())} encoding = self.options.get( 'encoding', self.state.document.settings.input_encoding) if self.content: - if self.options.has_key('file') or self.options.has_key('url'): + if 'file' in self.options or 'url' in self.options: raise self.error( '"%s" directive may not both specify an external file ' 'and have content.' % self.name) text = '\n'.join(self.content) - elif self.options.has_key('file'): - if self.options.has_key('url'): + elif 'file' in self.options: + if 'url' in self.options: raise self.error( 'The "file" and "url" options may not be simultaneously ' 'specified for the "%s" directive.' % self.name) @@ -159,7 +159,7 @@ class Raw(Directive): 'Problem with "%s" directive:\n%s: %s' % (self.name, error.__class__.__name__, error)) attributes['source'] = path - elif self.options.has_key('url'): + elif 'url' in self.options: source = self.options['url'] # Do not import urllib2 at the top of the module because # it may fail due to broken SSL dependencies, and it takes @@ -244,12 +244,12 @@ class Unicode(Directive): 'Invalid context: the "%s" directive can only be used within ' 'a substitution definition.' % self.name) substitution_definition = self.state_machine.node - if self.options.has_key('trim'): + if 'trim' in self.options: substitution_definition.attributes['ltrim'] = 1 substitution_definition.attributes['rtrim'] = 1 - if self.options.has_key('ltrim'): + if 'ltrim' in self.options: substitution_definition.attributes['ltrim'] = 1 - if self.options.has_key('rtrim'): + if 'rtrim' in self.options: substitution_definition.attributes['rtrim'] = 1 codes = self.comment_pattern.split(self.arguments[0])[0].split() element = nodes.Element() @@ -349,7 +349,7 @@ class Role(Directive): nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return messages + [error] - if not options.has_key('class'): + if 'class' not in options: try: options['class'] = directives.class_option(new_role_name) except ValueError, detail: @@ -373,7 +373,7 @@ class DefaultRole(Directive): def run(self): if not self.arguments: - if roles._roles.has_key(''): + if '' in roles._roles: # restore the "default" default role del roles._roles[''] return [] diff --git a/docutils/parsers/rst/directives/parts.py b/docutils/parsers/rst/directives/parts.py index da1586275..6ef8c905c 100644 --- a/docutils/parsers/rst/directives/parts.py +++ b/docutils/parsers/rst/directives/parts.py @@ -57,13 +57,13 @@ class Contents(Directive): title = nodes.title(title_text, '', *text_nodes) else: messages = [] - if self.options.has_key('local'): + if 'local' in self.options: title = None else: title = nodes.title('', language.labels['contents']) topic = nodes.topic(classes=['contents']) topic['classes'] += self.options.get('class', []) - if self.options.has_key('local'): + if 'local' in self.options: topic['classes'].append('local') if title: name = title.astext() diff --git a/docutils/parsers/rst/directives/tables.py b/docutils/parsers/rst/directives/tables.py index 639ce8d1f..5527c9f0b 100644 --- a/docutils/parsers/rst/directives/tables.py +++ b/docutils/parsers/rst/directives/tables.py @@ -49,7 +49,7 @@ class Table(Directive): source = self.state_machine.get_source(self.lineno - 1) table_head = [] max_header_cols = 0 - if self.options.has_key('header'): # separate table header in option + if 'header' in self.options: # separate table header in option rows, max_header_cols = self.parse_csv_data_into_rows( self.options['header'].split('\n'), self.HeaderDialect(), source) @@ -88,7 +88,7 @@ class Table(Directive): raise SystemMessagePropagation(error) def get_column_widths(self, max_cols): - if self.options.has_key('widths'): + if 'widths' in self.options: col_widths = self.options['widths'] if len(col_widths) != max_cols: error = self.state_machine.reporter.error( @@ -170,13 +170,13 @@ class CSVTable(Table): quoting = csv.QUOTE_MINIMAL def __init__(self, options): - if options.has_key('delim'): + if 'delim' in options: self.delimiter = str(options['delim']) - if options.has_key('keepspace'): + if 'keepspace' in options: self.skipinitialspace = False - if options.has_key('quote'): + if 'quote' in options: self.quotechar = str(options['quote']) - if options.has_key('escape'): + if 'escape' in options: self.doublequote = False self.escapechar = str(options['escape']) csv.Dialect.__init__(self) @@ -206,8 +206,8 @@ class CSVTable(Table): def run(self): try: if (not self.state.document.settings.file_insertion_enabled - and (self.options.has_key('file') - or self.options.has_key('url'))): + and ('file' in self.options + or 'url' in self.options)): warning = self.state_machine.reporter.warning( 'File and URL access deactivated; ignoring "%s" ' 'directive.' % self.name, nodes.literal_block( @@ -253,7 +253,7 @@ class CSVTable(Table): 'encoding', self.state.document.settings.input_encoding) if self.content: # CSV data is from directive content. - if self.options.has_key('file') or self.options.has_key('url'): + if 'file' in self.options or 'url' in self.options: error = self.state_machine.reporter.error( '"%s" directive may not both specify an external file and' ' have content.' % self.name, nodes.literal_block( @@ -261,9 +261,9 @@ class CSVTable(Table): raise SystemMessagePropagation(error) source = self.content.source(0) csv_data = self.content - elif self.options.has_key('file'): + elif 'file' in self.options: # CSV data is from an external file. - if self.options.has_key('url'): + if 'url' in self.options: error = self.state_machine.reporter.error( 'The "file" and "url" options may not be simultaneously' ' specified for the "%s" directive.' % self.name, @@ -289,7 +289,7 @@ class CSVTable(Table): % (self.name, error), nodes.literal_block( self.block_text, self.block_text), line=self.lineno) raise SystemMessagePropagation(severe) - elif self.options.has_key('url'): + elif 'url' in self.options: # CSV data is from a URL. # Do not import urllib2 at the top of the module because # it may fail due to broken SSL dependencies, and it takes diff --git a/docutils/parsers/rst/languages/__init__.py b/docutils/parsers/rst/languages/__init__.py index 18c884748..962802245 100644 --- a/docutils/parsers/rst/languages/__init__.py +++ b/docutils/parsers/rst/languages/__init__.py @@ -15,7 +15,7 @@ __docformat__ = 'reStructuredText' _languages = {} def get_language(language_code): - if _languages.has_key(language_code): + if language_code in _languages: return _languages[language_code] try: module = __import__(language_code, globals(), locals()) diff --git a/docutils/parsers/rst/languages/de.py b/docutils/parsers/rst/languages/de.py index ecdde3837..300a8a30f 100644 --- a/docutils/parsers/rst/languages/de.py +++ b/docutils/parsers/rst/languages/de.py @@ -1,6 +1,6 @@ # $Id$ # Authors: Engelbert Gruber ; -# Felix Wiemann +# Lea Wiemann # Copyright: This module has been placed in the public domain. # New language mappings are welcome. Before doing a new translation, please diff --git a/docutils/parsers/rst/roles.py b/docutils/parsers/rst/roles.py index 1da1395e9..062d53e50 100644 --- a/docutils/parsers/rst/roles.py +++ b/docutils/parsers/rst/roles.py @@ -101,7 +101,7 @@ def role(role_name, language_module, lineno, reporter): messages = [] msg_text = [] - if _roles.has_key(normname): + if normname in _roles: return _roles[normname], messages if role_name: @@ -135,7 +135,7 @@ def role(role_name, language_module, lineno, reporter): messages.append(message) # Look the role up in the registry, and return it. - if _role_registry.has_key(canonicalname): + if canonicalname in _role_registry: role_fn = _role_registry[canonicalname] register_local_role(normname, role_fn) return role_fn, messages @@ -171,7 +171,7 @@ def set_implicit_options(role_fn): """ if not hasattr(role_fn, 'options') or role_fn.options is None: role_fn.options = {'class': directives.class_option} - elif not role_fn.options.has_key('class'): + elif 'class' not in role_fn.options: role_fn.options['class'] = directives.class_option def register_generic_role(canonical_name, node_class): @@ -294,7 +294,7 @@ def rfc_reference_role(role, rawtext, text, lineno, inliner, register_canonical_role('rfc-reference', rfc_reference_role) def raw_role(role, rawtext, text, lineno, inliner, options={}, content=[]): - if not options.has_key('format'): + if 'format' not in options: msg = inliner.reporter.error( 'No format (Writer name) is associated with this role: "%s".\n' 'The "raw" role cannot be used directly.\n' @@ -340,7 +340,7 @@ def set_classes(options): Auxiliary function to set options['classes'] and delete options['class']. """ - if options.has_key('class'): - assert not options.has_key('classes') + if 'class' in options: + assert 'classes' not in options options['classes'] = options['class'] del options['class'] diff --git a/docutils/parsers/rst/states.py b/docutils/parsers/rst/states.py index 50f5dd082..d5efb20e5 100644 --- a/docutils/parsers/rst/states.py +++ b/docutils/parsers/rst/states.py @@ -512,8 +512,8 @@ class Inliner: non_whitespace_before = r'(? Additional docstring - - __docformat__ + + __docformat__ 'reStructuredText' - - a + + a 1 Attribute docstring - - C + + C - Super + Super C's docstring - - class_attribute + + class_attribute 1 class_attribute's docstring - - __init__ + + __init__ __init__'s docstring - - self + + self - - text + + text None - - self.instance_attribute + + self.instance_attribute (text * 7 + ' whaddyaknow') instance_attribute's docstring - - f + + f f's docstring - - x + + x # parameter x - - y + + y a * 5 # parameter y - - args + + args # parameter args - - f.function_attribute + + f.function_attribute 1 @@ -525,14 +525,14 @@ class TokenParser: def note_token(self): if self.type == tokenize.NL: return - del_ws = self.del_ws_prefix.has_key(self.string) - append_ws = not self.no_ws_suffix.has_key(self.string) - if self.openers.has_key(self.string): + del_ws = self.string in self.del_ws_prefix + append_ws = self.string not in self.no_ws_suffix + if self.string in self.openers: self.stack.append(self.string) if (self._type == token.NAME - or self.closers.has_key(self._string)): + or self._string in self.closers): del_ws = 1 - elif self.closers.has_key(self.string): + elif self.string in self.closers: assert self.stack[-1] == self.closers[self.string] self.stack.pop() elif self.string == '`': diff --git a/docutils/statemachine.py b/docutils/statemachine.py index 514e5dbd1..c29f128a7 100644 --- a/docutils/statemachine.py +++ b/docutils/statemachine.py @@ -377,7 +377,7 @@ class StateMachine: self.next_line(len(block) - 1) return block except UnexpectedIndentationError, error: - block, source, lineno = error + block, source, lineno = error.args self.next_line(len(block) - 1) # advance to last line of block raise @@ -441,7 +441,7 @@ class StateMachine: added. """ statename = state_class.__name__ - if self.states.has_key(statename): + if statename in self.states: raise DuplicateStateError(statename) self.states[statename] = state_class(self, self.debug) @@ -629,9 +629,9 @@ class State: Exceptions: `DuplicateTransitionError`, `UnknownTransitionError`. """ for name in names: - if self.transitions.has_key(name): + if name in self.transitions: raise DuplicateTransitionError(name) - if not transitions.has_key(name): + if name not in transitions: raise UnknownTransitionError(name) self.transition_order[:0] = names self.transitions.update(transitions) @@ -644,7 +644,7 @@ class State: Exception: `DuplicateTransitionError`. """ - if self.transitions.has_key(name): + if name in self.transitions: raise DuplicateTransitionError(name) self.transition_order[:0] = [name] self.transitions[name] = transition diff --git a/docutils/transforms/frontmatter.py b/docutils/transforms/frontmatter.py index eae149a44..cd537f910 100644 --- a/docutils/transforms/frontmatter.py +++ b/docutils/transforms/frontmatter.py @@ -388,7 +388,7 @@ class DocInfo(Transform): try: name = field[0][0].astext() normedname = nodes.fully_normalize_name(name) - if not (len(field) == 2 and bibliofields.has_key(normedname) + if not (len(field) == 2 and normedname in bibliofields and self.check_empty_biblio_field(field, name)): raise TransformError canonical = bibliofields[normedname] diff --git a/docutils/transforms/parts.py b/docutils/transforms/parts.py index 39cb74f75..26fcdb684 100644 --- a/docutils/transforms/parts.py +++ b/docutils/transforms/parts.py @@ -80,7 +80,7 @@ class Contents(Transform): def apply(self): details = self.startnode.details - if details.has_key('local'): + if 'local' in details: startnode = self.startnode.parent.parent while not (isinstance(startnode, nodes.section) or isinstance(startnode, nodes.document)): @@ -89,7 +89,7 @@ class Contents(Transform): else: startnode = self.document self.toc_id = self.startnode.parent['ids'][0] - if details.has_key('backlinks'): + if 'backlinks' in details: self.backlinks = details['backlinks'] else: self.backlinks = self.document.settings.toc_backlinks diff --git a/docutils/transforms/references.py b/docutils/transforms/references.py index 097877ee9..c45fdb0da 100644 --- a/docutils/transforms/references.py +++ b/docutils/transforms/references.py @@ -240,7 +240,7 @@ class IndirectHyperlinks(Transform): del target.multiply_indirect if reftarget.hasattr('refuri'): target['refuri'] = reftarget['refuri'] - if target.has_key('refid'): + if 'refid' in target: del target['refid'] elif reftarget.hasattr('refid'): target['refid'] = reftarget['refid'] @@ -257,7 +257,7 @@ class IndirectHyperlinks(Transform): target.resolved = 1 def nonexistent_indirect_target(self, target): - if self.document.nameids.has_key(target['refname']): + if target['refname'] in self.document.nameids: self.indirect_target_error(target, 'which is a duplicate, and ' 'cannot be used as a unique reference') else: @@ -505,7 +505,7 @@ class Footnotes(Transform): while 1: label = str(startnum) startnum += 1 - if not self.document.nameids.has_key(label): + if label not in self.document.nameids: break footnote.insert(0, nodes.label('', label)) for name in footnote['names']: @@ -600,12 +600,12 @@ class Footnotes(Transform): """ for footnote in self.document.footnotes: for label in footnote['names']: - if self.document.footnote_refs.has_key(label): + if label in self.document.footnote_refs: reflist = self.document.footnote_refs[label] self.resolve_references(footnote, reflist) for citation in self.document.citations: for label in citation['names']: - if self.document.citation_refs.has_key(label): + if label in self.document.citation_refs: reflist = self.document.citation_refs[label] self.resolve_references(citation, reflist) @@ -666,11 +666,11 @@ class Substitutions(Transform): for ref in subreflist: refname = ref['refname'] key = None - if defs.has_key(refname): + if refname in defs: key = refname else: normed_name = refname.lower() - if normed.has_key(normed_name): + if normed_name in normed: key = normed[normed_name] if key is None: msg = self.document.reporter.error( @@ -686,14 +686,14 @@ class Substitutions(Transform): subdef = defs[key] parent = ref.parent index = parent.index(ref) - if (subdef.attributes.has_key('ltrim') - or subdef.attributes.has_key('trim')): + if ('ltrim' in subdef.attributes + or 'trim' in subdef.attributes): if index > 0 and isinstance(parent[index - 1], nodes.Text): parent.replace(parent[index - 1], parent[index - 1].rstrip()) - if (subdef.attributes.has_key('rtrim') - or subdef.attributes.has_key('trim')): + if ('rtrim' in subdef.attributes + or 'trim' in subdef.attributes): if (len(parent) > index + 1 and isinstance(parent[index + 1], nodes.Text)): parent.replace(parent[index + 1], @@ -764,7 +764,7 @@ class TargetNotes(Transform): continue footnote = self.make_target_footnote(target['refuri'], refs, notes) - if not notes.has_key(target['refuri']): + if target['refuri'] not in notes: notes[target['refuri']] = footnote nodelist.append(footnote) # Take care of anonymous references. @@ -774,13 +774,13 @@ class TargetNotes(Transform): if ref.hasattr('refuri'): footnote = self.make_target_footnote(ref['refuri'], [ref], notes) - if not notes.has_key(ref['refuri']): + if ref['refuri'] not in notes: notes[ref['refuri']] = footnote nodelist.append(footnote) self.startnode.replace_self(nodelist) def make_target_footnote(self, refuri, refs, notes): - if notes.has_key(refuri): # duplicate? + if refuri in notes: # duplicate? footnote = notes[refuri] assert len(footnote['names']) == 1 footnote_name = footnote['names'][0] @@ -873,7 +873,7 @@ class DanglingReferencesVisitor(nodes.SparseNodeVisitor): if resolver_function(node): break else: - if self.document.nameids.has_key(refname): + if refname in self.document.nameids: msg = self.document.reporter.error( 'Duplicate target name, cannot be used as a unique ' 'reference: "%s".' % (node['refname']), base_node=node) diff --git a/docutils/transforms/writer_aux.py b/docutils/transforms/writer_aux.py index 6be338338..0db085fb0 100644 --- a/docutils/transforms/writer_aux.py +++ b/docutils/transforms/writer_aux.py @@ -1,5 +1,5 @@ # $Id$ -# Author: Felix Wiemann +# Author: Lea Wiemann # Copyright: This module has been placed in the public domain. """ diff --git a/docutils/utils.py b/docutils/utils.py index 456f3eed9..b88ffbbc1 100644 --- a/docutils/utils.py +++ b/docutils/utils.py @@ -161,7 +161,7 @@ class Reporter: Raise an exception or generate a warning if appropriate. """ attributes = kwargs.copy() - if kwargs.has_key('base_node'): + if 'base_node' in kwargs: source, line = get_source_line(kwargs['base_node']) del attributes['base_node'] if source is not None: @@ -308,7 +308,7 @@ def assemble_option_dict(option_list, options_spec): convertor = options_spec[name] # raises KeyError if unknown if convertor is None: raise KeyError(name) # or if explicitly disabled - if options.has_key(name): + if name in options: raise DuplicateOptionError('duplicate option "%s"' % name) try: options[name] = convertor(value) @@ -404,9 +404,9 @@ def clean_rcs_keywords(paragraph, keyword_substitutions): if len(paragraph) == 1 and isinstance(paragraph[0], nodes.Text): textnode = paragraph[0] for pattern, substitution in keyword_substitutions: - match = pattern.search(textnode.data) + match = pattern.search(textnode) if match: - textnode.data = pattern.sub(substitution, textnode.data) + paragraph[0] = nodes.Text(pattern.sub(substitution, textnode)) return def relative_path(source, target): diff --git a/docutils/writers/__init__.py b/docutils/writers/__init__.py index 39e1ecd5b..8e3bd1aaa 100644 --- a/docutils/writers/__init__.py +++ b/docutils/writers/__init__.py @@ -127,7 +127,7 @@ _writer_aliases = { def get_writer_class(writer_name): """Return the Writer class from the `writer_name` module.""" writer_name = writer_name.lower() - if _writer_aliases.has_key(writer_name): + if writer_name in _writer_aliases: writer_name = _writer_aliases[writer_name] module = __import__(writer_name, globals(), locals()) return module.Writer diff --git a/docutils/writers/html4css1/__init__.py b/docutils/writers/html4css1/__init__.py index 693672b76..57d2c6ef0 100644 --- a/docutils/writers/html4css1/__init__.py +++ b/docutils/writers/html4css1/__init__.py @@ -353,13 +353,13 @@ class HTMLTranslator(nodes.NodeVisitor): for (name, value) in attributes.items(): atts[name.lower()] = value classes = node.get('classes', []) - if atts.has_key('class'): + if 'class' in atts: classes.append(atts['class']) if classes: atts['class'] = ' '.join(classes) - assert not atts.has_key('id') + assert 'id' not in atts ids.extend(node.get('ids', [])) - if atts.has_key('ids'): + if 'ids' in atts: ids.extend(atts['ids']) del atts['ids'] if ids: @@ -712,7 +712,7 @@ class HTMLTranslator(nodes.NodeVisitor): assert not self.context, 'len(context) = %s' % len(self.context) def visit_emphasis(self, node): - self.body.append('') + self.body.append(self.starttag(node, 'em', '')) def depart_emphasis(self, node): self.body.append('') @@ -731,9 +731,9 @@ class HTMLTranslator(nodes.NodeVisitor): tagname = 'td' del atts['class'] node.parent.column += 1 - if node.has_key('morerows'): + if 'morerows' in node: atts['rowspan'] = node['morerows'] + 1 - if node.has_key('morecols'): + if 'morecols' in node: atts['colspan'] = node['morecols'] + 1 node.parent.column += node['morecols'] self.body.append(self.starttag(node, tagname, '', **atts)) @@ -752,9 +752,9 @@ class HTMLTranslator(nodes.NodeVisitor): usable. """ atts = {} - if node.has_key('start'): + if 'start' in node: atts['start'] = node['start'] - if node.has_key('enumtype'): + if 'enumtype' in node: atts['class'] = node['enumtype'] # @@@ To do: prefix, suffix. How? Change prefix/suffix to a # single "format" attribute? Use CSS2? @@ -941,26 +941,26 @@ class HTMLTranslator(nodes.NodeVisitor): def visit_image(self, node): atts = {} atts['src'] = node['uri'] - if node.has_key('width'): + if 'width' in node: atts['width'] = node['width'] - if node.has_key('height'): + if 'height' in node: atts['height'] = node['height'] - if node.has_key('scale'): - if Image and not (node.has_key('width') - and node.has_key('height')): + if 'scale' in node: + if Image and not ('width' in node + and 'height' in node): try: im = Image.open(str(atts['src'])) except (IOError, # Source image can't be found or opened UnicodeError): # PIL doesn't like Unicode paths. pass else: - if not atts.has_key('width'): + if 'width' not in atts: atts['width'] = str(im.size[0]) - if not atts.has_key('height'): + if 'height' not in atts: atts['height'] = str(im.size[1]) del im for att_name in 'width', 'height': - if atts.has_key(att_name): + if att_name in atts: match = re.match(r'([0-9.]+)(\S*)$', atts[att_name]) assert match atts[att_name] = '%s%s' % ( @@ -968,7 +968,7 @@ class HTMLTranslator(nodes.NodeVisitor): match.group(2)) style = [] for att_name in 'width', 'height': - if atts.has_key(att_name): + if att_name in atts: if re.match(r'^[0-9.]+$', atts[att_name]): # Interpret unitless values as pixels. atts[att_name] += 'px' @@ -984,7 +984,7 @@ class HTMLTranslator(nodes.NodeVisitor): suffix = '' else: suffix = '\n' - if node.has_key('align'): + if 'align' in node: if node['align'] == 'center': # "align" attribute is set in surrounding "div" element. self.body.append('
') @@ -1167,12 +1167,11 @@ class HTMLTranslator(nodes.NodeVisitor): if child is node: break return 0 + parent_length = len([n for n in node.parent if not isinstance( + n, (nodes.Invisible, nodes.label))]) if ( self.compact_simple or self.compact_field_list - or (self.compact_p - and (len(node.parent) == 1 - or len(node.parent) == 2 - and isinstance(node.parent[0], nodes.label)))): + or self.compact_p and parent_length == 1): return 1 return 0 @@ -1210,17 +1209,19 @@ class HTMLTranslator(nodes.NodeVisitor): raise nodes.SkipNode def visit_reference(self, node): - if node.has_key('refuri'): - href = node['refuri'] + atts = {'class': 'reference'} + if 'refuri' in node: + atts['href'] = node['refuri'] if ( self.settings.cloak_email_addresses - and href.startswith('mailto:')): - href = self.cloak_mailto(href) + and atts['href'].startswith('mailto:')): + atts['href'] = self.cloak_mailto(atts['href']) self.in_mailto = 1 + atts['class'] += ' external' else: - assert node.has_key('refid'), \ + assert 'refid' in node, \ 'References must have "refuri" or "refid" attribute.' - href = '#' + node['refid'] - atts = {'href': href, 'class': 'reference'} + atts['href'] = '#' + node['refid'] + atts['class'] += ' internal' if not isinstance(node.parent, nodes.TextElement): assert len(node) == 1 and isinstance(node[0], nodes.image) atts['class'] += ' image-reference' @@ -1277,7 +1278,7 @@ class HTMLTranslator(nodes.NodeVisitor): self.depart_docinfo_item() def visit_strong(self, node): - self.body.append('') + self.body.append(self.starttag(node, 'strong', '')) def depart_strong(self, node): self.body.append('') @@ -1363,8 +1364,8 @@ class HTMLTranslator(nodes.NodeVisitor): self.body.append('\n') def visit_target(self, node): - if not (node.has_key('refuri') or node.has_key('refid') - or node.has_key('refname')): + if not ('refuri' in node or 'refid' in node + or 'refname' in node): self.body.append(self.starttag(node, 'span', '', CLASS='target')) self.context.append('') else: diff --git a/docutils/writers/html4css1/html4css1.css b/docutils/writers/html4css1/html4css1.css index 331a2979a..345f1cc85 100644 --- a/docutils/writers/html4css1/html4css1.css +++ b/docutils/writers/html4css1/html4css1.css @@ -106,7 +106,7 @@ div.line-block div.line-block { margin-left: 1.5em } div.sidebar { - margin-left: 1em ; + margin: 0 0 0.5em 1em ; border: medium outset ; padding: 1em ; background-color: #ffffee ; diff --git a/docutils/writers/latex2e/__init__.py b/docutils/writers/latex2e/__init__.py index 0c459147e..4db7b67bf 100644 --- a/docutils/writers/latex2e/__init__.py +++ b/docutils/writers/latex2e/__init__.py @@ -21,6 +21,8 @@ from types import ListType from docutils import frontend, nodes, languages, writers, utils from docutils.writers.newlatex2e import unicode_map +from docutils.transforms.references import DanglingReferencesVisitor + class Writer(writers.Writer): supported = ('latex','latex2e') @@ -74,6 +76,10 @@ class Writer(writers.Writer): ['--use-latex-toc'], {'default': 0, 'action': 'store_true', 'validator': frontend.validate_boolean}), + ('Add parts on top of the section hierarchy.', + ['--use-part-section'], + {'default': 0, 'action': 'store_true', + 'validator': frontend.validate_boolean}), ('Let LaTeX print author and date, do not show it in docutils ' 'document info.', ['--use-latex-docinfo'], @@ -110,8 +116,12 @@ class Writer(writers.Writer): 'for compound enumerated lists. Default is "-".', ['--section-enumerator-separator'], {'default': '-', 'metavar': ''}), + ('When possibile, use the specified environment for literal-blocks. ' + 'Default is quoting of whitespace and special chars.', + ['--literal-block-env'], + {'default': '', }), ('When possibile, use verbatim for literal-blocks. ' - 'Default is to always use the mbox environment.', + 'Compatibility alias for "--literal-block-env=verbatim".', ['--use-verbatim-when-possible'], {'default': 0, 'action': 'store_true', 'validator': frontend.validate_boolean}), @@ -153,6 +163,9 @@ class Writer(writers.Writer): config_section = 'latex2e writer' config_section_dependencies = ('writers',) + visitor_attributes = ("head_prefix", "head", + "body_prefix", "body", "body_suffix") + output = None """Final translated form of `document`.""" @@ -164,11 +177,15 @@ class Writer(writers.Writer): visitor = self.translator_class(self.document) self.document.walkabout(visitor) self.output = visitor.astext() - self.head_prefix = visitor.head_prefix - self.head = visitor.head - self.body_prefix = visitor.body_prefix - self.body = visitor.body - self.body_suffix = visitor.body_suffix + # copy parts + for attr in self.visitor_attributes: + setattr(self, attr, getattr(visitor, attr)) + + def assemble_parts(self): + writers.Writer.assemble_parts(self) + for part in self.visitor_attributes: + self.parts[part] = ''.join(getattr(self, part)) + """ Notes on LaTeX @@ -177,6 +194,9 @@ Notes on LaTeX * LaTeX does not support multiple tocs in one document. (might be no limitation except for docutils documentation) + The "minitoc" latex package can produce per-chapter tocs in + book and report document classes. + * width * linewidth - width of a line in the local environment @@ -276,13 +296,13 @@ class Babel: return text.replace('"', self.double_quote_replacment) def get_language(self): - if self._ISO639_TO_BABEL.has_key(self.language): + if self.language in self._ISO639_TO_BABEL: return self._ISO639_TO_BABEL[self.language] else: # support dialects. - l = self.language.split("_")[0] - if self._ISO639_TO_BABEL.has_key(l): - return self._ISO639_TO_BABEL[l] + lang = self.language.split("_")[0] + if lang in self._ISO639_TO_BABEL: + return self._ISO639_TO_BABEL[lang] return None @@ -336,22 +356,9 @@ latex_headings = { class DocumentClass: """Details of a LaTeX document class.""" - # BUG: LaTeX has no deeper sections (actually paragrah is no - # section either). - # BUG: No support for unknown document classes. Make 'article' - # default? - _class_sections = { - 'book': ( 'chapter', 'section', 'subsection', 'subsubsection' ), - 'scrbook': ( 'chapter', 'section', 'subsection', 'subsubsection' ), - 'report': ( 'chapter', 'section', 'subsection', 'subsubsection' ), - 'scrreprt': ( 'chapter', 'section', 'subsection', 'subsubsection' ), - 'article': ( 'section', 'subsection', 'subsubsection' ), - 'scrartcl': ( 'section', 'subsection', 'subsubsection' ), - } - _deepest_section = 'subsubsection' - - def __init__(self, document_class): + def __init__(self, document_class, with_part=False): self.document_class = document_class + self._with_part = with_part def section(self, level): """ Return the section name at the given level for the specific @@ -359,11 +366,16 @@ class DocumentClass: Level is 1,2,3..., as level 0 is the title.""" - sections = self._class_sections[self.document_class] + sections = [ 'section', 'subsection', 'subsubsection', + 'paragraph', 'subparagraph' ] + if self.document_class in ('book', 'report', 'scrreprt', 'scrbook'): + sections.insert(0, 'chapter') + if self._with_part: + sections.insert(0, 'part') if level <= len(sections): return sections[level-1] else: - return self._deepest_section + return sections[-1] class Table: """ Manage a table while traversing. @@ -384,6 +396,7 @@ class Table: self._attrs = {} self._col_width = [] self._rowspan = [] + self.stubs = [] def open(self): self._open = 1 @@ -396,8 +409,10 @@ class Table: self._col_specs = None self.caption = None self._attrs = {} + self.stubs = [] def is_open(self): return self._open + def set_table_style(self, table_style): if not table_style in ('standard','booktabs','borderless','nolines'): return @@ -413,7 +428,7 @@ class Table: def set(self,attr,value): self._attrs[attr] = value def get(self,attr): - if self._attrs.has_key(attr): + if attr in self._attrs: return self._attrs[attr] return None def get_vertical_bar(self): @@ -422,7 +437,12 @@ class Table: return '' # horizontal lines are drawn below a row, because we. def get_opening(self): - return '\\begin{%s}[c]' % self._latex_type + if self._latex_type == 'longtable': + # otherwise longtable might move before paragraph and subparagraph + prefix = '\\leavevmode\n' + else: + prefix = '' + return '%s\\begin{%s}[c]' % (prefix, self._latex_type) def get_closing(self): line = "" if self._table_style == 'booktabs': @@ -431,8 +451,10 @@ class Table: lines = '\\hline\n' return '%s\\end{%s}' % (line,self._latex_type) - def visit_colspec(self,node): + def visit_colspec(self, node): self._col_specs.append(node) + # "stubs" list is an attribute of the tgroup element: + self.stubs.append(node.attributes.get('stub')) def get_colspecs(self): """ @@ -466,7 +488,7 @@ class Table: colwidth = factor * float(node['colwidth']+1) / width self._col_width.append(colwidth+0.005) self._rowspan.append(0) - latex_table_spec += "%sp{%.2f\\locallinewidth}" % (bar,colwidth+0.005) + latex_table_spec += "%sp{%.3f\\locallinewidth}" % (bar,colwidth+0.005) return latex_table_spec+bar def get_column_width(self): @@ -487,7 +509,8 @@ class Table: # a.append('\\hline\n') if self._table_style == 'booktabs': a.append('\\midrule\n') - a.append('\\endhead\n') + if self._latex_type == 'longtable': + a.append('\\endhead\n') # for longtable one could add firsthead, foot and lastfoot self._in_thead = 0 return a @@ -534,6 +557,10 @@ class Table: return self._cell_in_row def visit_entry(self): self._cell_in_row += 1 + def is_stub_column(self): + if len(self.stubs) >= self._cell_in_row: + return self.stubs[self._cell_in_row-1] + return False class LaTeXTranslator(nodes.NodeVisitor): @@ -541,12 +568,19 @@ class LaTeXTranslator(nodes.NodeVisitor): # When options are given to the documentclass, latex will pass them # to other packages, as done with babel. # Dummy settings might be taken from document settings - + + # Templates + # --------- + latex_head = '\\documentclass[%s]{%s}\n' - linking = '\\usepackage[colorlinks=%s,linkcolor=%s,urlcolor=%s]{hyperref}\n' + linking = "\\ifthenelse{\\isundefined{\\hypersetup}}{\n" \ + +"\\usepackage[colorlinks=%s,linkcolor=%s,urlcolor=%s]{hyperref}\n" \ + +"}{}\n" stylesheet = '\\input{%s}\n' # add a generated on day , machine by user using docutils version. - generator = '%% generator Docutils: http://docutils.sourceforge.net/\n' + generator = '% generated by Docutils \n' + # Config setting defaults + # ----------------------- # use latex tableofcontents or let docutils do it. use_latex_toc = 0 @@ -592,6 +626,7 @@ class LaTeXTranslator(nodes.NodeVisitor): if self.settings.use_bibtex: self.bibtex = self.settings.use_bibtex.split(",",1) + # TODO avoid errors on not declared citations. else: self.bibtex = None # language: labels, bibliographic_fields, and author_separators. @@ -601,11 +636,12 @@ class LaTeXTranslator(nodes.NodeVisitor): self.author_separator = self.language.author_separators[0] self.d_options = self.settings.documentoptions if self.babel.get_language(): - self.d_options += ',%s' % \ - self.babel.get_language() + self.d_options += ',%s' % self.babel.get_language() - self.d_class = DocumentClass(settings.documentclass) + self.d_class = DocumentClass(settings.documentclass, + settings.use_part_section) # object for a table while proccessing. + self.table_stack = [] self.active_table = Table('longtable',settings.table_style) # HACK. Should have more sophisticated typearea handling. @@ -663,7 +699,6 @@ class LaTeXTranslator(nodes.NodeVisitor): '\\usepackage{color}\n', '\\usepackage{multirow}\n', '\\usepackage{ifthen}\n', # before hyperref! - self.linking % (self.colorlinks, self.hyperlink_color, self.hyperlink_color), self.typearea, self.generator, # latex lengths @@ -687,17 +722,25 @@ class LaTeXTranslator(nodes.NodeVisitor): if stylesheet: settings.record_dependencies.add(stylesheet) self.head_prefix.append(self.stylesheet % (stylesheet)) - + # hyperref after stylesheet + # TODO conditionally if no hyperref is used dont include + self.head_prefix.append( self.linking % ( + self.colorlinks, self.hyperlink_color, self.hyperlink_color)) + + # + if self.settings.literal_block_env != '': + self.settings.use_verbatim_when_possible = True if self.linking: # and maybe check for pdf self.pdfinfo = [ ] self.pdfauthor = None - # pdftitle, pdfsubject, pdfauthor, pdfkeywords, pdfcreator, pdfproducer + # pdftitle, pdfsubject, pdfauthor, pdfkeywords, + # pdfcreator, pdfproducer else: self.pdfinfo = None # NOTE: Latex wants a date and an author, rst puts this into - # docinfo, so normally we donot want latex author/date handling. + # docinfo, so normally we do not want latex author/date handling. # latex article has its own handling of date and author, deactivate. - # So we always emit \title{...} \author{...} \date{...}, even if the + # self.astext() adds \title{...} \author{...} \date{...}, even if the # "..." are empty strings. self.head = [ ] # separate title, so we can appen subtitle. @@ -788,7 +831,7 @@ class LaTeXTranslator(nodes.NodeVisitor): #"iso-8859-8": "" # hebrew #"iso-8859-10": "" # latin6, more complete iso-8859-4 } - if tr.has_key(docutils_encoding.lower()): + if docutils_encoding.lower() in tr: return tr[docutils_encoding.lower()] # convert: latin-1 and utf-8 and similar things return docutils_encoding.replace("_", "").replace("-", "").lower() @@ -824,7 +867,7 @@ class LaTeXTranslator(nodes.NodeVisitor): return text def ensure_math(self, text): - if not self.__dict__.has_key('ensure_math_re'): + if not 'ensure_math_re' in self.__dict__: chars = { # lnot,pm,twosuperior,threesuperior,mu,onesuperior,times,div 'latin1' : '\xac\xb1\xb2\xb3\xb5\xb9\xd7\xf7' , @@ -848,10 +891,10 @@ class LaTeXTranslator(nodes.NodeVisitor): # compile the regexps once. do it here so one can see them. # # first the braces. - if not self.__dict__.has_key('encode_re_braces'): + if not 'encode_re_braces' in self.__dict__: self.encode_re_braces = re.compile(r'([{}])') text = self.encode_re_braces.sub(r'{\\\1}',text) - if not self.__dict__.has_key('encode_re_bslash'): + if not 'encode_re_bslash' in self.__dict__: # find backslash: except in the form '{\{}' or '{\}}'. self.encode_re_bslash = re.compile(r'(?0: + self.active_table = self.table_stack.pop() + else: + self.active_table.set_table_style(self.settings.table_style) def visit_target(self, node): # BUG: why not (refuri or refid or refname) means not footnote ? - if not (node.has_key('refuri') or node.has_key('refid') - or node.has_key('refname')): + if not ('refuri' in node or 'refid' in node + or 'refname' in node): for id in node['ids']: self.body.append('\\hypertarget{%s}{' % id) self.context.append('}' * len(node['ids'])) @@ -1978,7 +2037,8 @@ class LaTeXTranslator(nodes.NodeVisitor): def depart_term(self, node): # definition list term. - self.body.append('}] ') + # \leavevmode results in a line break if the term is followed by a item list. + self.body.append('}] \leavevmode ') def visit_tgroup(self, node): #self.body.append(self.starttag(node, 'colgroup')) @@ -2038,7 +2098,7 @@ class LaTeXTranslator(nodes.NodeVisitor): (l, text, id)) def visit_title(self, node): - """Only 3 section levels are supported by LaTeX article (AFAIR).""" + """Section and other titles.""" if isinstance(node.parent, nodes.topic): # the table of contents. @@ -2085,7 +2145,8 @@ class LaTeXTranslator(nodes.NodeVisitor): section_name = self.d_class.section(self.section_level) self.body.append('\\%s%s{' % (section_name, section_star)) - + # MAYBE postfix paragraph and subparagraph with \leavemode to + # ensure floatables stay in the section and text starts on a new line. self.context.append('}\n') def depart_title(self, node): diff --git a/docutils/writers/newlatex2e/__init__.py b/docutils/writers/newlatex2e/__init__.py index 08058cb2d..2830fd556 100644 --- a/docutils/writers/newlatex2e/__init__.py +++ b/docutils/writers/newlatex2e/__init__.py @@ -1,5 +1,5 @@ # $Id$ -# Author: Felix Wiemann +# Author: Lea Wiemann # Copyright: This module has been placed in the public domain. """ @@ -676,7 +676,7 @@ class LaTeXTranslator(nodes.SparseNodeVisitor): # Move IDs into TextElements. This won't work for images. # Need to review this. for node in document.traverse(nodes.Element): - if node.has_key('ids') and not isinstance(node, + if 'ids' in node and not isinstance(node, nodes.TextElement): next_text_element = node.next_node(nodes.TextElement) if next_text_element: diff --git a/docutils/writers/newlatex2e/unicode_map.py b/docutils/writers/newlatex2e/unicode_map.py index f5b019dcc..c0d63b6fe 100644 --- a/docutils/writers/newlatex2e/unicode_map.py +++ b/docutils/writers/newlatex2e/unicode_map.py @@ -1,5 +1,5 @@ # $Id$ -# Author: Felix Wiemann +# Author: Lea Wiemann # Copyright: This file has been placed in the public domain. # This is a mapping of Unicode characters to LaTeX equivalents. diff --git a/docutils/writers/s5_html/__init__.py b/docutils/writers/s5_html/__init__.py index 486c03f4a..73a1ec66f 100644 --- a/docutils/writers/s5_html/__init__.py +++ b/docutils/writers/s5_html/__init__.py @@ -251,7 +251,7 @@ class S5HTMLTranslator(html4css1.HTMLTranslator): """ source = os.path.join(source_dir, name) dest = os.path.join(dest_dir, name) - if self.theme_files_copied.has_key(dest): + if dest in self.theme_files_copied: return 1 else: self.theme_files_copied[dest] = 1 -- cgit v1.2.1