Skip to main content

prettycsharp

PyPI version Python versions Downloads CI Security Malware scan OpenSSF Scorecard License: MIT

An opinionated formatter for C#, written in Python, in the spirit of Prettier. It parses each file with tree-sitter and reprints the whole file in one consistent layout: braces, indentation, line breaks, blank lines, alignment and a few safe rewrites such as file-scoped namespaces, sorted usings and expression-bodied members. It needs no .NET SDK.

Before:

using System;
using Microsoft.Extensions.Logging;
namespace Shop.Orders {
public class OrderService {
    static private readonly int MaxRetries=3;
    public decimal Total(Order order) { return order.Lines.Where(l => l.IsTaxable).Sum(l => l.Amount); }
    public void Ship(Order order) {
        if (order == null) return;
        if (order.IsPaid) { Send(order); } else { Hold(order); }
    }
}
}

After:

using Microsoft.Extensions.Logging;
using System;

namespace Shop.Orders;

public class OrderService
{
    private static readonly int MaxRetries = 3;

    public decimal Total(Order order) =>
        order.Lines
            .Where(l => l.IsTaxable)
            .Sum(l => l.Amount);

    public void Ship(Order order)
    {
        if (order == null) return;

        if (order.IsPaid)
        {
            Send(order);
        }

        else
        {
            Hold(order);
        }
    }
}

Install

Python 3.10 or later.

pip install prettycsharp

Use

prettycsharp format src/
prettycsharp check src/
prettycsharp diff Order.cs

format rewrites files in place, check exits 1 when any file would change, and diff prints a unified diff. --write, --check and --diff are aliases. Given one file and no command, the formatted file goes to stdout; - formats stdin to stdout, with --stdin-filepath naming the path whose settings apply.

A target can be a .cs file, a folder, a .csproj (the files it compiles, after its Compile Include and Remove items) or a .sln or .slnx (every C# project in it). Folders are searched for .cs files.

Option Meaning
-o KEY=VALUE, --option Set one setting, over every settings file. Repeatable.
--config FILE Use this settings file instead of searching for one.
--no-ignore Do not skip what .gitignore and .prettycsharpignore list.
--stdin-filepath PATH The path stdin stands for.

Exit status: 0 when nothing needs to change, 1 when check or diff found a file that would change, 2 when a file could not be read, parsed or formatted, or a setting is wrong. A file that does not parse is reported and left untouched.

From Python:

from prettycsharp import CSharpSyntaxError, FormattingError, Settings, format_source

formatted = format_source(source)
narrow = format_source(source, Settings().with_values({"max_line_length": 100}))

Settings

Settings come from, highest precedence first:

  1. -o options on the command line;
  2. the nearest .prettycsharp.toml, or pyproject.toml with a [tool.prettycsharp] table, found by walking up from each file;
  3. the standard keys of .editorconfig (indent_style, indent_size, max_line_length, end_of_line, charset, insert_final_newline, and the Roslyn keys for braces, else/catch/finally placement, using order, namespace style, braces and modifier order);
  4. the defaults.
# .prettycsharp.toml
max_line_length = 100
brace_style = "kr"
continuation_keywords = "same_line"
align_assignments = false

Every setting, its default, its alternatives and an example of each layout are in DESIGN.md.

Skipping files and code

bin/, obj/, hidden folders and generated files (*.g.cs, *.Designer.cs, and files marked <auto-generated>) are always skipped. So is whatever .gitignore lists inside a git repository, and whatever a .prettycsharpignore file lists, in gitignore syntax.

Inside a file, // prettycsharp-ignore leaves the next statement or member as written, and // prettycsharp-ignore-start ... // prettycsharp-ignore-end leaves everything between them as written.

How it stays safe

Every output is parsed again and compared with the input as syntax trees, with only the changes the settings allow (parentheses, modifier and using order, attribute lists, trailing commas, expression bodies, namespace style, braces and regions) taken out of the comparison. The comments must hold the same words. If anything else differs, the file is not changed and the command reports the difference. String literals, including verbatim, raw and interpolated strings, are printed exactly as written.

Limits

prettycsharp reads C# through tree-sitter's C# grammar, which parses every #if branch as code. A declaration or statement split between #if and #else therefore does not parse, and neither does syntax newer than the grammar (such as C# 14's null-conditional assignment). Such files are reported with their line and column and left untouched.

License

MIT

Metadata

Release files for prettycsharp 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for prettycsharp 1.0.0
File Size Uploaded
prettycsharp-1.0.0.tar.gz 167.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for prettycsharp 1.0.0
File Interpreter ABI Platform
prettycsharp-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 234.1 kB

Release files / prettycsharp-1.0.0.tar.gz

Download URL prettycsharp-1.0.0.tar.gz
Size 167.1 kB
Tags Source
SHA-256 checksum
How to use checksums
801b26a057509d53253dd0c2bd0325048ca4afc102e2227d93aca9e2f5116fc0
BLAKE2b-256 checksum
How to use checksums
bc270f5cdd450dc4a9b11616575bbd4729c5bcb064c23189fc0ac0f208a85001
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.

Transparency log

Release files / prettycsharp-1.0.0-py3-none-any.whl

Download URL prettycsharp-1.0.0-py3-none-any.whl
Size 67.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
00153324bd051456e506f3011bfc148084af141e32f44c33ff457cba9f9d4fdf
BLAKE2b-256 checksum
How to use checksums
351568906a0a3d460694f178f613d2d86dd12234788caf46b34b49946997d050
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.

Transparency log

Release history Release notifications | RSS feed

1.1.9

2 release files

1.1.8

2 release files

1.1.7

2 release files

1.1.6

2 release files

1.1.5

2 release files

1.1.4

2 release files

1.1.3

2 release files

1.1.2

2 release files

1.1.1

2 release files

1.1.0

2 release files

This release

1.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page