Usage

Installation

To use Msort, first install it using pip:

$ pip install msort

Alternatively, use msort as a pre-commit hook - Pre-commit.

Command Line Usage

This section documents msort’s command line interface.

Input code

You can specify which python files should be checked by passing in the paths:

$ msort foo.py bar.py

The code to be checked can be supplied in a couple of other ways:

-ip INPUT-PATH, --input-path INPUT-PATH

If the input path is a .py file then only that code will be checked. If the input path is a directory or module, then msort will recursively check all code under the path.

-sp SKIP-PATTERNS --skip-patterns SKIP-PATTERNS

Use the --skip-patterns option to indicate exclusion criteria. If the supplied pattern is found in a .py then it will not be checked. To supply multiple patterns, use the option multiple times.

$ msort –sp pat1 –sp pat2

Output code

By default, msort will modify the original code but this behaviour can be modified using the --output-path option:

-o OUTPUT-PATH, --output-path OUTPUT-PATH

If the output path and input path are singular .py file then only that code will be checked and the modified code will be written to the supplied output path, creating a new file if needed. If the output path is a directory, then the modified code will be saved to a .py file with the same name as the input but in the newly created output directory. If the output path is a single .py file but the input path is a directory, then an exception will be raised.

Custom configurations

Default configurations regarding the preferred order of methods is built into msort.

The defaults can be overridden by using a configuration file - see Configurations.

If the configuration file has a non-standard name (i.e. not msort.ini or pyproject.toml) then the path can be specified using the --config-path option.

-cp CONFIG-PATH, --config-path CONFIG-PATH

This should be the relative path to a .ini or .toml file from which msort configurations can be loaded.

Msort configurations can also be overridden on the command line. Any field defined in the configuration file can be re-defined on the command line.

Class component ordering preferences can set on the command line - Components :

$ msort file.py --private-method=3 --dunder-method=12

This snippet would swap the default ordering of dunder methods and private methods.

Note, if you set multiple components to have the same sorting level then they will be sorted alphabetically.

Non-sorting parameters which are normally set in the configuration file can also be set on the command line.

--auto-static AUTO-STATIC

Check if a method could be made static and convert it if so (Default).

--n-auto-static N-AUTO-STATIC

Do not check for possible static methods.

--use-msort-group USE-MSORT-GROUP

Account for the msort_group() decorator during method sorting (Default). See Import Usage.

--n-use-msort-group N-USE-MSORT-GROUP

Do not account for the msort_group() decorator during method sorting.

--use-property-groups USE-PROPERTY-GROUPS

Group methods related to a class property together.

--n-use-property-groups N-USE-PROPERTY-GROUPS

Do not group methods related to a class property together (Default).

Alternative modes

Msort can be executed in alternative modes which do not modify the code.

--check CHECK

Runs msort and reports on the number of files which would be modified.

--diff DIFF

Runs msort and reports on the differences which would be made.

Misc

-v VERBOSE, --verbose VERBOSE

Modify the logging level of msort. 0 - no logging output 1 - warnings and info 2 - debug level

-p PARSER, --parser PARSER

Specify whether to use the AST or CST code parser. Defaults to CST parser and this is recommended.

See Parsing for more details.

-f FORCE, --force FORCE

Force msort to allow manual override of sorting levels such that Methods can be sorted with higher precedence than Fixed components.

Import Usage

Msort introduces the msort_group decorator which can be used to force a group of methods to be placed together by msort.

This decorator can be useful if you have a complex class with subsets of related methods.

Lets work through an example:

class Dog:
   def __init__(self, name: str, color: str, owner: str) -> None:
       self.name = name
       self.color = color
       self.owner = owner

   @msort_group(group="movement")
   def run(self) -> None:
       print("The dog is running!")

   @staticmethod
   @msort_group(group="sound")
   def whimper() -> None:
       print("The dog is whimpering!")

   @msort_group(group="sound")
   def growling(self) -> None:
       print("The dog is growling!")

   @msort_group(group="movement")
   def walk(self) -> None:
       print("The dog is walking!")

   @msort_group(group="movement")
   def wag(self) -> None:
       print("The dog is wagging its tail!")

   @msort_group(group="sound")
   def bark(self) -> None:
       print("The dog is barking!")

   @msort_group(group="describe")
   def describe(self) -> None:
       print(f"The {self.color} dog called {self.name} is owned by {self.owner}")

   @msort_group(group="describe")
   def color_of_dog(self) -> None:
       print(f"The dog is {self.color}")

In this example, the Dog class uses the msort_group decorator to define three method groups: movement, sound and describe.

Msort will interpret the msort_group decorator and sort the methods by the group name, then by any additional sorting parameter and then alphabetically by name.

class Dog:
   def __init__(self, name: str, color: str, owner: str) -> None:
       self.name = name
       self.color = color
       self.owner = owner

   @msort_group(group="describe")
   def color_of_dog(self) -> None:
       print(f"The dog is {self.color}")

   @msort_group(group="describe")
   def describe(self) -> None:
       print(f"The {self.color} dog called {self.name} is owned by {self.owner}")

   @msort_group(group="movement")
   def run(self) -> None:
       print("The dog is running!")

   @msort_group(group="movement")
   def wag(self) -> None:
       print("The dog is wagging its tail!")

   @msort_group(group="movement")
   def walk(self) -> None:
       print("The dog is walking!")

   @staticmethod
   @msort_group(group="sound")
   def whimper() -> None:
       print("The dog is whimpering!")

   @msort_group(group="sound")
   def bark(self) -> None:
       print("The dog is barking!")

   @msort_group(group="sound")
   def growling(self) -> None:
       print("The dog is growling!")

In the msort formatted Dog class, the methods are sorted by group with the describe group first, then the movement group and finally the sound group. Also notice that sorting withing groups is alphabetical, except whimper() which is the first sound group method as it also has the @staticmethod decorator, affording it a higher rank than the other instance methods. See Components for default ranks.