Thanks Mike. I'll be sure to read all this stuff before we meet up next week.
-Ingy On Tue, Jul 7, 2009 at 6:09 PM, Mike Orr <[email protected]> wrote: > On Tue, Jul 7, 2009 at 1:35 PM, Ingy dot Net<[email protected]> wrote: > > > 0) Primarily want a code review of what I have on > > http://github.com/ingydotnet/testml-py/ > > I can look at that later. > > > 1) Runtime introspection - there is all kinds of things I'm having > trouble > > finding at runtime. Like maybe I want to know what the file path is of > the > > current python module that py.test is executing for me. > > If you mean, "What is the path of the currently-executing module?", > that's ``__file__``. > > > Also note ``__name__``, which is the module's fully-qualified name (or > "__main__" if the file was run directly as a script). > > Imported modules are cached in sys.modules as {'name': <module>}. You > can inspect the module object for metainfo. > > > 1b) Stack trace introspection. > > That gets into a specialized area of Python which most people don't > do. You can raise a bogus exception and assign the traceback to a > variable. From there the ``inspect`` module might help, as well as > your old friends str(e), repr(e), dir(e), vars(e), and help(e). > > http://docs.python.org/library/inspect.html > (See especially the "interpreter stack" section) > > > 2) Popular idioms. I get the feeling that try/except usage is much more > > common than in Perl. > > try/except provides a way to isolate error code, little-used code, or > out-of-band code. It can also be (ab)used to provide an alternate > return value if the function has special cases. There's no speed > penalty for try if no exception is raised. > > The main difference between 'if' and 'try' is that 'if' suggests that > any branch might be taken in a normal case, while 'except' suggests > that this branch should rarely if ever happen. Of course, you can't > be 100% strict on this. It might be more elegent to have an > 'if/elif/elif/else' where the 'else' should never happen. Conversely, > you may be forced to use 'try' because a third-party function raises > an exception. > > Also note the differences between the exceptions. > 'ValueError': a function argument has the right type but an illegal value. > 'TypeError': a function argument contains a more serious error than > ValueError, or a > variable unexpectedly has the wrong type. > 'AssertionError': two parts of your own code appear to be > inconsistent. E.g., if one > routine builds a data structure and another routine reads it, or > if a variable that > should have been set is unexpectedly None. Useful in an 'else' > that should never > happen. Not normally used for function argument errors, or for errors > in > third-party code. > 'NotImplementedError': a good stub for functions that haven't been written, > for > superclass methods that must be overridden, or to ensure that > destructive code > doesn't get executed during development. > 'EnvironmentError': something is wrong in the runtime environment. > This could be > used for missing files or environment variables, unavailable > servers, invalid > configuration, etc. However, there are no standard rules for > which exceptions to > raise in these cases. You could ignore the condition and let > third-party code raise > OSError, KeyError, etc. However, this may confuse the user, > especially if the > error message is imprecise. > 'RuntimeError': specifically means miscellaneous error, something that > has no better > category. Useful for temporary situations during development, > especially to > inspect live code under pdb. Some people also use it for > environment/configuration > errors in the top-level script. > > There are other idioms but I can't think of them off the top of my > head. Remember that subscripting and ranges are open at the right > end, so that ``range(5)`` goes 0 to 4, and ``lis[1:3]`` gets elements > 1 and 2. > > When setting default values for functions, never use a mutable value: > > def func(lis=[], dic={}) # Bad > > The same list and dict will be shared across all calls to the > function, which will royally confuse users. Instead use a dummy > immutable value such as None: > > def func(lis=None): > if lis is None: > lis = [] > > > 3) Accessing global variables across modules. I spent 2 hours yesterday > on > > this, and still feel clueless. > > They are attributes of the module object. So first get the module via > import or an argument or sys.modules. Then use dotted notation if you > know the name of the variable beforehand, or getattr() if you're not > sure it exists or have to calcuate the name. You can also call > vars(m) to get the globals in dict form, but this is read-only. > > > 4) How the popular python test frameworks work. > > I'm not an expert on this but we can discuss it in person. Nose is > the fastest-growing test framework. The others are unittest and > py.test. There are several other test frameworks specific to web > applications, but I don't know if you're interested in that. > > > 5) Module installation and distribution best practices. > > There are currently two overlapping conventions for this. "distutils" > is built into Python and revolves around a setup.py file in the > package. Users can download the package manually, unpack it, and run > "python setup.py install". The distutils conventions are sufficient > for small packages. > > http://docs.python.org/library/distutils.html > http://docs.python.org/distutils/index.html#distutils-index > http://docs.python.org/install/index.html#install-index > > "setuptools" is a superset of distutils with more features, both in > the setup.py and in the installation procedure. "easy_install" comes > with setuptools, which can download and install a package in one step. > Larger packages may need setuptools' features and convenience > functions. Setuptools is not built into Python so you have to install > it separately. > > http://peak.telecommunity.com/ > (See the links under the third entry dated Friday, September 16, 2005) > > "pip" is an alternative to "easy_install". It's more modern but has > had less use and testing. Due to bootstrapping issues, you have to > manually install setuptools first, then "easy_install pip", and then > you can "pip install" everything else. Pip creates a slightly > different directory structure than easy_install, one that's preferred > by pip fans and is closer to the traditional Python structure. > > http://pypi.python.org/pypi/pip > > Any of these installation methods can be used on any package, no > matter which one it was built for. The only caveat is that if the > setup.py depends on setuptools features, the user will have had to > install setuptools beforehand, or else the application developer will > have had to put a trick into setup.py to auto-download setuptools. > > "virtualenv" creates an isolated Python runtime environment, into > which you can install packages that won't be seen outside the > environment. This is useful if you have two programs that need > conflicting library versions, or to create a test environment that can > be blown away and recreated easily. Virtualenv installs Setuptools in > the environment automatically, so that's one less step to do. > > http://pypi.python.org/pypi/virtualenv > > "virtualenvwrapper" is a set of command-line utilities for virtualenv. > It depends on Bash, so it doesn't work on Windows. > > http://pypi.python.org/pypi/virtualenvwrapper/1.18 > > "buildout" (officially "zc.buildout") is a way to make a repeatable > custom environment, such as for a server farm. Its functionality > overlaps with virtualenv, but it does it in a different way. Some > people find its configuration file harder to understand. Buildout is > more often used to create a deployment configuration for a finished > product, than for interactively trying out libraries during > development. Interestingly, buildout can be used within a virtualenv. > > http://pypi.python.org/pypi/zc.buildout > > -- > Mike Orr <[email protected]> >
