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