Big migrations and linting.

With pathclass.glob_many, we can clean up and feel more confident
about many programs that use pipeable to take glob patterns.

Added return 0 to all programs that didn't have it, so we have
consistent and explicit command line return values.

Other linting and whitespace.
This commit is contained in:
voussoir 2021-09-23 23:42:34 -07:00
parent 6751a5d6c9
commit 4a9051e617
No known key found for this signature in database
GPG key ID: 5F7554F8C26DACCB
64 changed files with 345 additions and 228 deletions

View file

@ -1,37 +1,24 @@
import argparse import argparse
import os import os
import re
import sys import sys
from voussoirkit import interactive from voussoirkit import interactive
from voussoirkit import pathclass from voussoirkit import pathclass
from voussoirkit import pipeable from voussoirkit import pipeable
from voussoirkit import stringtools
from voussoirkit import vlogging from voussoirkit import vlogging
from voussoirkit import winglob
log = vlogging.getLogger(__name__, 'adbinstall') log = vlogging.getLogger(__name__, 'adbinstall')
def natural_sorter(x):
'''
Used for sorting files in 'natural' order instead of lexicographic order,
so that you get 1 2 3 4 5 6 7 8 9 10 11 12 13 ...
instead of 1 10 11 12 13 2 3 4 5 ...
Thank you Mark Byers
http://stackoverflow.com/a/11150413
'''
convert = lambda text: int(text) if text.isdigit() else text.lower()
alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
return alphanum_key(x)
def adbinstall_argparse(args): def adbinstall_argparse(args):
patterns = pipeable.input_many(args.apks, skip_blank=True, strip=True) patterns = pipeable.input_many(args.apks, skip_blank=True, strip=True)
apks = [file for pattern in patterns for file in winglob.glob(pattern)] apks = pathclass.glob_many(patterns, files=True)
installs = [] installs = []
for apk in apks: for apk in apks:
apk = pathclass.Path(apk) apk = pathclass.Path(apk)
if apk.is_dir: if apk.is_dir:
files = apk.glob('*.apk') files = apk.glob('*.apk')
files.sort(key=lambda x: natural_sorter(x.basename.lower())) files.sort(key=lambda x: stringtools.natural_sorter(x.basename.lower()))
apk = files[-1] apk = files[-1]
installs.append(apk) installs.append(apk)
@ -46,6 +33,8 @@ def adbinstall_argparse(args):
log.info(command) log.info(command)
os.system(command) os.system(command)
return 0
@vlogging.main_decorator @vlogging.main_decorator
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -2,6 +2,7 @@ import os
import sys import sys
from voussoirkit import pathclass from voussoirkit import pathclass
from voussoirkit import pipeable
def windows(): def windows():
paths = os.getenv('PATH').strip(' ;').split(';') paths = os.getenv('PATH').strip(' ;').split(';')
@ -30,7 +31,9 @@ def main(argv):
executables = linux() executables = linux()
for executable in executables: for executable in executables:
print(executable.absolute_path) pipeable.stdout(executable.absolute_path)
return 0
if __name__ == '__main__': if __name__ == '__main__':
raise SystemExit(main(sys.argv[1:])) raise SystemExit(main(sys.argv[1:]))

View file

@ -7,16 +7,13 @@ Merge two or more files by performing bitwise or on their bits.
> bitwise_or file1 file2 --output file3 > bitwise_or file1 file2 --output file3
''' '''
import argparse import argparse
import os
import sys import sys
from voussoirkit import betterhelp from voussoirkit import betterhelp
from voussoirkit import interactive from voussoirkit import interactive
from voussoirkit import operatornotify
from voussoirkit import pathclass from voussoirkit import pathclass
from voussoirkit import pipeable from voussoirkit import pipeable
from voussoirkit import vlogging from voussoirkit import vlogging
from voussoirkit import winglob
log = vlogging.getLogger(__name__, 'bitwise_or') log = vlogging.getLogger(__name__, 'bitwise_or')
@ -24,8 +21,7 @@ CHUNK_SIZE = 2**20
def bitwise_or_argparse(args): def bitwise_or_argparse(args):
patterns = pipeable.input_many(args.files, skip_blank=True, strip=True) patterns = pipeable.input_many(args.files, skip_blank=True, strip=True)
files = [file for pattern in patterns for file in winglob.glob(pattern)] files = pathclass.glob_many(patterns, files=True)
files = [pathclass.Path(file) for file in files]
if len(files) < 2: if len(files) < 2:
log.fatal('Need at least two input files.') log.fatal('Need at least two input files.')

View file

@ -23,6 +23,8 @@ def breplace_argparse(args):
command = f'x.replace("{replace_from}", "{replace_to}")' command = f'x.replace("{replace_from}", "{replace_to}")'
brename.brename(command, autoyes=args.autoyes, recurse=args.recurse) brename.brename(command, autoyes=args.autoyes, recurse=args.recurse)
return 0
def main(argv): def main(argv):
parser = argparse.ArgumentParser(__doc__) parser = argparse.ArgumentParser(__doc__)

View file

@ -13,6 +13,8 @@ def clipboard_argparse(args):
text = text.replace('\r', '') text = text.replace('\r', '')
print(text) print(text)
return 0
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -1,6 +1,5 @@
import argparse import argparse
import codecs import codecs
import os
import pyperclip import pyperclip
import re import re
import sys import sys
@ -71,6 +70,8 @@ def contentreplace_argparse(args):
except UnicodeDecodeError: except UnicodeDecodeError:
log.error('%s encountered unicode decode error.', file.absolute_path) log.error('%s encountered unicode decode error.', file.absolute_path)
return 0
@vlogging.main_decorator @vlogging.main_decorator
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -1,26 +1,32 @@
import argparse import argparse
import os
import sys import sys
import zlib import zlib
from voussoirkit import pathclass
from voussoirkit import pipeable from voussoirkit import pipeable
from voussoirkit import winglob from voussoirkit import vlogging
log = vlogging.getLogger(__name__, 'crc32')
def crc32_argparse(args): def crc32_argparse(args):
files = ( return_status = 0
file
for pattern in pipeable.input_many(args.patterns) patterns = pipeable.input_many(args.patterns, skip_blank=True, strip=True)
for file in winglob.glob(pattern) files = pathclass.glob_many(patterns, files=True)
if os.path.isfile(file)
)
for file in files: for file in files:
try: try:
with open(file, 'rb') as handle: with open(file, 'rb') as handle:
crc = zlib.crc32(handle.read()) crc = zlib.crc32(handle.read())
print(hex(crc)[2:].rjust(8, '0'), file) crc = hex(crc)[2:].rjust(8, '0')
pipeable.stdout(f'{crc} {file}')
except Exception as e: except Exception as e:
print(file, e) log.error('%s %s', file, e)
return_status = 1
return return_status
@vlogging.main_decorator
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

36
crlf.py
View file

@ -1,28 +1,46 @@
''' '''
Convert LF line endings to CRLF. Convert LF line endings to CRLF.
''' '''
import argparse
import sys import sys
from voussoirkit import pathclass
from voussoirkit import pipeable from voussoirkit import pipeable
from voussoirkit import winglob
CR = b'\x0D' CR = b'\x0D'
LF = b'\x0A' LF = b'\x0A'
CRLF = CR + LF CRLF = CR + LF
def crlf(filename): def crlf(file):
with open(filename, 'rb') as handle: with file.open('rb') as handle:
content = handle.read() content = handle.read()
original = content
content = content.replace(CRLF, LF) content = content.replace(CRLF, LF)
content = content.replace(LF, CRLF) content = content.replace(LF, CRLF)
with open(filename, 'wb') as handle: if content == original:
return
with file.open('wb') as handle:
handle.write(content) handle.write(content)
def main(args): def crlf_argparse(args):
for line in pipeable.go(args, strip=True, skip_blank=True): patterns = pipeable.input_many(args.patterns, skip_blank=True, strip=True)
for filename in winglob.glob(line): files = pathclass.glob_many(patterns)
pipeable.stdout(filename) for file in files:
crlf(filename) crlf(file)
pipeable.stdout(file)
return 0
def main(argv):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('patterns')
parser.set_defaults(func=crlf_argparse)
args = parser.parse_args(argv)
return args.func(args)
if __name__ == '__main__': if __name__ == '__main__':
raise SystemExit(main(sys.argv[1:])) raise SystemExit(main(sys.argv[1:]))

26
crop.py
View file

@ -1,13 +1,12 @@
import argparse import argparse
import os
import PIL.Image import PIL.Image
import sys import sys
from voussoirkit import pathclass
from voussoirkit import pipeable from voussoirkit import pipeable
from voussoirkit import winglob
def crop(filename, crops, *, inplace=False): def crop(file, crops, *, inplace=False):
image = PIL.Image.open(filename) image = PIL.Image.open(file.absolute_path)
if len(crops) == 2: if len(crops) == 2:
crops.extend(image.size) crops.extend(image.size)
@ -20,24 +19,27 @@ def crop(filename, crops, *, inplace=False):
image = image.crop(crops) image = image.crop(crops)
if inplace: if inplace:
newname = filename newname = file
else: else:
suffix = '_'.join(str(x) for x in crops) suffix = '_'.join(str(x) for x in crops)
suffix = f'_{suffix}' suffix = f'_{suffix}'
(base, extension) = os.path.splitext(filename) base = file.replace_extension('').basename
newname = base + suffix + extension newname = file.parent.with_child(base + suffix).add_extension(file.extension)
pipeable.stdout(newname) pipeable.stdout(newname.absolute_path)
image.save(newname, exif=image.info.get('exif', b''), quality=100) image.save(newname.absolute_path, exif=image.info.get('exif', b''), quality=100)
def crop_argparse(args): def crop_argparse(args):
filenames = winglob.glob(args.pattern) patterns = pipeable.input(args.pattern, skip_blank=True, strip=True)
for filename in filenames: files = pathclass.glob_many(patterns, files=True)
for file in files:
crop( crop(
filename, file,
crops=args.crops, crops=args.crops,
inplace=args.inplace, inplace=args.inplace,
) )
return 0
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -1,14 +1,19 @@
import os import os
import shutil import shutil
import sys
from voussoirkit import pathclass
from voussoirkit import pipeable from voussoirkit import pipeable
from voussoirkit import winglob
for pattern in pipeable.go(skip_blank=True): def main(argv):
for name in winglob.glob(pattern): for path in pathclass.glob_many(pipeable.go(argv, skip_blank=True)):
if os.path.isfile(name): if path.is_file:
pipeable.stdout(name) pipeable.stdout(path.absolute_path)
os.remove(name) os.remove(path.absolute_path)
elif os.path.isdir(name): elif path.is_dir:
pipeable.stdout(name) pipeable.stdout(path.absolute_path)
shutil.rmtree(name) shutil.rmtree(path.absolute_path)
return 0
if __name__ == '__main__':
raise SystemExit(main(sys.argv[1:]))

View file

@ -45,6 +45,8 @@ def directory_discrepancy_argparse(args):
for discrepancy in sorted(files2.difference(files1)): for discrepancy in sorted(files2.difference(files1)):
print(discrepancy) print(discrepancy)
return 0
@vlogging.main_decorator @vlogging.main_decorator
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -55,6 +55,8 @@ def drawquarter_argparse(args):
print(output_filename.relative_path) print(output_filename.relative_path)
piece.save(output_filename.absolute_path) piece.save(output_filename.absolute_path)
return 0
def main(argv): def main(argv):
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()

View file

@ -3,17 +3,17 @@ import sys
from voussoirkit import pathclass from voussoirkit import pathclass
from voussoirkit import pipeable from voussoirkit import pipeable
from voussoirkit import winglob
def empty_directories_argparse(args): def empty_directories_argparse(args):
patterns = pipeable.input_many(args.patterns, skip_blank=True, strip=True) patterns = pipeable.input_many(args.patterns, skip_blank=True, strip=True)
directories = (pathclass.Path(d) for pattern in patterns for d in winglob.glob(pattern)) directories = pathclass.glob_many(patterns, directories=True)
directories = (d for d in directories if d.is_dir)
for directory in directories: for directory in directories:
if len(directory.listdir()) == 0: if len(directory.listdir()) == 0:
pipeable.stdout(directory.absolute_path) pipeable.stdout(directory.absolute_path)
return 0
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -25,6 +25,8 @@ def eval_argparse(args):
x = line x = line
pipeable.stdout(eval(args.eval_string)) pipeable.stdout(eval(args.eval_string))
return 0
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -29,7 +29,6 @@ import bs4
import requests import requests
import sys import sys
import tenacity import tenacity
import time
from voussoirkit import betterhelp from voussoirkit import betterhelp
from voussoirkit import downloady from voussoirkit import downloady

View file

@ -138,6 +138,8 @@ def ffstreams_argparse(args):
moveto=args.moveto, moveto=args.moveto,
) )
return 0
@vlogging.main_decorator @vlogging.main_decorator
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -16,9 +16,8 @@ argv = sys.argv[1:]
randname = [random.choice(string.digits) for x in range(12)] randname = [random.choice(string.digits) for x in range(12)]
randname = int(''.join(randname)) randname = int(''.join(randname))
for pattern in argv:
for path in winglob.glob(pattern): for path in pathclass.glob_many(argv):
path = pathclass.Path(path)
newname = str(randname).rjust(12, '0') + path.dot_extension newname = str(randname).rjust(12, '0') + path.dot_extension
randname += 1 randname += 1
newname = path.parent.with_child(newname) newname = path.parent.with_child(newname)

View file

@ -9,13 +9,10 @@ import string
import sys import sys
from voussoirkit import pathclass from voussoirkit import pathclass
from voussoirkit import winglob
argv = sys.argv[1:] argv = sys.argv[1:]
for pattern in argv: for path in pathclass.glob_many(argv):
for path in winglob.glob(pattern):
path = pathclass.Path(path)
newname = [random.choice(string.ascii_lowercase) for x in range(9)] newname = [random.choice(string.ascii_lowercase) for x in range(9)]
newname = ''.join(newname) + path.dot_extension newname = ''.join(newname) + path.dot_extension
newname = path.parent.with_child(newname) newname = path.parent.with_child(newname)

View file

@ -9,13 +9,10 @@ import string
import sys import sys
from voussoirkit import pathclass from voussoirkit import pathclass
from voussoirkit import winglob
argv = sys.argv[1:] argv = sys.argv[1:]
for pattern in argv: for path in pathclass.glob_many(argv):
for path in winglob.glob(pattern):
path = pathclass.Path(path)
newname = [random.choice(string.digits) for x in range(12)] newname = [random.choice(string.digits) for x in range(12)]
newname = ''.join(newname) + path.dot_extension newname = ''.join(newname) + path.dot_extension
newname = path.parent.with_child(newname) newname = path.parent.with_child(newname)

View file

@ -42,6 +42,7 @@ def filepull(pull_from='.', autoyes=False):
def filepull_argparse(args): def filepull_argparse(args):
filepull(pull_from=args.pull_from, autoyes=args.autoyes) filepull(pull_from=args.pull_from, autoyes=args.autoyes)
return 0
def main(argv): def main(argv):
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()

View file

@ -3,7 +3,7 @@ import PIL.Image
import sys import sys
from voussoirkit import pathclass from voussoirkit import pathclass
from voussoirkit import winglob from voussoirkit import pipeable
def grayscale(filename, *, inplace=False): def grayscale(filename, *, inplace=False):
filename = pathclass.Path(filename) filename = pathclass.Path(filename)
@ -20,18 +20,23 @@ def grayscale(filename, *, inplace=False):
image = PIL.Image.open(filename.absolute_path) image = PIL.Image.open(filename.absolute_path)
image = image.convert('LA').convert(image.mode) image = image.convert('LA').convert(image.mode)
print(f'{new_filename.absolute_path}')
image.save(new_filename.absolute_path, exif=image.info.get('exif', b'')) image.save(new_filename.absolute_path, exif=image.info.get('exif', b''))
return new_filename
def grayscale_argparse(args): def grayscale_argparse(args):
filenames = winglob.glob(args.pattern) patterns = pipeable.input_many(args.patterns, skip_blank=True, strip=True)
for filename in filenames: files = pathclass.glob_many(patterns, files=True)
grayscale(filename, inplace=args.inplace) for file in files:
new_filename = grayscale(file, inplace=args.inplace)
if new_filename:
pipeable.stdout(new_filename.absolute_path)
return 0
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('pattern') parser.add_argument('patterns', nargs='+')
parser.add_argument('--inplace', action='store_true') parser.add_argument('--inplace', action='store_true')
parser.set_defaults(func=grayscale_argparse) parser.set_defaults(func=grayscale_argparse)

View file

@ -11,6 +11,7 @@ def groupsof_argparse(args):
for chunk in chunks: for chunk in chunks:
chunk = args.separator.join(chunk) chunk = args.separator.join(chunk)
pipeable.stdout(chunk) pipeable.stdout(chunk)
return 0
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -65,6 +65,8 @@ def hash_hardlink_argparse(args):
send2trash.send2trash(follower.absolute_path) send2trash.send2trash(follower.absolute_path)
os.link(leader.absolute_path, follower.absolute_path) os.link(leader.absolute_path, follower.absolute_path)
return 0
@vlogging.main_decorator @vlogging.main_decorator
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -27,7 +27,11 @@ def root():
def heresmyclipboard_argparse(args): def heresmyclipboard_argparse(args):
log.info(f'Starting server on port {args.port}, pid={os.getpid()}') log.info(f'Starting server on port {args.port}, pid={os.getpid()}')
try:
site.run(host='0.0.0.0', port=args.port) site.run(host='0.0.0.0', port=args.port)
except KeyboardInterrupt:
pass
return 0
@vlogging.main_decorator @vlogging.main_decorator
def main(argv): def main(argv):

View file

@ -5,7 +5,6 @@ import argparse
import PIL.Image import PIL.Image
import sys import sys
def full_hex(h): def full_hex(h):
h = h.replace('#', '') h = h.replace('#', '')
if len(h) in [3, 4]: if len(h) in [3, 4]:
@ -28,6 +27,7 @@ def make_hexpng(h, width=1, height=1):
def hexpng_argparse(args): def hexpng_argparse(args):
make_hexpng(args.hex_value, width=args.width, height=args.height) make_hexpng(args.hex_value, width=args.width, height=args.height)
return 0
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -131,43 +131,59 @@ def load_image(filename):
return image return image
def build_ico_header_blob(image_count): def build_ico_header_blob(image_count):
datablob = (b'' datablob = b''.join([
+ little(0, 2) # reserved # reserved
+ little(1, 2) # 1 = ico type little(0, 2),
+ little(image_count, 2) # 1 = ico type
) little(1, 2),
little(image_count, 2),
])
return datablob return datablob
def build_icon_directory_blob(image, offset_from_start): def build_icon_directory_blob(image, offset_from_start):
(width, height) = image.size (width, height) = image.size
datablob = (b'' datablob = b''.join([
+ little(width if width < 256 else 0, 1) little(width if width < 256 else 0, 1),
+ little(height if height < 256 else 0, 1) little(height if height < 256 else 0, 1),
+ little(0, 1) # colors in palette # colors in palette
+ little(0, 1) # reserved little(0, 1),
+ little(1, 2) # color planes # reserved
+ little(32, 2) # bit depth little(0, 1),
+ little((width * height * 4) + BMP_HEADER_LENGTH, 4) # image bytes length # color planes
+ little(offset_from_start, 4) little(1, 2),
) # bit depth
little(32, 2),
# image bytes length
little((width * height * 4) + BMP_HEADER_LENGTH, 4),
little(offset_from_start, 4),
])
return datablob return datablob
def build_image_data_blob(image): def build_image_data_blob(image):
datablob = (b'' datablob = b''.join([
+ little(40, 4) # header size # header size
+ little(image.size[0], 4) little(40, 4),
little(image.size[0], 4),
# "Even if the AND mask is not supplied, if the image is in Windows BMP # "Even if the AND mask is not supplied, if the image is in Windows BMP
# format, the BMP header must still specify a doubled height." - wikipedia # format, the BMP header must still specify a doubled height." - wikipedia
+ little(image.size[1] * 2, 4) little(image.size[1] * 2, 4),
+ little(1, 2) # color planes # color planes
+ little(32, 2) # bit depth little(1, 2),
+ little(0, 4) # no compression # bit depth
+ little(0, 4) # bytes length, inferred little(32, 2),
+ little(0, 4) # hor print # no compression
+ little(0, 4) # ver print little(0, 4),
+ little(0, 4) # palette # bytes length, inferred
+ little(0, 4) # important palette little(0, 4),
) # hor print
little(0, 4),
# ver print
little(0, 4),
# palette
little(0, 4),
# important palette
little(0, 4),
])
pixeldata = [] pixeldata = []
# Image.getdata() is a list of (r, g, b, a) channels # Image.getdata() is a list of (r, g, b, a) channels
# But the BMP are written (b, g, r, a) # But the BMP are written (b, g, r, a)
@ -214,11 +230,10 @@ def images_to_ico(images):
final_data = b''.join(datablobs) final_data = b''.join(datablobs)
return final_data return final_data
if __name__ == '__main__': if __name__ == '__main__':
try: try:
inputfiles = sys.argv[1:] inputfiles = sys.argv[1:]
except: except Exception:
print('Please provide an image file') print('Please provide an image file')
raise SystemExit raise SystemExit
print('Iconifying', inputfiles) print('Iconifying', inputfiles)

View file

@ -1,12 +1,24 @@
import argparse
import sys import sys
from voussoirkit import betterhelp
from voussoirkit import pathclass from voussoirkit import pathclass
from voussoirkit import pipeable
def inodes_argparse(args):
patterns = pipeable.input_many(args.patterns, skip_blank=True, strip=True)
files = pathclass.glob_many(patterns, files=True)
for file in files:
pipeable.stdout(f'{file.stat.st_dev} {file.stat.st_ino} {file.relative_path}')
return 0
def main(argv): def main(argv):
for file in pathclass.cwd().listdir(): parser = argparse.ArgumentParser(description=__doc__)
if not file.is_file:
continue parser.add_argument('patterns', nargs='+')
print(file.stat.st_dev, file.stat.st_ino, file.relative_path) parser.set_defaults(func=inodes_argparse)
return betterhelp.single_main(argv, parser, __doc__)
if __name__ == '__main__': if __name__ == '__main__':
raise SystemExit(main(sys.argv[1:])) raise SystemExit(main(sys.argv[1:]))

View file

@ -17,7 +17,7 @@ def inputrename_argparse(args):
files = (file for file in pathclass.cwd().listdir() if args.keyword in file.basename) files = (file for file in pathclass.cwd().listdir() if args.keyword in file.basename)
prev = None prev = None
for file in files: for file in files:
print(file.relative_path) pipeable.stderr(file.relative_path)
this = input('> ') this = input('> ')
if this == '' and prev is not None: if this == '' and prev is not None:
this = prev this = prev
@ -27,6 +27,8 @@ def inputrename_argparse(args):
os.rename(file.absolute_path, new_name.absolute_path) os.rename(file.absolute_path, new_name.absolute_path)
prev = this prev = this
return 0
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -154,6 +154,7 @@ def main(argv):
check_forever() check_forever()
except KeyboardInterrupt: except KeyboardInterrupt:
pass pass
return 0
if __name__ == '__main__': if __name__ == '__main__':
raise SystemExit(main(sys.argv[1:])) raise SystemExit(main(sys.argv[1:]))

View file

@ -12,7 +12,9 @@ def linenumbers_argparse(args):
digits = len(str(len(lines))) digits = len(str(len(lines)))
form = '{no:>0%d} | {line}' % digits form = '{no:>0%d} | {line}' % digits
for (index, line) in enumerate(lines): for (index, line) in enumerate(lines):
print(form.format(no=index+1, line=line)) pipeable.stdout(form.format(no=index+1, line=line))
return 0
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -3,7 +3,6 @@ lint_argparse_returns
===================== =====================
''' '''
import ast import ast
import argparse
import sys import sys
from voussoirkit import pathclass from voussoirkit import pathclass

View file

@ -1,5 +1,4 @@
from voussoirkit import pipeable from voussoirkit import pipeable
for line in pipeable.go(): for line in pipeable.go():
pipeable.stdout(line.lower()) pipeable.stdout(line.lower())

View file

@ -8,17 +8,15 @@ import sys
from voussoirkit import pathclass from voussoirkit import pathclass
from voussoirkit import pipeable from voussoirkit import pipeable
from voussoirkit import winglob
def moveall_argparse(args): def moveall_argparse(args):
files = ( patterns = pipeable.input(args.source, skip_blank=True, strip=True)
pathclass.Path(file) files = pathclass.glob_many(patterns)
for pattern in pipeable.input(args.source)
for file in winglob.glob(pattern)
)
destination = pathclass.Path(args.destination)
if not destination.is_dir: destination = pathclass.Path(args.destination)
try:
destination.assert_is_directory()
except pathclass.NotDirectory:
pipeable.stderr('destination must be a directory.') pipeable.stderr('destination must be a directory.')
return 1 return 1
@ -39,6 +37,8 @@ def moveall_argparse(args):
pipeable.stdout(new_path.absolute_path) pipeable.stdout(new_path.absolute_path)
shutil.move(file.absolute_path, new_path.absolute_path) shutil.move(file.absolute_path, new_path.absolute_path)
return 0
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -11,7 +11,6 @@ import sys
from voussoirkit import bytestring from voussoirkit import bytestring
def parse_rules(lines): def parse_rules(lines):
rules = [] rules = []
for (times, title) in lines[::-1]: for (times, title) in lines[::-1]:
@ -125,7 +124,7 @@ def _unitconvert(value):
else: else:
return bytestring.parsebytes(value) return bytestring.parsebytes(value)
def example_argparse(args): def mp3slice_argparse(args):
if len(args.rules) == 1 and os.path.isfile(args.rules[0]): if len(args.rules) == 1 and os.path.isfile(args.rules[0]):
rules = read_rulefile(args.rules[0]) rules = read_rulefile(args.rules[0])
else: else:
@ -155,14 +154,14 @@ def example_argparse(args):
command = 'ffmpeg -i "%s" %s' % (args.input_filename, outputters) command = 'ffmpeg -i "%s" %s' % (args.input_filename, outputters)
print(command) print(command)
os.system(command) os.system(command)
return 0
def main(argv): def main(argv):
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('input_filename') parser.add_argument('input_filename')
parser.add_argument('rules', nargs='+', default=None) parser.add_argument('rules', nargs='+', default=None)
parser.set_defaults(func=example_argparse) parser.set_defaults(func=mp3slice_argparse)
args = parser.parse_args(argv) args = parser.parse_args(argv)
return args.func(args) return args.func(args)

View file

@ -3,17 +3,17 @@ import sys
from voussoirkit import pathclass from voussoirkit import pathclass
from voussoirkit import pipeable from voussoirkit import pipeable
from voussoirkit import winglob
def nonempty_directories_argparse(args): def nonempty_directories_argparse(args):
patterns = pipeable.input_many(args.patterns, skip_blank=True, strip=True) patterns = pipeable.input_many(args.patterns, skip_blank=True, strip=True)
directories = (pathclass.Path(d) for pattern in patterns for d in winglob.glob(pattern)) directories = pathclass.glob_many(patterns, directories=True)
directories = (d for d in directories if d.is_dir)
for directory in directories: for directory in directories:
if len(directory.listdir()) != 0: if len(directory.listdir()) != 0:
pipeable.stdout(directory.absolute_path) pipeable.stdout(directory.absolute_path)
return 0
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -1,26 +1,31 @@
import argparse import argparse
import itertools
import sys import sys
from voussoirkit import pipeable from voussoirkit import pipeable
def shuffle_argparse(args): def pickn_argparse(args):
if args.count < 1: if args.count < 1:
pipeable.stderr('count must be >= 1.') pipeable.stderr('count must be >= 1.')
return 1 return 1
lines = pipeable.input(args.source, read_files=True, skip_blank=True, strip=True) lines = pipeable.input(args.source, read_files=True, skip_blank=True, strip=True)
lines = list(lines)
lines = lines[:args.count]
for line in lines: for line in itertools.islice(lines, args.count):
pipeable.stdout(line) pipeable.stdout(line)
# Exhaust the rest of stdin so we don't get Broken Pipe error
for line in lines:
pass
return 0
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('source') parser.add_argument('source')
parser.add_argument('count', type=int) parser.add_argument('count', type=int)
parser.set_defaults(func=shuffle_argparse) parser.set_defaults(func=pickn_argparse)
args = parser.parse_args(argv) args = parser.parse_args(argv)
return args.func(args) return args.func(args)

View file

@ -38,11 +38,12 @@ def pip_download(package):
os.rename(os.path.join(tmpdir.name, filename), os.path.join(new_directory, filename)) os.rename(os.path.join(tmpdir.name, filename), os.path.join(new_directory, filename))
tmpdir.cleanup() tmpdir.cleanup()
def pip_download_argparse(args): def pip_download_argparse(args):
for package in args.packages: for package in args.packages:
pip_download(package) pip_download(package)
return 0
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -14,7 +14,6 @@ from voussoirkit import betterhelp
from voussoirkit import spinal from voussoirkit import spinal
from voussoirkit import pathclass from voussoirkit import pathclass
def prune_dirs(starting): def prune_dirs(starting):
starting = pathclass.Path(starting) starting = pathclass.Path(starting)
walker = spinal.walk(starting, yield_directories=True, yield_files=False) walker = spinal.walk(starting, yield_directories=True, yield_files=False)
@ -36,7 +35,6 @@ def prune_dirs(starting):
directory = double_check.pop() directory = double_check.pop()
pruneme(directory) pruneme(directory)
def prune_dirs_argparse(args): def prune_dirs_argparse(args):
return prune_dirs(args.starting) return prune_dirs(args.starting)

View file

@ -28,7 +28,6 @@ def make_randomfile(length, filename=None):
f.close() f.close()
print('Created %s' % filename) print('Created %s' % filename)
bytes = listget(sys.argv, 1, None) bytes = listget(sys.argv, 1, None)
if bytes is None: if bytes is None:
bytes = 2 ** 10 bytes = 2 ** 10

View file

@ -1,11 +1,14 @@
import os
import send2trash import send2trash
import sys
from voussoirkit import pathclass
from voussoirkit import pipeable from voussoirkit import pipeable
from voussoirkit import winglob
for pattern in pipeable.go(skip_blank=True): def main(argv):
for name in winglob.glob(pattern): for path in pathclass.glob_many(pipeable.go(argv, skip_blank=True)):
name = os.path.abspath(name) pipeable.stdout(path.absolute_path)
pipeable.stdout(name) send2trash.send2trash(path.absolute_path)
send2trash.send2trash(name) return 0
if __name__ == '__main__':
raise SystemExit(main(sys.argv[1:]))

View file

@ -5,7 +5,7 @@ from voussoirkit import pipeable
for line in pipeable.go(): for line in pipeable.go():
if os.path.isfile(line): if os.path.isfile(line):
print('Recycling', line) pipeable.stdout(line)
send2trash.send2trash(line) send2trash.send2trash(line)
else: else:
print('Not a file', line) pipeable.stderr('Not a file', line)

View file

@ -12,6 +12,9 @@ from voussoirkit import bytestring
from voussoirkit import imagetools from voussoirkit import imagetools
from voussoirkit import pipeable from voussoirkit import pipeable
from voussoirkit import spinal from voussoirkit import spinal
from voussoirkit import vlogging
log = vlogging.getLogger(__name__, 'rejpg')
PIL.ImageFile.LOAD_TRUNCATED_IMAGES = True PIL.ImageFile.LOAD_TRUNCATED_IMAGES = True
@ -24,7 +27,7 @@ def rejpg_argparse(args):
bytes_saved = 0 bytes_saved = 0
remaining_size = 0 remaining_size = 0
for filename in files: for filename in files:
print(filename) log.info('Processing %s.', filename)
bytesio = io.BytesIO() bytesio = io.BytesIO()
image = PIL.Image.open(filename) image = PIL.Image.open(filename)
@ -43,9 +46,11 @@ def rejpg_argparse(args):
f.write(new_bytes) f.write(new_bytes)
f.close() f.close()
print('Saved', bytestring.bytestring(bytes_saved)) log.info('Saved', bytestring.bytestring(bytes_saved))
print('Remaining are', bytestring.bytestring(remaining_size)) log.info('Remaining are', bytestring.bytestring(remaining_size))
return 0
@vlogging.main_decorator
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -2,6 +2,9 @@
Repeat the input as many times as you want. Repeat the input as many times as you want.
> repeat "hello" 8 > repeat "hello" 8
> repeat "yowza" inf
> echo hi | repeat !i 4 > echo hi | repeat !i 4
''' '''
import argparse import argparse
@ -9,17 +12,16 @@ import sys
from voussoirkit import pipeable from voussoirkit import pipeable
def repeat_argparse(args): def repeat_inf(text):
text = pipeable.input(args.text, split_lines=False)
if args.times == 'inf':
try: try:
while True: while True:
print(text) pipeable.stdout(text)
except KeyboardInterrupt: except KeyboardInterrupt:
return 0 return 0
else:
def repeat_times(text, times):
try: try:
times = int(args.times) times = int(times)
except ValueError: except ValueError:
pipeable.stderr('times should be an integer >= 1.') pipeable.stderr('times should be an integer >= 1.')
return 1 return 1
@ -30,10 +32,17 @@ def repeat_argparse(args):
try: try:
for t in range(times): for t in range(times):
print(text) pipeable.stdout(text)
except KeyboardInterrupt: except KeyboardInterrupt:
return 1 return 1
def repeat_argparse(args):
text = pipeable.input(args.text, split_lines=False)
if args.times == 'inf':
return repeat_inf(text)
else:
return repeat_times(text, args.times)
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -2,7 +2,6 @@ import sys
from voussoirkit import pipeable from voussoirkit import pipeable
lines = pipeable.input(sys.argv[1]) lines = pipeable.input(sys.argv[1])
replace_from = sys.argv[2] replace_from = sys.argv[2]
replace_to = sys.argv[3] replace_to = sys.argv[3]

View file

@ -1,5 +1,4 @@
from voussoirkit import pipeable from voussoirkit import pipeable
for line in pipeable.go(): for line in pipeable.go():
print(repr(line)) print(repr(line))

View file

@ -38,7 +38,6 @@ from voussoirkit import imagetools
from voussoirkit import pathclass from voussoirkit import pathclass
from voussoirkit import pipeable from voussoirkit import pipeable
from voussoirkit import vlogging from voussoirkit import vlogging
from voussoirkit import winglob
log = vlogging.getLogger(__name__, 'resize') log = vlogging.getLogger(__name__, 'resize')
@ -102,10 +101,11 @@ def resize(
image.save(new_name.absolute_path, exif=image.info.get('exif', b''), quality=quality) image.save(new_name.absolute_path, exif=image.info.get('exif', b''), quality=quality)
def resize_argparse(args): def resize_argparse(args):
filenames = winglob.glob(args.pattern) patterns = pipeable.input(args.pattern, skip_blank=True, strip=True)
for filename in filenames: files = pathclass.glob_many(patterns, files=True)
for file in files:
resize( resize(
filename, file,
args.new_w, args.new_w,
args.new_h, args.new_h,
inplace=args.inplace, inplace=args.inplace,
@ -115,6 +115,8 @@ def resize_argparse(args):
quality=args.quality, quality=args.quality,
) )
return 0
@vlogging.main_decorator @vlogging.main_decorator
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -4,13 +4,17 @@ Reverse a string.
import argparse import argparse
import sys import sys
from voussoirkit import pipeable
def reverse_argparse(args): def reverse_argparse(args):
print(''.join(reversed(args.string))) text = pipeable.input(args.text, split_lines=False)
pipeable.stdout(''.join(reversed(text)))
return 0
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('string') parser.add_argument('text')
parser.set_defaults(func=reverse_argparse) parser.set_defaults(func=reverse_argparse)
args = parser.parse_args(argv) args = parser.parse_args(argv)

View file

@ -8,8 +8,8 @@ from voussoirkit import pipeable
def reverse_argparse(args): def reverse_argparse(args):
lines = list(pipeable.input(args.lines)) lines = list(pipeable.input(args.lines))
lines.reverse() pipeable.stdout('\n'.join(reversed(lines)))
print('\n'.join(lines)) return 0
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -1,28 +1,29 @@
import argparse import argparse
import os
import PIL.Image import PIL.Image
import sys import sys
from voussoirkit import imagetools from voussoirkit import imagetools
from voussoirkit import pathclass
from voussoirkit import pipeable from voussoirkit import pipeable
from voussoirkit import vlogging from voussoirkit import vlogging
from voussoirkit import winglob
log = vlogging.getLogger(__name__, 'rotate') log = vlogging.getLogger(__name__, 'rotate')
def rotate_argparse(args): def rotate_argparse(args):
if args.angle is None and not args.exif: if args.angle is None and not args.exif:
pipeable.stderr('Either an angle or --exif must be provided.') log.fatal('Either an angle or --exif must be provided.')
return 1 return 1
filenames = winglob.glob(args.pattern) patterns = pipeable.input(args.pattern, skip_blank=True, strip=True)
for filename in filenames: files = pathclass.glob_many(patterns, files=True)
image = PIL.Image.open(filename)
for file in files:
image = PIL.Image.open(file.absolute_path)
if args.exif: if args.exif:
(new_image, exif) = imagetools.rotate_by_exif(image) (new_image, exif) = imagetools.rotate_by_exif(image)
if new_image is image: if new_image is image:
log.debug('%s doesn\'t need exif rotation.', filename) log.debug('%s doesn\'t need exif rotation.', file.absolute_path)
continue continue
image = new_image image = new_image
else: else:
@ -30,16 +31,19 @@ def rotate_argparse(args):
image = image.rotate(args.angle, expand=True) image = image.rotate(args.angle, expand=True)
if args.inplace: if args.inplace:
newname = filename newname = file
else: else:
if args.exif: if args.exif:
suffix = f'_exifrot' suffix = f'_exifrot'
else: else:
suffix = f'_{args.angle}' suffix = f'_{args.angle}'
(base, extension) = os.path.splitext(filename)
newname = base + suffix + extension base = file.replace_extension('').basename
newname = base + suffix
newname = file.parent.with_child(newname).add_extension(file.extension)
pipeable.stdout(newname) pipeable.stdout(newname)
image.save(newname, exif=exif, quality=args.quality) image.save(file.absolute_path, exif=exif, quality=args.quality)
@vlogging.main_decorator @vlogging.main_decorator
def main(argv): def main(argv):

View file

@ -251,6 +251,7 @@ def _search_argparse(args):
result_count += 1 result_count += 1
if args.show_count: if args.show_count:
print('%d items.' % result_count) print('%d items.' % result_count)
return 0
@pipeable.ctrlc_return1 @pipeable.ctrlc_return1
def search_argparse(args): def search_argparse(args):

View file

@ -12,6 +12,8 @@ def shuffle_argparse(args):
for line in lines: for line in lines:
pipeable.stdout(line) pipeable.stdout(line)
return 0
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -14,7 +14,8 @@ def main(argv):
elif path.is_dir: elif path.is_dir:
total += spinal.get_dir_size(path) total += spinal.get_dir_size(path)
print(total) pipeable.stdout(total)
return 0
if __name__ == '__main__': if __name__ == '__main__':
raise SystemExit(main(sys.argv[1:])) raise SystemExit(main(sys.argv[1:]))

View file

@ -53,6 +53,8 @@ def sole_lift_argparse(args):
os.rmdir(temp_dir.absolute_path) os.rmdir(temp_dir.absolute_path)
queue.append(directory.parent) queue.append(directory.parent)
return 0
@vlogging.main_decorator @vlogging.main_decorator
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -14,6 +14,8 @@ def sorted_argparse(args):
for line in lines: for line in lines:
pipeable.stdout(line) pipeable.stdout(line)
return 0
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -12,6 +12,8 @@ def printstderr_argparse(args):
for line in text: for line in text:
pipeable.stderr(line) pipeable.stderr(line)
return 0
@vlogging.main_decorator @vlogging.main_decorator
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -12,6 +12,8 @@ def printstdout_argparse(args):
for line in text: for line in text:
pipeable.stdout(line) pipeable.stdout(line)
return 0
@vlogging.main_decorator @vlogging.main_decorator
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -2,10 +2,10 @@ import PIL.Image
import argparse import argparse
import sys import sys
from voussoirkit import pathclass
from voussoirkit import pipeable from voussoirkit import pipeable
from voussoirkit import sentinel from voussoirkit import sentinel
from voussoirkit import vlogging from voussoirkit import vlogging
from voussoirkit import winglob
log = vlogging.getLogger(__name__, 'stitch') log = vlogging.getLogger(__name__, 'stitch')
@ -14,8 +14,8 @@ HORIZONTAL = sentinel.Sentinel('horizontal')
def stitch_argparse(args): def stitch_argparse(args):
patterns = pipeable.input_many(args.image_files, skip_blank=True, strip=True) patterns = pipeable.input_many(args.image_files, skip_blank=True, strip=True)
files = [file for pattern in patterns for file in winglob.glob(pattern)] files = pathclass.glob_many(patterns, files=True)
images = [PIL.Image.open(file) for file in files] images = [PIL.Image.open(file.absolute_path) for file in files]
if args.vertical: if args.vertical:
direction = VERTICAL direction = VERTICAL
else: else:
@ -42,6 +42,7 @@ def stitch_argparse(args):
log.info(args.output) log.info(args.output)
final_image.save(args.output) final_image.save(args.output)
return 0
@vlogging.main_decorator @vlogging.main_decorator
def main(argv): def main(argv):

3
sum.py
View file

@ -1,5 +1,4 @@
from voussoirkit import pipeable from voussoirkit import pipeable
total = sum(float(x) for x in pipeable.go() if x.strip()) total = sum(float(x) for x in pipeable.go() if x.strip())
pipeable.stdout(f'{total}\n') pipeable.stdout(f'{total}')

View file

@ -88,6 +88,8 @@ def svgrender_argparse(args):
axis='y' if args.y else 'x', axis='y' if args.y else 'x',
) )
return 0
@vlogging.main_decorator @vlogging.main_decorator
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -8,6 +8,10 @@ import time
from voussoirkit import bytestring from voussoirkit import bytestring
from voussoirkit import downloady from voussoirkit import downloady
from voussoirkit import pipeable from voussoirkit import pipeable
from voussoirkit import vlogging
log = vlogging.getLogger(__name__, 'threaded_dl')
downloady.log.setLevel(vlogging.WARNING)
def clean_url_list(urls): def clean_url_list(urls):
for url in urls: for url in urls:
@ -29,7 +33,7 @@ def clean_url_list(urls):
yield url yield url
def download_thread(url, filename, *, bytespersecond=None, headers=None, timeout=None): def download_thread(url, filename, *, bytespersecond=None, headers=None, timeout=None):
print(f' Starting "{filename}"') log.info(f'Starting "{filename}"')
downloady.download_file( downloady.download_file(
url, url,
filename, filename,
@ -37,7 +41,7 @@ def download_thread(url, filename, *, bytespersecond=None, headers=None, timeout
headers=headers, headers=headers,
timeout=timeout, timeout=timeout,
) )
print(f'+Finished "{filename}"') log.info(f'Finished "{filename}"')
def remove_finished(threads): def remove_finished(threads):
return [t for t in threads if t.is_alive()] return [t for t in threads if t.is_alive()]
@ -87,7 +91,7 @@ def threaded_dl(
) )
if os.path.exists(filename): if os.path.exists(filename):
print(f'Skipping existing file "{filename}"') log.info(f'Skipping existing file "{filename}"')
else: else:
kwargs = { kwargs = {
@ -103,7 +107,7 @@ def threaded_dl(
while len(threads) > 0: while len(threads) > 0:
threads = remove_finished(threads) threads = remove_finished(threads)
print(f'{len(threads)} threads remaining\r', end='', flush=True) pipeable.stderr(f'{len(threads)} threads remaining\r', end='')
time.sleep(0.1) time.sleep(0.1)
def threaded_dl_argparse(args): def threaded_dl_argparse(args):
@ -132,6 +136,9 @@ def threaded_dl_argparse(args):
timeout=args.timeout, timeout=args.timeout,
) )
return 0
@vlogging.main_decorator
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -21,6 +21,8 @@ def touch_argparse(args):
os.utime(filename) os.utime(filename)
pipeable.stdout(filename) pipeable.stdout(filename)
return 0
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -10,6 +10,7 @@ def unique_argparse(args):
if line not in seen: if line not in seen:
pipeable.stdout(line) pipeable.stdout(line)
seen.add(line) seen.add(line)
return 0
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -42,6 +42,7 @@ def watchforlinks_argparse(args):
loop_forever(extension=args.extension, regex=args.regex) loop_forever(extension=args.extension, regex=args.regex)
except KeyboardInterrupt: except KeyboardInterrupt:
pass pass
return 0
def main(argv): def main(argv):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)

View file

@ -4,10 +4,8 @@ import sys
from voussoirkit import bytestring from voussoirkit import bytestring
filename = os.path.abspath(sys.argv[1]) filename = os.path.abspath(sys.argv[1])
def zerofile(filename, length): def zerofile(filename, length):
if os.path.exists(filename): if os.path.exists(filename):
raise ValueError(f'{filename} already exists.') raise ValueError(f'{filename} already exists.')