pax_global_header00006660000000000000000000000064140403105750014511gustar00rootroot0000000000000052 comment=be64f0f22c0cd45995cd3a32d2e59cd5685fbd5b escapism-1.0.1/000077500000000000000000000000001404031057500133145ustar00rootroot00000000000000escapism-1.0.1/.gitignore000066400000000000000000000001721404031057500153040ustar00rootroot00000000000000MANIFEST build dist *.py[co] __pycache__ *.egg-info *~ *.bak .ipynb_checkpoints .tox .DS_Store \#*# .#* .coverage htmlcov escapism-1.0.1/.travis.yml000066400000000000000000000003251404031057500154250ustar00rootroot00000000000000language: python python: - 2.7 - 3.4 - 3.6 - 3.7 - 3.8 cache: - pip install: - pip install --upgrade pip - pip install -r test-requirements.txt -e . script: - pytest --cov escapism tests after_success: - codecov escapism-1.0.1/LICENSE000066400000000000000000000020741404031057500143240ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2015, Min Ragan-Kelley Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. escapism-1.0.1/MANIFEST.in000066400000000000000000000004441404031057500150540ustar00rootroot00000000000000include LICENSE include CONTRIBUTING.md include README.md # Documentation graft docs # docs subdirs we want to skip prune docs/_build # Patterns to exclude from any directory global-exclude *~ global-exclude *.pyc global-exclude *.pyo global-exclude .git global-exclude .ipynb_checkpoints escapism-1.0.1/PKG-INFO000066400000000000000000000013331404031057500144110ustar00rootroot00000000000000Metadata-Version: 1.1 Name: escapism Version: 1.0.1 Summary: Simple, generic API for escaping strings. Home-page: https://github.com/minrk/escapism Author: Min RK Author-email: benjaminrk@gmail.com License: MIT Description: There is no reason to install this package on its own. Platform: UNKNOWN Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 escapism-1.0.1/README.md000066400000000000000000000016651404031057500146030ustar00rootroot00000000000000# Escapism Simple escaping of text, given a set of safe characters and an escape character. ## Usage Not much to it. Two functions: ```python escaped = escapism.escape('string to escape') # 'string_20to_20escape' original = escapism.unescape(escaped) ``` There are two optional arguments you can pass to `escape()`: - `safe`: a string or set of characters that don't need escaping. Default: ascii letters and numbers. - `escape_char`: a single character used for escaping. Default: `_`. `escape_char` will never be considered a safe value. `unescape()` accepts the same `escape_char` argument as `escape()` if a value other than the default is used. ```python import string import escapism safe = string.ascii_letters + string.digits + '@_-.+' escape_char = r'%' escaped = escapism.escape('foø-bar@%!xX?', safe=safe, escape_char=escape_char) # 'fo%C3%B8-bar@%25%21xX%3F' original = escapism.unescape(escaped, escape_char=escape_char) ``` escapism-1.0.1/escapism.egg-info/000077500000000000000000000000001404031057500166125ustar00rootroot00000000000000escapism-1.0.1/escapism.egg-info/PKG-INFO000066400000000000000000000013331404031057500177070ustar00rootroot00000000000000Metadata-Version: 1.1 Name: escapism Version: 1.0.1 Summary: Simple, generic API for escaping strings. Home-page: https://github.com/minrk/escapism Author: Min RK Author-email: benjaminrk@gmail.com License: MIT Description: There is no reason to install this package on its own. Platform: UNKNOWN Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 escapism-1.0.1/escapism.egg-info/SOURCES.txt000066400000000000000000000004001404031057500204700ustar00rootroot00000000000000.gitignore .travis.yml LICENSE MANIFEST.in README.md escapism.py setup.cfg setup.py test-requirements.txt escapism.egg-info/PKG-INFO escapism.egg-info/SOURCES.txt escapism.egg-info/dependency_links.txt escapism.egg-info/top_level.txt tests/test_escapism.pyescapism-1.0.1/escapism.egg-info/dependency_links.txt000066400000000000000000000000011404031057500226600ustar00rootroot00000000000000 escapism-1.0.1/escapism.egg-info/top_level.txt000066400000000000000000000000111404031057500213340ustar00rootroot00000000000000escapism escapism-1.0.1/escapism.py000066400000000000000000000060001404031057500154660ustar00rootroot00000000000000"""Escape strings to a safe set Provide a generic API, given a set of safe characters and an escape character, to escape safe strings and unescape the result. A conservative default of [A-Za-z0-9] with _ as the escape character is used if no args are provided. """ # Copyright (c) Min RK # Distributed under the terms of the MIT License import re import string import sys import warnings __version__ = "1.0.1" SAFE = set(string.ascii_letters + string.digits) ESCAPE_CHAR = '_' if sys.version_info >= (3,): _ord = lambda byte: byte _bchr = lambda n: bytes([n]) else: _ord = ord _bchr = chr def _escape_char(c, escape_char=ESCAPE_CHAR): """Escape a single character""" buf = [] for byte in c.encode('utf8'): buf.append(escape_char) buf.append('%X' % _ord(byte)) return ''.join(buf) def escape(to_escape, safe=SAFE, escape_char=ESCAPE_CHAR, allow_collisions=False): """Escape a string so that it only contains characters in a safe set. Characters outside the safe list will be escaped with _%x_, where %x is the hex value of the character. If `allow_collisions` is True, occurrences of `escape_char` in the input will not be escaped. In this case, `unescape` cannot be used to reverse the transform because occurrences of the escape char in the resulting string are ambiguous. Only use this mode when: 1. collisions cannot occur or do not matter, and 2. unescape will never be called. .. versionadded: 1.0 allow_collisions argument. Prior to 1.0, behavior was the same as allow_collisions=False (default). """ if isinstance(to_escape, bytes): # always work on text to_escape = to_escape.decode('utf8') if not isinstance(safe, set): safe = set(safe) if allow_collisions: safe.add(escape_char) elif escape_char in safe: warnings.warn( "Escape character %r cannot be a safe character." " Set allow_collisions=True if you want to allow ambiguous escaped strings." % escape_char, RuntimeWarning, stacklevel=2, ) safe.remove(escape_char) chars = [] for c in to_escape: if c in safe: chars.append(c) else: chars.append(_escape_char(c, escape_char)) return u''.join(chars) def _unescape_char(m): """Unescape a single byte Used as a callback in pattern.subn. `m.group(1)` must be a single byte in hex, e.g. `a4` or `ff`. """ return _bchr(int(m.group(1), 16)) def unescape(escaped, escape_char=ESCAPE_CHAR): """Unescape a string escaped with `escape` escape_char must be the same as that used in the call to escape. """ if isinstance(escaped, bytes): # always work on text escaped = escaped.decode('utf8') escape_pat = re.compile(re.escape(escape_char).encode('utf8') + b'([a-z0-9]{2})', re.IGNORECASE) buf = escape_pat.subn(_unescape_char, escaped.encode('utf8'))[0] return buf.decode('utf8') escapism-1.0.1/setup.cfg000066400000000000000000000001031404031057500151270ustar00rootroot00000000000000[bdist_wheel] universal = 1 [egg_info] tag_build = tag_date = 0 escapism-1.0.1/setup.py000066400000000000000000000035421404031057500150320ustar00rootroot00000000000000#!/usr/bin/env python3 # coding: utf-8 # Copyright (c) Min RK. # Distributed under the terms of the MIT License. from __future__ import print_function import os import sys from setuptools import setup from setuptools.command.bdist_egg import bdist_egg pjoin = os.path.join here = os.path.abspath(os.path.dirname(__file__)) # Get the current package version. version_ns = {} with open(pjoin(here, 'escapism.py')) as f: exec(f.read(), {}, version_ns) class bdist_egg_disabled(bdist_egg): """Disabled version of bdist_egg Prevents setup.py install from performing setuptools' default easy_install, which it should never ever do. """ def run(self): sys.exit("Aborting implicit building of eggs. Use `pip install .` to install from source.") setup_args = dict( name = 'escapism', version = version_ns['__version__'], py_modules = ['escapism'], description = "Simple, generic API for escaping strings.", long_description = """There is no reason to install this package on its own.""", author = "Min RK", author_email = "benjaminrk@gmail.com", url = "https://github.com/minrk/escapism", license = "MIT", classifiers = [ 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', ], cmdclass = { 'bdist_egg': bdist_egg if 'bdist_egg' in sys.argv else bdist_egg_disabled, } ) if __name__ == '__main__': setup(**setup_args) escapism-1.0.1/test-requirements.txt000066400000000000000000000000321404031057500175500ustar00rootroot00000000000000pytest pytest-cov codecov escapism-1.0.1/tests/000077500000000000000000000000001404031057500144565ustar00rootroot00000000000000escapism-1.0.1/tests/test_escapism.py000066400000000000000000000027651404031057500177050ustar00rootroot00000000000000# coding: utf-8 import warnings import pytest from escapism import escape, unescape, SAFE text = type(u'') test_strings = [ u'asdf', u'sposmål', u'godtbrød', u'≠¡™£¢∞§¶¨•d', u'_\\-+', ] def test_escape_default(): for s in test_strings: e = escape(s) assert isinstance(e, text) u = unescape(e) assert isinstance(u, text) assert u == s def test_escape_custom_char(): for escape_char in r'\-%+_': for s in test_strings: e = escape(s, escape_char=escape_char) assert isinstance(e, text) u = unescape(e, escape_char=escape_char) assert isinstance(u, text) assert u == s def test_escape_custom_safe(): safe = 'ABCDEFabcdef0123456789' escape_char = '\\' safe_set = set(safe + '\\') for s in test_strings: e = escape(s, safe=safe, escape_char=escape_char) assert all(c in safe_set for c in e) u = unescape(e, escape_char=escape_char) assert u == s def test_safe_escape_char(): escape_char = "-" safe = SAFE.union({escape_char}) with pytest.warns(RuntimeWarning): e = escape(escape_char, safe=safe, escape_char=escape_char) assert e == "{}{:02X}".format(escape_char, ord(escape_char)) u = unescape(e, escape_char=escape_char) assert u == escape_char def test_allow_collisions(): escaped = escape('foo-bar ', escape_char='-', allow_collisions=True) assert escaped == 'foo-bar-20'