Last active
May 10, 2019 01:29
-
-
Save fish2000/51cf4ea3977abbd7ea6ce74c442eb870 to your computer and use it in GitHub Desktop.
Generic Python REPL configuration NOW WITH ANSI-COLOR FIGLET BANNERS DOGG
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- encoding: utf-8 -*- | |
import plistlib | |
import zict | |
import os | |
import appdirs | |
from replutilities import attr, isstring, isbytes | |
# UTILITY STUFF: Exceptions | |
class KeyValueError(ValueError): | |
pass | |
# UTILITY STUFF: Directory class | |
try: | |
from instakit.utils.filesystem import Directory | |
except (ImportError, SyntaxError): | |
class Directory(object): | |
def __init__(self, pth=None): | |
self.target = pth and str(pth) or os.getcwd() | |
@property | |
def name(self): | |
return self.target | |
@property | |
def exists(self): | |
return os.path.isdir(self.target) | |
def makedirs(self, pth=None): | |
os.makedirs(os.path.abspath( | |
os.path.join(self.name, pth or os.curdir)), exist_ok=False) | |
return self | |
def __str__(self): | |
return self.target | |
# UTILITY STUFF: AppDirs wrapper | |
class ReplEnvDirs(appdirs.AppDirs): | |
def __init__(self): | |
""" Initialize with a fixed “appname” parameter `replenv` """ | |
super(ReplEnvDirs, self).__init__(appname='replenv') | |
self.mode = 'linux' # use Linux directory layout | |
@property | |
def mode(self): | |
""" The “appdirs.system” global module variable controls the | |
operation of the properties of all `appdirs.AppDirs` instances. | |
""" | |
return appdirs.system | |
@mode.setter | |
def mode(self, value): | |
if value not in ('darwin', 'linux'): | |
raise ValueError("invalid mode: %s" % value) | |
appdirs.system = value | |
@property | |
def site_config(self): | |
return Directory(self.site_config_dir) | |
@property | |
def site_data(self): | |
return Directory(self.site_data_dir) | |
@property | |
def user_cache(self): | |
return Directory(self.user_cache_dir) | |
@property | |
def user_config(self): | |
return Directory(self.user_config_dir) | |
@property | |
def user_data(self): | |
return Directory(self.user_data_dir) | |
@property | |
def user_log(self): | |
return Directory(self.user_log_dir) | |
@property | |
def user_state(self): | |
return Directory(self.user_state_dir) | |
renvdirs = ReplEnvDirs() | |
if not renvdirs.user_config.exists: | |
renvdirs.user_config.makedirs() | |
ENCODING = 'UTF-8' | |
zfile = zict.File(str(renvdirs.user_config), mode='a') | |
zutf8 = zict.Func(dump=attr(plistlib, 'dumps', 'writePlistToString'), | |
load=attr(plistlib, 'loads', 'readPlistFromString'), | |
d=zfile) | |
zfunc = zict.Func(dump=lambda value: isstring(value) and value.encode(ENCODING) or value, | |
load=lambda value: isbytes(value) and value.decode(ENCODING) or value, | |
d=zutf8) | |
def has(key): | |
""" Test if a key is contained in the key-value store. """ | |
return key in zfunc | |
def count(): | |
""" Return the number of items in the key-value store. """ | |
return len(zfunc) | |
def get(key, default_value=None): | |
""" Return a value from the ReplEnv user-config key-value store. """ | |
if not key: | |
return default_value | |
try: | |
return zfunc[key] | |
except KeyError: | |
return default_value | |
def set(key, value): | |
""" Set and return a value in the ReplEnv user-config key-value store. """ | |
if not key: | |
raise KeyValueError("Non-Falsey key required (k: %s, v: %s)" % (key, value)) | |
if not value: | |
raise KeyValueError("Non-Falsey value required (k: %s, v: %s)" % (key, value)) | |
zfunc[key] = value | |
return get(key) | |
def delete(key): | |
""" Delete a value from the ReplEnv user-config key-value store. """ | |
if not key: | |
raise KeyValueError("Non-Falsey key required for deletion (k: %s)" % key) | |
del zfunc[key] | |
def iterate(): | |
""" Return an iterator for the key-value store. """ | |
return iter(zfunc) | |
def keys(): | |
""" Return an iterable with all of the keys in the key-value store. """ | |
return zfunc.keys() | |
def values(): | |
""" Return an iterable with all of the values in the key-value store. """ | |
return zfunc.values() | |
def items(): | |
""" Return an iterable yielding (key, value) for all items in the key-value store. """ | |
return zfunc.items() | |
__dir__ = lambda: ('KeyValueError', | |
'has', 'count', | |
'get', 'set', 'delete', 'iterate', | |
'keys', 'values', 'items') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- encoding: utf-8 -*- | |
""" | |
replenv.py | |
• Default module imports and other configgy code, | |
• For generic use in python repls – both the python2 and python3 interactive | |
interpreters, as well as bpython, ipython, ptpython, pyzo, PyCharm, and | |
whatever else; code specific to any given repl module lives in the config | |
files, per whatever that packages’ demands may be. | |
Created by FI$H 2000 on 2019-02-27. | |
Copyright (c) 2012-2025 Objects In Space And Time, LLC. All rights reserved. | |
""" | |
from __future__ import print_function, unicode_literals | |
if __name__ == '__main__': | |
# take your executions elsewhere: | |
raise RuntimeError( | |
"%s is for module import or star-import only" % __file__) | |
# Python version figlet banners: | |
banners = {} | |
banners['3.x'] = """ | |
888 888 .d8888b. | |
888 888 d88P Y88b | |
888 888 .d88P | |
88888b. 888 888 888888 88888b. .d88b. 88888b. 8888" 888 888 | |
888 "88b 888 888 888 888 "88b d88""88b 888 "88b "Y8b. `Y8bd8P' | |
888 888 888 888 888 888 888 888 888 888 888 888 888 X88K | |
888 d88P Y88b 888 Y88b. 888 888 Y88..88P 888 888 Y88b d88P d8b .d8""8b. | |
88888P" "Y88888 "Y888 888 888 "Y88P" 888 888 "Y8888P" Y8P 888 888 | |
888 888 | |
888 Y8b d88P | |
888 "Y88P" | |
""" | |
banners['3.8'] = """ | |
888 888 .d8888b. .d8888b. | |
888 888 d88P Y88b d88P Y88b | |
888 888 .d88P Y88b .d88P | |
88888b. 888 888 888888 88888b. .d88b. 88888b. 8888" "888888" | |
888 "88b 888 888 888 888 "88b d88""88b 888 "88b "Y8b. .d8Y""Y8b. | |
888 888 888 888 888 888 888 888 888 888 888 888 888 888 888 | |
888 d88P Y88b 888 Y88b. 888 888 Y88..88P 888 888 Y88b d88P d8b Y88b d88P | |
88888P" "Y88888 "Y888 888 888 "Y88P" 888 888 "Y8888P" Y8P "Y8888P" | |
888 888 | |
888 Y8b d88P | |
888 "Y88P" | |
""" | |
banners['3.7'] = """ | |
888 888 .d8888b. 8888888888 | |
888 888 d88P Y88b d88P | |
888 888 .d88P d88P | |
88888b. 888 888 888888 88888b. .d88b. 88888b. 8888" d88P | |
888 "88b 888 888 888 888 "88b d88""88b 888 "88b "Y8b. 88888888 | |
888 888 888 888 888 888 888 888 888 888 888 888 888 d88P | |
888 d88P Y88b 888 Y88b. 888 888 Y88..88P 888 888 Y88b d88P d8b d88P | |
88888P" "Y88888 "Y888 888 888 "Y88P" 888 888 "Y8888P" Y8P d88P | |
888 888 | |
888 Y8b d88P | |
888 "Y88P" | |
""" | |
banners['2.7'] = """ | |
888 888 .d8888b. 8888888888 | |
888 888 d88P Y88b d88P | |
888 888 888 d88P | |
88888b. 888 888 888888 88888b. .d88b. 88888b. .d88P d88P | |
888 "88b 888 888 888 888 "88b d88""88b 888 "88b .od888P" 88888888 | |
888 888 888 888 888 888 888 888 888 888 888 d88P" d88P | |
888 d88P Y88b 888 Y88b. 888 888 Y88..88P 888 888 888" d8b d88P | |
88888P" "Y88888 "Y888 888 888 "Y88P" 888 888 888888888 Y8P d88P | |
888 888 | |
888 Y8b d88P | |
888 "Y88P" | |
""" | |
# Add miscellaneous necessities: | |
from PIL import Image | |
from pprint import pprint, pformat | |
import sys, os, re | |
import appdirs | |
import argparse | |
import collections | |
import colorama | |
import colorio | |
import colormath | |
import contextlib | |
import copy | |
import datetime | |
import dateutil | |
import decimal | |
import functools | |
import inspect | |
import itertools | |
import math | |
import numpy | |
import requests | |
import shutil | |
import six | |
import sysconfig | |
import termcolor | |
import types | |
import xerox | |
# Configure ANSI-color python banner, per python version: | |
if six.PY3: | |
banner = banners.get('3.%s' % sys.version_info.minor, banners['3.x']) | |
banner_color = colorama.Fore.CYAN | |
else: | |
banner = banners['2.7'] | |
banner_color = colorama.Fore.LIGHTGREEN_EX | |
def print_python_banner(text, color, | |
reset=colorama.Style.RESET_ALL): | |
for line in text.splitlines(): | |
print(color + line, sep='') | |
print(reset, end='') | |
def print_warning(text, color=colorama.Fore.RED, | |
reset=colorama.Style.RESET_ALL): | |
print(color + text, sep='') | |
print(reset, end='') | |
# Practice safe star-importing: | |
__all__ = ('Image', | |
'pprint', 'pformat', | |
'sys', 'os', 're', | |
'appdirs', | |
'argparse', | |
'collections', | |
'colorama', | |
'colorio', | |
'colormath', | |
'contextlib', | |
'copy', | |
'datetime', | |
'dateutil', | |
'decimal', | |
'functools', | |
'inspect', | |
'itertools', | |
'math', | |
'numpy', | |
'reduce', | |
'requests', | |
'shutil', | |
'six', | |
'sysconfig', | |
'termcolor', | |
'types', | |
'xerox', | |
'print_python_banner', | |
'print_warning', 'banner', | |
'banner_color', | |
'modules') | |
python2_expires = 'January 1st, 2020' | |
is_python2_dead = datetime.datetime.now() >= dateutil.parser.parse(python2_expires) | |
try: | |
from functools import reduce | |
except (ImportError, SyntaxError): | |
pass | |
try: | |
if six.PY3: | |
from replpy3 import * | |
except (AttributeError, SyntaxError): | |
pass | |
else: | |
if six.PY3: | |
__all__ += (u'Σ',) | |
try: | |
import abc | |
import collections.abc as collectionsabc | |
import asciiplotlib | |
except (ImportError, SyntaxError): | |
pass | |
else: | |
# Extend `__all__`: | |
__all__ += ('abc', 'collectionsabc', 'asciiplotlib') | |
try: | |
from halogen.filesystem import (which, TemporaryName, Directory, | |
TemporaryDirectory, | |
TemporaryNamedFile) | |
except (ImportError, SyntaxError): | |
pass | |
else: | |
# Extend `__all__`: | |
__all__ += ('which', 'TemporaryName', 'Directory', | |
'TemporaryDirectory', | |
'TemporaryNamedFile') | |
try: | |
from instakit.utils.static import asset | |
except (ImportError, SyntaxError): | |
pass | |
else: | |
# Extend `__all__`: | |
__all__ += ('asset', 'image_paths', 'catimage') | |
# Prepare a list of readily open-able image file paths: | |
image_paths = list(map( | |
lambda image_file: asset.path('img', image_file), | |
asset.listfiles('img'))) | |
# I do this practically every time, so I might as well do it here: | |
catimage = Image.open(image_paths[0]) | |
# `__dir__` listifies `__all__`: | |
__dir__ = lambda: list(__all__) | |
modules = tuple(__dir__()) | |
# Print python banner before end-of-module -- | |
# if running in TextMate, we use `sys.stderr` instead of ANSI colors, | |
# as that’s the only way to get any sort of colored output in TextMate’s | |
# console output window: | |
if os.environ.get('TM_PYTHON'): | |
print(banner, file=sys.stderr) | |
else: | |
colorama.init() | |
print_python_banner(banner, banner_color) | |
if not six.PY3: | |
if is_python2_dead: | |
warning = u"∞§• ¡LOOK OUT! Python 2.x has been officially declared DEAD!!!!!!!" | |
else: | |
warning = u"∞§• ¡BEWARE! Python 2.x will perish when the clock strikes 2020!!!" | |
if os.environ.get('TM_PYTHON'): | |
print(warning, file=sys.stderr) | |
else: | |
print_warning(warning) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- encoding: utf-8 -*- | |
from __future__ import print_function, unicode_literals | |
try: | |
from functools import reduce | |
except (ImportError, SyntaxError): | |
pass | |
Σ = reduce | |
__all__ = (u'Σ',) | |
__dir__ = lambda: list(__all__) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- encoding: utf-8 -*- | |
from __future__ import print_function | |
import sys | |
try: | |
from pathlib import Path | |
except ImportError: | |
try: | |
from pathlib2 import Path | |
except ImportError: | |
Path = None | |
# N.B. this may or may not be a PY2/PY3 thing: | |
maxint = getattr(sys, 'maxint', | |
getattr(sys, 'maxsize', (2 ** 64) / 2)) | |
import io, os, re, six | |
import argparse | |
import array | |
import contextlib | |
import decimal | |
import numpy | |
__exports__ = {} | |
def doctrim(docstring): | |
""" This function is straight outta PEP257 -- q.v. `trim(…)`, | |
“Handling Docstring Indentation” subsection sub.: | |
https://www.python.org/dev/peps/pep-0257/#id18 | |
""" | |
if not docstring: | |
return '' | |
# Convert tabs to spaces (following the normal Python rules) | |
# and split into a list of lines: | |
lines = docstring.expandtabs().splitlines() | |
# Determine minimum indentation (first line doesn't count): | |
indent = maxint | |
for line in lines[1:]: | |
stripped = line.lstrip() | |
if stripped: | |
indent = min(indent, len(line) - len(stripped)) | |
# Remove indentation (first line is special): | |
trimmed = [lines[0].strip()] | |
if indent < maxint: | |
for line in lines[1:]: | |
trimmed.append(line[indent:].rstrip()) | |
# Strip off trailing and leading blank lines: | |
while trimmed and not trimmed[-1]: | |
trimmed.pop() | |
while trimmed and not trimmed[0]: | |
trimmed.pop(0) | |
# Return a single string: | |
return '\n'.join(trimmed) | |
def determine_name(thing, name=None, try_repr=False): | |
""" Private module function to find a name for a thing. """ | |
if name is not None: | |
return name | |
code = None | |
if hasattr(thing, '__export_name__'): | |
# q.v. “export(…)” deco-function sub. | |
if thing.__export_name__: | |
return thing.__export_name__ | |
if hasattr(thing, '__code__'): | |
# Python 3.x function code object | |
code = thing.__code__ | |
elif hasattr(thing, 'func_code'): | |
# Python 2.x function code object | |
code = thing.func_code | |
if code is not None: | |
if hasattr(code, 'co_name'): | |
# Use the code objects’ name | |
name = code.co_name | |
else: | |
# Try either __qualname__ or __name__ | |
if hasattr(thing, '__qualname__'): | |
name = thing.__qualname__ | |
elif hasattr(thing, '__name__'): | |
name = thing.__name__ | |
if try_repr and name is None: | |
return repr(thing) | |
return name | |
λ = determine_name(lambda: None) | |
class ExportError(NameError): | |
pass | |
def export(thing, name=None, *, doc=None): | |
""" Add a function -- or any object, really, to the export list. | |
Exported items will end up wih their names in the modules’ | |
`__all__` tuple, and will also be named in the list returned | |
by the modules’ `__dir__()` function. | |
Use export as a decorator to a function definition: | |
@export | |
def yo_dogg(i_heard=None): | |
... | |
… or manually, to export anything that doesn’t have a name: | |
yo_dogg = lambda i_heard=None: ... | |
dogg_heard_index = ( ... ) | |
export(yo_dogg, name="yo_dogg") | |
export(dogg_heard_index, name="dogg_heard_index") | |
""" | |
# Access the module-namespace __exports__ dict: | |
global __exports__ | |
# No explict name was passed -- try to determine one: | |
named = determine_name(thing, name=name) | |
# Double-check our determined name and item before stowing: | |
if named is None: | |
raise ExportError("can’t export an unnamed thing") | |
if named == λ: | |
raise ExportError("can’t export an unnamed lambda") | |
if named in __exports__: | |
raise ExportError("can’t re-export name “%s”" % named) | |
if thing is __exports__: | |
raise ExportError("can’t export the __export__ dict directly") | |
# At this point, “named” is valid -- if we were passed | |
# a lambda, try to rename it with our valid name: | |
if callable(thing): | |
if getattr(thing, '__name__', '') == λ: | |
thing.__name__ = thing.__qualname__ = named | |
# If a “doc” argument was passed in, attempt to assign | |
# the __doc__ attribute accordingly on the item -- note | |
# that this won’t work for e.g. slotted, builtin, or C-API | |
# types that lack mutable __dict__ internals (or at least | |
# a settable __doc__ slot or established attribute). | |
if doc is not None: | |
try: | |
thing.__doc__ = doctrim(doc) | |
except AttributeError: | |
pass | |
# Stow the item in the global __exports__ dict: | |
__exports__[named] = thing | |
# Attempt to assign our name as a private attribute | |
# on the item -- q.v. __doc__ note supra. | |
if not hasattr(thing, '__export_name__'): | |
try: | |
thing.__export_name__ = named | |
except AttributeError: | |
pass | |
# Return the thing, unchanged (that’s how we decorate). | |
return thing | |
# UTILITY FUNCTIONS: helpers for builtin container types: | |
@export | |
def tuplize(*items): | |
""" Return a new tuple containing all non-`None` arguments """ | |
return tuple(item for item in items if item is not None) | |
@export | |
def uniquify(*items): | |
""" Return a tuple with a unique set of all non-`None` arguments """ | |
return tuple(frozenset(item for item in items if item is not None)) | |
@export | |
def listify(*items): | |
""" Return a new list containing all non-`None` arguments """ | |
return list(item for item in items if item is not None) | |
def merge_two(one, two, cls=dict): | |
""" Merge two dictionaries into an instance of the specified class | |
Based on this docopt example source: https://git.io/fjCZ6 | |
""" | |
merged = ((key, one.get(key, None) or two.get(key, None)) \ | |
for key in set(one) | set(two)) | |
return cls(merged) | |
def merge_as(*dicts, cls=dict): | |
""" Merge all dictionaries into a new instance of the specified class """ | |
merged = cls() | |
for d in dicts: | |
merged = merge_two(merged, d, cls=cls) | |
return merged | |
@export | |
def merge_all(*dicts): | |
""" Merge all dictionary arguments into a new `dict` instance """ | |
return merge_as(*dicts, cls=dict) | |
# UTILITY STUFF: SimpleNamespace | |
@export | |
class SimpleNamespace(object): | |
""" Implementation courtesy this SO answer: | |
• https://stackoverflow.com/a/37161391/298171 | |
""" | |
__slots__ = tuplize('__dict__', '__weakref__') | |
def __init__(self, **kwargs): | |
self.__dict__.update(kwargs) | |
def __repr__(self): | |
keys = sorted(self.__dict__) | |
items = ("{}={!r}".format(k, self.__dict__[k]) for k in keys) | |
return "{}({})".format(type(self).__name__, ", ".join(items)) | |
def __eq__(self, other): | |
return self.__dict__ == other.__dict__ | |
# UTILITY FUNCTIONS: getattr(…) shortcuts: | |
or_none = lambda thing, atx: getattr(thing, atx, None) | |
getpyattr = lambda thing, atx, default_value=None: getattr(thing, '__%s__' % atx, default_value) | |
accessor = lambda function, thing, *attrs: ([atx for atx in (function(thing, atx) \ | |
for atx in attrs) \ | |
if atx is not None] or [None]).pop(0) | |
attr = lambda thing, *attrs: accessor(or_none, thing, *attrs) | |
pyattr = lambda thing, *attrs: accessor(getpyattr, thing, *attrs) | |
@export | |
def nameof(thing, fallback=''): | |
""" Get the name of a thing, according to either: | |
>>> thing.__qualname__ | |
… or: | |
>>> thing.__name__ | |
… optionally specifying a fallback string. | |
""" | |
return determine_name(thing) or fallback | |
BUILTINS = ('__builtins__', '__builtin__', 'builtins', 'builtin') | |
import types as thetypes | |
types = SimpleNamespace() | |
typed = re.compile(r"^(?P<typename>\w+)(?:Type)$") | |
# Fill a namespace with type aliases, minus the fucking 'Type' suffix -- | |
# We know they are types because they are in the fucking “types” module, OK? | |
# And those irritating four characters take up too much pointless space, if | |
# you asked me, which you implicitly did by reading the comments in my code, | |
# dogg. | |
for typename in dir(thetypes): | |
if typename.endswith('Type'): | |
setattr(types, typed.match(typename).group('typename'), | |
getattr(thetypes, typename)) | |
elif typename not in BUILTINS: | |
setattr(types, typename, getattr(thetypes, typename)) | |
# UTILITY FUNCTIONS: hasattr(…) shortcuts: | |
haspyattr = lambda thing, atx: hasattr(thing, '__%s__' % atx) | |
anyattrs = lambda thing, *attrs: any(hasattr(thing, atx) for atx in attrs) | |
allattrs = lambda thing, *attrs: all(hasattr(thing, atx) for atx in attrs) | |
anypyattrs = lambda thing, *attrs: any(haspyattr(thing, atx) for atx in attrs) | |
allpyattrs = lambda thing, *attrs: all(haspyattr(thing, atx) for atx in attrs) | |
isiterable = lambda thing: anypyattrs(thing, 'iter', 'getitem') | |
@export | |
def graceful_issubclass(thing, *cls_or_tuple): | |
""" A wrapper for `issubclass()` that tries to work with you. """ | |
length = 0 | |
try: | |
length = len(cls_or_tuple) | |
except TypeError: | |
pass | |
else: | |
if length == 1: | |
cls_or_tuple = cls_or_tuple[0] | |
else: | |
cls_or_tuple = tuple(item for item in cls_or_tuple if item is not None) | |
if (not isinstance(cls_or_tuple, (type, tuple))) \ | |
and isiterable(cls_or_tuple): | |
cls_or_tuple = tuple(cls_or_tuple) | |
try: | |
return issubclass(thing, cls_or_tuple) | |
except TypeError: | |
pass | |
try: | |
return issubclass(type(thing), cls_or_tuple) | |
except TypeError: | |
pass | |
return None | |
# UTILITY FUNCTIONS: is<something>() unary-predicates, and utility type-tuples with which | |
# said predicates use to make their decisions: | |
isabstractmethod = lambda method: getattr(method, '__isabstractmethod__', False) | |
isabstract = lambda thing: bool(pyattr(thing, 'abstractmethods', 'isabstractmethod')) | |
isabstractcontextmanager = lambda cls: graceful_issubclass(cls, contextlib.AbstractContextManager) | |
iscontextmanager = lambda cls: allpyattrs(cls, 'enter', 'exit') or isabstractcontextmanager(cls) | |
numeric_types = (int, float, decimal.Decimal) | |
array_types = (numpy.ndarray, | |
numpy.matrix, | |
numpy.ma.MaskedArray, array.ArrayType, | |
bytearray) | |
bytes_types = (bytes, bytearray) | |
string_types = six.string_types | |
path_classes = tuplize(argparse.FileType, or_none(os, 'PathLike'), Path) # Path may be “None” in disguise | |
path_types = string_types + bytes_types + path_classes | |
file_types = (io.TextIOBase, io.BufferedIOBase, io.RawIOBase, io.IOBase) | |
callable_types = (types.Function, | |
types.Method, | |
types.Lambda, | |
types.BuiltinFunction, | |
types.BuiltinMethod) | |
if six.PY3: | |
callable_types += ( | |
types.Coroutine, | |
types.ClassMethodDescriptor, | |
types.MemberDescriptor, | |
types.MethodDescriptor) | |
ispathtype = lambda cls: issubclass(cls, path_types) | |
ispath = lambda thing: graceful_issubclass(thing, path_types) or haspyattr(thing, 'fspath') | |
isvalidpath = lambda thing: ispath(thing) and os.path.exists(thing) | |
isnumber = lambda thing: issubclass(thing, numeric_types) | |
isnumeric = lambda thing: issubclass(thing, numeric_types) | |
isarray = lambda thing: graceful_issubclass(thing, array_types) | |
isstring = lambda thing: graceful_issubclass(thing, string_types) | |
isbytes = lambda thing: graceful_issubclass(thing, bytes_types) | |
isfunction = lambda thing: graceful_issubclass(thing, types.Function, types.Lambda) or callable(thing) | |
islambda = lambda thing: pyattr(thing, 'name', 'qualname') == λ | |
# THE MODULE EXPORTS: | |
export(λ, name='λ') | |
export(or_none, name='or_none', doc="or_none(thing, attribute) → shortcut for getattr(thing, attribute, None)") | |
export(getpyattr, name='getpyattr', doc="getpyattr(thing, attribute[, default]) → shortcut for getattr(thing, '__%s__' % attribute[, default])") | |
export(accessor, name='accessor', doc="accessor(func, thing, *attributes) → return the first non-None value had by successively applying func(thing, attribute)") | |
export(attr, name='attr', doc="Return the first existing attribute from a thing, given 1+ attribute names") | |
export(pyattr, name='pyattr', doc="Return the first existing __special__ attribute from a thing, given 1+ attribute names") | |
export(types, name='types', doc=""" Namespace containing type aliases from the `types` module, | |
sans the irritating and lexically unnecessary “Type” suffix -- | |
e.g. `types.ModuleType` can be accessed as just `types.Module` | |
from this namespace, which is less pointlessly redundant and | |
aesthetically more pleasant, like definitively. | |
""") | |
export(BUILTINS, name='BUILTINS') | |
export(haspyattr, name='haspyattr') | |
export(anyattrs, name='anyattrs') | |
export(allattrs, name='allattrs') | |
export(anypyattrs, name='anypyattrs') | |
export(allpyattrs, name='allpyattrs') | |
export(isiterable, name='isiterable') | |
export(isabstractmethod, name='isabstractmethod') | |
export(isabstract, name='isabstract') | |
export(isabstractcontextmanager, name='isabstractcontextmanager') | |
export(iscontextmanager, name='iscontextmanager') | |
export(numeric_types, name='numeric_types') | |
export(array_types, name='array_types') | |
export(bytes_types, name='bytes_types') | |
export(string_types, name='string_types') | |
export(path_classes, name='path_classes') | |
export(path_types, name='path_types') | |
export(file_types, name='file_types') | |
export(callable_types, name='callable_types') | |
export(ispathtype, name='ispathtype') | |
export(ispath, name='ispath') | |
export(isvalidpath, name='isvalidpath') | |
export(isnumber, name='isnumber') | |
export(isnumeric, name='isnumeric') | |
export(isarray, name='isarray') | |
export(isstring, name='isstring') | |
export(isbytes, name='isbytes') | |
export(isfunction, name='isfunction') | |
export(export) # hahaaaaa | |
export(None, name='__exports__') # in name only | |
export(None, name='__all__') # in name only | |
__all__ = tuple(__exports__.keys()) | |
__dir__ = lambda: list(__all__) | |
def test(): | |
from pprint import pprint | |
SEPARATOR_WIDTH = 80 | |
print_separator = lambda: print('-' * SEPARATOR_WIDTH) | |
print("ALL: (length=%i)" % len(__all__)) | |
print() | |
pprint(__all__) | |
print() | |
print("DIR(): (length=%i)" % len(__dir__())) | |
print() | |
pprint(__dir__()) | |
print() | |
print("EXPORTS: (length=%i)" % len(__exports__)) | |
print() | |
pprint(__exports__) | |
print() | |
print("» Checking “attr(•) accessor …”") | |
print() | |
import plistlib | |
dump = attr(plistlib, 'dumps', 'writePlistToString') | |
load = attr(plistlib, 'loads', 'readPlistFromString') | |
assert dump is not None | |
assert load is not None | |
wat = attr(plistlib, 'yo_dogg', 'wtf_hax') | |
assert wat is None | |
print("» Checking basic isXXX(•) functions …") | |
print() | |
assert graceful_issubclass(int, int) | |
assert isnumeric(int) | |
assert isarray(array.array) | |
assert isstring(str) | |
assert isstring("") | |
assert isbytes(bytes) | |
assert isbytes(bytearray) | |
assert isbytes(b"") | |
assert islambda(lambda: None) | |
assert isfunction(lambda: None) | |
assert isfunction(export) | |
# assert not isfunction(SimpleNamespace) | |
print("» Checking lambda naming …") | |
lammy = lambda: None | |
print("» lambda name = %s" % lammy.__name__) | |
print("» lambda name = %s" % pyattr(lammy, 'name', 'qualname')) | |
lammy_name = lammy.__name__ | |
lammy_pyattr_name = pyattr(lammy, 'name', 'qualname') | |
lambda_name = λ | |
assert lammy_name == lammy_pyattr_name | |
assert lammy_name == lambda_name | |
assert lammy_pyattr_name == lambda_name | |
print() | |
print("» Checking “types.__doc__ …”") | |
print() | |
print_separator() | |
print(types.__doc__) | |
print_separator() | |
print() | |
dict_one = { 'compress_level' : 9, | |
'optimize' : True, | |
'format' : 'png' } | |
dict_two = { 'yo' : 'dogg' } | |
dict_three = { 'compress_level' : 10, | |
'optimize' : True, | |
'format' : 'jpg' } | |
merged = merge_all(dict_one, dict_two, dict_three) | |
print("» Checking “merge_all(•) …”") | |
print() | |
assert merged == { 'compress_level' : 9, | |
'optimize' : True, | |
'format' : 'png', | |
'yo' : 'dogg' } | |
print_separator() | |
pprint(merged) | |
print_separator() | |
print() | |
if __name__ == '__main__': | |
test() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- encoding: utf-8 -*- | |
from replenv import * | |
if six.PY3: | |
from replutilities import * | |
import keyvalue |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- encoding: utf-8 -*- | |
from replenv import * | |
if six.PY3: | |
from replutilities import * | |
import keyvalue |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- encoding: utf-8 -*- | |
from replenv import * | |
if six.PY3: | |
from replutilities import * | |
import keyvalue |
The replenv
code is now part of Homage: q.v. https://github.com/fish2000/homage/tree/master/.script-bin for the latest updates
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The banners look like so: