Welcome! In this tutorial, you'll build your first Terraform data source using pyvider. Data sources are read-only queries that fetch information without creating infrastructure.
🤖 AI-Generated Content
This documentation was generated with AI assistance and is still being audited. Some, or potentially a lot, of this information may be inaccurate. Learn more.
A data source is a read-only query that fetches information from external systems. Unlike resources (which manage infrastructure), data sources just read data.
importattrs# Configuration: User inputs@attrs.defineclassFileInfoConfig:"""What the user wants to query."""path:str# Which file to query# Data: Query results@attrs.defineclassFileInfoData:"""Information we return about the file."""id:str# Unique identifierpath:str# File pathsize:int# File size in bytesexists:bool# Whether file existscontent:str# File content
frompyvider.data_sourcesimportregister_data_source,BaseDataSourcefrompyvider.schemaimports_data_source,a_str,a_num,a_bool,PvsSchema@register_data_source("file_info")classFileInfo(BaseDataSource):"""Reads information about a local file."""# Link our runtime typesconfig_class=FileInfoConfigstate_class=FileInfoData@classmethoddefget_schema(cls)->PvsSchema:"""Define what Terraform users see."""returns_data_source({# Input (from user)"path":a_str(required=True,description="File path to query"),# Outputs (we compute all of these)"id":a_str(computed=True,description="File path as ID"),"size":a_num(computed=True,description="File size in bytes"),"exists":a_bool(computed=True,description="Whether file exists"),"content":a_str(computed=True,description="File content"),})
What's happening?
@register_data_source("file_info") - Registers as a Terraform data source
importattrsfrompyvider.data_sourcesimportregister_data_source,BaseDataSourcefrompyvider.resources.contextimportResourceContextfrompyvider.schemaimports_data_source,a_str,a_num,a_bool,PvsSchemafrompathlibimportPath# Configuration (input)@attrs.defineclassFileInfoConfig:path:str# Data (output)@attrs.defineclassFileInfoData:id:strpath:strsize:intexists:boolcontent:str@register_data_source("file_info")classFileInfo(BaseDataSource):"""Reads information about a local file."""config_class=FileInfoConfigstate_class=FileInfoData@classmethoddefget_schema(cls)->PvsSchema:"""Define Terraform schema."""returns_data_source({# Input"path":a_str(required=True,description="File path to query"),# Outputs (all computed)"id":a_str(computed=True,description="File path as ID"),"size":a_num(computed=True,description="File size in bytes"),"exists":a_bool(computed=True,description="Whether file exists"),"content":a_str(computed=True,description="File content"),})asyncdefread(self,ctx:ResourceContext)->FileInfoData|None:"""Read file information."""ifnotctx.config:returnNonefile_path=Path(ctx.config.path)iffile_path.exists():content=file_path.read_text()size=file_path.stat().st_sizereturnFileInfoData(id=str(file_path.absolute()),path=str(file_path),size=size,exists=True,content=content,)else:returnFileInfoData(id=str(file_path.absolute()),path=str(file_path),size=0,exists=False,content="",)
terraform{required_providers{local={source="mycompany/local"}}}# Query file informationdata"local_file_info""readme"{path="../README.md"}# Use the data in outputsoutput"readme_exists"{value=data.local_file_info.readme.exists}output"readme_size"{value=data.local_file_info.readme.size}# Use data in a resourceresource"local_file""summary"{path="summary.txt"content=<<EOTREADME Information:- Exists: ${data.local_file_info.readme.exists}- Size: ${data.local_file_info.readme.size} bytesEOT}
Congratulations! You've built your first pyvider data source. You now understand:
✅ Data Sources vs Resources - Read-only queries vs managed infrastructure
✅ Simple Read Pattern - One method that returns data
✅ Input/Output Separation - Config for inputs, Data for outputs
✅ Deterministic IDs - Stable identification for query results
✅ Error Handling - Graceful handling of missing data