dagster-salesforce
A Dagster integration for Salesforce that provides resources for interacting with the Salesforce API, including querying data, managing records, and performing bulk operations.
Features
- Multiple authentication methods: Password, OAuth 2.0, JWT Bearer Token, and Session-based authentication
- Bulk operations: Efficiently handle large-scale data operations using Salesforce Bulk API 2.0
- Query support: Execute SOQL queries and export results to CSV
- CRUD operations: Create, read, update, and delete individual records
- Upsert support: Update or insert records based on external IDs
- Object metadata: Access Salesforce object schemas and field information
- Type-safe: Full type hints and Pydantic models for data validation
Installation
uv pip install dagster-salesforce
Example Usage
Password Authentication
The simplest authentication method using username, password, and security token:
import dagster as dg
from dagster_salesforce import SalesforceResource
from dagster_salesforce.credentials import SalesforceUserPasswordCredentials
from pathlib import Path
@dg.asset
def salesforce_accounts(context: dg.AssetExecutionContext, salesforce: SalesforceResource):
"""Download all Account records from Salesforce."""
# Get the Account object client
account_obj = salesforce.get_object_client("Account")
# Query accounts to CSV
output_dir = Path("/tmp/salesforce_accounts")
results = account_obj.query_to_csv(
query="SELECT Id, Name, Type, Industry FROM Account",
output_directory=output_dir,
batch_size=10000
)
context.log.info(f"Downloaded {sum(r.number_of_records for r in results)} accounts")
return {"output_files": [r.file for r in results if r.file]}
defs = dg.Definitions(
assets=[salesforce_accounts],
resources={
"salesforce": SalesforceResource(
credentials=SalesforceUserPasswordCredentials(
username=dg.EnvVar("SALESFORCE_USERNAME"),
password=dg.EnvVar("SALESFORCE_PASSWORD"),
security_token=dg.EnvVar("SALESFORCE_SECURITY_TOKEN"),
domain="login" # or "test" for sandbox
)
)
}
)
JWT Bearer Token Authentication (Recommended for Production)
For production environments, JWT authentication provides secure, token-based access:
import dagster as dg
from dagster_salesforce import SalesforceResource
from dagster_salesforce.credentials import SalesforceJWTOAuthCredentials
from pathlib import Path
@dg.asset
def salesforce_contacts(salesforce: SalesforceResource):
"""Upsert contacts into Salesforce."""
contact_obj = salesforce.get_object_client("Contact")
# Prepare records to upsert
records = [
{"Email": "john.doe@example.com", "FirstName": "John", "LastName": "Doe"},
{"Email": "jane.smith@example.com", "FirstName": "Jane", "LastName": "Smith"},
]
# Upsert using email as external ID
result = contact_obj.upsert_records(
result_output_directory=Path("/tmp/upsert_results"),
records=records,
external_id_field="Email",
wait=10
)
return {
"successful": result.successfulRecords,
"failed": result.failedRecords,
"files": result.files
}
defs = dg.Definitions(
assets=[salesforce_contacts],
resources={
"salesforce": SalesforceResource(
credentials=SalesforceJWTOAuthCredentials(
username=dg.EnvVar("SALESFORCE_USERNAME"),
consumer_key=dg.EnvVar("SALESFORCE_CONSUMER_KEY"),
privatekey_file=dg.EnvVar("SALESFORCE_PRIVATE_KEY_PATH")
# Or use privatekey=dg.EnvVar("SALESFORCE_PRIVATE_KEY") for key content
)
)
}
)
OAuth 2.0 Connected App Authentication
For web applications using OAuth 2.0 flow:
import dagster as dg
from dagster_salesforce import SalesforceResource
from dagster_salesforce.credentials import SalesforceConnectedAppOAuthCredentials
defs = dg.Definitions(
resources={
"salesforce": SalesforceResource(
credentials=SalesforceConnectedAppOAuthCredentials(
consumer_key=dg.EnvVar("SALESFORCE_CONSUMER_KEY"),
consumer_secret=dg.EnvVar("SALESFORCE_CONSUMER_SECRET"),
domain="login"
)
)
}
)
Direct Session Authentication
For using an existing session token:
import dagster as dg
from dagster_salesforce import SalesforceResource
from dagster_salesforce.credentials import SalesforceSessionCredentials
defs = dg.Definitions(
resources={
"salesforce": SalesforceResource(
credentials=SalesforceSessionCredentials(
session_id=dg.EnvVar("SALESFORCE_SESSION_ID"),
instance_url="https://your-instance.salesforce.com"
)
)
}
)
Working with Salesforce Objects
Query Data
import dagster as dg
from dagster_salesforce import SalesforceResource
from datetime import datetime, timedelta
from pathlib import Path
@dg.asset
def query_opportunities(salesforce: SalesforceResource):
"""Query opportunities with filtering."""
opportunity_obj = salesforce.get_object_client("Opportunity")
# Build query with date filter
last_month = datetime.now() - timedelta(days=30)
query = opportunity_obj.get_query(
incremental_key="LastModifiedDate",
incremental_from=last_month,
limit=1000
)
# Execute query and save to CSV
results = opportunity_obj.query_to_csv(
query=query,
output_directory=Path("/tmp/opportunities")
)
return results
Create, Update, and Delete Records
import dagster as dg
from dagster_salesforce import SalesforceResource
@dg.asset
def manage_leads(salesforce: SalesforceResource):
"""Demonstrate CRUD operations on Lead records."""
lead_obj = salesforce.get_object_client("Lead")
# Create a new lead
lead_id = lead_obj.create_record({
"FirstName": "Test",
"LastName": "Lead",
"Company": "Test Company",
"Email": "test@example.com"
})
# Update the lead
lead_obj.update_record(lead_id, {
"Status": "Qualified",
"Rating": "Hot"
})
# Delete the lead (if needed)
# lead_obj.delete_record(lead_id)
return {"created_lead_id": lead_id}
Bulk Operations
import dagster as dg
from dagster_salesforce import SalesforceResource
from pathlib import Path
@dg.asset
def bulk_import_accounts(salesforce: SalesforceResource):
"""Import accounts using Bulk API 2.0."""
account_obj = salesforce.get_object_client("Account")
# For large datasets, you can use CSV files
csv_file = Path("/path/to/accounts.csv")
result = account_obj.upsert_records(
result_output_directory=Path("/tmp/bulk_results"),
csv_file=str(csv_file),
external_id_field="External_Id__c",
batch_size=10000, # Salesforce automatically handles batching
wait=30
)
return {
"total_processed": result.successfulRecords + result.failedRecords,
"success_rate": result.successfulRecords / (result.successfulRecords + result.failedRecords)
if (result.successfulRecords + result.failedRecords) > 0 else 0
}
Access Field Metadata
import dagster as dg
from dagster_salesforce import SalesforceResource
@dg.asset
def analyze_object_schema(salesforce: SalesforceResource):
"""Analyze Salesforce object schema and fields."""
# Get Account object metadata
account_obj = salesforce.get_object_client("Account")
# Access field information
field_summary = {}
for field_name, field in account_obj.fields.items():
if field.custom: # Only custom fields
field_summary[field_name] = {
"label": field.label,
"type": field.type,
"required": not field.nillable,
"updateable": field.updateable
}
return field_summary
Notes
- Bulk API 2.0: This integration uses Salesforce Bulk API 2.0, which automatically handles internal batching. When uploading data, Salesforce automatically splits it into batches of 10,000 records.
- Rate Limits: The resource includes built-in handling for Salesforce API rate limits. Use
get_limits()to monitor your API usage. - Field Types: The integration preserves Salesforce field types and handles type conversions appropriately.
- Error Handling: Failed records in bulk operations are captured and reported in the result objects.
API Reference
SalesforceResource
The main resource for interacting with Salesforce:
get_object_client(sobject: str) -> SalesforceObject: Get a client for a specific Salesforce objectget_available_objects() -> List[str]: List all available Salesforce objectsget_limits() -> Dict: Get API usage limitscheck_connection() -> Dict: Verify connection and get instance information
SalesforceObject
Represents a Salesforce object (table) with methods for data operations:
query_to_csv(query: str, output_directory: Path, batch_size: int) -> List[SalesforceQueryResult]: Execute SOQL query and save results to CSV filescreate_record(data: Dict) -> str: Create a single recordupdate_record(record_id: str, data: Dict): Update a single recorddelete_record(record_id: str): Delete a single recordupsert_records(...): Bulk upsert operationget_query(incremental_key: str, incremental_from: datetime, limit: int) -> str: Build SOQL query with filters
Credentials Classes
SalesforceUserPasswordCredentials: Username/password authenticationSalesforceJWTOAuthCredentials: JWT Bearer Token authenticationSalesforceConnectedAppOAuthCredentials: OAuth 2.0 Connected App authenticationSalesforceSessionCredentials: Direct session access
Testing
# Run tests
make test
# Run linting and formatting
make ruff
# Run type checking
make check
Development
# Install development dependencies
make install
# Build the package
make build
License
See LICENSE file in the repository.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Metadata
Release files for dagster-salesforce 0.0.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| dagster_salesforce-0.0.3.tar.gz | 13.9 kB | Without provenance | Details for dagster_salesforce-0.0.3.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| dagster_salesforce-0.0.3-py3-none-any.whl | Python 3 | none | any | Details for dagster_salesforce-0.0.3-py3-none-any.whl |
Total release size: 26.6 kB
Release files / dagster_salesforce-0.0.3.tar.gz
| Download URL | dagster_salesforce-0.0.3.tar.gz |
|---|---|
| Size | 13.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
de7257d6d2db8f3acae9054c77d15747a58525c2c571d02c768fbe918661376e
|
|
BLAKE2b-256 checksum How to use checksums |
0ddc16e29dff666e591e0d68091becc719993bef44fcc933ae8641cb22dcf446
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / dagster_salesforce-0.0.3-py3-none-any.whl
| Download URL | dagster_salesforce-0.0.3-py3-none-any.whl |
|---|---|
| Size | 12.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1898738e9b60191e31c472af2451f7fd8379d9f7ca685d775bdd22f0a3012bac
|
|
BLAKE2b-256 checksum How to use checksums |
8c88af39391f1489ee6d6a05c827b6dc67c5dd0bbd36c0802478b09a73cf6137
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for dagster-salesforce 0.0.3
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.