diff --git a/.gitignore b/.gitignore index b532f3d..47c2ac4 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,8 @@ var/ *.egg-info/ .installed.cfg *.egg +.hypothesis/ +test/.hypothesis/ # PyInstaller # Usually these files are written by a python script from a template diff --git a/pagan/generator.py b/pagan/generator.py index 3b3adc9..51a166c 100644 --- a/pagan/generator.py +++ b/pagan/generator.py @@ -7,6 +7,7 @@ import os import sys +from builtins import bytes class FalseHashError(Exception): """ """ @@ -103,12 +104,7 @@ def hash_input(inpt, algo=HASH_SHA256): elif (algo == HASH_SHA512): hashcode = hashlib.sha512() - if sys.version_info.major == 2: - inpt = bytes(inpt) - else: - inpt = bytes(inpt, "utf-8") - - hashcode.update(inpt) + hashcode.update(bytes(inpt, "utf-8")) hexhash = hashcode.hexdigest() return hexhash @@ -270,8 +266,10 @@ def setup_pixelmap(hashcode): def generate(str, alg): - """Generates an PIL image avatar based on the given - input String. Acts as the main accessor to pagan.""" + """Generates an PIL image avatar based on the given input String. + + Acts as the main accessor to pagan. + """ img = Image.new(IMAGE_MODE, IMAGE_SIZE, BACKGROUND_COLOR) hashcode = hash_input(str, alg) pixelmap = setup_pixelmap(hashcode) @@ -280,18 +278,20 @@ def generate(str, alg): def generate_by_hash(hashcode): - """Generates an PIL image avatar based on the given - hash String. Acts as the main accessor to pagan.""" + """Generates an PIL image avatar based on the given hash String. + + Acts as the main accessor to pagan. + """ img = Image.new(IMAGE_MODE, IMAGE_SIZE, BACKGROUND_COLOR) if len(hashcode) < 32: print ("hashcode must have lenght >= 32, %s" % hashcode) raise FalseHashError - allowed = "0123456789abcdef" - hashcheck = [c in allowed for c in hashcode] - if False in hashcheck: - print ("hashcode has not allowed structure %s" % hashcode) - raise FalseHashError + allowed = "0123456789ABCDEFabcdef" + for c in hashcode: + if c not in allowed: + print ("hashcode has not allowed structure %s" % hashcode) + raise FalseHashError pixelmap = setup_pixelmap(hashcode) draw_image(pixelmap, img) diff --git a/pagan/pagan.py b/pagan/pagan.py index c561659..180fa54 100644 --- a/pagan/pagan.py +++ b/pagan/pagan.py @@ -3,7 +3,7 @@ import os -class Avatar(): +class Avatar(object): # Default output path is in the current working directory. DEFAULT_OUTPUT_PATH = os.path.join(os.getcwd(), "output/") @@ -18,8 +18,9 @@ def __init__(self, inpt, hashfun=DEFAULT_HASHFUN): self.img = self.__create_image(inpt, hashfun) def __create_image(self, inpt, hashfun): - """Creates the avatar based on the input and - the chosen hash function.""" + """Creates the avatar based on the input and the chosen hash function. + + """ if hashfun not in generator.HASHES.keys(): print ("Unknown or unsupported hash function. Using default: %s" % self.DEFAULT_HASHFUN) @@ -29,22 +30,24 @@ def __create_image(self, inpt, hashfun): return generator.generate(inpt, algo) def show(self): - """Shows a preview of the avatar in an external - image viewer.""" + """Shows a preview of the avatar in an external image viewer.""" self.img.show() def change(self, inpt, hashfun=DEFAULT_HASHFUN): """Change the avatar by providing a new input. - Uses the standard hash function if no one is given.""" + + Uses the standard hash function if no one is given. + """ self.img = self.__create_image(inpt, hashfun) def save(self, path=DEFAULT_OUTPUT_PATH, filename=DEFAULT_FILENAME): - """Saves a avatar under the given output path to - a given filename. The file ending ".png" is appended + """Saves a avatar under the given output path to a given filename. + + The file ending ".png" is appended automatically. If the path does not exist, it will be created. When no parameters are omitted, a default path - and/or filename will be used.""" - + and/or filename will be used. + """ # Creates a path when it does not exist. if not os.path.exists(path): os.makedirs(path) @@ -56,6 +59,7 @@ def save(self, path=DEFAULT_OUTPUT_PATH, filename=DEFAULT_FILENAME): # Saves the image under the given filepath. filepath = ("%s%s.png" % (path, filename)) filepath = os.path.join(path, "%s.png" % filename) + # FIXIT: filepath without SUFFIX, print writes false filename print ("Saving: %s" % filepath) self.img.save(filepath, 'PNG') diff --git a/setup.py b/setup.py index 98cc1a0..3bed64a 100644 --- a/setup.py +++ b/setup.py @@ -25,6 +25,6 @@ 'Environment :: Web Environment', 'Topic :: Software Development :: Libraries :: Python Modules' ], - install_requires=['Pillow>=2.3.0'] + install_requires=['Pillow>=2.3.0', 'future'] ) diff --git a/test/test_bin_pagan.py b/test/test_bin_pagan.py new file mode 100644 index 0000000..3a673dd --- /dev/null +++ b/test/test_bin_pagan.py @@ -0,0 +1,46 @@ +import os +from subprocess import PIPE +from subprocess import Popen + + +def test_simple_call(): + """check if calling the script simply works and yields no error""" + p = Popen(["pagan", "--noshow", "--output=/tmp/0101010101.png", "0101"], + stdout=PIPE, stderr=PIPE) + stdout, stderr = p.communicate() + assert stdout + assert not stderr + + +def test_simple_call_err(): + """fail if called with wrong arguments""" + p = Popen(["pagan", "--output=/tmp/0101010101.png", "--err", "0101"], + stdout=PIPE, stderr=PIPE) + stdout, stderr = p.communicate() + assert not stdout + assert stderr + + +def test_simple_call_err_no_input(): + """fail if no input given""" + p = Popen(["pagan", "--output=/tmp/0101010101.png"], + stdout=PIPE, stderr=PIPE) + stdout, stderr = p.communicate() + assert not stdout + assert stderr + + +def test_replace_chars_in_filename(): + """test replace chars in filename, if only called with input + + no punctuation allowed, so replace "one.png" with "one-png" + """ + p = Popen(["pagan", "--noshow", "/tmp/one.png"], + stdout=PIPE, stderr=PIPE) + stdout, stderr = p.communicate() + assert not stderr + assert stdout + expected_filename = "-tmp-one-png.png" + assert os.path.isfile(expected_filename) + if os.path.isfile(expected_filename): + os.unlink(expected_filename) diff --git a/test/test_generator.py b/test/test_generator.py index a147b3c..b9a488e 100644 --- a/test/test_generator.py +++ b/test/test_generator.py @@ -22,4 +22,4 @@ def test_generate_by_hash(): img = pagan.generator.generate_by_hash(md5.hexdigest()[:2]) with pytest.raises(pagan.generator.FalseHashError): - img = pagan.generator.generate_by_hash(md5.hexdigest()+"A") + img = pagan.generator.generate_by_hash(md5.hexdigest()+"G") diff --git a/test/test_hypo.py b/test/test_hypo.py new file mode 100644 index 0000000..70dbf75 --- /dev/null +++ b/test/test_hypo.py @@ -0,0 +1,14 @@ +# -*- coding: latin-1 -*- +import pagan +from hypothesis import given +import hypothesis.strategies as st + + +@given(st.text(), st.integers()) +def test_hypo(inpt, hashnr): + img = pagan.Avatar(inpt, hashnr) + assert (img.img) + + +if __name__ == "__main__": + test_hypo() diff --git a/test/test_pagan.py b/test/test_pagan.py index ad41ce6..f2ac4b5 100644 --- a/test/test_pagan.py +++ b/test/test_pagan.py @@ -1,4 +1,7 @@ # -*- coding: latin-1 -*- +import os +import random +import string import tempfile import pagan @@ -49,6 +52,17 @@ def test_save(): img0.save(tmpdir, tmpfile) +def test_save_new_dir(): + """save file in not existing directory""" + img0 = pagan.Avatar("1") + tmpdir = tempfile.gettempdir() + testdir = ''.join(random.SystemRandom().choice(string.digits) + for _ in range(12)) + testdir = os.path.join(tmpdir, testdir) + testfile = tempfile.mkstemp("", dir=tmpdir)[1].split("/")[-1] + img0.save(testdir, testfile) + + if __name__ == "__main__": test_create() test_diffrent_hash() @@ -56,3 +70,4 @@ def test_save(): test_show() test_change() test_save() + test_save_new_dir() diff --git a/tools/console/pagan b/tools/console/pagan old mode 100644 new mode 100755 index ddecaf4..73c9b41 --- a/tools/console/pagan +++ b/tools/console/pagan @@ -3,6 +3,7 @@ import argparse import os +import string import pagan from pagan import generator @@ -11,29 +12,41 @@ parser.add_argument("input", nargs="+", help="string, basis of avatar computing") parser.add_argument("--show", action="store_true", help="show avatar in external editor, default behavior") +parser.add_argument("--noshow", action="store_true", + help="don't show avatar in external editor") parser.add_argument("--output", help="save image to specific output path") parser.add_argument("--hash", default="MD5", help="use hash function, allowed %s, default %s" % - (generator.HASHES.values(), list(generator.HASHES.values())[0])) + (generator.HASHES.values(), "MD5")) args = parser.parse_args() -slogan = " ".join(args.input) +INPUT = " ".join(args.input) if args.hash and args.hash not in generator.HASHES.values(): HASH = "" elif args.hash and args.hash in generator.HASHES.values(): - HASH = list(generator.HASHES.values()).index(args.hash) + # dict.keys() must not be right ordered + for key in generator.HASHES: + if args.hash == generator.HASHES[key]: + HASH = key + break -if not args.output: +if not args.output and not args.noshow: args.show = True -img = pagan.Avatar(slogan, HASH) -if args.show: +img = pagan.Avatar(INPUT, HASH) +if not args.noshow and args.show: img.show() if args.output: img.save(*os.path.split(args.output)) else: - img.save(os.getcwd(), filename=args.input[0]) \ No newline at end of file + filename = args.input[0] + # make filename save again + allowed = string.ascii_letters + string.digits + "+-_" + filename = "".join([((c in allowed) and c or "-") for c in filename]) + + img.save(os.getcwd(), + filename=filename) diff --git a/tools/webserver/Readme.md b/tools/webserver/Readme.md deleted file mode 100644 index 501ca58..0000000 --- a/tools/webserver/Readme.md +++ /dev/null @@ -1,2 +0,0 @@ -requirement: - bottle diff --git a/tools/webserver/webserver.py b/tools/webserver/webserver.py deleted file mode 100644 index e6bde68..0000000 --- a/tools/webserver/webserver.py +++ /dev/null @@ -1,118 +0,0 @@ -"""pagan webserver""" -from bottle import debug -from bottle import error -from bottle import post -from bottle import request -from bottle import response -from bottle import route -from bottle import run -from bottle import static_file -from bottle import template -import hashlib -import logging -import pagan -import tempfile - -logging.warning("\n%s\n\ -early work in progress, try at your own risk\n\ -this will pollute your temp dir!\n\ -%s" % ("= "*32, "= "*32)) - -TEMPLATEINDEX = """ -
-

pagan

-
-Welcome to the python avatar generator for absolute nerds. -

Generate your own Avatar. -

-

-
-
-
Current SearchPrevious Search
-

{{slogan}} -

-

- -

{{hist1}} -

-

{{hist2}} -

-

{{hist3}} -

-

-""" - - -@error(404) -def error404(code): - """handle error 404 """ - return template('{{code}} Avatar not found. You may use this:', - code=code) - - -@route('/') -@post('/') -def index(): - """main functionality of webserver""" - default = ["pagan", "python", "avatar", "github"] - slogan = request.forms.get("slogan") - - if not slogan: - if request.get_cookie("hist1"): - slogan = request.get_cookie("hist1") - else: - slogan = "pagan" - - if not request.get_cookie("hist1"): - hist1, hist2, hist3, hist4 = default[:] - else: - hist1 = request.get_cookie("hist1") - hist2 = request.get_cookie("hist2") - hist3 = request.get_cookie("hist3") - hist4 = request.get_cookie("hist4") - - if slogan in (hist1, hist2, hist3, hist4): - history = [hist1, hist2, hist3, hist4] - history.remove(slogan) - hist1, hist2, hist3 = history[0], history[1], history[2] - - response.set_cookie("hist1", slogan, max_age=60*60*24*30, httponly=True) - response.set_cookie("hist2", hist1, max_age=60*60*24*30, httponly=True) - response.set_cookie("hist3", hist2, max_age=60*60*24*30, httponly=True) - response.set_cookie("hist4", hist3, max_age=60*60*24*30, httponly=True) - # slogan, hist1, hist2, hist3 = escape(slogan), escape(hist1),\ - # escape(hist2), escape(hist3) - md5 = hashlib.md5() - md5.update(slogan) - slogan_hash = md5.hexdigest() - md5.update(hist1) - hist1_hash = md5.hexdigest() - md5.update(hist2) - hist2_hash = md5.hexdigest() - md5.update(hist3) - hist3_hash = md5.hexdigest() - return template(TEMPLATEINDEX, slogan=slogan, - hist1=hist1, hist2=hist2, hist3=hist3, - sloganHash=slogan_hash, hist1Hash=hist1_hash, - hist2Hash=hist2_hash, hist3Hash=hist3_hash) - - -@route('/himage/') -def hashimage(hashvalue): - """generate image by hash, usese tempfile :-/""" - tmpf = tempfile.mkstemp(".png")[1] - image = pagan.Avatar("") - image.img = pagan.generator.generate_by_hash(hashvalue) - image.save("/", tmpf) - return static_file(tmpf, root="/") - -debug(True) -run(host='localhost', port=8080) diff --git a/tox.ini b/tox.ini index cd1c311..3f31375 100644 --- a/tox.ini +++ b/tox.ini @@ -4,10 +4,11 @@ # and then run "tox" from this directory. [tox] -envlist = py27, py34, py35 +envlist = py27, py34, py35, py36 skip_missing_interpreters = True [testenv] commands = pytest deps = pytest + hypothesis