{"id":13501342,"url":"https://github.com/bwhmather/ssort","last_synced_at":"2026-03-11T15:02:49.236Z","repository":{"id":40418751,"uuid":"349165135","full_name":"bwhmather/ssort","owner":"bwhmather","description":"Tool for automatically sorting python statements within a module","archived":false,"fork":false,"pushed_at":"2025-01-23T21:42:34.000Z","size":500,"stargazers_count":371,"open_issues_count":23,"forks_count":11,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-25T10:39:18.540Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bwhmather.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-03-18T17:40:44.000Z","updated_at":"2025-03-19T15:16:16.000Z","dependencies_parsed_at":"2024-05-10T20:33:55.211Z","dependency_job_id":"87ce3e30-445f-420a-bb9c-f4c29db2b1bb","html_url":"https://github.com/bwhmather/ssort","commit_stats":{"total_commits":384,"total_committers":6,"mean_commits":64.0,"dds":"0.25520833333333337","last_synced_commit":"0a53c300518d02b7a9fa5b09f354cff4bc4695ca"},"previous_names":[],"tags_count":34,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bwhmather%2Fssort","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bwhmather%2Fssort/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bwhmather%2Fssort/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bwhmather%2Fssort/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bwhmather","download_url":"https://codeload.github.com/bwhmather/ssort/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246162092,"owners_count":20733351,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T22:01:33.978Z","updated_at":"2025-10-21T20:04:04.920Z","avatar_url":"https://github.com/bwhmather.png","language":"Python","readme":"*****\nSSort\n*****\n\n|build-status| |coverage|\n\n.. |build-status| image:: https://github.com/bwhmather/ssort/actions/workflows/ci.yaml/badge.svg?branch=master\n    :target: https://github.com/bwhmather/ssort/actions/workflows/ci.yaml\n    :alt: Build Status\n\n.. |coverage| image:: https://coveralls.io/repos/github/bwhmather/ssort/badge.svg?branch=master\n    :target: https://coveralls.io/github/bwhmather/ssort?branch=master\n    :alt: Cocerage\n\n\n.. begin-docs\n\nThe python source code sorter.\n\nSorts the contents of python modules so that statements are placed after the things they depend on, but leaves grouping to the programmer.\nGroups class members by type and enforces topological sorting of methods.\n\nMakes old fashioned code navigation easier, you can always scroll up to see where something is defined, and reduces bikeshedding.\n\nCompatible with and intended to complement `isort \u003chttps://pycqa.github.io/isort/\u003e`_ and `black \u003chttps://black.readthedocs.io/en/stable/\u003e`_.\n\n\nBefore:\n\n.. code:: python\n\n    from module import BaseClass\n\n    def function():\n        return _dependency()\n\n    def _decorator(fn):\n        return fn\n\n    @_decorator\n    def _dependency():\n        return Class()\n\n    class Class(BaseClass):\n        def public_method(self):\n            return self\n\n        def __init__(self):\n            pass\n\nAfter:\n\n.. code:: python\n\n    from module import BaseClass\n\n    class Class(BaseClass):\n        def __init__(self):\n            pass\n\n        def public_method(self):\n            return self\n\n    def _decorator(fn):\n        return fn\n\n    @_decorator\n    def _dependency():\n        return Class()\n\n    def function():\n        return _dependency()\n\n\nInstallation\n============\n.. begin-installation\n\nSSort can be installed manually using pip.\n\n.. code:: bash\n\n    $ pip install ssort\n\n.. end-installation\n\n\nUsage\n=====\n.. begin-usage\n\nTo check that a file is correctly sorted use the `--check` flag.\n`--diff` can be passed to see what changes ``ssort`` would make.\n\n.. code:: bash\n\n    $ ssort --check --diff path/to/python_module.py\n\n\nTo allow ``ssort`` to rearrange your file, simply invoke with no extra flags.\nIf ``ssort`` needs to make changes to a `black \u003chttps://black.readthedocs.io/en/stable/\u003e`_ conformant file, the result will not necessarily be `black \u003chttps://black.readthedocs.io/en/stable/\u003e`_ conformant.\nThe result of running `black \u003chttps://black.readthedocs.io/en/stable/\u003e`_ on an ``ssort`` conformant file will always be ``ssort`` conformant.\nWe recommend that you reformat using `isort \u003chttps://pycqa.github.io/isort/\u003e`_ and `black \u003chttps://black.readthedocs.io/en/stable/\u003e`_ immediately after running ``ssort``.\n\n.. code:: bash\n\n    $ ssort src/ tests/; isort src/ tests/; black src/ tests/\n\nYou can also setup ssort to run automatically before commit by setting up `pre-commit \u003chttps://pre-commit.com/index.html\u003e`_,\nand registering ssort in your `.pre-commit-config.yaml`.\n\n.. code:: yaml\n\n  repos:\n  # ...\n  - repo: https://github.com/bwhmather/ssort\n    rev: master\n    hooks:\n    - id: ssort\n  - repo: https://github.com/pycqa/isort\n    rev: master\n    hooks:\n    - id: isort\n      name: isort (python)\n      args: [--profile=black]\n  - repo: https://github.com/psf/black\n    rev: master\n    hooks:\n    - id: black\n\n.. end-usage\n\n\nOutput\n======\n.. begin-output\n\n``ssort`` will sort top level statements and statements in class bodies.\n\nWhen sorting top level statements, ``ssort`` follows three simple rules:\n\n- Statements must always be moved after the statements that they depend on, unless there is a cycle.\n- If there is a cycle, the order of statements within the cycle must not be changed.\n- If there is no dependency between statements then, to the greatest extent possible, the original order should be kept.\n\nThese rules result in low level building blocks being moved to the top of modules, with higher level logic going at the bottom.\nThe `FAQ \u003c#why-does-ssort-sort-bottom-up-rather-than-top-down\u003e`_ goes into some detail about why this order was chosen.\n\nThe rules for sorting class bodies are more complicated.\nClass methods are generally only called from outside the class and so there aren't usually many interdependencies from which to derive structure.\n``ssort`` therefore ignores (deferred) dependencies between d`under and public methods and instead divides up class statements into hard-coded groups that it arranges in the following order:\n\n- The class docstring.\n- Special attributes, i.e. ``__slots__`` or ``__doc__``.\n- Inner classes.\n- Regular attributes.\n- Lifecycle d'under methods, e.g. ``__init__`` or ``__new__``.\n- Public methods, and unused private methods.\n- Other d'under methods, e.g. ``__getattr__`` or ``__len__``.\n\nApart from the docstring, this order is essentially arbitrary.\nIt is was chosen as being representative of current standard industry practice.\n\nD'under methods are arranged in a hard coded order within their group.\nStatements in other groups are left in their original order.\n\nPrivate methods should only be called from other methods in the class, and so are mixed in topologically.\n\nIf a class-definition-time dependency is detected between two statements preserving the relative order of the linked statements will take priority.\n\n.. end-output\n\n\nFrequently Asked Questions\n==========================\n.. begin-faq\n\nWhy does ``ssort`` sort bottom-up rather than top-down?\n-------------------------------------------------------\n\nPython is a scripting language, which means that the body of each module is evaluated, statement by statement, from top to bottom.\nIn almost all cases, things must be defined before they can be used.\nAttempting, in the subset of cases where it is possible, to reverse the order is difficult to do safely and leads to inconsistency with the cases where top-down ordering is impossible.\n\n\nTop-down ordering is only possible when lookups are deferred\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nTop-down ordering is only possible when lookups are deferred, but in most cases, lookups happen immediately.\n\n.. code:: python\n\n    # Broken.\n\n    variable = dependency()\n\n    def dependency():\n        ...\n\nIn this example python will try to find ``dependency`` in the ``locals()`` dict when the first line is evaluated, and fail because the statement that defines it has not been evaluated yet.\n\nAs far as I am aware, there is only one way to reference a variable that has not been bound yet, and that is to close over it in a function definition.\n\n.. code:: python\n\n    # Working.\n\n    def function():\n        return dependency()\n\n    def dependency():\n        ...\n\nThis is because the lookup is deferred until after ``function`` is called, which in this case doesn't happen until both functions are defined.\n\n\nTop-down ordering fails unsafe\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nIn cases where lookups are deferred, they may not be deferred sufficiently far to allow the dependant statement to be sorted before its dependencies.\n\nTake the following example formatted in bottom-up order.\n\n.. code:: python\n\n    # Hidden runtime dependency example sorted bottom-up.\n\n    def _shared_dep():\n        ...\n\n    def _decorator(fn):\n        _shared_dep()\n        return fn\n\n    @_decorator\n    def top_level():\n        _shared_dep()\n\nA naive analysis would suggest that ``_shared_dep`` is a runtime dependency and can safely be moved to the bottom of the script.\n\n.. code:: python\n\n    # Hidden runtime dependency example sorted top-down using naive analysis.\n\n    def _decorator(fn):\n        _shared_dep()\n        return fn\n\n    @_decorator\n    def top_level():\n        _shared_dep()\n\n    def _shared_dep():\n        ...\n\nThis will result in a ``NameError`` as ``_shared_dep`` will not have been bound when ``_decorator`` is invoked.\n\nMore powerful static analysls can mitigate this problem, but any missed hard references are likely to result in the program being broken.\nBottom-up sorting can only force broken reorderings when static analysis misses a reference that results in a cycle.\n\n\nTop-down ordering needs special cases for constants and imports\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nEven the most die hard proponent of top down ordering would not argue that ``import`` statements should be moved to the bottom of the file.\n\nTake the following example:\n\n.. code:: python\n\n    from module import first_dep\n\n    def second_dep():\n        ...\n\n    @decorator\n    def function():\n        first_dep()\n        second_dep()\n\nA strict top-down sort would see it reordered with the ``first_dep`` import at the bottom of the file.\n\n.. code:: python\n\n    from other_module import decorator\n\n    @decorator\n    def function():\n        first_dep()\n        second_dep()\n\n    def second_dep():\n        ...\n\n    from module import first_dep\n\n\nTop-down ordering makes code navigation difficult\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nWith bottom-up ordering, navigation is easy.\nIf you want to find where a variable is defined you scroll up.\nIf you want to find where a variable is used you scroll down.\nThese rules are reliable, and straightforward for programmers to learn and apply.\n\nWith top-down order, navigation is more tricky.\nIf you want to find where a variable is defined you scroll down, unless the variable is a constant or an import, or the variable is referenced here at import time, or the variable is referenced somewhere else at import time, or any of the many other special cases.\nIf you want to find where a variable is used, you basically have to scan the whole file.\n\nEvery special case added to the sorting tool is a special case that programmers need to learn if they are to navigate quickly, and top-down ordering requires a lot of special cases.\n\n\nWhy doesn't ssort allow me to configure X?\n------------------------------------------\n\n``ssort`` aims to bring about ecosystem wide consistency in how python source files are organised.\nIf this can be achieved then it will help all programmers familiar with its conventions to navigate unfamiliar codebases, and it will reduce arguments between programmers who prefer different conventions.\nThis only works if those conventions can't be changed.\n\n\nWhy was ssort created?\n----------------------\n\n``ssort`` exists because its author was too lazy to implement jump-to-definition in his text editor, and decided that it would be easier to just reformat all of the world's python code to make it possible to navigate by scrolling.\n\n.. end-faq\n\n\nLinks\n=====\n\n- Source code: https://github.com/bwhmather/ssort\n- Issue tracker: https://github.com/bwhmather/ssort/issues\n- PyPI: https://pypi.python.org/pypi/ssort\n\n\nLicense\n=======\n\nThe project is made available under the terms of the MIT license.  See `LICENSE \u003c./LICENSE\u003e`_ for details.\n\n.. end-docs\n","funding_links":[],"categories":["Python","UNIX-way formatters"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbwhmather%2Fssort","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbwhmather%2Fssort","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbwhmather%2Fssort/lists"}