AI refactoring without disclosure
The workflow this page exists for: your code needs an outside pair of eyes, a review, a refactoring, a bug hunt, and the outside pair of eyes is a language model you are not allowed or not willing to show the code to. So you show it the code minus everything that makes it yours. Anonymize here, paste the result into ChatGPT or Claude, let it rewrite as much as it wants, paste the reply into restore mode, and read the answer in your own vocabulary. The model does its work on func_3 and var_7. Your browser, and only your browser, knows those are calculate_payout and sepa_batch.
The same round trip covers the older cases too, the forum question about proprietary code and the snippet for a consultant without an NDA in place yet.
What becomes mod_1, what stays print
Anonymizing Python only works if the shared vocabulary survives. A snippet where len and requests.get have been renamed is unreadable to any helper, human or model. The line the tool draws is ownership, and it reads that line off the imports.
- Keywords, builtins like
printandisinstance, and dunder names such as__init__stay. - The standard library and a few hundred recognized packages stay whole:
os.path.join,datetime.timedelta,pd.read_csv,Flask,BaseModel, along with every name imported from them. - Everything you wrote gets a role-named placeholder. Classes become
Class1, functionsfunc_2, attributesattr_3, variablesvar_4, parametersparam_5, constantsCONST_6. - Project imports go as a unit.
from app.models import Invoicebecomesfrom mod_1.mod_2 import Class1, andInvoiceisClass1everywhere below.
So a Flask route keeps @bp.route readable while the blueprint variable, the URL string and your handler's name are gone. The recipient can tell it is Flask code with a decorated route, which is what makes their answer useful, and cannot tell it is your billing system.
f-strings keep their expressions
Strings are where Python code carries its data, and f-strings mix that data with live code. The tool splits them the way the interpreter does. Literal text pieces are masked, the expressions inside the braces stay code and get the same treatment as the rest of the file, and format specs survive untouched.
f"{customer.company_name} owes {total:.2f} EUR" comes out as f"{var_1.attr_4} str_2 {var_5:.2f} str_3". Still a valid f-string, still obviously a formatted message with a two-decimal number in it, and neither the attribute chain nor the phrasing of your dunning email is left. The :.2f spec is syntax and stays.
Plain literals are masked as 'str_1' unless they are syntax in disguise. File modes, encodings, HTTP methods and strftime patterns work like keywords, so open(p, "rb") and strftime("%Y-%m") stay as written and the findings line says so. Separator-only literals like ", " stay too.
The key never travels
Each replacement lands in the key as placeholder, original and role. The key is stored in this site's localStorage, filled per language, and read again on your next visit. It is not sent anywhere, there is nothing to create an account for, and clearing it takes a deliberate double click.
Persistence is what makes it practical. Paste three files from the same project over a week and PayoutService is Class2 in all of them, so an answer referring to several files restores in one go. To hand the restore ability to someone else, download the key as JSON and send it separately from the code.
One caveat worth spelling out: on a shared machine the key sits in the browser profile until someone resets it.
Placeholders do not hide structure
A tokenizer with role heuristics is not a type checker. A name it has never seen in a defining position is judged by shape and context, which very occasionally files a class as a function. That costs nothing on the round trip, the mapping stays exact either way.
What no renaming can remove is the architecture. A class with overdue_invoices replaced still shows a loop over a collection filtered by two conditions, and someone who knows the domain may read the intent from the shape alone. For most code that residual signal is acceptable. For an algorithm that is itself the trade secret, the honest answer is to not share it, anonymized or otherwise.
Sharing Python without oversharing
Is it safe to paste company code into ChatGPT?
Treat it like pasting it into an email to a stranger. Consumer chat products may store conversations, humans may review them, and depending on plan and settings the text can feed future training. Company policy usually forbids it outright for unreleased code. The workable middle ground is to strip what makes the code yours, the names, the strings, the comments, before it goes in, and that is what this page automates.
How do I anonymize Python code before sharing it?
Replace your identifiers with neutral ones, mask string literals, delete comments and docstrings, and keep the mapping so the answer can be translated back. Paste the file above and all four happen in one pass, in the browser, with a key for the reverse direction.
Will anonymized Python still run?
Yes for the names, they are valid identifiers replaced consistently. Masked strings change behavior at runtime, so tests need the restored version.
Are variable and function names really confidential?
A single one rarely is. Two hundred of them together are a map of the product: calculate_churn_risk, PayoutBatch, legacy_sap_export. Names are how code carries business context, which is exactly why sharing them can say more than you intended.
What is the difference between anonymizing and obfuscating Python?
Direction and audience. An obfuscator like PyArmor protects shipped code from its recipient and makes it deliberately unreadable. An anonymizer keeps the code perfectly readable and only detaches it from your project, reversibly, so a reviewer or a model can still work with it.
Do comments and docstrings leak information?
Usually more per line than the code. They name customers, tickets, deadlines and the feature the module is for. This is why comments are dropped by default here.
Can an AI model refactor code when all the names are placeholders?
Yes. Control flow, types, library calls and structure are what a model reasons over, and those all survive. The price is that advice tied to naming, say spotting that a function does something other than its name claims, is off the table. We consider that a fair trade for code under NDA.
What does an import line reveal about a codebase?
from app.services.payout import SepaExporter names a payments domain, a service layer and a banking format before any logic. Project imports deserve placeholders too.
How do I keep API keys and secrets out of shared code?
Secrets belong in the environment, not in source, so os.environ['STRIPE_KEY'] is already the right pattern and survives anonymizing with only the variable name masked. Hardcoded secrets are caught by the string masking, and long numeric literals are flagged separately since ids and account numbers hide there. Rotate anything that already escaped.