Revision 19e7c7f6

b/docs/source/capabilities.rst
6 6
.. autofunction:: schemes
7 7

  
8 8
.. autoclass:: Capabilities
9
    :members:
9

  
10
    :members:
11

  
12
    .. describe:: ":cap" in caps
13

  
14
        Check for the presence of capability. In addition to the URI, for capabilities of the form `urn:ietf:params:netconf:capability:$name:$version` their shorthand can be used as a key. For example, for `urn:ietf:params:netconf:capability:candidate:1.0` the shorthand would be `:candidate`. If version is significant, use `:candidate:1.0` as key.
15

  
16
    .. describe:: iter(caps)
17

  
18
        Return an iterator over the full URI's of capabilities represented by this object.
b/docs/source/conf.py
67 67
exclude_trees = []
68 68

  
69 69
# The reST default role (used for this markup: `text`) to use for all documents.
70
default_role = 'class' 
70
#default_role = 'obj'
71 71

  
72 72
# If true, '()' will be appended to :func: etc. cross-reference text.
73 73
#add_function_parentheses = True
b/docs/source/index.rst
1 1
Welcome
2 2
=======
3 3

  
4
``ncclient`` is a Python library for NETCONF clients. It aims to offer an intuitive API that
5
sensibly maps the XML-encoded nature of NETCONF to Python constructs and idioms, and make writing
6
network-management scripts easier. Other key features are:
4
`ncclient` is a Python library for NETCONF clients. It aims to offer an intuitive API that sensibly maps the XML-encoded nature of NETCONF to Python constructs and idioms, and make writing network-management scripts easier. Other key features are:
7 5

  
8 6
* Supports all operations and capabilities defined in :rfc:`4741`.
9 7
* Request pipelining.
......
11 9
* Keeping XML out of the way unless really needed.
12 10
* Extensible. New transport mappings and capabilities/operations can be easily added.
13 11

  
14
It is suitable for Python 2.6+ (not Python 3 yet, though), and depends on `paramiko
15
<http://www.lag.net/paramiko/>`_, an SSH library.
12
It is suitable for Python 2.6+ (not Python 3 yet, though), and depends on `paramiko <http://www.lag.net/paramiko/>`_, an SSH library.
16 13

  
17
The best way to introduce is of course, through a simple code example::
14
The best way to introduce is through a simple code example::
18 15

  
19 16
    from ncclient import manager
20 17

  
......
31 28
    
32 29
    manager
33 30
    api
34
    extending
35 31

  
36 32
Indices and tables
37 33
------------------
b/docs/source/manager.rst
4 4
.. automodule:: ncclient.manager
5 5
    :synopsis: High-level API
6 6

  
7
Module data
8
-----------
9 7

  
10
These attributes control what capabilties are exchanged with the NETCONF server and what operations
11
are available through the `Manager` API.
8
Customizing
9
------------
10

  
11
These attributes control what capabilties are exchanged with the NETCONF server and what operations are available through the :class:`Manager` API.
12 12

  
13 13
.. autodata:: OPERATIONS
14 14

  
15 15
.. autodata:: CAPABILITIES
16 16

  
17

  
17 18
Factory functions
18 19
-----------------
19 20

  
20
A `Manager` instance is created using a factory function.
21
A :class:`Manager` instance is created using a factory function.
21 22

  
22
.. autofunction:: connect_ssh(host[, port=830, timeout=None, unknown_host_cb=default_unknown_host_cb, username=None, password, key_filename=None, allow_agent=True, look_for_keys=True])
23
.. autofunction:: connect_ssh
23 24

  
24 25
.. autodata:: connect
25 26

  
26 27
Manager
27 28
-------
28 29

  
29
Exposes an API for RPC operations as method calls. The return type of these methods depends on
30
whether we are is in :attr:`asynchronous or synchronous mode <ncclient.manager.Manager.async_mode>`.
30
Exposes an API for RPC operations as method calls. The return type of these methods depends on whether we are in :attr:`asynchronous or synchronous mode <ncclient.manager.Manager.async_mode>`.
31 31

  
32
In synchronous mode replies are awaited and the corresponding `~ncclient.operations.RPCReply` object
33
is returned. Depending on the :attr:`exception raising mode <ncclient.manager.Manager.raise_mode>`,
34
an *rpc-error* in the reply may be raised as :exc:`RPCError` exceptions.
32
In synchronous mode replies are awaited and the corresponding :class:`~ncclient.operations.RPCReply` object is returned. Depending on the :attr:`exception raising mode <ncclient.manager.Manager.raise_mode>`, an `rpc-error` in the reply may be raised as an :exc:`~ncclient.operations.RPCError` exception.
35 33

  
36
However in asynchronous mode, operations return immediately with an `~ncclient.operations.RPC`
37
object. Error handling and checking for whether a reply has been received must be dealt with
38
manually. See the `~ncclient.operations.RPC` documentation for details.
34
However in asynchronous mode, operations return immediately with the corresponding :class:`~ncclient.operations.RPC` object. Error handling and checking for whether a reply has been received must be dealt with manually. See the :class:`~ncclient.operations.RPC` documentation for details.
39 35

  
40
Note that in case of the *get* and *get-config* operations, the reply is an instance of
41
`~ncclient.operations.GetReply` which exposes the additional attributes
42
:attr:`~ncclient.operations.GetReply.data` (as `~xml.etree.ElementTree.Element`) and
43
:attr:`~ncclient.operations.GetReply.data_xml` (as `string`), which are of primary interest in case
44
of these operations.
36
Note that in case of the :meth:`~Manager.get` and :meth:`~Manager.get_config` operations, the reply is an instance of :class:`~ncclient.operations.GetReply` which exposes the additional attributes :attr:`~ncclient.operations.GetReply.data` (as :class:`~xml.etree.ElementTree.Element`) and :attr:`~ncclient.operations.GetReply.data_xml` (as a string), which are of primary interest in case of these operations.
45 37

  
46
Presence of capabilities is verified to the extent possible, and you can expect a
47
:exc:`~ncclient.operations.MissingCapabilityError` if something is amiss. In case of transport-layer
48
errors, e.g. unexpected session close, :exc:`~ncclient.transport.TransportError` will be raised.
38
Presence of capabilities is verified to the extent possible, and you can expect a :exc:`~ncclient.operations.MissingCapabilityError` if something is amiss. In case of transport-layer errors, e.g. unexpected session close, :exc:`~ncclient.transport.TransportError` will be raised.
49 39

  
50
.. class:: Manager
51
    
52
    For details on the expected behavior of the operations and their parameters 
53
    refer to :rfc:`4741`.
40
.. autoclass:: Manager
54 41

  
55
    Manager instances are also context managers so you can use it like this::
42
    .. automethod:: get_config(source, filter=None)
56 43

  
57
        with manager.connect("host") as m:
58
            # do your stuff
59
    
60
    ... or like this::
61
    
62
        m = manager.connect("host")
63
        try:
64
            # do your stuff
65
        finally:
66
            m.close()
67
    
68
    .. method:: get_config(source[, filter=None])
69
        
70
        Retrieve all or part of a specified configuration.
71
        
72
        :param source: name of the configuration datastore being queried
73
        :type source: `string`
74
        
75
        :param filter: portions of the device configuration to retrieve (by default entire configuration is retrieved)
76
        :type filter: :ref:`filter_params`
77
    
78
    .. method:: edit_config(target, config[, default_operation=None, test_option=None, error_option=None])
79
        
80
        Loads all or part of a specified configuration to the specified target configuration.
81
        
82
        The ``"rollback-on-error"`` *error_option* depends on the ``:rollback-on-error`` capability.
83
        
84
        :param target: name of the configuration datastore being edited
85
        :type target: `string`
86
        
87
        :param config: configuration (must be rooted in *<config> .. </config>*)
88
        :type config: `string` or `~xml.etree.ElementTree.Element`
89
        
90
        :param default_operation: one of { ``"merge"``, ``"replace"``, or ``"none"`` }
91
        :type default_operation: `string`
92
        
93
        :param test_option: one of { ``"test_then_set"``, ``"set"`` }
94
        :type test_option: `string`
95
        
96
        :param error_option: one of { ``"stop-on-error"``, ``"continue-on-error"``, ``"rollback-on-error"`` }
97
        :type error_option: `string`
98
    
99
    .. method:: copy_config(source, target)
100
        
101
        Create or replace an entire configuration datastore with the contents of another complete
102
        configuration datastore. 
103
        
104
        :param source: configuration datastore to use as the source of the copy operation or *<config>* element containing the configuration subtree to copy
105
        :type source: :ref:`srctarget_params`
106
        
107
        :param target: configuration datastore to use as the destination of the copy operation
108
        :type target: :ref:`srctarget_params`
109
    
110
    .. method:: delete_config(target)
111
        
112
        Delete a configuration datastore.
113
        
114
        :param target: name or URL of configuration datastore to delete
115
        :type: :ref:`srctarget_params`
116
    
117
    .. method:: lock(target)
118
        
119
        Allows the client to lock the configuration system of a device.
120
        
121
        :param target: name of the configuration datastore to lock
122
        :type target: `string`
123
        
124
    .. method:: unlock(target)
125
    
126
        Release a configuration lock, previously obtained with the
127
        :meth:`~ncclient.manager.Manager.lock` operation.
128
        
129
        :param target: name of the configuration datastore to unlock
130
        :type target: `string`
131
    
132
    .. method:: locked(target)
133
        
134
        Returns a context manager for a lock on a datastore, e.g.::
135
        
136
            with m.locked("running"):
137
                # do your stuff
44
    .. automethod:: edit_config(target, config, default_operation=None, test_option=None, error_option=None)
138 45

  
139
        ... instead of::
140
        
141
            m.lock("running")
142
            try:
143
                # do your stuff
144
            finally:
145
                m.unlock("running")
146
        
147
        :param target: name of configuration datastore to lock
148
        :type target: `string`
149
        
150
        :rtype: `~ncclient.operations.LockContext`
151
    
152
    .. method:: get([filter=None])
153
        
154
        Retrieve running configuration and device state information.
155
        
156
        :param filter: portions of the device configuration to retrieve (by default entire configuration is retrieved)
157
        :type filter: :ref:`filter_params`
158
    
159
    .. method:: close_session()
160
        
161
        Request graceful termination of the NETCONF session, and also close the transport.
162
    
163
    .. method:: kill_session(session_id)
164
        
165
        Force the termination of a NETCONF session (not the current one!).
166
        
167
        :param session_id: session identifier of the NETCONF session to be terminated
168
        :type session_id: `string`
169
    
170
    .. method:: commit([confirmed=False, timeout=None])
171
    
172
        Commit the candidate configuration as the device's new current configuration. Depends on the
173
        *:candidate* capability.
174
        
175
        A confirmed commit (i.e. if *confirmed* is :const:`True`) is reverted if there is no
176
        followup commit within the *timeout* interval. If no timeout is specified the confirm
177
        timeout defaults to 600 seconds (10 minutes). A confirming commit may have the *confirmed*
178
        parameter but this is not required. Depends on the *:confirmed-commit* capability.
179
        
180
        :param confirmed: whether this is a confirmed commit
181
        :type confirmed: `bool`
182
        
183
        :param timeout: confirm timeout in seconds
184
        :type timeout: `int`
185
    
186
    .. method:: discard_changes()
187
    
188
        Revert the candidate configuration to the currently running configuration. Any uncommitted
189
        changes are discarded.
190
    
191
    .. method:: validate(source)
192
        
193
        Validate the contents of the specified configuration.
194
        
195
        :param source: name of the configuration datastore being validated or *<config>* element containing the configuration subtree to be validated
196
        :type source: :ref:`srctarget_params`
197
    
198
    .. attribute:: async_mode
199
        
200
        Specify whether operations are executed asynchronously (:const:`True`)
201
        or synchronously (:const:`False`) (the default).
202
    
203
    .. attribute:: raise_mode
204
        
205
        Specify which errors are raised as :exc:`~ncclient.operations.RPCError` exceptions.
206
        Valid values:
207
        
208
        * ``"all"`` -- any kind of *rpc-error* (error or warning)
209
        * ``"errors"`` -- where the *error-type* element says it is an error
210
        * ``"none"`` -- neither
46
    .. automethod:: copy_config(source, target)
47

  
48
    .. automethod:: delete_config(target)
49

  
50
    .. automethod:: lock(target)
211 51
        
212
    .. attribute:: client_capabilities
213
    
214
        `~ncclient.capabilities.Capabilities` object representing the client's capabilities.
215
    
216
    .. attribute:: server_capabilities
217
    
218
        `~ncclient.capabilities.Capabilities` object representing the server's capabilities.
219
    
220
    .. attribute:: session_id
221
    
222
        *session-id* assigned by the NETCONF server.
52
    .. automethod:: unlock(target)
53

  
54
    .. automethod:: locked(target)
55

  
56
    .. automethod:: get()
223 57
    
224
    .. attribute:: connected
225
        
226
        Bolean value indicating whether currently connected to the NETCONF server.
58
    .. automethod:: close_session()
59

  
60
    .. automethod:: kill_session(session_id)
61

  
62
    .. automethod:: commit(confirmed=False, timeout=None)
63

  
64
    .. automethod:: discard_changes()
65

  
66
    .. automethod:: validate(source)
67

  
68
    .. autoattribute:: async_mode
69

  
70
    .. autoattribute:: raise_mode
71

  
72
    .. autoattribute:: client_capabilities
73

  
74
    .. autoattribute:: server_capabilities
75

  
76
    .. autoattribute:: session_id
77

  
78
    .. autoattribute:: connected
227 79

  
228 80

  
229 81
Special kinds of parameters
......
236 88
Source and target parameters
237 89
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
238 90

  
239
Where an method takes a *source* or *target* argument, usually a datastore name or URL is expected.
240
The latter depends on the ``:url`` capability and on whether the specific URL scheme is supported.
241
Either must be specified as a `string`. For example, ``"running"``,
242
``"ftp://user:pass@host/config"``.
91
Where an method takes a *source* or *target* argument, usually a datastore name or URL is expected. The latter depends on the `:url` capability and on whether the specific URL scheme is supported. Either must be specified as a string. For example, `"running"`, `"ftp://user:pass@host/config"`.
243 92

  
244
If the source may be a *<config>* element, e.g. as allowed for the *validate* RPC, it can also be
245
specified as an XML string or an `~xml.etree.ElementTree.Element` object.
93
If the source may be a `config` element, e.g. as allowed for the `validate` RPC, it can also be specified as an XML string or an :class:`~xml.etree.ElementTree.Element` object.
246 94

  
247 95
.. _filter_params:
248 96

  
......
251 99

  
252 100
Where a method takes a *filter* argument, it can take on the following types:
253 101

  
254
* A ``tuple`` of *(type, criteria)*.
102
* A tuple of *(type, criteria)*.
255 103
    
256
    Here *type* has to be one of ``"xpath"`` or ``"subtree"``.
104
    Here *type* has to be one of `"xpath"` or `"subtree"`.
257 105
    
258
    * For ``"xpath"`` the *criteria* should be a `string` containing the XPath expression.
259
    * For ``"subtree"`` the *criteria* should be an XML string or an
260
      `~xml.etree.ElementTree.Element` object containing the criteria.
106
    * For `"xpath"` the *criteria* should be a string containing the XPath expression.
107
    * For `"subtree"` the *criteria* should be an XML string or an :class:`~xml.etree.ElementTree.Element` object containing the criteria.
261 108

  
262
* A *<filter>* element as an XML string or an `~xml.etree.ElementTree.Element` object.
109
* A `<filter>` element as an XML string or an :class:`~xml.etree.ElementTree.Element` object.
b/docs/source/operations.rst
1 1
:mod:`~ncclient.operations` -- Everything RPC
2 2
=============================================
3 3

  
4
Base classes
5
------------
6 4

  
7 5
.. module:: ncclient.operations
8 6
    :synopsis: Everything RPC
9 7

  
10
.. autoclass:: RPC(session[, async=False, timeout=None, raise_mode="none"])
8
.. autoclass:: RaiseMode
9
    :members: NONE, ERRORS, ALL
10

  
11
Base classes
12
------------
13

  
14
.. autoclass:: RPC(session, async=False, timeout=None, raise_mode="none")
11 15
    :members: DEPENDS, REPLY_CLS, _assert, _request, request, event, error, reply, raise_mode, is_async, timeout
12 16

  
13 17
.. autoclass:: RPCReply
14
    :members: xml, ok, error, errors
18
    :members: xml, ok, error, errors, _parsing_hook
15 19

  
16 20
.. autoexception:: RPCError
17 21
    :show-inheritance:
......
20 24
Operations
21 25
----------
22 26

  
23
*TODO*
24

  
25
The operation classes are currently undocumented. See documentation of `~ncclient.manager.Manager`
26
for methods that utilize the operation classes. The parameters accepted by :meth:`~RPC.request` for
27
these classes are the same.
27
The operation classes are currently undocumented. See documentation of :class:`~ncclient.manager.Manager` for methods that utilize the operation classes. The parameters accepted by :meth:`~RPC.request` for these classes are the same.
28 28

  
29 29
Replies with data
30 30
-----------------
b/docs/source/transport.rst
22 22
    :show-inheritance:
23 23
    :members: load_known_hosts, close, transport
24 24

  
25
    .. automethod:: connect(host[, port=830, timeout=None, username=None, password=None, key_filename=None, allow_agent=True, look_for_keys=True])
25
    .. automethod:: connect(host[, port=830, timeout=None, unknown_host_cb=default_unknown_host_cb, username=None, password=None, key_filename=None, allow_agent=True, look_for_keys=True])
26 26

  
27 27
Errors
28 28
------
......
40 40
    :show-inheritance:
41 41

  
42 42
.. autoexception:: SSHUnknownHostError
43
    :show-inheritance:
44

  
43
    :show-inheritance:
b/docs/source/xml_.rst
1 1
:mod:`~ncclient.xml_` -- XML handling
2 2
=====================================
3 3

  
4
.. module:: ncclient.xml_
4
.. automodule:: ncclient.xml_
5 5
    :synopsis: XML handling
6 6

  
7 7
.. autoexception:: XMLError
......
20 20

  
21 21
.. autodata:: FLOWMON_1_0
22 22

  
23
.. function:: register_namespace(prefix, uri)
24
    
25
    ElementTree's namespace map determines the prefixes for namespace URI's when serializing to XML.
26
    This method allows modifying this map to specify a prefix for a namespace URI.
23
.. autofunction:: register_namespace(prefix, uri)
27 24

  
28 25
.. autofunction:: qualify
29 26

  
......
36 33

  
37 34
.. autofunction:: parse_root
38 35

  
39
.. autofunction:: validated_element
40

  
41
.. 
36
.. autofunction:: validated_element
b/ncclient/capabilities.py
23 23
    return []
24 24

  
25 25
def schemes(url_uri):
26
    """Given a URI that has a *scheme* query string (i.e. *:url* capability URI), will return a list
27
    of supported schemes.
28
    """
26
    "Given a URI that has a *scheme* query string (i.e. `:url` capability URI), will return a list of supported schemes."
29 27
    return url_uri.partition("?scheme=")[2].split(",")
30 28

  
31 29
class Capabilities:
32 30

  
33
    """Represents the set of capabilities available to a NETCONF client or server. It is initialized
34
    with a list of capability URI's. These can be iterated over.
35
    
36
    Presence of a capability can be checked with the *in* operation. In addition to the URI, for
37
    capabilities of the form *urn:ietf:params:netconf:capability:$name:$version* their shorthand can
38
    be used as a key. For example, for *urn:ietf:params:netconf:capability:candidate:1.0* the
39
    shorthand would be *:candidate*. If version is significant, use *:candidate:1.0* as key.
40
    """
31
    "Represents the set of capabilities available to a NETCONF client or server. It is initialized with a list of capability URI's."
41 32
    
42 33
    def __init__(self, capabilities):
43 34
        self._dict = {}
b/ncclient/manager.py
12 12
# See the License for the specific language governing permissions and
13 13
# limitations under the License.
14 14

  
15
"This module is a thin layer of abstraction around the library. It exposes all core functionality."
15
"""This module is a thin layer of abstraction around the library. It exposes all core functionality."""
16 16

  
17 17
import capabilities
18 18
import operations
......
35 35
    "urn:liberouter:params:netconf:capability:power-control:1.0"
36 36
    "urn:ietf:params:netconf:capability:interleave:1.0"
37 37
]
38
"A list of URI's representing the client's capabilities. This is used during the initial capability exchange. Modify this if you need to announce some capability not already included."
38
"""A list of URI's representing the client's capabilities. This is used during the initial capability exchange. Modify this if you need to announce some capability not already included."""
39 39

  
40 40
OPERATIONS = {
41 41
    "get": operations.Get,
......
53 53
    "poweroff_machine": operations.PoweroffMachine,
54 54
    "reboot_machine": operations.RebootMachine
55 55
}
56
"""Dictionary of method names and corresponding `~ncclient.operations.RPC` subclasses. It is used to lookup operations, e.g. "get_config" is mapped to `~ncclient.operations.GetConfig`. It is thus possible to add additional operations to the `Manager` API."""
56
"""Dictionary of method names and corresponding :class:`~ncclient.operations.RPC` subclasses. It is used to lookup operations, e.g. `get_config` is mapped to :class:`~ncclient.operations.GetConfig`. It is thus possible to add additional operations to the :class:`Manager` API."""
57 57

  
58 58
def connect_ssh(*args, **kwds):
59
    """Initializes a NETCONF session over SSH, and creates a connected `Manager` instance. *host* must be specified, all the other arguments are optional and depend on the kind of host key verification and user authentication you want to complete.
60
        
61
    For the purpose of host key verification, on -NIX systems a user's :file:`~/.ssh/known_hosts` file is automatically considered. The *unknown_host_cb* argument specifies a callback that will be invoked when the server's host key cannot be verified. See :func:`~ncclient.transport.ssh.default_unknown_host_cb` for function signature.
62
    
63
    First, ``publickey`` authentication is attempted. If a specific *key_filename* is specified, it
64
    will be loaded and authentication attempted using it. If *allow_agent* is :const:`True` and an
65
    SSH agent is running, the keys provided by the agent will be tried. If *look_for_keys* is
66
    :const:`True`, keys in the :file:`~/.ssh/id_rsa` and :file:`~.ssh/id_dsa` will be tried. In case
67
    an encrypted key file is encountered, the *password* argument will be used as a decryption
68
    passphrase.
69
    
70
    If ``publickey`` authentication fails and the *password* argument has been supplied, ``password`` / ``keyboard-interactive`` SSH authentication will be attempted.
71
    
72
    :param host: hostname or address on which to connect
73
    :type host: `string`
74
    
75
    :param port: port on which to connect
76
    :type port: `int`
77
    
78
    :param timeout: timeout for socket connect
79
    :type timeout: `int`
80
    
81
    :param unknown_host_cb: optional; callback that is invoked when host key verification fails
82
    :type unknown_host_cb: `function`
83
    
84
    :param username: username to authenticate with, if not specified the username of the logged-in user is used
85
    :type username: `string`
86
    
87
    :param password: password for ``password`` authentication or passphrase for decrypting private key files
88
    :type password: `string`
89
    
90
    :param key_filename: location of a private key file on the file system
91
    :type key_filename: `string`
92
    
93
    :param allow_agent: whether to try connecting to SSH agent for keys
94
    :type allow_agent: `bool`
95
    
96
    :param look_for_keys: whether to look in usual locations for keys
97
    :type look_for_keys: `bool`
98
    
99
    :raises: :exc:`~ncclient.transport.SSHUnknownHostError`
100
    :raises: :exc:`~ncclient.transport.AuthenticationError`
101
    
102
    :rtype: `Manager`
59
    """Initialize a :class:`Manager` over the SSH transport. For documentation of arguments see :meth:`ncclient.transport.SSHSession.connect`.
60

  
61
    The underlying :class:`ncclient.transport.SSHSession` is created with :data:`CAPABILITIES`. It is first instructed to :meth:`~ncclient.transport.SSHSession.load_known_hosts` and then  all the provided arguments are passed directly to its implementation of :meth:`~ncclient.transport.SSHSession.connect`.
103 62
    """
104 63
    session = transport.SSHSession(capabilities.Capabilities(CAPABILITIES))
105 64
    session.load_known_hosts()
......
110 69
"Same as :func:`connect_ssh`, since SSH is the default (and currently, the only) transport."
111 70

  
112 71
class OpExecutor(type):
72

  
113 73
    def __new__(cls, name, bases, attrs):
114 74
        def make_wrapper(op_cls):
115 75
            def wrapper(self, *args, **kwds):
......
122 82

  
123 83
class Manager(object):
124 84

  
125
    __metaclass__ = OpExecutor
85
    """For details on the expected behavior of the operations and their parameters refer to :rfc:`4741`.
86

  
87
    Manager instances are also context managers so you can use it like this::
88

  
89
        with manager.connect("host") as m:
90
            # do your stuff
126 91

  
127
    RAISE_NONE = 0
128
    RAISE_ERRORS = 1
129
    RAISE_ALL = 2
92
    ... or like this::
130 93

  
131
    def __init__(self, session):
94
        m = manager.connect("host")
95
        try:
96
            # do your stuff
97
        finally:
98
            m.close_session()
99
    """
100

  
101
    __metaclass__ = OpExecutor
102

  
103
    def __init__(self, session, timeout=30):
132 104
        self._session = session
133 105
        self._async_mode = False
134
        self._timeout = None
135
        self._raise_mode = self.RAISE_ALL
106
        self._timeout = timeout
107
        self._raise_mode = operations.RaiseMode.ALL
136 108

  
137 109
    def __enter__(self):
138 110
        return self
......
141 113
        self.close_session()
142 114
        return False
143 115

  
116
    def __set_async_mode(self, mode):
117
        self._async_mode = mode
118

  
119
    def __set_raise_mode(self, mode):
120
        assert(choice in (operations.RaiseMode.NONE, operations.RaiseMode.ERRORS, operations.RaiseMode.ALL))
121
        self._raise_mode = mode
122

  
144 123
    def execute(self, cls, *args, **kwds):
145 124
        return cls(self._session,
146 125
                   async=self._async_mode,
......
148 127
                   raise_mode=self._raise_mode).request(*args, **kwds)
149 128

  
150 129
    def locked(self, target):
130
        """Returns a context manager for a lock on a datastore, where *target* is the name of the configuration datastore to lock, e.g.::
131

  
132
            with m.locked("running"):
133
                # do your stuff
134

  
135
        ... instead of::
136

  
137
            m.lock("running")
138
            try:
139
                # do your stuff
140
            finally:
141
                m.unlock("running")
142
        """
151 143
        return operations.LockContext(self._session, target)
152 144

  
153 145
    @property
154 146
    def client_capabilities(self):
147
        ":class:`~ncclient.capabilities.Capabilities` object representing the client's capabilities."
155 148
        return self._session._client_capabilities
156 149

  
157 150
    @property
158 151
    def server_capabilities(self):
152
        ":class:`~ncclient.capabilities.Capabilities` object representing the server's capabilities."
159 153
        return self._session._server_capabilities
160 154

  
161 155
    @property
162 156
    def session_id(self):
157
        "`session-id` assigned by the NETCONF server."
163 158
        return self._session.id
164 159

  
165 160
    @property
166 161
    def connected(self):
162
        "Whether currently connected to the NETCONF server."
167 163
        return self._session.connected
168 164

  
169
    def set_async_mode(self, mode):
170
        self._async_mode = mode
171

  
172
    def set_raise_mode(self, mode):
173
        assert(choice in (self.RAISE_NONE, self.RAISE_ERRORS, self.RAISE_ALL))
174
        self._raise_mode = mode
165
    async_mode = property(fget=lambda self: self._async_mode, fset=__set_async_mode)
166
    "Specify whether operations are executed asynchronously (`True`) or synchronously (`False`) (the default)."
175 167

  
176
    async_mode = property(fget=lambda self: self._async_mode, fset=set_async_mode)
177 168

  
178
    raise_mode = property(fget=lambda self: self._raise_mode, fset=set_raise_mode)
169
    raise_mode = property(fget=lambda self: self._raise_mode, fset=__set_raise_mode)
170
    "Specify which errors are raised as :exc:`~ncclient.operations.RPCError` exceptions. Valid values are the constants defined in :class:`~ncclient.operations.RaiseMode`. The default value is :attr:`~ncclient.operations.RaiseMode.ALL`."
b/ncclient/operations/__init__.py
13 13
# limitations under the License.
14 14

  
15 15
from errors import OperationError, TimeoutExpiredError, MissingCapabilityError
16
from rpc import RPC, RPCReply, RPCError
16
from rpc import RPC, RPCReply, RPCError, RaiseMode
17 17

  
18 18
# rfc4741 ops
19 19
from retrieve import Get, GetConfig, GetReply
......
27 27
    'RPC',
28 28
    'RPCReply',
29 29
    'RPCError',
30
    'RaiseMode',
30 31
    'Get',
31 32
    'GetConfig',
32 33
    'GetReply',
b/ncclient/operations/edit.py
19 19
import util
20 20

  
21 21
import logging
22

  
22 23
logger = logging.getLogger("ncclient.operations.edit")
23 24

  
24 25
"Operations related to changing device configuration"
25 26

  
26 27
class EditConfig(RPC):
28
    "`edit-config` RPC"
27 29

  
28
    "*<edit-config>* RPC"
29
    
30 30
    def request(self, target, config, default_operation=None, test_option=None, error_option=None):
31
        """Loads all or part of the specified *config* to the *target* configuration datastore.
32

  
33
        *target* is the name of the configuration datastore being edited
34

  
35
        *config* is the configuration, which must be rooted in the `config` element. It can be specified either as a string or an :class:`~xml.etree.ElementTree.Element`.
36

  
37
        *default_operation* if specified must be one of { `"merge"`, `"replace"`, or `"none"` }
38

  
39
        *test_option* if specified must be one of { `"test_then_set"`, `"set"` }
40

  
41
        *error_option* if specified must be one of { `"stop-on-error"`, `"continue-on-error"`, `"rollback-on-error"` }
42

  
43
        The `"rollback-on-error"` *error_option* depends on the `:rollback-on-error` capability.
44
        """
31 45
        node = new_ele("edit-config")
32 46
        node.append(util.datastore_or_url("target", target, self._assert))
33 47
        if error_option is not None:
......
38 52
            self._assert(':validate')
39 53
            sub_ele(node, "test-option").text = test_option
40 54
        if default_operation is not None:
41
            # TODO: check if it is a valid default-operation
55
        # TODO: check if it is a valid default-operation
42 56
            sub_ele(node, "default-operation").text = default_operation
43 57
        node.append(validated_element(config, ("config", qualify("config"))))
44 58
        return self._request(node)
45 59

  
46 60

  
47 61
class DeleteConfig(RPC):
48

  
49
    "*<delete-config>* RPC"
62
    "`delete-config` RPC"
50 63

  
51 64
    def request(self, target):
65
        """Delete a configuration datastore.
66

  
67
        :param target: name or URL of configuration datastore to delete
68
        :type: :ref:`srctarget_params`"""
52 69
        node = new_ele("delete-config")
53 70
        node.append(util.datastore_or_url("target", target, self._assert))
54 71
        return self._request(node)
55 72

  
56 73

  
57 74
class CopyConfig(RPC):
75
    "`copy-config` RPC"
58 76

  
59
    "*<copy-config>* RPC"
60
    
61 77
    def request(self, source, target):
78
        """Create or replace an entire configuration datastore with the contents of another complete
79
        configuration datastore.
80

  
81
        :param source: configuration datastore to use as the source of the copy operation or `config` element containing the configuration subtree to copy
82
        :type source: :ref:`srctarget_params`
83

  
84
        :param target: configuration datastore to use as the destination of the copy operation
85
        :type target: :ref:`srctarget_params`"""
62 86
        node = new_ele("copy-config")
63 87
        node.append(util.datastore_or_url("target", target, self._assert))
64 88
        node.append(util.datastore_or_url("source", source, self._assert))
......
66 90

  
67 91

  
68 92
class Validate(RPC):
69

  
70
    "*<validate>* RPC. Depends on the *:validate* capability."
93
    "`validate` RPC. Depends on the `:validate` capability."
71 94

  
72 95
    DEPENDS = [':validate']
73 96

  
74 97
    def request(self, source):
98
        """Validate the contents of the specified configuration.
99

  
100
        :param source: name of the configuration datastore being validated or `config` element containing the configuration subtree to be validated
101
        :type source: :ref:`srctarget_params`"""
75 102
        node = new_ele("validate")
76 103
        try:
77 104
            src = validated_element(source, ("config", qualify("config")))
......
83 110

  
84 111

  
85 112
class Commit(RPC):
86

  
87
    "*<commit>* RPC. Depends on the *:candidate* capability, and the *:confirmed-commit* "
113
    "`commit` RPC. Depends on the `:candidate` capability, and the `:confirmed-commit`."
88 114

  
89 115
    DEPENDS = [':candidate']
90
    
116

  
91 117
    def request(self, confirmed=False, timeout=None):
118
        """Commit the candidate configuration as the device's new current configuration. Depends on the `:candidate` capability.
119

  
120
        A confirmed commit (i.e. if *confirmed* is `True`) is reverted if there is no followup commit within the *timeout* interval. If no timeout is specified the confirm timeout defaults to 600 seconds (10 minutes). A confirming commit may have the *confirmed* parameter but this is not required. Depends on the `:confirmed-commit` capability.
121

  
122
        :param confirmed: whether this is a confirmed commit
123
        :type confirmed: bool
124

  
125
        :param timeout: confirm timeout in seconds
126
        :type timeout: int"""
92 127
        node = new_ele("commit")
93 128
        if confirmed:
94 129
            self._assert(":confirmed-commit")
......
99 134

  
100 135

  
101 136
class DiscardChanges(RPC):
102

  
103
    "*<discard-changes>* RPC. Depends on the *:candidate* capability."
137
    "`discard-changes` RPC. Depends on the `:candidate` capability."
104 138

  
105 139
    DEPENDS = [":candidate"]
106 140

  
107 141
    def request(self):
142
        """Revert the candidate configuration to the currently running configuration. Any uncommitted changes are discarded."""
108 143
        return self._request(new_ele("discard-changes"))
b/ncclient/operations/lock.py
12 12
# See the License for the specific language governing permissions and
13 13
# limitations under the License.
14 14

  
15
'Locking-related NETCONF operations'
15
"Locking-related NETCONF operations"
16 16

  
17 17
from ncclient.xml_ import *
18 18

  
19
from rpc import RPC
19
from rpc import RaiseMode, RPC
20 20

  
21
# TODO:
22
# should have some way to parse session-id from a lock-denied error, and raise
23
# a tailored exception
21
# TODO: parse session-id from a lock-denied error, and raise a tailored exception?
24 22

  
25 23
class Lock(RPC):
26 24

  
27
    "*<lock>* RPC"
25
    "`lock` RPC"
28 26
    
29 27
    def request(self, target):
28
        """Allows the client to lock the configuration system of a device.
29

  
30
        *target* is the name of the configuration datastore to lock
31
        """
30 32
        node = new_ele("lock")
31 33
        sub_ele(sub_ele(node, "target"), target)
32 34
        return self._request(node)
......
34 36

  
35 37
class Unlock(RPC):
36 38

  
37
    "*<unlock>* RPC"
39
    "`unlock` RPC"
38 40
    
39 41
    def request(self, target):
42
        """Release a configuration lock, previously obtained with the lock operation.
43

  
44
        *target* is the name of the configuration datastore to unlock
45
        """
40 46
        node = new_ele("unlock")
41 47
        sub_ele(sub_ele(node, "target"), target)
42 48
        return self._request(node)
......
44 50

  
45 51
class LockContext:
46 52

  
47
    """
48
    A context manager for the :class:`Lock` / :class:`Unlock` pair of RPC's.
49
    
50
    RPC errors are always raised as exceptions.
51
    
52
    Initialise with (:class:`Session <ncclient.transport.Session>`) instance
53
    and lock target.
53
    """A context manager for the :class:`Lock` / :class:`Unlock` pair of RPC's.
54

  
55
    Any `rpc-error` will be raised as an exception.
56

  
57
    Initialise with (:class:`Session <ncclient.transport.Session>`) instance and lock target.
54 58
    """
55 59

  
56 60
    def __init__(self, session, target):
......
58 62
        self.target = target
59 63

  
60 64
    def __enter__(self):
61
        Lock(self.session).request(self.target)
65
        Lock(self.session, raise_mode=RaiseMode.ERRORS).request(self.target)
62 66
        return self
63 67

  
64 68
    def __exit__(self, *args):
65
        Unlock(self.session).request(self.target)
69
        Unlock(self.session, raise_mode=RaiseMode.ERRORS).request(self.target)
66 70
        return False
b/ncclient/operations/retrieve.py
30 30
    
31 31
    @property
32 32
    def data_ele(self):
33
        "*data* element as an `~xml.etree.ElementTree.Element`"
33
        "*data* element as an :class:`~xml.etree.ElementTree.Element`"
34 34
        if not self._parsed:
35 35
            self.parse()
36 36
        return self._data
......
53 53
    REPLY_CLS = GetReply
54 54

  
55 55
    def request(self, filter=None):
56
        """Retrieve running configuration and device state information.
57

  
58
        :param filter: portions of the device configuration to retrieve (by default entire configuration is retrieved)
59
        :type filter: :ref:`filter_params`
60
        """
56 61
        node = new_ele("get")
57 62
        if filter is not None:
58 63
            node.append(util.build_filter(filter))
......
66 71
    REPLY_CLS = GetReply
67 72

  
68 73
    def request(self, source, filter=None):
74
        """Retrieve all or part of a specified configuration.
75

  
76
        :param source: name of the configuration datastore being queried
77
        :type source: string
78

  
79
        :param filter: portions of the device configuration to retrieve (by default entire configuration is retrieved)
80
        :type filter: :ref:`filter_params`"""
69 81
        node = new_ele("get-config")
70 82
        node.append(util.datastore_or_url("source", source, self._assert))
71 83
        if filter is not None:
b/ncclient/operations/rpc.py
26 26

  
27 27
class RPCError(OperationError):
28 28

  
29
    """Represents an *rpc-error*. It is a type of :exc:`OperationError` and can be raised like any
30
    other exception."""
29
    "Represents an `rpc-error`. It is a type of :exc:`OperationError` and can be raised as such."
31 30
    
32 31
    tag_to_attr = {
33 32
        qualify("error-type"): "_type",
......
56 55
    
57 56
    @property
58 57
    def xml(self):
59
        "*rpc-error* element as returned."
58
        "The `rpc-error` element as returned in XML."
60 59
        return self._raw
61 60
    
62 61
    @property
63 62
    def type(self):
64
        "`string` representing text of *error-type* element."
63
        "The contents of the `error-type` element."
65 64
        return self._type
66 65
    
67 66
    @property
68 67
    def tag(self):
69
        "`string` representing text of *error-tag* element."
68
        "The contents of the `error-tag` element."
70 69
        return self._tag
71 70
    
72 71
    @property
73 72
    def severity(self):
74
        "`string` representing text of *error-severity* element."
73
        "The contents of the `error-severity` element."
75 74
        return self._severity
76 75
    
77 76
    @property
78 77
    def path(self):
79
        "`string` or :const:`None`; representing text of *error-path* element."
78
        "The contents of the `error-path` element if present or `None`."
80 79
        return self._path
81 80
    
82 81
    @property
83 82
    def message(self):
84
        "`string` or :const:`None`; representing text of *error-message* element."
83
        "The contents of the `error-message` element if present or `None`."
85 84
        return self._message
86 85
    
87 86
    @property
88 87
    def info(self):
89
        "`string` (XML) or :const:`None`; representing *error-info* element."
88
        "XML string or `None`; representing the `error-info` element."
90 89
        return self._info
91 90

  
92 91

  
......
128 127
        self._parsed = True
129 128

  
130 129
    def _parsing_hook(self, root):
130
        "No-op by default. Gets given the *root* element."
131 131
        pass
132 132
    
133 133
    @property
......
142 142
    
143 143
    @property
144 144
    def error(self):
145
        "Returns the first `RPCError` and :const:`None` if there were no errors."
145
        "Returns the first :class:`RPCError` and `None` if there were no errors."
146 146
        self.parse()
147 147
        if self._errors:
148 148
            return self._errors[0]
......
151 151
    
152 152
    @property
153 153
    def errors(self):
154
        """`list` of `RPCError` objects. Will be empty if there were no *rpc-error* elements in
155
        reply."""
154
        "List of `RPCError` objects. Will be empty if there were no *rpc-error* elements in reply."
156 155
        self.parse()
157 156
        return self._errors
158 157

  
......
207 206
            self._id2rpc.clear()
208 207

  
209 208

  
209
class RaiseMode(object):
210

  
211
    NONE = 0
212
    "Don't attempt to raise any type of `rpc-error` as :exc:`RPCError`."
213

  
214
    ERRORS = 1
215
    "Raise only when the `error-type` indicates it is an honest-to-god error."
216

  
217
    ALL = 2
218
    "Don't look at the `error-type`, always raise."
219

  
220

  
210 221
class RPC(object):
211 222
    
212 223
    """Base class for all operations, directly corresponding to *rpc* requests. Handles making the
213 224
    request, and taking delivery of the reply."""
214
    
225

  
215 226
    DEPENDS = []
216
    """Subclasses can specify their dependencies on capabilities. List of URI's or abbreviated
217
    names, e.g. ':writable-running'. These are verified at the time of instantiation. If the
218
    capability is not available, a :exc:`MissingCapabilityError` is raised.
227
    """Subclasses can specify their dependencies on capabilities. List of URI's or abbreviated names, e.g. ':writable-running'. These are verified at the time of instantiation. If the capability is not available, a :exc:`MissingCapabilityError` is raised.
219 228
    """
220 229
    
221 230
    REPLY_CLS = RPCReply
222 231
    "Subclasses can specify a different reply class, but it should be a subclass of `RPCReply`."
223 232
    
224
    def __init__(self, session, async=False, timeout=None, raise_mode="none"):
233
    def __init__(self, session, async=False, timeout=30, raise_mode=RaiseMode.NONE):
225 234
        self._session = session
226 235
        try:
227 236
            for cap in self.DEPENDS:
......
245 254
        return to_xml(ele)
246 255

  
247 256
    def _request(self, op):
248
        """Implementations of :meth:`request` call this method to send the request and process the
249
        reply.
257
        """Implementations of :meth:`request` call this method to send the request and process the reply.
250 258
        
251
        In synchronous mode, blocks until the reply is received and returns `RPCReply`. Depending on
252
        the :attr:`raise_mode` a *rpc-error* element in the reply may lead to an :exc:`RPCError`
253
        exception.
259
        In synchronous mode, blocks until the reply is received and returns :class:`RPCReply`. Depending on the :attr:`raise_mode` a `rpc-error` element in the reply may lead to an :exc:`RPCError` exception.
254 260
        
255
        In asynchronous mode, returns immediately, returning *self*. The :attr:`event` attribute
256
        will be set when the reply has been received (see :attr:`reply`) or an error occured (see
257
        :attr:`error`).
261
        In asynchronous mode, returns immediately, returning *self*. The :attr:`event` attribute will be set when the reply has been received (see :attr:`reply`) or an error occured (see :attr:`error`).
258 262
        
259
        :param op: operation to be requested
263
        :param op: operation to b\e requested
260 264
        :type ops: `~xml.etree.ElementTree.Element`
261 265
        
262 266
        :rtype: `RPCReply` (sync) or `RPC` (async)
......
277 281
                self._reply.parse()
278 282
                if self._reply.error is not None:
279 283
                    # <rpc-error>'s [ RPCError ]
280
                    if self._raise_mode == "all":
284
                    if self._raise_mode == RaiseMode.ALL:
281 285
                        raise self._reply.error
282
                    elif (self._raise_mode == "errors" and
283
                          self._reply.error.type == "error"):
286
                    elif (self._raise_mode == RaiseMode.ERRORS and self._reply.error.type == "error"):
284 287
                        raise self._reply.error
285 288
                return self._reply
286 289
            else:
......
311 314
    
312 315
    @property
313 316
    def reply(self):
314
        "`RPCReply` element if reply has been received or :const:`None`"
317
        ":class:`RPCReply` element if reply has been received or `None`"
315 318
        return self._reply
316 319
    
317 320
    @property
318 321
    def error(self):
319
        """:exc:`Exception` type if an error occured or :const:`None`.
322
        """:exc:`Exception` type if an error occured or `None`.
320 323
        
321 324
        .. note::
322 325
            This represents an error which prevented a reply from being received. An *rpc-error*
......
341 344
        """
342 345
        return self._event
343 346

  
344
    def set_async(self, async=True):
347
    def __set_async(self, async=True):
345 348
        self._async = async
346 349
        if async and not session.can_pipeline:
347 350
            raise UserWarning('Asynchronous mode not supported for this device/session')
348 351

  
349
    def set_raise_mode(self, mode):
352
    def __set_raise_mode(self, mode):
350 353
        assert(choice in ("all", "errors", "none"))
351 354
        self._raise_mode = mode
352 355

  
353
    def set_timeout(self, timeout):
356
    def __set_timeout(self, timeout):
354 357
        self._timeout = timeout
355 358

  
356
    raise_mode = property(fget=lambda self: self._raise_mode, fset=set_raise_mode)
357
    """Depending on this exception raising mode, an *rpc-error* in the reply may be raised as
358
    :exc:`RPCError` exceptions. Valid values:
359
    raise_mode = property(fget=lambda self: self._raise_mode, fset=__set_raise_mode)
360
    """Depending on this exception raising mode, an `rpc-error` in the reply may be raised as an :exc:`RPCError` exception. Valid values are the constants defined in :class:`RaiseMode`. """
359 361
    
360
    * ``"all"`` -- any kind of *rpc-error* (error or warning)
361
    * ``"errors"`` -- when the *error-type* element says it is an error
362
    * ``"none"`` -- neither
363
    """
364
    
365
    is_async = property(fget=lambda self: self._async, fset=set_async)
366
    """Specifies whether this RPC will be / was requested asynchronously. By default RPC's are
367
    synchronous.
368
    """
362
    is_async = property(fget=lambda self: self._async, fset=__set_async)
363
    """Specifies whether this RPC will be / was requested asynchronously. By default RPC's are synchronous. """
369 364
    
370
    timeout = property(fget=lambda self: self._timeout, fset=set_timeout)
371
    """Timeout in seconds for synchronous waiting defining how long the RPC request will block on a
372
    reply before raising :exc:`TimeoutExpiredError`. By default there is no timeout, represented by
373
    :const:`None`.
365
    timeout = property(fget=lambda self: self._timeout, fset=__set_timeout)
366
    """Timeout in seconds for synchronous waiting defining how long the RPC request will block on a reply before raising :exc:`TimeoutExpiredError`.
374 367
    
375 368
    Irrelevant for asynchronous usage.
376 369
    """
b/ncclient/operations/session.py
12 12
# See the License for the specific language governing permissions and
13 13
# limitations under the License.
14 14

  
15
'Session-related NETCONF operations'
15
"Session-related NETCONF operations"
16 16

  
17 17
from ncclient.xml_ import *
18 18

  
......
20 20

  
21 21
class CloseSession(RPC):
22 22

  
23
    "*<close-session>* RPC. The connection to NETCONF server is also closed."
23
    "`close-session` RPC. The connection to NETCONF server is also closed."
24 24

  
25 25
    def request(self):
26
        "Request graceful termination of the NETCONF session, and also close the transport."
26 27
        try:
27 28
            return self._request(new_ele("close-session"))
28 29
        finally:
......
31 32

  
32 33
class KillSession(RPC):
33 34

  
34
    "*<kill-session>* RPC."
35
    
35
    "`kill-session` RPC."
36

  
36 37
    def request(self, session_id):
37
        """
38
        :arg session_id: *session-id* of NETCONF session to kill
39
        :type session_id: `string`
38
        """Force the termination of a NETCONF session (not the current one!)
39

  
40
        *session_id* is the session identifier of the NETCONF session to be terminated as a string
40 41
        """
41 42
        node = new_ele("kill-session")
42
        if not isinstance(session_id, basestring): # make sure
43
            session_id = str(session_id)
44 43
        sub_ele(node, "session-id").text = session_id
45 44
        return self._request(node)
b/ncclient/transport/session.py
131 131
        raise NotImplementedError
132 132

  
133 133
    def send(self, message):
134
        """Send the supplied *message* to NETCONF server.
135

  
136
        :arg message: an XML document
137

  
138
        :type message: `string`
139
        """
134
        """Send the supplied *message* (xml string) to NETCONF server."""
140 135
        if not self.connected:
141 136
            raise TransportError('Not connected to NETCONF server')
142 137
        logger.debug('queueing %s' % message)
......
161 156

  
162 157
    @property
163 158
    def id(self):
164
        """A `string` representing the `session-id`. If the session has not
165
        been initialized it will be :const:`None`"""
159
        """A string representing the `session-id`. If the session has not been initialized it will be `None`"""
166 160
        return self._id
167 161

  
168 162

  
......
176 170
    """
177 171

  
178 172
    def callback(self, root, raw):
179
        """Called when a new XML document is received. The `root` argument
180
        allows the callback to determine whether it wants to further process the
181
        document.
173
        """Called when a new XML document is received. The *root* argument allows the callback to determine whether it wants to further process the document.
182 174

  
183
        :arg root: tuple of `(tag, attributes)` where `tag` is the qualified name of the root element and `attributes` is a dictionary of its attributes (also qualified names)
184
        :type root: `tuple`
175
        Here, *root* is a tuple of *(tag, attributes)* where *tag* is the qualified name of the root element and *attributes* is a dictionary of its attributes (also qualified names).
185 176

  
186
        :arg raw: XML document
187
        :type raw: `string`
177
        *raw* will contain the XML document as a string.
188 178
        """
189 179
        raise NotImplementedError
190 180

  
b/ncclient/transport/ssh.py
32 32
TICK = 0.1
33 33

  
34 34
def default_unknown_host_cb(host, fingerprint):
35
    """An `unknown host callback` returns :const:`True` if it finds the key acceptable, and
36
    :const:`False` if not.
35
    """An unknown host callback returns `True` if it finds the key acceptable, and `False` if not.
37 36

  
38
    This default callback always returns :const:`False`, which would lead to :meth:`connect` raising
39
    a :exc:`SSHUnknownHost` exception.
37
    This default callback always returns `False`, which would lead to :meth:`connect` raising a :exc:`SSHUnknownHost` exception.
40 38
    
41 39
    Supply another valid callback if you need to verify the host key programatically.
42 40

  
43
    :arg host: the hostname that needs to be verified
44
    :type host: `string`
41
    *host* is the hostname that needs to be verified
45 42

  
46
    :arg fingerprint: a hex string representing the host key fingerprint, colon-delimited e.g. *4b:69:6c:72:6f:79:20:77:61:73:20:68:65:72:65:21*
47
    :type fingerprint: `string`
43
    *fingerprint* is a hex string representing the host key fingerprint, colon-delimited e.g. `"4b:69:6c:72:6f:79:20:77:61:73:20:68:65:72:65:21"`
48 44
    """
49 45
    return False
50 46

  
......
70 66
        self._parsing_pos = 0
71 67
    
72 68
    def _parse(self):
73
        """Messages ae delimited by MSG_DELIM. The buffer could have grown by a
74
        maximum of BUF_SIZE bytes everytime this method is called. Retains state
75
        across method calls and if a byte has been read it will not be
76
        considered again.
77
        """
69
        "Messages ae delimited by MSG_DELIM. The buffer could have grown by a maximum of BUF_SIZE bytes everytime this method is called. Retains state across method calls and if a byte has been read it will not be considered again."
78 70
        delim = MSG_DELIM
79 71
        n = len(delim) - 1
80 72
        expect = self._parsing_state
......
115 107
        self._parsing_pos = self._buffer.tell()
116 108

  
117 109
    def load_known_hosts(self, filename=None):
118
        """Load host keys from a :file:`known_hosts`-style file. Can be called multiple times.
110
        """Load host keys from an openssh :file:`known_hosts`-style file. Can be called multiple times.
119 111

  
120
        If *filename* is not specified, looks in the default locations i.e.
121
        :file:`~/.ssh/known_hosts` and :file:`~/ssh/known_hosts` for Windows.
112
        If *filename* is not specified, looks in the default locations i.e. :file:`~/.ssh/known_hosts` and :file:`~/ssh/known_hosts` for Windows.
122 113
        """
123 114
        if filename is None:
124 115
            filename = os.path.expanduser('~/.ssh/known_hosts')
......
139 130
            self._transport.close()
140 131
        self._connected = False
141 132

  
142
    def connect(self, host, port=830, timeout=None,
143
                unknown_host_cb=default_unknown_host_cb,
144
                username=None, password=None,
145
                key_filename=None, allow_agent=True, look_for_keys=True):
146
        """Connect via SSH and initialize the NETCONF session. First attempts the publickey
147
        authentication method and then password authentication.
133
    # REMEMBER to update transport.rst if sig. changes, since it is hardcoded there
134
    def connect(self, host, port=830, timeout=None, unknown_host_cb=default_unknown_host_cb,
135
                username=None, password=None, key_filename=None, allow_agent=True, look_for_keys=True):
136
        """Connect via SSH and initialize the NETCONF session. First attempts the publickey authentication method and then password authentication.
148 137

  
149
        To disable attemting publickey authentication altogether, call with *allow_agent* and
150
        *look_for_keys* as :const:`False`.
138
        To disable attempting publickey authentication altogether, call with *allow_agent* and *look_for_keys* as `False`.
151 139

  
152 140
        :arg host: the hostname or IP address to connect to
153
        :type host: `string`
141
        :type host: string
154 142

  
155 143
        :arg port: by default 830, but some devices use the default SSH port of 22 so this may need to be specified
156
        :type port: `int`
144
        :type port: int
157 145

  
158 146
        :arg timeout: an optional timeout for socket connect
159
        :type timeout: `int`
147
        :type timeout: int
160 148

  
161 149
        :arg unknown_host_cb: called when the server host key is not recognized
162
        :type unknown_host_cb: see :meth:`signature <ssh.default_unknown_host_cb>`
150
        :type unknown_host_cb: see the signature of :func:`default_unknown_host_cb`
163 151

  
164 152
        :arg username: the username to use for SSH authentication
165
        :type username: `string`
153
        :type username: string
166 154

  
167 155
        :arg password: the password used if using password authentication, or the passphrase to use for unlocking keys that require it
168
        :type password: `string`
156
        :type password: string
169 157

  
170 158
        :arg key_filename: a filename where a the private key to be used can be found
171
        :type key_filename: `string`
159
        :type key_filename: string
172 160

  
173 161
        :arg allow_agent: enables querying SSH agent (if found) for keys
174
        :type allow_agent: `bool`
162
        :type allow_agent: bool
175 163

  
176 164
        :arg look_for_keys: enables looking in the usual locations for ssh keys (e.g. :file:`~/.ssh/id_*`)
177
        :type look_for_keys: `bool`
165
        :type look_for_keys: bool
178 166
        """
179

  
180 167
        if username is None:
181 168
            username = getpass.getuser()
182 169
        
......
306 293
        q = self._q
307 294
        try:
308 295
            while True:
309
                # select on a paramiko ssh channel object does not ever return
310
                # it in the writable list, so it channel's don't exactly emulate
311
                # the socket api
296
                # select on a paramiko ssh channel object does not ever return it in the writable list, so channels don't exactly emulate the socket api
312 297
                r, w, e = select([chan], [], [], TICK)
313
                # will wakeup evey TICK seconds to check if something
314
                # to send, more if something to read (due to select returning
315
                # chan in readable list)
298
                # will wakeup evey TICK seconds to check if something to send, more if something to read (due to select returning chan in readable list)
316 299
                if r:
317 300
                    data = chan.recv(BUF_SIZE)
318 301
                    if data:
......
335 318

  
336 319
    @property
337 320
    def transport(self):
338
        """Underlying `paramiko.Transport
339
        <http://www.lag.net/paramiko/docs/paramiko.Transport-class.html>`_
340
        object. This makes it possible to call methods like set_keepalive on it.
341
        """
321
        "Underlying `paramiko.Transport <http://www.lag.net/paramiko/docs/paramiko.Transport-class.html>`_ object. This makes it possible to call methods like set_keepalive on it."
342 322
        return self._transport
b/ncclient/xml_.py
41 41
        from xml.etree import ElementTree
42 42
        # cElementTree uses ElementTree's _namespace_map, so that's ok
43 43
        ElementTree._namespace_map[uri] = prefix
44
register_namespace.func_doc = "ElementTree's namespace map determines the prefixes for namespace URI's when serializing to XML. This method allows modifying this map to specify a prefix for a namespace URI."
44 45

  
45 46
for (ns, pre) in {
46 47
    BASE_NS_1_0: 'nc',
......
51 52
}.items(): register_namespace(pre, ns)
52 53

  
53 54
qualify = lambda tag, ns=BASE_NS_1_0: tag if ns is None else "{%s}%s" % (ns, tag)
54
"""Qualify a tag name with a namespace, in :mod:`~xml.etree.ElementTree` fashion i.e. *{namespace}tagname*.
55

  
56
:arg tag: name of the tag
57
:type arg: `string`
58

  
59
:arg ns: namespace to qualify with
60
:type ns: `string`
61
"""
55
"""Qualify a *tag* name with a *namespace*, in :mod:`~xml.etree.ElementTree` fashion i.e. *{namespace}tagname*."""
62 56

  
63 57
def to_xml(ele, encoding="UTF-8"):
64
    """Convert an `~xml.etree.ElementTree.Element` to XML.
65
    
66
    :arg ele: the `~xml.etree.ElementTree.Element`
67
    :arg encoding: character encoding
68
    :rtype: `string`
69
    """
58
    "Convert and return the XML for an *ele* (:class:`~xml.etree.ElementTree.Element`) with specified *encoding*."
70 59
    xml = ET.tostring(ele, encoding)
71 60
    return xml if xml.startswith('<?xml') else '<?xml version="1.0" encoding="%s"?>%s' % (encoding, xml)
72 61

  
73 62
def to_ele(x):
74
    """Convert XML to `~xml.etree.ElementTree.Element`. If passed an `~xml.etree.ElementTree.Element` simply returns that.
75
    
76
    :arg x: the XML document or element
77
    :type x: `string` or `~xml.etree.ElementTree.Element`
78
    :rtype: `~xml.etree.ElementTree.Element`
79
    """
63
    "Convert and return the :class:`~xml.etree.ElementTree.Element` for the XML document *x*. If *x* is already an :class:`~xml.etree.ElementTree.Element` simply returns that."
80 64
    return x if ET.iselement(x) else ET.fromstring(x)
81 65

  
82 66
def parse_root(raw):
83
    """Efficiently parses the root element of an XML document.
84

  
85
    :arg raw: XML document
86
    :returns: a tuple of ``(tag, attrib)``, where *tag* is the (qualified) name of the element and *attrib* is a dictionary of its attributes.
87
    :rtype: `tuple`
88
    """
67
    "Efficiently parses the root element of a *raw* XML document, returning a tuple of its qualified name and attribute dictionary."
89 68
    fp = StringIO(raw)
90 69
    for event, element in ET.iterparse(fp, events=('start',)):
91 70
        return (element.tag, element.attrib)
......
93 72
def validated_element(x, tags=None, attrs=None):
94 73
    """Checks if the root element of an XML document or Element meets the supplied criteria.
95 74
    
96
    :arg tags: allowable tag name or sequence of allowable alternatives
97
    :type tags: `string` or sequence of strings
98
    
99
    :arg attrs: list of required attributes, each of which may be a sequence of several allowable alternatives
100
    :type attrs: sequence of strings or sequence of sequences of strings
101
    
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff