python-taxes 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- python_taxes-0.1.0/PKG-INFO +13 -0
- python_taxes-0.1.0/README.md +0 -0
- python_taxes-0.1.0/pyproject.toml +23 -0
- python_taxes-0.1.0/src/python_taxes/__init__.py +0 -0
- python_taxes-0.1.0/src/python_taxes/federal/calculators/__init__.py +13 -0
- python_taxes-0.1.0/src/python_taxes/federal/calculators/medicare.py +88 -0
- python_taxes-0.1.0/src/python_taxes/federal/calculators/social_security.py +32 -0
@@ -0,0 +1,13 @@
|
|
1
|
+
Metadata-Version: 2.3
|
2
|
+
Name: python-taxes
|
3
|
+
Version: 0.1.0
|
4
|
+
Summary: Development in progress - please come back later.
|
5
|
+
Author: Stacy Noland
|
6
|
+
Author-email: 46572585+stacynoland@users.noreply.github.com
|
7
|
+
Requires-Python: >=3.13
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
9
|
+
Classifier: Programming Language :: Python :: 3.13
|
10
|
+
Requires-Dist: pydantic (>=2.10.6,<3.0.0)
|
11
|
+
Description-Content-Type: text/markdown
|
12
|
+
|
13
|
+
|
File without changes
|
@@ -0,0 +1,23 @@
|
|
1
|
+
[project]
|
2
|
+
name = "python-taxes"
|
3
|
+
version = "0.1.0"
|
4
|
+
description = "Development in progress - please come back later."
|
5
|
+
authors = [
|
6
|
+
{name = "Stacy Noland", email = "46572585+stacynoland@users.noreply.github.com"}
|
7
|
+
]
|
8
|
+
readme = "README.md"
|
9
|
+
requires-python = ">=3.13"
|
10
|
+
dependencies = [
|
11
|
+
"pydantic (>=2.10.6,<3.0.0)"
|
12
|
+
]
|
13
|
+
|
14
|
+
[tool.poetry]
|
15
|
+
packages = [{include = "python_taxes", from = "src"}]
|
16
|
+
|
17
|
+
|
18
|
+
[tool.poetry.group.dev.dependencies]
|
19
|
+
pytest = "^8.3.5"
|
20
|
+
|
21
|
+
[build-system]
|
22
|
+
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
23
|
+
build-backend = "poetry.core.masonry.api"
|
File without changes
|
@@ -0,0 +1,88 @@
|
|
1
|
+
from decimal import Decimal
|
2
|
+
from typing import Annotated, Literal, Optional
|
3
|
+
|
4
|
+
from pydantic import Field, StrictBool, validate_call
|
5
|
+
|
6
|
+
from . import rounding
|
7
|
+
|
8
|
+
|
9
|
+
STANDARD_PERCENT = Decimal("1.45") / 100
|
10
|
+
|
11
|
+
SELF_EMPLOYED_PERCENT = Decimal("2.9") / 100
|
12
|
+
|
13
|
+
ADDITIONAL_PERCENT = Decimal("0.9") / 100
|
14
|
+
|
15
|
+
DEFAULT_THRESHOLD = Decimal("200000")
|
16
|
+
|
17
|
+
status_threshold = {
|
18
|
+
'single': DEFAULT_THRESHOLD,
|
19
|
+
'married': Decimal("250000"),
|
20
|
+
'separate': Decimal("125000"),
|
21
|
+
'hoh': DEFAULT_THRESHOLD,
|
22
|
+
}
|
23
|
+
|
24
|
+
|
25
|
+
@validate_call
|
26
|
+
def withholding(
|
27
|
+
taxable_wages: Annotated[Decimal, Field(ge=Decimal("0.01"), decimal_places=2)],
|
28
|
+
taxable_wages_ytd: Optional[
|
29
|
+
Annotated[Decimal, Field(ge=Decimal("0.01"), decimal_places=2)]] = None,
|
30
|
+
self_employed: StrictBool = False,
|
31
|
+
rounded: StrictBool = False,
|
32
|
+
) -> Decimal:
|
33
|
+
"""Required amount to withhold regardless of filing status
|
34
|
+
|
35
|
+
Parameters:
|
36
|
+
taxable_wages -- Earned this period
|
37
|
+
taxable_wages_ytd -- Earned this year
|
38
|
+
self_employed -- Person/employee is self-employed (default False)
|
39
|
+
round -- Round response to nearest whole dollar amount (default False)
|
40
|
+
"""
|
41
|
+
|
42
|
+
if not taxable_wages_ytd:
|
43
|
+
taxable_wages_ytd = 0
|
44
|
+
|
45
|
+
if self_employed:
|
46
|
+
tax_rate = SELF_EMPLOYED_PERCENT
|
47
|
+
else:
|
48
|
+
tax_rate = STANDARD_PERCENT
|
49
|
+
|
50
|
+
if (taxable_wages > DEFAULT_THRESHOLD
|
51
|
+
or (taxable_wages_ytd + taxable_wages) > DEFAULT_THRESHOLD):
|
52
|
+
tax_rate = tax_rate + ADDITIONAL_PERCENT
|
53
|
+
|
54
|
+
return (taxable_wages * tax_rate).quantize(rounding[rounded])
|
55
|
+
|
56
|
+
|
57
|
+
@validate_call
|
58
|
+
def additional_withholding(
|
59
|
+
taxable_wages_ytd: Annotated[Decimal, Field(ge=Decimal("0.01"), decimal_places=2)],
|
60
|
+
self_employed: StrictBool = False,
|
61
|
+
status: Optional[Literal['single', 'married', 'separate' 'hoh']] = 'single',
|
62
|
+
rounded: StrictBool = False,
|
63
|
+
) -> Decimal:
|
64
|
+
"""Additional withholding based on status
|
65
|
+
|
66
|
+
Parameters:
|
67
|
+
taxable_wages_ytd -- Earned this year
|
68
|
+
self_employed -- Person/employee is self-employed (default False)
|
69
|
+
status -- Filing status of person (default 'single')
|
70
|
+
round -- Round response to nearest whole dollar amount (default False)
|
71
|
+
"""
|
72
|
+
|
73
|
+
if self_employed:
|
74
|
+
tax_rate = SELF_EMPLOYED_PERCENT
|
75
|
+
else:
|
76
|
+
tax_rate = STANDARD_PERCENT
|
77
|
+
|
78
|
+
threshold = status_threshold[status]
|
79
|
+
|
80
|
+
if taxable_wages_ytd > threshold:
|
81
|
+
wages_over_threshold = taxable_wages_ytd - threshold
|
82
|
+
med_taxes = (taxable_wages_ytd - wages_over_threshold) * tax_rate
|
83
|
+
tax_rate = tax_rate + ADDITIONAL_PERCENT
|
84
|
+
med_taxes = med_taxes + (wages_over_threshold * tax_rate)
|
85
|
+
else:
|
86
|
+
med_taxes = taxable_wages_ytd * tax_rate
|
87
|
+
|
88
|
+
return med_taxes.quantize(rounding[rounded])
|
@@ -0,0 +1,32 @@
|
|
1
|
+
from decimal import Decimal
|
2
|
+
from typing import Annotated, Literal, Optional
|
3
|
+
|
4
|
+
from pydantic import Field, StrictBool, validate_call
|
5
|
+
|
6
|
+
from . import rounding
|
7
|
+
|
8
|
+
STANDARD_TAX = Decimal('6.200') / 100
|
9
|
+
|
10
|
+
SELF_EMPLOYED_TAX = Decimal('12.400') / 100
|
11
|
+
|
12
|
+
|
13
|
+
@validate_call
|
14
|
+
def withholding(
|
15
|
+
taxable_wages: Annotated[Decimal, Field(ge=0.01, decimal_places=2)],
|
16
|
+
self_employed: StrictBool = False,
|
17
|
+
rounded: StrictBool = False,
|
18
|
+
) -> Decimal:
|
19
|
+
"""Social security tax withholding.
|
20
|
+
|
21
|
+
Parameters:
|
22
|
+
taxable_wages -- Total wages to be taxed
|
23
|
+
self_employed -- Person/employee is self-employed (default False)
|
24
|
+
round -- Round response to nearest whole dollar amount (default False)
|
25
|
+
"""
|
26
|
+
|
27
|
+
if self_employed:
|
28
|
+
tax_rate = SELF_EMPLOYED_TAX
|
29
|
+
else:
|
30
|
+
tax_rate = STANDARD_TAX
|
31
|
+
|
32
|
+
return (taxable_wages * tax_rate).quantize(rounding[rounded])
|