syriantaxescli
A command-line tool for calculating Syrian salary and compensation taxes, built with Typer on top of the syriantaxes library.
Features
- Gross to net: the taxes, social security and net of a gross salary and compensations.
- Net to gross: the gross salary and compensations that pay a wanted net total.
- Salary scales: the gross for a whole range of net totals.
- Tax rules you can change: brackets, rates, minimum salary, rounding and social security, from
options or environment variables;
sytax rulesshows what is in use. - Output: rich tables or JSON, or export to
.xlsx,.csv,.jsonor.jsonl.
Installation
pip install syriantaxescli
Or with uv:
uv tool install syriantaxescli
Usage
sytax [GLOBAL OPTIONS] COMMAND [ARGS] [OPTIONS]
| Command | Aliases | What it does |
|---|---|---|
gross |
g |
Taxes and net of a gross salary and (optional) compensations. |
net |
n |
Gross salary and compensations for a wanted net total. |
range |
ar, r |
A salary scale for net totals from START to STOP every STEP. |
rules |
The tax rules in use, after config files, env vars and options. | |
config |
cfg |
show, path, init, presets: see Configuration. |
Amounts can be written as 1000000, 1,000,000, 1_000_000 or 1e6.
Examples
# 1,000,000 salary and 100,000 compensations
sytax gross 1000000 100000
# The same, with social security on an insured salary of 750,000
sytax gross 1000000 100000 --insured-salary 750000
# What gross pays 1,500,000 net, a quarter of it as compensations?
sytax net 1500000 -r 0.25
# A salary scale from 1M to 2M net, exported to Excel
sytax range 1000000 2000000 100000 -r 0.25 -e scale.xlsx
# JSON for scripts
sytax gross 1000000 -o json
range defaults STOP to START x 10 and STEP to START / 10, and allows at most 1,000 rows
(all three are settings).
Output options
| Option | Description |
|---|---|
-o, --output [table|json] |
Print a table or JSON (default: setting output.format). |
--json-indent N |
JSON indentation; 0 prints one line (setting output.json_indent). |
-e, --export PATH |
Write a .xlsx, .csv, .json or .jsonl file instead. |
--overwrite |
Replace the export file if it exists (otherwise it is an error). |
Configuration
No value is hard-coded. Every default (brackets, rates, rounding, minimums, social security, output format, range limits, the default compensation share) comes from a preset: a TOML file bundled with sytax that describes one version of the law. Out of the box you configure nothing. When something differs for you, override only that value, in the layer that fits:
| Precedence | Layer | Use it for |
|---|---|---|
| 1 (lowest) | preset (--preset; default: the newest) |
The law itself |
| 2 | user file config.toml |
Your company's settings, everywhere |
| 3 | project file sytax.toml |
One payroll folder (found from the current folder upward) |
| 4 | --config FILE / SYRIANTAXES_CONFIG |
A file shared by a team |
| 5 | .env and SYRIANTAXES_* env vars |
CI, scripts, containers |
| 6 | global options (--ss, --fixed-tax-rate, ...) |
One-off overrides |
| 7 (highest) | -s/--set KEY=VALUE |
Any setting, one-off |
Tables merge key by key; lists (brackets) are replaced as a whole. sytax config path shows where
the user file lives (override its folder with SYRIANTAXES_CONFIG_HOME).
sytax config init # write ./sytax.toml: the preset, every key commented out
sytax config init --user # the same, for every folder
sytax config show --sources # every setting and the layer that set it
sytax config show -o toml # the effective settings, as a config file
sytax config presets # the bundled presets
A config file holds only what you change:
preset = "syria-2024"
[tax]
min_salary = 900_000
[net]
compensation_share = 0.25 # net and range pay a quarter as compensations unless -r says otherwise
One-off overrides go before the command:
sytax --ss gross 1000000
sytax --fixed-tax-rate 0.04 net 1500000
sytax -s tax.min_salary=900000 -s output.format=json range 1000000
sytax --preset syria-2024 gross 1000000 100000
Default rules (preset syria-2024)
| Salary bracket | Rate |
|---|---|
| 0 – 837,000 | 0% |
| 837,000 – 850,000 | 11% |
| 850,000 – 1,100,000 | 13% |
| 1,100,000 and above | 15% |
- Compensations are taxed at a flat 5%.
- Taxes are rounded half up to the nearest 100.
- Net targets below the 837,000 minimum salary can't be calculated.
- Social security (7%, minimum insured salary 750,000) is off unless you pass
--ss, settax.social_security.enabled = true, or givegrossan--insured-salary.
Global options and environment variables
| Global option | Environment variable | Setting |
|---|---|---|
--preset |
SYRIANTAXES_PRESET |
preset |
--config |
SYRIANTAXES_CONFIG |
|
--brackets-mins |
SYRIANTAXES_BRACKET_TAX_MINS |
tax.brackets[].lower |
--brackets-rates |
SYRIANTAXES_BRACKET_TAX_RATES |
tax.brackets[].rate |
--min-allowed-salary |
SYRIANTAXES_MIN_ALLOWED_SALARY |
tax.min_salary |
--fixed-tax-rate |
SYRIANTAXES_FIXED_TAX_RATE |
tax.compensation_tax_rate |
--taxes-rounding-method |
SYRIANTAXES_TAXES_ROUNDING_METHOD |
tax.rounding.method |
--taxes-round-to-nearest |
SYRIANTAXES_TAXES_ROUND_TO_NEAREST |
tax.rounding.step |
--ss/--no-ss |
SYRIANTAXES_SS_ENABLED |
tax.social_security.enabled |
--ss-deduction-rate |
SYRIANTAXES_SS_DEDUCTION_RATE |
tax.social_security.rate |
--min-ss-allowed-salary |
SYRIANTAXES_MIN_SS_ALLOWED_SALARY |
tax.social_security.min_salary |
--ss-rounding-method |
SYRIANTAXES_SS_ROUNDING_METHOD |
tax.social_security.rounding.method |
--ss-round-to-nearest |
SYRIANTAXES_SS_ROUND_TO_NEAREST |
tax.social_security.rounding.step |
Brackets are given by their lower bounds; each runs up to the next one and the last has no top.
Repeat the option once per bracket (--brackets-mins 0 --brackets-mins 1000000 ...), or separate
values with spaces in the environment variable; always set both lists. Rounding methods are the
decimal module's modes, in any case and with or without ROUND_ (ceiling, ROUND_HALF_EVEN).
Adding a preset when the law changes
Copy the newest file in src/syriantaxescli/presets/, name it after the new law (names sort by
date and the last one is the default), and change the values. A test checks that every preset
is complete.
Upgrading from 0.1
- syriantaxes 1.0 defines brackets by their lower bounds only, so
--brackets-maxsandSYRIANTAXES_BRACKET_TAX_MAXSare gone; the last bracket has no top. grosstakes the insured salary as-i/--insured-salaryinstead of a third argument.-r/--compensations-ratedefaults tonet.compensation_share(0 in the preset).aris nowrange;arstill works as an alias.- Tax-rule options are global and go before the command:
sytax --ss gross 1e6. The environment variable names are unchanged. ruleslost itsconfigalias;configis now the configuration command group.--write-pathis now-e/--export(the old name still works), and every command can export.- JSON lines files have one compact object per line.
Project structure
src/syriantaxescli/
├── main.py # Builds the Typer app; `sytax` entry point
├── core/ # Calculations, independent of the CLI
│ ├── config.py # Layered config loading: presets, files, env, options
│ ├── settings.py # The settings model (pydantic), with no defaults in code
│ ├── rounding.py # Rounding methods and rules
│ ├── salary.py # The Salary result
│ └── services.py # gross / net / range calculations on syriantaxes
├── presets/ # Bundled law presets (TOML): the only defaults
└── cli/
├── callback.py # Root callback: --version, global options, lazy settings
├── commands/ # One Typer app per command: gross, net, range, rules, config
├── dependencies/ # typer-di dependencies: context, settings, overrides, output
├── options.py # Shared options
├── parsers.py # Decimal parsing
├── renderers.py # Tables and JSON
└── exporters.py # .xlsx, .csv, .json, .jsonl
Development
uv sync
uv run pytest # with branch coverage; fails below 100%
uv run mypy
uv run ruff check
uv run ruff format --check
License
GNU General Public License v3 (GPLv3)
Metadata
Release files for syriantaxescli 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| syriantaxescli-0.2.0.tar.gz | 25.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| syriantaxescli-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 59.7 kB
Release files / syriantaxescli-0.2.0.tar.gz
| Download URL | syriantaxescli-0.2.0.tar.gz |
|---|---|
| Size | 25.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b47d8a1930e449a183e891a07f2dcfb050d659efa817f15021c97d1d4bdad47a
|
|
BLAKE2b-256 checksum How to use checksums |
a84b41e336af7725593d46d551d64b63cc281cf27ab01cb77ef306c0e294681e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / syriantaxescli-0.2.0-py3-none-any.whl
| Download URL | syriantaxescli-0.2.0-py3-none-any.whl |
|---|---|
| Size | 34.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c116118b3b4092a7682b304d783eb13962fcb915053b110115fbf161359bd387
|
|
BLAKE2b-256 checksum How to use checksums |
36128ec34675782b3349f9c37cc25db58c04ef5d32bd0a8df8e19f2106d1cab9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|