Python Fire is a library for automatically generating command line interfaces (CLIs) from absolutely any Python object.

Related tags

python cli
Overview

Python Fire PyPI

Python Fire is a library for automatically generating command line interfaces (CLIs) from absolutely any Python object.

  • Python Fire is a simple way to create a CLI in Python. [1]
  • Python Fire is a helpful tool for developing and debugging Python code. [2]
  • Python Fire helps with exploring existing code or turning other people's code into a CLI. [3]
  • Python Fire makes transitioning between Bash and Python easier. [4]
  • Python Fire makes using a Python REPL easier by setting up the REPL with the modules and variables you'll need already imported and created. [5]

Installation

To install Python Fire with pip, run: pip install fire

To install Python Fire with conda, run: conda install fire -c conda-forge

To install Python Fire from source, first clone the repository and then run: python setup.py install

Basic Usage

You can call Fire on any Python object:
functions, classes, modules, objects, dictionaries, lists, tuples, etc. They all work!

Here's an example of calling Fire on a function.

import fire

def hello(name="World"):
  return "Hello %s!" % name

if __name__ == '__main__':
  fire.Fire(hello)

Then, from the command line, you can run:

python hello.py  # Hello World!
python hello.py --name=David  # Hello David!
python hello.py --help  # Shows usage information.

Here's an example of calling Fire on a class.

import fire

class Calculator(object):
  """A simple calculator class."""

  def double(self, number):
    return 2 * number

if __name__ == '__main__':
  fire.Fire(Calculator)

Then, from the command line, you can run:

python calculator.py double 10  # 20
python calculator.py double --number=15  # 30

To learn how Fire behaves on functions, objects, dicts, lists, etc, and to learn about Fire's other features, see the Using a Fire CLI page.

For additional examples, see The Python Fire Guide.

Why is it called Fire?

When you call Fire, it fires off (executes) your command.

Where can I learn more?

Please see The Python Fire Guide.

Reference

Setup Command Notes
install pip install fire
Creating a CLI Command Notes
import import fire
Call fire.Fire() Turns the current module into a Fire CLI.
Call fire.Fire(component) Turns component into a Fire CLI.
Using a CLI Command Notes
Help command --help or command -- --help
REPL command -- --interactive Enters interactive mode.
Separator command -- --separator=X Sets the separator to X. The default separator is -.
Completion command -- --completion [shell] Generates a completion script for the CLI.
Trace command -- --trace Gets a Fire trace for the command.
Verbose command -- --verbose

Note that these flags are separated from the Fire command by an isolated --.

License

Licensed under the Apache 2.0 License.

Disclaimer

This is not an official Google product.

Issues
  • incorrect control code displayed in Windows console.

    incorrect control code displayed in Windows console.

    when I run the basic example code. there are some control code displayed as output text. I guess it probably some color effects?

    How do I avoid it?

    FLAGS --minputs=MINPUTS --moutputs=MOUTPUTS

    NOTES You can also use flags syntax for POSITIONAL ARGUMENTS

    bug help wanted 
    opened by wenbingl 27
  • Use fire without editing code directly

    Use fire without editing code directly

    Currently you have to add something like this to the end of your file just to mess around with fire:

    if __name__ == '__main__':
        fire.Fire()
    

    and then run with

    python path/to/code.py
    

    But it'd be neat if instead you could just do

    fire path/to/code.py
    

    and that does equivalent of exec appending the ifmain statement to the end.

    Not sure how to do it - I know kernprof does some magic to inject into builtins before exec'ing code. (or maybe you get a code object back from exit) - but this would make fire even better as a debugging tool as well.

    opened by jtratner 27
  • use --help or -h to show comment info

    use --help or -h to show comment info

    Is there any way that can use "-h" or "--help" to show comment of a function or class.

    example:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    """
    :authors: wanglichao
    :version: 1.0 of 2017-03-20
    
    """
    
    import fire
    
    
    def hello(name):
        """this is a hello test1
        """
        return 'Hello {name}!'.format(name=name)
    
    
    def hello2(name):
        """this is a hello test2
        """
        return 'Hello {name}!'.format(name=name)
    
    
    if __name__ == '__main__':
        fire.Fire()
    

    expect result:

    python hello.py -- --help
    
    Usage: hello.py [OPTIONS] COMMAND [ARGS]...
                 authors: wanglichao
                 version: 1.0 of 2017-03-20
    
    Options:
                 -- --help
                 -- --interactive
                 -- --trace
                 -- --verbose
    
    Command:
                 fire           inner command
                 hello          this is a hello test1
                 hello2         this is a hello test2
    
    opened by xidianwlc 20
  • Issue #108: Shortcuts for boolean arguments

    Issue #108: Shortcuts for boolean arguments

    In response to this issue. This adds a feature where a shortcut can be used for boolean arguments of functions. For example the function

    def foo(bar=False):

    can be invoked as foo -b to set bar to True. While developing this, I came across a couple concerns:

    • In detecting whether or not arguments matched the pattern of a bool shortcut, I decided that python's regex library was the best way to solve this problem. Is adding re to imports ok?
    • If a naming collision occurs (see final assert of testBoolShortcutParsing) the program raises a FireError describing the ambiguity. Is this a proper manner to use this error in?
    • Currently, if a shortcut doesn't match any function argument, it is parsed as-is. Should something else be done in this scenario?
    opened by alexshadley 17
  • should return error code on invalid parameters

    should return error code on invalid parameters

    When firing a fire created command with invalid parameters, the return code is always 0. Shouldn't this return an error code ?

    enhancement 
    opened by madoke 17
  • Fix several warnings in the diff example

    Fix several warnings in the diff example

    Fixes ResourceWarning unclosed file:

    examples/diff/diff.py:78: ResourceWarning: unclosed file <_io.TextIOWrapper name='/tmp/tmpnby8pemm' mode='U' encoding='UTF-8'>
        self.tolines = open(tofile, 'U').readlines()
    

    And DeprecationWarning 'U' mode is deprecated:

    examples/diff/diff_test.py::DiffTest::testUnifiedDiff
      examples/diff/diff.py:77: DeprecationWarning: 'U' mode is deprecated
        with open(fromfile, 'U') as f:
    
    opened by BoboTiG 14
  • fire.py: Use fire on arbitrary file or module.

    fire.py: Use fire on arbitrary file or module.

    opened by nealmcb 12
  • Remove `IPython` dependency from `fire.Fire` or improve load times some other way

    Remove `IPython` dependency from `fire.Fire` or improve load times some other way

    import IPython takes about 0.5 seconds on my machine to import and is the longest part of running simple fire scripts at the moment. Launching a python script and printing something takes 0.15 seconds so the total with import fire becomes about 0.65 seconds.

    It's only used in _EmbedIPython and inspectutils.py so maybe it can be optional for command line apps and the inspection part ported over (or placed in a different smaller package)? Would such a pull request be useful?

    enhancement 
    opened by ubershmekel 12
  • Add conda forge

    Add conda forge

    The recipe hasn't been accepted yet, but it should be soon.

    opened by CJ-Wright 12
  • Multi-line parameter descriptions in Google-style docstrings

    Multi-line parameter descriptions in Google-style docstrings

    Hey there! Quick question regarding the behavior of multi-line parameter descriptions in Google-style docstrings.

    Consider the following code:

    # main.py
    def foo(bar):
        """
        This does a foo on a bar.
    
        Args:
            bar (str): Though a simple parameter, this parameter will need a lot of
                verbiage to describe, requiring a second line.
        """
        print(f"Hi, {bar}!")
    
    if __name__ == "__main__":
        import fire
    
        fire.Fire(foo)
    

    When running main.py --help, the resulting man is:

    NAME
        main.py - This does a foo on a bar.
    
    SYNOPSIS
        main.py BAR
    
    DESCRIPTION
        This does a foo on a bar.
    
    POSITIONAL ARGUMENTS
        BAR
            Though a simple parameter, this parameter will need a lot of
    
    NOTES
        You can also use flags syntax for POSITIONAL ARGUMENTS
    

    Notice that we are losing the following line here.

    I'd expect the newline-containing description to be un-newlined (definitely not a word)

    NAME
        main.py - This does a foo on a bar.
    
    SYNOPSIS
        main.py BAR
    
    DESCRIPTION
        This does a foo on a bar.
    
    POSITIONAL ARGUMENTS
        BAR
            Though a simple parameter, this parameter will need a lot of verbiage to describe, requiring a second line.
    
    NOTES
        You can also use flags syntax for POSITIONAL ARGUMENTS
    

    Or maybe included with the newline, but in some way retaining the following line. Any plans to support this, or (likely) am I missing something?

    bug help wanted 
    opened by lukedeo 12
  • What condition does fire use to decide if input is a tuple or a string

    What condition does fire use to decide if input is a tuple or a string

    I'm playing with:

    from fire import Fire
    
    def f(a):
        print(f'{type(a)=:}')
        print(f'{a=:}')
    
    Fire(f)
    

    and see

    python toy.py -a x,y,z
    

    returns a tuple

    type(a)=<class 'tuple'>
    a=('x', 'y', 'z')
    

    But

    python toy.py -a a.txt,b.txt,c.txt
    type(a)=<class 'str'>
    a=a.txt,b.txt,c.txt
    

    returns a string, which is kind of confusing.

    Version:

    >>> fire.__version__
    '0.3.1'
    
    opened by zyxue 0
  • OLIMEX/KiCAD

Rk3326

    OLIMEX/KiCAD Rk3326

    null

    opened by ilw4r 0
  • Logging messages don't using logging

    Logging messages don't using logging

    https://github.com/google/python-fire/blob/c1266d0dbb2114514fcf8be62044344b5a51c733/fire/core.py#L239 https://github.com/google/python-fire/blob/c1266d0dbb2114514fcf8be62044344b5a51c733/fire/core.py#L287

    When I get the help message, includes INFO: messages like: INFO: Showing help with the command {cmd}

    I would like such logging messages to use Python's logging framework which would allow me to suppress and redirect such messages.

    opened by bovlb 2
  • Output help as markdown

    Output help as markdown

    Thanks for a useful tool. Would it be possible to generate the help output as markdown text, suitable for saving to github repos?

    opened by bovlb 1
  • Help Casts All Input Flags To UPPERCASE In Print

    Help Casts All Input Flags To UPPERCASE In Print

    When requesting help output all available flags are being cast to upper case. This makes it difficult if not impossible for users of the wrapper methods the exact case needed to call requiring opening the code to view or asking a developer for assistance which diminishes the intent of help as a self-help solution. Fire is also case sensitive when using the flags so its best that help output preserves case to avoid the mismatch.

    I would prefer not to have to conform, but rather have Fire make sense in the behavior.

    opened by Sn3akyP3t3 0
  • Add decorator to parse function type hints

    Add decorator to parse function type hints

    This allows to tell fire what types are expected by type hints (fixes #300, also see #327 and #260 ) and not change current behaviour by making it optional decorator.

    cla: yes 
    opened by keanpantraw 1
  • Passing function as an argument

    Passing function as an argument

    Hello, can i pass some functions to fire?, like lambda or other predefined?

    For example:

    from fire import Fire
    
    dictionary = {"key":"value"}
    Fire()
    
    >>> py file.py dictionary get lambda: list(dictionary.keys())[-1]
    "value"
    

    This cli passes a lambda function as an argument, is this possible using fire?

    opened by tory1103 0
  • is autocomplete working??

    is autocomplete working??

    Hi,

    I am learning Fire and am interested in how completion works.

    I created a script main.py

    import fire
    
    
    def hello(name="World"):
        return "Hello %s!" % name
    
    
    if __name__ == '__main__':
        fire.Fire(hello)
    
    

    ran the following command,

    python main.py -- --completion > completion
    
    source completion
    

    Now when I run python main.py and press <TAB> it does not seem provide cli parameter. Let me know if I am not using it correctly.

    opened by ShivKJ 1
  • Is it possible to return `argparser` for customization?

    Is it possible to return `argparser` for customization?

    fire can complete ~90% of the CLI needs for my application. However, the help documentation is only available during runtime in my case. Is there some way of getting access to the argparse parser from Fire and modifying it as a user? It looks like the overload-able information is available up to this point:

    https://github.com/google/python-fire/blob/ed44d8b801fc24e40729abef11b2dcbf6588d361/fire/core.py#L129

    After which it disappears into the void. I would love to be able to modify this parser by adding runtime information. Bonus points if after doing so, I can give it back to fire to call the component trace, etc. 🙂

    opened by ntjess 0
  • Add custom formatter for Fire result

    Add custom formatter for Fire result

    Fixes #344 (see issue for more details)

    This lets you define a function that will take the result from the Fire component and allows the user to alter it before fire looks at it to render it.

    Why? Because you want to define a global way of formatting your data for your CLI across a family of functions/classes where it is impractical (and a major pain) to wrap them all.

    Outputting tabular data:

    import random
    def data():
        return [
            {
                'is_up': random.choice([False, True]), 
                'value_A': random.random(), 
                'value_B': random.random() + 100,
                'id': random.randint(1000, 5000)} 
            for i in range(8)
        ]
    
    import fire
    fire.Fire(data)
    

    Outputs this:

    {"is_up": true, "value_A": 0.6004291859538904, "value_B": 100.77910907893889, "id": 474}
    {"is_up": false, "value_A": 0.1406617230697117, "value_B": 100.35721554966845, "id": 740}
    {"is_up": true, "value_A": 0.3612392830626744, "value_B": 100.60814663568802, "id": 509}
    {"is_up": false, "value_A": 0.11247653550250092, "value_B": 100.2673181440675, "id": 305}
    {"is_up": false, "value_A": 0.9505598630828166, "value_B": 100.84615141986525, "id": 85}
    {"is_up": true, "value_A": 0.17544933002396768, "value_B": 100.66062056951291, "id": 385}
    {"is_up": false, "value_A": 0.25245927587860695, "value_B": 100.75492369068093, "id": 923}
    {"is_up": true, "value_A": 0.9237200249249168, "value_B": 100.94228120845642, "id": 702}
    

    But if we can define a formatter.

    import tabulate
    
    def fancy_table(result):
        if not result:  # show a message instead of an empty response
            return 'nada. sorry.'
        
        # display a list of dicts as a table
        if isinstance(result, (list, tuple)) and all(isinstance(x, dict) for x in result):
            return tabulate.tabulate([
                {col: cell_format(value) for col, value in row.items()}
                for row in result
            ], headers="keys")
    
        return result  # otherwise, let fire handle it
    
    def cell_format(value, decimals=3, bool=('🌹', '🥀')):
        if value is True:
            return bool[0]
        if value is False:
            return bool[1]
        if isinstance(value, float):
            return '{:.{}f}'.format(value, decimals)
        return value
    
    fire.Fire(data, formatter=fancy_table)
    

    Outputs this:

    is_up      value_A    value_B    id
    -------  ---------  ---------  ----
    🌹           0.115    100.013  1821
    🌹           0.439    100.167  4242
    🥀           0.68     100.345  2937
    🥀           0.074    100.119  4675
    🌹           0.189    100.462  4571
    🌹           0.221    100.342  1522
    🌹           0.02     100.452  2363
    🥀           0.023    100.812  2433
    

    Using a formatter means that:

    • if you don't provide a formatter, or if your formatter returns the original value (lambda x: x) then nothing is changed
    • if you want to change how some value is displayed, you can just return what you want it to render as e.g. lambda x: {'idk why, but': x} if isinstance(x, list) else x
    • if you are unable to make a class __str__ representation look like you want it to, you can handle it in the formatter instead e.g. lambda x: custom_str(x) if isinstance(x, some_class) else x
    • if you want to display nested dictionaries as yaml, you can use yaml.dump as a formatter
    • you can suppress output e.g. lambda x: None
    cla: yes 
    opened by beasteers 1
Releases(v0.4.0)
  • v0.4.0(Jan 22, 2021)

    Changelist

    • Support for Python 3.8 and Python 3.9
    • Argument types and defaults appear in help text
    • Support for asyncio coroutines
    • Support for modules and Python files with python -m fire
    • Keyword argument info from rst docstrings appears in help text
    • Bug fix for missing parts of multiline argument descriptions from Google and Numpy style docstrings.
    • Packaging of enum34
    • Support functions even when they override getattr in non-standard ways. (e.g. supports BeautifulSoup)

    Highlighted change: python -m fire

    You can use Python Fire without ever modifying your code. To use it, first install Python Fire with pip install fire. Then simply run python -m fire path/to/yourfile.py or python -m fire path.to.yourmodule.

    This is both a fast way to use Python Fire to create a CLI from your code, and a way to apply Python Fire quickly to a codebase you don't have access to.

    Source code(tar.gz)
    Source code(zip)
  • v0.3.1(Apr 7, 2020)

  • v0.3.0(Mar 24, 2020)

    Assorted Improvements in Python Fire v0.3.0

    • Use Fire on third-party code without making any code changes: python -m fire <module>
    • Docstring parsing fix for all lines are blank f01aad347632791e3438c1a753e42a514520d690
    • Improved parsing of numpy-style docstrings
    • #187 Expose built-in functions from the standard library (e.g. sin, cos)
    • #149 Support objects implementing __getattr__
    • #205 Fix ctrl-C handling in help screens
    • Support functools.wraps and lru_cache decorated functions
    • Better support for objects with properties
    • Objects with custom __str__ are now treated as Values. E.g. If such an object appears in a dict, the dict will still print in line-by-line mode rather than showing a help screen by default.
    • Formatting on Windows works properly now
    Source code(tar.gz)
    Source code(zip)
  • v0.2.1(Aug 1, 2019)

  • v0.1.3(Feb 23, 2018)

    This release has a few small improvements:

    • Do not treat arguments that start with '--' as strings [#99]
    • Fix for BinOps in args [#96]
    • six.u for Python 3 compatability in fuzz tests [#111]

    And a small packaging improvement:

    • Files in PyPi archive are world readable. [#107]
    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(Jul 26, 2019)

    Python Fire v0.2.0

    If you're new to Python Fire:

    1. Welcome! 🎉
    2. Fire automatically generates command line interfaces from any Python object you give it. 🔥

    e.g. You can call Fire on a function, as in this example (but you can also call Fire on anything else: classes, objects, dicts, etc. -- they all work.)

    def hello(name="World"):
      return "Hello %s!" % name
    
    fire.Fire(hello)
    
    hello.py --name=David  # Hello David!
    

    pip install fire to get started.

    Improvements in v0.2.0

    • Help and usage screens Help screens now have a man-page appearance and are shown with less-style pagination. Usage screens are shown when a user-error is encountered. The help and usage screens are considerably cleaner than the default output in previous versions of Fire.
    • Custom serialization If you define a custom __str__ method on an object, that will be used to serialize the object when it is the final result of a Fire command. This means better support for numpy arrays, and better support for custom types.
    • Docstring parsing Notably, docstrings are parsed in order to determine the descriptions to use for arguments in the help screens. We largely support (but not fully) Google, numpy, and RST style docstrings. These are the three most common styles of docstring used in Python code.
    • Access --help naturally You no longer need to separate --help from your command with an extra --. Simply running command -h or command --help will give help, provided there isn't an argument named help in your component.
    • NamedTuples can be indexed both by their field names and by their indexes.
    • Callable objects can both be called, and their members can be accessed. You must use flag syntax to call a callable object; you cannot pass their arguments positionally.
    • Single-hyphen flags are supported You can now specify -flag instead of --flag if preferred. Both work.
    • Short-flags are permitted when their use is unambiguous E.g. if your function has argument alpha, then you can specify its value with -a.
    • Fish completion support
    Source code(tar.gz)
    Source code(zip)
  • v0.1.2(Aug 29, 2017)

    Improvements

    • IPython is fully optional! [#7] Now Fire's only dependency is six (the Python 2, 3 compatibility module) which is fairly light weight. If you use Fire without IPython, we call it "Fire Lite." Pun intended.
    • The command argument accepts lists [#53] fire.Fire's optional command argument now accepts either a sequence of arguments or a single string. Previously the command argument only accepted a string.
    • New mkdocs documentation We've started using mkdocs for documentation. The documentation is available at https://google.github.io/python-fire.
    • Packaging improvements: the license file is now included in the release.
    • Output is no longer force converted to ASCII.
    Source code(tar.gz)
    Source code(zip)
  • v0.1.1(May 21, 2017)

    New Features

    • The Python Fire Guide is available
    • Support for annotations in functions
    • Support for keyword-only arguments in functions
    • Faster loading via lazy imports

    Bug Fixes

    • Serialize empty dictionaries
    • Serialize dictionaries with circular dependencies
    • Support non-comparable objects, numpy arrays, etc
    • Help for objects without source files
    • Completion scripts for top-level functions
    Source code(tar.gz)
    Source code(zip)
Owner
Google
Google ❤️ Open Source
Google
Cleo allows you to create beautiful and testable command-line interfaces.

Cleo Create beautiful and testable command-line interfaces. Cleo is mostly a higher level wrapper for CliKit, so a lot of the components and utilities

Sébastien Eustace 763 Oct 15, 2021
Pythonic command line arguments parser, that will make you smile

docopt creates beautiful command-line interfaces Video introduction to docopt: PyCon UK 2012: Create *beautiful* command-line interfaces with Python N

null 7.5k Oct 25, 2021
A drop-in replacement for argparse that allows options to also be set via config files and/or environment variables.

ConfigArgParse Overview Applications with more than a handful of user-settable options are best configured through a combination of command line args,

null 544 Oct 18, 2021
Python and tab completion, better together.

argcomplete - Bash tab completion for argparse Tab complete all the things! Argcomplete provides easy, extensible command line tab completion of argum

Andrey Kislyuk 991 Oct 22, 2021
Rich is a Python library for rich text and beautiful formatting in the terminal.

Rich 中文 readme • lengua española readme • Läs på svenska Rich is a Python library for rich text and beautiful formatting in the terminal. The Rich API

Will McGugan 30.4k Oct 24, 2021
Library for building powerful interactive command line applications in Python

Python Prompt Toolkit prompt_toolkit is a library for building powerful interactive command line applications in Python. Read the documentation on rea

prompt-toolkit 7.3k Oct 23, 2021
A thin, practical wrapper around terminal capabilities in Python

Blessings Coding with Blessings looks like this... from blessings import Terminal t = Terminal() print(t.bold('Hi there!')) print(t.bold_red_on_brig

Erik Rose 1.3k Oct 19, 2021
Cement is an advanced Application Framework for Python, with a primary focus on CLI

Cement Framework Cement is an advanced Application Framework for Python, with a primary focus on Command Line Interfaces (CLI). Its goal is to introdu

Data Folk Labs, LLC 1k Oct 25, 2021
Python Command-line Application Tools

Clint: Python Command-line Interface Tools Clint is a module filled with a set of awesome tools for developing commandline applications. C ommand L in

Kenneth Reitz Archive 57 Oct 12, 2021
Color text streams with a polished command line interface

colout(1) -- Color Up Arbitrary Command Output Synopsis colout [-h] [-r RESOURCE] colout [-g] [-c] [-l min,max] [-a] [-t] [-T DIR] [-P DIR] [-d COLORM

nojhan 1.1k Sep 28, 2021
sane is a command runner made simple.

sane is a command runner made simple.

Miguel M. 14 Jul 24, 2021
A fast, stateless http slash commands framework for scale. Built by the Crunchy bot team.

Roid ?? A fast, stateless http slash commands framework for scale. Built by the Crunchy bot team. ?? Installation You can install roid in it's default

Harrison Burt 7 Oct 17, 2021
Python composable command line interface toolkit

$ click_ Click is a Python package for creating beautiful command line interfaces in a composable way with as little code as necessary. It's the "Comm

The Pallets Projects 11.5k Oct 24, 2021
Simple cross-platform colored terminal text in Python

Colorama Makes ANSI escape character sequences (for producing colored terminal text and cursor positioning) work under MS Windows. PyPI for releases |

Jonathan Hartley 2.6k Oct 23, 2021
Python library that measures the width of unicode strings rendered to a terminal

Introduction This library is mainly for CLI programs that carefully produce output for Terminals, or make pretend to be an emulator. Problem Statement

Jeff Quast 250 Oct 15, 2021
plotting in the terminal

bashplotlib plotting in the terminal what is it? bashplotlib is a python package and command line tool for making basic plots in the terminal. It's a

Greg Lamp 1.6k Oct 17, 2021
emoji terminal output for Python

Emoji Emoji for Python. This project was inspired by kyokomi. Example The entire set of Emoji codes as defined by the unicode consortium is supported

Taehoon Kim 1.3k Oct 16, 2021
A cross platform package to do curses-like operations, plus higher level APIs and widgets to create text UIs and ASCII art animations

ASCIIMATICS Asciimatics is a package to help people create full-screen text UIs (from interactive forms to ASCII animations) on any platform. It is li

null 2.8k Oct 23, 2021
CalcuPy 📚 Create console-based calculators in a few lines of code.

CalcuPy ?? Create console-based calculators in a few lines of code. ?? Installation pip install calcupy ?? Usage from calcupy import Calculator calc

Dylan Tintenfich 6 Sep 26, 2021