From e9fc58543d2b9f385d0bf245828fdeea1b60c0ae Mon Sep 17 00:00:00 2001 From: Neil Date: Sun, 14 Apr 2013 10:45:58 +0200 Subject: [PATCH 1/1] Import skellington --- .gitignore | 6 + BUGS.txt | 1 + CHANGES.txt | 7 + LICENSE.txt | 16 +++ Makefile | 71 ++++++++++ README.txt | 47 +++++++ TODO.txt | 5 + android.txt | 4 + configure | 4 + data/README.txt | 2 + erdslangetjie/__init__.py | 3 + erdslangetjie/__main__.py | 4 + erdslangetjie/data.py | 27 ++++ pyweek_upload.py | 198 +++++++++++++++++++++++++++ run_game.py | 3 + run_game.pyw | 3 + scripts/erdslangetjie | 6 + setup.py | 277 ++++++++++++++++++++++++++++++++++++++ 18 files changed, 684 insertions(+) create mode 100644 .gitignore create mode 100644 BUGS.txt create mode 100644 CHANGES.txt create mode 100644 LICENSE.txt create mode 100644 Makefile create mode 100644 README.txt create mode 100644 TODO.txt create mode 100644 android.txt create mode 100755 configure create mode 100644 data/README.txt create mode 100644 erdslangetjie/__init__.py create mode 100644 erdslangetjie/__main__.py create mode 100644 erdslangetjie/data.py create mode 100644 pyweek_upload.py create mode 100644 run_game.py create mode 100644 run_game.pyw create mode 100755 scripts/erdslangetjie create mode 100755 setup.py 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("..") -- 2.34.1