forked from vterron/lemon
-
Notifications
You must be signed in to change notification settings - Fork 0
/
customparser.py
160 lines (128 loc) · 6.57 KB
/
customparser.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#! /usr/bin/env python
# Copyright (c) 2013 Victor Terron. All rights reserved.
# Institute of Astrophysics of Andalusia, IAA-CSIC
#
# This file is part of LEMON.
#
# LEMON is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import copy
import optparse
import re
import textwrap
# LEMON modules
import passband
class NewlinesFormatter(optparse.IndentedHelpFormatter):
""" This quick-and-dirty trick prevents optparse from stripping newlines
(using textwrap) when the description of the module is printed. This should
be acceptable enough until the transition to argparse is made. """
def _format_text(self, text):
text_width = self.width - self.current_indent
indent = ' ' * self.current_indent
# Wrap one paragraph at a time, then concatenate them
formatted_text = ""
for paragraph in text.split('\n\n'):
formatted_text += textwrap.fill(paragraph.strip(),
text_width,
initial_indent=indent,
subsequent_indent=indent)
formatted_text += '\n\n'
return formatted_text.rstrip()
def check_passband(option, opt, value):
""" Type-checking function for the 'passband' optparse option type.
This is the type-checking function for 'passband', a custom optparse type
that accepts a string with the name of a photometric filter and returns
it as a passband.Passband object. 'option' is an optpase.Option instance,
'opt' is the option string (e.g., -f), and 'value' is the string from the
command line that must be checked and converted to a Passband object.
In case of doubt, please refer to:
http://docs.python.org/2.7/library/optparse.html#adding-new-types
"""
try:
return passband.Passband(value)
except ValueError, e:
msg = "option %s: invalid photometric filter: %r (%s)"
raise optparse.OptionValueError(msg % (opt, value, e))
class PassbandOption(optparse.Option):
""" Custom optparse option type encapsulating a photometric filter.
This subclass of optparse's Option class implements 'passband', a custom
option type: it receives a string with the name of a photometric filter,
such as 'Johnson V', and returns it as a passband.Passband object. This
option supports all the photometric systems allowed by the Passband class.
"""
# A tuple of type names
TYPES = optparse.Option.TYPES + ('passband',)
# A dictionary mapping type names to type-checking functions
TYPE_CHECKER = copy.copy(optparse.Option.TYPE_CHECKER)
TYPE_CHECKER['passband'] = check_passband
def get_parser(description):
""" Return the OptionParser object used in the LEMON modules.
This function instantiates an optparse.OptionParser object and returns it.
Its 'description' argument (a paragraph of text giving a brief overview of
the program) is set to the value of the argument of the same name, while
the NewlinesFormatter class is used for printing help text ('formatter'
argument). This parser adds a custom option type, 'passband', which
receives a string with the name of a photometric filter and converts it to
a passband.Passband object. Neither the default -h nor --help options are
included.
"""
kwargs = dict(description = description,
add_help_option = False,
formatter = NewlinesFormatter(),
option_class = PassbandOption)
parser = optparse.OptionParser(**kwargs)
return parser
def clear_metavars(parser):
""" Set all the meta-variables of an OptionParser to a whitespace.
This is a hackish convenience function to set the meta-variables of all the
options of an OptionParser, independently of whether they are contained in
option groups, to the string ' '. This is not an empty string, but a string
consisting of a whitespace: this is necessary because if the meta-variable
evaluates to False the OptionParser converts the destination variable name
to uppercase and uses that instead.
Using this function on an OptionParser instance clears the meta-variables,
which means that where the help message showed '--filename=FILE' now only
'--filename=' will be displayed, with the equals sign indicating the fact
that the option takes a value.
"""
EMPTY_VALUE = ' '
for option in parser.option_list:
option.metavar = EMPTY_VALUE
for group in parser.__dict__['option_groups']:
for option in group.option_list:
option.metavar = EMPTY_VALUE
def additional_options_callback(option, opt_str, value, parser):
""" opt-parse callback function to parse option strings.
Use this function to parse a string containing an option with, if any, the
argument that it takes. For example, given the string '--downsample = 2',
'--downsample' would be recognized as the name of the option, and '2' as
the corresponding argument. The name of the option is mapped to the value
in option.dest, which is expected to be a dictionary. If the option does
not take any argument (for example, '-v' or '--verbose'), it is mapped to
None. Raises ValueError if the string can not be successfully parsed.
option - the Option instance that is calling the callback.
opt_str - the option string seen on the command-line.
value - the argument to this option seen on the command-line.
parser - the OptionParser instance driving the whole thing.
"""
regexp = "=?(?P<option>-+[\w-]+)\s*=?\s*(?P<value>\w+)?"
match = re.match(regexp, value)
if not match:
msg = ("cannot parse additional option. Are you using the GNU/POSIX "
"syntax? Note that options should always start with one or "
"two hyphens. Examples of valid syntax are '-o', '-o value', "
"'--name' and '--name=value', among many others.")
raise ValueError(msg)
opt_ = match.group('option')
value = match.group('value')
getattr(parser.values, option.dest)[opt_] = value