Stop Using f-strings for Everything! Meet t-string in Python 3.14

·

·

Stop Using f-strings for Everything

We have been using f-string since Python 3.6. We all love f-strings because they are fast and readable, but we know SQL injection is a problem if some lazy person concatenate all the strings together.

The Problem with f-strings

f-strings are amazing for printing messages like f"Hello, {name}!". How about the below SQL that Data Engineers always write:

query = f"SELECT * FROM users WHERE id = {user_id}"

Python instantly turns that into a raw string. By the time that string hits your database driver, the distinction between your safe SQL code and the potentially malicious user input is gone. It’s just text.

If you want to revision the tricks on f-string, vistis F-Strings Tricks You Didn’t Know.

t-string (PEP 750) in Python 3.14

Unlike an f-string, a t-string does not return a string. It returns a Template object. It is a “blueprint” of your string that keeps the static parts (the SQL keywords) separate from the dynamic parts (the user variables). This allows you to write a function that decides how to put them together safely.

user_id = 888

# Notice the 't' prefix
template = t"SELECT * FROM users WHERE id = {user_id}"

print(type(template))
print(template.strings)
print(template.interpolations)

Output:

<class 'string.templatelib.Template'>
('SELECT * FROM users WHERE id = ', '')
(Interpolation(888, 'user_id', None, ''),)

Avoid SQL Injection

If you are a Data Engineer, you’ve probably written code that looks like this:

# The "Old Way" - The Danger Zone
table_name = "sales_data"
date_filter = "2024-01-01"

# Using an f-string to build a query
df = spark.sql(f"SELECT * FROM {table_name} WHERE date >= '{date_filter}'")

The Pain Point is that if date_filter comes from a user-facing API (e.g., a dashboard filter), a malicious user could insert ' OR '1'='1, dumping your whole database.

You shouldn’t just pass a t-string to spark.sql() directly (Spark won’t understand it yet). Instead, you build a Processor Function. This function acts as a “Gatekeeper.”

Here is a coding example of how a Data Engineer should implement this:

# Python 3.14+ Conceptual Implementation
def safe_spark_sql(template):
    """
    A processor that converts a t-string into a secure Spark DataFrame.
    """
    query_parts = []
    
    # We iterate through the template components
    for part in template:
        if isinstance(part, str):
            # This is hardcoded SQL written by the developer. Safe.
            query_parts.append(part)
        else:
            # This is dynamic input. We need to sanitize it.
            val = part.value
            
            # Simple validation: Ensure no semicolons or comment dashes
            if isinstance(val, str) and (";" in val or "--" in val):
                raise ValueError(f"Potential SQL Injection detected in value: {val}")
            
            # Add quotes for string literals automatically
            query_parts.append(f"'{val}'")

    final_query = "".join(query_parts)
    print(f"Executing Secure Query: {final_query}") 
    return final_query

# --- Usage ---
# Imagine 'user_input' comes from a web form
user_input = "2024-01-01' DROP TABLE sales; --" 

# The t-string keeps the structure separate from the data
try:
    safe_sql = safe_spark_sql(t"SELECT * FROM sales WHERE date = {user_input}")
except ValueError as e:
    print(f"Blocked Attack: {e}")

Output:

Blocked Attack: Potential SQL Injection detected in value: 2024-01-01' DROP TABLE sales; --

Use t-strings to create an abstraction layer. It forces you to think about which parts of your query are static (safe) and which are dynamic (risky). It is essentially “Parameterized Queries” but for logic where native driver parameterization (like JDBC) might be limited or clumsy to implement in PySpark.

Final Through

As Data and AI Engineers, we handle the most valuable commodity in the world: Data.

For years, we’ve sacrificed security for the convenience of f-strings, or sacrificed readability for the safety of prepared statements. The proposed t-strings in Python offer the best of both worlds. They allow us to write code that looks simple but acts securely.