{"id":37778324,"url":"https://github.com/campenr/mothur-py","last_synced_at":"2026-01-16T15:02:21.729Z","repository":{"id":57443299,"uuid":"105411209","full_name":"campenr/mothur-py","owner":"campenr","description":"Python wrapper for the bioinformatics tool mothur","archived":false,"fork":false,"pushed_at":"2018-03-14T22:35:39.000Z","size":122,"stargazers_count":8,"open_issues_count":1,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-11-27T18:37:28.992Z","etag":null,"topics":["bioinformatics","mothur","python","python-wrapper"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/campenr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-10-01T01:10:42.000Z","updated_at":"2025-11-03T01:20:42.000Z","dependencies_parsed_at":"2022-09-02T08:30:36.345Z","dependency_job_id":null,"html_url":"https://github.com/campenr/mothur-py","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/campenr/mothur-py","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/campenr%2Fmothur-py","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/campenr%2Fmothur-py/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/campenr%2Fmothur-py/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/campenr%2Fmothur-py/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/campenr","download_url":"https://codeload.github.com/campenr/mothur-py/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/campenr%2Fmothur-py/sbom","scorecard":{"id":263851,"data":{"date":"2025-08-11","repo":{"name":"github.com/campenr/mothur-py","commit":"e8c0b21b6cf174d8fd2b0112aa08891739732d90"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: LICENSE.txt:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-17T11:27:58.089Z","repository_id":57443299,"created_at":"2025-08-17T11:27:58.089Z","updated_at":"2025-08-17T11:27:58.089Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28479406,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T11:59:17.896Z","status":"ssl_error","status_checked_at":"2026-01-16T11:55:55.838Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["bioinformatics","mothur","python","python-wrapper"],"created_at":"2026-01-16T15:02:21.580Z","updated_at":"2026-01-16T15:02:21.704Z","avatar_url":"https://github.com/campenr.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mothur-py\n\nCopyright \u0026#169; 2018, Richard Campen. All rights reserved.\n\nSee LICENSE.txt for full license conditions.\n\n---\n\n### Description\n\nA python wrapper for the command line version of the bioinformatics tool \n[mothur](https://www.mothur.org/).\n\nSee the change log at the end of this ReadMe for a full list of changes.\n\nMothur-py was inspired by the [ipython-mothurmagic](https://github.com/SchlossLab/ipython-mothurmagic) module, but with an\nintention to provide a more general python wrapper that would work outside of the IPython/Jupyter notebook environment, \nas well as provide support for mothur's `current` keyword functionality.\n\n**Note:** This module has only been tested with mothur v1.39.5 and python 3. It should in theory work with older \nversions of mothur, but the older the version the less likely as this module relies upon some of the more recent mothur \ncommands/output to function properly.\n\n---\n\n### Installation\n\nTo install the latest release version you can just `pip install mothur-py`. To install the most up to date code you should\ndownload/clone this repository and create a binary distribution using `python setup.py bdist_wheel` that will create a .whl file\nin the `dist` folder. You can then install mothur-py with pip from the .whl file using `pip install \u003cwheel_file_name\u003e`. The\nadvantage of this method over just running `python setup.py install` is that you can easily remove or update the package via pip.\n\n---\n\n### Basic Usage\n\n**NOTE:** mothur-py expects mothur to be installed in the users PATH environment variable. If this is not the case you\nwill need to tell it where to find the mothur executable. See the configuration section of the README for details.\n\nUse of this module revolves around the `Mothur` class that catches method calls and passes them off to mothur to be run \nas commands. An instance of the `Mothur` class needs to be created before running any commands:\n\n    # create instance of Mothur class\n    from mothur_py import Mothur\n    m = Mothur()\n    \nCommands in mothur can then be executed as methods of the `Mothur` class instance using the same names you would use \nwithin the command line version of mothur:\n\n    # run the mothur help command\n    m.help()\n\nCommand parameters can either be passed as python native types (i.e. strings, integers, floats, booleans, lists) *or* as\nstrings that match the format that mothur would expect:\n\n    # running make contigs using str input for file parameter, and int for processor paramenter\n    m.make.contigs(file='basic_usage.files', processors=2)\n\n    # running summary.single, passing calculators as mothur formatted list\n    m.summary.single(shared='basic_usage.shared', calc='nseqs-sobs-coverage-shannon-simpson')\n\n    # running summary.single, passing calculators as python list also works\n    m.summary.single(shared='basic_usage.shared', calc=['nseqs', 'sobs', 'coverage', 'shannon', 'simpson'])\n\nThe `Mothur` object saves a record of the current directories and files and the output files from mothur after executing each command.\nThese are stored as dictionary attributes of the `Mothur` object:\n\n    # run a command\n    m.summary.seqs(fasta='basic_usage.fasta')\n    \n    # display current mothur files\n    print(m.current_files)\n\n    # read in the output file from summary.seqs()\n    with open(m.output_files['summary'][0], 'r') as in_handle:\n        in_handle.read()\n\n**NOTE:** Due to the possibility of multiple output files with the same extension the output files are saved as lists within the attribute\ndictionaries with the file extension as the key. This issue does not occur for current files and dirs so they are stored as the actual\nvalues, not as lists of the values, with the key being the type of file according to mothur (usually the same as the file extension).\n\n**NOTE:** Each successive execution of a mothur command will update the current files and dirs, but will completely overwrite the saved output\nfiles. This is so that you have access to the current files generated more than one command ago, but do not get access to output from more than\none command ago, which would be confusing.\n\nThere is also implementation of the `current` keyword used in the command line version of mothur:\n       \n    # run the mothur summary.seqs command using the 'current' option\n    # NOTE: current is being passed as a string\n    m.summary.seqs(fasta='current')\n     \n    # like the command line version, you don't even need to specify \n    # the 'current' keyword for some commands\n    m.summary.seqs() \n    \nBehind the scenes, the `current` keyword is enabled by appending the users command with the `get.current()` command to \nlist the current directories and files being used by mothur, parsing of the output to extract this information, and \nprepending future commands with `set.dir()` and `set.current()` to tell mothur what these should be. This is necessary \nas each call to mothur is executed as a separate mothur session and therefore mothur can not store this information \nitself.\n\n---\n\n### Configuration \n    \nThe `Mothur` class stores configuration options for how mothur is executed. These options include `mothur_path` to tell\nmothur-py where to find the mothur executable, `verbosity` to control how much output there is, `mothur_seed` to control \nthe seed used by mothur for random number generation, `logfile_name` to set the name of the mothur logfile, \n`suppress_logfile` which suppresses the creation of the mothur logfile, and `line_limit` which sets the limit on how\nmany lines of stdout will be printed.\n\nThe default for `mothur_path` is `mothur` which will only work if mothur is in your PATH environment variable.\nIf it is not then you will need to specify where to find the mothur executable, including the name of the executable \nitself:\n\n    # configure mothur with executable in current directory on Windows\n    m = Mothur(mothur_path='mothur.exe')\n    \n    # configure mothur with executable in current directory on Linux\n    m = Mothur(mothur_path='./mothur')\n    \n    # configure mothur with executable in alternate directory on Windows\n    m = Mothur(mothur_path='\\\\path\\\\to\\\\mothur.exe')\n    \nFailure to correctly configure the `mothur_path` will usually result in a PermissionError:\n\n    m = Mothur(mothur_path='/not/a/real/path/to/mothur')\n    Traceback (most recent call last):\n      File \"\u003cstdin\u003e\", line 1, in \u003cmodule\u003e\n      File \".../mothur_py/core.py\", line 199, in __call__\n        p = Popen([self.root_object.mothur_path, '#%s' % commands_str], stdout=PIPE, stderr=STDOUT)\n      File \"/usr/lib/python3.5/subprocess.py\", line 947, in __init__\n        restore_signals, start_new_session)\n      File \"/usr/lib/python3.5/subprocess.py\", line 1551, in _execute_child\n        raise child_exception_type(errno_num, err_msg)\n    PermissionError: [Errno 13] Permission denied\n\nWhen `verbosity` is set to `0` (default) there is no output printed, `1` prints the normal output as would be seen with command \nline execution (minus the header that contains the mothur version and runtime information), and `2` displays all output\nincluding the commands being executed behind the scenes to enable the `current` keyword to work. The default option is \n`0`, with `1` being useful when you want to see the standard mothur output, and `2` being useful for debugging purposes. \n\nIf `mothur_seed` is set to a valid integer then this number will be passed to mothur to be used for random number\ngeneration. This is implemented by adding the `seed=\u003cyour seed here\u003e` named parameter to each mothur command. By default\n no seed is set (`mothur_seed=None`). Not all commands will accept having a seed set. For these commands you may need to \n set the `mothur_seed` parameter to `None` for the execution of that command, e.g.:\n \n    m = Mothur(mothur_seed=12345)\n    \n    # summary.seqs() allows setting the seed so this will run fine\n    m.summary.seqs(fasta='current')\n    \n    # help() does not accept having the seed set so need to alter that value temporarily, otherwise an error will occur\n    seed = m.mothur_seed\n    m.mothur_seed = None\n    m.help()\n    m.mothur_seed = seed\n    \nThe `logfile_name` option allows the user to specify the name of the mothur generated logfile. The logfile will store \nthe output from all mothur commands executed for the Mothur object it is configured for. When set to `None` (default) a\nrandom logfile name is generated for the mothur object in the format `mothur.py.\u003crandom_5_digit_number\u003e.logfile`.\n\n**Note:** When copying mothur objects it is important to then specify different logfiles for them otherwise they\nmay attempt to use the same logfile. Additionally, if `suppress_logfile` is true, the logfile will be suppressed even\nif it has been given a name by the user.\n\nThe `supress_logfile` option is useful when you don't want the log files, such as when running in an Jupyter (nee \nIPython) notebook with `verbosity=1`, in which case you already have a record of mothur's output and the mothur logfiles\nare superfluous. Default setting is `False`.\n\n**Note:** Currently, due to the way that mothur creates the logfiles, a logfile will always be created BUT it will be \ncleaned up upon successful execution if `suppress_logfile=True`. However, if mothur fails to successfully execute, i.e. \nexecution hangs or is interrupted, the logfile will not be cleaned up. For relevant discussion of this behaviour in \nmothur see [here](https://github.com/mothur/mothur/issues/281) and [here](https://github.com/mothur/mothur/issues/377).\n\nThe `line_limit` option is useful when the full stdout is not wanted, or when printing it will be problematic, such as\nwhen stdout is excessive and causes memory issues in the Jupyter (nee IPython) notebook environment. Setting `line_limit`\nto `-1` (default) imposes no line limit, while any positive integer (or zero) imposes a line limit that causes stdout to no\nlonger be printed once the limit is reaches. If the line limit is reached then a warning is printed to notify the user.\n\n**Note:** Only lines related to the user specified command count towards the line limit, therefore commands running\nin the background (viewable with verbosity == 2) do not count towards this limit. Additionally, when verbosity == 2\nthe additional commands that enable the `current` keyword functionality that are executed after the users command are \nstill displayed, even if the line limit has been reached. Setting a line limit does not change what is printed to the \nlogfile.\n\nYou can also instantiate the `Mothur` object with your desired configuration options.\n\n    m = Mothur(verbosity=1, mothur_seed=543210, suppress_logfile=True, line_limit=1000)\n    \n---\n\n### Advanced Usage\n\nThe current files and current directories for use in mothur are stored in dictionary attributes of the `Mothur` \ninstance, `current_files` and `current_dirs` respectively. These values can be passed to mothur commands, e.g:\n\n    # passing current fasta file to summary.seqs()\n    m.summary.seqs(fasta=m.current_files['fasta'])\n       \nThe `current` keyword is actually just a shortcut for this functionality so it will always be easier to just pass \n`'current'`. However, this demonstrates that the parameters of the mothur commands can accept any variable as long as it \nwill resolve to something that mothur accepts. In the above example, the dictionary value resolves to a string that is\nthe path to the `.fasta` file. As a better example of passing python variables as mothur command parameters, you could \nperform classification of sequences at multiple defined cutoffs as follows:\n\n    from copy import deepcopy\n    \n    # init results container\n    mothur_objs = dict()\n\n    # iterate over list off possible cutoff values\n    for cutoff in [70, 80, 90]:\n    \n        # make a copy of the original mothur object so we do not make unwanted modifications to the original\n        m_copy = deepcopy(m)\n       \n        # save outputs to different folders, but keep input the same\n        output_dir = 'cutoff_%s' % cutoff\n        m_copy.set.dir(output=output_dir, input='.')\n        m_copy.classify.seqs(fasta='current', count='current', reference='reference.fasta', taxonomy='referenece.tax',\n        cutoff=cutoff)\n        \n        # save to results container\n        mothur_objs[cutoff] = m_copy\n        \nThis may be a convoluted example, but it demonstrates the functionality well. One note of caution with this approach is \nthat depending on the mothur command and the parameter you are changing, you may be overwriting your output files as you \ngo. This is the reason for saving each output to a different folder in the above example. We also create multiple copies\nof the original mothur object and use those for the command instead so we can continue to use the `current` keyword\ndownstream and have it refer to the correct files:\n\n    # using the results container from above\n    for m_ in mothur_objs.values():\n        \n        # run remove.lineage() on each mothur object created previously to remove unwanted taxa\n        # because we saved each classify.seqs command to a different mothur object we can safely use the 'current'\n        # keyword here and know that it refers to the correct file\n        m_.remove.lineage(fasta='current', count='current', taxonomy='current, taxon='unknown')\n    \n\nYou can also instantiate a `Mothur` instance with predefined current file and directory dictionaries:\n\n    m = Mothur(current_files=my_predefined_files_dict, current_dirs=my_predefined_files_dict)\n\nThis can be convenient for saving and loading the state of a mothur object to/from file as such:\n\n    import json\n\n    # save state of mothur object, m, to json file\n    with open('mothur_object.json', 'w') as out_handle:\n        json.dump(vars(m), out_handle)\n\n    # can reload mothur object from the json file\n    with open('mothur_object.json', 'r') as in_handle:\n        m = Mothur(**json.load(in_handle))\n\n---\n\n### Change Log\n\n#### *v0.4.0*\n\nNew features:\n* Added a line limit configuration option to limit the amount of stdout printed to screen. Helps with potential memory\nissues when outputting in Jupyter (nee IPython) notebook\n\nBig fixes:\n* Current files/dirs and output are now only set after successful execution to prevent them being changed when mothur \nerrors\n\nChanges:\n* Added lines of text specifying transition from user input functions from background functions enabling the current\nkeyword functionality when verbosity == 2\n* For verbosity == 1, now does not print redundant warning/error text at the end of stdout\n* Split utility functions out into their own file (`mothur_py.utils`)\n* Refined `__str__` and `__repr__` for Mothur and MothurCommand\n\n#### *v0.3.1*\n\nNew features:\n* Allow setting the name of the mothur logfile via configuration of the Mothur object\n\nBug fixes:\n* Changed strings to match to detect errors and warnings from mothur in stdout\n* Now check both top level and output directories when removing logfile\n\n#### *v0.3.0*\n\nChanges:\n* The `output_files` attribute now stores the full file path for each output file, rather than just the file name as was done previously.\n\n#### *v0.2.5*\n\nNew features:\n* Added configuration option for path to the mothur executable, thereby adding support for any mothur executable location \n  (previously mothur had to be in users PATH environment variable).\n\n#### *v0.2.4*\n\nNew features:\n* Enabled passing python native types as command parameters, which are then converted to mothur compatible types as needed\n* Added parsing and saving of the output files generated by the last run mothur command\n* Improved documentation and examples\n\n#### *v0.2.3*\n\nBug fixes:\n* Fixed current files not being saved correctly to the mothur obejct after execution\n\n#### *v0.2.2*\n\nChanges:\n* No longer return the mothur object. If it is desired to store the altered object as a copy then the deepcopy function in the copy package should be used\n\nBug fixes:\n* Fixed verbosity level affecting the parsing of current files/dirs from stdout\n* Only update the current files/dirs for the mothur object once execution of mothur ends successfully\n* Fixed calls to unimplemented dunder methods (i.e. __deepcopy__) being parsed as mothur commands\n\nNew features:\n* Can set the seed that mothur uses for its random number generation\n* Added more unittests\n\n#### *v0.2.1*\n\nBug fixes:\n* Fixed bug where python failed to raise an error if mothur did\n\nNew features:\n* Use of an invalid command now raises an error in python, halting execution. Previously this would fail silently.\n\n#### *v0.2.0*\n\nChanges:\n* Renamed project from Rhea to mothur_py to avoid confusion with the R package for 16S amplicon analysis. Mothur class \nnow needs to be imported from mothur_py instead.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcampenr%2Fmothur-py","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcampenr%2Fmothur-py","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcampenr%2Fmothur-py/lists"}