Add Arithmetic formatter
This commit is contained in:
parent
1150f89cb0
commit
8728366e8f
10 changed files with 321 additions and 0 deletions
|
@ -0,0 +1,2 @@
|
|||
language = "python3"
|
||||
run = "python main.py"
|
|
@ -0,0 +1,3 @@
|
|||
# Arithmetic Formatter
|
||||
|
||||
This is the boilerplate for the Arithmetic Formatter project. Instructions for building your project can be found at https://www.freecodecamp.org/learn/scientific-computing-with-python/scientific-computing-with-python-projects/arithmetic-formatter
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,40 @@
|
|||
import re
|
||||
|
||||
|
||||
def arithmetic_arranger(problems, solve=False):
|
||||
line1 = ""
|
||||
line2 = ""
|
||||
line3 = ""
|
||||
line4 = ""
|
||||
if len(problems) > 5:
|
||||
return "Error: Too many problems."
|
||||
|
||||
for problem in problems:
|
||||
op = re.search('\\s[+-]\\s', problem)
|
||||
if op is None:
|
||||
return "Error: Operator must be '+' or '-'."
|
||||
op = op.group().strip()
|
||||
problem = problem.split(op)
|
||||
a, b = problem[0].strip(), problem[1].strip()
|
||||
if not a.isdigit() or not b.isdigit(): return "Error: Numbers must only contain digits."
|
||||
if len(a) > 4 or len(b) > 4: return "Error: Numbers cannot be more than four digits."
|
||||
if len(line1) > 0:
|
||||
line1 = line1 + 4 * " "
|
||||
line2 = line2 + 4 * " "
|
||||
line3 = line3 + 4 * " "
|
||||
pad = len(a) + 2 if len(a) > len(b) else len(b) + 2
|
||||
line1 = line1 + a.rjust(pad, " ")
|
||||
line2 = line2 + op + (pad - 1 - len(b)) * " " + b
|
||||
line3 = line3 + pad * "-"
|
||||
if solve is True:
|
||||
if len(line4) > 0:
|
||||
line4 = line4 + 4 * " "
|
||||
if op == "+":
|
||||
x = int(a) + int(b)
|
||||
line4 = line4 + str(x).rjust(pad, " ")
|
||||
else:
|
||||
x = int(a) - int(b)
|
||||
line4 = line4 + str(x).rjust(pad, " ")
|
||||
arranged_problems = line1 + '\n' + line2 + '\n' + line3
|
||||
if len(line4) > 0: arranged_problems = arranged_problems + '\n' + line4
|
||||
return arranged_problems
|
11
8-scientific-computing-python/1-arithmetic-formatter/main.py
Normal file
11
8-scientific-computing-python/1-arithmetic-formatter/main.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
# This entrypoint file to be used in development. Start by reading README.md
|
||||
from pytest import main
|
||||
|
||||
from arithmetic_arranger import arithmetic_arranger
|
||||
|
||||
|
||||
print(arithmetic_arranger(["32 + 698", "3801 - 2", "45 + 43", "123 + 49"], True))
|
||||
|
||||
|
||||
# Run unit tests automatically
|
||||
main(['-vv'])
|
154
8-scientific-computing-python/1-arithmetic-formatter/poetry.lock
generated
Normal file
154
8-scientific-computing-python/1-arithmetic-formatter/poetry.lock
generated
Normal file
|
@ -0,0 +1,154 @@
|
|||
[[package]]
|
||||
name = "atomicwrites"
|
||||
version = "1.4.1"
|
||||
description = "Atomic file writes."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
|
||||
[[package]]
|
||||
name = "attrs"
|
||||
version = "22.1.0"
|
||||
description = "Classes Without Boilerplate"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
|
||||
[package.extras]
|
||||
dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"]
|
||||
docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"]
|
||||
tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"]
|
||||
tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"]
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
description = "Cross-platform colored terminal text."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||
|
||||
[[package]]
|
||||
name = "iniconfig"
|
||||
version = "1.1.1"
|
||||
description = "iniconfig: brain-dead simple config-ini parsing"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "21.3"
|
||||
description = "Core utilities for Python packages"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
|
||||
|
||||
[[package]]
|
||||
name = "pluggy"
|
||||
version = "1.0.0"
|
||||
description = "plugin and hook calling mechanisms for python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.extras]
|
||||
dev = ["pre-commit", "tox"]
|
||||
testing = ["pytest", "pytest-benchmark"]
|
||||
|
||||
[[package]]
|
||||
name = "py"
|
||||
version = "1.11.0"
|
||||
description = "library with cross-python path, ini-parsing, io, code, log facilities"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
|
||||
[[package]]
|
||||
name = "pyparsing"
|
||||
version = "3.0.9"
|
||||
description = "pyparsing module - Classes and methods to define and execute parsing grammars"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6.8"
|
||||
|
||||
[package.extras]
|
||||
diagrams = ["jinja2", "railroad-diagrams"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "6.2.5"
|
||||
description = "pytest: simple powerful testing with Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
|
||||
attrs = ">=19.2.0"
|
||||
colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
||||
iniconfig = "*"
|
||||
packaging = "*"
|
||||
pluggy = ">=0.12,<2.0"
|
||||
py = ">=1.8.2"
|
||||
toml = "*"
|
||||
|
||||
[package.extras]
|
||||
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.10.2"
|
||||
description = "Python Library for Tom's Obvious, Minimal Language"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
|
||||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.8"
|
||||
content-hash = "b0cfcbac06077cd402c6bf0fdbc3a1f9250d0198334abbec48a77f542707e82a"
|
||||
|
||||
[metadata.files]
|
||||
atomicwrites = [
|
||||
{file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"},
|
||||
]
|
||||
attrs = [
|
||||
{file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"},
|
||||
{file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"},
|
||||
]
|
||||
colorama = [
|
||||
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||
]
|
||||
iniconfig = [
|
||||
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
|
||||
{file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
|
||||
]
|
||||
packaging = [
|
||||
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
|
||||
{file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
|
||||
]
|
||||
pluggy = [
|
||||
{file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
|
||||
{file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
|
||||
]
|
||||
py = [
|
||||
{file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
|
||||
{file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
|
||||
]
|
||||
pyparsing = [
|
||||
{file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"},
|
||||
{file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"},
|
||||
]
|
||||
pytest = [
|
||||
{file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"},
|
||||
{file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"},
|
||||
]
|
||||
toml = [
|
||||
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
|
||||
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
|
||||
]
|
|
@ -0,0 +1,15 @@
|
|||
[tool.poetry]
|
||||
name = "fcc-arithmetic-formatter"
|
||||
version = "0.1.0"
|
||||
description = ""
|
||||
authors = ["Your Name <you@example.com>"]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.8"
|
||||
pytest = "^6.2.4"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
|
@ -0,0 +1,19 @@
|
|||
{ pkgs }: {
|
||||
deps = [
|
||||
pkgs.python38Full
|
||||
pkgs.python38Packages.pytest
|
||||
];
|
||||
env = {
|
||||
PYTHON_LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [
|
||||
# Needed for pandas / numpy
|
||||
pkgs.stdenv.cc.cc.lib
|
||||
pkgs.zlib
|
||||
# Needed for pygame
|
||||
pkgs.glib
|
||||
# Needed for matplotlib
|
||||
pkgs.xorg.libX11
|
||||
];
|
||||
PYTHONBIN = "${pkgs.python38Full}/bin/python3.8";
|
||||
LANG = "en_US.UTF-8";
|
||||
};
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
import pytest
|
||||
|
||||
from arithmetic_arranger import arithmetic_arranger
|
||||
|
||||
test_cases = [
|
||||
pytest.param(
|
||||
[['3801 - 2', '123 + 49']],
|
||||
' 3801 123\n'
|
||||
'- 2 + 49\n'
|
||||
'------ -----',
|
||||
'Expected different output when calling "arithmetic_arranger()" with ["3801 - 2", "123 + 49"]',
|
||||
id='test_two_problems_arrangement1'),
|
||||
pytest.param(
|
||||
[['1 + 2', '1 - 9380']],
|
||||
' 1 1\n'
|
||||
'+ 2 - 9380\n'
|
||||
'--- ------',
|
||||
'Expected different output when calling "arithmetic_arranger()" with ["1 + 2", "1 - 9380"]',
|
||||
id='test_two_problems_arrangement2'),
|
||||
pytest.param(
|
||||
[['3 + 855', '3801 - 2', '45 + 43', '123 + 49']],
|
||||
' 3 3801 45 123\n'
|
||||
'+ 855 - 2 + 43 + 49\n'
|
||||
'----- ------ ---- -----',
|
||||
'Expected different output when calling "arithmetic_arranger()" with ["3 + 855", "3801 - 2", "45 + 43", "123 + 49"]',
|
||||
id='test_four_problems_arrangement'),
|
||||
pytest.param(
|
||||
[['11 + 4', '3801 - 2999', '1 + 2', '123 + 49', '1 - 9380']],
|
||||
' 11 3801 1 123 1\n'
|
||||
'+ 4 - 2999 + 2 + 49 - 9380\n'
|
||||
'---- ------ --- ----- ------',
|
||||
'Expected different output when calling "arithmetic_arranger()" with ["11 + 4", "3801 - 2999", "1 + 2", "123 + 49", "1 - 9380"]',
|
||||
id='test_five_problems_arrangement'),
|
||||
pytest.param(
|
||||
[['44 + 815', '909 - 2', '45 + 43', '123 + 49',
|
||||
'888 + 40', '653 + 87']],
|
||||
'Error: Too many problems.',
|
||||
'Expected calling "arithmetic_arranger()" with more than five problems to return "Error: Too many problems."',
|
||||
id='test_too_many_problems'),
|
||||
pytest.param(
|
||||
[['3 / 855', '3801 - 2', '45 + 43', '123 + 49']],
|
||||
"Error: Operator must be '+' or '-'.",
|
||||
'''Expected calling "arithmetic_arranger()" with a problem that uses the "/" operator to return "Error: Operator must be '+' or '-'."''',
|
||||
id='test_incorrect_operator'),
|
||||
pytest.param(
|
||||
[['24 + 85215', '3801 - 2', '45 + 43', '123 + 49']],
|
||||
'Error: Numbers cannot be more than four digits.',
|
||||
'Expected calling "arithmetic_arranger()" with a problem that has a number over 4 digits long to return "Error: Numbers cannot be more than four digits."',
|
||||
id='test_too_many_digits'),
|
||||
pytest.param(
|
||||
[['98 + 3g5', '3801 - 2', '45 + 43', '123 + 49']],
|
||||
'Error: Numbers must only contain digits.',
|
||||
'Expected calling "arithmetic_arranger()" with a problem that contains a letter character in the number to return "Error: Numbers must only contain digits."',
|
||||
id='test_only_digits'),
|
||||
pytest.param(
|
||||
[['3 + 855', '988 + 40'], True],
|
||||
' 3 988\n'
|
||||
'+ 855 + 40\n'
|
||||
'----- -----\n'
|
||||
' 858 1028',
|
||||
'Expected solutions to be correctly displayed in output when calling "arithmetic_arranger()" with ["3 + 855", "988 + 40"] and a second argument of `True`.',
|
||||
id='test_two_problems_with_solutions'),
|
||||
pytest.param(
|
||||
[['32 - 698', '1 - 3801', '45 + 43', '123 + 49', '988 + 40'], True],
|
||||
' 32 1 45 123 988\n'
|
||||
'- 698 - 3801 + 43 + 49 + 40\n'
|
||||
'----- ------ ---- ----- -----\n'
|
||||
' -666 -3800 88 172 1028',
|
||||
'Expected solutions to be correctly displayed in output when calling "arithmetic_arranger()" with five arithmetic problems and a second argument of `True`.',
|
||||
id='test_five_problems_with_solutions'),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('arguments,expected_output,fail_message', test_cases)
|
||||
def test_template(arguments, expected_output, fail_message):
|
||||
actual = arithmetic_arranger(*arguments)
|
||||
assert actual == expected_output, fail_message
|
Reference in a new issue