From e008b993e7c4f7975460ff54873de5aabb6a74bd Mon Sep 17 00:00:00 2001 From: Mike Naberezny Date: Wed, 10 Sep 2008 02:34:04 +0000 Subject: [PATCH] Organize into package. --- ez_setup.py | 229 ++++++++++++++++++ setup.py | 84 +++++++ src/py65/__init__.py | 1 + memory.py => src/py65/memory.py | 0 monitor.py => src/py65/monitor.py | 7 +- mpu.py => src/py65/mpu6502.py | 18 +- src/py65/tests/__init__.py | 14 ++ .../py65/tests/test_monitor.py | 2 +- mpu_test.py => src/py65/tests/test_mpu6502.py | 2 +- util.py => src/py65/util.py | 0 src/py65/version.txt | 1 + 11 files changed, 343 insertions(+), 15 deletions(-) create mode 100644 ez_setup.py create mode 100644 setup.py create mode 100644 src/py65/__init__.py rename memory.py => src/py65/memory.py (100%) rename monitor.py => src/py65/monitor.py (99%) rename mpu.py => src/py65/mpu6502.py (98%) create mode 100644 src/py65/tests/__init__.py rename monitor_test.py => src/py65/tests/test_monitor.py (98%) rename mpu_test.py => src/py65/tests/test_mpu6502.py (99%) rename util.py => src/py65/util.py (100%) create mode 100644 src/py65/version.txt diff --git a/ez_setup.py b/ez_setup.py new file mode 100644 index 0000000..6473c14 --- /dev/null +++ b/ez_setup.py @@ -0,0 +1,229 @@ +#!python +"""Bootstrap setuptools installation + +If you want to use setuptools in your package's setup.py, just include this +file in the same directory with it, and add this to the top of your setup.py:: + + from ez_setup import use_setuptools + use_setuptools() + +If you want to require a specific version of setuptools, set a download +mirror, or use an alternate download directory, you can do so by supplying +the appropriate options to ``use_setuptools()``. + +This file can also be run as a script to install or upgrade setuptools. +""" +import sys +DEFAULT_VERSION = "0.6c7" +DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3] + +md5_data = { + 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca', + 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb', + 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b', + 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a', + 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618', + 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac', + 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5', + 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4', + 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c', + 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b', + 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27', + 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277', + 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa', + 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e', + 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e', + 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f', + 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2', + 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc', + 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167', + 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64', + 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d', + 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20', + 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab', + 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53', + 'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2', + 'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e', + 'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372', +} + +import sys, os + +def _validate_md5(egg_name, data): + if egg_name in md5_data: + from md5 import md5 + digest = md5(data).hexdigest() + if digest != md5_data[egg_name]: + print >>sys.stderr, ( + "md5 validation of %s failed! (Possible download problem?)" + % egg_name + ) + sys.exit(2) + return data + + +def use_setuptools( + version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, + download_delay=15 +): + """Automatically find/download setuptools and make it available on sys.path + + `version` should be a valid setuptools version number that is available + as an egg for download under the `download_base` URL (which should end with + a '/'). `to_dir` is the directory where setuptools will be downloaded, if + it is not already available. If `download_delay` is specified, it should + be the number of seconds that will be paused before initiating a download, + should one be required. If an older version of setuptools is installed, + this routine will print a message to ``sys.stderr`` and raise SystemExit in + an attempt to abort the calling script. + """ + try: + import setuptools + if setuptools.__version__ == '0.0.1': + print >>sys.stderr, ( + "You have an obsolete version of setuptools installed. Please\n" + "remove it from your system entirely before rerunning this script." + ) + sys.exit(2) + except ImportError: + egg = download_setuptools(version, download_base, to_dir, download_delay) + sys.path.insert(0, egg) + import setuptools; setuptools.bootstrap_install_from = egg + + import pkg_resources + try: + pkg_resources.require("setuptools>="+version) + + except pkg_resources.VersionConflict, e: + # XXX could we install in a subprocess here? + print >>sys.stderr, ( + "The required version of setuptools (>=%s) is not available, and\n" + "can't be installed while this script is running. Please install\n" + " a more recent version first.\n\n(Currently using %r)" + ) % (version, e.args[0]) + sys.exit(2) + +def download_setuptools( + version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, + delay = 15 +): + """Download setuptools from a specified location and return its filename + + `version` should be a valid setuptools version number that is available + as an egg for download under the `download_base` URL (which should end + with a '/'). `to_dir` is the directory where the egg will be downloaded. + `delay` is the number of seconds to pause before an actual download attempt. + """ + import urllib2, shutil + egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) + url = download_base + egg_name + saveto = os.path.join(to_dir, egg_name) + src = dst = None + if not os.path.exists(saveto): # Avoid repeated downloads + try: + from distutils import log + if delay: + log.warn(""" +--------------------------------------------------------------------------- +This script requires setuptools version %s to run (even to display +help). I will attempt to download it for you (from +%s), but +you may need to enable firewall access for this script first. +I will start the download in %d seconds. + +(Note: if this machine does not have network access, please obtain the file + + %s + +and place it in this directory before rerunning this script.) +---------------------------------------------------------------------------""", + version, download_base, delay, url + ); from time import sleep; sleep(delay) + log.warn("Downloading %s", url) + src = urllib2.urlopen(url) + # Read/write all in one block, so we don't create a corrupt file + # if the download is interrupted. + data = _validate_md5(egg_name, src.read()) + dst = open(saveto,"wb"); dst.write(data) + finally: + if src: src.close() + if dst: dst.close() + return os.path.realpath(saveto) + +def main(argv, version=DEFAULT_VERSION): + """Install or upgrade setuptools and EasyInstall""" + + try: + import setuptools + except ImportError: + egg = None + try: + egg = download_setuptools(version, delay=0) + sys.path.insert(0,egg) + from setuptools.command.easy_install import main + return main(list(argv)+[egg]) # we're done here + finally: + if egg and os.path.exists(egg): + os.unlink(egg) + else: + if setuptools.__version__ == '0.0.1': + # tell the user to uninstall obsolete version + use_setuptools(version) + + req = "setuptools>="+version + import pkg_resources + try: + pkg_resources.require(req) + except pkg_resources.VersionConflict: + try: + from setuptools.command.easy_install import main + except ImportError: + from easy_install import main + main(list(argv)+[download_setuptools(delay=0)]) + sys.exit(0) # try to force an exit + else: + if argv: + from setuptools.command.easy_install import main + main(argv) + else: + print "Setuptools version",version,"or greater has been installed." + print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' + + + +def update_md5(filenames): + """Update our built-in md5 registry""" + + import re + from md5 import md5 + + for name in filenames: + base = os.path.basename(name) + f = open(name,'rb') + md5_data[base] = md5(f.read()).hexdigest() + f.close() + + data = [" %r: %r,\n" % it for it in md5_data.items()] + data.sort() + repl = "".join(data) + + import inspect + srcfile = inspect.getsourcefile(sys.modules[__name__]) + f = open(srcfile, 'rb'); src = f.read(); f.close() + + match = re.search("\nmd5_data = {\n([^}]+)}", src) + if not match: + print >>sys.stderr, "Internal error!" + sys.exit(2) + + src = src[:match.start(1)] + repl + src[match.end(1):] + f = open(srcfile,'w') + f.write(src) + f.close() + + +if __name__=='__main__': + if len(sys.argv)>2 and sys.argv[1]=='--md5update': + update_md5(sys.argv[2:]) + else: + main(sys.argv[1:]) diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..76ad57c --- /dev/null +++ b/setup.py @@ -0,0 +1,84 @@ +__revision__ = '$Id$' + +import urllib +import urllib2 +if not hasattr(urllib2, 'splituser'): + # setuptools wants to import this from urllib2 but it's not + # in there in Python 2.3.3, so we just alias it. + urllib2.splituser = urllib.splituser + +from ez_setup import use_setuptools +use_setuptools() + +import os +import sys +import string + +version, extra = string.split(sys.version, ' ', 1) +maj, minor = string.split(version, '.', 1) + +if not maj[0] >= '2' and minor[0] >= '3': + msg = ("Py65 requires Python 2.3 or better, you are attempting to " + "install it using version %s. Please install with a " + "supported version" % version) + +from setuptools import setup, find_packages +here = os.path.abspath(os.path.normpath(os.path.dirname(__file__))) + +DESC = """\ +Py65 is a simulation of the original NMOS 6502 microprocessor +from MOS Technology, written in Python. """ + +CLASSIFIERS = [ + 'Development Status :: 3 - Alpha', + 'Environment :: Console', + 'Intended Audience :: Developers', + 'Natural Language :: English', + 'Operating System :: POSIX', + 'Programming Language :: Assembly', + 'Topic :: Software Development :: Assemblers', + 'Topic :: Software Development :: Disassemblers', + 'Topic :: Software Development :: Debuggers', + 'Topic :: Software Development :: Embedded Systems', + 'Topic :: Software Development :: Interpreters', + 'Topic :: System :: Emulators', + 'Topic :: System :: Hardware' + ] + +version_txt = os.path.join(here, 'src/py65/version.txt') +py65_version = open(version_txt).read().strip() + +dist = setup( + name = 'py65', + version = py65_version, + license = '', + url = '', + download_url = '', + description = '6502 microprocessor simulation package', + long_description= DESC, + classifiers = CLASSIFIERS, + author = "Mike Naberezny", + author_email = "mike@naberezny.com", + maintainer = "Mike Naberezny", + maintainer_email = "mike@naberezny.com", + package_dir = {'':'src'}, + packages = find_packages(os.path.join(here, 'src')), + # put data files in egg 'doc' dir + data_files=[ ('doc', [ + 'README.txt', + 'TODO.txt', + ] + )], + install_requires = [], + extras_require = {}, + tests_require = [], + include_package_data = True, + zip_safe = False, + namespace_packages = ['py65'], + test_suite = "py65.tests", + entry_points = { + 'console_scripts': [ + 'py65mon = py65.monitor:main', + ], + }, +) diff --git a/src/py65/__init__.py b/src/py65/__init__.py new file mode 100644 index 0000000..de40ea7 --- /dev/null +++ b/src/py65/__init__.py @@ -0,0 +1 @@ +__import__('pkg_resources').declare_namespace(__name__) diff --git a/memory.py b/src/py65/memory.py similarity index 100% rename from memory.py rename to src/py65/memory.py diff --git a/monitor.py b/src/py65/monitor.py similarity index 99% rename from monitor.py rename to src/py65/monitor.py index 549f6b7..865d433 100644 --- a/monitor.py +++ b/src/py65/monitor.py @@ -5,10 +5,9 @@ import os import re import shlex import asyncore -from cmd import Cmd -from mpu import MPU -from util import itoa -from memory import ObservableMemory +from py65.mpu6502 import MPU +from py65.util import itoa +from py65.memory import ObservableMemory class Monitor(cmd.Cmd): diff --git a/mpu.py b/src/py65/mpu6502.py similarity index 98% rename from mpu.py rename to src/py65/mpu6502.py index 4c839f7..2ff40a2 100644 --- a/mpu.py +++ b/src/py65/mpu6502.py @@ -1,4 +1,4 @@ -from util import convert_to_bin, convert_to_bcd +from py65 import util class MPU: # vectors @@ -248,7 +248,7 @@ class MPU: tmp = 1 else: tmp = 0 - data = convert_to_bin(data) + convert_to_bin(self.a) + tmp + data = util.convert_to_bin(data) + util.convert_to_bin(self.a) + tmp self.flags &= ~(self.CARRY+self.OVERFLOW+self.NEGATIVE+self.ZERO) if data > 99: self.flags |= self.CARRY + self.OVERFLOW @@ -258,7 +258,7 @@ class MPU: self.flags |= self.ZERO else: self.flags |= data & 128 - self.a = convert_to_bcd(data) + self.a = util.convert_to_bcd(data) else: if self.flags & self.CARRY: tmp = 1 @@ -338,7 +338,7 @@ class MPU: else: borrow = 1 - data = convert_to_bin(self.a) - convert_to_bin(data) - borrow + data = util.convert_to_bin(self.a) - util.convert_to_bin(data) - borrow self.flags &= ~(self.CARRY + self.ZERO + self.NEGATIVE + self.OVERFLOW) if data == 0: self.flags |= self.ZERO + self.CARRY @@ -347,7 +347,7 @@ class MPU: else: self.flags |= self.NEGATIVE data +=100 - self.a = convert_to_bcd(data) + self.a = util.convert_to_bcd(data) else: if self.flags & self.CARRY: borrow = 0 @@ -668,7 +668,7 @@ class MPU: tmp = 0 if self.flags & self.DECIMAL: - data = convert_to_bin(data) + convert_to_bin(self.a) + tmp + data = util.convert_to_bin(data) + util.convert_to_bin(self.a) + tmp self.flags &= ~(self.CARRY+self.OVERFLOW+self.NEGATIVE+self.ZERO) if data > 99: self.flags |= self.CARRY+self.OVERFLOW @@ -677,7 +677,7 @@ class MPU: self.flags |= self.ZERO else: self.flags |= self.data & 128 - self.a = convert_to_bcd(data) + self.a = util.convert_to_bcd(data) else: if self.flags & self.CARRY: tmp = 1 @@ -1043,7 +1043,7 @@ class MPU: tmp = 0 else: tmp = 1 - data = convert_to_bin(self.a) - convert_to_bin(data) - tmp + data = util.convert_to_bin(self.a) - util.convert_to_bin(data) - tmp self.flags &= ~(self.CARRY+self.ZERO+self.NEGATIVE+self.OVERFLOW) if data == 0: self.flags |= self.ZERO + self.CARRY @@ -1052,7 +1052,7 @@ class MPU: else: self.flags |= self.NEGATIVE data +=100 - self.a = convert_to_bcd(data) + self.a = util.convert_to_bcd(data) else: if self.flags & self.CARRY: tmp = 0 diff --git a/src/py65/tests/__init__.py b/src/py65/tests/__init__.py new file mode 100644 index 0000000..4f7f1b7 --- /dev/null +++ b/src/py65/tests/__init__.py @@ -0,0 +1,14 @@ +# this is a package +from unittest import TestCase +def assertTrue(self, value, extra=None): + if not value: + raise AssertionError(extra) +def assertFalse(self, value, extra=None): + if value: + raise AssertionError(extra) + +if not hasattr(TestCase, 'assertTrue'): # Python 2.3.3 + TestCase.assertTrue = assertTrue + +if not hasattr(TestCase, 'assertFalse'): # Pytthon 2.3.3 + TestCase.assertFalse = assertFalse diff --git a/monitor_test.py b/src/py65/tests/test_monitor.py similarity index 98% rename from monitor_test.py rename to src/py65/tests/test_monitor.py index 7dfc6cd..5009fe9 100644 --- a/monitor_test.py +++ b/src/py65/tests/test_monitor.py @@ -1,7 +1,7 @@ import unittest import sys import re -from monitor import Monitor +from py65.monitor import Monitor class MonitorTests(unittest.TestCase): def test__parsenum_hex_literal(self): diff --git a/mpu_test.py b/src/py65/tests/test_mpu6502.py similarity index 99% rename from mpu_test.py rename to src/py65/tests/test_mpu6502.py index a6f4b40..9984d67 100644 --- a/mpu_test.py +++ b/src/py65/tests/test_mpu6502.py @@ -1,6 +1,6 @@ import unittest import sys -from mpu import MPU +from py65.mpu6502 import MPU class MPUTests(unittest.TestCase): diff --git a/util.py b/src/py65/util.py similarity index 100% rename from util.py rename to src/py65/util.py diff --git a/src/py65/version.txt b/src/py65/version.txt new file mode 100644 index 0000000..6e6566c --- /dev/null +++ b/src/py65/version.txt @@ -0,0 +1 @@ +0.01