Team work and collaboration

Set team file-naming rules and check filenames with Python

Define a simple team filename convention, test it on a synthetic folder, and write a review report without renaming or deleting anything. The checker separates structural errors, invalid dates, and unsupported extensions.

Show contents

Who this is forThis guide is for teams that want predictable filenames and a simple automated check before files are shared or archived.

What you need
  • Python 3.12 and a terminal command that starts that version.
  • A working folder where the scripts can create folders beneath outputs.
  • Agreement on the project codes, document labels, version format, and allowed extensions your team will use.
  • Only the Python standard library is required: csv, datetime, pathlib, and re.

01Write the naming convention before writing the checker

This example uses the format YYYYMMDD_project_document_vNN.ext. The date is eight digits and must be a real calendar date. project and document use lowercase letters or digits, optionally separated by hyphens. The version is v followed by exactly two digits. The allowed extensions are pdf, docx, xlsx, csv, and txt.

text
YYYYMMDD_project_document_vNN.ext

Example:
20260920_alpha_test-plan_v01.pdf
  • Use the file's relevant work date as YYYYMMDD.
  • Use lowercase project and document tokens.
  • Use underscores only between the four main filename parts.
  • Use v01, v02, and so on for versions instead of final, latest, new, or revised.
  • Keep the original file extension and restrict it to an agreed list.

02Create a synthetic folder with valid and invalid names

The following filenames are synthetic and were written specifically for this article. Save the setup script as create_file_naming_demo.py. It creates eight empty files; four follow the rule and four deliberately violate it.

python
from pathlib import Path

SOURCE = Path("outputs") / "file_naming_demo"
FILENAMES = [
    "20260920_alpha_test-plan_v01.pdf",
    "20260920_alpha_results_v02.csv",
    "20260921_beta_meeting-notes_v03.txt",
    "20261001_beta_budget_v01.xlsx",
    "2026-09-20_alpha_notes_v01.txt",
    "20260920_Alpha_notes_v01.txt",
    "20260920_alpha_notes_final.txt",
    "20260230_beta_results_v01.csv",
]

SOURCE.parent.mkdir(parents=True, exist_ok=True)
SOURCE.mkdir()  # Stop if the synthetic source already exists.

for filename in FILENAMES:
    target = SOURCE / filename
    with target.open("xb"):
        pass

The first four names are expected to pass. The fifth uses a hyphenated date instead of YYYYMMDD. The sixth contains an uppercase project token. The seventh uses final instead of vNN. The eighth has the correct shape but contains the impossible date 2026-02-30.

03Classify the eight names by hand

FilenameExpected statusReason
20260920_alpha_test-plan_v01.pdfPASSMatches structure and date is valid
20260920_alpha_results_v02.csvPASSMatches structure and date is valid
20260921_beta_meeting-notes_v03.txtPASSMatches structure and date is valid
20261001_beta_budget_v01.xlsxPASSMatches structure and date is valid
2026-09-20_alpha_notes_v01.txtFAILSTRUCTURE_ERROR
20260920_Alpha_notes_v01.txtFAILSTRUCTURE_ERROR
20260920_alpha_notes_final.txtFAILSTRUCTURE_ERROR
20260230_beta_results_v01.csvFAILINVALID_DATE

The expected totals are therefore 8 files checked, 4 passes, and 4 failures. Three failures are structural and one has a structurally valid filename but an invalid calendar date.

04Check filenames without renaming them

Save the following script as check_file_names.py. It reads filenames only and writes a CSV report into a separate output folder. It does not rename, move, edit, or delete any source file.

python
import csv
import re
from datetime import datetime
from pathlib import Path

SOURCE = Path("outputs") / "file_naming_demo"
OUTPUT_DIR = Path("outputs") / "file_naming_result"
REPORT = OUTPUT_DIR / "file_naming_report.csv"
ALLOWED_EXTENSIONS = {"pdf", "docx", "xlsx", "csv", "txt"}

NAME_PATTERN = re.compile(
    r"^(?P<date>[0-9]{8})_"
    r"(?P<project>[a-z0-9]+(?:-[a-z0-9]+)*)_"
    r"(?P<document>[a-z0-9]+(?:-[a-z0-9]+)*)_"
    r"(?P<version>v[0-9]{2})\."
    r"(?P<extension>[a-z0-9]+)$"
)


def check_filename(filename: str) -> tuple[str, str]:
    match = NAME_PATTERN.fullmatch(filename)
    if match is None:
        return "FAIL", "STRUCTURE_ERROR"

    extension = match.group("extension")
    if extension not in ALLOWED_EXTENSIONS:
        return "FAIL", "UNSUPPORTED_EXTENSION"

    try:
        datetime.strptime(match.group("date"), "%Y%m%d")
    except ValueError:
        return "FAIL", "INVALID_DATE"

    return "PASS", ""


def main() -> None:
    if not SOURCE.is_dir():
        raise FileNotFoundError(f"Source folder not found: {SOURCE}")
    if OUTPUT_DIR.exists():
        raise FileExistsError(f"Output folder already exists: {OUTPUT_DIR}")

    files = sorted(path for path in SOURCE.iterdir() if path.is_file())
    results = []

    for path in files:
        status, issue = check_filename(path.name)
        results.append({
            "filename": path.name,
            "status": status,
            "issue": issue,
        })

    OUTPUT_DIR.parent.mkdir(parents=True, exist_ok=True)
    OUTPUT_DIR.mkdir()
    with REPORT.open("x", encoding="utf-8", newline="") as stream:
        writer = csv.DictWriter(
            stream,
            fieldnames=["filename", "status", "issue"],
        )
        writer.writeheader()
        writer.writerows(results)

    passed = sum(row["status"] == "PASS" for row in results)
    failed = len(results) - passed
    print(f"Files checked: {len(results)}.")
    print(f"Passed: {passed}; failed: {failed}.")
    print(f"Report: {REPORT.as_posix()}")


if __name__ == "__main__":
    main()
text
python check_file_names.py

05Compare the expected report

The report should contain one row for every source file. Because filenames are sorted alphabetically before checking, the output order follows the sorted names rather than the setup-script list.

Expected countValue
Files checked8
PASS4
FAIL4
STRUCTURE_ERROR3
INVALID_DATE1

The expected console output below was derived by hand from the synthetic filenames and checker. It is not a captured execution log.

text
Files checked: 8.
Passed: 4; failed: 4.
Report: outputs/file_naming_result/file_naming_report.csv

06Review failures before changing filenames

  • Confirm that all four intended valid names receive PASS.
  • Confirm that 20260230_beta_results_v01.csv is rejected even though its text shape matches the regex.
  • Decide who is allowed to rename shared files before correcting anything.
  • Check links, scripts, CAD references, document references, or shared-drive shortcuts that may depend on existing filenames.
  • Run the checker again without changing OUTPUT_DIR. It should stop with FileExistsError instead of replacing the previous report.
ProblemWhat to check
Many STRUCTURE_ERROR resultsConfirm that the written team rule matches the naming practice people actually use.
Uppercase or spaces appear frequentlyDecide whether to prohibit them consistently or revise the rule instead of fixing files ad hoc.
A valid-looking date failsCheck whether the YYYYMMDD text represents a real calendar date.
Users keep writing final or latestUse explicit version numbers and define when a file becomes approved or released separately.
Renaming breaks referencesDo not automate renaming until dependent systems and links have been assessed.

07Keep naming rules useful rather than overly complicated

A filename convention cannot replace proper version control, document management, or metadata. A file called v03 does not prove that it is newer in content than v02, approved by the correct person, or linked to the correct project.

The example checks files directly inside one folder only. It does not recursively scan subfolders, enforce uniqueness across multiple shared drives, check file contents, or verify that the project token corresponds to a real project.

When a team changes its convention, record the effective date and decide whether old files are grandfathered or renamed. A practical rule should be stable enough for people to remember and strict enough for automated checks to produce useful results.

Execution and verification record

2026-09-20 · hand-checked example · target: Python 3.12 · standard library: csv, datetime, pathlib, re · no execution

  • Manually classified 8 synthetic filenames as 4 valid and 4 invalid.
  • Identified three structural failures: the hyphenated date, uppercase project token, and final version label.
  • Confirmed by calendar reasoning that 2026-02-30 is invalid even though 20260230 matches the eight-digit date shape.
  • Manually derived expected totals of 4 PASS, 4 FAIL, 3 STRUCTURE_ERROR, and 1 INVALID_DATE.
  • Inspected the script for full filename matching, allowed-extension checking, calendar-date validation, output collision protection, and absence of rename or delete operations.
  • Derived the expected console output by hand.
Verification limits
  • The code was not executed by the author of this response; no files or reports were created.
  • Recursive folders, shared-drive links, case-insensitive filesystem behavior, cross-project uniqueness, and dependent application references were not tested.
  • The naming convention is an example team policy and should be changed to fit the actual workflow.
  • The official documentation URLs were provided from known documentation locations but were not checked live.

Site-wide writing and verification principles

References

The explanations and examples were written for this site. See the official sources below for the related behavior and concepts.