github
Advanced Search
  • Home
  • Pricing and Signup
  • Explore GitHub
  • Blog
  • Login

directededge / directed-edge-bindings

  • Admin
  • Watch Unwatch
  • Fork
  • Your Fork
  • Pull Request
  • Download Source
    • 24
    • 2
  • Source
  • Commits
  • Network (2)
  • Issues (0)
  • Downloads (0)
  • Wiki (1)
  • Graphs
  • Tree: bc59e7e

click here to add a description

click here to add a homepage

  • Branches (5)
    • database_add_method
    • linktypes
    • master
    • related_threshold
    • tweetrex
  • Tags (0)
Sending Request…
Enable Donations

Pledgie Donations

Once activated, we'll place the following badge in your repository's detail box:
Pledgie_example
This service is courtesy of Pledgie.

Open Source bindings to the Directed Edge webservices API — Read more

  cancel

http://www.directededge.com/

  cancel
  • Private
  • Read-Only
  • HTTP Read-Only

This URL has Read+Write access

Add some docs. 
directededge (author)
Tue Jul 28 09:30:32 -0700 2009
commit  bc59e7e4b7aeef93af2d0bab825160b0b75f320d
tree    bc23bccf65d54c50bc643e49c7570da0a2cdb53d
parent  c77c657dc47872374af8cb46e112e8a5639e979e
directed-edge-bindings / Python / directed_edge.py Python/directed_edge.py
100644 309 lines (241 sloc) 11.303 kb
edit raw blame history
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
# Copyright (C) 2009 Directed Edge Ltd.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
import os
import urllib
import urllib2
import httplib2
import xml.dom.minidom
from sets import Set
 
class Resource:
    """REST resource used in the Directed Edge API"""
 
    def __init__(self, base_url, user=None, password=None):
        self.__base_url = base_url
        self.__http = httplib2.Http()
        if user:
            self.__http.add_credentials(user, password)
 
    def path(self, sub="", params={}):
        return self.__base_url + "/" + urllib2.quote(sub) + "?" + urllib.urlencode(params)
 
    def get(self, sub="", params={}):
        response, content = self.__http.request(self.path(sub, params), "GET")
        if response["status"] != "200":
            return "<directededge/>"
        return content
 
    def put(self, data, sub="", params={}):
        response, content = self.__http.request(self.path(sub, params), "PUT", data)
 
class Database:
    """A database on the Directed Edge server"""
 
    def __init__(self, name, password="", protocol="http"):
        if "DIRECTEDEDGE_HOST" in os.environ.keys():
            host = os.environ["DIRECTEDEDGE_HOST"]
        else:
            host = "webservices.directededge.com"
        self.name = name
        self.resource = Resource("http://%s/api/v1/%s" % (host, name), name, password)
 
    def import_from_file(self, file_name):
        file = open(file_name, "r")
        data = file.read()
        self.resource.put(data)
 
class Item:
    """An item in a Directed Edge database
 
There are of a collection of methods here for reading and writing to items.
In general as few reads from the remote database as required will be used,
specifically items cache all values when any of them are read and writes
will not be made to the remote database until save() is called."""
 
    def __init__(self, database, id):
        self.database = database
        self.id = id
 
        self.__links = {}
        self.__tags = Set()
        self.__properties = {}
 
        self.__links_to_remove = Set()
        self.__tags_to_remove = Set()
        self.__properties_to_remove = Set()
 
        self.__cached = False
        
    def name(self):
        """The ID of the item used to identify it in the database."""
 
        return self.id
 
    def links(self):
        """A dict mapping from link-names to link-weights."""
 
        self.__read()
        return self.__links
 
    def tags(self):
        """The list of tags for the item."""
 
        self.__read()
        return self.__tags
 
    def properties(self):
        """A dict of key-value pair associated with this item."""
 
        self.__read()
        return self.__properties
 
    def link_to(self, other, weight=0):
        """Links this item to another item with the given weight.
 
"Other" can be either another item object or the (string) ID of a second
item.
 
The default weight is 0, which indicates an unweighted link."""
 
        if isinstance(other, Item):
            other = other.name()
        self.__links[other] = weight
        if other in self.__links_to_remove:
            del self.__links_to_remove[other]
 
    def unlink_from(self, other):
        """Removes a link from this item to "other", also may be an Item or string."""
 
        if isinstance(other, Item):
            other = other.name()
        if self.__cached:
            if other in self.__links:
                del self.__links[other]
        else:
            self.__links_to_remove.add(other)
 
    def weight_for(self, link):
        """The corresponding weight for the given link, or 0 if there is no weight."""
 
        self.__read()
        if isinstance(link, Item):
            link = link.name()
        return self.__links[link]
 
    def add_tag(self, tag):
        self.__tags.add(tag)
        self.__tags_to_remove.discard(tag)
 
    def remove_tag(self, tag):
        if self.__cached:
            self.__tags.discard(tag)
        else:
            self.__tags_to_remove.add(tag)
 
    def __setitem__(self, key, value):
        """May be used to set properties for the item via item["foo"] = "bar"."""
 
        self.__properties[key] = value
        self.__properties_to_remove.discard(key)
 
    def __getitem__(self, key):
        """May be used to read properties from the item via item["foo"]."""
 
        self.__read()
        return self.__properties[key]
 
    def has_property(self, key):
        self.__read()
        return self.__properties.has_key(key)
 
    def clear_property(self, key):
        if not self.__cached:
            self.__properties_to_remove.add(key)
        if self.__properties.has_key(key):
            del self.__properties[key]
 
    def get_property(self, key):
        self.__read()
        if not self.has_property(key):
            return None
        return self.__properties[key]
 
    def related(self, tags=[], max_results=20):
        """Returns a list of up to max_results related items.
 
Items matching any of the given tags may be returned."""
 
        return self.__read_list(self.__document("related",
                                                { "tags" : ",".join(Set(tags)),
                                                  "maxResults" : max_results }), "related")
 
    def recommended(self, tags=[], max_results=20):
        """Returns a list of up to max_results recommended items.
 
Items matching any of the given tags may be returned."""
 
        return self.__read_list(self.__document("recommended",
                                                { "excludeLinked" : "true",
                                                  "tags" : ",".join(Set(tags)),
                                                  "maxResults" : max_results }), "recommended")
 
    def to_xml(self, tags=None, links=None, properties=None, include_document=True):
        if not tags:
            tags = self.__tags
        if not links:
            links = self.__links
        if not properties:
            properties = self.__properties
 
        implementation = xml.dom.minidom.getDOMImplementation()
        document = implementation.createDocument(None, "directededge", None)
        document.documentElement.setAttribute("version", "0.1")
        item_element = document.createElement("item")
        item_element.setAttribute("id", self.id)
 
        for tag in tags:
            tag_element = document.createElement("tag")
            item_element.appendChild(tag_element)
            tag_element.appendChild(document.createTextNode(tag))
 
        for link in links:
            link_element = document.createElement("link")
            item_element.appendChild(link_element)
            if self.__links[link] > 0:
                link_element.setAttribute("weight", str(links[link]))
            link_element.appendChild(document.createTextNode(link))
 
        for property in properties:
            property_element = document.createElement("property")
            item_element.appendChild(property_element)
            property_element.setAttribute("name", property)
            property_element.appendChild(document.createTextNode(properties[property]))
 
        document.documentElement.appendChild(item_element)
 
        if include_document:
            return document.toxml("utf-8")
        else:
            return item_element.toxml("utf-8")
 
    def save(self):
        """Writes any local changes to the item back to the remote database."""
 
        if self.__cached:
            self.database.resource.put(self.to_xml(), self.id)
        else:
            if self.__links or self.__tags or self.__properties:
                self.database.resource.put(self.to_xml(), self.id + "/add")
            if self.__links_to_remove or self.__tags_to_remove or self.__properties_to_remove:
                to_dict = lambda list, default: dict(map(lambda x: [x, default], list))
                self.database.resource.put(self.to_xml(self.__tags_to_remove,
                                                       to_dict(self.__links_to_remove, 0),
                                                       to_dict(self.__properties_to_remove, "")),
                                           self.id + "/remove")
 
                self.__links_to_remove.clear()
                self.__tags_to_remove.clear()
                self.__properties_to_remove.clear()
 
    def __read(self):
        if not self.__cached:
            document = self.__document()
 
            for node in document.getElementsByTagName("link"):
                name = node.firstChild.data
                weight = 0
                if node.attributes.has_key("weight"):
                    weight = int(node.attributes["weight"].value)
                if name not in self.__links:
                    self.__links[name] = weight
 
            self.__tags.update(self.__read_list(document, "tag"))
 
            for node in document.getElementsByTagName("property"):
                name = node.attributes["name"].value
                if name not in self.__properties:
                    self.__properties[name] = node.firstChild.data
 
            self.__cached = True
 
    def __document(self, sub="", params={}):
        content = self.database.resource.get(self.id + "/" + sub, params)
        return xml.dom.minidom.parseString(content)
 
    def __read_list(self, document, element_name):
        values = []
        for node in document.getElementsByTagName(element_name):
            values.append(node.firstChild.data)
        return values
 
class Exporter:
    """A simple tool to export items to an XML file"""
    def __init__(self, file_name):
        self.__database = Database("export")
        self.__file = open(file_name, "w")
        self.__file.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n")
        self.__file.write("<directededge version=\"0.1\">\n")
 
    def database(self):
        return self.__database
 
    def export(self, item):
        self.__file.write(item.to_xml(None, None, None, False) + "\n")
 
    def finish(self):
        self.__file.write("</directededge>\n")
        self.__file.close()
 
Blog | Support | Training | Contact | API | Status | Twitter | Help | Security
© 2010 GitHub Inc. All rights reserved. | Terms of Service | Privacy Policy
Powered by the Dedicated Servers and
Cloud Computing of Rackspace Hosting®
Dedicated Server