Skip to content

Commit

Permalink
Various minor improvements and refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
davidfoerster committed Oct 27, 2019
1 parent 12a07b5 commit 3270889
Show file tree
Hide file tree
Showing 10 changed files with 70 additions and 52 deletions.
6 changes: 3 additions & 3 deletions po/de/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -262,9 +262,9 @@ msgstr "Benutzen Sie „{help_opt:s}“ um die Programmhilfe anzuzeigen."
msgid "Overlapping source entries:"
msgstr "Überlappende Quelleneinträge:"

#: src/aptsources_cleanup/__main__.py:280
msgid "{ordinal:2d}. file '{file:s}':"
msgstr "{ordinal:2d}. Datei {file:s}“:"
#: src/aptsources_cleanup/__main__.py:284
msgid "{ordinal:2d}. file {file!r}:"
msgstr "{ordinal:2d}. Datei {file!r}:"

#: src/aptsources_cleanup/__main__.py:283
msgid "I disabled the latter entry."
Expand Down
6 changes: 3 additions & 3 deletions po/en/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -260,9 +260,9 @@ msgstr "Use “{help_opt:s}” to display the program help."
msgid "Overlapping source entries:"
msgstr "Overlapping source entries:"

#: src/aptsources_cleanup/__main__.py:279
msgid "{ordinal:2d}. file '{file:s}':"
msgstr "{ordinal:2d}. file {file:s}”:"
#: src/aptsources_cleanup/__main__.py:284
msgid "{ordinal:2d}. file {file!r}:"
msgstr "{ordinal:2d}. file {file!r}:"

#: src/aptsources_cleanup/__main__.py:282
msgid "I disabled the latter entry."
Expand Down
35 changes: 20 additions & 15 deletions src/aptsources_cleanup/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
from .util.filesystem import *
from .util.gettext import *
from .util.relations import *
from .util.io import replace_TextIOWrapper
from .util.strings import *
from .util.io import *
from . import *
import sys
import os.path
Expand All @@ -17,20 +18,22 @@
from itertools import starmap
from functools import reduce, partial as fpartial
import aptsources.sourceslist
aptsources_cleanup = sys.modules[__package__]
import aptsources_cleanup


argparse._ = _
argparse.ngettext = _N


def main(*args):
def main(args=None):
"""Main program entry point
See the output of the '--help' option for usage.
"""

args = parse_args(args or sys.argv[1:])
if args is None:
args = sys.argv[1:]
args = parse_args(args)
if args.debug_import_fail:
from .util.import_check import import_check
import_check('aptsources.sourceslist', 'apt', None, args.debug_import_fail)
Expand All @@ -53,12 +56,12 @@ def main(*args):

def load_sources_dir(sourceslist, dirname):
if not os.path.isdir(dirname):
termwrap.stderr().print('{:s}: {:s}: {:s}'.format(
_('Error'), _('No such directory'), dirname))
termwrap.stderr().print(': '.join(
(_('Error'), _('No such directory'), dirname)))
return 1

import glob
del sourceslist.list[:]
sourceslist.list.clear()
foreach(sourceslist.load, glob.iglob(os.path.join(dirname, '*.list')))
return 0

Expand Down Expand Up @@ -181,7 +184,7 @@ def __call__(self, parser, namespace, values, option_string):
else:
version = globals().get('__version__')
if version is not None:
version = '%(prog)s, version ' + version
version = '%(prog)s, version ' + version.replace('%', '%%')

parser._print_message(
parser._get_formatter()._format_text(version).strip() + '\n',
Expand All @@ -193,8 +196,9 @@ def parse_args(args):
suppress_debug = (
None if args and '--help-debug' in args else argparse.SUPPRESS)

translations.add_fallback(DictTranslations(
ID_DESCRIPTION=aptsources_cleanup.__doc__.rpartition('\n\n\n')[0].strip()))
translations.add_fallback(
DictTranslations(ID_DESCRIPTION=
prefix(aptsources_cleanup.__doc__, '\n\n\n', reverse=True).strip()))

ap = MyArgumentParser(formatter_class=TerminalHelpFormatter,
add_help=False, description=_('ID_DESCRIPTION'),
Expand Down Expand Up @@ -271,13 +275,13 @@ def handle_duplicates(sourceslist, apply_changes=None,
duplicates = tuple(get_duplicates(
sourceslist, equivalent_schemes=equivalent_schemes))
if duplicates:
for dupe_set in duplicates:
orig = dupe_set.pop(0)
for dupe_set in map(iter, duplicates):
orig = next(dupe_set)
for dupe in dupe_set:
stdout.print(_('Overlapping source entries:'))
for i, se in enumerate((orig, dupe), 1):
stdout_indent1.print(
_("{ordinal:2d}. file '{file:s}':")
_("{ordinal:2d}. file {file!r}:")
.format(ordinal=i, file=se.file))
stdout_indent2.print(se.line)
stdout.print(_('I disabled the latter entry.'), end='\n\n')
Expand Down Expand Up @@ -366,6 +370,7 @@ def handle_empty_files(sourceslist):
sys.stderr = replace_TextIOWrapper(sys.stderr, errors='namereplace')

try:
sys.exit(main())
rv = main()
except KeyboardInterrupt:
sys.exit(2)
rv = 2
sys.exit(rv)
23 changes: 14 additions & 9 deletions src/aptsources_cleanup/util/functools.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@ class comp:
__slots__ = ('funcs',)


@classmethod
def make(cls, *funcs):
def __new__(cls, *funcs):
if len(funcs) <= 1:
return funcs[0] if funcs else identity
return cls(*funcs)
return super().__new__(cls)


def __init__(self, *funcs):
Expand All @@ -32,12 +31,15 @@ def __init__(self, *funcs):


def __call__(self, *args):
funcs = iter(self.funcs)
x = next(funcs, identity)(*args)
del args
for f in funcs:
x = f(x)
return x
funcs = self.funcs
if funcs:
funcs = iter(funcs)
args = next(funcs)(*args)
for f in funcs:
args = f(args)
else:
args, = args
return args


class LazyInstance:
Expand Down Expand Up @@ -79,6 +81,9 @@ def __init__(self, factory, type_hint=None, strict=False):
self._li_type_hint = type_hint


__hash__ = None


@property
def _instance(self):
"""Accesses the wrapped instance
Expand Down
4 changes: 2 additions & 2 deletions src/aptsources_cleanup/util/gettext.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
)

from . import terminal, collections
from .strings import startswith_token
from .strings import startswith_token, prefix
from .operator import identity, methodcaller, peek
from .itertools import unique, last, filterfalse
from .functools import LazyInstance, comp, partial as fpartial
Expand All @@ -34,7 +34,7 @@ def _get_archive():

def get_localedir(locales_subdir=os.path.join('share', 'locales')):
src_root = os.path.dirname(os.path.dirname(
sys.modules[ (__package__ or __name__).partition('.')[0] ].__file__))
__import__(prefix(__package__ or __name__, '.')).__file__))
src_root_locales = os.path.join(src_root, locales_subdir)

if _get_archive() is None and not os.path.isdir(src_root_locales):
Expand Down
16 changes: 8 additions & 8 deletions src/aptsources_cleanup/util/import_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ def import_check(module_name, apt_pkg_suffix, import_error=None, debug_fail=0):
apt_pkg = '-'.join((python_name, apt_pkg_suffix))

paragraphs = [
'{:s}: {!s}. {:s} {:s}'.format(
'{:s}: {!s}. {:s} sudo apt-get install {:s}'.format(
type(import_error).__name__, import_error,
_("Do you have the '{package:s}' package installed? You can do so with:")
.format(package=apt_pkg),
apt_pkg)
]

if not samefile(python_exe, sys.executable) or debug_fail:
questional_interpreter_msg = len(paragraphs)
questionable_interpreter_msg = len(paragraphs)
paragraphs.append(': '.join((
_('Warning'),
_("The current Python interpreter is '{py_exe:s}'. Please use the "
Expand All @@ -51,26 +51,26 @@ def import_check(module_name, apt_pkg_suffix, import_error=None, debug_fail=0):
.format(py_exe=sys.executable, py_exe_default=python_exe,
module=module_name))))
else:
questional_interpreter_msg = None
questionable_interpreter_msg = None

if not pkg.check_integrity(python_pkg, paragraphs, debug_fail):
msg = (
_("Please make sure that the '{package:s}' package wasn't corrupted and "
"that '{py_exe:s}' refers to the Python interpreter from the same "
"package.")
.format(package=python_pkg, py_exe=python_exe))
if questional_interpreter_msg is not None:
paragraphs[questional_interpreter_msg] = ' '.join((
paragraphs[questional_interpreter_msg], msg))
if questionable_interpreter_msg is not None:
paragraphs[questionable_interpreter_msg] = ' '.join((
paragraphs[questionable_interpreter_msg], msg))
else:
paragraphs.append(': '.join((_('Warning'), msg)))

try:
termwrap.get(sys.stderr, ignore_errors=False)
stderr = termwrap.get(sys.stderr, ignore_errors=False)
except EnvironmentError as ex:
print(_('Warning'),
_('Cannot wrap text output due a failure to get the terminal size'),
ex, sep=': ', end='\n\n', file=sys.stderr)

termwrap.stderr().print_all(paragraphs)
stderr.print_all(paragraphs)
sys.exit(127)
17 changes: 11 additions & 6 deletions src/aptsources_cleanup/util/operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ class methodcaller:
__slots__ = ('func', 'args')


def __init__(self, func, *args):
def __new__(cls, func, *args):
if not callable(func):
func = operator.methodcaller(func, *args)
args = ()
return operator.methodcaller(func, *args)
return super().__new__(cls)


def __init__(self, func, *args):
self.func = func
self.args = args

Expand All @@ -47,7 +49,10 @@ def starcall(func, args):
return func(*args)


def peek(func, arg0, *args):
def peek(func, *args):
"""Calls func with the given arguments and returns _the first argument_."""
func(arg0, *args)
return arg0

if not args:
raise TypeError('Need at least 2 arguments; got 1')
func(*args)
return args[0]
7 changes: 5 additions & 2 deletions src/aptsources_cleanup/util/strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ def startswith_token(s, prefix, sep=None):
s.find(sep, prefix_len, prefix_len + len(sep)) == prefix_len)


def prefix(s, sep):
pos = s.find(sep)
def prefix(s, *args, reverse=False):
if reverse:
pos = s.rfind(*args)
else:
pos = s.find(*args)
return s[:pos] if pos >= 0 else s
6 changes: 3 additions & 3 deletions src/aptsources_cleanup/util/terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,11 +212,11 @@ def _attribute_items(self,
'max_lines', 'placeholder', 'tabsize')
):
assert isinstance(mandatory_attrs, collections.abc.Sized)
yield from zip(
mandatory_attrs, map(fpartial(getattr, self), mandatory_attrs))
self_getattr = fpartial(getattr, self)
yield from zip(mandatory_attrs, map(self_getattr, mandatory_attrs))

for k in optional_attrs:
try:
yield (k, getattr(self, k))
yield (k, self_getattr(k))
except AttributeError:
pass
2 changes: 1 addition & 1 deletion src/aptsources_cleanup/util/version/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def load(cls):

version_file = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(
sys.modules[strings.prefix(__package__ or __name__, '.')].__file__))),
__import__(strings.prefix(__package__ or __name__, '.')).__file__))),
'VERSION')
try:
version_file = open(version_file)
Expand Down

0 comments on commit 3270889

Please sign in to comment.