├── metadata
└── default.meta
├── .gitignore
├── bin
├── config.ini.sample
├── suds
│ ├── bindings
│ │ ├── __init__.py
│ │ ├── rpc.py
│ │ ├── multiref.py
│ │ └── document.py
│ ├── umx
│ │ ├── basic.py
│ │ ├── __init__.py
│ │ ├── attrlist.py
│ │ ├── encoded.py
│ │ ├── typed.py
│ │ └── core.py
│ ├── mx
│ │ ├── basic.py
│ │ ├── __init__.py
│ │ ├── typer.py
│ │ ├── encoded.py
│ │ └── core.py
│ ├── sax
│ │ ├── document.py
│ │ ├── enc.py
│ │ ├── __init__.py
│ │ ├── text.py
│ │ ├── parser.py
│ │ └── attribute.py
│ ├── metrics.py
│ ├── transport
│ │ ├── options.py
│ │ ├── https.py
│ │ ├── __init__.py
│ │ └── http.py
│ ├── soaparray.py
│ ├── serviceproxy.py
│ ├── xsd
│ │ ├── __init__.py
│ │ ├── deplist.py
│ │ ├── doctor.py
│ │ ├── query.py
│ │ └── sxbuiltin.py
│ ├── builder.py
│ ├── __init__.py
│ ├── options.py
│ ├── reader.py
│ ├── wsse.py
│ ├── LICENSE
│ ├── plugin.py
│ └── servicedefinition.py
├── jiracommon.py
├── jira_soap.py
└── jira_xml.py
├── default
├── app.conf
├── jira.conf
└── commands.conf
├── LICENSE
├── CHANGELOG.md
├── TESTS.md
└── README.md
/metadata/default.meta:
--------------------------------------------------------------------------------
1 | []
2 | export=system
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bin/config.ini
2 | local/*
3 | metadata/local.meta
4 | *.pyc
--------------------------------------------------------------------------------
/bin/config.ini.sample:
--------------------------------------------------------------------------------
1 | [jira]
2 | hostname = jira.example.com
3 | username = admin
4 | password = changeme
5 | jira_protocol = https
6 | jira_port = 443
7 | soap_protocol = https
8 | soap_port = 8080
9 | maxresults = 100
--------------------------------------------------------------------------------
/default/app.conf:
--------------------------------------------------------------------------------
1 | [ui]
2 | is_visible = false
3 | label = Add-on for JIRA
4 |
5 | [install]
6 | build = 1
7 | is_configured = true
8 |
9 | [package]
10 | id = jira
11 | check_for_updates = true
12 |
13 | [launcher]
14 | author = Fred de Boer, Russell Uman, Stephen Sorkin, Jeffrey Isenberg
15 | description = Add-on for JIRA
16 | version = 2.1
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2013 Splunk Inc.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
--------------------------------------------------------------------------------
/default/jira.conf:
--------------------------------------------------------------------------------
1 | [jira]
2 | default_project = WTF
3 | tempMax = 1000
4 |
5 | ## SearchXML command configuration ##
6 | # Built-in fields to display. Required.
7 | # If you want to use one of the time options, include updated, created, and/or resolved
8 | # If you want a field that contains multiple values (e.g., lables), you need to include the path to the individual elements
9 | keys = link,project,key,summary,type,priority,status,resolution,assignee,reporter,created,updated,resolved,fixVersion,components,labels/label
10 | # Fields containing durations, force them to return seconds instead of something human-readable. Optional.
11 | time_keys = timeestimate, originalestimate, timespent
12 | # Custom fields to display. Optional.
13 | custom_keys =
--------------------------------------------------------------------------------
/bin/suds/bindings/__init__.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Provides modules containing classes to support Web Services (SOAP)
19 | bindings.
20 | """
--------------------------------------------------------------------------------
/default/commands.conf:
--------------------------------------------------------------------------------
1 | [jira]
2 | filename = jira_rest.py
3 | local = true
4 | overrides_timeorder = true
5 | streaming = true
6 | supports_multivalues = true
7 | generating = stream
8 |
9 | [jirarest]
10 | filename = jira_rest.py
11 | local = true
12 | overrides_timeorder = true
13 | streaming = true
14 | supports_multivalues = true
15 | generating = stream
16 |
17 | [jirasoap]
18 | filename = jira_soap.py
19 | generating = true
20 | required_fields =
21 |
22 | # These streaming versions create real events. I'm not sure which is better yet. For now you get options.
23 | [jirasoapevents]
24 | filename = jira_soap.py
25 | generating=true
26 | local = true
27 | overrides_timeorder = true
28 | passauth = true
29 | required_fields =
30 | retainsevents = true
31 |
32 | [jiraxml]
33 | filename = jira_xml.py
34 | generating = true
35 | passauth = true
36 | required_fields =
37 |
38 | # These streaming versions create real events. I'm not sure which is better yet. For now you get options.
39 | [jiraxmlevents]
40 | filename = jira_xml.py
41 | generating=true
42 | local = true
43 | overrides_timeorder = true
44 | passauth = true
45 | required_fields =
46 | retainsevents = true
--------------------------------------------------------------------------------
/bin/jiracommon.py:
--------------------------------------------------------------------------------
1 | import ConfigParser
2 | import os
3 | import splunk.bundle as sb
4 | import splunk.Intersplunk as isp
5 |
6 | def getSplunkConf():
7 | results, dummyresults, settings = isp.getOrganizedResults()
8 | namespace = settings.get("namespace", None)
9 | owner = settings.get("owner", None)
10 | sessionKey = settings.get("sessionKey", None)
11 |
12 | conf = sb.getConf('jira', namespace=namespace, owner=owner, sessionKey=sessionKey)
13 | stanza = conf.get('jira')
14 |
15 | return stanza
16 |
17 | def getLocalConf():
18 | local_conf = ConfigParser.ConfigParser()
19 | location = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))
20 | local_conf.read(location + '/config.ini')
21 |
22 | return local_conf
23 |
24 | def flatten(item, keys):
25 | response = {}
26 | for (key, replacer) in keys:
27 | if not replacer:
28 | response[key] = str(item[key])
29 | else:
30 | response[key] = replacer.get(item[key], item[key])
31 |
32 | return response
33 |
34 | def api_to_dict(apidata):
35 | dictdata = {}
36 | for item in apidata:
37 | dictdata[item['id']] = item['name']
38 | return dictdata
--------------------------------------------------------------------------------
/bin/suds/umx/basic.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Provides basic unmarshaller classes.
19 | """
20 |
21 | from logging import getLogger
22 | from suds import *
23 | from suds.umx import *
24 | from suds.umx.core import Core
25 |
26 |
27 | class Basic(Core):
28 | """
29 | A object builder (unmarshaller).
30 | """
31 |
32 | def process(self, node):
33 | """
34 | Process an object graph representation of the xml I{node}.
35 | @param node: An XML tree.
36 | @type node: L{sax.element.Element}
37 | @return: A suds object.
38 | @rtype: L{Object}
39 | """
40 | content = Content(node)
41 | return Core.process(self, content)
--------------------------------------------------------------------------------
/bin/suds/mx/basic.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Provides basic I{marshaller} classes.
19 | """
20 |
21 | from logging import getLogger
22 | from suds import *
23 | from suds.mx import *
24 | from suds.mx.core import Core
25 |
26 | log = getLogger(__name__)
27 |
28 |
29 | class Basic(Core):
30 | """
31 | A I{basic} (untyped) marshaller.
32 | """
33 |
34 | def process(self, value, tag=None):
35 | """
36 | Process (marshal) the tag with the specified value using the
37 | optional type information.
38 | @param value: The value (content) of the XML node.
39 | @type value: (L{Object}|any)
40 | @param tag: The (optional) tag name for the value. The default is
41 | value.__class__.__name__
42 | @type tag: str
43 | @return: An xml node.
44 | @rtype: L{Element}
45 | """
46 | content = Content(tag=tag, value=value)
47 | result = Core.process(self, content)
48 | return result
--------------------------------------------------------------------------------
/bin/suds/umx/__init__.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Provides modules containing classes to support
19 | unmarshalling (XML).
20 | """
21 |
22 | from suds.sudsobject import Object
23 |
24 |
25 |
26 | class Content(Object):
27 | """
28 | @ivar node: The content source node.
29 | @type node: L{sax.element.Element}
30 | @ivar data: The (optional) content data.
31 | @type data: L{Object}
32 | @ivar text: The (optional) content (xml) text.
33 | @type text: basestring
34 | """
35 |
36 | extensions = []
37 |
38 | def __init__(self, node, **kwargs):
39 | Object.__init__(self)
40 | self.node = node
41 | self.data = None
42 | self.text = None
43 | for k,v in kwargs.items():
44 | setattr(self, k, v)
45 |
46 | def __getattr__(self, name):
47 | if name not in self.__dict__:
48 | if name in self.extensions:
49 | v = None
50 | setattr(self, name, v)
51 | else:
52 | raise AttributeError, \
53 | 'Content has no attribute %s' % name
54 | else:
55 | v = self.__dict__[name]
56 | return v
--------------------------------------------------------------------------------
/bin/suds/sax/document.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Provides XML I{document} classes.
19 | """
20 |
21 | from logging import getLogger
22 | from suds import *
23 | from suds.sax import *
24 | from suds.sax.element import Element
25 |
26 | log = getLogger(__name__)
27 |
28 | class Document(Element):
29 | """ simple document """
30 |
31 | DECL = ''
32 |
33 | def __init__(self, root=None):
34 | Element.__init__(self, 'document')
35 | if root is not None:
36 | self.append(root)
37 |
38 | def root(self):
39 | if len(self.children):
40 | return self.children[0]
41 | else:
42 | return None
43 |
44 | def str(self):
45 | s = []
46 | s.append(self.DECL)
47 | s.append('\n')
48 | s.append(self.root().str())
49 | return ''.join(s)
50 |
51 | def plain(self):
52 | s = []
53 | s.append(self.DECL)
54 | s.append(self.root().plain())
55 | return ''.join(s)
56 |
57 | def __str__(self):
58 | return unicode(self).encode('utf-8')
59 |
60 | def __unicode__(self):
61 | return self.str()
--------------------------------------------------------------------------------
/bin/suds/mx/__init__.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Provides modules containing classes to support
19 | marshalling (XML).
20 | """
21 |
22 | from suds.sudsobject import Object
23 |
24 |
25 | class Content(Object):
26 | """
27 | Marshaller Content.
28 | @ivar tag: The content tag.
29 | @type tag: str
30 | @ivar value: The content's value.
31 | @type value: I{any}
32 | """
33 |
34 | extensions = []
35 |
36 | def __init__(self, tag=None, value=None, **kwargs):
37 | """
38 | @param tag: The content tag.
39 | @type tag: str
40 | @param value: The content's value.
41 | @type value: I{any}
42 | """
43 | Object.__init__(self)
44 | self.tag = tag
45 | self.value = value
46 | for k,v in kwargs.items():
47 | setattr(self, k, v)
48 |
49 | def __getattr__(self, name):
50 | if name not in self.__dict__:
51 | if name in self.extensions:
52 | v = None
53 | setattr(self, name, v)
54 | else:
55 | raise AttributeError, \
56 | 'Content has no attribute %s' % name
57 | else:
58 | v = self.__dict__[name]
59 | return v
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | Change Log
2 | ==========
3 |
4 | ## 2.1
5 |
6 | * Add detail option to rapidboards mode
7 | * Fix exception when Labels have the value "Labels"
8 |
9 | ## 2.0.1
10 |
11 | * Add urlencode.quote_plus to arguments so that we don't barf on special characters
12 |
13 | ## 2.0
14 |
15 | * Add jirarest command and documentation
16 | * Rename jira and jiraevents commands to jiraxml and jiraxmlevents respectively - "| jira" is now an alias of jirarest
17 | * jiraxml and jirasoap commands are now deprecated, and will not be developed further (but pull requests are still accepted if there's something you need to have fixed!)
18 | * source is standardized as the command being run: jira_rest, jira_xml, jira_soap
19 | * sourcetype is standardized as the kind of results being returned: jira_issues, jira_filters, jira_sprints, etc.
20 | * index is no longer set in returned events
21 |
22 | ## 1.11
23 |
24 | * Remove _raw field as it was misformatted, and made it impossible to collect results in a summary index
25 |
26 | ## 1.10
27 |
28 | * Add time option to SearchXML and SOAP commands, allows setting _time field to now(), updated, resolved, or created
29 |
30 | ## 1.9
31 |
32 | * Make time_keys and custom_keys configuration parameters optional for the SearchXML command
33 |
34 | ## 1.8
35 |
36 | * Make Protocol and Port configurable
37 | * gitignore .pyc files
38 |
39 | ## 1.7
40 |
41 | * Set _time to now()
42 | * Fix a bug that breaks the main while loop when tempMax is undefined
43 |
44 | ## 1.6
45 |
46 | * Make output of fixVersions prettier in the SOAP command
47 | * Switch from keywords to sys.argv to parse command line and options
48 | * Fix bug in default query
49 |
50 | ## 1.5
51 |
52 | * Make tempMax configurable in SearchXML command
53 | * Make mv fields actually mv in SearchXML command
54 | * Manually construct header in SearchXML command to preserve ordering
55 |
56 | ## 1.4
57 |
58 | * Fix bug with outputResults()
59 | * Move hostname configuration to config.ini
60 |
61 | ## 1.3
62 |
63 | * Add alternate streaming versions of both commands
64 |
65 | ## 1.2
66 |
67 | * Add SOAP command
68 |
69 | ## 1.1
70 |
71 | * Add _time field
72 |
73 | ## 1.0
74 |
75 | * Initial commit of SearchXML command
--------------------------------------------------------------------------------
/bin/suds/metrics.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | The I{metrics} module defines classes and other resources
19 | designed for collecting and reporting performance metrics.
20 | """
21 |
22 | import time
23 | from logging import getLogger
24 | from suds import *
25 | from math import modf
26 |
27 | log = getLogger(__name__)
28 |
29 | class Timer:
30 |
31 | def __init__(self):
32 | self.started = 0
33 | self.stopped = 0
34 |
35 | def start(self):
36 | self.started = time.time()
37 | self.stopped = 0
38 | return self
39 |
40 | def stop(self):
41 | if self.started > 0:
42 | self.stopped = time.time()
43 | return self
44 |
45 | def duration(self):
46 | return ( self.stopped - self.started )
47 |
48 | def __str__(self):
49 | if self.started == 0:
50 | return 'not-running'
51 | if self.started > 0 and self.stopped == 0:
52 | return 'started: %d (running)' % self.started
53 | duration = self.duration()
54 | jmod = ( lambda m : (m[1], m[0]*1000) )
55 | if duration < 1:
56 | ms = (duration*1000)
57 | return '%d (ms)' % ms
58 | if duration < 60:
59 | m = modf(duration)
60 | return '%d.%.3d (seconds)' % jmod(m)
61 | m = modf(duration/60)
62 | return '%d.%.3d (minutes)' % jmod(m)
63 |
--------------------------------------------------------------------------------
/TESTS.md:
--------------------------------------------------------------------------------
1 | Tests
2 | =====
3 |
4 | This is a manual test script (which is not the best, but it's significantly better than nothing)
5 |
6 | Please test each of these queries, substituting variables for ones that make sense for your JIRA installation, before each
7 | release or pull request. | table helps verify.
8 |
9 | ## jirarest
10 |
11 | | jirarest filters
12 | * Should return a list of filters favorited by the jira user.
13 |
14 | | jirarest issues FILTER_ID
15 | * Should return a list of issues. Use an id from the filters mode.
16 |
17 | | jirarest jqlsearch JQL_QUERY
18 | * Should return a list of issues for some reasonable query.
19 |
20 | | jirarest jqlsearch JQL_QUERY comments
21 | * Should return a list of comments on the issues returned by the query.
22 |
23 | | jirarest jqlsearch JQL_QUERY changefield
24 | * Should return a list of issues with internal field names instead of pretty field names.
25 |
26 | | jirarest jqlsearch JQL_QUERY changetime updated
27 | * Should return a list of issues with _time set to updated instead of created.
28 |
29 | | jirarest jqlsearch JQL_QUERY comments changefield changetime updated
30 | * All together now.
31 |
32 | | jirarest jqlsearch JQL_QUERY fields "status,duedate"
33 | * Should return a list of issues with just key, created, status, and duedate fields.
34 |
35 | | jirarest changelog JQL_QUERY
36 | * Should return a list of changes (history) for the issues returned by the query.
37 |
38 | | jirarest rapidboards list
39 | * Should return a list of all rapidboards.
40 |
41 | | jirarest rapidboards all
42 | * Should return a list of all sprints in all rapidboards.
43 |
44 | | jirarest rapidboards RAPIDBOARD_ID
45 | * Should return a list of all issues in a specific rapidboard. Use an id from the list option.
46 |
47 | | jirarest rapidboards RAPIDBOARD_ID detail sprints
48 | * Should return a list of all sprints in a specific rapidboard. Use an id from the list option.
49 |
50 | | jirarest rapidboards RAPIDBOARD_ID detail issues
51 | * Should return a list of all active issues in a specific rapidboard, including column and swimlane information.
52 | Use an id from the list option.
53 |
54 | ... | jirarest batch JQL_QUERY $foo$
55 | * I don't really know how to test this I should get an example from Fred.
56 |
57 | ## jirasoap
58 |
59 | ## jiraxml
--------------------------------------------------------------------------------
/bin/suds/transport/options.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Contains classes for transport options.
19 | """
20 |
21 |
22 | from suds.transport import *
23 | from suds.properties import *
24 |
25 |
26 | class Options(Skin):
27 | """
28 | Options:
29 | - B{proxy} - An http proxy to be specified on requests.
30 | The proxy is defined as {protocol:proxy,}
31 | - type: I{dict}
32 | - default: {}
33 | - B{timeout} - Set the url open timeout (seconds).
34 | - type: I{float}
35 | - default: 90
36 | - B{headers} - Extra HTTP headers.
37 | - type: I{dict}
38 | - I{str} B{http} - The I{http} protocol proxy URL.
39 | - I{str} B{https} - The I{https} protocol proxy URL.
40 | - default: {}
41 | - B{username} - The username used for http authentication.
42 | - type: I{str}
43 | - default: None
44 | - B{password} - The password used for http authentication.
45 | - type: I{str}
46 | - default: None
47 | """
48 | def __init__(self, **kwargs):
49 | domain = __name__
50 | definitions = [
51 | Definition('proxy', dict, {}),
52 | Definition('timeout', (int,float), 90),
53 | Definition('headers', dict, {}),
54 | Definition('username', basestring, None),
55 | Definition('password', basestring, None),
56 | ]
57 | Skin.__init__(self, domain, definitions, kwargs)
--------------------------------------------------------------------------------
/bin/suds/soaparray.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | The I{soaparray} module provides XSD extensions for handling
19 | soap (section 5) encoded arrays.
20 | """
21 |
22 | from suds import *
23 | from logging import getLogger
24 | from suds.xsd.sxbasic import Factory as SXFactory
25 | from suds.xsd.sxbasic import Attribute as SXAttribute
26 |
27 |
28 | class Attribute(SXAttribute):
29 | """
30 | Represents an XSD that handles special
31 | attributes that are extensions for WSDLs.
32 | @ivar aty: Array type information.
33 | @type aty: The value of wsdl:arrayType.
34 | """
35 |
36 | def __init__(self, schema, root, aty):
37 | """
38 | @param aty: Array type information.
39 | @type aty: The value of wsdl:arrayType.
40 | """
41 | SXAttribute.__init__(self, schema, root)
42 | if aty.endswith('[]'):
43 | self.aty = aty[:-2]
44 | else:
45 | self.aty = aty
46 |
47 | def autoqualified(self):
48 | aqs = SXAttribute.autoqualified(self)
49 | aqs.append('aty')
50 | return aqs
51 |
52 | def description(self):
53 | d = SXAttribute.description(self)
54 | d = d+('aty',)
55 | return d
56 |
57 | #
58 | # Builder function, only builds Attribute when arrayType
59 | # attribute is defined on root.
60 | #
61 | def __fn(x, y):
62 | ns = (None, "http://schemas.xmlsoap.org/wsdl/")
63 | aty = y.get('arrayType', ns=ns)
64 | if aty is None:
65 | return SXAttribute(x, y)
66 | else:
67 | return Attribute(x, y, aty)
68 |
69 | #
70 | # Remap tags to __fn() builder.
71 | #
72 | SXFactory.maptag('attribute', __fn)
--------------------------------------------------------------------------------
/bin/suds/sax/enc.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Provides XML I{special character} encoder classes.
19 | """
20 |
21 | import re
22 |
23 | class Encoder:
24 | """
25 | An XML special character encoder/decoder.
26 | @cvar encodings: A mapping of special characters encoding.
27 | @type encodings: [(str,str)]
28 | @cvar decodings: A mapping of special characters decoding.
29 | @type decodings: [(str,str)]
30 | @cvar special: A list of special characters
31 | @type special: [char]
32 | """
33 |
34 | encodings = \
35 | (( '&(?!(amp|lt|gt|quot|apos);)', '&' ),( '<', '<' ),( '>', '>' ),( '"', '"' ),("'", ''' ))
36 | decodings = \
37 | (( '<', '<' ),( '>', '>' ),( '"', '"' ),( ''', "'" ),( '&', '&' ))
38 | special = \
39 | ('&', '<', '>', '"', "'")
40 |
41 | def needsEncoding(self, s):
42 | """
43 | Get whether string I{s} contains special characters.
44 | @param s: A string to check.
45 | @type s: str
46 | @return: True if needs encoding.
47 | @rtype: boolean
48 | """
49 | if isinstance(s, basestring):
50 | for c in self.special:
51 | if c in s:
52 | return True
53 | return False
54 |
55 | def encode(self, s):
56 | """
57 | Encode special characters found in string I{s}.
58 | @param s: A string to encode.
59 | @type s: str
60 | @return: The encoded string.
61 | @rtype: str
62 | """
63 | if isinstance(s, basestring) and self.needsEncoding(s):
64 | for x in self.encodings:
65 | s = re.sub(x[0], x[1], s)
66 | return s
67 |
68 | def decode(self, s):
69 | """
70 | Decode special characters encodings found in string I{s}.
71 | @param s: A string to decode.
72 | @type s: str
73 | @return: The decoded string.
74 | @rtype: str
75 | """
76 | if isinstance(s, basestring) and '&' in s:
77 | for x in self.decodings:
78 | s = s.replace(x[0], x[1])
79 | return s
80 |
--------------------------------------------------------------------------------
/bin/suds/umx/attrlist.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Provides filtered attribute list classes.
19 | """
20 |
21 | from suds import *
22 | from suds.umx import *
23 | from suds.sax import Namespace
24 |
25 |
26 | class AttrList:
27 | """
28 | A filtered attribute list.
29 | Items are included during iteration if they are in either the (xs) or
30 | (xml) namespaces.
31 | @ivar raw: The I{raw} attribute list.
32 | @type raw: list
33 | """
34 | def __init__(self, attributes):
35 | """
36 | @param attributes: A list of attributes
37 | @type attributes: list
38 | """
39 | self.raw = attributes
40 |
41 | def real(self):
42 | """
43 | Get list of I{real} attributes which exclude xs and xml attributes.
44 | @return: A list of I{real} attributes.
45 | @rtype: I{generator}
46 | """
47 | for a in self.raw:
48 | if self.skip(a): continue
49 | yield a
50 |
51 | def rlen(self):
52 | """
53 | Get the number of I{real} attributes which exclude xs and xml attributes.
54 | @return: A count of I{real} attributes.
55 | @rtype: L{int}
56 | """
57 | n = 0
58 | for a in self.real():
59 | n += 1
60 | return n
61 |
62 | def lang(self):
63 | """
64 | Get list of I{filtered} attributes which exclude xs.
65 | @return: A list of I{filtered} attributes.
66 | @rtype: I{generator}
67 | """
68 | for a in self.raw:
69 | if a.qname() == 'xml:lang':
70 | return a.value
71 | return None
72 |
73 | def skip(self, attr):
74 | """
75 | Get whether to skip (filter-out) the specified attribute.
76 | @param attr: An attribute.
77 | @type attr: I{Attribute}
78 | @return: True if should be skipped.
79 | @rtype: bool
80 | """
81 | ns = attr.namespace()
82 | skip = (
83 | Namespace.xmlns[1],
84 | 'http://schemas.xmlsoap.org/soap/encoding/',
85 | 'http://schemas.xmlsoap.org/soap/envelope/',
86 | 'http://www.w3.org/2003/05/soap-envelope',
87 | )
88 | return ( Namespace.xs(ns) or ns[1] in skip )
89 |
--------------------------------------------------------------------------------
/bin/suds/serviceproxy.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | The service proxy provides access to web services.
19 |
20 | Replaced by: L{client.Client}
21 | """
22 |
23 | from logging import getLogger
24 | from suds import *
25 | from suds.client import Client
26 |
27 | log = getLogger(__name__)
28 |
29 |
30 | class ServiceProxy(object):
31 |
32 | """
33 | A lightweight soap based web service proxy.
34 | @ivar __client__: A client.
35 | Everything is delegated to the 2nd generation API.
36 | @type __client__: L{Client}
37 | @note: Deprecated, replaced by L{Client}.
38 | """
39 |
40 | def __init__(self, url, **kwargs):
41 | """
42 | @param url: The URL for the WSDL.
43 | @type url: str
44 | @param kwargs: keyword arguments.
45 | @keyword faults: Raise faults raised by server (default:True),
46 | else return tuple from service method invocation as (http code, object).
47 | @type faults: boolean
48 | @keyword proxy: An http proxy to be specified on requests (default:{}).
49 | The proxy is defined as {protocol:proxy,}
50 | @type proxy: dict
51 | """
52 | client = Client(url, **kwargs)
53 | self.__client__ = client
54 |
55 | def get_instance(self, name):
56 | """
57 | Get an instance of a WSDL type by name
58 | @param name: The name of a type defined in the WSDL.
59 | @type name: str
60 | @return: An instance on success, else None
61 | @rtype: L{sudsobject.Object}
62 | """
63 | return self.__client__.factory.create(name)
64 |
65 | def get_enum(self, name):
66 | """
67 | Get an instance of an enumeration defined in the WSDL by name.
68 | @param name: The name of a enumeration defined in the WSDL.
69 | @type name: str
70 | @return: An instance on success, else None
71 | @rtype: L{sudsobject.Object}
72 | """
73 | return self.__client__.factory.create(name)
74 |
75 | def __str__(self):
76 | return str(self.__client__)
77 |
78 | def __unicode__(self):
79 | return unicode(self.__client__)
80 |
81 | def __getattr__(self, name):
82 | builtin = name.startswith('__') and name.endswith('__')
83 | if builtin:
84 | return self.__dict__[name]
85 | else:
86 | return getattr(self.__client__.service, name)
--------------------------------------------------------------------------------
/bin/suds/xsd/__init__.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | The I{schema} module provides a intelligent representation of
19 | an XSD schema. The I{raw} model is the XML tree and the I{model}
20 | is the denormalized, objectified and intelligent view of the schema.
21 | Most of the I{value-add} provided by the model is centered around
22 | tranparent referenced type resolution and targeted denormalization.
23 | """
24 |
25 | from logging import getLogger
26 | from suds import *
27 | from suds.sax import Namespace, splitPrefix
28 |
29 | log = getLogger(__name__)
30 |
31 |
32 | def qualify(ref, resolvers, defns=Namespace.default):
33 | """
34 | Get a reference that is I{qualified} by namespace.
35 | @param ref: A referenced schema type name.
36 | @type ref: str
37 | @param resolvers: A list of objects to be used to resolve types.
38 | @type resolvers: [L{sax.element.Element},]
39 | @param defns: An optional target namespace used to qualify references
40 | when no prefix is specified.
41 | @type defns: A default namespace I{tuple: (prefix,uri)} used when ref not prefixed.
42 | @return: A qualified reference.
43 | @rtype: (name, namespace-uri)
44 | """
45 | ns = None
46 | p, n = splitPrefix(ref)
47 | if p is not None:
48 | if not isinstance(resolvers, (list, tuple)):
49 | resolvers = (resolvers,)
50 | for r in resolvers:
51 | resolved = r.resolvePrefix(p)
52 | if resolved[1] is not None:
53 | ns = resolved
54 | break
55 | if ns is None:
56 | raise Exception('prefix (%s) not resolved' % p)
57 | else:
58 | ns = defns
59 | return (n, ns[1])
60 |
61 | def isqref(object):
62 | """
63 | Get whether the object is a I{qualified reference}.
64 | @param object: An object to be tested.
65 | @type object: I{any}
66 | @rtype: boolean
67 | @see: L{qualify}
68 | """
69 | return (\
70 | isinstance(object, tuple) and \
71 | len(object) == 2 and \
72 | isinstance(object[0], basestring) and \
73 | isinstance(object[1], basestring))
74 |
75 |
76 | class Filter:
77 | def __init__(self, inclusive=False, *items):
78 | self.inclusive = inclusive
79 | self.items = items
80 | def __contains__(self, x):
81 | if self.inclusive:
82 | result = ( x in self.items )
83 | else:
84 | result = ( x not in self.items )
85 | return result
86 |
87 |
--------------------------------------------------------------------------------
/bin/suds/bindings/rpc.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Provides classes for the (WS) SOAP I{rpc/literal} and I{rpc/encoded} bindings.
19 | """
20 |
21 | from logging import getLogger
22 | from suds import *
23 | from suds.mx.encoded import Encoded as MxEncoded
24 | from suds.umx.encoded import Encoded as UmxEncoded
25 | from suds.bindings.binding import Binding, envns
26 | from suds.sax.element import Element
27 |
28 | log = getLogger(__name__)
29 |
30 |
31 | encns = ('SOAP-ENC', 'http://schemas.xmlsoap.org/soap/encoding/')
32 |
33 | class RPC(Binding):
34 | """
35 | RPC/Literal binding style.
36 | """
37 |
38 | def param_defs(self, method):
39 | return self.bodypart_types(method)
40 |
41 | def envelope(self, header, body):
42 | env = Binding.envelope(self, header, body)
43 | env.addPrefix(encns[0], encns[1])
44 | env.set('%s:encodingStyle' % envns[0],
45 | 'http://schemas.xmlsoap.org/soap/encoding/')
46 | return env
47 |
48 | def bodycontent(self, method, args, kwargs):
49 | n = 0
50 | root = self.method(method)
51 | for pd in self.param_defs(method):
52 | if n < len(args):
53 | value = args[n]
54 | else:
55 | value = kwargs.get(pd[0])
56 | p = self.mkparam(method, pd, value)
57 | if p is not None:
58 | root.append(p)
59 | n += 1
60 | return root
61 |
62 | def replycontent(self, method, body):
63 | return body[0].children
64 |
65 | def method(self, method):
66 | """
67 | Get the document root. For I{rpc/(literal|encoded)}, this is the
68 | name of the method qualifed by the schema tns.
69 | @param method: A service method.
70 | @type method: I{service.Method}
71 | @return: A root element.
72 | @rtype: L{Element}
73 | """
74 | ns = method.soap.input.body.namespace
75 | if ns[0] is None:
76 | ns = ('ns0', ns[1])
77 | method = Element(method.name, ns=ns)
78 | return method
79 |
80 |
81 | class Encoded(RPC):
82 | """
83 | RPC/Encoded (section 5) binding style.
84 | """
85 |
86 | def marshaller(self):
87 | return MxEncoded(self.schema())
88 |
89 | def unmarshaller(self, typed=True):
90 | """
91 | Get the appropriate XML decoder.
92 | @return: Either the (basic|typed) unmarshaller.
93 | @rtype: L{UmxTyped}
94 | """
95 | if typed:
96 | return UmxEncoded(self.schema())
97 | else:
98 | return RPC.unmarshaller(self, typed)
99 |
--------------------------------------------------------------------------------
/bin/suds/sax/__init__.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | The sax module contains a collection of classes that provide a
19 | (D)ocument (O)bject (M)odel representation of an XML document.
20 | The goal is to provide an easy, intuative interface for managing XML
21 | documents. Although, the term, DOM, is used above, this model is
22 | B{far} better.
23 |
24 | XML namespaces in suds are represented using a (2) element tuple
25 | containing the prefix and the URI. Eg: I{('tns', 'http://myns')}
26 |
27 | @var encoder: A I{pluggable} XML special character processor used to
28 | encode/decode strings.
29 | @type encoder: L{Encoder}
30 | """
31 |
32 | from suds.sax.enc import Encoder
33 |
34 | #
35 | # pluggable XML special character encoder.
36 | #
37 | encoder = Encoder()
38 |
39 |
40 | def splitPrefix(name):
41 | """
42 | Split the name into a tuple (I{prefix}, I{name}). The first element in
43 | the tuple is I{None} when the name does't have a prefix.
44 | @param name: A node name containing an optional prefix.
45 | @type name: basestring
46 | @return: A tuple containing the (2) parts of I{name}
47 | @rtype: (I{prefix}, I{name})
48 | """
49 | if isinstance(name, basestring) \
50 | and ':' in name:
51 | return tuple(name.split(':', 1))
52 | else:
53 | return (None, name)
54 |
55 |
56 | class Namespace:
57 | """
58 | The namespace class represents XML namespaces.
59 | """
60 |
61 | default = (None, None)
62 | xmlns = ('xml', 'http://www.w3.org/XML/1998/namespace')
63 | xsdns = ('xs', 'http://www.w3.org/2001/XMLSchema')
64 | xsins = ('xsi', 'http://www.w3.org/2001/XMLSchema-instance')
65 | all = (xsdns, xsins)
66 |
67 | @classmethod
68 | def create(cls, p=None, u=None):
69 | return (p, u)
70 |
71 | @classmethod
72 | def none(cls, ns):
73 | return ( ns == cls.default )
74 |
75 | @classmethod
76 | def xsd(cls, ns):
77 | try:
78 | return cls.w3(ns) and ns[1].endswith('XMLSchema')
79 | except:
80 | pass
81 | return False
82 |
83 | @classmethod
84 | def xsi(cls, ns):
85 | try:
86 | return cls.w3(ns) and ns[1].endswith('XMLSchema-instance')
87 | except:
88 | pass
89 | return False
90 |
91 | @classmethod
92 | def xs(cls, ns):
93 | return ( cls.xsd(ns) or cls.xsi(ns) )
94 |
95 | @classmethod
96 | def w3(cls, ns):
97 | try:
98 | return ns[1].startswith('http://www.w3.org')
99 | except:
100 | pass
101 | return False
102 |
103 | @classmethod
104 | def isns(cls, ns):
105 | try:
106 | return isinstance(ns, tuple) and len(ns) == len(cls.default)
107 | except:
108 | pass
109 | return False
110 |
--------------------------------------------------------------------------------
/bin/suds/transport/https.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Contains classes for basic HTTP (authenticated) transport implementations.
19 | """
20 |
21 | import urllib2 as u2
22 | from suds.transport import *
23 | from suds.transport.http import HttpTransport
24 | from logging import getLogger
25 |
26 | log = getLogger(__name__)
27 |
28 |
29 | class HttpAuthenticated(HttpTransport):
30 | """
31 | Provides basic http authentication that follows the RFC-2617 specification.
32 | As defined by specifications, credentials are provided to the server
33 | upon request (HTTP/1.0 401 Authorization Required) by the server only.
34 | @ivar pm: The password manager.
35 | @ivar handler: The authentication handler.
36 | """
37 |
38 | def __init__(self, **kwargs):
39 | """
40 | @param kwargs: Keyword arguments.
41 | - B{proxy} - An http proxy to be specified on requests.
42 | The proxy is defined as {protocol:proxy,}
43 | - type: I{dict}
44 | - default: {}
45 | - B{timeout} - Set the url open timeout (seconds).
46 | - type: I{float}
47 | - default: 90
48 | - B{username} - The username used for http authentication.
49 | - type: I{str}
50 | - default: None
51 | - B{password} - The password used for http authentication.
52 | - type: I{str}
53 | - default: None
54 | """
55 | HttpTransport.__init__(self, **kwargs)
56 | self.pm = u2.HTTPPasswordMgrWithDefaultRealm()
57 |
58 | def open(self, request):
59 | self.addcredentials(request)
60 | return HttpTransport.open(self, request)
61 |
62 | def send(self, request):
63 | self.addcredentials(request)
64 | return HttpTransport.send(self, request)
65 |
66 | def addcredentials(self, request):
67 | credentials = self.credentials()
68 | if not (None in credentials):
69 | u = credentials[0]
70 | p = credentials[1]
71 | self.pm.add_password(None, request.url, u, p)
72 |
73 | def credentials(self):
74 | return (self.options.username, self.options.password)
75 |
76 | def u2handlers(self):
77 | handlers = HttpTransport.u2handlers(self)
78 | handlers.append(u2.HTTPBasicAuthHandler(self.pm))
79 | return handlers
80 |
81 |
82 | class WindowsHttpAuthenticated(HttpAuthenticated):
83 | """
84 | Provides Windows (NTLM) http authentication.
85 | @ivar pm: The password manager.
86 | @ivar handler: The authentication handler.
87 | @author: Christopher Bess
88 | """
89 |
90 | def u2handlers(self):
91 | # try to import ntlm support
92 | try:
93 | from ntlm import HTTPNtlmAuthHandler
94 | except ImportError:
95 | raise Exception("Cannot import python-ntlm module")
96 | handlers = HttpTransport.u2handlers(self)
97 | handlers.append(HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(self.pm))
98 | return handlers
99 |
--------------------------------------------------------------------------------
/bin/suds/sax/text.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Contains XML text classes.
19 | """
20 |
21 | from suds import *
22 | from suds.sax import *
23 |
24 |
25 | class Text(unicode):
26 | """
27 | An XML text object used to represent text content.
28 | @ivar lang: The (optional) language flag.
29 | @type lang: bool
30 | @ivar escaped: The (optional) XML special character escaped flag.
31 | @type escaped: bool
32 | """
33 | __slots__ = ('lang', 'escaped',)
34 |
35 | @classmethod
36 | def __valid(cls, *args):
37 | return ( len(args) and args[0] is not None )
38 |
39 | def __new__(cls, *args, **kwargs):
40 | if cls.__valid(*args):
41 | lang = kwargs.pop('lang', None)
42 | escaped = kwargs.pop('escaped', False)
43 | result = super(Text, cls).__new__(cls, *args, **kwargs)
44 | result.lang = lang
45 | result.escaped = escaped
46 | else:
47 | result = None
48 | return result
49 |
50 | def escape(self):
51 | """
52 | Encode (escape) special XML characters.
53 | @return: The text with XML special characters escaped.
54 | @rtype: L{Text}
55 | """
56 | if not self.escaped:
57 | post = sax.encoder.encode(self)
58 | escaped = ( post != self )
59 | return Text(post, lang=self.lang, escaped=escaped)
60 | return self
61 |
62 | def unescape(self):
63 | """
64 | Decode (unescape) special XML characters.
65 | @return: The text with escaped XML special characters decoded.
66 | @rtype: L{Text}
67 | """
68 | if self.escaped:
69 | post = sax.encoder.decode(self)
70 | return Text(post, lang=self.lang)
71 | return self
72 |
73 | def trim(self):
74 | post = self.strip()
75 | return Text(post, lang=self.lang, escaped=self.escaped)
76 |
77 | def __add__(self, other):
78 | joined = u''.join((self, other))
79 | result = Text(joined, lang=self.lang, escaped=self.escaped)
80 | if isinstance(other, Text):
81 | result.escaped = ( self.escaped or other.escaped )
82 | return result
83 |
84 | def __repr__(self):
85 | s = [self]
86 | if self.lang is not None:
87 | s.append(' [%s]' % self.lang)
88 | if self.escaped:
89 | s.append(' ')
90 | return ''.join(s)
91 |
92 | def __getstate__(self):
93 | state = {}
94 | for k in self.__slots__:
95 | state[k] = getattr(self, k)
96 | return state
97 |
98 | def __setstate__(self, state):
99 | for k in self.__slots__:
100 | setattr(self, k, state[k])
101 |
102 |
103 | class Raw(Text):
104 | """
105 | Raw text which is not XML escaped.
106 | This may include I{string} XML.
107 | """
108 | def escape(self):
109 | return self
110 |
111 | def unescape(self):
112 | return self
113 |
114 | def __add__(self, other):
115 | joined = u''.join((self, other))
116 | return Raw(joined, lang=self.lang)
117 |
--------------------------------------------------------------------------------
/bin/suds/transport/__init__.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Contains transport interface (classes).
19 | """
20 |
21 |
22 | class TransportError(Exception):
23 | def __init__(self, reason, httpcode, fp=None):
24 | Exception.__init__(self, reason)
25 | self.httpcode = httpcode
26 | self.fp = fp
27 |
28 | class Request:
29 | """
30 | A transport request
31 | @ivar url: The url for the request.
32 | @type url: str
33 | @ivar message: The message to be sent in a POST request.
34 | @type message: str
35 | @ivar headers: The http headers to be used for the request.
36 | @type headers: dict
37 | """
38 |
39 | def __init__(self, url, message=None):
40 | """
41 | @param url: The url for the request.
42 | @type url: str
43 | @param message: The (optional) message to be send in the request.
44 | @type message: str
45 | """
46 | self.url = url
47 | self.headers = {}
48 | self.message = message
49 |
50 | def __str__(self):
51 | s = []
52 | s.append('URL:%s' % self.url)
53 | s.append('HEADERS: %s' % self.headers)
54 | s.append('MESSAGE:')
55 | s.append(self.message)
56 | return '\n'.join(s)
57 |
58 |
59 | class Reply:
60 | """
61 | A transport reply
62 | @ivar code: The http code returned.
63 | @type code: int
64 | @ivar message: The message to be sent in a POST request.
65 | @type message: str
66 | @ivar headers: The http headers to be used for the request.
67 | @type headers: dict
68 | """
69 |
70 | def __init__(self, code, headers, message):
71 | """
72 | @param code: The http code returned.
73 | @type code: int
74 | @param headers: The http returned headers.
75 | @type headers: dict
76 | @param message: The (optional) reply message received.
77 | @type message: str
78 | """
79 | self.code = code
80 | self.headers = headers
81 | self.message = message
82 |
83 | def __str__(self):
84 | s = []
85 | s.append('CODE: %s' % self.code)
86 | s.append('HEADERS: %s' % self.headers)
87 | s.append('MESSAGE:')
88 | s.append(self.message)
89 | return '\n'.join(s)
90 |
91 |
92 | class Transport:
93 | """
94 | The transport I{interface}.
95 | """
96 |
97 | def __init__(self):
98 | """
99 | Constructor.
100 | """
101 | from suds.transport.options import Options
102 | self.options = Options()
103 | del Options
104 |
105 | def open(self, request):
106 | """
107 | Open the url in the specified request.
108 | @param request: A transport request.
109 | @type request: L{Request}
110 | @return: An input stream.
111 | @rtype: stream
112 | @raise TransportError: On all transport errors.
113 | """
114 | raise Exception('not-implemented')
115 |
116 | def send(self, request):
117 | """
118 | Send soap message. Implementations are expected to handle:
119 | - proxies
120 | - I{http} headers
121 | - cookies
122 | - sending message
123 | - brokering exceptions into L{TransportError}
124 | @param request: A transport request.
125 | @type request: L{Request}
126 | @return: The reply
127 | @rtype: L{Reply}
128 | @raise TransportError: On all transport errors.
129 | """
130 | raise Exception('not-implemented')
131 |
--------------------------------------------------------------------------------
/bin/suds/mx/typer.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Provides sx typing classes.
19 | """
20 |
21 | from logging import getLogger
22 | from suds import *
23 | from suds.mx import *
24 | from suds.sax import Namespace as NS
25 | from suds.sax.text import Text
26 |
27 | log = getLogger(__name__)
28 |
29 |
30 | class Typer:
31 | """
32 | Provides XML node typing as either automatic or manual.
33 | @cvar types: A dict of class to xs type mapping.
34 | @type types: dict
35 | """
36 |
37 | types = {
38 | int : ('int', NS.xsdns),
39 | long : ('long', NS.xsdns),
40 | float : ('float', NS.xsdns),
41 | str : ('string', NS.xsdns),
42 | unicode : ('string', NS.xsdns),
43 | Text : ('string', NS.xsdns),
44 | bool : ('boolean', NS.xsdns),
45 | }
46 |
47 | @classmethod
48 | def auto(cls, node, value=None):
49 | """
50 | Automatically set the node's xsi:type attribute based on either I{value}'s
51 | class or the class of the node's text. When I{value} is an unmapped class,
52 | the default type (xs:any) is set.
53 | @param node: An XML node
54 | @type node: L{sax.element.Element}
55 | @param value: An object that is or would be the node's text.
56 | @type value: I{any}
57 | @return: The specified node.
58 | @rtype: L{sax.element.Element}
59 | """
60 | if value is None:
61 | value = node.getText()
62 | if isinstance(value, Object):
63 | known = cls.known(value)
64 | if known.name is None:
65 | return node
66 | tm = (known.name, known.namespace())
67 | else:
68 | tm = cls.types.get(value.__class__, cls.types.get(str))
69 | cls.manual(node, *tm)
70 | return node
71 |
72 | @classmethod
73 | def manual(cls, node, tval, ns=None):
74 | """
75 | Set the node's xsi:type attribute based on either I{value}'s
76 | class or the class of the node's text. Then adds the referenced
77 | prefix(s) to the node's prefix mapping.
78 | @param node: An XML node
79 | @type node: L{sax.element.Element}
80 | @param tval: The name of the schema type.
81 | @type tval: str
82 | @param ns: The XML namespace of I{tval}.
83 | @type ns: (prefix, uri)
84 | @return: The specified node.
85 | @rtype: L{sax.element.Element}
86 | """
87 | xta = ':'.join((NS.xsins[0], 'type'))
88 | node.addPrefix(NS.xsins[0], NS.xsins[1])
89 | if ns is None:
90 | node.set(xta, tval)
91 | else:
92 | ns = cls.genprefix(node, ns)
93 | qname = ':'.join((ns[0], tval))
94 | node.set(xta, qname)
95 | node.addPrefix(ns[0], ns[1])
96 | return node
97 |
98 | @classmethod
99 | def genprefix(cls, node, ns):
100 | """
101 | Generate a prefix.
102 | @param node: An XML node on which the prefix will be used.
103 | @type node: L{sax.element.Element}
104 | @param ns: A namespace needing an unique prefix.
105 | @type ns: (prefix, uri)
106 | @return: The I{ns} with a new prefix.
107 | """
108 | for n in range(1, 1024):
109 | p = 'ns%d' % n
110 | u = node.resolvePrefix(p, default=None)
111 | if u is None or u == ns[1]:
112 | return (p, ns[1])
113 | raise Exception('auto prefix, exhausted')
114 |
115 | @classmethod
116 | def known(cls, object):
117 | try:
118 | md = object.__metadata__
119 | known = md.sxtype
120 | return known
121 | except:
122 | pass
123 |
124 |
--------------------------------------------------------------------------------
/bin/suds/xsd/deplist.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | The I{depsolve} module defines a class for performing dependancy solving.
19 | """
20 |
21 | from logging import getLogger
22 | from suds import *
23 |
24 | log = getLogger(__name__)
25 |
26 |
27 | class DepList:
28 | """
29 | Dependancy solving list.
30 | Items are tuples: (object, (deps,))
31 | @ivar raw: The raw (unsorted) items.
32 | @type raw: list
33 | @ivar index: The index of (unsorted) items.
34 | @type index: list
35 | @ivar stack: The sorting stack.
36 | @type stack: list
37 | @ivar pushed: The I{pushed} set tracks items that have been
38 | processed.
39 | @type pushed: set
40 | @ivar sorted: The sorted list of items.
41 | @type sorted: list
42 | """
43 |
44 | def __init__(self):
45 | """ """
46 | self.unsorted = []
47 | self.index = {}
48 | self.stack = []
49 | self.pushed = set()
50 | self.sorted = None
51 |
52 | def add(self, *items):
53 | """
54 | Add items to be sorted.
55 | @param items: One or more items to be added.
56 | @type items: I{item}
57 | @return: self
58 | @rtype: L{DepList}
59 | """
60 | for item in items:
61 | self.unsorted.append(item)
62 | key = item[0]
63 | self.index[key] = item
64 | return self
65 |
66 | def sort(self):
67 | """
68 | Sort the list based on dependancies.
69 | @return: The sorted items.
70 | @rtype: list
71 | """
72 | self.sorted = list()
73 | self.pushed = set()
74 | for item in self.unsorted:
75 | popped = []
76 | self.push(item)
77 | while len(self.stack):
78 | try:
79 | top = self.top()
80 | ref = top[1].next()
81 | refd = self.index.get(ref)
82 | if refd is None:
83 | log.debug('"%s" not found, skipped', Repr(ref))
84 | continue
85 | self.push(refd)
86 | except StopIteration:
87 | popped.append(self.pop())
88 | continue
89 | for p in popped:
90 | self.sorted.append(p)
91 | self.unsorted = self.sorted
92 | return self.sorted
93 |
94 | def top(self):
95 | """
96 | Get the item at the top of the stack.
97 | @return: The top item.
98 | @rtype: (item, iter)
99 | """
100 | return self.stack[-1]
101 |
102 | def push(self, item):
103 | """
104 | Push and item onto the sorting stack.
105 | @param item: An item to push.
106 | @type item: I{item}
107 | @return: The number of items pushed.
108 | @rtype: int
109 | """
110 | if item in self.pushed:
111 | return
112 | frame = (item, iter(item[1]))
113 | self.stack.append(frame)
114 | self.pushed.add(item)
115 |
116 | def pop(self):
117 | """
118 | Pop the top item off the stack and append
119 | it to the sorted list.
120 | @return: The popped item.
121 | @rtype: I{item}
122 | """
123 | try:
124 | frame = self.stack.pop()
125 | return frame[0]
126 | except:
127 | pass
128 |
129 |
130 | if __name__ == '__main__':
131 | a = ('a', ('x',))
132 | b = ('b', ('a',))
133 | c = ('c', ('a','b'))
134 | d = ('d', ('c',))
135 | e = ('e', ('d','a'))
136 | f = ('f', ('e','c','d','a'))
137 | x = ('x', ())
138 | L = DepList()
139 | L.add(c, e, d, b, f, a, x)
140 | print [x[0] for x in L.sort()]
--------------------------------------------------------------------------------
/bin/suds/bindings/multiref.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Provides classes for handling soap multirefs.
19 | """
20 |
21 | from logging import getLogger
22 | from suds import *
23 | from suds.sax.element import Element
24 |
25 | log = getLogger(__name__)
26 |
27 | soapenc = (None, 'http://schemas.xmlsoap.org/soap/encoding/')
28 |
29 | class MultiRef:
30 | """
31 | Resolves and replaces multirefs.
32 | @ivar nodes: A list of non-multiref nodes.
33 | @type nodes: list
34 | @ivar catalog: A dictionary of multiref nodes by id.
35 | @type catalog: dict
36 | """
37 |
38 | def __init__(self):
39 | self.nodes = []
40 | self.catalog = {}
41 |
42 | def process(self, body):
43 | """
44 | Process the specified soap envelope body and replace I{multiref} node
45 | references with the contents of the referenced node.
46 | @param body: A soap envelope body node.
47 | @type body: L{Element}
48 | @return: The processed I{body}
49 | @rtype: L{Element}
50 | """
51 | self.nodes = []
52 | self.catalog = {}
53 | self.build_catalog(body)
54 | self.update(body)
55 | body.children = self.nodes
56 | return body
57 |
58 | def update(self, node):
59 | """
60 | Update the specified I{node} by replacing the I{multiref} references with
61 | the contents of the referenced nodes and remove the I{href} attribute.
62 | @param node: A node to update.
63 | @type node: L{Element}
64 | @return: The updated node
65 | @rtype: L{Element}
66 | """
67 | self.replace_references(node)
68 | for c in node.children:
69 | self.update(c)
70 | return node
71 |
72 | def replace_references(self, node):
73 | """
74 | Replacing the I{multiref} references with the contents of the
75 | referenced nodes and remove the I{href} attribute. Warning: since
76 | the I{ref} is not cloned,
77 | @param node: A node to update.
78 | @type node: L{Element}
79 | """
80 | href = node.getAttribute('href')
81 | if href is None:
82 | return
83 | id = href.getValue()
84 | ref = self.catalog.get(id)
85 | if ref is None:
86 | log.error('soap multiref: %s, not-resolved', id)
87 | return
88 | node.append(ref.children)
89 | node.setText(ref.getText())
90 | for a in ref.attributes:
91 | if a.name != 'id':
92 | node.append(a)
93 | node.remove(href)
94 |
95 | def build_catalog(self, body):
96 | """
97 | Create the I{catalog} of multiref nodes by id and the list of
98 | non-multiref nodes.
99 | @param body: A soap envelope body node.
100 | @type body: L{Element}
101 | """
102 | for child in body.children:
103 | if self.soaproot(child):
104 | self.nodes.append(child)
105 | id = child.get('id')
106 | if id is None: continue
107 | key = '#%s' % id
108 | self.catalog[key] = child
109 |
110 | def soaproot(self, node):
111 | """
112 | Get whether the specified I{node} is a soap encoded root.
113 | This is determined by examining @soapenc:root='1'.
114 | The node is considered to be a root when the attribute
115 | is not specified.
116 | @param node: A node to evaluate.
117 | @type node: L{Element}
118 | @return: True if a soap encoded root.
119 | @rtype: bool
120 | """
121 | root = node.getAttribute('root', ns=soapenc)
122 | if root is None:
123 | return True
124 | else:
125 | return ( root.value == '1' )
126 |
--------------------------------------------------------------------------------
/bin/suds/builder.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | The I{builder} module provides an wsdl/xsd defined types factory
19 | """
20 |
21 | from logging import getLogger
22 | from suds import *
23 | from suds.sudsobject import Factory
24 |
25 | log = getLogger(__name__)
26 |
27 |
28 | class Builder:
29 | """ Builder used to construct an object for types defined in the schema """
30 |
31 | def __init__(self, resolver):
32 | """
33 | @param resolver: A schema object name resolver.
34 | @type resolver: L{resolver.Resolver}
35 | """
36 | self.resolver = resolver
37 |
38 | def build(self, name):
39 | """ build a an object for the specified typename as defined in the schema """
40 | if isinstance(name, basestring):
41 | type = self.resolver.find(name)
42 | if type is None:
43 | raise TypeNotFound(name)
44 | else:
45 | type = name
46 | cls = type.name
47 | if type.mixed():
48 | data = Factory.property(cls)
49 | else:
50 | data = Factory.object(cls)
51 | resolved = type.resolve()
52 | md = data.__metadata__
53 | md.sxtype = resolved
54 | md.ordering = self.ordering(resolved)
55 | history = []
56 | self.add_attributes(data, resolved)
57 | for child, ancestry in type.children():
58 | if self.skip_child(child, ancestry):
59 | continue
60 | self.process(data, child, history[:])
61 | return data
62 |
63 | def process(self, data, type, history):
64 | """ process the specified type then process its children """
65 | if type in history:
66 | return
67 | if type.enum():
68 | return
69 | history.append(type)
70 | resolved = type.resolve()
71 | value = None
72 | if type.unbounded():
73 | value = []
74 | else:
75 | if len(resolved) > 0:
76 | if resolved.mixed():
77 | value = Factory.property(resolved.name)
78 | md = value.__metadata__
79 | md.sxtype = resolved
80 | else:
81 | value = Factory.object(resolved.name)
82 | md = value.__metadata__
83 | md.sxtype = resolved
84 | md.ordering = self.ordering(resolved)
85 | setattr(data, type.name, value)
86 | if value is not None:
87 | data = value
88 | if not isinstance(data, list):
89 | self.add_attributes(data, resolved)
90 | for child, ancestry in resolved.children():
91 | if self.skip_child(child, ancestry):
92 | continue
93 | self.process(data, child, history[:])
94 |
95 | def add_attributes(self, data, type):
96 | """ add required attributes """
97 | for attr, ancestry in type.attributes():
98 | name = '_%s' % attr.name
99 | value = attr.get_default()
100 | setattr(data, name, value)
101 |
102 | def skip_child(self, child, ancestry):
103 | """ get whether or not to skip the specified child """
104 | if child.any(): return True
105 | for x in ancestry:
106 | if x.choice():
107 | return True
108 | return False
109 |
110 | def ordering(self, type):
111 | """ get the ordering """
112 | result = []
113 | for child, ancestry in type.resolve():
114 | name = child.name
115 | if child.name is None:
116 | continue
117 | if child.isattr():
118 | name = '_%s' % child.name
119 | result.append(name)
120 | return result
121 |
--------------------------------------------------------------------------------
/bin/suds/umx/encoded.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Provides soap encoded unmarshaller classes.
19 | """
20 |
21 | from logging import getLogger
22 | from suds import *
23 | from suds.umx import *
24 | from suds.umx.typed import Typed
25 | from suds.sax import splitPrefix, Namespace
26 |
27 | log = getLogger(__name__)
28 |
29 | #
30 | # Add encoded extensions
31 | # aty = The soap (section 5) encoded array type.
32 | #
33 | Content.extensions.append('aty')
34 |
35 |
36 | class Encoded(Typed):
37 | """
38 | A SOAP section (5) encoding unmarshaller.
39 | This marshaller supports rpc/encoded soap styles.
40 | """
41 |
42 | def start(self, content):
43 | #
44 | # Grab the array type and continue
45 | #
46 | self.setaty(content)
47 | Typed.start(self, content)
48 |
49 | def end(self, content):
50 | #
51 | # Squash soap encoded arrays into python lists. This is
52 | # also where we insure that empty arrays are represented
53 | # as empty python lists.
54 | #
55 | aty = content.aty
56 | if aty is not None:
57 | self.promote(content)
58 | return Typed.end(self, content)
59 |
60 | def postprocess(self, content):
61 | #
62 | # Ensure proper rendering of empty arrays.
63 | #
64 | if content.aty is None:
65 | return Typed.postprocess(self, content)
66 | else:
67 | return content.data
68 |
69 | def setaty(self, content):
70 | """
71 | Grab the (aty) soap-enc:arrayType and attach it to the
72 | content for proper array processing later in end().
73 | @param content: The current content being unmarshalled.
74 | @type content: L{Content}
75 | @return: self
76 | @rtype: L{Encoded}
77 | """
78 | name = 'arrayType'
79 | ns = (None, 'http://schemas.xmlsoap.org/soap/encoding/')
80 | aty = content.node.get(name, ns)
81 | if aty is not None:
82 | content.aty = aty
83 | parts = aty.split('[')
84 | ref = parts[0]
85 | if len(parts) == 2:
86 | self.applyaty(content, ref)
87 | else:
88 | pass # (2) dimensional array
89 | return self
90 |
91 | def applyaty(self, content, xty):
92 | """
93 | Apply the type referenced in the I{arrayType} to the content
94 | (child nodes) of the array. Each element (node) in the array
95 | that does not have an explicit xsi:type attribute is given one
96 | based on the I{arrayType}.
97 | @param content: An array content.
98 | @type content: L{Content}
99 | @param xty: The XSI type reference.
100 | @type xty: str
101 | @return: self
102 | @rtype: L{Encoded}
103 | """
104 | name = 'type'
105 | ns = Namespace.xsins
106 | parent = content.node
107 | for child in parent.getChildren():
108 | ref = child.get(name, ns)
109 | if ref is None:
110 | parent.addPrefix(ns[0], ns[1])
111 | attr = ':'.join((ns[0], name))
112 | child.set(attr, xty)
113 | return self
114 |
115 | def promote(self, content):
116 | """
117 | Promote (replace) the content.data with the first attribute
118 | of the current content.data that is a I{list}. Note: the
119 | content.data may be empty or contain only _x attributes.
120 | In either case, the content.data is assigned an empty list.
121 | @param content: An array content.
122 | @type content: L{Content}
123 | """
124 | for n,v in content.data:
125 | if isinstance(v, list):
126 | content.data = v
127 | return
128 | content.data = []
--------------------------------------------------------------------------------
/bin/suds/sax/parser.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | The sax module contains a collection of classes that provide a
19 | (D)ocument (O)bject (M)odel representation of an XML document.
20 | The goal is to provide an easy, intuative interface for managing XML
21 | documents. Although, the term, DOM, is used above, this model is
22 | B{far} better.
23 |
24 | XML namespaces in suds are represented using a (2) element tuple
25 | containing the prefix and the URI. Eg: I{('tns', 'http://myns')}
26 |
27 | """
28 |
29 | from logging import getLogger
30 | import suds.metrics
31 | from suds import *
32 | from suds.sax import *
33 | from suds.sax.document import Document
34 | from suds.sax.element import Element
35 | from suds.sax.text import Text
36 | from suds.sax.attribute import Attribute
37 | from xml.sax import make_parser, InputSource, ContentHandler
38 | from xml.sax.handler import feature_external_ges
39 | from cStringIO import StringIO
40 |
41 | log = getLogger(__name__)
42 |
43 |
44 | class Handler(ContentHandler):
45 | """ sax hanlder """
46 |
47 | def __init__(self):
48 | self.nodes = [Document()]
49 |
50 | def startElement(self, name, attrs):
51 | top = self.top()
52 | node = Element(unicode(name), parent=top)
53 | for a in attrs.getNames():
54 | n = unicode(a)
55 | v = unicode(attrs.getValue(a))
56 | attribute = Attribute(n,v)
57 | if self.mapPrefix(node, attribute):
58 | continue
59 | node.append(attribute)
60 | node.charbuffer = []
61 | top.append(node)
62 | self.push(node)
63 |
64 | def mapPrefix(self, node, attribute):
65 | skip = False
66 | if attribute.name == 'xmlns':
67 | if len(attribute.value):
68 | node.expns = unicode(attribute.value)
69 | skip = True
70 | elif attribute.prefix == 'xmlns':
71 | prefix = attribute.name
72 | node.nsprefixes[prefix] = unicode(attribute.value)
73 | skip = True
74 | return skip
75 |
76 | def endElement(self, name):
77 | name = unicode(name)
78 | current = self.top()
79 | if len(current.charbuffer):
80 | current.text = Text(u''.join(current.charbuffer))
81 | del current.charbuffer
82 | if len(current):
83 | current.trim()
84 | currentqname = current.qname()
85 | if name == currentqname:
86 | self.pop()
87 | else:
88 | raise Exception('malformed document')
89 |
90 | def characters(self, content):
91 | text = unicode(content)
92 | node = self.top()
93 | node.charbuffer.append(text)
94 |
95 | def push(self, node):
96 | self.nodes.append(node)
97 | return node
98 |
99 | def pop(self):
100 | return self.nodes.pop()
101 |
102 | def top(self):
103 | return self.nodes[len(self.nodes)-1]
104 |
105 |
106 | class Parser:
107 | """ SAX Parser """
108 |
109 | @classmethod
110 | def saxparser(cls):
111 | p = make_parser()
112 | p.setFeature(feature_external_ges, 0)
113 | h = Handler()
114 | p.setContentHandler(h)
115 | return (p, h)
116 |
117 | def parse(self, file=None, string=None):
118 | """
119 | SAX parse XML text.
120 | @param file: Parse a python I{file-like} object.
121 | @type file: I{file-like} object.
122 | @param string: Parse string XML.
123 | @type string: str
124 | """
125 | timer = metrics.Timer()
126 | timer.start()
127 | sax, handler = self.saxparser()
128 | if file is not None:
129 | sax.parse(file)
130 | timer.stop()
131 | metrics.log.debug('sax (%s) duration: %s', file, timer)
132 | return handler.nodes[0]
133 | if string is not None:
134 | source = InputSource(None)
135 | source.setByteStream(StringIO(string))
136 | sax.parse(source)
137 | timer.stop()
138 | metrics.log.debug('%s\nsax duration: %s', string, timer)
139 | return handler.nodes[0]
--------------------------------------------------------------------------------
/bin/suds/__init__.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Suds is a lightweight SOAP python client that provides a
19 | service proxy for Web Services.
20 | """
21 |
22 | import os
23 | import sys
24 |
25 | #
26 | # Project properties
27 | #
28 |
29 | __version__ = '0.4'
30 | __build__="GA R699-20100913"
31 |
32 | #
33 | # Exceptions
34 | #
35 |
36 | class MethodNotFound(Exception):
37 | def __init__(self, name):
38 | Exception.__init__(self, "Method not found: '%s'" % name)
39 |
40 | class PortNotFound(Exception):
41 | def __init__(self, name):
42 | Exception.__init__(self, "Port not found: '%s'" % name)
43 |
44 | class ServiceNotFound(Exception):
45 | def __init__(self, name):
46 | Exception.__init__(self, "Service not found: '%s'" % name)
47 |
48 | class TypeNotFound(Exception):
49 | def __init__(self, name):
50 | Exception.__init__(self, "Type not found: '%s'" % tostr(name))
51 |
52 | class BuildError(Exception):
53 | msg = \
54 | """
55 | An error occured while building a instance of (%s). As a result
56 | the object you requested could not be constructed. It is recommended
57 | that you construct the type manually using a Suds object.
58 | Please open a ticket with a description of this error.
59 | Reason: %s
60 | """
61 | def __init__(self, name, exception):
62 | Exception.__init__(self, BuildError.msg % (name, exception))
63 |
64 | class SoapHeadersNotPermitted(Exception):
65 | msg = \
66 | """
67 | Method (%s) was invoked with SOAP headers. The WSDL does not
68 | define SOAP headers for this method. Retry without the soapheaders
69 | keyword argument.
70 | """
71 | def __init__(self, name):
72 | Exception.__init__(self, self.msg % name)
73 |
74 | class WebFault(Exception):
75 | def __init__(self, fault, document):
76 | if hasattr(fault, 'faultstring'):
77 | Exception.__init__(self, "Server raised fault: '%s'" % fault.faultstring)
78 | self.fault = fault
79 | self.document = document
80 |
81 | #
82 | # Logging
83 | #
84 |
85 | class Repr:
86 | def __init__(self, x):
87 | self.x = x
88 | def __str__(self):
89 | return repr(self.x)
90 |
91 | #
92 | # Utility
93 | #
94 |
95 | def tostr(object, encoding=None):
96 | """ get a unicode safe string representation of an object """
97 | if isinstance(object, basestring):
98 | if encoding is None:
99 | return object
100 | else:
101 | return object.encode(encoding)
102 | if isinstance(object, tuple):
103 | s = ['(']
104 | for item in object:
105 | if isinstance(item, basestring):
106 | s.append(item)
107 | else:
108 | s.append(tostr(item))
109 | s.append(', ')
110 | s.append(')')
111 | return ''.join(s)
112 | if isinstance(object, list):
113 | s = ['[']
114 | for item in object:
115 | if isinstance(item, basestring):
116 | s.append(item)
117 | else:
118 | s.append(tostr(item))
119 | s.append(', ')
120 | s.append(']')
121 | return ''.join(s)
122 | if isinstance(object, dict):
123 | s = ['{']
124 | for item in object.items():
125 | if isinstance(item[0], basestring):
126 | s.append(item[0])
127 | else:
128 | s.append(tostr(item[0]))
129 | s.append(' = ')
130 | if isinstance(item[1], basestring):
131 | s.append(item[1])
132 | else:
133 | s.append(tostr(item[1]))
134 | s.append(', ')
135 | s.append('}')
136 | return ''.join(s)
137 | try:
138 | return unicode(object)
139 | except:
140 | return str(object)
141 |
142 | class null:
143 | """
144 | The I{null} object.
145 | Used to pass NULL for optional XML nodes.
146 | """
147 | pass
148 |
149 | def objid(obj):
150 | return obj.__class__.__name__\
151 | +':'+hex(id(obj))
152 |
153 |
154 | import client
155 |
--------------------------------------------------------------------------------
/bin/jira_soap.py:
--------------------------------------------------------------------------------
1 | """
2 | External search command for querying the JIRA SOAP API
3 |
4 | Usage:
5 | | jirasoap search "text search" | ... ... # text search
6 | | jirasoap jqlsearch "JQL query" | ... ... # JQL search*
7 | | jirasoap issues | ... ... # filter search
8 | | jirasoap filters | ... ... # list all filters (to get ids for issues command)
9 |
10 | * The jqlsearch doesn't handle '=' very well - splunk parses these as options.
11 | Instead of saying "project = foo AND status = Open" say "project in (foo) AND status in (Open)".
12 | Or use the SearchRequest XML command instead
13 |
14 | Author: Fred de Boer
15 | Author: Jeffrey Isenberg
16 | Author: Russell Uman
17 | """
18 |
19 | import splunk.Intersplunk as isp
20 | import splunk.mining.dcutils as dcu
21 |
22 | import jiracommon
23 | import logging
24 | import sys
25 | import time
26 |
27 | from suds.client import Client
28 |
29 | try:
30 | messages = {}
31 | logging.getLogger('suds').setLevel(logging.INFO)
32 |
33 | logger = dcu.getLogger()
34 |
35 | # Get configuration values from config.ini
36 | local_conf = jiracommon.getLocalConf()
37 |
38 | hostname = local_conf.get('jira', 'hostname')
39 | username = local_conf.get('jira', 'username')
40 | password = local_conf.get('jira', 'password')
41 | protocol = local_conf.get('jira', 'soap_protocol');
42 | port = local_conf.get('jira', 'soap_port');
43 |
44 | url = "%s://%s:%s/rpc/soap/jirasoapservice-v2?wsdl" % (protocol, hostname, port)
45 | logger.info(url)
46 | client = Client(url)
47 | auth = client.service.login(username, password)
48 |
49 | keywords, argvals = isp.getKeywordsAndOptions()
50 |
51 | time_option = argvals.get('time', "now")
52 |
53 | logger.info('argv: ' + str(sys.argv))
54 |
55 | if sys.argv[1] == 'filters':
56 | filters = client.service.getFavouriteFilters(auth)
57 |
58 | keys = (('author', None), ('id', None), ('name', None))
59 |
60 | results = []
61 | for filter in filters:
62 | row = jiracommon.flatten(filter, keys)
63 | logger.info(time.time())
64 | row['host'] = hostname
65 | row['source'] = "jira_soap"
66 | row['sourcetype'] = "jira_filters"
67 | row['_time'] = int(time.time())
68 | results.append(row)
69 | isp.outputResults(results)
70 | sys.exit(0)
71 |
72 | elif sys.argv[1] == 'issues':
73 | filter_id = sys.argv[-1]
74 | issues = client.service.getIssuesFromFilter(auth, filter_id)
75 | # TODO this 1000 issue max isn't working as expected - if there are more than 1000 results, no results are returned
76 | elif sys.argv[1] == 'search':
77 | search = sys.argv[-1]
78 | issues = (client.service.getIssuesFromTextSearch(auth, search, 1000) )
79 | elif sys.argv[1] == 'jqlsearch':
80 | jql = sys.argv[-1]
81 | issues = (client.service.getIssuesFromJqlSearch(auth, jql, 1000) )
82 | else:
83 | logger.fatal('invalid command')
84 | sys.exit(1)
85 |
86 | statuses = jiracommon.api_to_dict(client.service.getStatuses(auth))
87 | resolutions = jiracommon.api_to_dict(client.service.getResolutions(auth))
88 | priorities = jiracommon.api_to_dict(client.service.getPriorities(auth))
89 |
90 | resolutions[None] = 'UNRESOLVED'
91 |
92 | results = []
93 |
94 | keys = (('assignee', None),
95 | ('description', None),
96 | ('key', None),
97 | ('summary', None),
98 | ('reporter', None),
99 | ('status', statuses),
100 | ('resolution', resolutions),
101 | ('priority', priorities),
102 | ('project', None),
103 | ('type', None),
104 | ('created', None),
105 | ('updated', None))
106 | for issue in issues:
107 | row = jiracommon.flatten(issue, keys)
108 |
109 | # Special handling for multi-value fields
110 | affectedVersions = []
111 | for f in issue['affectsVersions']:
112 | affectedVersions.append(f['name'])
113 | row['affectedVersions'] = affectedVersions
114 |
115 | fixVersions = []
116 | for f in issue['fixVersions']:
117 | fixVersions.append(f['name'])
118 | row['fixVersions'] = fixVersions
119 |
120 | # Custom fields
121 | for f in issue['customFieldValues']:
122 | if f['customfieldId'] == "customfield_10020":
123 | row['SFDCcase'] = f['values']
124 | if f['customfieldId'] == "customfield_10091":
125 | row['TargetRelease'] = f['values']
126 |
127 | row['host'] = hostname
128 | row['source'] = 'jira_soap'
129 | row['sourcetype'] = "jira_issues"
130 |
131 | # override _time if time argument is set
132 | if time_option == "now":
133 | row['_time'] = int(time.time())
134 | else:
135 | row['_time'] = int(time.mktime(time.strptime(row[time_option], '%Y-%m-%d %H:%M:%S')))
136 |
137 | results.append(row)
138 |
139 | isp.outputResults(results)
140 |
141 | except Exception, e:
142 | logger.exception(str(e))
143 | isp.generateErrorResults(str(e))
--------------------------------------------------------------------------------
/bin/suds/mx/encoded.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Provides encoded I{marshaller} classes.
19 | """
20 |
21 | from logging import getLogger
22 | from suds import *
23 | from suds.mx import *
24 | from suds.mx.literal import Literal
25 | from suds.mx.typer import Typer
26 | from suds.sudsobject import Factory, Object
27 | from suds.xsd.query import TypeQuery
28 |
29 | log = getLogger(__name__)
30 |
31 | #
32 | # Add encoded extensions
33 | # aty = The soap (section 5) encoded array type.
34 | #
35 | Content.extensions.append('aty')
36 |
37 |
38 | class Encoded(Literal):
39 | """
40 | A SOAP section (5) encoding marshaller.
41 | This marshaller supports rpc/encoded soap styles.
42 | """
43 |
44 | def start(self, content):
45 | #
46 | # For soap encoded arrays, the 'aty' (array type) information
47 | # is extracted and added to the 'content'. Then, the content.value
48 | # is replaced with an object containing an 'item=[]' attribute
49 | # containing values that are 'typed' suds objects.
50 | #
51 | start = Literal.start(self, content)
52 | if start and isinstance(content.value, (list,tuple)):
53 | resolved = content.type.resolve()
54 | for c in resolved:
55 | if hasattr(c[0], 'aty'):
56 | content.aty = (content.tag, c[0].aty)
57 | self.cast(content)
58 | break
59 | return start
60 |
61 | def end(self, parent, content):
62 | #
63 | # For soap encoded arrays, the soapenc:arrayType attribute is
64 | # added with proper type and size information.
65 | # Eg: soapenc:arrayType="xs:int[3]"
66 | #
67 | Literal.end(self, parent, content)
68 | if content.aty is None:
69 | return
70 | tag, aty = content.aty
71 | ns0 = ('at0', aty[1])
72 | ns1 = ('at1', 'http://schemas.xmlsoap.org/soap/encoding/')
73 | array = content.value.item
74 | child = parent.getChild(tag)
75 | child.addPrefix(ns0[0], ns0[1])
76 | child.addPrefix(ns1[0], ns1[1])
77 | name = '%s:arrayType' % ns1[0]
78 | value = '%s:%s[%d]' % (ns0[0], aty[0], len(array))
79 | child.set(name, value)
80 |
81 | def encode(self, node, content):
82 | if content.type.any():
83 | Typer.auto(node, content.value)
84 | return
85 | if content.real.any():
86 | Typer.auto(node, content.value)
87 | return
88 | ns = None
89 | name = content.real.name
90 | if self.xstq:
91 | ns = content.real.namespace()
92 | Typer.manual(node, name, ns)
93 |
94 | def cast(self, content):
95 | """
96 | Cast the I{untyped} list items found in content I{value}.
97 | Each items contained in the list is checked for XSD type information.
98 | Items (values) that are I{untyped}, are replaced with suds objects and
99 | type I{metadata} is added.
100 | @param content: The content holding the collection.
101 | @type content: L{Content}
102 | @return: self
103 | @rtype: L{Encoded}
104 | """
105 | aty = content.aty[1]
106 | resolved = content.type.resolve()
107 | array = Factory.object(resolved.name)
108 | array.item = []
109 | query = TypeQuery(aty)
110 | ref = query.execute(self.schema)
111 | if ref is None:
112 | raise TypeNotFound(qref)
113 | for x in content.value:
114 | if isinstance(x, (list, tuple)):
115 | array.item.append(x)
116 | continue
117 | if isinstance(x, Object):
118 | md = x.__metadata__
119 | md.sxtype = ref
120 | array.item.append(x)
121 | continue
122 | if isinstance(x, dict):
123 | x = Factory.object(ref.name, x)
124 | md = x.__metadata__
125 | md.sxtype = ref
126 | array.item.append(x)
127 | continue
128 | x = Factory.property(ref.name, x)
129 | md = x.__metadata__
130 | md.sxtype = ref
131 | array.item.append(x)
132 | content.value = array
133 | return self
134 |
--------------------------------------------------------------------------------
/bin/suds/umx/typed.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Provides typed unmarshaller classes.
19 | """
20 |
21 | from logging import getLogger
22 | from suds import *
23 | from suds.umx import *
24 | from suds.umx.core import Core
25 | from suds.resolver import NodeResolver, Frame
26 | from suds.sudsobject import Factory
27 |
28 | log = getLogger(__name__)
29 |
30 |
31 | #
32 | # Add typed extensions
33 | # type = The expected xsd type
34 | # real = The 'true' XSD type
35 | #
36 | Content.extensions.append('type')
37 | Content.extensions.append('real')
38 |
39 |
40 | class Typed(Core):
41 | """
42 | A I{typed} XML unmarshaller
43 | @ivar resolver: A schema type resolver.
44 | @type resolver: L{NodeResolver}
45 | """
46 |
47 | def __init__(self, schema):
48 | """
49 | @param schema: A schema object.
50 | @type schema: L{xsd.schema.Schema}
51 | """
52 | self.resolver = NodeResolver(schema)
53 |
54 | def process(self, node, type):
55 | """
56 | Process an object graph representation of the xml L{node}.
57 | @param node: An XML tree.
58 | @type node: L{sax.element.Element}
59 | @param type: The I{optional} schema type.
60 | @type type: L{xsd.sxbase.SchemaObject}
61 | @return: A suds object.
62 | @rtype: L{Object}
63 | """
64 | content = Content(node)
65 | content.type = type
66 | return Core.process(self, content)
67 |
68 | def reset(self):
69 | log.debug('reset')
70 | self.resolver.reset()
71 |
72 | def start(self, content):
73 | #
74 | # Resolve to the schema type; build an object and setup metadata.
75 | #
76 | if content.type is None:
77 | found = self.resolver.find(content.node)
78 | if found is None:
79 | log.error(self.resolver.schema)
80 | raise TypeNotFound(content.node.qname())
81 | content.type = found
82 | else:
83 | known = self.resolver.known(content.node)
84 | frame = Frame(content.type, resolved=known)
85 | self.resolver.push(frame)
86 | real = self.resolver.top().resolved
87 | content.real = real
88 | cls_name = real.name
89 | if cls_name is None:
90 | cls_name = content.node.name
91 | content.data = Factory.object(cls_name)
92 | md = content.data.__metadata__
93 | md.sxtype = real
94 |
95 | def end(self, content):
96 | self.resolver.pop()
97 |
98 | def unbounded(self, content):
99 | return content.type.unbounded()
100 |
101 | def nillable(self, content):
102 | resolved = content.type.resolve()
103 | return ( content.type.nillable or \
104 | (resolved.builtin() and resolved.nillable ) )
105 |
106 | def append_attribute(self, name, value, content):
107 | """
108 | Append an attribute name/value into L{Content.data}.
109 | @param name: The attribute name
110 | @type name: basestring
111 | @param value: The attribute's value
112 | @type value: basestring
113 | @param content: The current content being unmarshalled.
114 | @type content: L{Content}
115 | """
116 | type = self.resolver.findattr(name)
117 | if type is None:
118 | log.warn('attribute (%s) type, not-found', name)
119 | else:
120 | value = self.translated(value, type)
121 | Core.append_attribute(self, name, value, content)
122 |
123 | def append_text(self, content):
124 | """
125 | Append text nodes into L{Content.data}
126 | Here is where the I{true} type is used to translate the value
127 | into the proper python type.
128 | @param content: The current content being unmarshalled.
129 | @type content: L{Content}
130 | """
131 | Core.append_text(self, content)
132 | known = self.resolver.top().resolved
133 | content.text = self.translated(content.text, known)
134 |
135 | def translated(self, value, type):
136 | """ translate using the schema type """
137 | if value is not None:
138 | resolved = type.resolve()
139 | return resolved.translate(value)
140 | else:
141 | return value
--------------------------------------------------------------------------------
/bin/suds/mx/core.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Provides I{marshaller} core classes.
19 | """
20 |
21 | from logging import getLogger
22 | from suds import *
23 | from suds.mx import *
24 | from suds.mx.appender import ContentAppender
25 | from suds.sax.element import Element
26 | from suds.sax.document import Document
27 | from suds.sudsobject import Property
28 |
29 |
30 | log = getLogger(__name__)
31 |
32 |
33 | class Core:
34 | """
35 | An I{abstract} marshaller. This class implement the core
36 | functionality of the marshaller.
37 | @ivar appender: A content appender.
38 | @type appender: L{ContentAppender}
39 | """
40 |
41 | def __init__(self):
42 | """
43 | """
44 | self.appender = ContentAppender(self)
45 |
46 | def process(self, content):
47 | """
48 | Process (marshal) the tag with the specified value using the
49 | optional type information.
50 | @param content: The content to process.
51 | @type content: L{Object}
52 | """
53 | log.debug('processing:\n%s', content)
54 | self.reset()
55 | if content.tag is None:
56 | content.tag = content.value.__class__.__name__
57 | document = Document()
58 | if isinstance(content.value, Property):
59 | root = self.node(content)
60 | self.append(document, content)
61 | else:
62 | self.append(document, content)
63 | return document.root()
64 |
65 | def append(self, parent, content):
66 | """
67 | Append the specified L{content} to the I{parent}.
68 | @param parent: The parent node to append to.
69 | @type parent: L{Element}
70 | @param content: The content to append.
71 | @type content: L{Object}
72 | """
73 | log.debug('appending parent:\n%s\ncontent:\n%s', parent, content)
74 | if self.start(content):
75 | self.appender.append(parent, content)
76 | self.end(parent, content)
77 |
78 | def reset(self):
79 | """
80 | Reset the marshaller.
81 | """
82 | pass
83 |
84 | def node(self, content):
85 | """
86 | Create and return an XML node.
87 | @param content: The content for which proccessing has been suspended.
88 | @type content: L{Object}
89 | @return: An element.
90 | @rtype: L{Element}
91 | """
92 | return Element(content.tag)
93 |
94 | def start(self, content):
95 | """
96 | Appending this content has started.
97 | @param content: The content for which proccessing has started.
98 | @type content: L{Content}
99 | @return: True to continue appending
100 | @rtype: boolean
101 | """
102 | return True
103 |
104 | def suspend(self, content):
105 | """
106 | Appending this content has suspended.
107 | @param content: The content for which proccessing has been suspended.
108 | @type content: L{Content}
109 | """
110 | pass
111 |
112 | def resume(self, content):
113 | """
114 | Appending this content has resumed.
115 | @param content: The content for which proccessing has been resumed.
116 | @type content: L{Content}
117 | """
118 | pass
119 |
120 | def end(self, parent, content):
121 | """
122 | Appending this content has ended.
123 | @param parent: The parent node ending.
124 | @type parent: L{Element}
125 | @param content: The content for which proccessing has ended.
126 | @type content: L{Content}
127 | """
128 | pass
129 |
130 | def setnil(self, node, content):
131 | """
132 | Set the value of the I{node} to nill.
133 | @param node: A I{nil} node.
134 | @type node: L{Element}
135 | @param content: The content to set nil.
136 | @type content: L{Content}
137 | """
138 | pass
139 |
140 | def setdefault(self, node, content):
141 | """
142 | Set the value of the I{node} to a default value.
143 | @param node: A I{nil} node.
144 | @type node: L{Element}
145 | @param content: The content to set the default value.
146 | @type content: L{Content}
147 | @return: The default.
148 | """
149 | pass
150 |
151 | def optional(self, content):
152 | """
153 | Get whether the specified content is optional.
154 | @param content: The content which to check.
155 | @type content: L{Content}
156 | """
157 | return False
158 |
159 |
--------------------------------------------------------------------------------
/bin/suds/options.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Suds basic options classes.
19 | """
20 |
21 | from suds.properties import *
22 | from suds.wsse import Security
23 | from suds.xsd.doctor import Doctor
24 | from suds.transport import Transport
25 | from suds.cache import Cache, NoCache
26 |
27 |
28 | class TpLinker(AutoLinker):
29 | """
30 | Transport (auto) linker used to manage linkage between
31 | transport objects Properties and those Properties that contain them.
32 | """
33 |
34 | def updated(self, properties, prev, next):
35 | if isinstance(prev, Transport):
36 | tp = Unskin(prev.options)
37 | properties.unlink(tp)
38 | if isinstance(next, Transport):
39 | tp = Unskin(next.options)
40 | properties.link(tp)
41 |
42 |
43 | class Options(Skin):
44 | """
45 | Options:
46 | - B{cache} - The XML document cache. May be set (None) for no caching.
47 | - type: L{Cache}
48 | - default: L{NoCache}
49 | - B{faults} - Raise faults raised by server,
50 | else return tuple from service method invocation as (httpcode, object).
51 | - type: I{bool}
52 | - default: True
53 | - B{service} - The default service name.
54 | - type: I{str}
55 | - default: None
56 | - B{port} - The default service port name, not tcp port.
57 | - type: I{str}
58 | - default: None
59 | - B{location} - This overrides the service port address I{URL} defined
60 | in the WSDL.
61 | - type: I{str}
62 | - default: None
63 | - B{transport} - The message transport.
64 | - type: L{Transport}
65 | - default: None
66 | - B{soapheaders} - The soap headers to be included in the soap message.
67 | - type: I{any}
68 | - default: None
69 | - B{wsse} - The web services I{security} provider object.
70 | - type: L{Security}
71 | - default: None
72 | - B{doctor} - A schema I{doctor} object.
73 | - type: L{Doctor}
74 | - default: None
75 | - B{xstq} - The B{x}ml B{s}chema B{t}ype B{q}ualified flag indicates
76 | that the I{xsi:type} attribute values should be qualified by namespace.
77 | - type: I{bool}
78 | - default: True
79 | - B{prefixes} - Elements of the soap message should be qualified (when needed)
80 | using XML prefixes as opposed to xmlns="" syntax.
81 | - type: I{bool}
82 | - default: True
83 | - B{retxml} - Flag that causes the I{raw} soap envelope to be returned instead
84 | of the python object graph.
85 | - type: I{bool}
86 | - default: False
87 | - B{prettyxml} - Flag that causes I{pretty} xml to be rendered when generating
88 | the outbound soap envelope.
89 | - type: I{bool}
90 | - default: False
91 | - B{autoblend} - Flag that ensures that the schema(s) defined within the
92 | WSDL import each other.
93 | - type: I{bool}
94 | - default: False
95 | - B{cachingpolicy} - The caching policy.
96 | - type: I{int}
97 | - 0 = Cache XML documents.
98 | - 1 = Cache WSDL (pickled) object.
99 | - default: 0
100 | - B{plugins} - A plugin container.
101 | - type: I{list}
102 | """
103 | def __init__(self, **kwargs):
104 | domain = __name__
105 | definitions = [
106 | Definition('cache', Cache, NoCache()),
107 | Definition('faults', bool, True),
108 | Definition('transport', Transport, None, TpLinker()),
109 | Definition('service', (int, basestring), None),
110 | Definition('port', (int, basestring), None),
111 | Definition('location', basestring, None),
112 | Definition('soapheaders', (), ()),
113 | Definition('wsse', Security, None),
114 | Definition('doctor', Doctor, None),
115 | Definition('xstq', bool, True),
116 | Definition('prefixes', bool, True),
117 | Definition('retxml', bool, False),
118 | Definition('prettyxml', bool, False),
119 | Definition('autoblend', bool, False),
120 | Definition('cachingpolicy', int, 0),
121 | Definition('plugins', (list, tuple), []),
122 | ]
123 | Skin.__init__(self, domain, definitions, kwargs)
124 |
--------------------------------------------------------------------------------
/bin/jira_xml.py:
--------------------------------------------------------------------------------
1 | """
2 | External search command for querying the JIRA SearchRequest XML endpoint
3 |
4 | Usage:
5 | | jira [time=TIME_OPTION JQL_QUERY | ... ...
6 |
7 | Author: Stephen Sorkin
8 | Author: Russell Uman
9 | """
10 |
11 | import base64
12 | import datetime
13 | import lxml.etree as et
14 | import re
15 | import sys
16 | import time
17 | import urllib
18 | import urllib2
19 |
20 | import jiracommon
21 |
22 | import splunk.mining.dcutils as dcu
23 | import splunk.Intersplunk as isp
24 |
25 | try:
26 | messages = {}
27 | logger = dcu.getLogger()
28 |
29 | # Get configuration values from jira.conf
30 | splunk_conf = jiracommon.getSplunkConf()
31 |
32 | keys = splunk_conf.get('keys', '').split(',')
33 | time_keys = splunk_conf.get('time_keys', '').split(',')
34 | custom_keys = splunk_conf.get('custom_keys', '').split(',')
35 |
36 | offset = 0
37 | count = int(splunk_conf.get('tempMax', 1000))
38 |
39 | # Get configuration values from config.ini
40 | local_conf = jiracommon.getLocalConf()
41 |
42 | hostname = local_conf.get('jira', 'hostname')
43 | username = local_conf.get('jira', 'username')
44 | password = local_conf.get('jira', 'password')
45 | protocol = local_conf.get('jira', 'jira_protocol')
46 | port = local_conf.get('jira', 'jira_port')
47 |
48 | keywords, argvals = isp.getKeywordsAndOptions()
49 | logger.info('keywords: %s' % keywords)
50 | logger.info('argvals: %s' % argvals)
51 | logger.info('argv: %s' % sys.argv)
52 |
53 | # jql must be the last argument (but it's optional)
54 | if len(sys.argv) > 1:
55 | jql = sys.argv[-1]
56 | # default is to search for all issues in the default project
57 | else:
58 | jql = "project=%s" % splunk_conf.get('default_project')
59 | logger.info('jql: %s' % jql)
60 |
61 | time_option = argvals.get('time', "now")
62 | logger.info('time: %s' % time)
63 |
64 | results = []
65 |
66 | header = ['_time']
67 | for k in keys:
68 | header.append(k)
69 | for k in time_keys:
70 | header.append(k)
71 | for k in custom_keys:
72 | header.append(k)
73 | header.extend(['host', 'source', 'sourcetype'])
74 |
75 | while True:
76 | query = urllib.urlencode({'jqlQuery':jql, 'tempMax':count, 'pager/start':offset})
77 |
78 | url = "%s://%s:%s/sr/jira.issueviews:searchrequest-xml/temp/SearchRequest.xml?%s" % (protocol, hostname, port, query)
79 | request = urllib2.Request(url)
80 | logger.info(url)
81 |
82 | request.add_header('Authorization', "Basic %s" % base64.b64encode("%s:%s" % (username, password)))
83 | result = urllib2.urlopen(request)
84 |
85 | root = et.parse(result)
86 |
87 | added_count = 0
88 | for elem in root.iter('item'):
89 | added_count = added_count + 1
90 | row = {}
91 |
92 | for k in keys:
93 | v = elem.xpath(k)
94 | if len(v) > 1:
95 | row[k] = [val.text for val in v]
96 | if '__mv_' + k not in header:
97 | header.append('__mv_' + k)
98 | elif len(v) == 1:
99 | row[k] = v[0].text
100 |
101 | for k in time_keys:
102 | # If time_keys is empty, then the split above results in ['']
103 | if k:
104 | v = elem.xpath(k)
105 | if len(v) == 1:
106 | row[k] = v[0].get("seconds")
107 |
108 | for k in custom_keys:
109 | # If custom_keys is empty, then the split above results in ['']
110 | if k:
111 | v = elem.xpath('customfields/customfield/customfieldvalues/customfieldvalue[../../customfieldname/text() = "%s"]' % k)
112 | if len(v) > 1:
113 | row[k] = [val.text for val in v]
114 | if '__mv_' + k not in header:
115 | header.append('__mv_' + k)
116 | elif len(v) == 1:
117 | row[k] = v[0].text
118 |
119 | v = elem.xpath('customfields/customfield/customfieldvalues/label[../../customfieldname/text() = "%s"]' % k)
120 | if len(v) > 1:
121 | row[k] = [val.text for val in v]
122 | if '__mv_' + k not in header:
123 | header.append('__mv_' + k)
124 | elif len(v) == 1:
125 | row[k] = v[0].text
126 |
127 | # override _time if time argument is set
128 | if time_option == "now":
129 | row['_time'] = int(time.time())
130 | elif time_option in keys:
131 | time_text = elem.findtext(time_option)
132 | if time_text != None:
133 | logger.info("time text: %s" % time_text)
134 | time_value = re.sub(r' (\+|-)\d+$', '', elem.findtext(time_option))
135 | timestamp = time.mktime(datetime.datetime.strptime(time_value, "%a, %d %b %Y %H:%M:%S").timetuple())
136 | row['_time'] = timestamp
137 | else:
138 | row['_time'] = 0
139 | else:
140 | row['_time'] = 0
141 |
142 | row['host'] = hostname
143 | row['source'] = 'jira_xml'
144 | row['sourcetype'] = 'jira_issues'
145 |
146 | results.append(row)
147 |
148 | if added_count > 0:
149 | offset = offset + added_count
150 |
151 | if added_count < count:
152 | break
153 |
154 | isp.outputResults(results, None, header)
155 |
156 | except Exception, e:
157 | logger.exception(str(e))
158 | isp.generateErrorResults(str(e))
--------------------------------------------------------------------------------
/bin/suds/reader.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Contains xml document reader classes.
19 | """
20 |
21 |
22 | from suds.sax.parser import Parser
23 | from suds.transport import Request
24 | from suds.cache import Cache, NoCache
25 | from suds.store import DocumentStore
26 | from suds.plugin import PluginContainer
27 | from logging import getLogger
28 |
29 |
30 | log = getLogger(__name__)
31 |
32 |
33 | class Reader:
34 | """
35 | The reader provides integration with cache.
36 | @ivar options: An options object.
37 | @type options: I{Options}
38 | """
39 |
40 | def __init__(self, options):
41 | """
42 | @param options: An options object.
43 | @type options: I{Options}
44 | """
45 | self.options = options
46 | self.plugins = PluginContainer(options.plugins)
47 |
48 | def mangle(self, name, x):
49 | """
50 | Mangle the name by hashing the I{name} and appending I{x}.
51 | @return: the mangled name.
52 | """
53 | h = abs(hash(name))
54 | return '%s-%s' % (h, x)
55 |
56 |
57 | class DocumentReader(Reader):
58 | """
59 | The XML document reader provides an integration
60 | between the SAX L{Parser} and the document cache.
61 | """
62 |
63 | def open(self, url):
64 | """
65 | Open an XML document at the specified I{url}.
66 | First, the document attempted to be retrieved from
67 | the I{object cache}. If not found, it is downloaded and
68 | parsed using the SAX parser. The result is added to the
69 | cache for the next open().
70 | @param url: A document url.
71 | @type url: str.
72 | @return: The specified XML document.
73 | @rtype: I{Document}
74 | """
75 | cache = self.cache()
76 | id = self.mangle(url, 'document')
77 | d = cache.get(id)
78 | if d is None:
79 | d = self.download(url)
80 | cache.put(id, d)
81 | self.plugins.document.parsed(url=url, document=d.root())
82 | return d
83 |
84 | def download(self, url):
85 | """
86 | Download the docuemnt.
87 | @param url: A document url.
88 | @type url: str.
89 | @return: A file pointer to the docuemnt.
90 | @rtype: file-like
91 | """
92 | store = DocumentStore()
93 | fp = store.open(url)
94 | if fp is None:
95 | fp = self.options.transport.open(Request(url))
96 | content = fp.read()
97 | fp.close()
98 | ctx = self.plugins.document.loaded(url=url, document=content)
99 | content = ctx.document
100 | sax = Parser()
101 | return sax.parse(string=content)
102 |
103 | def cache(self):
104 | """
105 | Get the cache.
106 | @return: The I{options} when I{cachingpolicy} = B{0}.
107 | @rtype: L{Cache}
108 | """
109 | if self.options.cachingpolicy == 0:
110 | return self.options.cache
111 | else:
112 | return NoCache()
113 |
114 |
115 | class DefinitionsReader(Reader):
116 | """
117 | The WSDL definitions reader provides an integration
118 | between the Definitions and the object cache.
119 | @ivar fn: A factory function (constructor) used to
120 | create the object not found in the cache.
121 | @type fn: I{Constructor}
122 | """
123 |
124 | def __init__(self, options, fn):
125 | """
126 | @param options: An options object.
127 | @type options: I{Options}
128 | @param fn: A factory function (constructor) used to
129 | create the object not found in the cache.
130 | @type fn: I{Constructor}
131 | """
132 | Reader.__init__(self, options)
133 | self.fn = fn
134 |
135 | def open(self, url):
136 | """
137 | Open a WSDL at the specified I{url}.
138 | First, the WSDL attempted to be retrieved from
139 | the I{object cache}. After unpickled from the cache, the
140 | I{options} attribute is restored.
141 | If not found, it is downloaded and instantiated using the
142 | I{fn} constructor and added to the cache for the next open().
143 | @param url: A WSDL url.
144 | @type url: str.
145 | @return: The WSDL object.
146 | @rtype: I{Definitions}
147 | """
148 | cache = self.cache()
149 | id = self.mangle(url, 'wsdl')
150 | d = cache.get(id)
151 | if d is None:
152 | d = self.fn(url, self.options)
153 | cache.put(id, d)
154 | else:
155 | d.options = self.options
156 | for imp in d.imports:
157 | imp.imported.options = self.options
158 | return d
159 |
160 | def cache(self):
161 | """
162 | Get the cache.
163 | @return: The I{options} when I{cachingpolicy} = B{1}.
164 | @rtype: L{Cache}
165 | """
166 | if self.options.cachingpolicy == 1:
167 | return self.options.cache
168 | else:
169 | return NoCache()
--------------------------------------------------------------------------------
/bin/suds/bindings/document.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Provides classes for the (WS) SOAP I{document/literal}.
19 | """
20 |
21 | from logging import getLogger
22 | from suds import *
23 | from suds.bindings.binding import Binding
24 | from suds.sax.element import Element
25 |
26 | log = getLogger(__name__)
27 |
28 |
29 | class Document(Binding):
30 | """
31 | The document/literal style. Literal is the only (@use) supported
32 | since document/encoded is pretty much dead.
33 | Although the soap specification supports multiple documents within the soap
34 | , it is very uncommon. As such, suds presents an I{RPC} view of
35 | service methods defined with a single document parameter. This is done so
36 | that the user can pass individual parameters instead of one, single document.
37 | To support the complete specification, service methods defined with multiple documents
38 | (multiple message parts), must present a I{document} view for that method.
39 | """
40 |
41 | def bodycontent(self, method, args, kwargs):
42 | #
43 | # The I{wrapped} vs I{bare} style is detected in 2 ways.
44 | # If there is 2+ parts in the message then it is I{bare}.
45 | # If there is only (1) part and that part resolves to a builtin then
46 | # it is I{bare}. Otherwise, it is I{wrapped}.
47 | #
48 | if not len(method.soap.input.body.parts):
49 | return ()
50 | wrapped = method.soap.input.body.wrapped
51 | if wrapped:
52 | pts = self.bodypart_types(method)
53 | root = self.document(pts[0])
54 | else:
55 | root = []
56 | n = 0
57 | for pd in self.param_defs(method):
58 | if n < len(args):
59 | value = args[n]
60 | else:
61 | value = kwargs.get(pd[0])
62 | n += 1
63 | p = self.mkparam(method, pd, value)
64 | if p is None:
65 | continue
66 | if not wrapped:
67 | ns = pd[1].namespace('ns0')
68 | p.setPrefix(ns[0], ns[1])
69 | root.append(p)
70 | return root
71 |
72 | def replycontent(self, method, body):
73 | wrapped = method.soap.output.body.wrapped
74 | if wrapped:
75 | return body[0].children
76 | else:
77 | return body.children
78 |
79 | def document(self, wrapper):
80 | """
81 | Get the document root. For I{document/literal}, this is the
82 | name of the wrapper element qualifed by the schema tns.
83 | @param wrapper: The method name.
84 | @type wrapper: L{xsd.sxbase.SchemaObject}
85 | @return: A root element.
86 | @rtype: L{Element}
87 | """
88 | tag = wrapper[1].name
89 | ns = wrapper[1].namespace('ns0')
90 | d = Element(tag, ns=ns)
91 | return d
92 |
93 | def mkparam(self, method, pdef, object):
94 | #
95 | # Expand list parameters into individual parameters
96 | # each with the type information. This is because in document
97 | # arrays are simply unbounded elements.
98 | #
99 | if isinstance(object, (list, tuple)):
100 | tags = []
101 | for item in object:
102 | tags.append(self.mkparam(method, pdef, item))
103 | return tags
104 | else:
105 | return Binding.mkparam(self, method, pdef, object)
106 |
107 | def param_defs(self, method):
108 | #
109 | # Get parameter definitions for document literal.
110 | # The I{wrapped} vs I{bare} style is detected in 2 ways.
111 | # If there is 2+ parts in the message then it is I{bare}.
112 | # If there is only (1) part and that part resolves to a builtin then
113 | # it is I{bare}. Otherwise, it is I{wrapped}.
114 | #
115 | pts = self.bodypart_types(method)
116 | wrapped = method.soap.input.body.wrapped
117 | if not wrapped:
118 | return pts
119 | result = []
120 | # wrapped
121 | for p in pts:
122 | resolved = p[1].resolve()
123 | for child, ancestry in resolved:
124 | if child.isattr():
125 | continue
126 | if self.bychoice(ancestry):
127 | log.debug(
128 | '%s\ncontained by , excluded as param for %s()',
129 | child,
130 | method.name)
131 | continue
132 | result.append((child.name, child))
133 | return result
134 |
135 | def returned_types(self, method):
136 | result = []
137 | wrapped = method.soap.output.body.wrapped
138 | rts = self.bodypart_types(method, input=False)
139 | if wrapped:
140 | for pt in rts:
141 | resolved = pt.resolve(nobuiltin=True)
142 | for child, ancestry in resolved:
143 | result.append(child)
144 | break
145 | else:
146 | result += rts
147 | return result
148 |
149 | def bychoice(self, ancestry):
150 | """
151 | The ancestry contains a
152 | @param ancestry: A list of ancestors.
153 | @type ancestry: list
154 | @return: True if contains
155 | @rtype: boolean
156 | """
157 | for x in ancestry:
158 | if x.choice():
159 | return True
160 | return False
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Add-on for JIRA
2 | ======================
3 |
4 | This is a Splunk Add-on for JIRA.
5 |
6 | ## Status
7 |
8 | I am no longer maintaining this app. The version in this repository is older than the newest version available at http://apps.splunk.com/app/1438/. Any bug reports or support requests should probably be made on answers.splunk.com.
9 |
10 | ## Commands
11 |
12 | ### jirarest (REST API)
13 |
14 | #### Syntax
15 |
16 | ```
17 | | jirarest MODE OPTIONS
18 | ```
19 |
20 | #### Modes
21 |
22 | * List favorite filters of the configured user
23 |
24 | ```
25 | | jirarest filters
26 | ```
27 |
28 | * Run a specific filter and return Issues
29 |
30 | ```
31 | | jirarest issues FILTER_ID
32 | ```
33 |
34 | * Run a JQL search and return Issues.
35 |
36 | ```
37 | | jirarest jqlsearch JQL_QUERY
38 | ```
39 |
40 | * Run a JQL search and return the all Changes for all matching Issues.
41 |
42 | ```
43 | | jirarest changelog JQL_QUERY
44 | ```
45 |
46 | * List rapidboards or sprints (Greenhopper REST API)
47 |
48 | ```
49 | | jirarest rapidboards list|all|(RAPIDBOARD_ID [detail sprints|issues])
50 | ```
51 |
52 | * list will list all scrum boards.
53 | * all will list all sprints in all scrum boards.
54 | * RAPIDBOARD_ID will list all sprints in one specific scrum board.
55 | * "detail sprints" gives details on the active sprints in the rapidboard.
56 | * "detail issues" gives details on the active issues in active sprints including swimlanes and groupings.
57 | * Hint: to get issues in a sprint use jqlquery "sprint=sprint_id" after you have found the desired sprint id here with rapidboards.
58 |
59 | * Pipe search results into a jqlsearch
60 |
61 | ```
62 | | search ... | eval foo="WTF-1,WTF-2,WTF-3" | makemv delim=, foo | map search="|jirarest batch JQL_QUERY $foo$"
63 | ```
64 |
65 | * The JQL_QUERY in the batch command is a partial query that ends with the IN keyword, e.g. "key in"
66 | * Results piped in from the preceding search will populate the IN clause.
67 | * Results piped in can be comma- or space- separated
68 | * This is a little ungainly, but quite powerful if you want to pull a list of JIRA keys from an external source and then get all the Issues from JIRA
69 |
70 | #### Options
71 |
72 | * comments
73 | * Shows comments for all Issues returned by main option.
74 | * Compatible with issues, jqlquery, and batch commands.
75 |
76 | * changefield
77 | * By default, pretty names for fields are show. Changefield outputs internal field names instead.
78 | * Compatible with issues, jqlquery and batch commands.
79 |
80 | * changetime TIME_FIELD
81 | * Sets _time to the chosen field. If field does not contain a valid, returns 0 Epoch time
82 | * _time defaults to created if changetime is not set
83 | * Compatible with issues, jqlquery, and batch commands.
84 |
85 | * fields "[INTERNAL_FIELD_NAME,...]"
86 | * Limits the set of fields returned
87 | * Takes a comma-separated list of internal field names. No extra spaces, we're too lazy to trim
88 | * If you want multiple fields, please enclose the field list in double-quotes
89 | * key and created are always returned
90 |
91 | #### Notes
92 |
93 | * The rest command can also be called with | jira.
94 |
95 | ### jirasoap (SOAP API - deprecated)
96 |
97 | #### Syntax
98 |
99 | ```
100 | | jirasoap MODE OPTIONS
101 | ```
102 |
103 | #### MODES
104 |
105 | * List all filters available to the logged-in user
106 |
107 | ```
108 | | jirasoap filters
109 | ```
110 |
111 | * Run a filter
112 |
113 | ```
114 | | jirasoap issues [time=TIME_OPTION] FILTER_ID
115 | ```
116 |
117 | * Run a text search
118 |
119 | ```
120 | | jirasoap search [time=TIME_OPTION] "foo bar bas"
121 | ```
122 |
123 | * Run a JQL search
124 |
125 | ```
126 | | jirasoap jqlsearch [time=TIME_OPTION] JQL_QUERY
127 | ```
128 |
129 | #### Options
130 |
131 | * time
132 | * *Syntax:* now | updated | created | resolved
133 | * *Description:* By default, _time is set to the current timestamp (now), but if you'd like to have _time reflect one of the native timefields on the issue, you can choose from updated, created, or resolved (if this field is empty, _time will be set to the unix epoch - January 1, 1970 00:00:00 GMT)
134 |
135 | #### Notes
136 |
137 | jirasoap is a 'generating' command that produces a results table. It does not create events. There is also a prototype retainsevents version called 'jirasoapevents' with the same syntax.
138 | It creates real events instead of a table, but the events are empty so far...
139 |
140 | ### jiraxml (SearchRequest XML - deprecated)
141 |
142 | #### Synopsis
143 |
144 | Send a JQL query, return a table with one row for each result
145 |
146 | #### Syntax
147 |
148 | ```
149 | | jira [time=TIME_OPTION] [JQL_QUERY]
150 | ```
151 |
152 | #### Arguments
153 |
154 | * time
155 | * *Syntax:* now | updated | created | resolved
156 | * *Description:* By default, _time is set to the current timestamp (now), but if you'd like to have _time reflect one of the native timefields on the issue, you can choose from updated, created, or resolved (if this field is empty, _time will be set to the unix epoch - January 1, 1970 00:00:00 GMT)
157 | * JQL_QUERY
158 | * If omitted, search for all Issues in the default project
159 |
160 | #### Notes
161 |
162 | jiraxml is a 'generating' command that produces a results table. It does not create events. There is also a prototype retainsevents version called 'jiraxmlevents' with the same syntax.
163 | It creates real events instead of a table, but the events are empty so far...
164 |
165 | ## Deployment
166 |
167 | 1. Place the app into $SPLUNK_HOME/etc/apps/jira
168 | 2. Create a folder named local, copy default/jira.conf into local, and update with configuration specific to your instance.
169 | 3. Copy config.ini.sample to config.ini and update with your authentication credentials
170 |
171 | Configure which keys to display in the table with the keys, time_keys, and custom_keys fields.
172 |
173 | * Note that the SOAP API command ignores the key configuration.
174 |
175 | ## Acknowledgements
176 |
177 | * ~~App maintained by Russell Uman~~
178 | * jirarest command written by Fred de Boer
179 | * jirasoap command written by Fred de Boer
180 | * jiraxml command written by Stephen Sorkin and Jeffrey Isenberg
181 | * The Splunk MySQL app was used as a model, and lots of snippets here were stolen from its commands
182 | * To support the jirasoap command, this App redistributes suds 4.0 https://fedorahosted.org/suds/
183 |
--------------------------------------------------------------------------------
/bin/suds/sax/attribute.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Provides XML I{attribute} classes.
19 | """
20 |
21 | import suds.sax
22 | from logging import getLogger
23 | from suds import *
24 | from suds.sax import *
25 | from suds.sax.text import Text
26 |
27 | log = getLogger(__name__)
28 |
29 | class Attribute:
30 | """
31 | An XML attribute object.
32 | @ivar parent: The node containing this attribute
33 | @type parent: L{element.Element}
34 | @ivar prefix: The I{optional} namespace prefix.
35 | @type prefix: basestring
36 | @ivar name: The I{unqualified} name of the attribute
37 | @type name: basestring
38 | @ivar value: The attribute's value
39 | @type value: basestring
40 | """
41 | def __init__(self, name, value=None):
42 | """
43 | @param name: The attribute's name with I{optional} namespace prefix.
44 | @type name: basestring
45 | @param value: The attribute's value
46 | @type value: basestring
47 | """
48 | self.parent = None
49 | self.prefix, self.name = splitPrefix(name)
50 | self.setValue(value)
51 |
52 | def clone(self, parent=None):
53 | """
54 | Clone this object.
55 | @param parent: The parent for the clone.
56 | @type parent: L{element.Element}
57 | @return: A copy of this object assigned to the new parent.
58 | @rtype: L{Attribute}
59 | """
60 | a = Attribute(self.qname(), self.value)
61 | a.parent = parent
62 | return a
63 |
64 | def qname(self):
65 | """
66 | Get the B{fully} qualified name of this attribute
67 | @return: The fully qualified name.
68 | @rtype: basestring
69 | """
70 | if self.prefix is None:
71 | return self.name
72 | else:
73 | return ':'.join((self.prefix, self.name))
74 |
75 | def setValue(self, value):
76 | """
77 | Set the attributes value
78 | @param value: The new value (may be None)
79 | @type value: basestring
80 | @return: self
81 | @rtype: L{Attribute}
82 | """
83 | if isinstance(value, Text):
84 | self.value = value
85 | else:
86 | self.value = Text(value)
87 | return self
88 |
89 | def getValue(self, default=Text('')):
90 | """
91 | Get the attributes value with optional default.
92 | @param default: An optional value to be return when the
93 | attribute's has not been set.
94 | @type default: basestring
95 | @return: The attribute's value, or I{default}
96 | @rtype: L{Text}
97 | """
98 | if self.hasText():
99 | return self.value
100 | else:
101 | return default
102 |
103 | def hasText(self):
104 | """
105 | Get whether the attribute has I{text} and that it is not an empty
106 | (zero length) string.
107 | @return: True when has I{text}.
108 | @rtype: boolean
109 | """
110 | return ( self.value is not None and len(self.value) )
111 |
112 | def namespace(self):
113 | """
114 | Get the attributes namespace. This may either be the namespace
115 | defined by an optional prefix, or its parent's namespace.
116 | @return: The attribute's namespace
117 | @rtype: (I{prefix}, I{name})
118 | """
119 | if self.prefix is None:
120 | return Namespace.default
121 | else:
122 | return self.resolvePrefix(self.prefix)
123 |
124 | def resolvePrefix(self, prefix):
125 | """
126 | Resolve the specified prefix to a known namespace.
127 | @param prefix: A declared prefix
128 | @type prefix: basestring
129 | @return: The namespace that has been mapped to I{prefix}
130 | @rtype: (I{prefix}, I{name})
131 | """
132 | ns = Namespace.default
133 | if self.parent is not None:
134 | ns = self.parent.resolvePrefix(prefix)
135 | return ns
136 |
137 | def match(self, name=None, ns=None):
138 | """
139 | Match by (optional) name and/or (optional) namespace.
140 | @param name: The optional attribute tag name.
141 | @type name: str
142 | @param ns: An optional namespace.
143 | @type ns: (I{prefix}, I{name})
144 | @return: True if matched.
145 | @rtype: boolean
146 | """
147 | if name is None:
148 | byname = True
149 | else:
150 | byname = ( self.name == name )
151 | if ns is None:
152 | byns = True
153 | else:
154 | byns = ( self.namespace()[1] == ns[1] )
155 | return ( byname and byns )
156 |
157 | def __eq__(self, rhs):
158 | """ equals operator """
159 | return rhs is not None and \
160 | isinstance(rhs, Attribute) and \
161 | self.prefix == rhs.name and \
162 | self.name == rhs.name
163 |
164 | def __repr__(self):
165 | """ get a string representation """
166 | return \
167 | 'attr (prefix=%s, name=%s, value=(%s))' %\
168 | (self.prefix, self.name, self.value)
169 |
170 | def __str__(self):
171 | """ get an xml string representation """
172 | return unicode(self).encode('utf-8')
173 |
174 | def __unicode__(self):
175 | """ get an xml string representation """
176 | n = self.qname()
177 | if self.hasText():
178 | v = self.value.escape()
179 | else:
180 | v = self.value
181 | return u'%s="%s"' % (n, v)
182 |
--------------------------------------------------------------------------------
/bin/suds/wsse.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | The I{wsse} module provides WS-Security.
19 | """
20 |
21 | from logging import getLogger
22 | from suds import *
23 | from suds.sudsobject import Object
24 | from suds.sax.element import Element
25 | from suds.sax.date import UTC
26 | from datetime import datetime, timedelta
27 |
28 | try:
29 | from hashlib import md5
30 | except ImportError:
31 | # Python 2.4 compatibility
32 | from md5 import md5
33 |
34 |
35 | dsns = \
36 | ('ds',
37 | 'http://www.w3.org/2000/09/xmldsig#')
38 | wssens = \
39 | ('wsse',
40 | 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd')
41 | wsuns = \
42 | ('wsu',
43 | 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd')
44 | wsencns = \
45 | ('wsenc',
46 | 'http://www.w3.org/2001/04/xmlenc#')
47 |
48 |
49 | class Security(Object):
50 | """
51 | WS-Security object.
52 | @ivar tokens: A list of security tokens
53 | @type tokens: [L{Token},...]
54 | @ivar signatures: A list of signatures.
55 | @type signatures: TBD
56 | @ivar references: A list of references.
57 | @type references: TBD
58 | @ivar keys: A list of encryption keys.
59 | @type keys: TBD
60 | """
61 |
62 | def __init__(self):
63 | """ """
64 | Object.__init__(self)
65 | self.mustUnderstand = True
66 | self.tokens = []
67 | self.signatures = []
68 | self.references = []
69 | self.keys = []
70 |
71 | def xml(self):
72 | """
73 | Get xml representation of the object.
74 | @return: The root node.
75 | @rtype: L{Element}
76 | """
77 | root = Element('Security', ns=wssens)
78 | root.set('mustUnderstand', str(self.mustUnderstand).lower())
79 | for t in self.tokens:
80 | root.append(t.xml())
81 | return root
82 |
83 |
84 | class Token(Object):
85 | """ I{Abstract} security token. """
86 |
87 | @classmethod
88 | def now(cls):
89 | return datetime.now()
90 |
91 | @classmethod
92 | def utc(cls):
93 | return datetime.utcnow()
94 |
95 | @classmethod
96 | def sysdate(cls):
97 | utc = UTC()
98 | return str(utc)
99 |
100 | def __init__(self):
101 | Object.__init__(self)
102 |
103 |
104 | class UsernameToken(Token):
105 | """
106 | Represents a basic I{UsernameToken} WS-Secuirty token.
107 | @ivar username: A username.
108 | @type username: str
109 | @ivar password: A password.
110 | @type password: str
111 | @ivar nonce: A set of bytes to prevent reply attacks.
112 | @type nonce: str
113 | @ivar created: The token created.
114 | @type created: L{datetime}
115 | """
116 |
117 | def __init__(self, username=None, password=None):
118 | """
119 | @param username: A username.
120 | @type username: str
121 | @param password: A password.
122 | @type password: str
123 | """
124 | Token.__init__(self)
125 | self.username = username
126 | self.password = password
127 | self.nonce = None
128 | self.created = None
129 |
130 | def setnonce(self, text=None):
131 | """
132 | Set I{nonce} which is arbitraty set of bytes to prevent
133 | reply attacks.
134 | @param text: The nonce text value.
135 | Generated when I{None}.
136 | @type text: str
137 | """
138 | if text is None:
139 | s = []
140 | s.append(self.username)
141 | s.append(self.password)
142 | s.append(Token.sysdate())
143 | m = md5()
144 | m.update(':'.join(s))
145 | self.nonce = m.hexdigest()
146 | else:
147 | self.nonce = text
148 |
149 | def setcreated(self, dt=None):
150 | """
151 | Set I{created}.
152 | @param dt: The created date & time.
153 | Set as datetime.utc() when I{None}.
154 | @type dt: L{datetime}
155 | """
156 | if dt is None:
157 | self.created = Token.utc()
158 | else:
159 | self.created = dt
160 |
161 |
162 | def xml(self):
163 | """
164 | Get xml representation of the object.
165 | @return: The root node.
166 | @rtype: L{Element}
167 | """
168 | root = Element('UsernameToken', ns=wssens)
169 | u = Element('Username', ns=wssens)
170 | u.setText(self.username)
171 | root.append(u)
172 | p = Element('Password', ns=wssens)
173 | p.setText(self.password)
174 | root.append(p)
175 | if self.nonce is not None:
176 | n = Element('Nonce', ns=wssens)
177 | n.setText(self.nonce)
178 | root.append(n)
179 | if self.created is not None:
180 | n = Element('Created', ns=wsuns)
181 | n.setText(str(UTC(self.created)))
182 | root.append(n)
183 | return root
184 |
185 |
186 | class Timestamp(Token):
187 | """
188 | Represents the I{Timestamp} WS-Secuirty token.
189 | @ivar created: The token created.
190 | @type created: L{datetime}
191 | @ivar expires: The token expires.
192 | @type expires: L{datetime}
193 | """
194 |
195 | def __init__(self, validity=90):
196 | """
197 | @param validity: The time in seconds.
198 | @type validity: int
199 | """
200 | Token.__init__(self)
201 | self.created = Token.utc()
202 | self.expires = self.created + timedelta(seconds=validity)
203 |
204 | def xml(self):
205 | root = Element("Timestamp", ns=wsuns)
206 | created = Element('Created', ns=wsuns)
207 | created.setText(str(UTC(self.created)))
208 | expires = Element('Expires', ns=wsuns)
209 | expires.setText(str(UTC(self.expires)))
210 | root.append(created)
211 | root.append(expires)
212 | return root
--------------------------------------------------------------------------------
/bin/suds/transport/http.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Contains classes for basic HTTP transport implementations.
19 | """
20 |
21 | import urllib2 as u2
22 | import base64
23 | import socket
24 | from suds.transport import *
25 | from suds.properties import Unskin
26 | from urlparse import urlparse
27 | from cookielib import CookieJar
28 | from logging import getLogger
29 |
30 | log = getLogger(__name__)
31 |
32 |
33 | class HttpTransport(Transport):
34 | """
35 | HTTP transport using urllib2. Provided basic http transport
36 | that provides for cookies, proxies but no authentication.
37 | """
38 |
39 | def __init__(self, **kwargs):
40 | """
41 | @param kwargs: Keyword arguments.
42 | - B{proxy} - An http proxy to be specified on requests.
43 | The proxy is defined as {protocol:proxy,}
44 | - type: I{dict}
45 | - default: {}
46 | - B{timeout} - Set the url open timeout (seconds).
47 | - type: I{float}
48 | - default: 90
49 | """
50 | Transport.__init__(self)
51 | Unskin(self.options).update(kwargs)
52 | self.cookiejar = CookieJar()
53 | self.proxy = {}
54 | self.urlopener = None
55 |
56 | def open(self, request):
57 | try:
58 | url = request.url
59 | log.debug('opening (%s)', url)
60 | u2request = u2.Request(url)
61 | self.proxy = self.options.proxy
62 | return self.u2open(u2request)
63 | except u2.HTTPError, e:
64 | raise TransportError(str(e), e.code, e.fp)
65 |
66 | def send(self, request):
67 | result = None
68 | url = request.url
69 | msg = request.message
70 | headers = request.headers
71 | try:
72 | u2request = u2.Request(url, msg, headers)
73 | self.addcookies(u2request)
74 | self.proxy = self.options.proxy
75 | request.headers.update(u2request.headers)
76 | log.debug('sending:\n%s', request)
77 | fp = self.u2open(u2request)
78 | self.getcookies(fp, u2request)
79 | result = Reply(200, fp.headers.dict, fp.read())
80 | log.debug('received:\n%s', result)
81 | except u2.HTTPError, e:
82 | if e.code in (202,204):
83 | result = None
84 | else:
85 | raise TransportError(e.msg, e.code, e.fp)
86 | return result
87 |
88 | def addcookies(self, u2request):
89 | """
90 | Add cookies in the cookiejar to the request.
91 | @param u2request: A urllib2 request.
92 | @rtype: u2request: urllib2.Requet.
93 | """
94 | self.cookiejar.add_cookie_header(u2request)
95 |
96 | def getcookies(self, fp, u2request):
97 | """
98 | Add cookies in the request to the cookiejar.
99 | @param u2request: A urllib2 request.
100 | @rtype: u2request: urllib2.Requet.
101 | """
102 | self.cookiejar.extract_cookies(fp, u2request)
103 |
104 | def u2open(self, u2request):
105 | """
106 | Open a connection.
107 | @param u2request: A urllib2 request.
108 | @type u2request: urllib2.Requet.
109 | @return: The opened file-like urllib2 object.
110 | @rtype: fp
111 | """
112 | tm = self.options.timeout
113 | url = self.u2opener()
114 | if self.u2ver() < 2.6:
115 | socket.setdefaulttimeout(tm)
116 | return url.open(u2request)
117 | else:
118 | return url.open(u2request, timeout=tm)
119 |
120 | def u2opener(self):
121 | """
122 | Create a urllib opener.
123 | @return: An opener.
124 | @rtype: I{OpenerDirector}
125 | """
126 | if self.urlopener is None:
127 | return u2.build_opener(*self.u2handlers())
128 | else:
129 | return self.urlopener
130 |
131 | def u2handlers(self):
132 | """
133 | Get a collection of urllib handlers.
134 | @return: A list of handlers to be installed in the opener.
135 | @rtype: [Handler,...]
136 | """
137 | handlers = []
138 | handlers.append(u2.ProxyHandler(self.proxy))
139 | return handlers
140 |
141 | def u2ver(self):
142 | """
143 | Get the major/minor version of the urllib2 lib.
144 | @return: The urllib2 version.
145 | @rtype: float
146 | """
147 | try:
148 | part = u2.__version__.split('.', 1)
149 | n = float('.'.join(part))
150 | return n
151 | except Exception, e:
152 | log.exception(e)
153 | return 0
154 |
155 | def __deepcopy__(self, memo={}):
156 | clone = self.__class__()
157 | p = Unskin(self.options)
158 | cp = Unskin(clone.options)
159 | cp.update(p)
160 | return clone
161 |
162 |
163 | class HttpAuthenticated(HttpTransport):
164 | """
165 | Provides basic http authentication for servers that don't follow
166 | the specified challenge / response model. This implementation
167 | appends the I{Authorization} http header with base64 encoded
168 | credentials on every http request.
169 | """
170 |
171 | def open(self, request):
172 | self.addcredentials(request)
173 | return HttpTransport.open(self, request)
174 |
175 | def send(self, request):
176 | self.addcredentials(request)
177 | return HttpTransport.send(self, request)
178 |
179 | def addcredentials(self, request):
180 | credentials = self.credentials()
181 | if not (None in credentials):
182 | encoded = base64.encodestring(':'.join(credentials))
183 | basic = 'Basic %s' % encoded[:-1]
184 | request.headers['Authorization'] = basic
185 |
186 | def credentials(self):
187 | return (self.options.username, self.options.password)
--------------------------------------------------------------------------------
/bin/suds/xsd/doctor.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | The I{doctor} module provides classes for fixing broken (sick)
19 | schema(s).
20 | """
21 |
22 | from logging import getLogger
23 | from suds.sax import splitPrefix, Namespace
24 | from suds.sax.element import Element
25 | from suds.plugin import DocumentPlugin, DocumentContext
26 |
27 | log = getLogger(__name__)
28 |
29 |
30 | class Doctor:
31 | """
32 | Schema Doctor.
33 | """
34 | def examine(self, root):
35 | """
36 | Examine and repair the schema (if necessary).
37 | @param root: A schema root element.
38 | @type root: L{Element}
39 | """
40 | pass
41 |
42 |
43 | class Practice(Doctor):
44 | """
45 | A collection of doctors.
46 | @ivar doctors: A list of doctors.
47 | @type doctors: list
48 | """
49 |
50 | def __init__(self):
51 | self.doctors = []
52 |
53 | def add(self, doctor):
54 | """
55 | Add a doctor to the practice
56 | @param doctor: A doctor to add.
57 | @type doctor: L{Doctor}
58 | """
59 | self.doctors.append(doctor)
60 |
61 | def examine(self, root):
62 | for d in self.doctors:
63 | d.examine(root)
64 | return root
65 |
66 |
67 | class TnsFilter:
68 | """
69 | Target Namespace filter.
70 | @ivar tns: A list of target namespaces.
71 | @type tns: [str,...]
72 | """
73 |
74 | def __init__(self, *tns):
75 | """
76 | @param tns: A list of target namespaces.
77 | @type tns: [str,...]
78 | """
79 | self.tns = []
80 | self.add(*tns)
81 |
82 | def add(self, *tns):
83 | """
84 | Add I{targetNamesapces} to be added.
85 | @param tns: A list of target namespaces.
86 | @type tns: [str,...]
87 | """
88 | self.tns += tns
89 |
90 | def match(self, root, ns):
91 | """
92 | Match by I{targetNamespace} excluding those that
93 | are equal to the specified namespace to prevent
94 | adding an import to itself.
95 | @param root: A schema root.
96 | @type root: L{Element}
97 | """
98 | tns = root.get('targetNamespace')
99 | if len(self.tns):
100 | matched = ( tns in self.tns )
101 | else:
102 | matched = 1
103 | itself = ( ns == tns )
104 | return ( matched and not itself )
105 |
106 |
107 | class Import:
108 | """
109 | An to be applied.
110 | @cvar xsdns: The XSD namespace.
111 | @type xsdns: (p,u)
112 | @ivar ns: An import namespace.
113 | @type ns: str
114 | @ivar location: An optional I{schemaLocation}.
115 | @type location: str
116 | @ivar filter: A filter used to restrict application to
117 | a particular schema.
118 | @type filter: L{TnsFilter}
119 | """
120 |
121 | xsdns = Namespace.xsdns
122 |
123 | def __init__(self, ns, location=None):
124 | """
125 | @param ns: An import namespace.
126 | @type ns: str
127 | @param location: An optional I{schemaLocation}.
128 | @type location: str
129 | """
130 | self.ns = ns
131 | self.location = location
132 | self.filter = TnsFilter()
133 |
134 | def setfilter(self, filter):
135 | """
136 | Set the filter.
137 | @param filter: A filter to set.
138 | @type filter: L{TnsFilter}
139 | """
140 | self.filter = filter
141 |
142 | def apply(self, root):
143 | """
144 | Apply the import (rule) to the specified schema.
145 | If the schema does not already contain an import for the
146 | I{namespace} specified here, it is added.
147 | @param root: A schema root.
148 | @type root: L{Element}
149 | """
150 | if not self.filter.match(root, self.ns):
151 | return
152 | if self.exists(root):
153 | return
154 | node = Element('import', ns=self.xsdns)
155 | node.set('namespace', self.ns)
156 | if self.location is not None:
157 | node.set('schemaLocation', self.location)
158 | log.debug('inserting: %s', node)
159 | root.insert(node)
160 |
161 | def add(self, root):
162 | """
163 | Add an to the specified schema root.
164 | @param root: A schema root.
165 | @type root: L{Element}
166 | """
167 | node = Element('import', ns=self.xsdns)
168 | node.set('namespace', self.ns)
169 | if self.location is not None:
170 | node.set('schemaLocation', self.location)
171 | log.debug('%s inserted', node)
172 | root.insert(node)
173 |
174 | def exists(self, root):
175 | """
176 | Check to see if the already exists
177 | in the specified schema root by matching I{namesapce}.
178 | @param root: A schema root.
179 | @type root: L{Element}
180 | """
181 | for node in root.children:
182 | if node.name != 'import':
183 | continue
184 | ns = node.get('namespace')
185 | if self.ns == ns:
186 | return 1
187 | return 0
188 |
189 |
190 | class ImportDoctor(Doctor, DocumentPlugin):
191 | """
192 | Doctor used to fix missing imports.
193 | @ivar imports: A list of imports to apply.
194 | @type imports: [L{Import},...]
195 | """
196 |
197 | def __init__(self, *imports):
198 | """
199 | """
200 | self.imports = []
201 | self.add(*imports)
202 |
203 | def add(self, *imports):
204 | """
205 | Add a namesapce to be checked.
206 | @param imports: A list of L{Import} objects.
207 | @type imports: [L{Import},..]
208 | """
209 | self.imports += imports
210 |
211 | def examine(self, node):
212 | for imp in self.imports:
213 | imp.apply(node)
214 |
215 | def parsed(self, context):
216 | node = context.document
217 | # xsd root
218 | if node.name == 'schema' and Namespace.xsd(node.namespace()):
219 | self.examine(node)
220 | return
221 | # look deeper
222 | context = DocumentContext()
223 | for child in node:
224 | context.document = child
225 | self.parsed(context)
226 |
--------------------------------------------------------------------------------
/bin/suds/xsd/query.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | The I{query} module defines a class for performing schema queries.
19 | """
20 |
21 | from logging import getLogger
22 | from suds import *
23 | from suds.sudsobject import *
24 | from suds.xsd import qualify, isqref
25 | from suds.xsd.sxbuiltin import Factory
26 |
27 | log = getLogger(__name__)
28 |
29 |
30 | class Query(Object):
31 | """
32 | Schema query base class.
33 | """
34 |
35 | def __init__(self, ref=None):
36 | """
37 | @param ref: The schema reference being queried.
38 | @type ref: qref
39 | """
40 | Object.__init__(self)
41 | self.id = objid(self)
42 | self.ref = ref
43 | self.history = []
44 | self.resolved = False
45 | if not isqref(self.ref):
46 | raise Exception('%s, must be qref' % tostr(self.ref))
47 |
48 | def execute(self, schema):
49 | """
50 | Execute this query using the specified schema.
51 | @param schema: The schema associated with the query. The schema
52 | is used by the query to search for items.
53 | @type schema: L{schema.Schema}
54 | @return: The item matching the search criteria.
55 | @rtype: L{sxbase.SchemaObject}
56 | """
57 | raise Exception, 'not-implemented by subclass'
58 |
59 | def filter(self, result):
60 | """
61 | Filter the specified result based on query criteria.
62 | @param result: A potential result.
63 | @type result: L{sxbase.SchemaObject}
64 | @return: True if result should be excluded.
65 | @rtype: boolean
66 | """
67 | if result is None:
68 | return True
69 | reject = ( result in self.history )
70 | if reject:
71 | log.debug('result %s, rejected by\n%s', Repr(result), self)
72 | return reject
73 |
74 | def result(self, result):
75 | """
76 | Query result post processing.
77 | @param result: A query result.
78 | @type result: L{sxbase.SchemaObject}
79 | """
80 | if result is None:
81 | log.debug('%s, not-found', self.ref)
82 | return
83 | if self.resolved:
84 | result = result.resolve()
85 | log.debug('%s, found as: %s', self.ref, Repr(result))
86 | self.history.append(result)
87 | return result
88 |
89 |
90 | class BlindQuery(Query):
91 | """
92 | Schema query class that I{blindly} searches for a reference in
93 | the specified schema. It may be used to find Elements and Types but
94 | will match on an Element first. This query will also find builtins.
95 | """
96 |
97 | def execute(self, schema):
98 | if schema.builtin(self.ref):
99 | name = self.ref[0]
100 | b = Factory.create(schema, name)
101 | log.debug('%s, found builtin (%s)', self.id, name)
102 | return b
103 | result = None
104 | for d in (schema.elements, schema.types):
105 | result = d.get(self.ref)
106 | if self.filter(result):
107 | result = None
108 | else:
109 | break
110 | if result is None:
111 | eq = ElementQuery(self.ref)
112 | eq.history = self.history
113 | result = eq.execute(schema)
114 | return self.result(result)
115 |
116 |
117 | class TypeQuery(Query):
118 | """
119 | Schema query class that searches for Type references in
120 | the specified schema. Matches on root types only.
121 | """
122 |
123 | def execute(self, schema):
124 | if schema.builtin(self.ref):
125 | name = self.ref[0]
126 | b = Factory.create(schema, name)
127 | log.debug('%s, found builtin (%s)', self.id, name)
128 | return b
129 | result = schema.types.get(self.ref)
130 | if self.filter(result):
131 | result = None
132 | return self.result(result)
133 |
134 |
135 | class GroupQuery(Query):
136 | """
137 | Schema query class that searches for Group references in
138 | the specified schema.
139 | """
140 |
141 | def execute(self, schema):
142 | result = schema.groups.get(self.ref)
143 | if self.filter(result):
144 | result = None
145 | return self.result(result)
146 |
147 |
148 | class AttrQuery(Query):
149 | """
150 | Schema query class that searches for Attribute references in
151 | the specified schema. Matches on root Attribute by qname first, then searches
152 | deep into the document.
153 | """
154 |
155 | def execute(self, schema):
156 | result = schema.attributes.get(self.ref)
157 | if self.filter(result):
158 | result = self.__deepsearch(schema)
159 | return self.result(result)
160 |
161 | def __deepsearch(self, schema):
162 | from suds.xsd.sxbasic import Attribute
163 | result = None
164 | for e in schema.all:
165 | result = e.find(self.ref, (Attribute,))
166 | if self.filter(result):
167 | result = None
168 | else:
169 | break
170 | return result
171 |
172 |
173 | class AttrGroupQuery(Query):
174 | """
175 | Schema query class that searches for attributeGroup references in
176 | the specified schema.
177 | """
178 |
179 | def execute(self, schema):
180 | result = schema.agrps.get(self.ref)
181 | if self.filter(result):
182 | result = None
183 | return self.result(result)
184 |
185 |
186 | class ElementQuery(Query):
187 | """
188 | Schema query class that searches for Element references in
189 | the specified schema. Matches on root Elements by qname first, then searches
190 | deep into the document.
191 | """
192 |
193 | def execute(self, schema):
194 | result = schema.elements.get(self.ref)
195 | if self.filter(result):
196 | result = self.__deepsearch(schema)
197 | return self.result(result)
198 |
199 | def __deepsearch(self, schema):
200 | from suds.xsd.sxbasic import Element
201 | result = None
202 | for e in schema.all:
203 | result = e.find(self.ref, (Element,))
204 | if self.filter(result):
205 | result = None
206 | else:
207 | break
208 | return result
--------------------------------------------------------------------------------
/bin/suds/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/bin/suds/plugin.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | The plugin module provides classes for implementation
19 | of suds plugins.
20 | """
21 |
22 | from suds import *
23 | from logging import getLogger
24 |
25 | log = getLogger(__name__)
26 |
27 |
28 | class Context(object):
29 | """
30 | Plugin context.
31 | """
32 | pass
33 |
34 |
35 | class InitContext(Context):
36 | """
37 | Init Context.
38 | @ivar wsdl: The wsdl.
39 | @type wsdl: L{wsdl.Definitions}
40 | """
41 | pass
42 |
43 |
44 | class DocumentContext(Context):
45 | """
46 | The XML document load context.
47 | @ivar url: The URL.
48 | @type url: str
49 | @ivar document: Either the XML text or the B{parsed} document root.
50 | @type document: (str|L{sax.element.Element})
51 | """
52 | pass
53 |
54 |
55 | class MessageContext(Context):
56 | """
57 | The context for sending the soap envelope.
58 | @ivar envelope: The soap envelope to be sent.
59 | @type envelope: (str|L{sax.element.Element})
60 | @ivar reply: The reply.
61 | @type reply: (str|L{sax.element.Element}|object)
62 | """
63 | pass
64 |
65 |
66 | class Plugin:
67 | """
68 | Plugin base.
69 | """
70 | pass
71 |
72 |
73 | class InitPlugin(Plugin):
74 | """
75 | The base class for suds I{init} plugins.
76 | """
77 |
78 | def initialized(self, context):
79 | """
80 | Suds client initialization.
81 | Called after wsdl the has been loaded. Provides the plugin
82 | with the opportunity to inspect/modify the WSDL.
83 | @param context: The init context.
84 | @type context: L{InitContext}
85 | """
86 | pass
87 |
88 |
89 | class DocumentPlugin(Plugin):
90 | """
91 | The base class for suds I{document} plugins.
92 | """
93 |
94 | def loaded(self, context):
95 | """
96 | Suds has loaded a WSDL/XSD document. Provides the plugin
97 | with an opportunity to inspect/modify the unparsed document.
98 | Called after each WSDL/XSD document is loaded.
99 | @param context: The document context.
100 | @type context: L{DocumentContext}
101 | """
102 | pass
103 |
104 | def parsed(self, context):
105 | """
106 | Suds has parsed a WSDL/XSD document. Provides the plugin
107 | with an opportunity to inspect/modify the parsed document.
108 | Called after each WSDL/XSD document is parsed.
109 | @param context: The document context.
110 | @type context: L{DocumentContext}
111 | """
112 | pass
113 |
114 |
115 | class MessagePlugin(Plugin):
116 | """
117 | The base class for suds I{soap message} plugins.
118 | """
119 |
120 | def marshalled(self, context):
121 | """
122 | Suds will send the specified soap envelope.
123 | Provides the plugin with the opportunity to inspect/modify
124 | the envelope Document before it is sent.
125 | @param context: The send context.
126 | The I{envelope} is the envelope docuemnt.
127 | @type context: L{MessageContext}
128 | """
129 | pass
130 |
131 | def sending(self, context):
132 | """
133 | Suds will send the specified soap envelope.
134 | Provides the plugin with the opportunity to inspect/modify
135 | the message text it is sent.
136 | @param context: The send context.
137 | The I{envelope} is the envelope text.
138 | @type context: L{MessageContext}
139 | """
140 | pass
141 |
142 | def received(self, context):
143 | """
144 | Suds has received the specified reply.
145 | Provides the plugin with the opportunity to inspect/modify
146 | the received XML text before it is SAX parsed.
147 | @param context: The reply context.
148 | The I{reply} is the raw text.
149 | @type context: L{MessageContext}
150 | """
151 | pass
152 |
153 | def parsed(self, context):
154 | """
155 | Suds has sax parsed the received reply.
156 | Provides the plugin with the opportunity to inspect/modify
157 | the sax parsed DOM tree for the reply before it is unmarshalled.
158 | @param context: The reply context.
159 | The I{reply} is DOM tree.
160 | @type context: L{MessageContext}
161 | """
162 | pass
163 |
164 | def unmarshalled(self, context):
165 | """
166 | Suds has unmarshalled the received reply.
167 | Provides the plugin with the opportunity to inspect/modify
168 | the unmarshalled reply object before it is returned.
169 | @param context: The reply context.
170 | The I{reply} is unmarshalled suds object.
171 | @type context: L{MessageContext}
172 | """
173 | pass
174 |
175 |
176 | class PluginContainer:
177 | """
178 | Plugin container provides easy method invocation.
179 | @ivar plugins: A list of plugin objects.
180 | @type plugins: [L{Plugin},]
181 | @cvar ctxclass: A dict of plugin method / context classes.
182 | @type ctxclass: dict
183 | """
184 |
185 | domains = {\
186 | 'init': (InitContext, InitPlugin),
187 | 'document': (DocumentContext, DocumentPlugin),
188 | 'message': (MessageContext, MessagePlugin ),
189 | }
190 |
191 | def __init__(self, plugins):
192 | """
193 | @param plugins: A list of plugin objects.
194 | @type plugins: [L{Plugin},]
195 | """
196 | self.plugins = plugins
197 |
198 | def __getattr__(self, name):
199 | domain = self.domains.get(name)
200 | if domain:
201 | plugins = []
202 | ctx, pclass = domain
203 | for p in self.plugins:
204 | if isinstance(p, pclass):
205 | plugins.append(p)
206 | return PluginDomain(ctx, plugins)
207 | else:
208 | raise Exception, 'plugin domain (%s), invalid' % name
209 |
210 |
211 | class PluginDomain:
212 | """
213 | The plugin domain.
214 | @ivar ctx: A context.
215 | @type ctx: L{Context}
216 | @ivar plugins: A list of plugins (targets).
217 | @type plugins: list
218 | """
219 |
220 | def __init__(self, ctx, plugins):
221 | self.ctx = ctx
222 | self.plugins = plugins
223 |
224 | def __getattr__(self, name):
225 | return Method(name, self)
226 |
227 |
228 | class Method:
229 | """
230 | Plugin method.
231 | @ivar name: The method name.
232 | @type name: str
233 | @ivar domain: The plugin domain.
234 | @type domain: L{PluginDomain}
235 | """
236 |
237 | def __init__(self, name, domain):
238 | """
239 | @param name: The method name.
240 | @type name: str
241 | @param domain: A plugin domain.
242 | @type domain: L{PluginDomain}
243 | """
244 | self.name = name
245 | self.domain = domain
246 |
247 | def __call__(self, **kwargs):
248 | ctx = self.domain.ctx()
249 | ctx.__dict__.update(kwargs)
250 | for plugin in self.domain.plugins:
251 | try:
252 | method = getattr(plugin, self.name, None)
253 | if method and callable(method):
254 | method(ctx)
255 | except Exception, pe:
256 | log.exception(pe)
257 | return ctx
258 |
--------------------------------------------------------------------------------
/bin/suds/umx/core.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | Provides base classes for XML->object I{unmarshalling}.
19 | """
20 |
21 | from logging import getLogger
22 | from suds import *
23 | from suds.umx import *
24 | from suds.umx.attrlist import AttrList
25 | from suds.sax.text import Text
26 | from suds.sudsobject import Factory, merge
27 |
28 |
29 | log = getLogger(__name__)
30 |
31 | reserved = { 'class':'cls', 'def':'dfn', }
32 |
33 | class Core:
34 | """
35 | The abstract XML I{node} unmarshaller. This class provides the
36 | I{core} unmarshalling functionality.
37 | """
38 |
39 | def process(self, content):
40 | """
41 | Process an object graph representation of the xml I{node}.
42 | @param content: The current content being unmarshalled.
43 | @type content: L{Content}
44 | @return: A suds object.
45 | @rtype: L{Object}
46 | """
47 | self.reset()
48 | return self.append(content)
49 |
50 | def append(self, content):
51 | """
52 | Process the specified node and convert the XML document into
53 | a I{suds} L{object}.
54 | @param content: The current content being unmarshalled.
55 | @type content: L{Content}
56 | @return: A I{append-result} tuple as: (L{Object}, I{value})
57 | @rtype: I{append-result}
58 | @note: This is not the proper entry point.
59 | @see: L{process()}
60 | """
61 | self.start(content)
62 | self.append_attributes(content)
63 | self.append_children(content)
64 | self.append_text(content)
65 | self.end(content)
66 | return self.postprocess(content)
67 |
68 | def postprocess(self, content):
69 | """
70 | Perform final processing of the resulting data structure as follows:
71 | - Mixed values (children and text) will have a result of the I{content.node}.
72 | - Simi-simple values (attributes, no-children and text) will have a result of a
73 | property object.
74 | - Simple values (no-attributes, no-children with text nodes) will have a string
75 | result equal to the value of the content.node.getText().
76 | @param content: The current content being unmarshalled.
77 | @type content: L{Content}
78 | @return: The post-processed result.
79 | @rtype: I{any}
80 | """
81 | node = content.node
82 | if len(node.children) and node.hasText():
83 | return node
84 | attributes = AttrList(node.attributes)
85 | if attributes.rlen() and \
86 | not len(node.children) and \
87 | node.hasText():
88 | p = Factory.property(node.name, node.getText())
89 | return merge(content.data, p)
90 | if len(content.data):
91 | return content.data
92 | lang = attributes.lang()
93 | if content.node.isnil():
94 | return None
95 | if not len(node.children) and content.text is None:
96 | if self.nillable(content):
97 | return None
98 | else:
99 | return Text('', lang=lang)
100 | if isinstance(content.text, basestring):
101 | return Text(content.text, lang=lang)
102 | else:
103 | return content.text
104 |
105 | def append_attributes(self, content):
106 | """
107 | Append attribute nodes into L{Content.data}.
108 | Attributes in the I{schema} or I{xml} namespaces are skipped.
109 | @param content: The current content being unmarshalled.
110 | @type content: L{Content}
111 | """
112 | attributes = AttrList(content.node.attributes)
113 | for attr in attributes.real():
114 | name = attr.name
115 | value = attr.value
116 | self.append_attribute(name, value, content)
117 |
118 | def append_attribute(self, name, value, content):
119 | """
120 | Append an attribute name/value into L{Content.data}.
121 | @param name: The attribute name
122 | @type name: basestring
123 | @param value: The attribute's value
124 | @type value: basestring
125 | @param content: The current content being unmarshalled.
126 | @type content: L{Content}
127 | """
128 | key = name
129 | key = '_%s' % reserved.get(key, key)
130 | setattr(content.data, key, value)
131 |
132 | def append_children(self, content):
133 | """
134 | Append child nodes into L{Content.data}
135 | @param content: The current content being unmarshalled.
136 | @type content: L{Content}
137 | """
138 | for child in content.node:
139 | cont = Content(child)
140 | cval = self.append(cont)
141 | key = reserved.get(child.name, child.name)
142 | if key in content.data:
143 | v = getattr(content.data, key)
144 | if isinstance(v, list):
145 | v.append(cval)
146 | else:
147 | setattr(content.data, key, [v, cval])
148 | continue
149 | if self.unbounded(cont):
150 | if cval is None:
151 | setattr(content.data, key, [])
152 | else:
153 | setattr(content.data, key, [cval,])
154 | else:
155 | setattr(content.data, key, cval)
156 |
157 | def append_text(self, content):
158 | """
159 | Append text nodes into L{Content.data}
160 | @param content: The current content being unmarshalled.
161 | @type content: L{Content}
162 | """
163 | if content.node.hasText():
164 | content.text = content.node.getText()
165 |
166 | def reset(self):
167 | pass
168 |
169 | def start(self, content):
170 | """
171 | Processing on I{node} has started. Build and return
172 | the proper object.
173 | @param content: The current content being unmarshalled.
174 | @type content: L{Content}
175 | @return: A subclass of Object.
176 | @rtype: L{Object}
177 | """
178 | content.data = Factory.object(content.node.name)
179 |
180 | def end(self, content):
181 | """
182 | Processing on I{node} has ended.
183 | @param content: The current content being unmarshalled.
184 | @type content: L{Content}
185 | """
186 | pass
187 |
188 | def bounded(self, content):
189 | """
190 | Get whether the content is bounded (not a list).
191 | @param content: The current content being unmarshalled.
192 | @type content: L{Content}
193 | @return: True if bounded, else False
194 | @rtype: boolean
195 | '"""
196 | return ( not self.unbounded(content) )
197 |
198 | def unbounded(self, content):
199 | """
200 | Get whether the object is unbounded (a list).
201 | @param content: The current content being unmarshalled.
202 | @type content: L{Content}
203 | @return: True if unbounded, else False
204 | @rtype: boolean
205 | '"""
206 | return False
207 |
208 | def nillable(self, content):
209 | """
210 | Get whether the object is nillable.
211 | @param content: The current content being unmarshalled.
212 | @type content: L{Content}
213 | @return: True if nillable, else False
214 | @rtype: boolean
215 | '"""
216 | return False
--------------------------------------------------------------------------------
/bin/suds/xsd/sxbuiltin.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | The I{sxbuiltin} module provides classes that represent
19 | XSD I{builtin} schema objects.
20 | """
21 |
22 | from logging import getLogger
23 | from suds import *
24 | from suds.xsd import *
25 | from suds.sax.date import *
26 | from suds.xsd.sxbase import XBuiltin
27 | import datetime as dt
28 |
29 |
30 | log = getLogger(__name__)
31 |
32 |
33 | class XString(XBuiltin):
34 | """
35 | Represents an (xsd) node
36 | """
37 | pass
38 |
39 |
40 | class XAny(XBuiltin):
41 | """
42 | Represents an (xsd) node
43 | """
44 |
45 | def __init__(self, schema, name):
46 | XBuiltin.__init__(self, schema, name)
47 | self.nillable = False
48 |
49 | def get_child(self, name):
50 | child = XAny(self.schema, name)
51 | return (child, [])
52 |
53 | def any(self):
54 | return True
55 |
56 |
57 | class XBoolean(XBuiltin):
58 | """
59 | Represents an (xsd) boolean builtin type.
60 | """
61 |
62 | translation = (
63 | { '1':True,'true':True,'0':False,'false':False },
64 | { True:'true',1:'true',False:'false',0:'false' },
65 | )
66 |
67 | def translate(self, value, topython=True):
68 | if topython:
69 | if isinstance(value, basestring):
70 | return XBoolean.translation[0].get(value)
71 | else:
72 | return None
73 | else:
74 | if isinstance(value, (bool,int)):
75 | return XBoolean.translation[1].get(value)
76 | else:
77 | return value
78 |
79 |
80 | class XInteger(XBuiltin):
81 | """
82 | Represents an (xsd) xs:int builtin type.
83 | """
84 |
85 | def translate(self, value, topython=True):
86 | if topython:
87 | if isinstance(value, basestring) and len(value):
88 | return int(value)
89 | else:
90 | return None
91 | else:
92 | if isinstance(value, int):
93 | return str(value)
94 | else:
95 | return value
96 |
97 | class XLong(XBuiltin):
98 | """
99 | Represents an (xsd) xs:long builtin type.
100 | """
101 |
102 | def translate(self, value, topython=True):
103 | if topython:
104 | if isinstance(value, basestring) and len(value):
105 | return long(value)
106 | else:
107 | return None
108 | else:
109 | if isinstance(value, (int,long)):
110 | return str(value)
111 | else:
112 | return value
113 |
114 |
115 | class XFloat(XBuiltin):
116 | """
117 | Represents an (xsd) xs:float builtin type.
118 | """
119 |
120 | def translate(self, value, topython=True):
121 | if topython:
122 | if isinstance(value, basestring) and len(value):
123 | return float(value)
124 | else:
125 | return None
126 | else:
127 | if isinstance(value, float):
128 | return str(value)
129 | else:
130 | return value
131 |
132 |
133 | class XDate(XBuiltin):
134 | """
135 | Represents an (xsd) xs:date builtin type.
136 | """
137 |
138 | def translate(self, value, topython=True):
139 | if topython:
140 | if isinstance(value, basestring) and len(value):
141 | return Date(value).date
142 | else:
143 | return None
144 | else:
145 | if isinstance(value, dt.date):
146 | return str(Date(value))
147 | else:
148 | return value
149 |
150 |
151 | class XTime(XBuiltin):
152 | """
153 | Represents an (xsd) xs:time builtin type.
154 | """
155 |
156 | def translate(self, value, topython=True):
157 | if topython:
158 | if isinstance(value, basestring) and len(value):
159 | return Time(value).time
160 | else:
161 | return None
162 | else:
163 | if isinstance(value, dt.date):
164 | return str(Time(value))
165 | else:
166 | return value
167 |
168 |
169 | class XDateTime(XBuiltin):
170 | """
171 | Represents an (xsd) xs:datetime builtin type.
172 | """
173 |
174 | def translate(self, value, topython=True):
175 | if topython:
176 | if isinstance(value, basestring) and len(value):
177 | return DateTime(value).datetime
178 | else:
179 | return None
180 | else:
181 | if isinstance(value, dt.date):
182 | return str(DateTime(value))
183 | else:
184 | return value
185 |
186 |
187 | class Factory:
188 |
189 | tags =\
190 | {
191 | # any
192 | 'anyType' : XAny,
193 | # strings
194 | 'string' : XString,
195 | 'normalizedString' : XString,
196 | 'ID' : XString,
197 | 'Name' : XString,
198 | 'QName' : XString,
199 | 'NCName' : XString,
200 | 'anySimpleType' : XString,
201 | 'anyURI' : XString,
202 | 'NOTATION' : XString,
203 | 'token' : XString,
204 | 'language' : XString,
205 | 'IDREFS' : XString,
206 | 'ENTITIES' : XString,
207 | 'IDREF' : XString,
208 | 'ENTITY' : XString,
209 | 'NMTOKEN' : XString,
210 | 'NMTOKENS' : XString,
211 | # binary
212 | 'hexBinary' : XString,
213 | 'base64Binary' : XString,
214 | # integers
215 | 'int' : XInteger,
216 | 'integer' : XInteger,
217 | 'unsignedInt' : XInteger,
218 | 'positiveInteger' : XInteger,
219 | 'negativeInteger' : XInteger,
220 | 'nonPositiveInteger' : XInteger,
221 | 'nonNegativeInteger' : XInteger,
222 | # longs
223 | 'long' : XLong,
224 | 'unsignedLong' : XLong,
225 | # shorts
226 | 'short' : XInteger,
227 | 'unsignedShort' : XInteger,
228 | 'byte' : XInteger,
229 | 'unsignedByte' : XInteger,
230 | # floats
231 | 'float' : XFloat,
232 | 'double' : XFloat,
233 | 'decimal' : XFloat,
234 | # dates & times
235 | 'date' : XDate,
236 | 'time' : XTime,
237 | 'dateTime': XDateTime,
238 | 'duration': XString,
239 | 'gYearMonth' : XString,
240 | 'gYear' : XString,
241 | 'gMonthDay' : XString,
242 | 'gDay' : XString,
243 | 'gMonth' : XString,
244 | # boolean
245 | 'boolean' : XBoolean,
246 | }
247 |
248 | @classmethod
249 | def maptag(cls, tag, fn):
250 | """
251 | Map (override) tag => I{class} mapping.
252 | @param tag: An xsd tag name.
253 | @type tag: str
254 | @param fn: A function or class.
255 | @type fn: fn|class.
256 | """
257 | cls.tags[tag] = fn
258 |
259 | @classmethod
260 | def create(cls, schema, name):
261 | """
262 | Create an object based on the root tag name.
263 | @param schema: A schema object.
264 | @type schema: L{schema.Schema}
265 | @param name: The name.
266 | @type name: str
267 | @return: The created object.
268 | @rtype: L{XBuiltin}
269 | """
270 | fn = cls.tags.get(name)
271 | if fn is not None:
272 | return fn(schema, name)
273 | else:
274 | return XBuiltin(schema, name)
275 |
--------------------------------------------------------------------------------
/bin/suds/servicedefinition.py:
--------------------------------------------------------------------------------
1 | # This program is free software; you can redistribute it and/or modify
2 | # it under the terms of the (LGPL) GNU Lesser General Public License as
3 | # published by the Free Software Foundation; either version 3 of the
4 | # License, or (at your option) any later version.
5 | #
6 | # This program is distributed in the hope that it will be useful,
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Library Lesser General Public License for more details at
10 | # ( http://www.gnu.org/licenses/lgpl.html ).
11 | #
12 | # You should have received a copy of the GNU Lesser General Public License
13 | # along with this program; if not, write to the Free Software
14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 | # written by: Jeff Ortel ( jortel@redhat.com )
16 |
17 | """
18 | The I{service definition} provides a textual representation of a service.
19 | """
20 |
21 | from logging import getLogger
22 | from suds import *
23 | import suds.metrics as metrics
24 | from suds.sax import Namespace
25 |
26 | log = getLogger(__name__)
27 |
28 | class ServiceDefinition:
29 | """
30 | A service definition provides an object used to generate a textual description
31 | of a service.
32 | @ivar wsdl: A wsdl.
33 | @type wsdl: L{wsdl.Definitions}
34 | @ivar service: The service object.
35 | @type service: L{suds.wsdl.Service}
36 | @ivar ports: A list of port-tuple: (port, [(method-name, pdef)])
37 | @type ports: [port-tuple,..]
38 | @ivar prefixes: A list of remapped prefixes.
39 | @type prefixes: [(prefix,uri),..]
40 | @ivar types: A list of type definitions
41 | @type types: [I{Type},..]
42 | """
43 |
44 | def __init__(self, wsdl, service):
45 | """
46 | @param wsdl: A wsdl object
47 | @type wsdl: L{Definitions}
48 | @param service: A service B{name}.
49 | @type service: str
50 | """
51 | self.wsdl = wsdl
52 | self.service = service
53 | self.ports = []
54 | self.params = []
55 | self.types = []
56 | self.prefixes = []
57 | self.addports()
58 | self.paramtypes()
59 | self.publictypes()
60 | self.getprefixes()
61 | self.pushprefixes()
62 |
63 | def pushprefixes(self):
64 | """
65 | Add our prefixes to the wsdl so that when users invoke methods
66 | and reference the prefixes, the will resolve properly.
67 | """
68 | for ns in self.prefixes:
69 | self.wsdl.root.addPrefix(ns[0], ns[1])
70 |
71 | def addports(self):
72 | """
73 | Look through the list of service ports and construct a list of tuples where
74 | each tuple is used to describe a port and it's list of methods as:
75 | (port, [method]). Each method is tuple: (name, [pdef,..] where each pdef is
76 | a tuple: (param-name, type).
77 | """
78 | timer = metrics.Timer()
79 | timer.start()
80 | for port in self.service.ports:
81 | p = self.findport(port)
82 | for op in port.binding.operations.values():
83 | m = p[0].method(op.name)
84 | binding = m.binding.input
85 | method = (m.name, binding.param_defs(m))
86 | p[1].append(method)
87 | metrics.log.debug("method '%s' created: %s", m.name, timer)
88 | p[1].sort()
89 | timer.stop()
90 |
91 | def findport(self, port):
92 | """
93 | Find and return a port tuple for the specified port.
94 | Created and added when not found.
95 | @param port: A port.
96 | @type port: I{service.Port}
97 | @return: A port tuple.
98 | @rtype: (port, [method])
99 | """
100 | for p in self.ports:
101 | if p[0] == p: return p
102 | p = (port, [])
103 | self.ports.append(p)
104 | return p
105 |
106 | def getprefixes(self):
107 | """
108 | Add prefixes foreach namespace referenced by parameter types.
109 | """
110 | namespaces = []
111 | for l in (self.params, self.types):
112 | for t,r in l:
113 | ns = r.namespace()
114 | if ns[1] is None: continue
115 | if ns[1] in namespaces: continue
116 | if Namespace.xs(ns) or Namespace.xsd(ns):
117 | continue
118 | namespaces.append(ns[1])
119 | if t == r: continue
120 | ns = t.namespace()
121 | if ns[1] is None: continue
122 | if ns[1] in namespaces: continue
123 | namespaces.append(ns[1])
124 | i = 0
125 | namespaces.sort()
126 | for u in namespaces:
127 | p = self.nextprefix()
128 | ns = (p, u)
129 | self.prefixes.append(ns)
130 |
131 | def paramtypes(self):
132 | """ get all parameter types """
133 | for m in [p[1] for p in self.ports]:
134 | for p in [p[1] for p in m]:
135 | for pd in p:
136 | if pd[1] in self.params: continue
137 | item = (pd[1], pd[1].resolve())
138 | self.params.append(item)
139 |
140 | def publictypes(self):
141 | """ get all public types """
142 | for t in self.wsdl.schema.types.values():
143 | if t in self.params: continue
144 | if t in self.types: continue
145 | item = (t, t)
146 | self.types.append(item)
147 | tc = lambda x,y: cmp(x[0].name, y[0].name)
148 | self.types.sort(cmp=tc)
149 |
150 | def nextprefix(self):
151 | """
152 | Get the next available prefix. This means a prefix starting with 'ns' with
153 | a number appended as (ns0, ns1, ..) that is not already defined on the
154 | wsdl document.
155 | """
156 | used = [ns[0] for ns in self.prefixes]
157 | used += [ns[0] for ns in self.wsdl.root.nsprefixes.items()]
158 | for n in range(0,1024):
159 | p = 'ns%d'%n
160 | if p not in used:
161 | return p
162 | raise Exception('prefixes exhausted')
163 |
164 | def getprefix(self, u):
165 | """
166 | Get the prefix for the specified namespace (uri)
167 | @param u: A namespace uri.
168 | @type u: str
169 | @return: The namspace.
170 | @rtype: (prefix, uri).
171 | """
172 | for ns in Namespace.all:
173 | if u == ns[1]: return ns[0]
174 | for ns in self.prefixes:
175 | if u == ns[1]: return ns[0]
176 | raise Exception('ns (%s) not mapped' % u)
177 |
178 | def xlate(self, type):
179 | """
180 | Get a (namespace) translated I{qualified} name for specified type.
181 | @param type: A schema type.
182 | @type type: I{suds.xsd.sxbasic.SchemaObject}
183 | @return: A translated I{qualified} name.
184 | @rtype: str
185 | """
186 | resolved = type.resolve()
187 | name = resolved.name
188 | if type.unbounded():
189 | name += '[]'
190 | ns = resolved.namespace()
191 | if ns[1] == self.wsdl.tns[1]:
192 | return name
193 | prefix = self.getprefix(ns[1])
194 | return ':'.join((prefix, name))
195 |
196 | def description(self):
197 | """
198 | Get a textual description of the service for which this object represents.
199 | @return: A textual description.
200 | @rtype: str
201 | """
202 | s = []
203 | indent = (lambda n : '\n%*s'%(n*3,' '))
204 | s.append('Service ( %s ) tns="%s"' % (self.service.name, self.wsdl.tns[1]))
205 | s.append(indent(1))
206 | s.append('Prefixes (%d)' % len(self.prefixes))
207 | for p in self.prefixes:
208 | s.append(indent(2))
209 | s.append('%s = "%s"' % p)
210 | s.append(indent(1))
211 | s.append('Ports (%d):' % len(self.ports))
212 | for p in self.ports:
213 | s.append(indent(2))
214 | s.append('(%s)' % p[0].name)
215 | s.append(indent(3))
216 | s.append('Methods (%d):' % len(p[1]))
217 | for m in p[1]:
218 | sig = []
219 | s.append(indent(4))
220 | sig.append(m[0])
221 | sig.append('(')
222 | for p in m[1]:
223 | sig.append(self.xlate(p[1]))
224 | sig.append(' ')
225 | sig.append(p[0])
226 | sig.append(', ')
227 | sig.append(')')
228 | try:
229 | s.append(''.join(sig))
230 | except:
231 | pass
232 | s.append(indent(3))
233 | s.append('Types (%d):' % len(self.types))
234 | for t in self.types:
235 | s.append(indent(4))
236 | s.append(self.xlate(t[0]))
237 | s.append('\n\n')
238 | return ''.join(s)
239 |
240 | def __str__(self):
241 | return unicode(self).encode('utf-8')
242 |
243 | def __unicode__(self):
244 | try:
245 | return self.description()
246 | except Exception, e:
247 | log.exception(e)
248 | return tostr(e)
--------------------------------------------------------------------------------