Migrated to python-3.4, removed over.core.types.enum as it is now provided by Python's enum.Enum. Minor fixes.

This commit is contained in:
Overwatch 2014-08-17 00:31:44 +02:00
parent fd984be2f6
commit 5e655c8e06
7 changed files with 49 additions and 104 deletions

View file

@ -10,4 +10,3 @@ from . import aux
#from . import m #from . import m
#from . import serial #from . import serial
_version = 2.999

View file

@ -2,6 +2,13 @@
# encoding: utf-8 # encoding: utf-8
import sys import sys
import re
from . import file
from . import textui
from ..version import _revision
prefix = textui.prefix
# FIXME This very seriously needs to be heavily simplified and de-duplicated # FIXME This very seriously needs to be heavily simplified and de-duplicated
# TODO same parser for cmdline and Config # TODO same parser for cmdline and Config
@ -14,7 +21,7 @@ def _parse(data, dtype):
if data.startswith("\"") and data.endswith("\""): if data.startswith("\"") and data.endswith("\""):
value = data[1:-1].replace("\\\"", "\"") value = data[1:-1].replace("\\\"", "\"")
else: else:
raise GeneralError raise RuntimeError
elif dtype == "bool": elif dtype == "bool":
if data == "True": if data == "True":
@ -22,34 +29,34 @@ def _parse(data, dtype):
elif data == "False": elif data == "False":
value = False value = False
else: else:
raise GeneralError raise RuntimeError
elif dtype == "int": elif dtype == "int":
try: try:
value = int(data) value = int(data)
except ValueError: except ValueError:
raise GeneralError raise RuntimeError
elif dtype == "float": elif dtype == "float":
try: try:
value = float(data) value = float(data)
except ValueError: except ValueError:
raise GeneralError raise RuntimeError
return value return value
_over_help_texts = [ _over_help_texts = [
("OverCore: what, how and huh?", ["OverCore is a Python 3 module that provides basic functionality for programs. Functionality such as configuration, commandline parsing, text handling and output, file handling, a non-interactive help system and (not all that much) more."]), ("over.core: what, how and huh?", ["over.core is a Python 3 module that provides basic functionality for programs. Functionality such as configuration, commandline parsing, text handling and output, file handling, a non-interactive help system and (not all that much) more."]),
("Data Types", ["OverCore currently supports 4 data types.", "A §bbool§/ is either exactly §mTrue§/ or exactly §mFalse§/. Bool options that are §mTrue§/ look like this: §B--§goption§/. The same name only §mFalse§/ would be §B--no-§goption§/. Makes sense, doesn't it? Their short versions are either §B+§go§/ for §mTrue§/ or §B-§go§/ for §mFalse§/.", "A §bstr§/ing is just any raw text. Remember to enclose it in quotes if it has spaces or other nasty characters in it.", "An §bint§/eger is a whole number. Negative, zero, positive.", "Finally, a §bfloat§/ is any real number."]), ("Data Types", ["over.core currently supports 4 data types.", "A §bbool§/ is either exactly §mTrue§/ or exactly §mFalse§/. Bool options that are §mTrue§/ look like this: §B--§goption§/. The same name only §mFalse§/ would be §B--no-§goption§/. Makes sense, doesn't it? Their short versions are either §B+§go§/ for §mTrue§/ or §B-§go§/ for §mFalse§/.", "A §bstr§/ing is just any raw text. Remember to enclose it in quotes if it has spaces or other nasty characters in it.", "An §bint§/eger is a whole number. Negative, zero, positive.", "Finally, a §bfloat§/ is any real number."]),
("The Commandline Parser", ["This, in conjunction with the configuration system, is the strongest part of OverCore and the very reason for its continued existence.", "Each configurable option can be assigned to on the command line. Take an option named §Bres-file§/ as an example. To assign to it, you can use §B--§gres-file§/ §msomething§/ (it's case sensitive). That's it, now its value is §msomething§/! Pretty easy, right?", "Now, you're probably thinking: \"I'm not typing that all over again, Martin!\" Well, you don't have to! Options can have their short names. It's a single letter (again, case sensitive) with a plus or minus sign in front of it. So §B--§gres-file§/ §msomething§/ becomes §B+§gf§/ §msomething§/. That's much better, ain't it? And there's more. Short names can be grouped together. If you have a bunch of bool switches, like §B--§garmed§/ (short: §B+§gA§/), §B--no-§gsound§/ (short: §B-§gS§/), §B--no-§gstore§/ (short: §B-§gs§/) and §B--§gforce§/ (short: §B+§gF§/), you can group their shorts into groups with the same boolean value: §B-§gSs§/ §B+§gAF§/. You can even have a non-bool option in a group, it just has to be on the very right (because it needs to be followed by data): §B-§gSs§/ §B+§gAFf§/ §msomething§/. It doesn't matter if that group begins with §B+§/ or §B-§/.", "If you use an option more than once, its last (rightmost) occurence applies. For example, after §B+§gf§/ §msomething§/ §B+§gf§/ §mor_other§/ is parsed, option §Bres-file§/ holds the value §mor_other§/. It goes the same for bools: after §B+§gA§/ §B--no-§garmed§/ §B+§gA§/, §Barmed§/ is §mTrue§/. However, if an option is §cplural§/, all occurences are used. Sequence §B+§gA§/ §B-§gA§/ §B+§gA§/ would be [§mTrue§/, §mFalse§/, §mTrue§/], and §B--§gnum§/ §m1§/ §B--§gnum§/ §m2§/ would end up looking like [§m1§/, §m2§/]. You don't need to type §B--§gnum§/ for every field either: §B--§gnum§/ §m1§/ §m2§/ would work exactly the same. That's because the parser keeps reading everything after a plural option (that takes data, i.e. not bools) right until it encounters two dashes, like those of a following option. You can use just the two dashes to stop the parsing manually, usually when you don't want to follow with a long option. Example: §B--§gnum§/ §m1§/ §m5§/ §m9§/ §B--§/. I repeat: a plural (non-bool) option needs to be terminated by two dashes. This wouldn't work: §B--§gnum§/ §m1§/ §m5§/ §m9§/ §B+§gf§/ §mthat_one§/, everything after §B--§gnum§/ would be consumed as its data, §Bincluding +§gf§/ §mthat_one§/."]), ("The Commandline Parser", ["This, in conjunction with the configuration system, is the strongest part of over.core and the very reason for its continued existence.", "Each configurable option can be assigned to on the command line. Take an option named §Bres-file§/ as an example. To assign to it, you can use §B--§gres-file§/ §msomething§/ (it's case sensitive). That's it, now its value is §msomething§/! Pretty easy, right?", "Now, you're probably thinking: \"I'm not typing that all over again, Martin!\" Well, you don't have to! Options can have their short names. It's a single letter (again, case sensitive) with a plus or minus sign in front of it. So §B--§gres-file§/ §msomething§/ becomes §B+§gf§/ §msomething§/. That's much better, ain't it? And there's more. Short names can be grouped together. If you have a bunch of bool switches, like §B--§garmed§/ (short: §B+§gA§/), §B--no-§gsound§/ (short: §B-§gS§/), §B--no-§gstore§/ (short: §B-§gs§/) and §B--§gforce§/ (short: §B+§gF§/), you can group their shorts into groups with the same boolean value: §B-§gSs§/ §B+§gAF§/. You can even have a non-bool option in a group, it just has to be on the very right (because it needs to be followed by data): §B-§gSs§/ §B+§gAFf§/ §msomething§/. It doesn't matter if that group begins with §B+§/ or §B-§/.", "If you use an option more than once, its last (rightmost) occurence applies. For example, after §B+§gf§/ §msomething§/ §B+§gf§/ §mor_other§/ is parsed, option §Bres-file§/ holds the value §mor_other§/. It goes the same for bools: after §B+§gA§/ §B--no-§garmed§/ §B+§gA§/, §Barmed§/ is §mTrue§/. However, if an option is §cplural§/, all occurences are used. Sequence §B+§gA§/ §B-§gA§/ §B+§gA§/ would be [§mTrue§/, §mFalse§/, §mTrue§/], and §B--§gnum§/ §m1§/ §B--§gnum§/ §m2§/ would end up looking like [§m1§/, §m2§/]. You don't need to type §B--§gnum§/ for every field either: §B--§gnum§/ §m1§/ §m2§/ would work exactly the same. That's because the parser keeps reading everything after a plural option (that takes data, i.e. not bools) right until it encounters two dashes, like those of a following option. You can use just the two dashes to stop the parsing manually, usually when you don't want to follow with a long option. Example: §B--§gnum§/ §m1§/ §m5§/ §m9§/ §B--§/. I repeat: a plural (non-bool) option needs to be terminated by two dashes. This wouldn't work: §B--§gnum§/ §m1§/ §m5§/ §m9§/ §B+§gf§/ §mthat_one§/, everything after §B--§gnum§/ would be consumed as its data, §Bincluding +§gf§/ §mthat_one§/."]),
("The Config File", ["If enabled in the program code, a config file will be generated when you first run it. By default, everything in the config file will be filled with default values and commented out. The general syntax as well as individual options are explained inside. If you run a newer version of the program that offers more configurable options, the config file will be automatically updated. If you'd like to modify an option in the config file, first uncomment it and then change its value. Resolving order for option values is 1) default (hardcoded), 2) config file and 3) commandline arguments."]), ("The Config File", ["If enabled in the program code, a config file will be generated when you first run it. By default, everything in the config file will be filled with default values and commented out. The general syntax as well as individual options are explained inside. If you run a newer version of the program that offers more configurable options, the config file will be automatically updated. If you'd like to modify an option in the config file, first uncomment it and then change its value. Resolving order for option values is 1) default (hardcoded), 2) config file and 3) commandline arguments."]),
("Other", ["When enabled in the program, an OverCore program offers two options: §B--§ghelp§/ and §B--§gover-help§/. The first describes the program and its options, including their types, current values and whether is their current value coming from defaults, config files or the command line. The second option displays the help you're reading right now. You may now guess which rank I hold in the Obvious Corps.", "As the brighter amongst you might have noticed, OverCore likes colors. A lot. Generally, I use blue for §bdata types§/, magenta for §mvalues§/, white and green for §B--§goptions§/ and reserve red and yellow for when §rshit hits§/ §ythe fan§/, where red letters usually tell you §Bwhy§/ and yellow ones tell you §Bwhat§/.", "And it's not just colors! I like money, too. Push donations to §B1sekErApM4zh35RFW7qGWs5Yeo9EYWjyV§/, or catch me somewhere and force me to accept cash."]) ("Other", ["When enabled in the program, an over.core program offers two options: §B--§ghelp§/ and §B--§gover-help§/. The first describes the program and its options, including their types, current values and whether is their current value coming from defaults, config files or the command line. The second option displays the help you're reading right now. You may now guess which rank I hold in the Obvious Corps.", "As the brighter amongst you might have noticed, over.core likes colors. A lot. Generally, I use blue for §bdata types§/, magenta for §mvalues§/, white and green for §B--§goptions§/ and reserve red and yellow for when §rshit hits§/ §ythe fan§/, where red letters usually tell you §Bwhy§/ and yellow ones tell you §Bwhat§/.", "And it's not just colors! I like money, too. Push donations to §B1sekErApM4zh35RFW7qGWs5Yeo9EYWjyV§/, or catch me somewhere and force me to accept cash."])
] ]
# -------------------------------------------------- # --------------------------------------------------
def _output(text, indent=0, newlines=1): def _output(text, indent=0, newlines=1):
sys.stdout.write(render(paragraph(text, indent=indent), True)) sys.stdout.write(textui.render(textui.paragraph(text, indent=indent), True))
sys.stdout.write(newlines * "\n") sys.stdout.write(newlines * "\n")
sys.stdout.flush() sys.stdout.flush()
@ -66,9 +73,9 @@ def _print_help(main, help_texts, chapter=None, list_options=False):
# dirty as fuck :-) # dirty as fuck :-)
if not chapter and not main.version is None: if not chapter and not main.version is None:
if help_texts == _over_help_texts: if help_texts == _over_help_texts:
_output(">>> §yOverCore§/ version §y%s§/, licensed under §yAO-JSL§/" %(_version), newlines=2) _output(">>> §yover.core§/ version §y%d§/ (%s), licensed under the §yAO-JSL§/" %_revision, newlines=2)
else: else:
_output("§y%s§/ version §y%s§/, licensed under §y%s§/" %(main.name, main.version, main.license), newlines=2) _output("§y%s§/ version §y%s§/, licensed under the §y%s§/" %(main.name, main.version, main.license), newlines=2)
# general help texts # general help texts
for help_text in help_texts: for help_text in help_texts:
@ -186,9 +193,11 @@ class CfgAccessor:
if len(matches) == 1: if len(matches) == 1:
return matches[0].value return matches[0].value
else: else:
self.main._print("game over, lights out! OverCore internal buggaroo", prefix.fail, exc=GeneralError) self.main._print("game over, lights out! over.core internal buggaroo", prefix.fail)
raise RuntimeError
else: else:
self.main._print("option §r%s§/ doesn't exist" %(opt_name), prefix.fail, exc=GeneralError) self.main._print("option §r%s§/ doesn't exist" %(opt_name), prefix.fail)
raise RuntimeError
# -------------------------------------------------- # --------------------------------------------------
@ -220,14 +229,14 @@ class Main:
self.cmdline = cmdline self.cmdline = cmdline
self.help_texts = [] # (chapter, [paragraphs]) self.help_texts = [] # (chapter, [paragraphs])
self.allow_exit = allow_exit self.allow_exit = allow_exit
self._print = Output("over.Main", default_suffix=".\n", timestamp=True) self._print = textui.Output("over.core.app.Main")
if cfg_file: if cfg_file:
self.cfg_file = File(cfg_file) self.cfg_file = file.File(cfg_file, encoding="utf-8")
if not self.cfg_file.data: if not self.cfg_file.data:
self.cfg_file.data = """# Et configuration file for %s self.cfg_file.data = """# Et configuration file for %s
# Licensed under %s # Licensed under the %s
# #
# Syntax # Syntax
# There are 4 data types: bool, int, float and str (string). # There are 4 data types: bool, int, float and str (string).
@ -515,7 +524,8 @@ class Main:
self.targets = [u for u in unparsed if u != "--"] self.targets = [u for u in unparsed if u != "--"]
if self.unknowns: if self.unknowns:
self._print("unknown options on the command line: §r%s§/" %("§/, §r".join(self.unknowns)), prefix.fail, exc=GeneralError) self._print("unknown options on the command line: §r%s§/" %("§/, §r".join(self.unknowns)), prefix.fail)
raise RuntimeError
# parse the config file # parse the config file
if self.cfg_file: if self.cfg_file:
@ -544,19 +554,21 @@ class Main:
for element in elements: for element in elements:
try: try:
opt.value.append(_parse(element, opt.dtype)) opt.value.append(_parse(element, opt.dtype))
except GeneralError: except RuntimeError:
self._print("config file syntax error for option §B--§r%s§/" %(opt.name), prefix.fail, exc=GeneralError) self._print("config file syntax error for option §B--§r%s§/" %(opt.name), prefix.fail)
raise
else: else:
try: try:
opt.value = _parse(d, opt.dtype) opt.value = _parse(d, opt.dtype)
except GeneralError: except RuntimeError:
self._print("config file syntax error for option §B--§r%s§/" %(opt.name), prefix.fail, exc=GeneralError) self._print("config file syntax error for option §B--§r%s§/" %(opt.name), prefix.fail)
raise
else: else:
self._print("updating config file with option §B--§y%s§/" %(opt.name)) self._print("updating config file with option §B--§y%s§/" %(opt.name))
new_lines.append("") new_lines.append("")
new_lines.append(paragraph(render(opt.description, colors=False), prefix="#", width=80)) new_lines.append(textui.paragraph(textui.render(opt.description, colors=False), prefix="#", width=80))
new_lines.append("# *** data type: %s" %(opt.dtype)) new_lines.append("# *** data type: %s" %(opt.dtype))
if opt.plural: if opt.plural:
@ -616,8 +628,8 @@ class Main:
""" """
self.add_option("help", "bool", False, "Display this help message.", callback=self.help, short_name=short_name, use_cfg_file=False) self.add_option("help", "bool", False, "Display this help message.", callback=self.help, short_name=short_name, use_cfg_file=False)
self.add_option("over-help", "bool", False, "Display general usage information for OverCore.", callback=self.help_over, use_cfg_file=False) self.add_option("over-help", "bool", False, "Display general usage information for over.core.", callback=self.help_over, use_cfg_file=False)
self.add_option("help-over", "bool", False, "Display general usage information for OverCore.", callback=self.help_over, use_cfg_file=False, hidden=True) self.add_option("help-over", "bool", False, "Display general usage information for over.core.", callback=self.help_over, use_cfg_file=False, hidden=True)
def add_help(self, chapter, paragraphs): def add_help(self, chapter, paragraphs):
self.help_texts.append((chapter, paragraphs)) self.help_texts.append((chapter, paragraphs))

View file

@ -15,8 +15,8 @@ echo "- translating from Python to C"
cython -3 cython_types.pyx -o cython_types.c || die "translating" cython -3 cython_types.pyx -o cython_types.c || die "translating"
echo "- compiling and linking" echo "- compiling and linking"
gcc $CFLAGS -I/usr/include/python3.3 -pthread -c cython_types.c || die "compilation" gcc $CFLAGS -I/usr/include/python3.4 -pthread -c cython_types.c || die "compilation"
gcc $LFLAGS -L/usr/lib -lpython3.3 cython_types.o -o cython_types.so || die "linking" gcc $LFLAGS -L/usr/lib -lpython3.4 cython_types.o -o cython_types.so || die "linking"
rm -f cython_types.{c,o} rm -f cython_types.{c,o}
echo "- done" echo "- done"

View file

@ -109,40 +109,3 @@ cdef class map:
pairs.append("%s: %s" %(repr(self.keys[i]), repr(self.vals[i]))) pairs.append("%s: %s" %(repr(self.keys[i]), repr(self.vals[i])))
return "<{%s}>" %(", ".join(pairs)) return "<{%s}>" %(", ".join(pairs))
# --------------------------------------------------
cdef class enum:
"""
Emulates a C++-like enum type.
Based on a py2 enum function by Alec Thomas and acjohnson55.
"""
def __init__(self, str name, words, int start=0):
"""
Initializes the enum.
name is used for __repr__ only
words is a sequence of enum keys
start is the numerical value of the first key
"""
self.typename = name
self.reverse_enums = dict(enumerate(words, start))
self.enums = dict((value, key) for key, value in self.reverse_enums.items())
def name(self, int value):
if value in self.reverse_enums:
return self.reverse_enums[value]
else:
raise AttributeError("no %s has a value of %s" %(self, value))
def __getattr__(self, aname):
if aname in self.enums:
return self.enums[aname]
else:
raise AttributeError("%s not in %s" %(aname, self))
def __repr__(self):
return "<enum %s>" %(self.typename)

View file

@ -109,43 +109,3 @@ class map:
pairs.append("%s: %s" %(repr(self.keys[i]), repr(self.vals[i]))) pairs.append("%s: %s" %(repr(self.keys[i]), repr(self.vals[i])))
return "<{%s}>" %(", ".join(pairs)) return "<{%s}>" %(", ".join(pairs))
# --------------------------------------------------
class enum:
"""
Emulates a C++-like enum type.
Based on a py2 enum function by Alec Thomas and acjohnson55.
"""
def __init__(self, name, words, start=0):
"""
Initializes the enum.
name is used for __repr__ only
words is a sequence of enum keys
start is the numerical value of the first key
"""
self.typename = name
self.reverse_enums = dict(enumerate(words, start))
self.enums = dict((value, key) for key, value in self.reverse_enums.items())
def name(self, value):
if value in self.reverse_enums:
return self.reverse_enums[value]
else:
raise AttributeError("no %s has a value of %s" %(self, value))
def __getattr__(self, aname):
if aname in self.enums:
return self.enums[aname]
else:
raise AttributeError("%s not in %s" %(aname, self))
def __repr__(self):
return "<enum %s>" %(self.typename)
# --------------------------------------------------

View file

@ -4,6 +4,9 @@
import math import math
import re import re
import sys import sys
import struct
import fcntl
import termios
import time import time
# -------------------------------------------------- # --------------------------------------------------
@ -76,6 +79,10 @@ class ProgressBar:
self.value = value self.value = value
self.draw() self.draw()
def blank(self):
sys.stderr.write("\r" + self.old_len * " " + "\r")
sys.stderr.flush()
# -------------------------------------------------- # --------------------------------------------------

4
version.py Normal file
View file

@ -0,0 +1,4 @@
#! /bin/env python3
# encoding: utf-8
_revision = (0, '00000000') # GIT_REVISION_IDENTIFIER