Mercurial > touhou
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() |