code: def upload_file(self, local_path, project_id, parent_data, existing_file_id=None, remote_filename=None):
          
          path_data = PathData(local_path)
          hash_data = path_data.get_hash()
          file_upload_operations = FileUploadOperations(self.data_service, None)
          upload_id = file_upload_operations.create_upload(project_id, path_data, hash_data,
                                                           remote_filename=remote_filename,
                                                           storage_provider=self.config.storage_provider_id)
          context = UploadContext(self.config, self.data_service, upload_id, path_data)
          ParallelChunkProcessor(context).run()
          remote_file_data = file_upload_operations.finish_upload(upload_id, hash_data, parent_data, existing_file_id)
          return File(self, remote_file_data)
docs: Upload a file under a specific location in DDSConnection possibly replacing an existing file.
          :param local_path: str: path to a local file to upload
          :param project_id: str: uuid of the project to add this file to
          :param parent_data: ParentData: info about the parent of this file
          :param existing_file_id: str: uuid of file to create a new version of (or None to create a new file)
          :param remote_filename: str: name to use for our remote file (defaults to local_path basename otherwise)
          :return: File