2 #author: Bryan Bishop <kanzure@gmail.com>
5 #purpose: an attempt at implementing the octopart api v2
6 #url: http://octopart.com/api/documentation
7 #skdb api key: 476188c7
12 from urllib
import urlencode
13 from StringIO
import StringIO
15 octopart_api_key
= "476188c7"
16 bryan_message
= "bryan hasn't got this far yet"
19 '''a wrapper to Octopart.com'''
20 timeout
= 15 #dunno what to put here (seconds)
21 base_url
= "http://octopart.com/api/v2/"
22 filters
= "case_package, category_id, color, conductor_material, contact_material, contacts_type, dielectric_material, flammability_rating, gender, glow_wire_compliant, halogen_free_status, housing_color, housing_material, insulation_material, jacket_material, lead_free_status, lens_color, lens_type, lifecycle_status, logic_type, manufacturer, material, mounting_type, orientation, packaging, polarity, processor_type, rohs, shielding, shrouded, supplier, termination_style, thermal_shutdown"
23 ranged_filters
= "access_time, avg_authavail, avg_authprice, avg_avail, avg_price, breakdown_voltage, cable_length, capacitance, carry_current, character_size_height, clock_speed, coil_resistance, contact_resistance, cord_length, current_rating, data_rate, dropout_voltage, equivalent_series_resistance_esr, forward_voltage, frequency, gain, inductance, input_bias_current, input_current, input_power, input_voltage_dc, load_capacitance, luminous_intensity, mated_height, number_of_channels, number_of_circuits, number_of_conductors, number_of_detents, number_of_gates, number_of_i_o_pins, number_of_outlets, number_of_outputs, number_of_pins, number_of_positions, number_of_rows, operating_temperature, output_current, output_power, output_voltage, peak_wavelength, pin_pitch, power_consumption, power_rating, q_factor, quiescent_current, resistance, resistance_tolerance, sample_rate, size_diameter, size_height, size_inner_diameter, size_length, size_thickness, size_width, slew_rate, supply_voltage_dc, switching_current, switching_frequency, switching_voltage, temperature_coefficient, threshold_voltage, voltage_rating_ac, voltage_rating_dc, voltage_rating_transient, wavelength, weight"
24 def __init__(self
, api_key
=None):
25 self
.api_key
= api_key
26 def web_fetch(self
, url
):
29 curl
.setopt(curl
.URL
, url
)
30 curl
.setopt(curl
.TIMEOUT
, self
.timeout
)
31 curl
.setopt(curl
.WRITEFUNCTION
, buffer.write
)
34 response
= buffer.getvalue().strip()
36 def get_categories(self
, id=4179, attach_ancestors
=0):
37 if isinstance(id, list):
38 specific_url
= "categories/get_multi"
39 #url: http://octopart.com/api/v2/categories/get_multi?ids=[5432,692,2344]
41 else: #it's just a single number
42 specific_url
= "categories/get"
43 #url: http://octopart.com/api/v2/categories/get?id=533642
47 attach_ancestors
= str(attach_ancestors
)
49 url
= self
.base_url
+ specific_url
+ "?" + id_variable
+ "=" + id + "&attach_ancestors=" + attach_ancestors
+ "&apikey=" + self
.api_key
50 response_json
= self
.web_fetch(url
)
53 #The response is a list of category objects that match the ids requested.
54 #If a match is not found for a given id, the response will not include that object.
55 #In other words, if no categories are found the reponse will be an empty list.
56 #raise NotImplementedError, bryan_message
58 return simplejson
.loads(response_json
)
59 def get_whitepapers(self
, id):
60 '''returns a whitepaper object
61 id: the whitepaper object id'''
62 if isinstance(id, list):
63 specific_url
= "whitepapers/get_multi"
64 #url: http://octopart.com/api/v2/whitepapers/get_multi
67 specific_url
= "whitepapers/get"
68 #url: http://octopart.com/api/v2/whitepapers/get
72 url
= self
.base_url
+ specific_url
+ "?" + id_variable
+ "=" + id
73 response_json
= self
.web_fetch(url
)
77 #url: http://octopart.com/api/documentation#whitepaper
79 return simplejson
.loads(response_json
)
80 def search_categories(self
, query
="", start
=0, limit
=10, ancestor_id
=None, attach_ancestors
=0):
81 '''query: query string (optional)
82 start: ordinal position of the first result (default is 0)
83 limit: maximum number of results to return (default is 10)
84 ancestor_id: if specified, limit search to all descendants of the specified ancestor (optional)
85 attach_ancestors: if specified, attach ancestors to category objects (optional)'''
86 specific_url
= "categories/search"
88 if not ancestor_id
: ancestor_id
= ""
89 if not attach_ancestors
: anttach_ancestors
= ""
92 ancestor_id
= str(ancestor_id
)
93 attach_ancestors
= str(attach_ancestors
)
95 url
= self
.base_url
+ specific_url
+ "?" + "q=" + query
+ "&start=" + start
+ "&limit=" + limit
+ "&ancestor_id=" + ancestor_id
+ "&attach_ancestors=" + attach_ancestors
+ "&apikey=" + self
.api_key
96 response_json
= self
.web_fetch(url
)
99 # * results[]{} - The sorted list of matched items
100 # o item{} - A matched category object
101 # o highlight - A short snippet of text highlighting matched keywords
102 # * request{} - The request parameters (from the arguments above)
107 # * hits - The total number of matched objects
108 # * time - The amount of time it took to process the entire request (in seconds)
109 return simplejson
.loads(response_json
)
110 def search_parts(self
, query
="", start
=0, limit
=10, filters
=None, ranged_filters
=None, sort_by
=None):
111 '''query: query string (optional)
112 start: ordinal position of the first result (default is 0, max is 1000)
113 limit: number of results to return (default is 10, maximum is 100)
114 filter: JSON encoded list of (fieldname, values) pairs (optional)
115 example: filters=[["color",["Red"]], ["material",["Tantalum","Ceramic"]]]
116 ranged_filters: JSON encoded list of (fieldname, min/max values) pairs, using null as wildcard. (optional)
117 example: ranged_filters=[["resistance",[[100,1000],[2000,null]]]]
118 sort_by: JSON encoded list of (fieldname,sort-order) pairs, default is [["score","desc"]] (optional)
119 example: sort_by=[["resistance","desc"],["avg_price","asc"]]'''
120 specific_url
= "parts/search"
122 #some preliminary checks
123 if start
< 0: raise ValueError, "Octopart.search_parts: start must be greater than 0"
124 if start
> 1000: raise ValueError, "Octopart.search_parts: start must be less than or equal to 1000"
125 if limit
<= 0: limit
= 100 #set it to the maximum
126 if limit
> 100: raise ValueError, "Octopart.search_parts: limit must be between 0 and 100 (inclusive)"
127 if not query
: query
= ""
128 if not filters
: filters
= ""
129 if not ranged_filters
: ranged_filters
= ""
130 if not sort_by
: sort_by
= ""
135 url
= self
.base_url
+ specific_url
+ "?" + "q=" + query
+ "&start=" + start
+ "&apikey=" + self
.api_key
136 #do not include filters and rangedfilters if they aren't available
137 if ranged_filters
!= "": url
= url
+ "&rangedfilters=" + ranged_filters
138 if filters
!= "": url
= url
+ "&filters=" + filters
139 if sort_by
!= "": url
= url
+ "&sortby=" + sort_by
141 response_json
= self
.web_fetch(url
)
142 response
= simplejson
.loads(response_json
)
145 # * results[]{} - The sorted list of matched items
146 # o item{} - A matched part object
147 # o highlight - A short snippet of text highlighting matched keywords
148 # * request{} - The request parameters (from the arguments above)
155 # * hits - The total number of matched objects
156 # * time - The amount of time it took to process the entire request (in seconds)
157 hits
= response
["hits"]
158 time
= response
["time"] #in seconds
160 for part
in response
["results"]:
163 for attribute
in part
["specs"]:
164 specs
[attribute
["attribute"]["fieldname"]] = attribute
["values"]
165 print "part id: ", part
["id"]
168 print "\t" + spec
+ "\t" + str(specs
[spec
])
171 def search_whitepapers(self
, query
="", start
=0, limit
=10):
172 '''execute a search over all whitepapers
173 query: query string (optional)
174 start: ordinal position of the first result where the first position is 0 (default is 0, max is 1000) (optional)
175 limit: maximum number of results to return (default is 10, max is 100) (optional)
177 specific_url
= "whitepapers/search"
179 #some preliminary checks
180 if start
<0: raise ValueError, "Octopart.search_whitepapers: start must be greater than or equal to 0"
181 if start
>1000: raise ValueError, "Octopart.search_whitepapers: start must be less than or equal to 1000"
184 url
= self
.base_url
+ specific_url
+ "?q=" + query
+ "&start=" + start
+ "&limit=" + limit
+ "&apikey=" + self
.api_key
185 response_json
= self
.web_fetch(url
)
188 # * results[]{} - The sorted list of matched items
189 # o item{} - A matched whitepaper object
190 # o highlight - A short snippet of text highlighting matched keywords
191 # * request{} - The request parameters (from the arguments above)
195 # * hits - The total number of matched objects
196 # * time - The amount of time it took to process the entire request (in seconds)
197 return simplejson
.loads(response_json
)
198 def suggest_part_query(self
, query
, limit
=1):
199 '''suggest a part search query string, optimized for speed and useful for auto-complete features
200 query: query string with minimum length of 2 characters (required)
201 limit: maximum number of results to return (default is 10, max is 10)
203 specific_url
= "parts/suggest"
205 #some preliminary checks
206 if len(query
)<2: raise ValueError, "Octopart.suggest_part_query: length of query string must be at least 2 characters"
207 if limit
>10 or limit
<1: raise ValueError, "Octopart.suggest_part_query: limit must be between 1 and 10"
210 url
= self
.base_url
+ specific_url
+ "?q=" + query
+ "&limit=" + limit
+ "&apikey=" + self
.api_key
211 response_json
= self
.web_fetch(url
)
214 # * results[] - The sorted list of search suggestions
215 # * request{} - The request parameters (from the arguments above)
218 # * hits - The total number of matched suggestions
219 # * time - The amount of time it took to process the entire request (in seconds)
220 return simplejson
.loads(response_json
)
222 def octopart_search(query
):
223 '''searches octopart with the string'''
224 octopart
= Octopart(octopart_api_key
)
225 #categories = octopart.get_categories(id=4179)
226 #print "categories: %s" % (categories)
227 parts
= octopart
.search_parts(query
=query
, limit
=1)
228 #print "parts: %s" % (parts)
231 class OctopartTests(unittest
.TestCase
):
232 def test_octopart_get_category(self
):
233 octopart
= Octopart(octopart_api_key
)
234 categories
= octopart
.get_category(id=4179)
237 if __name__
== "__main__":
238 optfunc
.run(octopart_search
)