Introduction to Patent_Client#

The patent_client package provides easy access to a number of USPTO and EPO patent data resources, all through a familiar ORM-like interface. If you have experience with the Django ORM with some extra features to accomodate the various data sources. Each data source is encapsulated in a Model object that represents various API’s. The top-level models are:

  • USApplication (USPTO Patent Examination Data System)

  • PtabTrial (USPTO PTAB Trials API)

  • Assignment (USPTO Assignments API)

  • Inpadoc (EPO Inpadoc API)

Several of these models also have sub-models, as discussed below. This notebook shows some simple examples for doing data lookups with each of the models. The other notebooks in the repository show more complex analysis using the Pandas data science library.

USApplication (USPTO Patent Examination Data System)#

The first model we’ll look at is USApplication, an abstraction on top of the USPTO Patent Examination Data System API. The first step, which is common to all models, is to import the model object - USApplication.

[1]:
from patent_client import USApplication

The model can then be queried to get actual data back to do analysis, review, etc. All queries take one of two forms:

  • Model.objects.filter(query) -> retreives many objects

  • Model.objects.get(query) -> retreives one object, otherwise throws an error

For example, we can query USApplications by applicant by passing the query:

USApplication.objects.filter(first_named_applicant='Tesla Motors')

This query will retrieve all applications that name Tesla Motors as an applicant. By default, if you pass in only an argument without a keyword, like this:

USApplication.objects.get("10123456")

the model assumes that you’re referring to the application number, and fetches the corresponding app. A complete list of available query fields is available at Model.objects.query_fields. For example:

USApplication.objects.query_fields

NOTE: If you ever need help with something, try calling the Python builtin “help” function. All models have (or should have) super-handy help text about queries, available information, related objects, etc. E.g.:

help(USApplication)

To protect the innocent, we’ll use Tesla’s patent portfolio as an example - a company that has publicly agreed not to assert its patents against others. To do a lookup by applicant, we query USApplication object like this:

[2]:
tesla_apps = USApplication.objects.filter(first_named_applicant='Tesla Motors')
print('We found apps with these applicant names:')
print(list(set(a.applicants[0].name for a in tesla_apps)))
We found apps with these applicant names:
['Inc.; Tesla Motors', 'TESLA MOTORS. INC.;', 'Tesla Motors, Inc.;', 'TESLA MOTORS CANADA ULC;', 'Tesla Motors Canada ULC;', 'TESLA MOTORS, INC.;', 'TESLA MOTORS, INC;']

Let’s grab one case, and explore the data therein. Note that all Model objects are dataclasses, with all the magic that includes, including descriptive str functions with basic data:

[3]:
tesla_app = tesla_apps[15]
tesla_app
[3]:
USApplication(appl_id='16057119', patent_title='NOVEL BATTERY SYSTEMS BASED ON TWO-ADDITIVE ELECTROLYTE SYSTEMS INCLUDING 1,2,6-OXODITHIANE-2,2,6,6-TETRAOXIDE', app_status='Non Final Action Mailed')

A complete list of data attributes can be found by examining the fields of the dataclass

[4]:
[f.name for f in tesla_app.fields()]
[4]:
['appl_id',
 'app_filing_date',
 'patent_title',
 'app_status',
 'app_status_date',
 'app_early_pub_number',
 'app_early_pub_date',
 'patent_number',
 'patent_issue_date',
 'wipo_early_pub_number',
 'wipo_early_pub_date',
 'corr_addr_cust_no',
 'app_cust_number',
 'app_attr_dock_number',
 'app_location',
 'first_inventor_file',
 'app_type',
 'app_entity_status',
 'app_confr_number',
 'app_cls_sub_cls',
 'app_grp_art_number',
 'app_exam_name',
 'pta_pte_summary',
 'correspondent',
 'inventors',
 'applicants',
 'attorneys',
 'transactions',
 'child_continuity',
 'parent_continuity',
 'foreign_priority',
 'pta_pte_tran_history',
 'assignments']

As you can see, there is a wealth of data about this particular case. Most of the names are relatively self-explanatory. We can look at some basic data by grabbing all the elements that start with “app”. First, we’ll use the .to_dict() method to convert the application to a standard Python dictionary. Then we’ll only print items if they contain “_app”:

[5]:
for k, v in tesla_app.to_dict().items():
    if 'app_' in k or k == 'appl_id':
        print(f'{k}: {v}')
app_attr_dock_number: TSLA.005A2
app_cls_sub_cls: 429/324000
app_confr_number: 2162
app_cust_number: 113241
app_early_pub_date: 2019-09-12
app_early_pub_number: US20190280334A1
app_entity_status: UNDISCOUNTED
app_exam_name: YANCHUK, STEPHEN J
app_filing_date: 2018-08-07
app_grp_art_number: 1723
app_location: ELECTRONIC
app_status: Non Final Action Mailed
app_status_date: 2022-07-19
app_type: Utility
appl_id: 16057119

There are also some composite data elements. These elements consist of several related Model objects that model some part of the Application data. These data elements are:

  • USApplication.transactions (a list of Transaction objects)

  • USApplication.children and USApplication.parents (both are lists of Relationship objects)

  • USApplication.foreign_priority (a list of ForeignPriority objects)

  • USApplication.pta_pte_history (a list of PtaPteHistory objects)

  • USApplication.pta_pte_summary (a PtaPteSummary object)

  • USApplication.correspondent (a Correspondent object)

  • USApplication.attorneys (a list of Attorney objects)

To use as an example, let’s take a look at the transaction data, and fetch the first 15 records.

[6]:
tesla_app.transactions[:15]
[6]:
[Transaction(date=datetime.date(2022, 7, 21), code='ELC_RVW', description='Electronic Review'),
 Transaction(date=datetime.date(2022, 7, 21), code='EML_NTF', description='Email Notification'),
 Transaction(date=datetime.date(2022, 7, 21), code='MCTNF', description='Mail Non-Final Rejection'),
 Transaction(date=datetime.date(2022, 7, 15), code='CTNF', description='Non-Final Rejection'),
 Transaction(date=datetime.date(2022, 7, 15), code='IDSC', description='Information Disclosure Statement considered'),
 Transaction(date=datetime.date(2022, 7, 15), code='IDSC', description='Information Disclosure Statement considered'),
 Transaction(date=datetime.date(2021, 12, 20), code='WIDS', description='Information Disclosure Statement (IDS) Filed'),
 Transaction(date=datetime.date(2021, 7, 23), code='M844', description='Information Disclosure Statement (IDS) Filed'),
 Transaction(date=datetime.date(2021, 7, 26), code='FWDX', description='Date Forwarded to Examiner'),
 Transaction(date=datetime.date(2021, 7, 23), code='RCEX', description='Request for Continued Examination (RCE)'),
 Transaction(date=datetime.date(2021, 7, 26), code='ABN9', description='Disposal for a RCE / CPA / R129'),
 Transaction(date=datetime.date(2021, 7, 23), code='XT/G', description='Request for Extension of Time - Granted'),
 Transaction(date=datetime.date(2021, 7, 23), code='WIDS', description='Information Disclosure Statement (IDS) Filed'),
 Transaction(date=datetime.date(2021, 7, 23), code='BRCE', description='Workflow - Request for RCE - Begin'),
 Transaction(date=datetime.date(2021, 1, 25), code='ELC_RVW', description='Electronic Review')]

You might notice that the above data is relatively messy. We can make the data look a bit cleaner by converting the objects to a Pandas dataframe. Every list of objects in patent_client has a .to_pandas method that will convert it to a pandas dataframe:

[7]:
import pandas as pd
pd.set_option('display.max_colwidth', None) # makes sure the table runs all the way to the edge

tesla_app.transactions[:15].to_pandas()
[7]:
code date description
0 ELC_RVW 2022-07-21 Electronic Review
1 EML_NTF 2022-07-21 Email Notification
2 MCTNF 2022-07-21 Mail Non-Final Rejection
3 CTNF 2022-07-15 Non-Final Rejection
4 IDSC 2022-07-15 Information Disclosure Statement considered
5 IDSC 2022-07-15 Information Disclosure Statement considered
6 WIDS 2021-12-20 Information Disclosure Statement (IDS) Filed
7 M844 2021-07-23 Information Disclosure Statement (IDS) Filed
8 FWDX 2021-07-26 Date Forwarded to Examiner
9 RCEX 2021-07-23 Request for Continued Examination (RCE)
10 ABN9 2021-07-26 Disposal for a RCE / CPA / R129
11 XT/G 2021-07-23 Request for Extension of Time - Granted
12 WIDS 2021-07-23 Information Disclosure Statement (IDS) Filed
13 BRCE 2021-07-23 Workflow - Request for RCE - Begin
14 ELC_RVW 2021-01-25 Electronic Review

PtabProceeding (USPTO PTAB Api)#

Now that you’ve seen a little bit of the USApplication API, let’s take a look at the PTAB Trials API. We’ll start with the usual import:

[8]:
from patent_client import PtabProceeding

For randomness’ sake, we’ll pick the first IPR of 2017 to play around with, and look it up by its trial number:

[9]:
trial = PtabProceeding.objects.get('IPR2017-00001')
print(f'PTAB Trial No. {trial.proceeding_number} was filed {trial.accorded_filing_date} to challenge U.S. Patent {trial.respondent_patent_number}')
print(f'The case is styled {trial.petitioner_party_name} v. {trial.respondent_party_name}')
PTAB Trial No. IPR2017-00001 was filed 2016-10-01 to challenge U.S. Patent 7468661
The case is styled Emerson Electric Co. v. SIPCO, LLC

The complete list of available data is again available at .attrs:

[10]:
[f.name for f in trial.fields()]
[10]:
['last_modified_date',
 'last_modified_user_id',
 'institution_decision_date',
 'proceeding_filing_date',
 'accorded_filing_date',
 'proceeding_status_category',
 'proceeding_number',
 'proceeding_last_modified_date',
 'proceeding_type_category',
 'subproceeding_type_category',
 'decision_date',
 'docket_notice_mail_date',
 'declaration_date',
 'style_name_text',
 'respondent_technology_center_number',
 'respondent_patent_owner_name',
 'respondent_party_name',
 'respondent_group_art_unit_number',
 'respondent_inventor_name',
 'respondent_counsel_name',
 'respondent_grant_date',
 'respondent_patent_number',
 'respondent_application_number_text',
 'respondent_publication_number',
 'respondent_publication_date',
 'petitioner_technology_center_number',
 'petitioner_patent_owner_name',
 'petitioner_party_name',
 'petitioner_group_art_unit_number',
 'petitioner_inventor_name',
 'petitioner_counsel_name',
 'petitioner_grant_date',
 'petitioner_patent_number',
 'petitioner_application_number_text',
 'appellant_technology_center_number',
 'appellant_patent_owner_name',
 'appellant_party_name',
 'appellant_group_art_unit_number',
 'appellant_inventor_name',
 'appellant_counsel_name',
 'appellant_grant_date',
 'appellant_patent_number',
 'appellant_application_number_text',
 'appellant_publication_date',
 'appellant_publication_number',
 'third_party_name',
 'second_respondent_party_name',
 'second_respondent_appl_number_text',
 'second_respondent_patent_number',
 'second_respondent_grant_date',
 'second_respondent_patent_owner_name',
 'second_respondent_inventor_name',
 'second_respondent_counsel_name',
 'second_respondent_g_a_u_number',
 'second_respondent_tech_center_number',
 'second_respondent_pub_number',
 'second_respondent_publication_date',
 'additional_respondents']

Where possible, there are also related objects that can be fetch from a Model object. For example, the challenged patent has a related USApplication. A complete list of all related objects and other data can be found by calling the help function on the object:

[11]:
help(trial)
Help on PtabProceeding in module patent_client.uspto.ptab.model object:

class PtabProceeding(patent_client.util.model.Model)
 |  PtabProceeding(last_modified_date: 'datetime.datetime' = None, last_modified_user_id: 'datetime.datetime' = None, institution_decision_date: 'datetime.date' = None, proceeding_filing_date: 'datetime.date' = None, accorded_filing_date: 'datetime.date' = None, proceeding_status_category: str = None, proceeding_number: str = None, proceeding_last_modified_date: 'datetime.date' = None, proceeding_type_category: str = None, subproceeding_type_category: str = None, decision_date: 'datetime.date' = None, docket_notice_mail_date: 'datetime.date' = None, declaration_date: 'datetime.date' = None, style_name_text: str = None, respondent_technology_center_number: str = None, respondent_patent_owner_name: str = None, respondent_party_name: str = None, respondent_group_art_unit_number: str = None, respondent_inventor_name: str = None, respondent_counsel_name: str = None, respondent_grant_date: 'datetime.date' = None, respondent_patent_number: str = None, respondent_application_number_text: str = None, respondent_publication_number: str = None, respondent_publication_date: 'datetime.date' = None, petitioner_technology_center_number: str = None, petitioner_patent_owner_name: str = None, petitioner_party_name: str = None, petitioner_group_art_unit_number: str = None, petitioner_inventor_name: str = None, petitioner_counsel_name: str = None, petitioner_grant_date: 'datetime.date' = None, petitioner_patent_number: str = None, petitioner_application_number_text: str = None, appellant_technology_center_number: str = None, appellant_patent_owner_name: str = None, appellant_party_name: str = None, appellant_group_art_unit_number: str = None, appellant_inventor_name: str = None, appellant_counsel_name: str = None, appellant_grant_date: 'datetime.date' = None, appellant_patent_number: str = None, appellant_application_number_text: str = None, appellant_publication_date: 'datetime.date' = None, appellant_publication_number: str = None, third_party_name: str = None, second_respondent_party_name: str = None, second_respondent_appl_number_text: str = None, second_respondent_patent_number: str = None, second_respondent_grant_date: 'datetime.date' = None, second_respondent_patent_owner_name: str = None, second_respondent_inventor_name: str = None, second_respondent_counsel_name: str = None, second_respondent_g_a_u_number: str = None, second_respondent_tech_center_number: str = None, second_respondent_pub_number: str = None, second_respondent_publication_date: 'datetime.date' = None, additional_respondents: 'ListManager[str]' = <factory>) -> None
 |
 |  A PTAB Proceeding - e.g. IPR/CBM/DER Trial, Patent Appeal, Interference, etc.
 |
 |  All fields are query-able. Date ranges can be formed by inserting "from" or "to" on a query
 |  for a date range.
 |
 |  Method resolution order:
 |      PtabProceeding
 |      patent_client.util.model.Model
 |      patent_client.util.model.ModelABC
 |      builtins.object
 |
 |  Methods defined here:
 |
 |  __eq__(self, other)
 |
 |  __init__(self, last_modified_date: 'datetime.datetime' = None, last_modified_user_id: 'datetime.datetime' = None, institution_decision_date: 'datetime.date' = None, proceeding_filing_date: 'datetime.date' = None, accorded_filing_date: 'datetime.date' = None, proceeding_status_category: str = None, proceeding_number: str = None, proceeding_last_modified_date: 'datetime.date' = None, proceeding_type_category: str = None, subproceeding_type_category: str = None, decision_date: 'datetime.date' = None, docket_notice_mail_date: 'datetime.date' = None, declaration_date: 'datetime.date' = None, style_name_text: str = None, respondent_technology_center_number: str = None, respondent_patent_owner_name: str = None, respondent_party_name: str = None, respondent_group_art_unit_number: str = None, respondent_inventor_name: str = None, respondent_counsel_name: str = None, respondent_grant_date: 'datetime.date' = None, respondent_patent_number: str = None, respondent_application_number_text: str = None, respondent_publication_number: str = None, respondent_publication_date: 'datetime.date' = None, petitioner_technology_center_number: str = None, petitioner_patent_owner_name: str = None, petitioner_party_name: str = None, petitioner_group_art_unit_number: str = None, petitioner_inventor_name: str = None, petitioner_counsel_name: str = None, petitioner_grant_date: 'datetime.date' = None, petitioner_patent_number: str = None, petitioner_application_number_text: str = None, appellant_technology_center_number: str = None, appellant_patent_owner_name: str = None, appellant_party_name: str = None, appellant_group_art_unit_number: str = None, appellant_inventor_name: str = None, appellant_counsel_name: str = None, appellant_grant_date: 'datetime.date' = None, appellant_patent_number: str = None, appellant_application_number_text: str = None, appellant_publication_date: 'datetime.date' = None, appellant_publication_number: str = None, third_party_name: str = None, second_respondent_party_name: str = None, second_respondent_appl_number_text: str = None, second_respondent_patent_number: str = None, second_respondent_grant_date: 'datetime.date' = None, second_respondent_patent_owner_name: str = None, second_respondent_inventor_name: str = None, second_respondent_counsel_name: str = None, second_respondent_g_a_u_number: str = None, second_respondent_tech_center_number: str = None, second_respondent_pub_number: str = None, second_respondent_publication_date: 'datetime.date' = None, additional_respondents: 'ListManager[str]' = <factory>) -> None
 |
 |  __repr__(self)
 |      Return repr(self).
 |
 |  ----------------------------------------------------------------------
 |  Readonly properties defined here:
 |
 |  decisions
 |      Decisions associated with the Proceeding
 |
 |  documents
 |      Documents associated with the Proceeding
 |
 |  us_application
 |      The US Application provided by PEDS associated with the Proceeding
 |
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |
 |  __annotations__ = {'accorded_filing_date': 'datetime.date', 'additiona...
 |
 |  __dataclass_fields__ = {'accorded_filing_date': Field(name='accorded_f...
 |
 |  __dataclass_params__ = _DataclassParams(init=True,repr=True,eq=True,or...
 |
 |  __hash__ = None
 |
 |  __manager__ = 'patent_client.uspto.ptab.manager.PtabProceedingManager'
 |
 |  accorded_filing_date = None
 |
 |  appellant_application_number_text = None
 |
 |  appellant_counsel_name = None
 |
 |  appellant_grant_date = None
 |
 |  appellant_group_art_unit_number = None
 |
 |  appellant_inventor_name = None
 |
 |  appellant_party_name = None
 |
 |  appellant_patent_number = None
 |
 |  appellant_patent_owner_name = None
 |
 |  appellant_publication_date = None
 |
 |  appellant_publication_number = None
 |
 |  appellant_technology_center_number = None
 |
 |  decision_date = None
 |
 |  declaration_date = None
 |
 |  docket_notice_mail_date = None
 |
 |  institution_decision_date = None
 |
 |  last_modified_date = None
 |
 |  last_modified_user_id = None
 |
 |  petitioner_application_number_text = None
 |
 |  petitioner_counsel_name = None
 |
 |  petitioner_grant_date = None
 |
 |  petitioner_group_art_unit_number = None
 |
 |  petitioner_inventor_name = None
 |
 |  petitioner_party_name = None
 |
 |  petitioner_patent_number = None
 |
 |  petitioner_patent_owner_name = None
 |
 |  petitioner_technology_center_number = None
 |
 |  proceeding_filing_date = None
 |
 |  proceeding_last_modified_date = None
 |
 |  proceeding_number = None
 |
 |  proceeding_status_category = None
 |
 |  proceeding_type_category = None
 |
 |  respondent_application_number_text = None
 |
 |  respondent_counsel_name = None
 |
 |  respondent_grant_date = None
 |
 |  respondent_group_art_unit_number = None
 |
 |  respondent_inventor_name = None
 |
 |  respondent_party_name = None
 |
 |  respondent_patent_number = None
 |
 |  respondent_patent_owner_name = None
 |
 |  respondent_publication_date = None
 |
 |  respondent_publication_number = None
 |
 |  respondent_technology_center_number = None
 |
 |  second_respondent_appl_number_text = None
 |
 |  second_respondent_counsel_name = None
 |
 |  second_respondent_g_a_u_number = None
 |
 |  second_respondent_grant_date = None
 |
 |  second_respondent_inventor_name = None
 |
 |  second_respondent_party_name = None
 |
 |  second_respondent_patent_number = None
 |
 |  second_respondent_patent_owner_name = None
 |
 |  second_respondent_pub_number = None
 |
 |  second_respondent_publication_date = None
 |
 |  second_respondent_tech_center_number = None
 |
 |  style_name_text = None
 |
 |  subproceeding_type_category = None
 |
 |  third_party_name = None
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from patent_client.util.model.Model:
 |
 |  __iter__(self)
 |
 |  fields(self)
 |      Return list of fields
 |
 |  items(self)
 |
 |  to_dict(self, item_class=<class 'patent_client.util.row.Row'>, collection_class=<class 'patent_client.util.collections.ListManager'>)
 |      Convert model to a dictionary representation
 |
 |  to_json(self, *args, **kwargs)
 |
 |  to_pandas(self)
 |      Convert object to Pandas Series
 |
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from patent_client.util.model.Model:
 |
 |  __default_fields__ = False
 |
 |  __exclude_fields__ = []
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from patent_client.util.model.ModelABC:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)

From the data above, we see that there is a related data object called “us_application”. That is, we can fetch the application object that corresponds to the PtabTrial simply by retreiving the attribute .us_application, like so:

[12]:
trial_app = trial.us_application
print(trial_app)
print({k:v for (k, v) in trial_app.to_dict().items() if 'app_' in k})
USApplication(appl_id='11395685', patent_title='SYSTEM AND METHOD FOR MONITORING AND CONTROLLING REMOTE DEVICES', app_status='Patented Case')
{'app_attr_dock_number': 'STAT3', 'app_cls_sub_cls': '340/531000', 'app_confr_number': '1922', 'app_cust_number': '89818', 'app_early_pub_date': datetime.date(2006, 8, 17), 'app_early_pub_number': 'US20060181406A1', 'app_entity_status': 'UNDISCOUNTED', 'app_exam_name': 'PHAM, TOAN NGOC', 'app_filing_date': datetime.date(2006, 3, 31), 'app_grp_art_number': '2612', 'app_location': 'ELECTRONIC', 'app_status': 'Patented Case', 'app_status_date': datetime.date(2008, 12, 3), 'app_type': 'Utility'}