1"""Example usage of pyUSPTO for patent application search and retrieval.
2
3Demonstrates the PatentDataClient for searching applications, retrieving metadata,
4downloading documents, and exporting CSV.
5"""
6
7import json
8import os
9
10from pyUSPTO import ApplicationContinuityData, PatentDataClient, USPTOConfig
11
12DEST_PATH = "./notes/download-example"
13
14# --- Client Initialization ---
15api_key = os.environ.get("USPTO_API_KEY", "YOUR_API_KEY_HERE")
16if api_key == "YOUR_API_KEY_HERE":
17 raise ValueError(
18 "API key is not set. Set the USPTO_API_KEY environment variable."
19 )
20config = USPTOConfig(api_key=api_key)
21client = PatentDataClient(config=config)
22
23print("-" * 40)
24print("Example 1: Default search")
25print("-" * 40)
26
27response = client.search_applications(limit=5)
28print(
29 f"Found {response.count} total patent applications matching default/broad criteria."
30)
31print(
32 f"Displaying first {len(response.patent_file_wrapper_data_bag)} applications from response:"
33)
34
35for patent_wrapper in response.patent_file_wrapper_data_bag:
36 app_meta = patent_wrapper.application_meta_data
37 if app_meta:
38 print(f"\n Application: {patent_wrapper.application_number_text}")
39 print(f" Title: {app_meta.invention_title}")
40 print(f" Status: {app_meta.application_status_description_text}")
41 print(f" Filing Date: {app_meta.filing_date}")
42
43 if app_meta.patent_number:
44 print(f" Patent Number: {app_meta.patent_number}")
45 print(f" Grant Date: {app_meta.grant_date}")
46
47 if app_meta.inventor_bag:
48 print(" Inventors:")
49 for inventor in app_meta.inventor_bag:
50 name_parts = [
51 part
52 for part in [inventor.first_name, inventor.last_name]
53 if part
54 ]
55 print(f" - {' '.join(name_parts).strip()}")
56 if inventor.correspondence_address_bag:
57 address = inventor.correspondence_address_bag[0]
58 if address.city_name and address.geographic_region_code:
59 print(
60 f" ({address.city_name}, {address.geographic_region_code})"
61 )
62
63 if app_meta.applicant_bag:
64 print(" Applicants:")
65 for applicant in app_meta.applicant_bag:
66 print(f" - {applicant.applicant_name_text}")
67
68# Export results to CSV
69if response.count > 0:
70 print("\nGenerating CSV for the current response:")
71 csv_data = response.to_csv()
72 csv_path = os.path.join(DEST_PATH, "patent_search_results.csv")
73 os.makedirs(DEST_PATH, exist_ok=True)
74 with open(csv_path, "w", newline="", encoding="utf-8") as f:
75 f.write(csv_data)
76 print(f"Full CSV data saved to {csv_path}.")
77
78print("-" * 40)
79print("Example 2: Search by inventor name")
80print("-" * 40)
81
82inventor_search_response = client.search_applications(
83 inventor_name_q="Smith", limit=2
84)
85print(
86 f"Found {inventor_search_response.count} patents with 'Smith' as inventor (showing up to 2)."
87)
88for patent_wrapper in inventor_search_response.patent_file_wrapper_data_bag:
89 if patent_wrapper.application_meta_data:
90 print(
91 f" - App No: {patent_wrapper.application_number_text}, Title: {patent_wrapper.application_meta_data.invention_title}"
92 )
93
94print("-" * 40)
95print("Example 3: Search by filing date range")
96print("-" * 40)
97
98date_search_response = client.search_applications(
99 filing_date_from_q="2020-01-01", filing_date_to_q="2020-12-31", limit=2
100)
101print(
102 f"Found {date_search_response.count} patents filed in 2020 (showing up to 2)."
103)
104for patent_wrapper in date_search_response.patent_file_wrapper_data_bag:
105 if patent_wrapper.application_meta_data:
106 print(
107 f" - App No: {patent_wrapper.application_number_text}, Filing Date: {patent_wrapper.application_meta_data.filing_date}"
108 )
109
110print("-" * 40)
111print("Example 4: Get application by number")
112print("-" * 40)
113
114app_no_to_fetch = "18045436"
115print(f"Retrieving patent application: {app_no_to_fetch}")
116patent_wrapper_detail = client.get_application_by_number(
117 application_number=app_no_to_fetch
118)
119if patent_wrapper_detail:
120 print(
121 f"Successfully retrieved: {patent_wrapper_detail.application_number_text}"
122 )
123 if patent_wrapper_detail.application_meta_data:
124 print(
125 f"Title: {patent_wrapper_detail.application_meta_data.invention_title}"
126 )
127
128 print("\nRetrieving document information...")
129 documents_bag = client.get_application_documents(
130 application_number=app_no_to_fetch
131 )
132 print(f"Found {len(documents_bag)} documents for application {app_no_to_fetch}")
133
134 if documents_bag.documents:
135 document_to_download = documents_bag.documents[0]
136 print("\nFirst document details:")
137 print(f" Document ID: {document_to_download.document_identifier}")
138 print(
139 f" Document Type: {document_to_download.document_code} - {document_to_download.document_code_description_text}"
140 )
141 print(f" Date: {document_to_download.official_date}")
142 print(f" Direction: {document_to_download.direction_category}")
143
144 if (
145 document_to_download.document_formats
146 and document_to_download.document_identifier
147 ):
148 print("\nDownloading first PDF document...")
149 print(json.dumps(document_to_download.to_dict(), indent=2))
150 downloaded_path = client.download_document(
151 document=document_to_download,
152 format="PDF",
153 destination=DEST_PATH,
154 overwrite=True,
155 )
156 print(f"Downloaded document to: {downloaded_path}")
157 else:
158 print(
159 "No downloadable formats available for the first document or document identifier missing."
160 )
161 else:
162 print("No documents listed for this application.")
163
164 # Download publication XML (grant or pgpub)
165 print("\nChecking for publication files (grant/pgpub XML)...")
166 if patent_wrapper_detail.grant_document_meta_data:
167 grant_metadata = patent_wrapper_detail.grant_document_meta_data
168 print(f"Grant document available: {grant_metadata.xml_file_name}")
169 print(f" Product: {grant_metadata.product_identifier}")
170 print(f" Created: {grant_metadata.file_create_date_time}")
171
172 print("\nDownloading grant XML...")
173 grant_path = client.download_publication(
174 printed_metadata=grant_metadata,
175 destination=DEST_PATH,
176 overwrite=True,
177 )
178 print(f"Downloaded grant XML to: {grant_path}")
179
180 if patent_wrapper_detail.pgpub_document_meta_data:
181 pgpub_metadata = patent_wrapper_detail.pgpub_document_meta_data
182 print(f"\nPre-grant publication available: {pgpub_metadata.xml_file_name}")
183
184 pgpub_path = client.download_publication(
185 printed_metadata=pgpub_metadata,
186 file_name="my_pgpub.xml",
187 destination=DEST_PATH,
188 overwrite=True,
189 )
190 print(f"Downloaded pgpub XML to: {pgpub_path}")
191
192 if patent_wrapper_detail.assignment_bag:
193 print("\nAssignments:")
194 for assignment in patent_wrapper_detail.assignment_bag:
195 for assignee in assignment.assignee_bag:
196 print(
197 f" - {assignee.assignee_name_text} (Recorded: {assignment.assignment_recorded_date})"
198 )
199 print(f" Conveyance: {assignment.conveyance_text}")
200else:
201 print(f"Could not retrieve details for application {app_no_to_fetch}")
202
203print("-" * 40)
204print("Example 5: Search by patent number")
205print("-" * 40)
206
207target_patent_number = "10000000"
208print(f"Searching for patent US {target_patent_number} B2...")
209patent_search_response = client.search_applications(
210 patent_number_q=target_patent_number, limit=1
211)
212
213if (
214 patent_search_response.count > 0
215 and patent_search_response.patent_file_wrapper_data_bag
216):
217 found_patent_wrapper = patent_search_response.patent_file_wrapper_data_bag[0]
218 if (
219 found_patent_wrapper.application_meta_data
220 and found_patent_wrapper.application_meta_data.patent_number
221 ):
222 print(
223 f"Retrieved patent: US {found_patent_wrapper.application_meta_data.patent_number}"
224 )
225 else:
226 print(
227 f"Retrieved patent application: {found_patent_wrapper.application_number_text}"
228 )
229
230 if found_patent_wrapper.patent_term_adjustment_data:
231 pta = found_patent_wrapper.patent_term_adjustment_data
232 print(f"Patent Term Adjustment: {pta.adjustment_total_quantity} days")
233 if pta.a_delay_quantity is not None:
234 print(f" A Delay: {pta.a_delay_quantity} days")
235 if pta.b_delay_quantity is not None:
236 print(f" B Delay: {pta.b_delay_quantity} days")
237 if pta.c_delay_quantity is not None:
238 print(f" C Delay: {pta.c_delay_quantity} days")
239 if pta.applicant_day_delay_quantity is not None:
240 print(f" Applicant Delay: {pta.applicant_day_delay_quantity} days")
241
242 continuity_data = ApplicationContinuityData.from_wrapper(
243 wrapper=found_patent_wrapper
244 )
245 if continuity_data.parent_continuity_bag:
246 print("\nParent Applications:")
247 for p_continuity in continuity_data.parent_continuity_bag:
248 print(f" - App No: {p_continuity.parent_application_number_text}")
249 print(
250 f" Type: {p_continuity.claim_parentage_type_code_description_text}"
251 )
252 print(f" Filing Date: {p_continuity.parent_application_filing_date}")
253
254 if continuity_data.child_continuity_bag:
255 print("\nChild Applications:")
256 for c_continuity in continuity_data.child_continuity_bag:
257 print(f" - App No: {c_continuity.child_application_number_text}")
258 print(
259 f" Type: {c_continuity.claim_parentage_type_code_description_text}"
260 )
261 print(f" Filing Date: {c_continuity.child_application_filing_date}")
262else:
263 print(f"No patents found with patent number: {target_patent_number}")
264
265print("-" * 40)
266print("Example 6: POST search")
267print("-" * 40)
268
269print("POST search for applications with 'AI' in title...")
270post_search_body = {
271 "q": "applicationMetaData.inventionTitle:AI",
272 "pagination": {"offset": 0, "limit": 2},
273}
274post_response = client.search_applications(post_body=post_search_body)
275print(
276 f"Found {post_response.count} applications via POST search (showing up to 2)."
277)
278for patent_wrapper in post_response.patent_file_wrapper_data_bag:
279 if patent_wrapper.application_meta_data:
280 print(
281 f" - App No: {patent_wrapper.application_number_text}, Title: {patent_wrapper.application_meta_data.invention_title}"
282 )
283
284print("-" * 40)
285print("Example 7: Search by CPC classification")
286print("-" * 40)
287
288# CPC codes containing spaces or slashes are automatically quoted for the Lucene query.
289print("Searching by CPC classification code 'H10D 64/667'...")
290cpc_response = client.search_applications(classification_q="H10D 64/667", limit=3)
291print(f"Found {cpc_response.count} applications with CPC code H10D 64/667.")
292for patent_wrapper in cpc_response.patent_file_wrapper_data_bag:
293 app_meta = patent_wrapper.application_meta_data
294 if app_meta:
295 print(
296 f" - App No: {patent_wrapper.application_number_text}, Title: {app_meta.invention_title}"
297 )
298 if app_meta.cpc_classification_bag:
299 print(f" CPC codes: {', '.join(app_meta.cpc_classification_bag)}")
300
301print("-" * 40)
302print("Example 8: Get status codes")
303print("-" * 40)
304
305status_code_response = client.get_status_codes(params={"limit": 5})
306print(
307 f"Retrieved {len(status_code_response.status_code_bag)} status codes (out of {status_code_response.count} total)."
308)
309for code_obj in status_code_response.status_code_bag:
310 print(f" - Code: {code_obj.code}, Description: {code_obj.description}")