runez


Namerunez JSON
Version 5.3.0 PyPI version JSON
download
home_pagehttps://github.com/codrsquad/runez
SummaryFriendly misc/utils/convenience library
upload_time2025-01-17 18:40:50
maintainerNone
docs_urlNone
authorZoran Simic
requires_python>=3.6
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            Friendly misc/utils/convenience library
=======================================

.. image:: https://img.shields.io/pypi/v/runez.svg
    :target: https://pypi.org/project/runez/
    :alt: Version on pypi

.. image:: https://github.com/codrsquad/runez/workflows/Tests/badge.svg
    :target: https://github.com/codrsquad/runez/actions
    :alt: Tested with Github Actions

.. image:: https://codecov.io/gh/codrsquad/runez/branch/main/graph/badge.svg
    :target: https://codecov.io/gh/codrsquad/runez
    :alt: Test code codecov

.. image:: https://img.shields.io/pypi/pyversions/runez.svg
    :target: https://github.com/codrsquad/runez
    :alt: Python versions tested (link to github project)


Overview
========

**runez** is a convenience ``"utils"`` library for common operations I found myself rewriting multiple times.

The name was initially meant as "run ez" ("run easy"),
the fact that it sounds like "runes" gives it a bit of a mystery/magic side that's also relatively appropriate
(it does indeed concentrate a bit of invocation magic, as you can save quite a few lines of repetitive code by using it)


Features
========

- Usable with any python version

- Pure python standalone library, does not bring in any additional dependency

- Takes care of most edge cases, with nice errors

  - Functions can be called without checking for return code etc (abort by default, with nice error)

  - They can also be called with ``fatal=False``, in which case the return value will indicate whether call succeeded or not

- Support for ``dryrun`` mode (show what would be done, but don't do it)

- Perform most typical logging setups in one call to ``runez.log.setup()``

- Log operations systematically (at debug level mostly), examples::

    Running: foo ...
    Copy foo -> bar
    Would move foo -> bar    (for dryrun)

- ``CaptureOutput`` context manager -> grab output/logging from any code section

- 100% test coverage


Example
=======

Run a program::

    import runez

    # Aborts if "foo" doesn't exist
    output = runez.run("ls", "foo")

    # Output can also be ignored
    runez.run("ls", "foo")

    # Don't capture output, just run the command and let output "pass through"
    runez.run("ls", "foo", stdout=None, stderr=None)

    # Don't abort, return False on failure (or actual output when successful)
    output = runez.run("ls", "foo", fatal=False)


File operations::

    import runez

    runez.touch("foo")
    runez.copy("foo", "bar")
    runez.move("foo", "baz")
    runez.delete("foo")

    runez.write("foo", "bar\nbaz\n")
    content = "\n".join(runez.readlines("foo", first=10))

    full_path = runez.resolved_path("foo/bar")
    folder = runez.parent_folder(full_path)
    runez.ensure_folder(folder)
    with runez.Anchored(folder):
        assert runez.short(full_path) == "bar"


Installation
============

As usual, available on pypi_: ``pip install runez``


Philosophy
==========

``runez`` tries to provide a consistent interface across functions.
Here are the main tenets for functions involving I/O (such as writing, reading, copy-ing files etc):

All IO-related functions **NOT returning content** (``run()``, ``delete()``, ...)
have this common signature: ``fatal=True, logger=UNSET, dryrun=UNSET``

- ``fatal``: decides whether operation should raise an exception on failure or not

  - ``fatal=True`` (default): raise an exception on failure, log a meaningful error

  - ``fatal=False``: don't raise on failure, log a meaningful error

  - ``fatal=None``: don't raise on failure, don't log anything

  - In non-fatal mode, calls try to return a usable value appropriate for the call (see docstring of each function)

- ``logger``: decides how chatty the operation should be

  - ``LOG.error()`` is used for failures, except when ``fatal`` is not True AND provided ``logger`` is a callable

  - ``logger=UNSET`` (default):

    - ``LOG.debug("Running: ...")`` to trace activity

    - ``print("Would run: ...")`` in dryrun mode

  - ``logger=False``: Log errors only (used internally, to avoid unnecessary log chatter when one operation calls another)

  - ``logger=mylogger``: call provided ``mylogger()`` to trace activity (example: ``logger=MY_LOGGER.info``)

    - ``mylogger("Running: ...")`` to trace activity

    - ``mylogger("Would run: ...")`` in dryrun mode

  - ``logger=None``: Don't log anything (even errors)

- ``dryrun`` allows to override current ``runez.DRYRUN`` setting just for that call



All IO-related functions **returning content** (``read_json()``, ``readlines()``, ...)
use a simpler convention based on: ``default=UNSET``,
which decides whether operation should raise an exception on failure or not:

- When ``default`` is **NOT provided**, the function call will abort on failure with an exception,
  logging a meaningful error via ``LOG.error()``

- When ``default`` **is provided** (even if ``None``), the function call will NOT abort,
  but return the specified ``default`` instead, it is up to the caller to log anything
  in that case (no log chatter comes from ``runez`` in that case, at all)


.. _pypi: https://pypi.org/

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/codrsquad/runez",
    "name": "runez",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.6",
    "maintainer_email": null,
    "keywords": null,
    "author": "Zoran Simic",
    "author_email": "zoran@simicweb.com",
    "download_url": "https://files.pythonhosted.org/packages/18/61/22d3007e5215c6e0aec5be0cac55082354c8613714d68af5361ab72152e3/runez-5.3.0.tar.gz",
    "platform": null,
    "description": "Friendly misc/utils/convenience library\n=======================================\n\n.. image:: https://img.shields.io/pypi/v/runez.svg\n    :target: https://pypi.org/project/runez/\n    :alt: Version on pypi\n\n.. image:: https://github.com/codrsquad/runez/workflows/Tests/badge.svg\n    :target: https://github.com/codrsquad/runez/actions\n    :alt: Tested with Github Actions\n\n.. image:: https://codecov.io/gh/codrsquad/runez/branch/main/graph/badge.svg\n    :target: https://codecov.io/gh/codrsquad/runez\n    :alt: Test code codecov\n\n.. image:: https://img.shields.io/pypi/pyversions/runez.svg\n    :target: https://github.com/codrsquad/runez\n    :alt: Python versions tested (link to github project)\n\n\nOverview\n========\n\n**runez** is a convenience ``\"utils\"`` library for common operations I found myself rewriting multiple times.\n\nThe name was initially meant as \"run ez\" (\"run easy\"),\nthe fact that it sounds like \"runes\" gives it a bit of a mystery/magic side that's also relatively appropriate\n(it does indeed concentrate a bit of invocation magic, as you can save quite a few lines of repetitive code by using it)\n\n\nFeatures\n========\n\n- Usable with any python version\n\n- Pure python standalone library, does not bring in any additional dependency\n\n- Takes care of most edge cases, with nice errors\n\n  - Functions can be called without checking for return code etc (abort by default, with nice error)\n\n  - They can also be called with ``fatal=False``, in which case the return value will indicate whether call succeeded or not\n\n- Support for ``dryrun`` mode (show what would be done, but don't do it)\n\n- Perform most typical logging setups in one call to ``runez.log.setup()``\n\n- Log operations systematically (at debug level mostly), examples::\n\n    Running: foo ...\n    Copy foo -> bar\n    Would move foo -> bar    (for dryrun)\n\n- ``CaptureOutput`` context manager -> grab output/logging from any code section\n\n- 100% test coverage\n\n\nExample\n=======\n\nRun a program::\n\n    import runez\n\n    # Aborts if \"foo\" doesn't exist\n    output = runez.run(\"ls\", \"foo\")\n\n    # Output can also be ignored\n    runez.run(\"ls\", \"foo\")\n\n    # Don't capture output, just run the command and let output \"pass through\"\n    runez.run(\"ls\", \"foo\", stdout=None, stderr=None)\n\n    # Don't abort, return False on failure (or actual output when successful)\n    output = runez.run(\"ls\", \"foo\", fatal=False)\n\n\nFile operations::\n\n    import runez\n\n    runez.touch(\"foo\")\n    runez.copy(\"foo\", \"bar\")\n    runez.move(\"foo\", \"baz\")\n    runez.delete(\"foo\")\n\n    runez.write(\"foo\", \"bar\\nbaz\\n\")\n    content = \"\\n\".join(runez.readlines(\"foo\", first=10))\n\n    full_path = runez.resolved_path(\"foo/bar\")\n    folder = runez.parent_folder(full_path)\n    runez.ensure_folder(folder)\n    with runez.Anchored(folder):\n        assert runez.short(full_path) == \"bar\"\n\n\nInstallation\n============\n\nAs usual, available on pypi_: ``pip install runez``\n\n\nPhilosophy\n==========\n\n``runez`` tries to provide a consistent interface across functions.\nHere are the main tenets for functions involving I/O (such as writing, reading, copy-ing files etc):\n\nAll IO-related functions **NOT returning content** (``run()``, ``delete()``, ...)\nhave this common signature: ``fatal=True, logger=UNSET, dryrun=UNSET``\n\n- ``fatal``: decides whether operation should raise an exception on failure or not\n\n  - ``fatal=True`` (default): raise an exception on failure, log a meaningful error\n\n  - ``fatal=False``: don't raise on failure, log a meaningful error\n\n  - ``fatal=None``: don't raise on failure, don't log anything\n\n  - In non-fatal mode, calls try to return a usable value appropriate for the call (see docstring of each function)\n\n- ``logger``: decides how chatty the operation should be\n\n  - ``LOG.error()`` is used for failures, except when ``fatal`` is not True AND provided ``logger`` is a callable\n\n  - ``logger=UNSET`` (default):\n\n    - ``LOG.debug(\"Running: ...\")`` to trace activity\n\n    - ``print(\"Would run: ...\")`` in dryrun mode\n\n  - ``logger=False``: Log errors only (used internally, to avoid unnecessary log chatter when one operation calls another)\n\n  - ``logger=mylogger``: call provided ``mylogger()`` to trace activity (example: ``logger=MY_LOGGER.info``)\n\n    - ``mylogger(\"Running: ...\")`` to trace activity\n\n    - ``mylogger(\"Would run: ...\")`` in dryrun mode\n\n  - ``logger=None``: Don't log anything (even errors)\n\n- ``dryrun`` allows to override current ``runez.DRYRUN`` setting just for that call\n\n\n\nAll IO-related functions **returning content** (``read_json()``, ``readlines()``, ...)\nuse a simpler convention based on: ``default=UNSET``,\nwhich decides whether operation should raise an exception on failure or not:\n\n- When ``default`` is **NOT provided**, the function call will abort on failure with an exception,\n  logging a meaningful error via ``LOG.error()``\n\n- When ``default`` **is provided** (even if ``None``), the function call will NOT abort,\n  but return the specified ``default`` instead, it is up to the caller to log anything\n  in that case (no log chatter comes from ``runez`` in that case, at all)\n\n\n.. _pypi: https://pypi.org/\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Friendly misc/utils/convenience library",
    "version": "5.3.0",
    "project_urls": {
        "Documentation": "https://github.com/codrsquad/runez/wiki",
        "Homepage": "https://github.com/codrsquad/runez",
        "Release notes": "https://github.com/codrsquad/runez/wiki/Release-notes",
        "Source": "https://github.com/codrsquad/runez"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "402efa9da4d52522be15341cfb8d051d28053c30950a9bb08fd7c61e2b97abce",
                "md5": "4f8eb735890c3bc281e9898caaee6384",
                "sha256": "c04b8389ec50aea4c40b47353df8b02d2fac0ad9747647ab55a1077b6998508a"
            },
            "downloads": -1,
            "filename": "runez-5.3.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "4f8eb735890c3bc281e9898caaee6384",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.6",
            "size": 120847,
            "upload_time": "2025-01-17T18:40:45",
            "upload_time_iso_8601": "2025-01-17T18:40:45.951428Z",
            "url": "https://files.pythonhosted.org/packages/40/2e/fa9da4d52522be15341cfb8d051d28053c30950a9bb08fd7c61e2b97abce/runez-5.3.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "186122d3007e5215c6e0aec5be0cac55082354c8613714d68af5361ab72152e3",
                "md5": "37b3c94da0bddb736a78f562c4322818",
                "sha256": "ae53402a9fd6c5ce3b86882e208055c39fe20a924a9daa11402587525eeaf7cd"
            },
            "downloads": -1,
            "filename": "runez-5.3.0.tar.gz",
            "has_sig": false,
            "md5_digest": "37b3c94da0bddb736a78f562c4322818",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.6",
            "size": 161433,
            "upload_time": "2025-01-17T18:40:50",
            "upload_time_iso_8601": "2025-01-17T18:40:50.554671Z",
            "url": "https://files.pythonhosted.org/packages/18/61/22d3007e5215c6e0aec5be0cac55082354c8613714d68af5361ab72152e3/runez-5.3.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-01-17 18:40:50",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "codrsquad",
    "github_project": "runez",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "runez"
}
        
Elapsed time: 0.41611s