comparison pytouhou/options.py @ 567:b2269b9c6119

Add a configuration parser, and pass those options to argparse as defaults. Also include an xdg helper.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Tue, 01 Jul 2014 23:17:40 +0200
parents 5f7f859a72f9
children e7a4731a278b
comparison
equal deleted inserted replaced
566:04ae31809dc7 567:b2269b9c6119
10 ## but WITHOUT ANY WARRANTY; without even the implied warranty of 10 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 ## GNU General Public License for more details. 12 ## GNU General Public License for more details.
13 ## 13 ##
14 14
15 from argparse import ArgumentParser 15 import os
16 from ConfigParser import RawConfigParser, NoOptionError
17
18 from pytouhou.utils.xdg import load_config_paths
19
20
21 class Options(object):
22 def __init__(self, name, defaults):
23 load_paths = list(reversed([os.path.join(directory, '%s.cfg' % name)
24 for directory
25 in load_config_paths(name)]))
26
27 self.config = RawConfigParser(defaults)
28 self.paths = self.config.read(load_paths)
29 self.section = name if self.config.has_section(name) else 'DEFAULT'
30
31 def get(self, option):
32 try:
33 return self.config.get(self.section, option)
34 except NoOptionError:
35 return None
36
37
38 def patch_argument_parser():
39 from argparse import ArgumentParser, _ActionsContainer
40
41 original_method = _ActionsContainer.add_argument
42
43 def add_argument(self, *args, **kwargs):
44 if 'default' not in kwargs:
45 dest = kwargs.get('dest')
46 if dest is None:
47 for dest in args:
48 dest = dest.lstrip('-')
49 value = self.default.get(dest)
50 if value is not None:
51 break
52 else:
53 dest = dest.replace('_', '-')
54 value = self.default.get(dest)
55 if value is not None:
56 argument_type = kwargs.get('type')
57 if argument_type is not None:
58 value = argument_type(value)
59 action = kwargs.get('action')
60 if action == 'store_true':
61 value = value.lower() == 'true'
62 elif action == 'store_false':
63 value = value.lower() != 'true'
64 if kwargs.get('nargs') == '*' and isinstance(value, str):
65 value = value.split()
66 kwargs['default'] = value
67 elif dest == 'double-buffer':
68 kwargs['default'] = None
69 return original_method(self, *args, **kwargs)
70 _ActionsContainer.add_argument = add_argument
71
72 class Parser(ArgumentParser):
73 def __init__(self, *args, **kwargs):
74 self.default = kwargs.pop('default')
75 ArgumentParser.__init__(self, *args, **kwargs)
76
77 def add_argument_group(self, *args, **kwargs):
78 group = ArgumentParser.add_argument_group(self, *args, **kwargs)
79 group.default = self.default
80 group.add_argument_group = self.add_argument_group
81 group.add_mutually_exclusive_group = self.add_mutually_exclusive_group
82 return group
83
84 def add_mutually_exclusive_group(self, *args, **kwargs):
85 group = ArgumentParser.add_mutually_exclusive_group(self, *args, **kwargs)
86 group.default = self.default
87 group.add_argument_group = self.add_argument_group
88 group.add_mutually_exclusive_group = self.add_mutually_exclusive_group
89 return group
90
91 return Parser
92
93
94 ArgumentParser = patch_argument_parser()
95
96
97 def parse_config(section, defaults):
98 return Options(section, defaults)
16 99
17 100
18 def parse_arguments(defaults): 101 def parse_arguments(defaults):
19 parser = ArgumentParser(description='Libre reimplementation of the Touhou 6 engine.') 102 parser = ArgumentParser(description='Libre reimplementation of the Touhou 6 engine.', default=defaults)
20 103
21 parser.add_argument('data', metavar='DAT', default=defaults['data'], nargs='*', help='Game’s data files') 104 parser.add_argument('data', metavar='DAT', nargs='*', help='Game’s data files')
22 parser.add_argument('-p', '--path', metavar='DIRECTORY', default='.', help='Game directory path.') 105 parser.add_argument('-p', '--path', metavar='DIRECTORY', help='Game directory path.')
23 parser.add_argument('--debug', action='store_true', help='Set unlimited continues, and perhaps other debug features.') 106 parser.add_argument('--debug', action='store_true', help='Set unlimited continues, and perhaps other debug features.')
24 parser.add_argument('--verbosity', metavar='VERBOSITY', choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], help='Select the wanted logging level.') 107 parser.add_argument('--verbosity', metavar='VERBOSITY', choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], help='Select the wanted logging level.')
25 108
26 game_group = parser.add_argument_group('Game options') 109 game_group = parser.add_argument_group('Game options')
27 game_group.add_argument('-s', '--stage', metavar='STAGE', type=int, default=None, help='Stage, 1 to 7 (Extra), nothing means story mode.') 110 game_group.add_argument('-s', '--stage', metavar='STAGE', type=int, help='Stage, 1 to 7 (Extra), nothing means story mode.')
28 game_group.add_argument('-r', '--rank', metavar='RANK', type=int, default=0, help='Rank, from 0 (Easy, default) to 3 (Lunatic).') 111 game_group.add_argument('-r', '--rank', metavar='RANK', type=int, help='Rank, from 0 (Easy, default) to 3 (Lunatic).')
29 game_group.add_argument('-c', '--character', metavar='CHARACTER', type=int, default=0, help='Select the character to use, from 0 (ReimuA, default) to 3 (MarisaB).') 112 game_group.add_argument('-c', '--character', metavar='CHARACTER', type=int, help='Select the character to use, from 0 (ReimuA, default) to 3 (MarisaB).')
30 game_group.add_argument('-b', '--boss-rush', action='store_true', help='Fight only bosses.') 113 game_group.add_argument('-b', '--boss-rush', action='store_true', help='Fight only bosses.')
31 game_group.add_argument('--game', metavar='GAME', choices=['EoSD'], default='EoSD', help='Select the game engine to use.') 114 game_group.add_argument('--game', metavar='GAME', choices=['EoSD'], help='Select the game engine to use.')
32 game_group.add_argument('--interface', metavar='INTERFACE', choices=['EoSD', 'Sample'], default='EoSD', help='Select the interface to use.') 115 game_group.add_argument('--interface', metavar='INTERFACE', choices=['EoSD', 'Sample'], help='Select the interface to use.')
33 game_group.add_argument('--hints', metavar='HINTS', default=None, help='Hints file, to display text while playing.') 116 game_group.add_argument('--hints', metavar='HINTS', help='Hints file, to display text while playing.')
34 117
35 replay_group = parser.add_argument_group('Replay options') 118 replay_group = parser.add_argument_group('Replay options')
36 replay_group.add_argument('--replay', metavar='REPLAY', help='Select a file to replay.') 119 replay_group.add_argument('--replay', metavar='REPLAY', help='Select a file to replay.')
37 replay_group.add_argument('--save-replay', metavar='REPLAY', help='Save the upcoming game into a replay file.') 120 replay_group.add_argument('--save-replay', metavar='REPLAY', help='Save the upcoming game into a replay file.')
38 replay_group.add_argument('--skip-replay', action='store_true', help='Skip the replay and start to play when it’s finished.') 121 replay_group.add_argument('--skip-replay', action='store_true', help='Skip the replay and start to play when it’s finished.')
39 122
40 netplay_group = parser.add_argument_group('Netplay options') 123 netplay_group = parser.add_argument_group('Netplay options')
41 netplay_group.add_argument('--port', metavar='PORT', type=int, default=0, help='Local port to use.') 124 netplay_group.add_argument('--port', metavar='PORT', type=int, help='Local port to use.')
42 netplay_group.add_argument('--remote', metavar='REMOTE', default=None, help='Remote address.') 125 netplay_group.add_argument('--remote', metavar='REMOTE', help='Remote address.')
43 netplay_group.add_argument('--friendly-fire', action='store_true', help='Allow friendly-fire during netplay.') 126 netplay_group.add_argument('--friendly-fire', action='store_true', help='Allow friendly-fire during netplay.')
44 127
45 graphics_group = parser.add_argument_group('Graphics options') 128 graphics_group = parser.add_argument_group('Graphics options')
46 graphics_group.add_argument('--backend', metavar='BACKEND', choices=['opengl', 'sdl'], default=['opengl', 'sdl'], nargs='*', help='Which backend to use (opengl or sdl).') 129 graphics_group.add_argument('--backend', metavar='BACKEND', choices=['opengl', 'sdl'], nargs='*', help='Which backend to use (opengl or sdl).')
47 graphics_group.add_argument('--fps-limit', metavar='FPS', default=-1, type=int, help='Set fps limit. A value of 0 disables fps limiting, while a negative value limits to 60 fps if and only if vsync doesn’t work.') 130 graphics_group.add_argument('--fps-limit', metavar='FPS', type=int, help='Set fps limit. A value of 0 disables fps limiting, while a negative value limits to 60 fps if and only if vsync doesn’t work.')
48 graphics_group.add_argument('--no-background', action='store_false', help='Disable background display (huge performance boost on slow systems).') 131 graphics_group.add_argument('--no-background', action='store_false', help='Disable background display (huge performance boost on slow systems).')
49 graphics_group.add_argument('--no-particles', action='store_false', help='Disable particles handling (huge performance boost on slow systems).') 132 graphics_group.add_argument('--no-particles', action='store_false', help='Disable particles handling (huge performance boost on slow systems).')
50 graphics_group.add_argument('--no-sound', action='store_false', help='Disable music and sound effects.') 133 graphics_group.add_argument('--no-sound', action='store_false', help='Disable music and sound effects.')
51 134
52 opengl_group = parser.add_argument_group('OpenGL backend options') 135 opengl_group = parser.add_argument_group('OpenGL backend options')
53 opengl_group.add_argument('--gl-flavor', choices=['core', 'es', 'compatibility', 'legacy'], default='compatibility', help='OpenGL profile to use.') 136 opengl_group.add_argument('--gl-flavor', choices=['core', 'es', 'compatibility', 'legacy'], help='OpenGL profile to use.')
54 opengl_group.add_argument('--gl-version', default=2.1, type=float, help='OpenGL version to use.') 137 opengl_group.add_argument('--gl-version', type=float, help='OpenGL version to use.')
55 138
56 double_buffer = opengl_group.add_mutually_exclusive_group() 139 double_buffer = opengl_group.add_mutually_exclusive_group()
57 double_buffer.add_argument('--double-buffer', dest='double_buffer', action='store_true', default=None, help='Enable double buffering.') 140 double_buffer.add_argument('--double-buffer', dest='double_buffer', action='store_true', help='Enable double buffering.')
58 double_buffer.add_argument('--single-buffer', dest='double_buffer', action='store_false', default=None, help='Disable double buffering.') 141 double_buffer.add_argument('--single-buffer', dest='double_buffer', action='store_false', help='Disable double buffering.')
59 142
60 return parser.parse_args() 143 return parser.parse_args()