'This method first syncs device counters and device objects, so that the two computers
can determine who has what and, in comparison, what it needs to request.
Then, it uses those device records to partially download and partially upload.
Not all at once--that would be less robust!
Afterwards, it returns summary statistics about what was synced, but no specific
state--this allows it to assume nothing for the next go-around (as this method
is called in a loop elsewhere)'

def sync_models(self):

    if self.verbose:
        print '\nCLIENT:    sync_models'
    (counters_to_download, counters_to_upload) = self.sync_device_records()
    download_results = {'saved_model_count': 0, 'unsaved_model_count': 0}
    try:
        if self.verbose:
            print 'CLIENT:    sync_models,    downloading'
        response = json.loads(self.post('models/download', {'device_counters': counters_to_download}).content)
        download_results.update(save_serialized_models(response.get('models', '[]'), verbose=self.verbose))
        self.session.models_downloaded += download_results['saved_model_count']
        self.display_and_count_errors(download_results, context_name='downloading    models')
    except Exception as e:
        print ('Exception    downloading    models    (in    api_client):    %s,    %s,    %s' % (e.__class__.__name__, e.message, e.args))
        download_results['error'] = e
        self.session.errors += 1
    upload_results = {'saved_model_count': 0, 'unsaved_model_count': 0}
    try:
        if self.verbose:
            print 'CLIENT:    sync_models,    uploading'
        response = self.post('models/upload', {'models': get_serialized_models(counters_to_upload, verbose=self.verbose)})
        upload_results.update(json.loads(response.content))
        self.session.models_uploaded += upload_results['saved_model_count']
        self.display_and_count_errors(upload_results, context_name='uploading    models')
    except Exception as e:
        print ('Exception    uploading    models    (in    api_client):    %s,    %s,    %s' % (e.__class__.__name__, e.message, e.args))
        upload_results['error'] = e
        self.session.errors += 1
    self.session.save()
    return {'download_results': download_results, 'upload_results': upload_results}
