From: Neil Date: Sun, 14 Apr 2013 08:45:58 +0000 (+0200) Subject: Import skellington X-Git-Url: https://git.ctpug.org.za/?a=commitdiff_plain;ds=inline;h=e9fc58543d2b9f385d0bf245828fdeea1b60c0ae;p=erdslangetjie.git Import skellington --- e9fc58543d2b9f385d0bf245828fdeea1b60c0ae diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..064bcac --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.py[cod] +*.so +*.egg +*.egg-info +.*.swp +*~ diff --git a/BUGS.txt b/BUGS.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/BUGS.txt @@ -0,0 +1 @@ + diff --git a/CHANGES.txt b/CHANGES.txt new file mode 100644 index 0000000..9da9763 --- /dev/null +++ b/CHANGES.txt @@ -0,0 +1,7 @@ + +Changes +======= + + + + diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..3529d2f --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,16 @@ +Licence: ISC + +Copyright (c) 2013, Neil Muller (http://www.pyweek.org/u/drnlm/) + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a8f26bb --- /dev/null +++ b/Makefile @@ -0,0 +1,71 @@ +#fake Makefile for erdslangetjie, to support the common +# ./configure;make;make install + +PYTHON = python + +#build: Setup setup.py +build: setup.py + $(PYTHON) setup.py build + +#install: Setup setup.py +install: setup.py + $(PYTHON) setup.py install + +#Setup: +# $(PYTHON) configure.py + +test check tests: + $(PYTHON) run_tests.py + +testall: + #python2.5 setup.py test + python2.7 setup.py test + #python3.1 setup.py test + make checkdocs + +#docs: install +# cd docs/utils +# $(PYTHON) makedocs.py + +clean: + rm -rf build dist MANIFEST .coverage + rm -f erdslangetjie/*~ + rm -rf bin develop-eggs eggs parts .installed.cfg erdslangetjie.egg-info + find . -name *.pyc -exec rm {} \; + find . -name *.swp -exec rm {} \; + $(PYTHON) setup.py clean + +# push changes +push: + #bzr push lp:erdslangetjie + #svn commit + git commit + +# commit changes +commit: + #bzr commit + git commit + +#upload to pypi +upload: + make clean + #if you have your gpg key set up... sign your release. + #$(PYTHON) setup.py sdist upload --sign --identity="Your Name " + $(PYTHON) setup.py sdist upload + +sdist: + make clean + make testall + $(PYTHON) setup.py sdist + +checkdocs: + $(PYTHON) setup.py checkdocs -setuptools + +showdocs: + $(PYTHON) setup.py showdocs -setuptools + +coverage: + coverage run run_tests.py + coverage report -m + + diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..45794d4 --- /dev/null +++ b/README.txt @@ -0,0 +1,47 @@ +Peter's Thread Snake +===================== + +Entry in PyWeek #16 +URL: http://www.pyweek.org/e/erdslangetjie +Team: erdslangetjie +Members: Neil Muller (drnlm) +License: see LICENSE.txt + + +Running the Game +---------------- + +On Windows or Mac OS X, locate the "run_game.pyw" file and double-click it. + +Othewise open a terminal / console and "cd" to the game directory and run: + + python run_game.py + + +How to Play the Game +-------------------- + +TODO + + +Development notes +----------------- + +Creating a source distribution with:: + + python setup.py sdist + +You may also generate Windows executables and OS X applications:: + + python setup.py py2exe + python setup.py py2app + +Upload files to PyWeek with:: + + python pyweek_upload.py + +Upload to the Python Package Index with:: + + python setup.py register + python setup.py sdist upload + diff --git a/TODO.txt b/TODO.txt new file mode 100644 index 0000000..1bad070 --- /dev/null +++ b/TODO.txt @@ -0,0 +1,5 @@ + + +TODO +==== + diff --git a/android.txt b/android.txt new file mode 100644 index 0000000..d911c4c --- /dev/null +++ b/android.txt @@ -0,0 +1,4 @@ +title=Peter's Thread Snake +author=Neil Muller +api=1 +orientation=landscape diff --git a/configure b/configure new file mode 100755 index 0000000..546f631 --- /dev/null +++ b/configure @@ -0,0 +1,4 @@ +#fake configure for pywebsite, to support the common +# ./configure;make;make install + +#python config.py -auto diff --git a/data/README.txt b/data/README.txt new file mode 100644 index 0000000..18bcae8 --- /dev/null +++ b/data/README.txt @@ -0,0 +1,2 @@ +Place your game's data files in here (images, fonts, map files, sounds, +etc). diff --git a/erdslangetjie/__init__.py b/erdslangetjie/__init__.py new file mode 100644 index 0000000..6cd298b --- /dev/null +++ b/erdslangetjie/__init__.py @@ -0,0 +1,3 @@ +if __name__ == "__main__": + import main + main.main() diff --git a/erdslangetjie/__main__.py b/erdslangetjie/__main__.py new file mode 100644 index 0000000..dbb20cd --- /dev/null +++ b/erdslangetjie/__main__.py @@ -0,0 +1,4 @@ + +def main(): + """ your app starts here + """ diff --git a/erdslangetjie/data.py b/erdslangetjie/data.py new file mode 100644 index 0000000..66b66bb --- /dev/null +++ b/erdslangetjie/data.py @@ -0,0 +1,27 @@ +'''Simple data loader module. + +Loads data files from the "data" directory shipped with a game. + +Enhancing this to handle caching etc. is left as an exercise for the reader. + +Note that pyglet users should probably just add the data directory to the +pyglet.resource search path. +''' + +import os + +data_py = os.path.abspath(os.path.dirname(__file__)) +data_dir = os.path.normpath(os.path.join(data_py, '..', 'data')) + +def filepath(filename): + '''Determine the path to a file in the data directory. + ''' + return os.path.join(data_dir, filename) + +def load(filename, mode='rb'): + '''Open a file in the data directory. + + "mode" is passed as the second arg to open(). + ''' + return open(os.path.join(data_dir, filename), mode) + diff --git a/pyweek_upload.py b/pyweek_upload.py new file mode 100644 index 0000000..053a0cc --- /dev/null +++ b/pyweek_upload.py @@ -0,0 +1,198 @@ +''' +Upload script specifically engineered for the PyWeek challenge. + +Handles authentication and gives upload progress feedback. +''' +import sys, os, httplib, cStringIO, socket, time, getopt + +class Upload: + def __init__(self, filename): + self.filename = filename + +boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' +sep_boundary = '\n--' + boundary +end_boundary = sep_boundary + '--' + +def mimeEncode(data, sep_boundary=sep_boundary, end_boundary=end_boundary): + '''Take the mapping of data and construct the body of a + multipart/form-data message with it using the indicated boundaries. + ''' + ret = cStringIO.StringIO() + for key, value in data.items(): + # handle multiple entries for the same name + if type(value) != type([]): value = [value] + for value in value: + ret.write(sep_boundary) + if isinstance(value, Upload): + ret.write('\nContent-Disposition: form-data; name="%s"'%key) + filename = os.path.basename(value.filename) + ret.write('; filename="%s"\n\n'%filename) + value = open(os.path.join(value.filename), "rb").read() + else: + ret.write('\nContent-Disposition: form-data; name="%s"'%key) + ret.write("\n\n") + value = str(value) + ret.write(str(value)) + if value and value[-1] == '\r': + ret.write('\n') # write an extra newline + ret.write(end_boundary) + return ret.getvalue() + +class Progress: + def __init__(self, info, data): + self.info = info + self.tosend = len(data) + self.total = self.tosend/1024 + self.data = cStringIO.StringIO(data) + self.start = self.now = time.time() + self.sent = 0 + self.num = 0 + self.stepsize = self.total / 100 or 1 + self.steptimes = [] + self.display() + + def __iter__(self): return self + + def next(self): + self.num += 1 + if self.sent >= self.tosend: + print self.info, 'done', ' '*(75-len(self.info)-6) + sys.stdout.flush() + raise StopIteration + + chunk = self.data.read(1024) + self.sent += len(chunk) + #print (self.num, self.stepsize, self.total, self.sent, self.tosend) + + if self.num % self.stepsize: + return chunk + self.display() + return chunk + + def display(self): + # figure how long we've spent - guess how long to go + now = time.time() + steptime = now - self.now + self.steptimes.insert(0, steptime) + if len(self.steptimes) > 5: + self.steptimes.pop() + steptime = sum(self.steptimes) / len(self.steptimes) + self.now = now + eta = steptime * ((self.total - self.num)/self.stepsize) + + # tell it like it is (or might be) + if now - self.start > 3: + M = eta / 60 + H = M / 60 + M = M % 60 + S = eta % 60 + if self.total: + s = '%s %2d%% (ETA %02d:%02d:%02d)'%(self.info, + self.num * 100. / self.total, H, M, S) + else: + s = '%s 0%% (ETA %02d:%02d:%02d)'%(self.info, H, M, S) + elif self.total: + s = '%s %2d%%'%(self.info, self.num * 100. / self.total) + else: + s = '%s %d done'%(self.info, self.num) + sys.stdout.write(s + ' '*(75-len(s)) + '\r') + sys.stdout.flush() + +class progressHTTPConnection(httplib.HTTPConnection): + def progress_send(self, str): + """Send `str' to the server.""" + if self.sock is None: + self.connect() + + p = Progress('Uploading', str) + for chunk in p: + sent = 0 + while sent != len(chunk): + try: + sent += self.sock.send(chunk) + except socket.error, v: + if v[0] == 32: # Broken pipe + self.close() + raise + p.display() + +class progressHTTP(httplib.HTTP): + _connection_class = progressHTTPConnection + def _setup(self, conn): + httplib.HTTP._setup(self, conn) + self.progress_send = self._conn.progress_send + +def http_request(data, server, port, url): + h = progressHTTP(server, port) + + data = mimeEncode(data) + h.putrequest('POST', url) + h.putheader('Content-type', 'multipart/form-data; boundary=%s'%boundary) + h.putheader('Content-length', str(len(data))) + h.putheader('Host', server) + h.endheaders() + + h.progress_send(data) + + errcode, errmsg, headers = h.getreply() + + f = h.getfile() + response = f.read().strip() + f.close() + + print '%s %s'%(errcode, errmsg) + if response: print response + +def usage(): + print '''This program is to be used to upload files to the PyWeek system. +You may use it to upload screenshots or code submissions. + +REQUIRED ARGUMENTS: + -u username + -p password + -d description of file + -c file to upload + -e entry short name + +OPTIONAL ARGUMENTS: + -s file is a screenshot + -f file is FINAL submission + -h override default host name (www.pyweek.org) + -P override default host port (80) + +In order to qualify for judging at the end of the challenge, you MUST +upload your source and check the "Final Submission" checkbox. +''' + + +if __name__ == '__main__': + try: + optlist, args = getopt.getopt(sys.argv[1:], 'e:u:p:sfd:h:P:c:') + except getopt.GetoptError, message: + print message + usage() + sys.exit(1) + host = 'www.pyweek.org' + port = 80 + data = dict(version=2) + optional = {} + url = None + for opt, arg in optlist: + if opt == '-u': data['user'] = arg + elif opt == '-p': data['password'] = arg + elif opt == '-s': optional['is_screenshot'] = 'yes' + elif opt == '-f': optional['is_final'] = 'yes' + elif opt == '-d': data['description'] = arg + elif opt == '-c': data['content_file'] = Upload(arg) + elif opt == '-e': url = '/e/%s/oup/'%arg + elif opt == '-h': host = arg + elif opt == '-P': port = int(arg) + + if len(data) < 4 or url is None: + print 'Required argument missing' + usage() + sys.exit(1) + + data.update(optional) + http_request(data, host, port, url) + diff --git a/run_game.py b/run_game.py new file mode 100644 index 0000000..56b5de8 --- /dev/null +++ b/run_game.py @@ -0,0 +1,3 @@ +import erdslangetjie.__main__ +if __name__ == "__main__": + erdslangetjie.__main__.main() diff --git a/run_game.pyw b/run_game.pyw new file mode 100644 index 0000000..871ff48 --- /dev/null +++ b/run_game.pyw @@ -0,0 +1,3 @@ +import erdslangetjie.main +if __name__ == "__main__": + erdslangetjie.main.main() diff --git a/scripts/erdslangetjie b/scripts/erdslangetjie new file mode 100755 index 0000000..44b3743 --- /dev/null +++ b/scripts/erdslangetjie @@ -0,0 +1,6 @@ +#!/usr/bin/env python + +import erdslangetjie.__main__ +if __name__ == "__main__": + erdslangetjie.__main__.main() + diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..8cf810a --- /dev/null +++ b/setup.py @@ -0,0 +1,277 @@ +import os + +# usage: python setup.py command +# +# sdist - build a source dist +# py2exe - build an exe +# py2app - build an app +# cx_freeze - build a linux binary (not implemented) +# +# the goods are placed in the dist dir for you to .zip up or whatever... + + +APP_NAME = 'erdslangetjie' +DESCRIPTION = open('README.txt').read() +CHANGES = open('CHANGES.txt').read() +TODO = open('TODO.txt').read() + + + +METADATA = { + 'name':APP_NAME, + 'version': '0.0.1', + 'license': 'short_licence', + 'description': 'TODO', + 'author': 'Neil Muller', + #'author_email': '', + 'url': 'http://www.pyweek.org/e/erdslangetjie', + 'classifiers': [ + 'Development Status :: 4 - Beta', + 'Intended Audience :: End Users/Desktop', + 'Intended Audience :: Information Technology', + 'License :: OSI Approved :: BSD License', + 'Operating System :: OS Independent', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.5', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.0', + 'Programming Language :: Python :: 3.1', + 'Programming Language :: Python :: 3.2', + 'Topic :: Software Development :: Libraries :: pygame', + 'Topic :: Games/Entertainment :: Real Time Strategy', + ], + + + 'py2exe.target':'', + #'py2exe.icon':'icon.ico', #64x64 + 'py2exe.binary':APP_NAME, #leave off the .exe, it will be added + + 'py2app.target':APP_NAME, + 'py2app.icon':'icon.icns', #128x128 + + #'cx_freeze.cmd':'~/src/cx_Freeze-3.0.3/FreezePython', + 'cx_freeze.cmd':'cxfreeze', + 'cx_freeze.target':'%s_linux' % APP_NAME, + 'cx_freeze.binary':APP_NAME, + } + +files_to_remove = ['tk84.dll', + '_ssl.pyd', + 'tcl84.dll', + os.path.join('numpy','core', '_dotblas.pyd'), + os.path.join('numpy', 'linalg', 'lapack_lite.pyd'), +] + + +directories_to_remove = [os.path.join('numpy', 'distutils'), + 'distutils', + 'tcl', +] + + +cmdclass = {} +PACKAGEDATA = { + 'cmdclass': cmdclass, + + 'package_dir': {'erdslangetjie': 'erdslangetjie', + }, + 'packages': ['erdslangetjie', + ], + 'scripts': ['scripts/erdslangetjie'], +} + +PACKAGEDATA.update(METADATA) + + +from distutils.core import setup, Extension +try: + import py2exe +except: + pass + +import sys +import glob +import os +import shutil + +try: + cmd = sys.argv[1] +except IndexError: + print 'Usage: setup.py install|py2exe|py2app|cx_freeze' + raise SystemExit + +# utility for adding subdirectories +def add_files(dest,generator): + for dirpath, dirnames, filenames in generator: + for name in 'CVS', '.svn': + if name in dirnames: + dirnames.remove(name) + + for name in filenames: + if '~' in name: continue + suffix = os.path.splitext(name)[1] + if suffix in ('.pyc', '.pyo'): continue + if name[0] == '.': continue + filename = os.path.join(dirpath, name) + dest.append(filename) + +# define what is our data +_DATA_DIR = os.path.join('erdslangetjie', 'data') +data = [] +add_files(data,os.walk(_DATA_DIR)) + + + + +#data_dirs = [os.path.join(f2.replace(_DATA_DIR, 'data'), '*') for f2 in data] +data_dirs = [os.path.join(f2.replace(_DATA_DIR, 'data')) for f2 in data] +PACKAGEDATA['package_data'] = {'erdslangetjie': data_dirs} + + + + + +data.extend(glob.glob('*.txt')) +#data.append('MANIFEST.in') +# define what is our source +src = [] +add_files(src,os.walk('erdslangetjie')) +src.extend(glob.glob('*.py')) + + + + +# build the sdist target +if cmd not in "py2exe py2app cx_freeze".split(): + f = open("MANIFEST.in","w") + for l in data: f.write("include "+l+"\n") + for l in src: f.write("include "+l+"\n") + f.close() + + setup(**PACKAGEDATA) + +# build the py2exe target +if cmd in ('py2exe',): + dist_dir = os.path.join('dist',METADATA['py2exe.target']) + data_dir = dist_dir + + src = 'run_game.py' + dest = METADATA['py2exe.binary']+'.py' + shutil.copy(src,dest) + + setup( + options={'py2exe':{ + 'dist_dir':dist_dir, + 'dll_excludes':['_dotblas.pyd','_numpy.pyd', 'numpy.linalg.lapack_lite.pyd', 'numpy.core._dotblas.pyd'] + files_to_remove, + 'excludes':['matplotlib', 'tcl', 'OpenGL'], + 'ignores':['matplotlib', 'tcl', 'OpenGL'], + 'bundle_files':1, + }}, +# windows=[{ + console=[{ + 'script':dest, + #'icon_resources':[(1,METADATA['py2exe.icon'])], + }], + ) + +# build the py2app target +if cmd == 'py2app': + dist_dir = os.path.join('dist',METADATA['py2app.target']+'.app') + data_dir = os.path.join(dist_dir,'Contents','Resources') + from setuptools import setup + + src = 'run_game.py' + dest = METADATA['py2app.target']+'.py' + shutil.copy(src,dest) + + APP = [dest] + DATA_FILES = [] + OPTIONS = {'argv_emulation': True, + #'iconfile':METADATA['py2app.icon'] + } + + setup( + app=APP, + data_files=DATA_FILES, + options={'py2app': OPTIONS}, + setup_requires=['py2app'], + ) + +# make the cx_freeze target +if cmd == 'cx_freeze': + app_dist_dir = METADATA['cx_freeze.target'] + "_" + METADATA['version'] + dist_dir = os.path.join('dist', app_dist_dir) + data_dir = dist_dir + + modules_exclude = "tcl,tk" + cmd_args = (METADATA['cx_freeze.cmd'], dist_dir, METADATA['cx_freeze.binary'], modules_exclude) + sys_cmd = '%s --install-dir=%s --target-name=%s --exclude-modules=%s run_game.py' % cmd_args + print sys_cmd + os.system(sys_cmd) + + import shutil + if os.path.exists(os.path.join(data_dir, "tcl")): + shutil.rmtree( os.path.join(data_dir, "tcl") ) + if os.path.exists(os.path.join(data_dir, "tk")): + shutil.rmtree( os.path.join(data_dir, "tk") ) + + + +# recursively make a bunch of folders +def make_dirs(dname_): + parts = list(os.path.split(dname_)) + dname = None + while len(parts): + if dname == None: + dname = parts.pop(0) + else: + dname = os.path.join(dname,parts.pop(0)) + if not os.path.isdir(dname): + os.mkdir(dname) + +# copy data into the binaries +if cmd in ('py2exe','cx_freeze','py2app'): + dest = data_dir + for fname in data: + dname = os.path.join(dest,os.path.dirname(fname)) + make_dirs(dname) + if not os.path.isdir(fname): + #print (fname,dname) + shutil.copy(fname,dname) + +# make a tgz files. +if cmd == 'cx_freeze': + sys_cmd = "cd dist; tar -vczf %s.tgz %s/" % (app_dist_dir,app_dist_dir) + os.system(sys_cmd) + + +# remove files from the zip. +if 0 and cmd in ('py2exe'): + import shutil + + #shutil.rmtree( os.path.join('dist') ) + #shutil.rmtree( os.path.join('build') ) + + + os.system("unzip dist/library.zip -d dist\library") + + for fn in files_to_remove: + os.remove( os.path.join('dist', 'library', fn) ) + + + for d in directories_to_remove: + if os.path.exists( os.path.join('dist', 'library', d) ): + shutil.rmtree( os.path.join('dist', 'library', d) ) + + os.remove( os.path.join('dist', 'library.zip') ) + + + os.chdir("dist") + os.chdir("library") + + os.system("zip -r -9 ..\library.zip .") + + os.chdir("..") + os.chdir("..")