Claude Code for stat: Python File Status Flag Interpretation — Claude Skills 360 Blog
Blog / AI / Claude Code for stat: Python File Status Flag Interpretation
AI

Claude Code for stat: Python File Status Flag Interpretation

Published: December 9, 2028
Read time: 5 min read
By: Claude Skills 360

Python’s stat module provides symbolic constants and helper functions for interpreting os.stat() result objects and POSIX file mode bits. import stat. Type tests: stat.S_ISREG(mode), stat.S_ISDIR(mode), stat.S_ISLNK(mode), stat.S_ISSOCK(mode), stat.S_ISBLK(mode), stat.S_ISCHR(mode), stat.S_ISFIFO(mode) — each takes an st_mode integer (from os.stat().st_mode) and returns a bool. Extract bits: stat.S_IFMT(mode) → file type bits; stat.S_IMODE(mode) → permission bits (lower 12 bits). Permission constants: stat.S_IRUSR (0o400), stat.S_IWUSR (0o200), stat.S_IXUSR (0o100), stat.S_IRGRP, stat.S_IWGRP, stat.S_IXGRP, stat.S_IROTH, stat.S_IWOTH, stat.S_IXOTH. Special bits: stat.S_ISUID (setuid), stat.S_ISGID (setgid), stat.S_ISVTX (sticky). Index constants: stat.ST_MODE, stat.ST_INO, stat.ST_DEV, stat.ST_NLINK, stat.ST_UID, stat.ST_GID, stat.ST_SIZE, stat.ST_ATIME, stat.ST_MTIME, stat.ST_CTIME — use when indexing os.stat() as a tuple. Format: stat.filemode(mode)"-rwxr-xr-x" string. Claude Code generates permission checkers, file type routers, directory walkers, and mode formatting utilities.

CLAUDE.md for stat

## stat Stack
- Stdlib: import stat, os
- Mode:   st = os.stat(path); mode = st.st_mode
- Type:   stat.S_ISREG(mode)   stat.S_ISDIR(mode)   stat.S_ISLNK(mode)
- Perms:  bool(mode & stat.S_IRUSR)  # readable by owner
-         stat.S_IMODE(mode)          # permission bits (0o755)
- Format: stat.filemode(mode)         # "-rwxr-xr-x"
- Set:    os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)

stat File Mode Pipeline

# app/statutil.py — mode parsing, permission checks, chmod helpers, walker
from __future__ import annotations

import os
import stat
from dataclasses import dataclass
from pathlib import Path
from typing import Iterator


# ─────────────────────────────────────────────────────────────────────────────
# 1. File type helpers
# ─────────────────────────────────────────────────────────────────────────────

def file_type(mode: int) -> str:
    """
    Return a human-readable file type string for a mode integer.

    Example:
        st = os.stat("/etc/hosts")
        print(file_type(st.st_mode))   # "regular file"
    """
    tests = [
        (stat.S_ISREG,  "regular file"),
        (stat.S_ISDIR,  "directory"),
        (stat.S_ISLNK,  "symlink"),
        (stat.S_ISSOCK, "socket"),
        (stat.S_ISBLK,  "block device"),
        (stat.S_ISCHR,  "char device"),
        (stat.S_ISFIFO, "FIFO/pipe"),
    ]
    for fn, name in tests:
        if fn(mode):
            return name
    return "unknown"


def is_executable(path: "str | Path") -> bool:
    """
    Return True if any executable bit (user/group/other) is set.

    Example:
        if is_executable("/usr/bin/python3"):
            print("it's executable")
    """
    mode = os.stat(str(path)).st_mode
    return bool(mode & (stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH))


def is_world_writable(path: "str | Path") -> bool:
    """
    Return True if the 'other write' bit is set (world-writable).

    Example:
        if is_world_writable("/tmp/shared"):
            print("WARNING: world-writable")
    """
    mode = os.stat(str(path)).st_mode
    return bool(mode & stat.S_IWOTH)


def has_setuid(path: "str | Path") -> bool:
    """Return True if the setuid bit is set."""
    return bool(os.stat(str(path)).st_mode & stat.S_ISUID)


def has_sticky(path: "str | Path") -> bool:
    """Return True if the sticky bit is set."""
    return bool(os.stat(str(path)).st_mode & stat.S_ISVTX)


# ─────────────────────────────────────────────────────────────────────────────
# 2. Permission inspection
# ─────────────────────────────────────────────────────────────────────────────

@dataclass
class PermissionBits:
    """
    Parsed POSIX permission bits for a file.

    Example:
        bits = PermissionBits.from_path("/etc/passwd")
        print(bits)
        if bits.world_writable:
            print("SECURITY RISK")
    """
    mode:  int
    path:  str = ""

    @classmethod
    def from_path(cls, path: "str | Path") -> "PermissionBits":
        p = Path(path)
        return cls(mode=p.stat().st_mode, path=str(p))

    @classmethod
    def from_mode(cls, mode: int) -> "PermissionBits":
        return cls(mode=mode)

    @property
    def octal(self) -> str:
        return oct(stat.S_IMODE(self.mode))

    @property
    def string(self) -> str:
        return stat.filemode(self.mode)

    @property
    def owner_read(self) -> bool:
        return bool(self.mode & stat.S_IRUSR)

    @property
    def owner_write(self) -> bool:
        return bool(self.mode & stat.S_IWUSR)

    @property
    def owner_exec(self) -> bool:
        return bool(self.mode & stat.S_IXUSR)

    @property
    def group_read(self) -> bool:
        return bool(self.mode & stat.S_IRGRP)

    @property
    def group_write(self) -> bool:
        return bool(self.mode & stat.S_IWGRP)

    @property
    def group_exec(self) -> bool:
        return bool(self.mode & stat.S_IXGRP)

    @property
    def other_read(self) -> bool:
        return bool(self.mode & stat.S_IROTH)

    @property
    def other_write(self) -> bool:
        return bool(self.mode & stat.S_IWOTH)

    @property
    def other_exec(self) -> bool:
        return bool(self.mode & stat.S_IXOTH)

    @property
    def world_writable(self) -> bool:
        return self.other_write

    @property
    def setuid(self) -> bool:
        return bool(self.mode & stat.S_ISUID)

    @property
    def setgid(self) -> bool:
        return bool(self.mode & stat.S_ISGID)

    @property
    def sticky(self) -> bool:
        return bool(self.mode & stat.S_ISVTX)

    def __str__(self) -> str:
        flags = []
        if self.setuid:
            flags.append("SETUID")
        if self.setgid:
            flags.append("SETGID")
        if self.sticky:
            flags.append("STICKY")
        if self.world_writable:
            flags.append("WORLD-WRITABLE")
        flags_str = f"  [{' '.join(flags)}]" if flags else ""
        return f"{self.string}  {self.octal}{flags_str}"


# ─────────────────────────────────────────────────────────────────────────────
# 3. chmod helpers
# ─────────────────────────────────────────────────────────────────────────────

def chmod_octal(path: "str | Path", mode: str) -> None:
    """
    Set file permissions using an octal string (e.g. "0o644", "644", "755").

    Example:
        chmod_octal("script.sh", "755")
        chmod_octal("config.ini", "0o640")
    """
    if isinstance(mode, str):
        mode_int = int(mode, 8) if not mode.startswith("0o") else int(mode, 0)
    else:
        mode_int = mode  # type: ignore[assignment]
    os.chmod(str(path), mode_int)


def make_executable(path: "str | Path") -> None:
    """
    Add the executable bit for owner (u+x) to a file.

    Example:
        make_executable("deploy.sh")
    """
    p = Path(path)
    current = p.stat().st_mode
    p.chmod(current | stat.S_IXUSR)


def remove_world_write(path: "str | Path") -> None:
    """
    Remove the world-writable bit (o-w) from a file.

    Example:
        remove_world_write("/etc/cron.d/myjob")
    """
    p = Path(path)
    current = p.stat().st_mode
    p.chmod(current & ~stat.S_IWOTH)


# ─────────────────────────────────────────────────────────────────────────────
# 4. Security audit walker
# ─────────────────────────────────────────────────────────────────────────────

@dataclass
class SecurityIssue:
    path: str
    issue: str
    mode_str: str


def audit_permissions(root: "str | Path", follow_symlinks: bool = False) -> list[SecurityIssue]:
    """
    Walk root and report files with dangerous permission settings:
    world-writable, setuid, setgid on regular files.

    Example:
        issues = audit_permissions("/etc")
        for issue in issues:
            print(f"  {issue.path}: {issue.issue} ({issue.mode_str})")
    """
    issues: list[SecurityIssue] = []
    for dirpath, dirs, files in os.walk(str(root)):
        for name in list(dirs) + files:
            full = os.path.join(dirpath, name)
            try:
                st = os.lstat(full) if not follow_symlinks else os.stat(full)
            except OSError:
                continue
            mode = st.st_mode
            mode_str = stat.filemode(mode)
            if stat.S_ISREG(mode) and (mode & stat.S_IWOTH):
                issues.append(SecurityIssue(full, "world-writable", mode_str))
            if stat.S_ISREG(mode) and (mode & stat.S_ISUID):
                issues.append(SecurityIssue(full, "setuid", mode_str))
            if stat.S_ISREG(mode) and (mode & stat.S_ISGID):
                issues.append(SecurityIssue(full, "setgid", mode_str))
    return issues


# ─────────────────────────────────────────────────────────────────────────────
# 5. stat result formatter
# ─────────────────────────────────────────────────────────────────────────────

def format_stat(path: "str | Path") -> dict:
    """
    Return a human-readable dict of os.stat() fields for a path.

    Example:
        info = format_stat("/etc/hosts")
        for k, v in info.items():
            print(f"  {k}: {v}")
    """
    import datetime
    p = Path(path)
    st = p.stat()
    mode = st.st_mode
    return {
        "path":     str(p),
        "type":     file_type(mode),
        "mode":     stat.filemode(mode),
        "octal":    oct(stat.S_IMODE(mode)),
        "size":     st.st_size,
        "uid":      st.st_uid,
        "gid":      st.st_gid,
        "nlink":    st.st_nlink,
        "mtime":    datetime.datetime.fromtimestamp(st.st_mtime).isoformat(timespec="seconds"),
        "atime":    datetime.datetime.fromtimestamp(st.st_atime).isoformat(timespec="seconds"),
    }


# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────

if __name__ == "__main__":
    import tempfile

    print("=== stat demo ===")

    with tempfile.TemporaryDirectory() as td:
        # ── create test files ──────────────────────────────────────────────────
        regular = Path(td) / "data.txt"
        regular.write_text("hello")
        script = Path(td) / "run.sh"
        script.write_text("#!/bin/sh\necho hi\n")
        subdir = Path(td) / "subdir"
        subdir.mkdir()

        # ── file_type ──────────────────────────────────────────────────────────
        print("\n--- file_type ---")
        for p in [regular, subdir]:
            mode = os.stat(p).st_mode
            print(f"  {p.name}: {file_type(mode)}")

        # ── PermissionBits ─────────────────────────────────────────────────────
        print("\n--- PermissionBits ---")
        bits = PermissionBits.from_path(regular)
        print(f"  {regular.name}: {bits}")
        print(f"  owner_read={bits.owner_read}  owner_write={bits.owner_write}")
        print(f"  world_writable={bits.world_writable}")

        # ── chmod_octal + make_executable ─────────────────────────────────────
        print("\n--- chmod ---")
        chmod_octal(regular, "644")
        print(f"  after chmod 644: {stat.filemode(os.stat(regular).st_mode)}")
        make_executable(script)
        print(f"  after u+x: {stat.filemode(os.stat(script).st_mode)}")

        # ── format_stat ───────────────────────────────────────────────────────
        print("\n--- format_stat ---")
        info = format_stat(regular)
        for k, v in info.items():
            print(f"  {k}: {v}")

        # ── world-writable audit ──────────────────────────────────────────────
        print("\n--- audit_permissions ---")
        os.chmod(regular, 0o666)   # make world-writable
        issues = audit_permissions(td)
        for issue in issues:
            rel = Path(issue.path).name
            print(f"  {rel}: {issue.issue} ({issue.mode_str})")

        # ── stat constants ────────────────────────────────────────────────────
        print("\n--- common mode constants ---")
        for name in ["S_IRUSR", "S_IWUSR", "S_IXUSR", "S_IRGRP", "S_IROTH", "S_ISUID", "S_ISVTX"]:
            val = getattr(stat, name)
            print(f"  stat.{name} = {oct(val)}")

    print("\n=== done ===")

For the pathlib.Path.stat() / pathlib.Path.chmod() alternative — Path.stat() returns the same os.stat_result as os.stat(), and Path.chmod(mode) sets permissions — use pathlib for the object-oriented API when you already have a Path object; import stat for the mode constants and helper functions (S_ISREG, filemode, etc.) regardless — they are complementary, not alternatives. For the os.access alternative — os.access(path, os.R_OK | os.W_OK) checks the effective UID’s permissions (honours setuid/setgid) rather than raw mode bits — use os.access when you need to know if the current process can actually read or write a file; use stat when you need to inspect or set the raw permission bits regardless of effective UID. The Claude Skills 360 bundle includes stat skill sets covering file_type()/is_executable()/is_world_writable()/has_setuid()/has_sticky() mode tests, PermissionBits with all owner_*/group_*/other_* properties and world_writable/setuid/sticky, chmod_octal()/make_executable()/remove_world_write() permission setters, audit_permissions() security walker returning SecurityIssue records, and format_stat() human-readable stat dict. Start with the free tier to try file mode patterns and stat pipeline code generation.

Keep Reading

AI

Claude Code for email.contentmanager: Python Email Content Accessors

Read and write EmailMessage body content with Python's email.contentmanager module and Claude Code — email contentmanager ContentManager for the class that maps content types to get and set handler functions allowing EmailMessage to support get_content and set_content with type-specific behaviour, email contentmanager raw_data_manager for the ContentManager instance that handles raw bytes and str payloads without any conversion, email contentmanager content_manager for the standard ContentManager instance used by email.policy.default that intelligently handles text plain text html multipart and binary content types, email contentmanager get_content_text for the handler that returns the decoded text payload of a text-star message part as a str, email contentmanager get_content_binary for the handler that returns the raw decoded bytes payload of a non-text message part, email contentmanager get_data_manager for the get-handler lookup used by EmailMessage get_content to find the right reader function for the content type, email contentmanager set_content text for the handler that creates and sets a text part correctly choosing charset and transfer encoding, email contentmanager set_content bytes for the handler that creates and sets a binary part with base64 encoding and optional filename Content-Disposition, email contentmanager EmailMessage get_content for the method that reads the message body using the registered content manager handlers, email contentmanager EmailMessage set_content for the method that sets the message body and MIME headers in one call, email contentmanager EmailMessage make_alternative make_mixed make_related for the methods that convert a simple message into a multipart container, email contentmanager EmailMessage add_attachment for the method that attaches a file or bytes to a multipart message, and email contentmanager integration with email.message and email.policy and email.mime and io for building high-level email readers attachment extractors text body accessors HTML readers and policy-aware MIME construction pipelines.

5 min read Feb 12, 2029
AI

Claude Code for email.charset: Python Email Charset Encoding

Control header and body encoding for international email with Python's email.charset module and Claude Code — email charset Charset for the class that wraps a character set name with the encoding rules for header encoding and body encoding describing how to encode text for that charset in email messages, email charset Charset header_encoding for the attribute specifying whether headers using this charset should use QP quoted-printable encoding BASE64 encoding or no encoding, email charset Charset body_encoding for the attribute specifying the Content-Transfer-Encoding to use for message bodies in this charset such as QP or BASE64, email charset Charset output_codec for the attribute giving the Python codec name used to encode the string to bytes for the wire format, email charset Charset input_codec for the attribute giving the Python codec name used to decode incoming bytes to str, email charset Charset get_output_charset for returning the output charset name, email charset Charset header_encode for encoding a header string using the charset's header_encoding method, email charset Charset body_encode for encoding body content using the charset's body_encoding, email charset Charset convert for converting a string from the input_codec to the output_codec, email charset add_charset for registering a new charset with custom encoding rules in the global charset registry, email charset add_alias for adding an alias name that maps to an existing registered charset, email charset add_codec for registering a codec name mapping for use by the charset machinery, and email charset integration with email.message and email.mime and email.policy and email.encoders for building international email senders non-ASCII header encoders Content-Transfer-Encoding selectors charset-aware message constructors and MIME encoding pipelines.

5 min read Feb 11, 2029
AI

Claude Code for email.utils: Python Email Address and Header Utilities

Parse and format RFC 2822 email addresses and dates with Python's email.utils module and Claude Code — email utils parseaddr for splitting a display-name plus angle-bracket address string into a realname and email address tuple, email utils formataddr for combining a realname and address string into a properly quoted RFC 2822 address with angle brackets, email utils getaddresses for parsing a list of raw address header strings each potentially containing multiple comma-separated addresses into a list of realname address tuples, email utils parsedate for parsing an RFC 2822 date string into a nine-tuple compatible with time.mktime, email utils parsedate_tz for parsing an RFC 2822 date string into a ten-tuple that includes the UTC offset timezone in seconds, email utils parsedate_to_datetime for parsing an RFC 2822 date string into an aware datetime object with timezone, email utils formatdate for formatting a POSIX timestamp or the current time as an RFC 2822 date string with optional usegmt and localtime flags, email utils format_datetime for formatting a datetime object as an RFC 2822 date string, email utils make_msgid for generating a globally unique Message-ID string with optional idstring and domain components, email utils decode_rfc2231 for decoding an RFC 2231 encoded parameter value into a tuple of charset language and value, email utils encode_rfc2231 for encoding a string as an RFC 2231 encoded parameter value, email utils collapse_rfc2231_value for collapsing a decoded RFC 2231 tuple to a Unicode string, and email utils integration with email.message and email.headerregistry and datetime and time for building address parsers date formatters message-id generators header extractors and RFC-compliant email construction utilities.

5 min read Feb 10, 2029

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free