Package: retsdk
RETSDKA Python SDK for the Real Estate Transaction Standard (RETS)Installationpip install retsdkUsageInitialize a clientCreate a new RETSConnection instance to connect to a RETS server.Examplefromretsdk.clientimportRETSConnectionrets=RETSConnection(username='your_rets_username',password='your_rets_password',login_url='https://rets.somemls.com/rets/Login/')# Metadata info & transaction URLs get loaded automaticallyprint(rets.metadata_version)# 1.00.00235print(rets.metadata_timestamp)# 2015-05-20T20:08:15Zprint(rets.min_metadata_timestamp)# 2015-05-20T20:08:15Zprint(rets.get_metadata_url)# https://rets.somemls.com/rets/GetMetadata/print(rets.get_search_url)# https://rets.somemls.com/rets/Search/print(rets.get_object_url)# https://rets.somemls.com/rets/GetObject/Initialization ArgumentsArgumentTypeRequiredMeaningusernameStringYesRETS account usernamepasswordStringYesRETS account passwordlogin_urlStringYesRETS server login URLauth_typeStringNoAuthentication type (defaults to 'digest')rets_versionStringNoSpecifies the RETS version to be used (defaults to 'RETS/1.7.2')user_agentStringNoSpecifies the user-agent (defaults to 'RETSDK/1.0')Download MetadataThere are (usually) several tiers of metadata to consider in a RETS system. These are resource metadata, class metadata, table metadata, and lookup-type metadata. RETSDK has methods to work with each of these programmatically, but if you would like to view metadata right in your browser with no additional setup, you can also tryRETSMD.All of the metadata query methods return a response dictionary with the following items:KeyMeaningValuemore_rowsIndicates whether there are more rows to downloadBooleanokIndicates whether the process completed successfullyBooleanrecord_countThe number of rows returnedIntegerreply_codeThe server's RETS reply codeIntegerreply_textThe message accompanying the RETS reply codeStringrowsThe metadata records returned by the serverList1. Resource MetadataResource metadata is the top layer of metadata; it tells you what resources are accessible from your account. Use theget_resource_metadata()method to download resource metadata.ArgumentsNoneExample# Get the RETS system's resource metadataresponse=rets.get_resource_metadata()frompprintimportpprintpprint(response)#{'more_rows': False,# 'ok': True,# 'record_count': 2,# 'reply_code': '0',# 'reply_text': 'Operation Success.',# 'rows': [{'ClassCount': 1,#           'ClassDate': '2015-01-28T21:06:04Z',#           'ClassVersion': '1.00.00001',#           'Description': 'Agent',#           'KeyField': 'sysid',#           'LookupDate': '2015-01-21T17:31:54Z',#           'LookupVersion': '1.00.00001',#           'ObjectDate': '2014-03-21T17:15:24Z',#           'ObjectVersion': '1.00.00001',#           'ResourceID': 'Agent',#           'StandardName': 'Agent',#           'TableName': 'Agent',#           'VisibleName': 'Agent'},#          {'ClassCount': 1,#           'ClassDate': '2015-01-28T16:19:02Z',#           'ClassVersion': '1.00.00001',#           'Description': 'Listing',#           'KeyField': 'sysid',#           'LookupDate': '2015-01-28T14:34:35Z',#           'LookupVersion': '1.00.00001',#           'ObjectDate': '2015-01-28T14:34:35Z',#           'ObjectVersion': '1.00.00001',#           'ResourceID': 'Property',#           'StandardName': 'Property',#           'TableName': 'Listing',#           'VisibleName': 'Listing'}]}2. Class MetadataClass metadata provides information about the classes in a resource. Use theget_class_metadata()method to get class metadata.ArgumentsArgument NameRequiredMeaningresourceNoThe ID of a RETS resource. Defaults to 'Property'.Exampleclass_metadata_response=rets.get_class_metadata(resource='Property')pprint(class_metadata_response)#{'more_rows': False,# 'ok': True,# 'record_count': 1,# 'reply_code': '0',# 'reply_text': 'Operation Success.',# 'rows': [{'ClassName': 'Listing',#           'Description': 'Cross Property',#           'StandardName': None,#           'TableDate': '2015-01-28T02:49:39Z',#           'TableVersion': '1.00.00985',#           'UpdateDate': '2015-01-28T14:32:06Z',#           'UpdateVersion': '1.00.00001',#           'VisibleName': 'Cross Property'}]}3. Table MetadataTable metadata tells you about the specific fields available in a class. Use theget_table_metadata()method to get table metadata.ArgumentsArgument NameRequiredMeaningresourceNoThe ID of a resource. Defaults to 'Property'.class_nameNoThe class name or system name of a class within a resource. Defaults to 'Listing'.Exampletable_metadata_response=rets.get_table_metadata(resource='Property',class_name='Listing')pprint(table_metadata_response)#{'more_rows': False,# 'ok': True,# 'record_count': 2,# 'reply_code': '0',# 'reply_text': 'Operation Success.',# 'rows': [{'Alignment': 'Left',#           'DBName': 'price',#           'DataType': 'Int',#           'Default': None,#           'InKeyIndex': 0,#           'Index': 1,#           'Interpretation': 'Number',#           'LongName': 'Price',#           'LookupName': None,#           'MaxSelect': None,#           'Maximum': 2147483647,#           'MaximumLength': 11,#           'MetadataEntryID': 200,#           'Minimum': -2147483648,#           'Precision': None,#           'Required': 1,#           'Searchable': 1,#           'ShortName': 'Price',#           'StandardName': 'Price',#           'SystemName': 'Price',#           'Unique': 0,#           'Units': 'USD',#           'UseSeparator': None},#          {'Alignment': 'Left',#           'DBName': 'property_type',#           'DataType': 'Character',#           'Default': None,#           'InKeyIndex': 0,#           'Index': 1,#           'Interpretation': 'Lookup',#           'LongName': 'Property Type',#           'LookupName': 'PropertyType',#           'MaxSelect': None,#           'Maximum': None,#           'MaximumLength': 32,#           'MetadataEntryID': 201,#           'Minimum': None,#           'Precision': None,#           'Required': 1,#           'Searchable': 1,#           'ShortName': 'PropertyType',#           'StandardName': 'PropertyType',#           'SystemName': 'PropertyType',#           'Unique': 0,#           'Units': None,#           'UseSeparator': None}]}4. Lookup-Type MetadataThe last type of metadata data to consider is lookup-type metdata. If a field in the table metadata has an interpretation of "Lookup", there is a list of specific values that the field can hold. Get this list of values with theget_lookup_type_metadata()method.ArgumentsArgument NameRequiredMeaningresourceNoThe ID of a resource. Defaults to 'Property'.lookup_nameYesA field's lookup name.Examplelookup_type_metadata_response=rets.get_lookup_type_metadata(resource='Property',lookup_name='PropertyType')pprint(lookup_type_metadata_response)# {'more_rows': False,#  'ok': True,#  'record_count': 3,#  'reply_code': '0',#  'reply_text': 'Operation Success.',#  'rows': [{'LongValue': 'Single Family Detached',#           'MetadataEntryID': 10002,#           'ShortValue': 'SFD',#           'Value': 'SFD'},#          {'LongValue': 'Condominium',#           'MetadataEntryID': 10003,#           'ShortValue': 'CON',#           'Value': 'CON'},#          {'LongValue': 'Multifamily',#           'MetadataEntryID': 10004,#           'ShortValue': 'MUL',#           'Value': 'MUL'}]}Download DataDownload data or search through records using theget_data()method. You will need to specify a query (using DMQL) and a list of the fields that you would like to have returned to you (seeDownload Metadatato learn how to find out what fields are available).ArgumentsArgument NameRequiredMeaningresourceYesThe ID of a RETS system resource.class_nameYesThe name of a class in the specified resource.queryYesA DMQL queryfieldsYesA list of the fields to be returneddata_formatNoThe RETS data format to be used with fields. Defaults to 'COMPACT-DECODED'.limitNoThe maximum number of records to returnoffsetNoAn offset position that can be used with limitResponse DictionaryKeyMeaningValue Typemore_rowsIndicates whether there are more rows to download for the current queryBooleanokIndicates whether the query was processed successfullyBooleanrecord_countThe number of rows returnedIntegerreply_codeThe server's RETS reply codeIntegerreply_textThe message accompanying the RETS reply codeStringrowsThe actual records returned by the queryListExamples# Query all listings with "SFD" PropertyType, return only MLSNumber and Pricerets_query="(PropertyType=SFD)"fields_to_be_downloaded=["MLSNumber","Price"]data=rets.get_data(resource='Property',class_name='Property',query=query,fields=fields_to_be_downloaded,)pprint(data)# {'more_rows': False,#  'ok': True,#  'record_count': '10',#  'reply_code': '0',#  'reply_text': 'Operation Success.',#  'rows': [{'Price': 199000.0, 'MLSNumber': 'MLS0000001'},#           {'Price': 2500000.0, 'MLSNumber': 'MLS0000002'},#           {'Price': 319500.0, 'MLSNumber': 'MLS0000003'},#           {'Price': 275900.0, 'MLSNumber': 'MLS0000004'},#           {'Price': 239900.0, 'MLSNumber': 'MLS0000005'},#           {'Price': 339900.0, 'MLSNumber': 'MLS0000006'},#           {'Price': 249900.0, 'MLSNumber': 'MLS0000007'},#           {'Price': 219900.0, 'MLSNumber': 'MLS0000008'},#           {'Price': 579900.0, 'MLSNumber': 'MLS0000009'},#           {'Price': 209900.0, 'MLSNumber': 'MLS0000010'}]}You may optionally use thelimitandoffsetparameters to page the data that you want to download. This allows you to break large downloads into smaller pieces.# A broader RETS query that might returns lots of recordsrets_query=(PropertyType=SFD,CON,MUL)fields_to_be_downloaded=["MLSNumber","Price"]# Use a loop to download 10 records at a timedownload_complete=Falselast_offset=0whilenotdownload_complete:data=rets.get_data(resource='Property',class_name='Listing',query=rets_query,fields=fields_to_be_downloaded,limit=10,offset=last_offset)forrowindata['rows']:# Do something with the rows you downloaded here (save to a database, etc.)passifdata['more_rows']:# Still more to download!last_offset+=10else:# Done!download_complete=TrueGetting a Record Count without Returning DataIf you just want a count of how many records match your query, you can useget_count()instead of get_data(). get_count() will return an integer instead of a full response dictionary.You do not specify fields, limit, or offset with get_count(), but otherwise it works just like get_data(). It is, in fact, just another wrapper for the RETS Search transaction with theCountparameter set differently.Examplerow_count=rets.get_count('Property',class_name='Property',query=rets_query)print(row_count)# 105Download ImagesUse theget_object()method to download images. This method is a wrapper for the RETS specification's GetObject transaction.get_object() returns a response dictionary, but the dictionary does not contain 'rows', 'record_count' or 'more_rows'. Instead, it will contain an item called 'object_data', where the actual object data will be stored as bytes.ArgumentsArgument NameRequiredMeaningresourceYesThe ID of a RETS system resource.obj_typeYesThe type of object to be returned (e.g., 'Photo').obj_idYesThe system ID of the record associated with object.order_noNoThe order number of the image or other object (for situations where there are multiple images associated with one listing)pathNoA file system path where image data should be written (used only when write=True).writeNoA boolean value that can optionally be set to True if you would like get_object() to write image/object data to a file for you. You must specifiy a path if you wish to use this option.Response Dictionary:KeyMeaningValue TypeokIndicates whether the object download was successfulBooleanreply_codeThe server's RETS reply codeIntegerreply_textThe message accompanying the RETS reply codeStringobject_dataThe object data payloadBytesExample# Download an image (as bytes)img_response=rets.get_object(resource='Property',obj_type='Photo',obj_id='MLS0000001',order_no=0)# Write the image data to a file somewherepath="/tmp/rets/images/MLS0000001_01.jpg"ifimg_response['ok']:withopen(path,'wb')asf:f.write(img_response['object_data'])LogoutIf you would like to, you can close your RETS session with thelogout()method.ArgumentsNoneResponse Dictionary:KeyMeaningValue Typemore_rowsIndicates whether there are more rows to download for the current transactionBooleanokIndicates whether the transaction was successfulBooleanrecord_countThe number of rows returnedIntegerreply_codeThe server's RETS reply codeIntegerreply_textThe message accompanying the RETS reply codeStringrowsThe actual records returned by the logout transactionListExamplelogout_response=rets.logout()pprint(logout_response)# {'more_rows': False,#  'ok': True,#  'record_count': 1,#  'reply_code': '0',#  'reply_text': 'Operation Success.',#  'rows': [{'SignOffMessage': 'Connection Closed'}]}ExceptionsRETSDK raises these exceptions when stuff goes wrong:ExceptionMeaningretsdk.exceptions.AuthenticationErrorRaised when an unsupported authentication type is specified during intializationretsdk.exceptions.RequestErrorRaised if a RETS transaction request cannot be completedretsdk.exceptions.TransactionErrorRaised if the user attempts to perform a transaction that is not supported by the current RETS account.