| Conditions | 25 |
| Total Lines | 139 |
| Lines | 0 |
| Ratio | 0 % |
| Changes | 1 | ||
| Bugs | 1 | Features | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like main() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | """Entry point and related functionality""" |
||
| 138 | def main(): |
||
| 139 | """setuptools entry point""" |
||
| 140 | from optparse import OptionParser, OptionGroup |
||
| 141 | parser = OptionParser(usage="%prog [options] [action] ...", |
||
| 142 | version="%%prog v%s" % __version__) |
||
| 143 | parser.add_option('-d', '--daemonize', action="store_true", |
||
| 144 | dest="daemonize", default=False, help="Attempt to set up global " |
||
| 145 | "keybindings using python-xlib and a D-Bus service using dbus-python. " |
||
| 146 | "Exit if neither succeeds") |
||
| 147 | parser.add_option('-b', '--bindkeys', action="store_true", |
||
| 148 | dest="daemonize", default=False, |
||
| 149 | help="Deprecated alias for --daemonize") |
||
| 150 | parser.add_option('--debug', action="store_true", dest="debug", |
||
| 151 | default=False, help="Display debug messages") |
||
| 152 | parser.add_option('--no-workarea', action="store_true", dest="no_workarea", |
||
| 153 | default=False, help="Overlap panels but work better with " |
||
| 154 | "non-rectangular desktops") |
||
| 155 | |||
| 156 | help_group = OptionGroup(parser, "Additional Help") |
||
| 157 | help_group.add_option('--show-bindings', action="store_true", |
||
| 158 | dest="show_binds", default=False, help="List all configured keybinds") |
||
| 159 | help_group.add_option('--show-actions', action="store_true", |
||
| 160 | dest="show_args", default=False, help="List valid arguments for use " |
||
| 161 | "without --daemonize") |
||
| 162 | parser.add_option_group(help_group) |
||
| 163 | |||
| 164 | opts, args = parser.parse_args() |
||
| 165 | |||
| 166 | # Hook up grep to filter out spurious libwnck error messages that we |
||
| 167 | # can't filter properly because PyGTK doesn't expose g_log_set_handler() |
||
| 168 | if not opts.debug: |
||
| 169 | glib_log_filter = subprocess.Popen( |
||
| 170 | ['grep', '-v', 'Unhandled action type _OB_WM'], |
||
| 171 | stdin=subprocess.PIPE) |
||
| 172 | |||
| 173 | # Redirect stderr through grep |
||
| 174 | os.dup2(glib_log_filter.stdin.fileno(), sys.stderr.fileno()) |
||
| 175 | |||
| 176 | # Set up the output verbosity |
||
| 177 | logging.basicConfig(level=logging.DEBUG if opts.debug else logging.INFO, |
||
| 178 | format='%(levelname)s: %(message)s') |
||
| 179 | |||
| 180 | # Load the config from file if present |
||
| 181 | # TODO: Refactor all this |
||
| 182 | cfg_path = os.path.join(XDG_CONFIG_DIR, 'quicktile.cfg') |
||
| 183 | first_run = not os.path.exists(cfg_path) |
||
| 184 | |||
| 185 | config = RawConfigParser() |
||
| 186 | config.optionxform = str # Make keys case-sensitive |
||
| 187 | # TODO: Maybe switch to two config files so I can have only the keys in the |
||
| 188 | # keymap case-sensitive? |
||
| 189 | config.read(cfg_path) |
||
| 190 | dirty = False |
||
| 191 | |||
| 192 | if not config.has_section('general'): |
||
| 193 | config.add_section('general') |
||
| 194 | # Change this if you make backwards-incompatible changes to the |
||
| 195 | # section and key naming in the config file. |
||
| 196 | config.set('general', 'cfg_schema', 1) |
||
| 197 | dirty = True |
||
| 198 | |||
| 199 | for key, val in DEFAULTS['general'].items(): |
||
| 200 | if not config.has_option('general', key): |
||
| 201 | config.set('general', key, str(val)) |
||
| 202 | dirty = True |
||
| 203 | |||
| 204 | mk_raw = modkeys = config.get('general', 'ModMask') |
||
| 205 | if ' ' in modkeys.strip() and '<' not in modkeys: |
||
| 206 | modkeys = '<%s>' % '><'.join(modkeys.strip().split()) |
||
| 207 | logging.info("Updating modkeys format:\n %r --> %r", mk_raw, modkeys) |
||
| 208 | config.set('general', 'ModMask', modkeys) |
||
| 209 | dirty = True |
||
| 210 | |||
| 211 | # Either load the keybindings or use and save the defaults |
||
| 212 | if config.has_section('keys'): |
||
| 213 | keymap = dict(config.items('keys')) |
||
| 214 | else: |
||
| 215 | keymap = DEFAULTS['keys'] |
||
| 216 | config.add_section('keys') |
||
| 217 | for row in keymap.items(): |
||
| 218 | config.set('keys', row[0], row[1]) |
||
| 219 | dirty = True |
||
| 220 | |||
| 221 | # Migrate from the deprecated syntax for punctuation keysyms |
||
| 222 | for key in keymap: |
||
| 223 | # Look up unrecognized shortkeys in a hardcoded dict and |
||
| 224 | # replace with valid names like ',' -> 'comma' |
||
| 225 | transKey = key |
||
| 226 | if key in KEYLOOKUP: |
||
| 227 | logging.warn("Updating config file from deprecated keybind syntax:" |
||
| 228 | "\n\t%r --> %r", key, KEYLOOKUP[key]) |
||
| 229 | transKey = KEYLOOKUP[key] |
||
| 230 | dirty = True |
||
| 231 | |||
| 232 | if dirty: |
||
| 233 | cfg_file = file(cfg_path, 'wb') |
||
| 234 | config.write(cfg_file) |
||
| 235 | cfg_file.close() |
||
| 236 | if first_run: |
||
| 237 | logging.info("Wrote default config file to %s", cfg_path) |
||
| 238 | |||
| 239 | ignore_workarea = ((not config.getboolean('general', 'UseWorkarea')) or |
||
| 240 | opts.no_workarea) |
||
| 241 | |||
| 242 | # TODO: Rearchitect so this hack isn't needed |
||
| 243 | commands.cycle_dimensions = commands.commands.add_many( |
||
| 244 | layout.make_winsplit_positions(config.getint('general', 'ColumnCount')) |
||
| 245 | )(commands.cycle_dimensions) |
||
| 246 | |||
| 247 | try: |
||
| 248 | winman = WindowManager(ignore_workarea=ignore_workarea) |
||
| 249 | except XInitError as err: |
||
| 250 | logging.critical(err) |
||
| 251 | sys.exit(1) |
||
| 252 | app = QuickTileApp(winman, commands.commands, keymap, modmask=modkeys) |
||
| 253 | |||
| 254 | if opts.show_binds: |
||
| 255 | app.show_binds() |
||
| 256 | if opts.show_args: |
||
| 257 | print commands.commands |
||
| 258 | |||
| 259 | if opts.daemonize: |
||
| 260 | if not app.run(): |
||
| 261 | logging.critical("Neither the Xlib nor the D-Bus backends were " |
||
| 262 | "available") |
||
| 263 | sys.exit(errno.ENOENT) |
||
| 264 | # FIXME: What's the proper exit code for "library not found"? |
||
| 265 | elif not first_run: |
||
| 266 | if args: |
||
| 267 | winman.screen.force_update() |
||
| 268 | |||
| 269 | for arg in args: |
||
| 270 | commands.commands.call(arg, winman) |
||
| 271 | while gtk.events_pending(): # pylint: disable=no-member |
||
| 272 | gtk.main_iteration() # pylint: disable=no-member |
||
| 273 | elif not opts.show_args and not opts.show_binds: |
||
| 274 | print commands.commands |
||
| 275 | print "\nUse --help for a list of valid options." |
||
| 276 | sys.exit(errno.ENOENT) |
||
| 277 | |||
| 282 |