{ "info": { "author": "Jan Verbeek", "author_email": "jan.verbeek@posteo.nl", "bugtrack_url": null, "classifiers": [ "Environment :: Console", "Intended Audience :: Developers", "Intended Audience :: System Administrators", "License :: OSI Approved :: ISC License (ISCL)", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: System :: System Shells" ], "description": "mocksh is a library for shell scripting inside Python. It makes external\ncommands available as functions, and provides accessible ways to use their\nresults. It tries to copy the semantics of sh (the Bourne shell) when they\nmake sense in Python.\n\nIt acts as a thin layer around the\n`subprocess `_ module.\n\n======\nBasics\n======\n\nIn the simplest case, a command is run until completion, and the output is\nshown without being captured:\n\n.. code-block:: python\n\n >>> from mocksh import sh\n >>> sh.echo(\"Hello, world\")\n Hello, world\n\nIf the command fails, it raises an exception:\n\n.. code-block:: python\n\n >>> sh.false()\n Traceback (most recent call last):\n ...\n mocksh.CommandError[1]: Command 'false' failed with status code 1\n\nThis most basic form is useful for commands that are run for their side\neffects. Command output isn't captured by default, because it's often useful.\nIf something goes wrong, it provides extra information that an exception\ndoesn't know about.\n\n----------------\nCapturing output\n----------------\n\nOutput can be captured with the ``capture_`` method, awkwardly inserted into\nthe middle, right before the arguments:\n\n.. code-block:: python\n\n >>> str(sh.echo.capture_(\"Hello, Python\"))\n 'Hello, Python\\n'\n\nThe process doesn't immediately return a string. You have to tell it how you\nwant to access the output:\n\n.. code-block:: python\n\n >>> bytes(sh.dd.capture_('if=/dev/urandom', 'count=1', 'bs=16')) # raw bytes\n b'w\\xc4K\\xd9\\x04\\xa7\\x8f\\x0el\\xe9\\xb0\\xa1(\\x8f\\tp'\n >>> for num in sh.seq.capture_(3): # line by line\n ... print(num)\n 1\n 2\n 3\n >>> list(sh.shuf.capture_('-n', 5, '/usr/share/dict/words'))\n ['upgrading', 'humongous', 'thesauri', 'candidly', 'drools']\n\nCommands called this way return immediately, before the command is finished.\nThis means the output can be processed line by line without wasting memory\nif the output is large.\n\n------\nPiping\n------\n\nAnother special method, ``pipe_``, lets you construct pipelines:\n\n.. code-block:: python\n\n >>> sh.fortune.pipe_().cowsay() # Like 'fortune | cowsay'\n ______________________________________\n / Are you making all this up as you go \\\n \\ along? /\n --------------------------------------\n \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n ||----w |\n || ||\n\nThe next command in the pipeline is called like a method, the same way you\nwould call a command on the ``sh`` object.\n\nThis can naturally be combined with ``capture_``:\n\n.. code-block:: python\n\n >>> str(sh.fortune.pipe_().rot13.capture_()) # Like 'fortune | rot13'\n 'Lbhe cerfrag cynaf jvyy or fhpprffshy.\\n'\n\n-------\nTesting\n-------\n\nBy default, commands raise an exception if they fail, but that's not always\ndesirable. Sometimes you just want to test whether a command succeeded. The\n``test_`` special method can be used for that:\n\n.. code-block:: python\n\n >>> if sh.ping.test_('-c', 1, 'fake.domain'):\n ... print(\"fake.domain is up\")\n ... else:\n ... print(\"fake.domain is down\")\n ping: fake.domain: Name or service not known\n fake.domain is down\n\n==========\nInstalling\n==========\n\n::\n $ pip install mocksh\n\nBecause the module is only a single file, you could also just dump\n``mocksh.py`` into your scripts folder.\n\n==============\nAdvanced usage\n==============\n\n--------------------\nOther argument forms\n--------------------\n\nSome commands have subcommands. For example, ``git`` has ``git status`` and\n``git commit``. They can be separated by a dot:\n\n.. code-block:: python\n >>> sh.git.status()\n On branch master\n ...\n\nUnderscores in command names are converted to dashes, because many commands\nhave dashes in their names but Python doesn't allow dashes in its names. To\nrun a command that does have an underscore in its name, or any weird\ncharacters, you can use indexing syntax:\n\n.. code-block:: python\n >>> sh.units_cur() # Doesn't work, converted to units-cur\n Traceback (most recent call last):\n ...\n FileNotFoundError: [Errno 2] No such file or directory: 'units-cur': 'units-cur'\n >>> sh['units_cur']() # works\n ...\n >>> sh.sudo['units_cur']()\n ...\n\nYou can also index with multiple arguments. This gives an easy way of\ndefining aliases:\n\n.. code-block:: python\n >>> lh = sh.ls['-l', '-h']\n >>> lh('/')\n total 16K\n drwxr-xr-x 1 root root 2.4K Jul 14 08:26 bin\n ...\n\n---------------\nCommand options\n---------------\n\nOptions can be passed either as regular arguments or as keyword arguments:\n\n.. code-block:: python\n\n >>> sh.curl('-L', '--data', 'test', 'httpbin.org/post') # wordy, but transparent\n ...\n >>> sh.curl('httpbin.org/post', L=True, data='test') # fancy, but opaque\n ...\n\nBoth examples are exactly equivalent, and generate the same command.\n\nOptions are processed according to a few rules.\n\n* Options that are one character long are short options, others are long\n options. This means ``v`` is translated to ``-v``, but ``verbose`` is\n translated to ``--verbose``.\n* Underscores ( ``_`` ) are translated to dashes ( ``-`` ). This is because\n Python does not allow dashes in keyword arguments. ``cookie_jar`` becomes\n ``--cookie-jar``.\n* If the value of the argument is ``False``, it's discarded. If the value is\n ``True``, only the flag is added. Otherwise, the key and the value are\n both added. ``L=True`` becomes ``-L``, and ``data='test'`` becomes\n ``--data test``.\n* For long options that nevertheless take a single dash, you can start the\n argument with a dash. ``java -jar ...`` can be expressed as\n ``sh.java(_jar=...)``\n* Options are inserted after the command name and before the other arguments.\n\nThis is enough to deal with most programs. But if it doesn't do what you\nwant, sticking to the simple, dependable form is always a good option.\n\n---------------\nSpecial options\n---------------\n\nKeyword arguments that end with an underscore aren't added to the command,\nbut used for special behavior. ``mocksh`` has a few special keyword\narguments, and any others are forwarded to ``subprocess`` (without the\nunderscore).\n\nFor example, to append command output to a file:\n\n.. code-block:: python\n >>> with open('log.txt', 'a') as f: # rsync -Pr somedir somehost: >> log.txt\n ... sh.rsync('-Pr', 'somedir', 'somehost:', stdout_=f) # stdout_, not stdout\n\nThat's roughly equivalent to this use of ``subprocess``:\n\n.. code-block:: python\n >>> import subprocess\n >>> with open('log.txt', 'a') as f:\n ... subprocess.run(['rsync', '-Pr', 'somedir', 'somehost:'], stdout=f)\n\nIn addition to the arguments of `subprocess.Popen `_,\nmocksh supports the following arguments:\n\n* ``check``: Whether to automatically raise an exception if the command\n fails. ``True`` by default.\n* ``input``: String or bytes to be sent to the standard input of the command.\n* ``wait``: Whether to wait until the command is finished before returning.\n To run a command in the background, add ``wait_=False``.\n* ``timeout``: Optionally, how many seconds to wait before raising a\n ``subprocess.TimeoutExpred`` exception.\n* ``capture_stdout``: If ``True``, capture the standard output of the command.\n ``capture_stdout_=True`` is equivalent to ``stdout_=sh.PIPE_``.\n* ``capture_stderr``: Likewise, but for stderr. If only stderr is captured,\n converting the command to a string will give the stderr output.\n\n---------------\nProcess objects\n---------------\n\nCommands return ``mocksh.Process`` objects, a subclass of\n``subprocess.Popen``. It can be used like a regular instance of ``Popen``,\nbut has additional features, most of which are covered by other sections.\n\nA process in a pipeline will have a ``tail`` attribute, set to the previous\ncommand in the pipeline. If the process at the start of the pipeline has an\nopen ``stdin``, its ``stdin`` attribute is set to that.\n\n``Process.wait`` is pipeline-aware, and will wait for the entire pipeline to\nfinish, with proper timeout handling.\n\nThe ``Process.check_returncode`` method raises a ``CommandError`` even if\n``check=False``, for manual checking.\n\nThe ``captured`` property points to ``stdout`` if it's captured, or\n``stderr`` if that's captured. If both are captured, ``stdout`` and\n``stderr`` have to be addressed directly.\n\n---------------------\nAsynchronous commands\n---------------------\n\nCommands can be run in the background by adding ``wait_=False`` to the\nargument list.\n\nTo make sure they finish, they can be used as a context manager:\n\n.. code-block:: python\n >>> with sh.wget('some.large/file.ext'):\n ... something_else()\n ... # wget is now guaranteed to have finished, and would have thrown an\n ... # exception if it failed\n ... use('file.ext')\n\nBecause ``capture_`` also runs processes in the background, you can wait\nwith gathering the output until later. You could loop through its lines:\n\n.. code-block:: python\n >>> for line in sh.long_process():\n ... process(line)\n\nOr you could collect it all in one go:\n\n.. code-block:: python\n >>> proc = sh.expensive_computation()\n >>> # do things\n >>> output = str(proc)\n\n------------------\nException handling\n------------------\n\nCommands that fail raise a ``CommandError``.\n\nAs a convenience for ``from mocksh import sh``, the exception type is\naccessible as ``sh.CommandError_`` (note the underscore).\n\nThe exception is subclassed for different return codes and signals.\nSubclasses can be accessed with the ``code`` classmethod. For example:\n\n.. code-block:: python\n >>> try:\n ... sh.false()\n ... except sh.CommandError_.code(10):\n ... print(\"Exited with 10\")\n ... except sh.CommandError_.code(1):\n ... print(\"Exited with 1\")\n Exited with 1\n\nSignals can be referred to by name:\n\n.. code-block:: python\n >>> try:\n ... sh.tcc('-run', '-', input_='#include int main() { puts(0); }')\n ... except sh.CommandError_.code('SIGSEGV'):\n ... ...\n\n---------------\nCommand objects\n---------------\n\n``sh`` is a ``mocksh.Command`` object. Commands like ``sh.echo`` and\n``sh.ls['-l', '-h']`` are also ``Command`` objects.\n\n``Command`` objects can contain a prepared set of arguments for ``Process``.\nThis is how piping is implemented: ``_pipe`` returns a new ``Command``\nobject with ``tail`` set to the last ``Process``.\n\nIf you're tired of typing ``.capture_`` all the time, you could\ncreate your own launcher like this:\n\n.. code-block:: python\n >>> import mocksh\n >>> mysh = mocksh.Command(capture_stdout=True, wait=False)\n >>> str(mysh.echo('test'))\n 'test\\n'\n\n-------------------------------------\nWhy you should use subprocess instead\n-------------------------------------\n\nmocksh is a leaky abstraction. It pretends external processes are Python\nfunctions, but external processes don't behave like Python functions at all.\nIt tries to copy sh's semantics, but sh's semantics are incompatible with\nPython's syntax.\n\nIn most cases you're better off using ``subprocess`` directly, through a\nnice interface like `subprocess.run `_.\nIt will be easier to reason about because it doesn't hide what's getting\nexecuted.\n\n----------------\nSimilar projects\n----------------\n\n* `sh `_ (unrelated to other uses of the word\n ``sh`` in this document)\n* `plumbum `_\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/blyxxyz/mocksh", "keywords": "", "license": "ISC", "maintainer": "", "maintainer_email": "", "name": "mocksh", "package_url": "https://pypi.org/project/mocksh/", "platform": "", "project_url": "https://pypi.org/project/mocksh/", "project_urls": { "Homepage": "https://github.com/blyxxyz/mocksh" }, "release_url": "https://pypi.org/project/mocksh/0.0.1/", "requires_dist": null, "requires_python": "", "summary": "Simple shell-style process calling", "version": "0.0.1" }, "last_serial": 4075429, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "8f29c6770a91168ecee1d70951b44c5c", "sha256": "ff9a376ae69c30daac848718c90cf336ab42970471c3ea20809e22056cbdab60" }, "downloads": -1, "filename": "mocksh-0.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "8f29c6770a91168ecee1d70951b44c5c", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 17732, "upload_time": "2018-07-17T21:20:56", "url": "https://files.pythonhosted.org/packages/be/68/24b1dc99e5e2654c0abf46767c460dfd580f51cb93cd91a3eb87abddacb6/mocksh-0.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a70faa1d1f758129e2236058c9c88c42", "sha256": "84e233dd286c35c8c344f3c0e06ee55a6918cf68c1ccd9f310239ba358835bc0" }, "downloads": -1, "filename": "mocksh-0.0.1.tar.gz", "has_sig": false, "md5_digest": "a70faa1d1f758129e2236058c9c88c42", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16884, "upload_time": "2018-07-17T21:21:28", "url": "https://files.pythonhosted.org/packages/ac/81/6a6c5dc0507e18097ec00188ea6549f108a1072be7b6d138b9ace5fce1e9/mocksh-0.0.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "8f29c6770a91168ecee1d70951b44c5c", "sha256": "ff9a376ae69c30daac848718c90cf336ab42970471c3ea20809e22056cbdab60" }, "downloads": -1, "filename": "mocksh-0.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "8f29c6770a91168ecee1d70951b44c5c", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 17732, "upload_time": "2018-07-17T21:20:56", "url": "https://files.pythonhosted.org/packages/be/68/24b1dc99e5e2654c0abf46767c460dfd580f51cb93cd91a3eb87abddacb6/mocksh-0.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a70faa1d1f758129e2236058c9c88c42", "sha256": "84e233dd286c35c8c344f3c0e06ee55a6918cf68c1ccd9f310239ba358835bc0" }, "downloads": -1, "filename": "mocksh-0.0.1.tar.gz", "has_sig": false, "md5_digest": "a70faa1d1f758129e2236058c9c88c42", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16884, "upload_time": "2018-07-17T21:21:28", "url": "https://files.pythonhosted.org/packages/ac/81/6a6c5dc0507e18097ec00188ea6549f108a1072be7b6d138b9ace5fce1e9/mocksh-0.0.1.tar.gz" } ] }