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]>
>

Reply via email to