~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/pyutils.py

  • Committer: Vincent Ladeuil
  • Date: 2012-01-18 14:09:19 UTC
  • mto: This revision was merged to the branch mainline in revision 6468.
  • Revision ID: v.ladeuil+lp@free.fr-20120118140919-rlvdrhpc0nq1lbwi
Change set/remove to require a lock for the branch config files.

This means that tests (or any plugin for that matter) do not requires an
explicit lock on the branch anymore to change a single option. This also
means the optimisation becomes "opt-in" and as such won't be as
spectacular as it may be and/or harder to get right (nothing fails
anymore).

This reduces the diff by ~300 lines.

Code/tests that were updating more than one config option is still taking
a lock to at least avoid some IOs and demonstrate the benefits through
the decreased number of hpss calls.

The duplication between BranchStack and BranchOnlyStack will be removed
once the same sharing is in place for local config files, at which point
the Stack class itself may be able to host the changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2010 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
"""General Python convenience functions."""
 
18
 
 
19
from __future__ import absolute_import
 
20
 
 
21
import sys
 
22
 
 
23
 
 
24
def get_named_object(module_name, member_name=None):
 
25
    """Get the Python object named by a given module and member name.
 
26
 
 
27
    This is usually much more convenient than dealing with ``__import__``
 
28
    directly::
 
29
 
 
30
        >>> doc = get_named_object('bzrlib.pyutils', 'get_named_object.__doc__')
 
31
        >>> doc.splitlines()[0]
 
32
        'Get the Python object named by a given module and member name.'
 
33
 
 
34
    :param module_name: a module name, as would be found in sys.modules if
 
35
        the module is already imported.  It may contain dots.  e.g. 'sys' or
 
36
        'os.path'.
 
37
    :param member_name: (optional) a name of an attribute in that module to
 
38
        return.  It may contain dots.  e.g. 'MyClass.some_method'.  If not
 
39
        given, the named module will be returned instead.
 
40
    :raises: ImportError or AttributeError.
 
41
    """
 
42
    # We may have just a module name, or a module name and a member name,
 
43
    # and either may contain dots.  __import__'s return value is a bit
 
44
    # unintuitive, so we need to take care to always return the object
 
45
    # specified by the full combination of module name + member name.
 
46
    if member_name:
 
47
        # Give __import__ a from_list.  It will return the last module in
 
48
        # the dotted module name.
 
49
        attr_chain = member_name.split('.')
 
50
        from_list = attr_chain[:1]
 
51
        obj = __import__(module_name, {}, {}, from_list)
 
52
        for attr in attr_chain:
 
53
            obj = getattr(obj, attr)
 
54
    else:
 
55
        # We're just importing a module, no attributes, so we have no
 
56
        # from_list.  __import__ will return the first module in the dotted
 
57
        # module name, so we look up the module from sys.modules.
 
58
        __import__(module_name, globals(), locals(), [])
 
59
        obj = sys.modules[module_name]
 
60
    return obj
 
61
 
 
62
 
 
63
def calc_parent_name(module_name, member_name=None):
 
64
    """Determine the 'parent' of a given dotted module name and (optional)
 
65
    member name.
 
66
 
 
67
    The idea is that ``getattr(parent_obj, final_attr)`` will equal
 
68
    get_named_object(module_name, member_name).
 
69
 
 
70
    :return: (module_name, member_name, final_attr) tuple.
 
71
    """
 
72
# +SKIP is not recognized by python2.4
 
73
# Typical use is::
 
74
 
75
#     >>> parent_mod, parent_member, final_attr = calc_parent_name(
 
76
#     ...     module_name, member_name) # doctest: +SKIP
 
77
#     >>> parent_obj = get_named_object(parent_mod, parent_member)
 
78
#     ... # doctest: +SKIP
 
79
    if member_name is not None:
 
80
        split_name = member_name.rsplit('.', 1)
 
81
        if len(split_name) == 1:
 
82
            return (module_name, None, member_name)
 
83
        else:
 
84
            return (module_name, split_name[0], split_name[1])
 
85
    else:
 
86
        split_name = module_name.rsplit('.', 1)
 
87
        if len(split_name) == 1:
 
88
            raise AssertionError(
 
89
                'No parent object for top-level module %r' % (module_name,))
 
90
        else:
 
91
            return (split_name[0], None, split_name[1])